blob: 51ae3b50cf1776d25680e75737d1cfcaba6ea134 [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
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007#include "src/ic/handler-compiler.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +01008
9#include "src/field-type.h"
10#include "src/ic/call-optimization.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011#include "src/ic/ic.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012#include "src/isolate-inl.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013
14namespace v8 {
15namespace internal {
16
17#define __ ACCESS_MASM(masm)
18
Emily Bernierd0a1eb72015-03-24 16:35:39 -040019void PropertyHandlerCompiler::PushVectorAndSlot(Register vector,
20 Register slot) {
21 MacroAssembler* masm = this->masm();
22 __ Push(vector);
23 __ Push(slot);
24}
25
26
27void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) {
28 MacroAssembler* masm = this->masm();
29 __ Pop(slot);
30 __ Pop(vector);
31}
32
33
34void PropertyHandlerCompiler::DiscardVectorAndSlot() {
35 MacroAssembler* masm = this->masm();
36 // Remove vector and slot.
37 __ Drop(2);
38}
39
Ben Murdochb8a8cc12014-11-26 15:28:44 +000040
41void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
42 MacroAssembler* masm, Label* miss_label, Register receiver,
43 Handle<Name> name, Register scratch0, Register scratch1) {
44 DCHECK(!AreAliased(receiver, scratch0, scratch1));
45 DCHECK(name->IsUniqueName());
46 Counters* counters = masm->isolate()->counters();
47 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
48 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
49
50 Label done;
51
52 const int kInterceptorOrAccessCheckNeededMask =
53 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
54
55 // Bail out if the receiver has a named interceptor or requires access checks.
56 Register map = scratch1;
57 __ Ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
58 __ Ldrb(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
59 __ Tst(scratch0, kInterceptorOrAccessCheckNeededMask);
60 __ B(ne, miss_label);
61
62 // Check that receiver is a JSObject.
63 __ Ldrb(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000064 __ Cmp(scratch0, FIRST_JS_RECEIVER_TYPE);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000065 __ B(lt, miss_label);
66
67 // Load properties array.
68 Register properties = scratch0;
69 __ Ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
70 // Check that the properties array is a dictionary.
71 __ Ldr(map, FieldMemOperand(properties, HeapObject::kMapOffset));
72 __ JumpIfNotRoot(map, Heap::kHashTableMapRootIndex, miss_label);
73
74 NameDictionaryLookupStub::GenerateNegativeLookup(
75 masm, miss_label, &done, receiver, properties, name, scratch1);
76 __ Bind(&done);
77 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
78}
79
80
81void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040082 MacroAssembler* masm, int index, Register result, Label* miss) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000083 __ LoadNativeContextSlot(index, result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000084 // Load its initial map. The global functions all have initial maps.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040085 __ Ldr(result,
86 FieldMemOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000087 // Load the prototype from the initial map.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040088 __ Ldr(result, FieldMemOperand(result, Map::kPrototypeOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000089}
90
91
92void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
93 MacroAssembler* masm, Register receiver, Register scratch1,
94 Register scratch2, Label* miss_label) {
95 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
96 // TryGetFunctionPrototype can't put the result directly in x0 because the
97 // 3 inputs registers can't alias and we call this function from
98 // LoadIC::GenerateFunctionPrototype, where receiver is x0. So we explicitly
99 // move the result in x0.
100 __ Mov(x0, scratch1);
101 __ Ret();
102}
103
104
105// Generate code to check that a global property cell is empty. Create
106// the property cell at compilation time if no cell exists for the
107// property.
108void PropertyHandlerCompiler::GenerateCheckPropertyCell(
109 MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
110 Register scratch, Label* miss) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000111 Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000112 DCHECK(cell->value()->IsTheHole());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000113 Handle<WeakCell> weak_cell = masm->isolate()->factory()->NewWeakCell(cell);
114 __ LoadWeakValue(scratch, weak_cell, miss);
115 __ Ldr(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000116 __ JumpIfNotRoot(scratch, Heap::kTheHoleValueRootIndex, miss);
117}
118
119
120static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
121 Register holder, Register name,
122 Handle<JSObject> holder_obj) {
123 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000124 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
125 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
126 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000127
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000128 __ Push(name, receiver, holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000129}
130
131
132static void CompileCallLoadPropertyWithInterceptor(
133 MacroAssembler* masm, Register receiver, Register holder, Register name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000134 Handle<JSObject> holder_obj, Runtime::FunctionId id) {
135 DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
136 Runtime::FunctionForId(id)->nargs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000137 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000138 __ CallRuntime(id);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000139}
140
141
142// Generate call to api function.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000143void PropertyHandlerCompiler::GenerateApiAccessorCall(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000144 MacroAssembler* masm, const CallOptimization& optimization,
145 Handle<Map> receiver_map, Register receiver, Register scratch,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000146 bool is_store, Register store_parameter, Register accessor_holder,
147 int accessor_index) {
148 DCHECK(!AreAliased(accessor_holder, scratch));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000149 DCHECK(!AreAliased(receiver, scratch));
150
151 MacroAssembler::PushPopQueue queue(masm);
152 queue.Queue(receiver);
153 // Write the arguments to the stack frame.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000154 if (is_store) {
155 DCHECK(!receiver.is(store_parameter));
156 DCHECK(!scratch.is(store_parameter));
157 queue.Queue(store_parameter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000158 }
159 queue.PushQueued();
160
161 DCHECK(optimization.is_simple_api_call());
162
163 // Abi for CallApiFunctionStub.
164 Register callee = x0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000165 Register data = x4;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000166 Register holder = x2;
167 Register api_function_address = x1;
168
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000169 // Put callee in place.
170 __ LoadAccessor(callee, accessor_holder, accessor_index,
171 is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
172
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000173 // Put holder in place.
174 CallOptimization::HolderLookup holder_lookup;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000175 int holder_depth = 0;
176 optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup,
177 &holder_depth);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000178 switch (holder_lookup) {
179 case CallOptimization::kHolderIsReceiver:
180 __ Mov(holder, receiver);
181 break;
182 case CallOptimization::kHolderFound:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000183 __ Ldr(holder, FieldMemOperand(receiver, HeapObject::kMapOffset));
184 __ Ldr(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
185 for (int i = 1; i < holder_depth; i++) {
186 __ Ldr(holder, FieldMemOperand(holder, HeapObject::kMapOffset));
187 __ Ldr(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
188 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000189 break;
190 case CallOptimization::kHolderNotFound:
191 UNREACHABLE();
192 break;
193 }
194
195 Isolate* isolate = masm->isolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000196 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000197 bool call_data_undefined = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000198 // Put call data in place.
199 if (api_call_info->data()->IsUndefined()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000200 call_data_undefined = true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000201 __ LoadRoot(data, Heap::kUndefinedValueRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000202 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100203 if (optimization.is_constant_call()) {
204 __ Ldr(data,
205 FieldMemOperand(callee, JSFunction::kSharedFunctionInfoOffset));
206 __ Ldr(data,
207 FieldMemOperand(data, SharedFunctionInfo::kFunctionDataOffset));
208 __ Ldr(data,
209 FieldMemOperand(data, FunctionTemplateInfo::kCallCodeOffset));
210 } else {
211 __ Ldr(data,
212 FieldMemOperand(callee, FunctionTemplateInfo::kCallCodeOffset));
213 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000214 __ Ldr(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset));
215 }
216
217 if (api_call_info->fast_handler()->IsCode()) {
218 // Just tail call into the fast handler if present.
219 __ Jump(handle(Code::cast(api_call_info->fast_handler())),
220 RelocInfo::CODE_TARGET);
221 return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000222 }
223
224 // Put api_function_address in place.
225 Address function_address = v8::ToCData<Address>(api_call_info->callback());
226 ApiFunction fun(function_address);
227 ExternalReference ref = ExternalReference(
228 &fun, ExternalReference::DIRECT_API_CALL, masm->isolate());
229 __ Mov(api_function_address, ref);
230
231 // Jump to stub.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100232 CallApiAccessorStub stub(isolate, is_store, call_data_undefined,
233 !optimization.is_constant_call());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000234 __ TailCallStub(&stub);
235}
236
237
238void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000239 MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
240 int accessor_index, int expected_arguments, Register scratch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000241 // ----------- S t a t e -------------
242 // -- lr : return address
243 // -----------------------------------
244 Label miss;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000245 {
246 FrameScope scope(masm, StackFrame::INTERNAL);
247
248 // Save value register, so we can restore it later.
249 __ Push(value());
250
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000251 if (accessor_index >= 0) {
252 DCHECK(!AreAliased(holder, scratch));
253 DCHECK(!AreAliased(receiver, scratch));
254 DCHECK(!AreAliased(value(), scratch));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000255 // Call the JavaScript setter with receiver and value on the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000256 if (map->IsJSGlobalObjectMap()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000257 // Swap in the global receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000258 __ Ldr(scratch,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000259 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000260 receiver = scratch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000261 }
262 __ Push(receiver, value());
263 ParameterCount actual(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000264 ParameterCount expected(expected_arguments);
265 __ LoadAccessor(x1, holder, accessor_index, ACCESSOR_SETTER);
266 __ InvokeFunction(x1, expected, actual, CALL_FUNCTION,
267 CheckDebugStepCallWrapper());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000268 } else {
269 // If we generate a global code snippet for deoptimization only, remember
270 // the place to continue after deoptimization.
271 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
272 }
273
274 // We have to return the passed value, not the return value of the setter.
275 __ Pop(x0);
276
277 // Restore context register.
278 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
279 }
280 __ Ret();
281}
282
283
284void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000285 MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
286 int accessor_index, int expected_arguments, Register scratch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000287 {
288 FrameScope scope(masm, StackFrame::INTERNAL);
289
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000290 if (accessor_index >= 0) {
291 DCHECK(!AreAliased(holder, scratch));
292 DCHECK(!AreAliased(receiver, scratch));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000293 // Call the JavaScript getter with the receiver on the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000294 if (map->IsJSGlobalObjectMap()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000295 // Swap in the global receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000296 __ Ldr(scratch,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000297 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000298 receiver = scratch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000299 }
300 __ Push(receiver);
301 ParameterCount actual(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000302 ParameterCount expected(expected_arguments);
303 __ LoadAccessor(x1, holder, accessor_index, ACCESSOR_GETTER);
304 __ InvokeFunction(x1, expected, actual, CALL_FUNCTION,
305 CheckDebugStepCallWrapper());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000306 } else {
307 // If we generate a global code snippet for deoptimization only, remember
308 // the place to continue after deoptimization.
309 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
310 }
311
312 // Restore context register.
313 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
314 }
315 __ Ret();
316}
317
318
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000319static void StoreIC_PushArgs(MacroAssembler* masm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000320 __ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000321 StoreDescriptor::ValueRegister(),
322 VectorStoreICDescriptor::SlotRegister(),
323 VectorStoreICDescriptor::VectorRegister());
324}
325
326
327void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
328 StoreIC_PushArgs(masm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000329
330 // The slow case calls into the runtime to complete the store without causing
331 // an IC miss that would otherwise cause a transition to the generic stub.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000332 __ TailCallRuntime(Runtime::kStoreIC_Slow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000333}
334
335
336void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) {
337 ASM_LOCATION("ElementHandlerCompiler::GenerateStoreSlow");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000338 StoreIC_PushArgs(masm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000339
340 // The slow case calls into the runtime to complete the store without causing
341 // an IC miss that would otherwise cause a transition to the generic stub.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000342 __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000343}
344
345
346#undef __
347#define __ ACCESS_MASM(masm())
348
349
350Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
351 Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
352 Label miss;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400353 if (IC::ICUseVector(kind())) {
354 PushVectorAndSlot();
355 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000356 FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000357
358 // Get the value from the cell.
359 Register result = StoreDescriptor::ValueRegister();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400360 Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
361 __ LoadWeakValue(result, weak_cell, &miss);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000362 __ Ldr(result, FieldMemOperand(result, PropertyCell::kValueOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000363
364 // Check for deleted property if property can actually be deleted.
365 if (is_configurable) {
366 __ JumpIfRoot(result, Heap::kTheHoleValueRootIndex, &miss);
367 }
368
369 Counters* counters = isolate()->counters();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100370 __ IncrementCounter(counters->ic_named_load_global_stub(), 1, x1, x3);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400371 if (IC::ICUseVector(kind())) {
372 DiscardVectorAndSlot();
373 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000374 __ Ret();
375
376 FrontendFooter(name, &miss);
377
378 // Return the generated code.
379 return GetCode(kind(), Code::NORMAL, name);
380}
381
382
383Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor(
384 Handle<Name> name) {
385 Label miss;
386
387 ASM_LOCATION("NamedStoreHandlerCompiler::CompileStoreInterceptor");
388
389 __ Push(receiver(), this->name(), value());
390
391 // Do tail-call to the runtime system.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000392 __ TailCallRuntime(Runtime::kStorePropertyWithInterceptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000393
394 // Return the generated code.
395 return GetCode(kind(), Code::FAST, name);
396}
397
398
399Register NamedStoreHandlerCompiler::value() {
400 return StoreDescriptor::ValueRegister();
401}
402
403
404void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
405 Handle<Name> name) {
406 if (!label->is_unused()) {
407 __ Bind(label);
408 __ Mov(this->name(), Operand(name));
409 }
410}
411
412
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400413void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
414 __ Mov(this->name(), Operand(name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000415}
416
417
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000418void NamedStoreHandlerCompiler::RearrangeVectorAndSlot(
419 Register current_map, Register destination_map) {
420 DCHECK(false); // Not implemented.
421}
422
423
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400424void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000425 Register map_reg,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400426 Register scratch,
427 Label* miss) {
428 Handle<WeakCell> cell = Map::WeakCellForMap(transition);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400429 DCHECK(!map_reg.is(scratch));
430 __ LoadWeakValue(map_reg, cell, miss);
431 if (transition->CanBeDeprecated()) {
432 __ Ldrsw(scratch, FieldMemOperand(map_reg, Map::kBitField3Offset));
433 __ TestAndBranchIfAnySet(scratch, Map::Deprecated::kMask, miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000434 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400435}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000436
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400437
438void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
439 int descriptor,
440 Register value_reg,
441 Register scratch,
442 Label* miss_label) {
443 DCHECK(!map_reg.is(scratch));
444 DCHECK(!map_reg.is(value_reg));
445 DCHECK(!value_reg.is(scratch));
446 __ LoadInstanceDescriptors(map_reg, scratch);
447 __ Ldr(scratch,
448 FieldMemOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
449 __ Cmp(value_reg, scratch);
450 __ B(ne, miss_label);
451}
452
Ben Murdoch097c5b22016-05-18 11:27:45 +0100453void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400454 Register value_reg,
455 Label* miss_label) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000456 Register map_reg = scratch1();
457 Register scratch = scratch2();
458 DCHECK(!value_reg.is(map_reg));
459 DCHECK(!value_reg.is(scratch));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400460 __ JumpIfSmi(value_reg, miss_label);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100461 if (field_type->IsClass()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000462 __ Ldr(map_reg, FieldMemOperand(value_reg, HeapObject::kMapOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100463 __ CmpWeakValue(map_reg, Map::WeakCellForMap(field_type->AsClass()),
464 scratch);
465 __ B(ne, miss_label);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400466 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000467}
468
469
470Register PropertyHandlerCompiler::CheckPrototypes(
471 Register object_reg, Register holder_reg, Register scratch1,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000472 Register scratch2, Handle<Name> name, Label* miss, PrototypeCheckType check,
473 ReturnHolder return_what) {
474 Handle<Map> receiver_map = map();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000475
476 // object_reg and holder_reg registers can alias.
477 DCHECK(!AreAliased(object_reg, scratch1, scratch2));
478 DCHECK(!AreAliased(holder_reg, scratch1, scratch2));
479
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000480 if (FLAG_eliminate_prototype_chain_checks) {
481 Handle<Cell> validity_cell =
482 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
483 if (!validity_cell.is_null()) {
484 DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid),
485 validity_cell->value());
486 __ Mov(scratch1, Operand(validity_cell));
487 __ Ldr(scratch1, FieldMemOperand(scratch1, Cell::kValueOffset));
488 __ Cmp(scratch1, Operand(Smi::FromInt(Map::kPrototypeChainValid)));
489 __ B(ne, miss);
490 }
491
492 // The prototype chain of primitives (and their JSValue wrappers) depends
493 // on the native context, which can't be guarded by validity cells.
494 // |object_reg| holds the native context specific prototype in this case;
495 // we need to check its map.
496 if (check == CHECK_ALL_MAPS) {
497 __ Ldr(scratch1, FieldMemOperand(object_reg, HeapObject::kMapOffset));
498 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
499 __ CmpWeakValue(scratch1, cell, scratch2);
500 __ B(ne, miss);
501 }
502 }
503
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000504 // Keep track of the current object in register reg.
505 Register reg = object_reg;
506 int depth = 0;
507
508 Handle<JSObject> current = Handle<JSObject>::null();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000509 if (receiver_map->IsJSGlobalObjectMap()) {
510 current = isolate()->global_object();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000511 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000512
513 // Check access rights to the global object. This has to happen after
514 // the map check so that we know that the object is actually a global
515 // object.
516 // This allows us to install generated handlers for accesses to the
517 // global proxy (as opposed to using slow ICs). See corresponding code
518 // in LookupForRead().
519 if (receiver_map->IsJSGlobalProxyMap()) {
520 UseScratchRegisterScope temps(masm());
521 __ CheckAccessGlobalProxy(reg, scratch2, temps.AcquireX(), miss);
522 }
523
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000524 Handle<JSObject> prototype = Handle<JSObject>::null();
525 Handle<Map> current_map = receiver_map;
526 Handle<Map> holder_map(holder()->map());
527 // Traverse the prototype chain and check the maps in the prototype chain for
528 // fast and global objects or do negative lookup for normal objects.
529 while (!current_map.is_identical_to(holder_map)) {
530 ++depth;
531
532 // Only global objects and objects that do not require access
533 // checks are allowed in stubs.
534 DCHECK(current_map->IsJSGlobalProxyMap() ||
535 !current_map->is_access_check_needed());
536
537 prototype = handle(JSObject::cast(current_map->prototype()));
538 if (current_map->is_dictionary_map() &&
539 !current_map->IsJSGlobalObjectMap()) {
540 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
541 if (!name->IsUniqueName()) {
542 DCHECK(name->IsString());
543 name = factory()->InternalizeString(Handle<String>::cast(name));
544 }
545 DCHECK(current.is_null() || (current->property_dictionary()->FindEntry(
546 name) == NameDictionary::kNotFound));
547
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000548 if (FLAG_eliminate_prototype_chain_checks && depth > 1) {
549 // TODO(jkummerow): Cache and re-use weak cell.
550 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
551 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000552 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
553 scratch2);
554
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000555 if (!FLAG_eliminate_prototype_chain_checks) {
556 __ Ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
557 __ Ldr(holder_reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
558 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000559 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000560 Register map_reg = scratch1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000561 if (!FLAG_eliminate_prototype_chain_checks) {
562 __ Ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
563 }
564 if (current_map->IsJSGlobalObjectMap()) {
565 GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
566 name, scratch2, miss);
567 } else if (!FLAG_eliminate_prototype_chain_checks &&
568 (depth != 1 || check == CHECK_ALL_MAPS)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400569 Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
570 __ CmpWeakValue(map_reg, cell, scratch2);
571 __ B(ne, miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000572 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000573 if (!FLAG_eliminate_prototype_chain_checks) {
574 __ Ldr(holder_reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000575 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000576 }
577
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000578 reg = holder_reg; // From now on the object will be in holder_reg.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000579 // Go to the next object in the prototype chain.
580 current = prototype;
581 current_map = handle(current->map());
582 }
583
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000584 DCHECK(!current_map->IsJSGlobalProxyMap());
585
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000586 // Log the check depth.
587 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
588
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000589 if (!FLAG_eliminate_prototype_chain_checks &&
590 (depth != 0 || check == CHECK_ALL_MAPS)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000591 // Check the holder map.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400592 __ Ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
593 Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
594 __ CmpWeakValue(scratch1, cell, scratch2);
595 __ B(ne, miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000596 }
597
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000598 bool return_holder = return_what == RETURN_HOLDER;
599 if (FLAG_eliminate_prototype_chain_checks && return_holder && depth != 0) {
600 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000601 }
602
603 // Return the register containing the holder.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000604 return return_holder ? reg : no_reg;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000605}
606
607
608void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
609 if (!miss->is_unused()) {
610 Label success;
611 __ B(&success);
612
613 __ Bind(miss);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400614 if (IC::ICUseVector(kind())) {
615 DCHECK(kind() == Code::LOAD_IC);
616 PopVectorAndSlot();
617 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000618 TailCallBuiltin(masm(), MissBuiltin(kind()));
619
620 __ Bind(&success);
621 }
622}
623
624
625void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
626 if (!miss->is_unused()) {
627 Label success;
628 __ B(&success);
629
630 GenerateRestoreName(miss, name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000631 if (IC::ICUseVector(kind())) PopVectorAndSlot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000632 TailCallBuiltin(masm(), MissBuiltin(kind()));
633
634 __ Bind(&success);
635 }
636}
637
638
639void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
640 // Return the constant value.
641 __ LoadObject(x0, value);
642 __ Ret();
643}
644
645
646void NamedLoadHandlerCompiler::GenerateLoadCallback(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100647 Register reg, Handle<AccessorInfo> callback) {
648 DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), receiver()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000649 DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), reg));
650
Ben Murdoch097c5b22016-05-18 11:27:45 +0100651 // Build v8::PropertyCallbackInfo::args_ array on the stack and push property
652 // name below the exit frame to make GC aware of them.
653 STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0);
654 STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1);
655 STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2);
656 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3);
657 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4);
658 STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5);
659 STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6);
660 STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000661
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())));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100676 __ Push(scratch3(), scratch4(), scratch4(), scratch2(), reg);
677 __ Push(Smi::FromInt(0)); // should_throw_on_error -> false
678 __ Push(name());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000679
680 // Abi for CallApiGetter.
681 Register getter_address_reg = x2;
682
683 // Set up the call.
684 Address getter_address = v8::ToCData<Address>(callback->getter());
685 ApiFunction fun(getter_address);
686 ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
687 ExternalReference ref = ExternalReference(&fun, type, isolate());
688 __ Mov(getter_address_reg, ref);
689
690 CallApiGetterStub stub(isolate());
691 __ TailCallStub(&stub);
692}
693
694
695void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
696 LookupIterator* it, Register holder_reg) {
697 DCHECK(!AreAliased(receiver(), this->name(), scratch1(), scratch2(),
698 scratch3()));
699 DCHECK(holder()->HasNamedInterceptor());
700 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
701
702 // Compile the interceptor call, followed by inline code to load the
703 // property from further up the prototype chain if the call fails.
704 // Check that the maps haven't changed.
705 DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
706
707 // Preserve the receiver register explicitly whenever it is different from the
708 // holder and it is needed should the interceptor return without any result.
709 // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
710 // case might cause a miss during the prototype check.
711 bool must_perform_prototype_check =
712 !holder().is_identical_to(it->GetHolder<JSObject>());
713 bool must_preserve_receiver_reg =
714 !receiver().is(holder_reg) &&
715 (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
716
717 // Save necessary data before invoking an interceptor.
718 // Requires a frame to make GC aware of pushed pointers.
719 {
720 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
721 if (must_preserve_receiver_reg) {
722 __ Push(receiver(), holder_reg, this->name());
723 } else {
724 __ Push(holder_reg, this->name());
725 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400726 InterceptorVectorSlotPush(holder_reg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000727 // Invoke an interceptor. Note: map checks from receiver to
728 // interceptor's holder has been compiled before (see a caller
729 // of this method.)
730 CompileCallLoadPropertyWithInterceptor(
731 masm(), receiver(), holder_reg, this->name(), holder(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000732 Runtime::kLoadPropertyWithInterceptorOnly);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000733
734 // Check if interceptor provided a value for property. If it's
735 // the case, return immediately.
736 Label interceptor_failed;
737 __ JumpIfRoot(x0, Heap::kNoInterceptorResultSentinelRootIndex,
738 &interceptor_failed);
739 frame_scope.GenerateLeaveFrame();
740 __ Ret();
741
742 __ Bind(&interceptor_failed);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400743 InterceptorVectorSlotPop(holder_reg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000744 if (must_preserve_receiver_reg) {
745 __ Pop(this->name(), holder_reg, receiver());
746 } else {
747 __ Pop(this->name(), holder_reg);
748 }
749 // Leave the internal frame.
750 }
751
752 GenerateLoadPostInterceptor(it, holder_reg);
753}
754
755
756void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
757 // Call the runtime system to load the interceptor.
758 DCHECK(holder()->HasNamedInterceptor());
759 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
760 PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
761 holder());
762
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000763 __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000764}
765
766
767Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100768 Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
769 LanguageMode language_mode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000770 ASM_LOCATION("NamedStoreHandlerCompiler::CompileStoreCallback");
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400771 Register holder_reg = Frontend(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000772
773 // Stub never generated for non-global objects that require access checks.
774 DCHECK(holder()->IsJSGlobalProxy() || !holder()->IsAccessCheckNeeded());
775
776 // receiver() and holder_reg can alias.
777 DCHECK(!AreAliased(receiver(), scratch1(), scratch2(), value()));
778 DCHECK(!AreAliased(holder_reg, scratch1(), scratch2(), value()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000779 // If the callback cannot leak, then push the callback directly,
780 // otherwise wrap it in a weak cell.
781 if (callback->data()->IsUndefined() || callback->data()->IsSmi()) {
782 __ Mov(scratch1(), Operand(callback));
783 } else {
784 Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
785 __ Mov(scratch1(), Operand(cell));
786 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000787 __ Mov(scratch2(), Operand(name));
788 __ Push(receiver(), holder_reg, scratch1(), scratch2(), value());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100789 __ Push(Smi::FromInt(language_mode));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000790
791 // Do tail-call to the runtime system.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000792 __ TailCallRuntime(Runtime::kStoreCallbackProperty);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000793
794 // Return the generated code.
795 return GetCode(kind(), Code::FAST, name);
796}
797
798
799#undef __
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000800} // namespace internal
801} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000802
803#endif // V8_TARGET_ARCH_IA32