blob: 153a8168207121389892de1ec307edc1a6211e65 [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
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000030#if V8_TARGET_ARCH_MIPS
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000031
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
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000120void StubCompiler::GenerateDictionaryNegativeLookup(MacroAssembler* masm,
121 Label* miss_label,
122 Register receiver,
123 Handle<Name> name,
124 Register scratch0,
125 Register scratch1) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000126 ASSERT(name->IsUniqueName());
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000127 ASSERT(!receiver.is(scratch0));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000128 Counters* counters = masm->isolate()->counters();
129 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
130 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
131
132 Label done;
133
134 const int kInterceptorOrAccessCheckNeededMask =
135 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
136
137 // Bail out if the receiver has a named interceptor or requires access checks.
138 Register map = scratch1;
139 __ lw(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
140 __ lbu(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
141 __ And(scratch0, scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
142 __ Branch(miss_label, ne, scratch0, Operand(zero_reg));
143
144 // Check that receiver is a JSObject.
145 __ lbu(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
146 __ Branch(miss_label, lt, scratch0, Operand(FIRST_SPEC_OBJECT_TYPE));
147
148 // Load properties array.
149 Register properties = scratch0;
150 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
151 // Check that the properties array is a dictionary.
152 __ lw(map, FieldMemOperand(properties, HeapObject::kMapOffset));
153 Register tmp = properties;
154 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
155 __ Branch(miss_label, ne, map, Operand(tmp));
156
157 // Restore the temporarily used register.
158 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
159
160
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000161 NameDictionaryLookupStub::GenerateNegativeLookup(masm,
162 miss_label,
163 &done,
164 receiver,
165 properties,
166 name,
167 scratch1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000168 __ bind(&done);
169 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
170}
171
172
ager@chromium.org5c838252010-02-19 08:53:10 +0000173void StubCache::GenerateProbe(MacroAssembler* masm,
174 Code::Flags flags,
175 Register receiver,
176 Register name,
177 Register scratch,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000178 Register extra,
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000179 Register extra2,
180 Register extra3) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000181 Isolate* isolate = masm->isolate();
182 Label miss;
183
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000184 // Make sure that code is valid. The multiplying code relies on the
185 // entry size being 12.
186 ASSERT(sizeof(Entry) == 12);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000187
188 // Make sure the flags does not name a specific type.
189 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
190
191 // Make sure that there are no register conflicts.
192 ASSERT(!scratch.is(receiver));
193 ASSERT(!scratch.is(name));
194 ASSERT(!extra.is(receiver));
195 ASSERT(!extra.is(name));
196 ASSERT(!extra.is(scratch));
197 ASSERT(!extra2.is(receiver));
198 ASSERT(!extra2.is(name));
199 ASSERT(!extra2.is(scratch));
200 ASSERT(!extra2.is(extra));
201
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000202 // Check register validity.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000203 ASSERT(!scratch.is(no_reg));
204 ASSERT(!extra.is(no_reg));
205 ASSERT(!extra2.is(no_reg));
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000206 ASSERT(!extra3.is(no_reg));
207
208 Counters* counters = masm->isolate()->counters();
209 __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1,
210 extra2, extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000211
212 // Check that the receiver isn't a smi.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000213 __ JumpIfSmi(receiver, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000214
215 // Get the map of the receiver and compute the hash.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000216 __ lw(scratch, FieldMemOperand(name, Name::kHashFieldOffset));
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000217 __ lw(at, FieldMemOperand(receiver, HeapObject::kMapOffset));
218 __ Addu(scratch, scratch, at);
219 uint32_t mask = kPrimaryTableSize - 1;
220 // We shift out the last two bits because they are not part of the hash and
221 // they are always 01 for maps.
222 __ srl(scratch, scratch, kHeapObjectTagSize);
223 __ Xor(scratch, scratch, Operand((flags >> kHeapObjectTagSize) & mask));
224 __ And(scratch, scratch, Operand(mask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000225
226 // Probe the primary table.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000227 ProbeTable(isolate,
228 masm,
229 flags,
230 kPrimary,
231 receiver,
232 name,
233 scratch,
234 extra,
235 extra2,
236 extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000237
238 // Primary miss: Compute hash for secondary probe.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000239 __ srl(at, name, kHeapObjectTagSize);
240 __ Subu(scratch, scratch, at);
241 uint32_t mask2 = kSecondaryTableSize - 1;
242 __ Addu(scratch, scratch, Operand((flags >> kHeapObjectTagSize) & mask2));
243 __ And(scratch, scratch, Operand(mask2));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000244
245 // Probe the secondary table.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000246 ProbeTable(isolate,
247 masm,
248 flags,
249 kSecondary,
250 receiver,
251 name,
252 scratch,
253 extra,
254 extra2,
255 extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000256
257 // Cache miss: Fall-through and let caller handle the miss by
258 // entering the runtime system.
259 __ bind(&miss);
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000260 __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1,
261 extra2, extra3);
ager@chromium.org5c838252010-02-19 08:53:10 +0000262}
263
264
265void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
266 int index,
267 Register prototype) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000268 // Load the global or builtins object from the current context.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000269 __ lw(prototype,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000270 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
271 // Load the native context from the global or builtins object.
272 __ lw(prototype,
273 FieldMemOperand(prototype, GlobalObject::kNativeContextOffset));
274 // Load the function from the native context.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000275 __ lw(prototype, MemOperand(prototype, Context::SlotOffset(index)));
276 // Load the initial map. The global functions all have initial maps.
277 __ lw(prototype,
278 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
279 // Load the prototype from the initial map.
280 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000281}
282
283
lrn@chromium.org7516f052011-03-30 08:52:27 +0000284void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000285 MacroAssembler* masm,
286 int index,
287 Register prototype,
288 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000289 Isolate* isolate = masm->isolate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000290 // Get the global function with the given index.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000291 Handle<JSFunction> function(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000292 JSFunction::cast(isolate->native_context()->get(index)));
machenbach@chromium.org57a54ac2014-01-31 14:01:53 +0000293
294 // Check we're still in the same context.
295 Register scratch = prototype;
296 const int offset = Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX);
297 __ lw(scratch, MemOperand(cp, offset));
298 __ lw(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset));
299 __ lw(scratch, MemOperand(scratch, Context::SlotOffset(index)));
300 __ li(at, function);
301 __ Branch(miss, ne, at, Operand(scratch));
302
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
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000310void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
311 Register dst,
312 Register src,
313 bool inobject,
314 int index,
315 Representation representation) {
titzer@chromium.orgbc176052014-03-05 15:10:53 +0000316 ASSERT(!representation.IsDouble());
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000317 int offset = index * kPointerSize;
318 if (!inobject) {
319 // Calculate the offset into the properties array.
320 offset = offset + FixedArray::kHeaderSize;
321 __ lw(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
322 src = dst;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000323 }
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000324 __ lw(dst, FieldMemOperand(src, offset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000325}
326
327
328void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
329 Register receiver,
330 Register scratch,
331 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000332 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000333 __ JumpIfSmi(receiver, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000334
335 // Check that the object is a JS array.
336 __ GetObjectType(receiver, scratch, scratch);
337 __ Branch(miss_label, ne, scratch, Operand(JS_ARRAY_TYPE));
338
339 // Load length directly from the JS array.
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000340 __ Ret(USE_DELAY_SLOT);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000341 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000342}
343
344
ager@chromium.org5c838252010-02-19 08:53:10 +0000345void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
346 Register receiver,
347 Register scratch1,
348 Register scratch2,
349 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000350 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000351 __ Ret(USE_DELAY_SLOT);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000352 __ mov(v0, scratch1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000353}
354
355
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000356void StubCompiler::GenerateCheckPropertyCell(MacroAssembler* masm,
357 Handle<JSGlobalObject> global,
358 Handle<Name> name,
359 Register scratch,
360 Label* miss) {
361 Handle<Cell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000362 ASSERT(cell->value()->IsTheHole());
363 __ li(scratch, Operand(cell));
danno@chromium.orgf95d4b92013-06-13 14:40:17 +0000364 __ lw(scratch, FieldMemOperand(scratch, Cell::kValueOffset));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000365 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
366 __ Branch(miss, ne, scratch, Operand(at));
367}
368
369
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000370void StoreStubCompiler::GenerateNegativeHolderLookup(
danno@chromium.orgbee51992013-07-10 14:57:15 +0000371 MacroAssembler* masm,
372 Handle<JSObject> holder,
373 Register holder_reg,
374 Handle<Name> name,
375 Label* miss) {
376 if (holder->IsJSGlobalObject()) {
377 GenerateCheckPropertyCell(
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000378 masm, Handle<JSGlobalObject>::cast(holder), name, scratch1(), miss);
danno@chromium.orgbee51992013-07-10 14:57:15 +0000379 } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
380 GenerateDictionaryNegativeLookup(
381 masm, miss, holder_reg, name, scratch1(), scratch2());
382 }
383}
384
385
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000386// Generate StoreTransition code, value is passed in a0 register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000387// After executing generated code, the receiver_reg and name_reg
388// may be clobbered.
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000389void StoreStubCompiler::GenerateStoreTransition(MacroAssembler* masm,
390 Handle<JSObject> object,
391 LookupResult* lookup,
392 Handle<Map> transition,
393 Handle<Name> name,
394 Register receiver_reg,
395 Register storage_reg,
396 Register value_reg,
397 Register scratch1,
398 Register scratch2,
399 Register scratch3,
400 Label* miss_label,
401 Label* slow) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000402 // a0 : value.
403 Label exit;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000404
danno@chromium.orgf005df62013-04-30 16:36:45 +0000405 int descriptor = transition->LastAdded();
406 DescriptorArray* descriptors = transition->instance_descriptors();
407 PropertyDetails details = descriptors->GetDetails(descriptor);
408 Representation representation = details.representation();
409 ASSERT(!representation.IsNone());
410
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000411 if (details.type() == CONSTANT) {
412 Handle<Object> constant(descriptors->GetValue(descriptor), masm->isolate());
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000413 __ li(scratch1, constant);
danno@chromium.orgbee51992013-07-10 14:57:15 +0000414 __ Branch(miss_label, ne, value_reg, Operand(scratch1));
titzer@chromium.orgbc176052014-03-05 15:10:53 +0000415 } else if (representation.IsSmi()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000416 __ JumpIfNotSmi(value_reg, miss_label);
titzer@chromium.orgbc176052014-03-05 15:10:53 +0000417 } else if (representation.IsHeapObject()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000418 __ JumpIfSmi(value_reg, miss_label);
titzer@chromium.orgbc176052014-03-05 15:10:53 +0000419 } else if (representation.IsDouble()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000420 Label do_store, heap_number;
421 __ LoadRoot(scratch3, Heap::kHeapNumberMapRootIndex);
422 __ AllocateHeapNumber(storage_reg, scratch1, scratch2, scratch3, slow);
423
424 __ JumpIfNotSmi(value_reg, &heap_number);
425 __ SmiUntag(scratch1, value_reg);
426 __ mtc1(scratch1, f6);
427 __ cvt_d_w(f4, f6);
428 __ jmp(&do_store);
429
430 __ bind(&heap_number);
431 __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex,
danno@chromium.orgbee51992013-07-10 14:57:15 +0000432 miss_label, DONT_DO_SMI_CHECK);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000433 __ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
434
435 __ bind(&do_store);
436 __ sdc1(f4, FieldMemOperand(storage_reg, HeapNumber::kValueOffset));
437 }
438
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000439 // Stub never generated for non-global objects that require access
440 // checks.
441 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
442
443 // Perform map transition for the receiver if necessary.
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000444 if (details.type() == FIELD &&
445 object->map()->unused_property_fields() == 0) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000446 // The properties must be extended before we can store the value.
447 // We jump to a runtime call that extends the properties array.
448 __ push(receiver_reg);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000449 __ li(a2, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000450 __ Push(a2, a0);
451 __ TailCallExternalReference(
452 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
453 masm->isolate()),
454 3, 1);
455 return;
456 }
457
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000458 // Update the map of the object.
459 __ li(scratch1, Operand(transition));
460 __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
verwaest@chromium.org37141392012-05-31 13:27:02 +0000461
danno@chromium.orgbee51992013-07-10 14:57:15 +0000462 // Update the write barrier for the map field.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000463 __ RecordWriteField(receiver_reg,
464 HeapObject::kMapOffset,
465 scratch1,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000466 scratch2,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000467 kRAHasNotBeenSaved,
468 kDontSaveFPRegs,
469 OMIT_REMEMBERED_SET,
470 OMIT_SMI_CHECK);
471
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000472 if (details.type() == CONSTANT) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000473 ASSERT(value_reg.is(a0));
474 __ Ret(USE_DELAY_SLOT);
475 __ mov(v0, a0);
476 return;
477 }
478
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000479 int index = transition->instance_descriptors()->GetFieldIndex(
480 transition->LastAdded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000481
482 // Adjust for the number of properties stored in the object. Even in the
483 // face of a transition we can use the old map here because the size of the
484 // object and the number of in-object properties is not going to change.
485 index -= object->map()->inobject_properties();
486
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000487 // TODO(verwaest): Share this code as a code stub.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000488 SmiCheck smi_check = representation.IsTagged()
489 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000490 if (index < 0) {
491 // Set the property straight into the object.
492 int offset = object->map()->instance_size() + (index * kPointerSize);
titzer@chromium.orgbc176052014-03-05 15:10:53 +0000493 if (representation.IsDouble()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000494 __ sw(storage_reg, FieldMemOperand(receiver_reg, offset));
495 } else {
496 __ sw(value_reg, FieldMemOperand(receiver_reg, offset));
497 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000498
titzer@chromium.orgbc176052014-03-05 15:10:53 +0000499 if (!representation.IsSmi()) {
danno@chromium.orgf005df62013-04-30 16:36:45 +0000500 // Update the write barrier for the array address.
titzer@chromium.orgbc176052014-03-05 15:10:53 +0000501 if (!representation.IsDouble()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000502 __ mov(storage_reg, value_reg);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000503 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000504 __ RecordWriteField(receiver_reg,
505 offset,
danno@chromium.orgbee51992013-07-10 14:57:15 +0000506 storage_reg,
danno@chromium.orgf005df62013-04-30 16:36:45 +0000507 scratch1,
508 kRAHasNotBeenSaved,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000509 kDontSaveFPRegs,
510 EMIT_REMEMBERED_SET,
511 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000512 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000513 } else {
514 // Write to the properties array.
515 int offset = index * kPointerSize + FixedArray::kHeaderSize;
516 // Get the properties array
517 __ lw(scratch1,
518 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
titzer@chromium.orgbc176052014-03-05 15:10:53 +0000519 if (representation.IsDouble()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000520 __ sw(storage_reg, FieldMemOperand(scratch1, offset));
521 } else {
522 __ sw(value_reg, FieldMemOperand(scratch1, offset));
523 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000524
titzer@chromium.orgbc176052014-03-05 15:10:53 +0000525 if (!representation.IsSmi()) {
danno@chromium.orgf005df62013-04-30 16:36:45 +0000526 // Update the write barrier for the array address.
titzer@chromium.orgbc176052014-03-05 15:10:53 +0000527 if (!representation.IsDouble()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000528 __ mov(storage_reg, value_reg);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000529 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000530 __ RecordWriteField(scratch1,
531 offset,
danno@chromium.orgbee51992013-07-10 14:57:15 +0000532 storage_reg,
danno@chromium.orgf005df62013-04-30 16:36:45 +0000533 receiver_reg,
534 kRAHasNotBeenSaved,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000535 kDontSaveFPRegs,
536 EMIT_REMEMBERED_SET,
537 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000538 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000539 }
540
541 // Return the value (register v0).
542 ASSERT(value_reg.is(a0));
543 __ bind(&exit);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000544 __ Ret(USE_DELAY_SLOT);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000545 __ mov(v0, a0);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000546}
547
548
549// Generate StoreField code, value is passed in a0 register.
550// When leaving generated code after success, the receiver_reg and name_reg
551// may be clobbered. Upon branch to miss_label, the receiver and name
552// registers have their original values.
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000553void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
554 Handle<JSObject> object,
555 LookupResult* lookup,
556 Register receiver_reg,
557 Register name_reg,
558 Register value_reg,
559 Register scratch1,
560 Register scratch2,
561 Label* miss_label) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000562 // a0 : value
563 Label exit;
564
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000565 // Stub never generated for non-global objects that require access
566 // checks.
567 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
568
569 int index = lookup->GetFieldIndex().field_index();
570
571 // Adjust for the number of properties stored in the object. Even in the
572 // face of a transition we can use the old map here because the size of the
573 // object and the number of in-object properties is not going to change.
574 index -= object->map()->inobject_properties();
575
danno@chromium.orgf005df62013-04-30 16:36:45 +0000576 Representation representation = lookup->representation();
577 ASSERT(!representation.IsNone());
titzer@chromium.orgbc176052014-03-05 15:10:53 +0000578 if (representation.IsSmi()) {
danno@chromium.orgf005df62013-04-30 16:36:45 +0000579 __ JumpIfNotSmi(value_reg, miss_label);
titzer@chromium.orgbc176052014-03-05 15:10:53 +0000580 } else if (representation.IsHeapObject()) {
ulan@chromium.org906e2fb2013-05-14 08:14:38 +0000581 __ JumpIfSmi(value_reg, miss_label);
titzer@chromium.orgbc176052014-03-05 15:10:53 +0000582 } else if (representation.IsDouble()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000583 // Load the double storage.
584 if (index < 0) {
585 int offset = object->map()->instance_size() + (index * kPointerSize);
586 __ lw(scratch1, FieldMemOperand(receiver_reg, offset));
587 } else {
588 __ lw(scratch1,
589 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
590 int offset = index * kPointerSize + FixedArray::kHeaderSize;
591 __ lw(scratch1, FieldMemOperand(scratch1, offset));
592 }
593
594 // Store the value into the storage.
595 Label do_store, heap_number;
596 __ JumpIfNotSmi(value_reg, &heap_number);
597 __ SmiUntag(scratch2, value_reg);
598 __ mtc1(scratch2, f6);
599 __ cvt_d_w(f4, f6);
600 __ jmp(&do_store);
601
602 __ bind(&heap_number);
603 __ CheckMap(value_reg, scratch2, Heap::kHeapNumberMapRootIndex,
danno@chromium.orgf005df62013-04-30 16:36:45 +0000604 miss_label, DONT_DO_SMI_CHECK);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000605 __ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
606
danno@chromium.orgf005df62013-04-30 16:36:45 +0000607 __ bind(&do_store);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000608 __ sdc1(f4, FieldMemOperand(scratch1, HeapNumber::kValueOffset));
609 // Return the value (register v0).
610 ASSERT(value_reg.is(a0));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000611 __ Ret(USE_DELAY_SLOT);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000612 __ mov(v0, a0);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000613 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +0000614 }
615
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000616 // TODO(verwaest): Share this code as a code stub.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000617 SmiCheck smi_check = representation.IsTagged()
618 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000619 if (index < 0) {
620 // Set the property straight into the object.
621 int offset = object->map()->instance_size() + (index * kPointerSize);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000622 __ sw(value_reg, FieldMemOperand(receiver_reg, offset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000623
titzer@chromium.orgbc176052014-03-05 15:10:53 +0000624 if (!representation.IsSmi()) {
danno@chromium.orgf005df62013-04-30 16:36:45 +0000625 // Skip updating write barrier if storing a smi.
626 __ JumpIfSmi(value_reg, &exit);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000627
danno@chromium.orgf005df62013-04-30 16:36:45 +0000628 // Update the write barrier for the array address.
629 // Pass the now unused name_reg as a scratch register.
630 __ mov(name_reg, value_reg);
631 __ RecordWriteField(receiver_reg,
632 offset,
633 name_reg,
634 scratch1,
635 kRAHasNotBeenSaved,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000636 kDontSaveFPRegs,
637 EMIT_REMEMBERED_SET,
638 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000639 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000640 } else {
641 // Write to the properties array.
642 int offset = index * kPointerSize + FixedArray::kHeaderSize;
643 // Get the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000644 __ lw(scratch1,
645 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000646 __ sw(value_reg, FieldMemOperand(scratch1, offset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000647
titzer@chromium.orgbc176052014-03-05 15:10:53 +0000648 if (!representation.IsSmi()) {
danno@chromium.orgf005df62013-04-30 16:36:45 +0000649 // Skip updating write barrier if storing a smi.
650 __ JumpIfSmi(value_reg, &exit);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000651
danno@chromium.orgf005df62013-04-30 16:36:45 +0000652 // Update the write barrier for the array address.
653 // Ok to clobber receiver_reg and name_reg, since we return.
654 __ mov(name_reg, value_reg);
655 __ RecordWriteField(scratch1,
656 offset,
657 name_reg,
658 receiver_reg,
659 kRAHasNotBeenSaved,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000660 kDontSaveFPRegs,
661 EMIT_REMEMBERED_SET,
662 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000663 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000664 }
665
666 // Return the value (register v0).
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000667 ASSERT(value_reg.is(a0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000668 __ bind(&exit);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000669 __ Ret(USE_DELAY_SLOT);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000670 __ mov(v0, a0);
ager@chromium.org5c838252010-02-19 08:53:10 +0000671}
672
673
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000674void StoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
675 Label* label,
676 Handle<Name> name) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000677 if (!label->is_unused()) {
678 __ bind(label);
679 __ li(this->name(), Operand(name));
680 }
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000681}
682
683
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000684static void PushInterceptorArguments(MacroAssembler* masm,
685 Register receiver,
686 Register holder,
687 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000688 Handle<JSObject> holder_obj) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000689 STATIC_ASSERT(StubCache::kInterceptorArgsNameIndex == 0);
690 STATIC_ASSERT(StubCache::kInterceptorArgsInfoIndex == 1);
691 STATIC_ASSERT(StubCache::kInterceptorArgsThisIndex == 2);
692 STATIC_ASSERT(StubCache::kInterceptorArgsHolderIndex == 3);
693 STATIC_ASSERT(StubCache::kInterceptorArgsLength == 4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000694 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000695 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
696 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000697 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000698 __ li(scratch, Operand(interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000699 __ Push(scratch, receiver, holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000700}
701
702
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000703static void CompileCallLoadPropertyWithInterceptor(
704 MacroAssembler* masm,
705 Register receiver,
706 Register holder,
707 Register name,
machenbach@chromium.org37be4082013-11-26 13:50:38 +0000708 Handle<JSObject> holder_obj,
709 IC::UtilityId id) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000710 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
machenbach@chromium.org37be4082013-11-26 13:50:38 +0000711 __ CallExternalReference(
712 ExternalReference(IC_Utility(id), masm->isolate()),
713 StubCache::kInterceptorArgsLength);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000714}
715
716
machenbach@chromium.org6f1040e2014-02-04 07:54:22 +0000717// Generate call to api function.
titzer@chromium.orgf5a24542014-03-04 09:06:17 +0000718void StubCompiler::GenerateFastApiCall(MacroAssembler* masm,
719 const CallOptimization& optimization,
720 Handle<Map> receiver_map,
721 Register receiver,
722 Register scratch_in,
723 bool is_store,
724 int argc,
725 Register* values) {
machenbach@chromium.org6f1040e2014-02-04 07:54:22 +0000726 ASSERT(!receiver.is(scratch_in));
727 // Preparing to push, adjust sp.
728 __ Subu(sp, sp, Operand((argc + 1) * kPointerSize));
729 __ sw(receiver, MemOperand(sp, argc * kPointerSize)); // Push receiver.
730 // Write the arguments to stack frame.
731 for (int i = 0; i < argc; i++) {
732 Register arg = values[argc-1-i];
733 ASSERT(!receiver.is(arg));
734 ASSERT(!scratch_in.is(arg));
735 __ sw(arg, MemOperand(sp, (argc-1-i) * kPointerSize)); // Push arg.
736 }
palfia@homejinni.comcc96b0e2014-01-23 17:24:54 +0000737 ASSERT(optimization.is_simple_api_call());
738
machenbach@chromium.orge014e5b2014-01-28 07:51:38 +0000739 // Abi for CallApiFunctionStub.
740 Register callee = a0;
741 Register call_data = t0;
742 Register holder = a2;
machenbach@chromium.org57a54ac2014-01-31 14:01:53 +0000743 Register api_function_address = a1;
palfia@homejinni.comcc96b0e2014-01-23 17:24:54 +0000744
machenbach@chromium.orge014e5b2014-01-28 07:51:38 +0000745 // Put holder in place.
machenbach@chromium.org6f1040e2014-02-04 07:54:22 +0000746 CallOptimization::HolderLookup holder_lookup;
747 Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType(
748 receiver_map,
749 &holder_lookup);
750 switch (holder_lookup) {
751 case CallOptimization::kHolderIsReceiver:
752 __ Move(holder, receiver);
753 break;
754 case CallOptimization::kHolderFound:
755 __ li(holder, api_holder);
756 break;
757 case CallOptimization::kHolderNotFound:
758 UNREACHABLE();
759 break;
760 }
palfia@homejinni.comcc96b0e2014-01-23 17:24:54 +0000761
machenbach@chromium.orge014e5b2014-01-28 07:51:38 +0000762 Isolate* isolate = masm->isolate();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000763 Handle<JSFunction> function = optimization.constant_function();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000764 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
machenbach@chromium.orge014e5b2014-01-28 07:51:38 +0000765 Handle<Object> call_data_obj(api_call_info->data(), isolate);
766
767 // Put callee in place.
768 __ li(callee, function);
769
palfia@homejinni.comcc96b0e2014-01-23 17:24:54 +0000770 bool call_data_undefined = false;
machenbach@chromium.orge014e5b2014-01-28 07:51:38 +0000771 // Put call_data in place.
772 if (isolate->heap()->InNewSpace(*call_data_obj)) {
773 __ li(call_data, api_call_info);
774 __ lw(call_data, FieldMemOperand(call_data, CallHandlerInfo::kDataOffset));
775 } else if (call_data_obj->IsUndefined()) {
palfia@homejinni.comcc96b0e2014-01-23 17:24:54 +0000776 call_data_undefined = true;
machenbach@chromium.orge014e5b2014-01-28 07:51:38 +0000777 __ LoadRoot(call_data, Heap::kUndefinedValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000778 } else {
machenbach@chromium.orge014e5b2014-01-28 07:51:38 +0000779 __ li(call_data, call_data_obj);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000780 }
machenbach@chromium.orge014e5b2014-01-28 07:51:38 +0000781 // Put api_function_address in place.
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000782 Address function_address = v8::ToCData<Address>(api_call_info->callback());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000783 ApiFunction fun(function_address);
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000784 ExternalReference::Type type = ExternalReference::DIRECT_API_CALL;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000785 ExternalReference ref =
786 ExternalReference(&fun,
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000787 type,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000788 masm->isolate());
machenbach@chromium.orge014e5b2014-01-28 07:51:38 +0000789 __ li(api_function_address, Operand(ref));
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000790
machenbach@chromium.orge014e5b2014-01-28 07:51:38 +0000791 // Jump to stub.
titzer@chromium.orgf5a24542014-03-04 09:06:17 +0000792 CallApiFunctionStub stub(is_store, call_data_undefined, argc);
machenbach@chromium.orge014e5b2014-01-28 07:51:38 +0000793 __ TailCallStub(&stub);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000794}
795
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000796
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000797void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000798 __ Jump(code, RelocInfo::CODE_TARGET);
799}
800
801
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000802#undef __
803#define __ ACCESS_MASM(masm())
804
805
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +0000806Register StubCompiler::CheckPrototypes(Handle<HeapType> type,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000807 Register object_reg,
808 Handle<JSObject> holder,
809 Register holder_reg,
810 Register scratch1,
811 Register scratch2,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000812 Handle<Name> name,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000813 Label* miss,
814 PrototypeCheckType check) {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000815 Handle<Map> receiver_map(IC::TypeToMap(*type, isolate()));
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000816
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000817 // Make sure there's no overlap between holder and object registers.
818 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
819 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
820 && !scratch2.is(scratch1));
821
822 // Keep track of the current object in register reg.
823 Register reg = object_reg;
824 int depth = 0;
825
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000826 Handle<JSObject> current = Handle<JSObject>::null();
827 if (type->IsConstant()) current = Handle<JSObject>::cast(type->AsConstant());
828 Handle<JSObject> prototype = Handle<JSObject>::null();
829 Handle<Map> current_map = receiver_map;
830 Handle<Map> holder_map(holder->map());
831 // Traverse the prototype chain and check the maps in the prototype chain for
832 // fast and global objects or do negative lookup for normal objects.
833 while (!current_map.is_identical_to(holder_map)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000834 ++depth;
835
836 // Only global objects and objects that do not require access
837 // checks are allowed in stubs.
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000838 ASSERT(current_map->IsJSGlobalProxyMap() ||
839 !current_map->is_access_check_needed());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000840
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000841 prototype = handle(JSObject::cast(current_map->prototype()));
842 if (current_map->is_dictionary_map() &&
843 !current_map->IsJSGlobalObjectMap() &&
844 !current_map->IsJSGlobalProxyMap()) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000845 if (!name->IsUniqueName()) {
846 ASSERT(name->IsString());
847 name = factory()->InternalizeString(Handle<String>::cast(name));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000848 }
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000849 ASSERT(current.is_null() ||
850 current->property_dictionary()->FindEntry(*name) ==
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000851 NameDictionary::kNotFound);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000852
853 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
854 scratch1, scratch2);
855
856 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
857 reg = holder_reg; // From now on the object will be in holder_reg.
858 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
859 } else {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000860 Register map_reg = scratch1;
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000861 if (depth != 1 || check == CHECK_ALL_MAPS) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000862 // CheckMap implicitly loads the map of |reg| into |map_reg|.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000863 __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000864 } else {
865 __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
866 }
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000867
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000868 // Check access rights to the global object. This has to happen after
869 // the map check so that we know that the object is actually a global
870 // object.
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000871 if (current_map->IsJSGlobalProxyMap()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000872 __ CheckAccessGlobalProxy(reg, scratch2, miss);
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000873 } else if (current_map->IsJSGlobalObjectMap()) {
874 GenerateCheckPropertyCell(
875 masm(), Handle<JSGlobalObject>::cast(current), name,
876 scratch2, miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000877 }
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000878
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000879 reg = holder_reg; // From now on the object will be in holder_reg.
880
881 if (heap()->InNewSpace(*prototype)) {
882 // The prototype is in new space; we cannot store a reference to it
883 // in the code. Load it from the map.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000884 __ lw(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000885 } else {
886 // The prototype is in old space; load it directly.
887 __ li(reg, Operand(prototype));
888 }
889 }
890
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000891 // Go to the next object in the prototype chain.
892 current = prototype;
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000893 current_map = handle(current->map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000894 }
895
896 // Log the check depth.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000897 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000898
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000899 if (depth != 0 || check == CHECK_ALL_MAPS) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000900 // Check the holder map.
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000901 __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000902 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000903
904 // Perform security check for access to the global object.
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000905 ASSERT(current_map->IsJSGlobalProxyMap() ||
906 !current_map->is_access_check_needed());
907 if (current_map->IsJSGlobalProxyMap()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000908 __ CheckAccessGlobalProxy(reg, scratch1, miss);
909 }
910
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000911 // Return the register containing the holder.
912 return reg;
913}
914
915
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000916void LoadStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000917 if (!miss->is_unused()) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000918 Label success;
919 __ Branch(&success);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000920 __ bind(miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000921 TailCallBuiltin(masm(), MissBuiltin(kind()));
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000922 __ bind(&success);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000923 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000924}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000925
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000926
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000927void StoreStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000928 if (!miss->is_unused()) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000929 Label success;
930 __ Branch(&success);
danno@chromium.orgbee51992013-07-10 14:57:15 +0000931 GenerateRestoreName(masm(), miss, name);
932 TailCallBuiltin(masm(), MissBuiltin(kind()));
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000933 __ bind(&success);
danno@chromium.orgbee51992013-07-10 14:57:15 +0000934 }
935}
936
937
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000938Register LoadStubCompiler::CallbackHandlerFrontend(
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +0000939 Handle<HeapType> type,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000940 Register object_reg,
941 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000942 Handle<Name> name,
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +0000943 Handle<Object> callback) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000944 Label miss;
945
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000946 Register reg = HandlerFrontendHeader(type, object_reg, holder, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000947
948 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
949 ASSERT(!reg.is(scratch2()));
950 ASSERT(!reg.is(scratch3()));
951 ASSERT(!reg.is(scratch4()));
952
953 // Load the properties dictionary.
954 Register dictionary = scratch4();
955 __ lw(dictionary, FieldMemOperand(reg, JSObject::kPropertiesOffset));
956
957 // Probe the dictionary.
958 Label probe_done;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000959 NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
960 &miss,
961 &probe_done,
962 dictionary,
963 this->name(),
964 scratch2(),
965 scratch3());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000966 __ bind(&probe_done);
967
968 // If probing finds an entry in the dictionary, scratch3 contains the
969 // pointer into the dictionary. Check that the value is the callback.
970 Register pointer = scratch3();
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000971 const int kElementsStartOffset = NameDictionary::kHeaderSize +
972 NameDictionary::kElementsStartIndex * kPointerSize;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000973 const int kValueOffset = kElementsStartOffset + kPointerSize;
974 __ lw(scratch2(), FieldMemOperand(pointer, kValueOffset));
975 __ Branch(&miss, ne, scratch2(), Operand(callback));
976 }
977
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000978 HandlerFrontendFooter(name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000979 return reg;
980}
981
982
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000983void LoadStubCompiler::GenerateLoadField(Register reg,
984 Handle<JSObject> holder,
985 PropertyIndex field,
986 Representation representation) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000987 if (!reg.is(receiver())) __ mov(receiver(), reg);
988 if (kind() == Code::LOAD_IC) {
989 LoadFieldStub stub(field.is_inobject(holder),
990 field.translate(holder),
991 representation);
992 GenerateTailCall(masm(), stub.GetCode(isolate()));
993 } else {
994 KeyedLoadFieldStub stub(field.is_inobject(holder),
995 field.translate(holder),
996 representation);
997 GenerateTailCall(masm(), stub.GetCode(isolate()));
998 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000999}
1000
1001
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001002void LoadStubCompiler::GenerateLoadConstant(Handle<Object> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001003 // Return the constant value.
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001004 __ li(v0, value);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001005 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001006}
1007
1008
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001009void LoadStubCompiler::GenerateLoadCallback(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001010 Register reg,
1011 Handle<ExecutableAccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001012 // Build AccessorInfo::args_ list on the stack and push property name below
1013 // the exit frame to make GC aware of them and store pointers to them.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001014 STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0);
1015 STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1);
1016 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2);
1017 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3);
1018 STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4);
1019 STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5);
1020 STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001021 ASSERT(!scratch2().is(reg));
1022 ASSERT(!scratch3().is(reg));
1023 ASSERT(!scratch4().is(reg));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001024 __ push(receiver());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001025 if (heap()->InNewSpace(callback->data())) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001026 __ li(scratch3(), callback);
1027 __ lw(scratch3(), FieldMemOperand(scratch3(),
1028 ExecutableAccessorInfo::kDataOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001029 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001030 __ li(scratch3(), Handle<Object>(callback->data(), isolate()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001031 }
palfia@homejinni.com79d0bf72013-06-10 19:35:04 +00001032 __ Subu(sp, sp, 6 * kPointerSize);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001033 __ sw(scratch3(), MemOperand(sp, 5 * kPointerSize));
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00001034 __ LoadRoot(scratch3(), Heap::kUndefinedValueRootIndex);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001035 __ sw(scratch3(), MemOperand(sp, 4 * kPointerSize));
palfia@homejinni.com79d0bf72013-06-10 19:35:04 +00001036 __ sw(scratch3(), MemOperand(sp, 3 * kPointerSize));
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00001037 __ li(scratch4(),
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001038 Operand(ExternalReference::isolate_address(isolate())));
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001039 __ sw(scratch4(), MemOperand(sp, 2 * kPointerSize));
1040 __ sw(reg, MemOperand(sp, 1 * kPointerSize));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001041 __ sw(name(), MemOperand(sp, 0 * kPointerSize));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001042 __ Addu(scratch2(), sp, 1 * kPointerSize);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001043
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001044 __ mov(a2, scratch2()); // Saved in case scratch2 == a1.
machenbach@chromium.org57a54ac2014-01-31 14:01:53 +00001045 // Abi for CallApiGetter.
1046 Register getter_address_reg = a2;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001047
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001048 Address getter_address = v8::ToCData<Address>(callback->getter());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001049 ApiFunction fun(getter_address);
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001050 ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
danno@chromium.orgfe578672013-06-15 14:38:35 +00001051 ExternalReference ref = ExternalReference(&fun, type, isolate());
machenbach@chromium.orge014e5b2014-01-28 07:51:38 +00001052 __ li(getter_address_reg, Operand(ref));
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001053
machenbach@chromium.org57a54ac2014-01-31 14:01:53 +00001054 CallApiGetterStub stub;
1055 __ TailCallStub(&stub);
ager@chromium.org5c838252010-02-19 08:53:10 +00001056}
1057
1058
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001059void LoadStubCompiler::GenerateLoadInterceptor(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001060 Register holder_reg,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001061 Handle<Object> object,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001062 Handle<JSObject> interceptor_holder,
1063 LookupResult* lookup,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001064 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001065 ASSERT(interceptor_holder->HasNamedInterceptor());
1066 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1067
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001068 // So far the most popular follow ups for interceptor loads are FIELD
1069 // and CALLBACKS, so inline only them, other cases may be added
1070 // later.
1071 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001072 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001073 if (lookup->IsField()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001074 compile_followup_inline = true;
1075 } else if (lookup->type() == CALLBACKS &&
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001076 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
1077 ExecutableAccessorInfo* callback =
1078 ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001079 compile_followup_inline = callback->getter() != NULL &&
1080 callback->IsCompatibleReceiver(*object);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001081 }
1082 }
1083
1084 if (compile_followup_inline) {
1085 // Compile the interceptor call, followed by inline code to load the
1086 // property from further up the prototype chain if the call fails.
1087 // Check that the maps haven't changed.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001088 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001089
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001090 // Preserve the receiver register explicitly whenever it is different from
1091 // the holder and it is needed should the interceptor return without any
1092 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1093 // the FIELD case might cause a miss during the prototype check.
1094 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001095 bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001096 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1097
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001098 // Save necessary data before invoking an interceptor.
1099 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001100 {
1101 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001102 if (must_preserve_receiver_reg) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001103 __ Push(receiver(), holder_reg, this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001104 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001105 __ Push(holder_reg, this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001106 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001107 // Invoke an interceptor. Note: map checks from receiver to
1108 // interceptor's holder has been compiled before (see a caller
1109 // of this method).
machenbach@chromium.org37be4082013-11-26 13:50:38 +00001110 CompileCallLoadPropertyWithInterceptor(
1111 masm(), receiver(), holder_reg, this->name(), interceptor_holder,
1112 IC::kLoadPropertyWithInterceptorOnly);
1113
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001114 // Check if interceptor provided a value for property. If it's
1115 // the case, return immediately.
1116 Label interceptor_failed;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001117 __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
1118 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001119 frame_scope.GenerateLeaveFrame();
1120 __ Ret();
1121
1122 __ bind(&interceptor_failed);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001123 __ pop(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001124 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001125 if (must_preserve_receiver_reg) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001126 __ pop(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001127 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001128 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001129 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001130 GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001131 } else { // !compile_followup_inline
1132 // Call the runtime system to load the interceptor.
1133 // Check that the maps haven't changed.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001134 PushInterceptorArguments(masm(), receiver(), holder_reg,
1135 this->name(), interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001136
1137 ExternalReference ref = ExternalReference(
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001138 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate());
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001139 __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001140 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001141}
1142
1143
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001144void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
1145 Label success;
1146 // Check that the object is a boolean.
1147 __ LoadRoot(at, Heap::kTrueValueRootIndex);
1148 __ Branch(&success, eq, object, Operand(at));
1149 __ LoadRoot(at, Heap::kFalseValueRootIndex);
1150 __ Branch(miss, ne, object, Operand(at));
1151 __ bind(&success);
1152}
1153
1154
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00001155Handle<Code> StoreStubCompiler::CompileStoreCallback(
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00001156 Handle<JSObject> object,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001157 Handle<JSObject> holder,
danno@chromium.orgbee51992013-07-10 14:57:15 +00001158 Handle<Name> name,
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001159 Handle<ExecutableAccessorInfo> callback) {
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00001160 Register holder_reg = HandlerFrontend(
1161 IC::CurrentTypeOf(object, isolate()), receiver(), holder, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001162
1163 // Stub never generated for non-global objects that require access
1164 // checks.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001165 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001166
machenbach@chromium.org6f1040e2014-02-04 07:54:22 +00001167 __ Push(receiver(), holder_reg); // Receiver.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00001168 __ li(at, Operand(callback)); // Callback info.
danno@chromium.orgbee51992013-07-10 14:57:15 +00001169 __ push(at);
1170 __ li(at, Operand(name));
1171 __ Push(at, value());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001172
1173 // Do tail-call to the runtime system.
1174 ExternalReference store_callback_property =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001175 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00001176 __ TailCallExternalReference(store_callback_property, 5, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001177
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001178 // Return the generated code.
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00001179 return GetCode(kind(), Code::FAST, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001180}
1181
1182
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001183#undef __
1184#define __ ACCESS_MASM(masm)
1185
1186
1187void StoreStubCompiler::GenerateStoreViaSetter(
1188 MacroAssembler* masm,
bmeurer@chromium.org25530ce2014-02-07 09:11:16 +00001189 Handle<HeapType> type,
machenbach@chromium.orgbcc36722014-03-11 07:52:26 +00001190 Register receiver,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001191 Handle<JSFunction> setter) {
1192 // ----------- S t a t e -------------
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001193 // -- ra : return address
1194 // -----------------------------------
1195 {
1196 FrameScope scope(masm, StackFrame::INTERNAL);
1197
1198 // Save value register, so we can restore it later.
machenbach@chromium.orgbcc36722014-03-11 07:52:26 +00001199 __ push(value());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001200
1201 if (!setter.is_null()) {
1202 // Call the JavaScript setter with receiver and value on the stack.
bmeurer@chromium.org25530ce2014-02-07 09:11:16 +00001203 if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) {
1204 // Swap in the global receiver.
1205 __ lw(receiver,
1206 FieldMemOperand(
1207 receiver, JSGlobalObject::kGlobalReceiverOffset));
1208 }
machenbach@chromium.orgbcc36722014-03-11 07:52:26 +00001209 __ Push(receiver, value());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001210 ParameterCount actual(1);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001211 ParameterCount expected(setter);
1212 __ InvokeFunction(setter, expected, actual,
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00001213 CALL_FUNCTION, NullCallWrapper());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001214 } else {
1215 // If we generate a global code snippet for deoptimization only, remember
1216 // the place to continue after deoptimization.
1217 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
1218 }
1219
1220 // We have to return the passed value, not the return value of the setter.
1221 __ pop(v0);
1222
1223 // Restore context register.
1224 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
1225 }
1226 __ Ret();
1227}
1228
1229
1230#undef __
1231#define __ ACCESS_MASM(masm())
1232
1233
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00001234Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00001235 Handle<JSObject> object,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001236 Handle<Name> name) {
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00001237 __ Push(receiver(), this->name(), value());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001238
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001239 // Do tail-call to the runtime system.
1240 ExternalReference store_ic_property =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001241 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00001242 __ TailCallExternalReference(store_ic_property, 3, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001243
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001244 // Return the generated code.
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00001245 return GetCode(kind(), Code::FAST, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001246}
1247
1248
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +00001249Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<HeapType> type,
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001250 Handle<JSObject> last,
1251 Handle<Name> name) {
1252 NonexistentHandlerFrontend(type, last, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001253
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001254 // Return undefined if maps of the full prototype chain is still the same.
1255 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1256 __ Ret();
1257
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001258 // Return the generated code.
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00001259 return GetCode(kind(), Code::FAST, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001260}
1261
1262
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00001263Register* LoadStubCompiler::registers() {
1264 // receiver, name, scratch1, scratch2, scratch3, scratch4.
1265 static Register registers[] = { a0, a2, a3, a1, t0, t1 };
1266 return registers;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001267}
1268
1269
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00001270Register* KeyedLoadStubCompiler::registers() {
1271 // receiver, name, scratch1, scratch2, scratch3, scratch4.
1272 static Register registers[] = { a1, a0, a2, a3, t0, t1 };
1273 return registers;
1274}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001275
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00001276
machenbach@chromium.orgbcc36722014-03-11 07:52:26 +00001277Register StoreStubCompiler::value() {
1278 return a0;
1279}
1280
1281
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001282Register* StoreStubCompiler::registers() {
machenbach@chromium.orgbcc36722014-03-11 07:52:26 +00001283 // receiver, name, scratch1, scratch2, scratch3.
1284 static Register registers[] = { a1, a2, a3, t0, t1 };
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001285 return registers;
1286}
1287
1288
1289Register* KeyedStoreStubCompiler::registers() {
machenbach@chromium.orgbcc36722014-03-11 07:52:26 +00001290 // receiver, name, scratch1, scratch2, scratch3.
1291 static Register registers[] = { a2, a1, a3, t0, t1 };
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001292 return registers;
1293}
1294
1295
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001296#undef __
1297#define __ ACCESS_MASM(masm)
1298
1299
1300void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
bmeurer@chromium.org25530ce2014-02-07 09:11:16 +00001301 Handle<HeapType> type,
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001302 Register receiver,
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001303 Handle<JSFunction> getter) {
1304 // ----------- S t a t e -------------
1305 // -- a0 : receiver
1306 // -- a2 : name
1307 // -- ra : return address
1308 // -----------------------------------
1309 {
1310 FrameScope scope(masm, StackFrame::INTERNAL);
1311
1312 if (!getter.is_null()) {
1313 // Call the JavaScript getter with the receiver on the stack.
bmeurer@chromium.org25530ce2014-02-07 09:11:16 +00001314 if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) {
1315 // Swap in the global receiver.
1316 __ lw(receiver,
1317 FieldMemOperand(
1318 receiver, JSGlobalObject::kGlobalReceiverOffset));
1319 }
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001320 __ push(receiver);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001321 ParameterCount actual(0);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001322 ParameterCount expected(getter);
1323 __ InvokeFunction(getter, expected, actual,
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00001324 CALL_FUNCTION, NullCallWrapper());
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001325 } else {
1326 // If we generate a global code snippet for deoptimization only, remember
1327 // the place to continue after deoptimization.
1328 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
1329 }
1330
1331 // Restore context register.
1332 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
1333 }
1334 __ Ret();
1335}
1336
1337
1338#undef __
1339#define __ ACCESS_MASM(masm())
1340
1341
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00001342Handle<Code> LoadStubCompiler::CompileLoadGlobal(
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +00001343 Handle<HeapType> type,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001344 Handle<GlobalObject> global,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001345 Handle<PropertyCell> cell,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001346 Handle<Name> name,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00001347 bool is_dont_delete) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001348 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001349
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001350 HandlerFrontendHeader(type, receiver(), global, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001351
1352 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00001353 __ li(a3, Operand(cell));
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00001354 __ lw(t0, FieldMemOperand(a3, Cell::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001355
1356 // Check for deleted property if property can actually be deleted.
1357 if (!is_dont_delete) {
1358 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
1359 __ Branch(&miss, eq, t0, Operand(at));
1360 }
1361
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001362 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001363 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001364 __ Ret(USE_DELAY_SLOT);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001365 __ mov(v0, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001366
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00001367 HandlerFrontendFooter(name, &miss);
1368
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001369 // Return the generated code.
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001370 return GetCode(kind(), Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001371}
1372
1373
danno@chromium.orgbee51992013-07-10 14:57:15 +00001374Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC(
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00001375 TypeHandleList* types,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001376 CodeHandleList* handlers,
1377 Handle<Name> name,
1378 Code::StubType type,
1379 IcCheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001380 Label miss;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001381
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00001382 if (check == PROPERTY &&
1383 (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC)) {
1384 __ Branch(&miss, ne, this->name(), Operand(name));
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001385 }
1386
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001387 Label number_case;
machenbach@chromium.org3a9c5d92014-02-21 08:10:27 +00001388 Register match = scratch1();
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00001389 Label* smi_target = IncludesNumberType(types) ? &number_case : &miss;
machenbach@chromium.org3a9c5d92014-02-21 08:10:27 +00001390 __ JumpIfSmi(receiver(), smi_target, match); // Reg match is 0 if Smi.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001391
machenbach@chromium.org3a9c5d92014-02-21 08:10:27 +00001392 Register map_reg = scratch2();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001393
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00001394 int receiver_count = types->length();
danno@chromium.orgf005df62013-04-30 16:36:45 +00001395 int number_of_handled_maps = 0;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001396 __ lw(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00001397 for (int current = 0; current < receiver_count; ++current) {
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +00001398 Handle<HeapType> type = types->at(current);
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00001399 Handle<Map> map = IC::TypeToMap(*type, isolate());
danno@chromium.orgf005df62013-04-30 16:36:45 +00001400 if (!map->is_deprecated()) {
1401 number_of_handled_maps++;
machenbach@chromium.org3a9c5d92014-02-21 08:10:27 +00001402 // Check map and tail call if there's a match.
1403 // Separate compare from branch, to provide path for above JumpIfSmi().
1404 __ Subu(match, map_reg, Operand(map));
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +00001405 if (type->Is(HeapType::Number())) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001406 ASSERT(!number_case.is_unused());
1407 __ bind(&number_case);
1408 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00001409 __ Jump(handlers->at(current), RelocInfo::CODE_TARGET,
machenbach@chromium.org3a9c5d92014-02-21 08:10:27 +00001410 eq, match, Operand(zero_reg));
danno@chromium.orgf005df62013-04-30 16:36:45 +00001411 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00001412 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00001413 ASSERT(number_of_handled_maps != 0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001414
1415 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001416 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001417
1418 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001419 InlineCacheState state =
danno@chromium.orgf005df62013-04-30 16:36:45 +00001420 number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001421 return GetICCode(kind(), type, name, state);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001422}
1423
1424
machenbach@chromium.org2904d1a2014-03-18 01:05:18 +00001425void StoreStubCompiler::GenerateStoreArrayLength() {
1426 // Prepare tail call to StoreIC_ArrayLength.
1427 __ Push(receiver(), value());
1428
1429 ExternalReference ref =
1430 ExternalReference(IC_Utility(IC::kStoreIC_ArrayLength),
1431 masm()->isolate());
1432 __ TailCallExternalReference(ref, 2, 1);
1433}
1434
1435
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00001436Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
1437 MapHandleList* receiver_maps,
1438 CodeHandleList* handler_stubs,
1439 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00001440 Label miss;
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00001441 __ JumpIfSmi(receiver(), &miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001442
1443 int receiver_count = receiver_maps->length();
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00001444 __ lw(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001445 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00001446 if (transitioned_maps->at(i).is_null()) {
1447 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00001448 scratch1(), Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001449 } else {
1450 Label next_map;
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00001451 __ Branch(&next_map, ne, scratch1(), Operand(receiver_maps->at(i)));
1452 __ li(transition_map(), Operand(transitioned_maps->at(i)));
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00001453 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001454 __ bind(&next_map);
1455 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00001456 }
1457
1458 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001459 TailCallBuiltin(masm(), MissBuiltin(kind()));
danno@chromium.org40cb8782011-05-25 07:58:50 +00001460
1461 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001462 return GetICCode(
1463 kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001464}
1465
1466
danno@chromium.org40cb8782011-05-25 07:58:50 +00001467#undef __
1468#define __ ACCESS_MASM(masm)
1469
1470
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001471void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
1472 MacroAssembler* masm) {
1473 // ---------- S t a t e --------------
1474 // -- ra : return address
1475 // -- a0 : key
1476 // -- a1 : receiver
1477 // -----------------------------------
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00001478 Label slow, miss;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001479
1480 Register key = a0;
1481 Register receiver = a1;
1482
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00001483 __ JumpIfNotSmi(key, &miss);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001484 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
1485 __ sra(a2, a0, kSmiTagSize);
1486 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
1487 __ Ret();
1488
1489 // Slow case, key and receiver still in a0 and a1.
1490 __ bind(&slow);
1491 __ IncrementCounter(
1492 masm->isolate()->counters()->keyed_load_external_array_slow(),
1493 1, a2, a3);
1494 // Entry registers are intact.
1495 // ---------- S t a t e --------------
1496 // -- ra : return address
1497 // -- a0 : key
1498 // -- a1 : receiver
1499 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001500 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001501
1502 // Miss case, call the runtime.
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00001503 __ bind(&miss);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001504
1505 // ---------- S t a t e --------------
1506 // -- ra : return address
1507 // -- a0 : key
1508 // -- a1 : receiver
1509 // -----------------------------------
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00001510 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001511}
1512
1513
ager@chromium.org5c838252010-02-19 08:53:10 +00001514#undef __
1515
1516} } // namespace v8::internal
1517
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001518#endif // V8_TARGET_ARCH_MIPS