blob: 7cfef6a1b4161b554d3bf14743741f0796daeb37 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2014 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005#if V8_TARGET_ARCH_ARM64
6
7#include "src/ic/call-optimization.h"
8#include "src/ic/handler-compiler.h"
9#include "src/ic/ic.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010#include "src/isolate-inl.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011
12namespace v8 {
13namespace internal {
14
15#define __ ACCESS_MASM(masm)
16
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017void PropertyHandlerCompiler::PushVectorAndSlot(Register vector,
18 Register slot) {
19 MacroAssembler* masm = this->masm();
20 __ Push(vector);
21 __ Push(slot);
22}
23
24
25void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) {
26 MacroAssembler* masm = this->masm();
27 __ Pop(slot);
28 __ Pop(vector);
29}
30
31
32void PropertyHandlerCompiler::DiscardVectorAndSlot() {
33 MacroAssembler* masm = this->masm();
34 // Remove vector and slot.
35 __ Drop(2);
36}
37
Ben Murdochb8a8cc12014-11-26 15:28:44 +000038
39void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
40 MacroAssembler* masm, Label* miss_label, Register receiver,
41 Handle<Name> name, Register scratch0, Register scratch1) {
42 DCHECK(!AreAliased(receiver, scratch0, scratch1));
43 DCHECK(name->IsUniqueName());
44 Counters* counters = masm->isolate()->counters();
45 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
46 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
47
48 Label done;
49
50 const int kInterceptorOrAccessCheckNeededMask =
51 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
52
53 // Bail out if the receiver has a named interceptor or requires access checks.
54 Register map = scratch1;
55 __ Ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
56 __ Ldrb(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
57 __ Tst(scratch0, kInterceptorOrAccessCheckNeededMask);
58 __ B(ne, miss_label);
59
60 // Check that receiver is a JSObject.
61 __ Ldrb(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000062 __ Cmp(scratch0, FIRST_JS_RECEIVER_TYPE);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000063 __ B(lt, miss_label);
64
65 // Load properties array.
66 Register properties = scratch0;
67 __ Ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
68 // Check that the properties array is a dictionary.
69 __ Ldr(map, FieldMemOperand(properties, HeapObject::kMapOffset));
70 __ JumpIfNotRoot(map, Heap::kHashTableMapRootIndex, miss_label);
71
72 NameDictionaryLookupStub::GenerateNegativeLookup(
73 masm, miss_label, &done, receiver, properties, name, scratch1);
74 __ Bind(&done);
75 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
76}
77
78
79void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040080 MacroAssembler* masm, int index, Register result, Label* miss) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000081 __ LoadNativeContextSlot(index, result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000082 // Load its initial map. The global functions all have initial maps.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040083 __ Ldr(result,
84 FieldMemOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000085 // Load the prototype from the initial map.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040086 __ Ldr(result, FieldMemOperand(result, Map::kPrototypeOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000087}
88
89
90void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
91 MacroAssembler* masm, Register receiver, Register scratch1,
92 Register scratch2, Label* miss_label) {
93 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
94 // TryGetFunctionPrototype can't put the result directly in x0 because the
95 // 3 inputs registers can't alias and we call this function from
96 // LoadIC::GenerateFunctionPrototype, where receiver is x0. So we explicitly
97 // move the result in x0.
98 __ Mov(x0, scratch1);
99 __ Ret();
100}
101
102
103// Generate code to check that a global property cell is empty. Create
104// the property cell at compilation time if no cell exists for the
105// property.
106void PropertyHandlerCompiler::GenerateCheckPropertyCell(
107 MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
108 Register scratch, Label* miss) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000109 Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000110 DCHECK(cell->value()->IsTheHole());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000111 Handle<WeakCell> weak_cell = masm->isolate()->factory()->NewWeakCell(cell);
112 __ LoadWeakValue(scratch, weak_cell, miss);
113 __ Ldr(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000114 __ JumpIfNotRoot(scratch, Heap::kTheHoleValueRootIndex, miss);
115}
116
117
118static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
119 Register holder, Register name,
120 Handle<JSObject> holder_obj) {
121 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000122 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
123 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
124 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000125
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000126 __ Push(name, receiver, holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000127}
128
129
130static void CompileCallLoadPropertyWithInterceptor(
131 MacroAssembler* masm, Register receiver, Register holder, Register name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000132 Handle<JSObject> holder_obj, Runtime::FunctionId id) {
133 DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
134 Runtime::FunctionForId(id)->nargs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000135 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000136 __ CallRuntime(id);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000137}
138
139
140// Generate call to api function.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000141void PropertyHandlerCompiler::GenerateApiAccessorCall(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000142 MacroAssembler* masm, const CallOptimization& optimization,
143 Handle<Map> receiver_map, Register receiver, Register scratch,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000144 bool is_store, Register store_parameter, Register accessor_holder,
145 int accessor_index) {
146 DCHECK(!AreAliased(accessor_holder, scratch));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000147 DCHECK(!AreAliased(receiver, scratch));
148
149 MacroAssembler::PushPopQueue queue(masm);
150 queue.Queue(receiver);
151 // Write the arguments to the stack frame.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000152 if (is_store) {
153 DCHECK(!receiver.is(store_parameter));
154 DCHECK(!scratch.is(store_parameter));
155 queue.Queue(store_parameter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000156 }
157 queue.PushQueued();
158
159 DCHECK(optimization.is_simple_api_call());
160
161 // Abi for CallApiFunctionStub.
162 Register callee = x0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000163 Register data = x4;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000164 Register holder = x2;
165 Register api_function_address = x1;
166
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000167 // Put callee in place.
168 __ LoadAccessor(callee, accessor_holder, accessor_index,
169 is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
170
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000171 // Put holder in place.
172 CallOptimization::HolderLookup holder_lookup;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000173 int holder_depth = 0;
174 optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup,
175 &holder_depth);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000176 switch (holder_lookup) {
177 case CallOptimization::kHolderIsReceiver:
178 __ Mov(holder, receiver);
179 break;
180 case CallOptimization::kHolderFound:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000181 __ Ldr(holder, FieldMemOperand(receiver, HeapObject::kMapOffset));
182 __ Ldr(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
183 for (int i = 1; i < holder_depth; i++) {
184 __ Ldr(holder, FieldMemOperand(holder, HeapObject::kMapOffset));
185 __ Ldr(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
186 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000187 break;
188 case CallOptimization::kHolderNotFound:
189 UNREACHABLE();
190 break;
191 }
192
193 Isolate* isolate = masm->isolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000194 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000195 bool call_data_undefined = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000196 // Put call data in place.
197 if (api_call_info->data()->IsUndefined()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000198 call_data_undefined = true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000199 __ LoadRoot(data, Heap::kUndefinedValueRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000200 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000201 __ Ldr(data,
202 FieldMemOperand(callee, JSFunction::kSharedFunctionInfoOffset));
203 __ Ldr(data,
204 FieldMemOperand(data, SharedFunctionInfo::kFunctionDataOffset));
205 __ Ldr(data, FieldMemOperand(data, FunctionTemplateInfo::kCallCodeOffset));
206 __ Ldr(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset));
207 }
208
209 if (api_call_info->fast_handler()->IsCode()) {
210 // Just tail call into the fast handler if present.
211 __ Jump(handle(Code::cast(api_call_info->fast_handler())),
212 RelocInfo::CODE_TARGET);
213 return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000214 }
215
216 // Put api_function_address in place.
217 Address function_address = v8::ToCData<Address>(api_call_info->callback());
218 ApiFunction fun(function_address);
219 ExternalReference ref = ExternalReference(
220 &fun, ExternalReference::DIRECT_API_CALL, masm->isolate());
221 __ Mov(api_function_address, ref);
222
223 // Jump to stub.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000224 CallApiAccessorStub stub(isolate, is_store, call_data_undefined);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000225 __ TailCallStub(&stub);
226}
227
228
229void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000230 MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
231 int accessor_index, int expected_arguments, Register scratch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000232 // ----------- S t a t e -------------
233 // -- lr : return address
234 // -----------------------------------
235 Label miss;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000236 {
237 FrameScope scope(masm, StackFrame::INTERNAL);
238
239 // Save value register, so we can restore it later.
240 __ Push(value());
241
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000242 if (accessor_index >= 0) {
243 DCHECK(!AreAliased(holder, scratch));
244 DCHECK(!AreAliased(receiver, scratch));
245 DCHECK(!AreAliased(value(), scratch));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000246 // Call the JavaScript setter with receiver and value on the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000247 if (map->IsJSGlobalObjectMap()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000248 // Swap in the global receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000249 __ Ldr(scratch,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000250 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000251 receiver = scratch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000252 }
253 __ Push(receiver, value());
254 ParameterCount actual(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000255 ParameterCount expected(expected_arguments);
256 __ LoadAccessor(x1, holder, accessor_index, ACCESSOR_SETTER);
257 __ InvokeFunction(x1, expected, actual, CALL_FUNCTION,
258 CheckDebugStepCallWrapper());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000259 } else {
260 // If we generate a global code snippet for deoptimization only, remember
261 // the place to continue after deoptimization.
262 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
263 }
264
265 // We have to return the passed value, not the return value of the setter.
266 __ Pop(x0);
267
268 // Restore context register.
269 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
270 }
271 __ Ret();
272}
273
274
275void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000276 MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
277 int accessor_index, int expected_arguments, Register scratch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000278 {
279 FrameScope scope(masm, StackFrame::INTERNAL);
280
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000281 if (accessor_index >= 0) {
282 DCHECK(!AreAliased(holder, scratch));
283 DCHECK(!AreAliased(receiver, scratch));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000284 // Call the JavaScript getter with the receiver on the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000285 if (map->IsJSGlobalObjectMap()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000286 // Swap in the global receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000287 __ Ldr(scratch,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000288 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000289 receiver = scratch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000290 }
291 __ Push(receiver);
292 ParameterCount actual(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000293 ParameterCount expected(expected_arguments);
294 __ LoadAccessor(x1, holder, accessor_index, ACCESSOR_GETTER);
295 __ InvokeFunction(x1, expected, actual, CALL_FUNCTION,
296 CheckDebugStepCallWrapper());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000297 } else {
298 // If we generate a global code snippet for deoptimization only, remember
299 // the place to continue after deoptimization.
300 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
301 }
302
303 // Restore context register.
304 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
305 }
306 __ Ret();
307}
308
309
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000310static void StoreIC_PushArgs(MacroAssembler* masm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000311 __ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000312 StoreDescriptor::ValueRegister(),
313 VectorStoreICDescriptor::SlotRegister(),
314 VectorStoreICDescriptor::VectorRegister());
315}
316
317
318void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
319 StoreIC_PushArgs(masm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000320
321 // The slow case calls into the runtime to complete the store without causing
322 // an IC miss that would otherwise cause a transition to the generic stub.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000323 __ TailCallRuntime(Runtime::kStoreIC_Slow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000324}
325
326
327void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) {
328 ASM_LOCATION("ElementHandlerCompiler::GenerateStoreSlow");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000329 StoreIC_PushArgs(masm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000330
331 // The slow case calls into the runtime to complete the store without causing
332 // an IC miss that would otherwise cause a transition to the generic stub.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000333 __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000334}
335
336
337#undef __
338#define __ ACCESS_MASM(masm())
339
340
341Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
342 Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
343 Label miss;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400344 if (IC::ICUseVector(kind())) {
345 PushVectorAndSlot();
346 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000347 FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000348
349 // Get the value from the cell.
350 Register result = StoreDescriptor::ValueRegister();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400351 Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
352 __ LoadWeakValue(result, weak_cell, &miss);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000353 __ Ldr(result, FieldMemOperand(result, PropertyCell::kValueOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000354
355 // Check for deleted property if property can actually be deleted.
356 if (is_configurable) {
357 __ JumpIfRoot(result, Heap::kTheHoleValueRootIndex, &miss);
358 }
359
360 Counters* counters = isolate()->counters();
361 __ IncrementCounter(counters->named_load_global_stub(), 1, x1, x3);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400362 if (IC::ICUseVector(kind())) {
363 DiscardVectorAndSlot();
364 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000365 __ Ret();
366
367 FrontendFooter(name, &miss);
368
369 // Return the generated code.
370 return GetCode(kind(), Code::NORMAL, name);
371}
372
373
374Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor(
375 Handle<Name> name) {
376 Label miss;
377
378 ASM_LOCATION("NamedStoreHandlerCompiler::CompileStoreInterceptor");
379
380 __ Push(receiver(), this->name(), value());
381
382 // Do tail-call to the runtime system.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000383 __ TailCallRuntime(Runtime::kStorePropertyWithInterceptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000384
385 // Return the generated code.
386 return GetCode(kind(), Code::FAST, name);
387}
388
389
390Register NamedStoreHandlerCompiler::value() {
391 return StoreDescriptor::ValueRegister();
392}
393
394
395void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
396 Handle<Name> name) {
397 if (!label->is_unused()) {
398 __ Bind(label);
399 __ Mov(this->name(), Operand(name));
400 }
401}
402
403
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400404void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
405 __ Mov(this->name(), Operand(name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000406}
407
408
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000409void NamedStoreHandlerCompiler::RearrangeVectorAndSlot(
410 Register current_map, Register destination_map) {
411 DCHECK(false); // Not implemented.
412}
413
414
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400415void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000416 Register map_reg,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400417 Register scratch,
418 Label* miss) {
419 Handle<WeakCell> cell = Map::WeakCellForMap(transition);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400420 DCHECK(!map_reg.is(scratch));
421 __ LoadWeakValue(map_reg, cell, miss);
422 if (transition->CanBeDeprecated()) {
423 __ Ldrsw(scratch, FieldMemOperand(map_reg, Map::kBitField3Offset));
424 __ TestAndBranchIfAnySet(scratch, Map::Deprecated::kMask, miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000425 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400426}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000427
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400428
429void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
430 int descriptor,
431 Register value_reg,
432 Register scratch,
433 Label* miss_label) {
434 DCHECK(!map_reg.is(scratch));
435 DCHECK(!map_reg.is(value_reg));
436 DCHECK(!value_reg.is(scratch));
437 __ LoadInstanceDescriptors(map_reg, scratch);
438 __ Ldr(scratch,
439 FieldMemOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
440 __ Cmp(value_reg, scratch);
441 __ B(ne, miss_label);
442}
443
444
445void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(HeapType* field_type,
446 Register value_reg,
447 Label* miss_label) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000448 Register map_reg = scratch1();
449 Register scratch = scratch2();
450 DCHECK(!value_reg.is(map_reg));
451 DCHECK(!value_reg.is(scratch));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400452 __ JumpIfSmi(value_reg, miss_label);
453 HeapType::Iterator<Map> it = field_type->Classes();
454 if (!it.Done()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000455 __ Ldr(map_reg, FieldMemOperand(value_reg, HeapObject::kMapOffset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400456 Label do_store;
457 while (true) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000458 __ CmpWeakValue(map_reg, Map::WeakCellForMap(it.Current()), scratch);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400459 it.Advance();
460 if (it.Done()) {
461 __ B(ne, miss_label);
462 break;
463 }
464 __ B(eq, &do_store);
465 }
466 __ Bind(&do_store);
467 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000468}
469
470
471Register PropertyHandlerCompiler::CheckPrototypes(
472 Register object_reg, Register holder_reg, Register scratch1,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000473 Register scratch2, Handle<Name> name, Label* miss, PrototypeCheckType check,
474 ReturnHolder return_what) {
475 Handle<Map> receiver_map = map();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000476
477 // object_reg and holder_reg registers can alias.
478 DCHECK(!AreAliased(object_reg, scratch1, scratch2));
479 DCHECK(!AreAliased(holder_reg, scratch1, scratch2));
480
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000481 if (FLAG_eliminate_prototype_chain_checks) {
482 Handle<Cell> validity_cell =
483 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
484 if (!validity_cell.is_null()) {
485 DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid),
486 validity_cell->value());
487 __ Mov(scratch1, Operand(validity_cell));
488 __ Ldr(scratch1, FieldMemOperand(scratch1, Cell::kValueOffset));
489 __ Cmp(scratch1, Operand(Smi::FromInt(Map::kPrototypeChainValid)));
490 __ B(ne, miss);
491 }
492
493 // The prototype chain of primitives (and their JSValue wrappers) depends
494 // on the native context, which can't be guarded by validity cells.
495 // |object_reg| holds the native context specific prototype in this case;
496 // we need to check its map.
497 if (check == CHECK_ALL_MAPS) {
498 __ Ldr(scratch1, FieldMemOperand(object_reg, HeapObject::kMapOffset));
499 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
500 __ CmpWeakValue(scratch1, cell, scratch2);
501 __ B(ne, miss);
502 }
503 }
504
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000505 // Keep track of the current object in register reg.
506 Register reg = object_reg;
507 int depth = 0;
508
509 Handle<JSObject> current = Handle<JSObject>::null();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000510 if (receiver_map->IsJSGlobalObjectMap()) {
511 current = isolate()->global_object();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000512 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000513
514 // Check access rights to the global object. This has to happen after
515 // the map check so that we know that the object is actually a global
516 // object.
517 // This allows us to install generated handlers for accesses to the
518 // global proxy (as opposed to using slow ICs). See corresponding code
519 // in LookupForRead().
520 if (receiver_map->IsJSGlobalProxyMap()) {
521 UseScratchRegisterScope temps(masm());
522 __ CheckAccessGlobalProxy(reg, scratch2, temps.AcquireX(), miss);
523 }
524
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000525 Handle<JSObject> prototype = Handle<JSObject>::null();
526 Handle<Map> current_map = receiver_map;
527 Handle<Map> holder_map(holder()->map());
528 // Traverse the prototype chain and check the maps in the prototype chain for
529 // fast and global objects or do negative lookup for normal objects.
530 while (!current_map.is_identical_to(holder_map)) {
531 ++depth;
532
533 // Only global objects and objects that do not require access
534 // checks are allowed in stubs.
535 DCHECK(current_map->IsJSGlobalProxyMap() ||
536 !current_map->is_access_check_needed());
537
538 prototype = handle(JSObject::cast(current_map->prototype()));
539 if (current_map->is_dictionary_map() &&
540 !current_map->IsJSGlobalObjectMap()) {
541 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
542 if (!name->IsUniqueName()) {
543 DCHECK(name->IsString());
544 name = factory()->InternalizeString(Handle<String>::cast(name));
545 }
546 DCHECK(current.is_null() || (current->property_dictionary()->FindEntry(
547 name) == NameDictionary::kNotFound));
548
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000549 if (FLAG_eliminate_prototype_chain_checks && depth > 1) {
550 // TODO(jkummerow): Cache and re-use weak cell.
551 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
552 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000553 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
554 scratch2);
555
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000556 if (!FLAG_eliminate_prototype_chain_checks) {
557 __ Ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
558 __ Ldr(holder_reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
559 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000560 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000561 Register map_reg = scratch1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000562 if (!FLAG_eliminate_prototype_chain_checks) {
563 __ Ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
564 }
565 if (current_map->IsJSGlobalObjectMap()) {
566 GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
567 name, scratch2, miss);
568 } else if (!FLAG_eliminate_prototype_chain_checks &&
569 (depth != 1 || check == CHECK_ALL_MAPS)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400570 Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
571 __ CmpWeakValue(map_reg, cell, scratch2);
572 __ B(ne, miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000573 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000574 if (!FLAG_eliminate_prototype_chain_checks) {
575 __ Ldr(holder_reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000576 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000577 }
578
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000579 reg = holder_reg; // From now on the object will be in holder_reg.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000580 // Go to the next object in the prototype chain.
581 current = prototype;
582 current_map = handle(current->map());
583 }
584
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000585 DCHECK(!current_map->IsJSGlobalProxyMap());
586
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000587 // Log the check depth.
588 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
589
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000590 if (!FLAG_eliminate_prototype_chain_checks &&
591 (depth != 0 || check == CHECK_ALL_MAPS)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000592 // Check the holder map.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400593 __ Ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
594 Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
595 __ CmpWeakValue(scratch1, cell, scratch2);
596 __ B(ne, miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000597 }
598
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000599 bool return_holder = return_what == RETURN_HOLDER;
600 if (FLAG_eliminate_prototype_chain_checks && return_holder && depth != 0) {
601 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000602 }
603
604 // Return the register containing the holder.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000605 return return_holder ? reg : no_reg;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000606}
607
608
609void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
610 if (!miss->is_unused()) {
611 Label success;
612 __ B(&success);
613
614 __ Bind(miss);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400615 if (IC::ICUseVector(kind())) {
616 DCHECK(kind() == Code::LOAD_IC);
617 PopVectorAndSlot();
618 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000619 TailCallBuiltin(masm(), MissBuiltin(kind()));
620
621 __ Bind(&success);
622 }
623}
624
625
626void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
627 if (!miss->is_unused()) {
628 Label success;
629 __ B(&success);
630
631 GenerateRestoreName(miss, name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000632 if (IC::ICUseVector(kind())) PopVectorAndSlot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000633 TailCallBuiltin(masm(), MissBuiltin(kind()));
634
635 __ Bind(&success);
636 }
637}
638
639
640void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
641 // Return the constant value.
642 __ LoadObject(x0, value);
643 __ Ret();
644}
645
646
647void NamedLoadHandlerCompiler::GenerateLoadCallback(
648 Register reg, Handle<ExecutableAccessorInfo> callback) {
649 DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), reg));
650
651 // Build ExecutableAccessorInfo::args_ list on the stack and push property
652 // name below the exit frame to make GC aware of them and store pointers to
653 // them.
654 STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0);
655 STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1);
656 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2);
657 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3);
658 STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4);
659 STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5);
660 STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6);
661
662 __ Push(receiver());
663
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000664 Handle<Object> data(callback->data(), isolate());
665 if (data->IsUndefined() || data->IsSmi()) {
666 __ Mov(scratch3(), Operand(data));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000667 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000668 Handle<WeakCell> cell =
669 isolate()->factory()->NewWeakCell(Handle<HeapObject>::cast(data));
670 // The callback is alive if this instruction is executed,
671 // so the weak cell is not cleared and points to data.
672 __ GetWeakValue(scratch3(), cell);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000673 }
674 __ LoadRoot(scratch4(), Heap::kUndefinedValueRootIndex);
675 __ Mov(scratch2(), Operand(ExternalReference::isolate_address(isolate())));
676 __ Push(scratch3(), scratch4(), scratch4(), scratch2(), reg, name());
677
678 Register args_addr = scratch2();
679 __ Add(args_addr, __ StackPointer(), kPointerSize);
680
681 // Stack at this point:
682 // sp[40] callback data
683 // sp[32] undefined
684 // sp[24] undefined
685 // sp[16] isolate
686 // args_addr -> sp[8] reg
687 // sp[0] name
688
689 // Abi for CallApiGetter.
690 Register getter_address_reg = x2;
691
692 // Set up the call.
693 Address getter_address = v8::ToCData<Address>(callback->getter());
694 ApiFunction fun(getter_address);
695 ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
696 ExternalReference ref = ExternalReference(&fun, type, isolate());
697 __ Mov(getter_address_reg, ref);
698
699 CallApiGetterStub stub(isolate());
700 __ TailCallStub(&stub);
701}
702
703
704void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
705 LookupIterator* it, Register holder_reg) {
706 DCHECK(!AreAliased(receiver(), this->name(), scratch1(), scratch2(),
707 scratch3()));
708 DCHECK(holder()->HasNamedInterceptor());
709 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
710
711 // Compile the interceptor call, followed by inline code to load the
712 // property from further up the prototype chain if the call fails.
713 // Check that the maps haven't changed.
714 DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
715
716 // Preserve the receiver register explicitly whenever it is different from the
717 // holder and it is needed should the interceptor return without any result.
718 // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
719 // case might cause a miss during the prototype check.
720 bool must_perform_prototype_check =
721 !holder().is_identical_to(it->GetHolder<JSObject>());
722 bool must_preserve_receiver_reg =
723 !receiver().is(holder_reg) &&
724 (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
725
726 // Save necessary data before invoking an interceptor.
727 // Requires a frame to make GC aware of pushed pointers.
728 {
729 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
730 if (must_preserve_receiver_reg) {
731 __ Push(receiver(), holder_reg, this->name());
732 } else {
733 __ Push(holder_reg, this->name());
734 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400735 InterceptorVectorSlotPush(holder_reg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000736 // Invoke an interceptor. Note: map checks from receiver to
737 // interceptor's holder has been compiled before (see a caller
738 // of this method.)
739 CompileCallLoadPropertyWithInterceptor(
740 masm(), receiver(), holder_reg, this->name(), holder(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000741 Runtime::kLoadPropertyWithInterceptorOnly);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000742
743 // Check if interceptor provided a value for property. If it's
744 // the case, return immediately.
745 Label interceptor_failed;
746 __ JumpIfRoot(x0, Heap::kNoInterceptorResultSentinelRootIndex,
747 &interceptor_failed);
748 frame_scope.GenerateLeaveFrame();
749 __ Ret();
750
751 __ Bind(&interceptor_failed);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400752 InterceptorVectorSlotPop(holder_reg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000753 if (must_preserve_receiver_reg) {
754 __ Pop(this->name(), holder_reg, receiver());
755 } else {
756 __ Pop(this->name(), holder_reg);
757 }
758 // Leave the internal frame.
759 }
760
761 GenerateLoadPostInterceptor(it, holder_reg);
762}
763
764
765void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
766 // Call the runtime system to load the interceptor.
767 DCHECK(holder()->HasNamedInterceptor());
768 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
769 PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
770 holder());
771
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000772 __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000773}
774
775
776Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
777 Handle<JSObject> object, Handle<Name> name,
778 Handle<ExecutableAccessorInfo> callback) {
779 ASM_LOCATION("NamedStoreHandlerCompiler::CompileStoreCallback");
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400780 Register holder_reg = Frontend(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000781
782 // Stub never generated for non-global objects that require access checks.
783 DCHECK(holder()->IsJSGlobalProxy() || !holder()->IsAccessCheckNeeded());
784
785 // receiver() and holder_reg can alias.
786 DCHECK(!AreAliased(receiver(), scratch1(), scratch2(), value()));
787 DCHECK(!AreAliased(holder_reg, scratch1(), scratch2(), value()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000788 // If the callback cannot leak, then push the callback directly,
789 // otherwise wrap it in a weak cell.
790 if (callback->data()->IsUndefined() || callback->data()->IsSmi()) {
791 __ Mov(scratch1(), Operand(callback));
792 } else {
793 Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
794 __ Mov(scratch1(), Operand(cell));
795 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000796 __ Mov(scratch2(), Operand(name));
797 __ Push(receiver(), holder_reg, scratch1(), scratch2(), value());
798
799 // Do tail-call to the runtime system.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000800 __ TailCallRuntime(Runtime::kStoreCallbackProperty);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000801
802 // Return the generated code.
803 return GetCode(kind(), Code::FAST, name);
804}
805
806
807#undef __
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000808} // namespace internal
809} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000810
811#endif // V8_TARGET_ARCH_IA32