blob: a704492550b332594e79c47501958a2e865b03af [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
Ben Murdochda12d292016-06-02 14:46:10 +01009#include "src/api-arguments.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010010#include "src/field-type.h"
11#include "src/ic/call-optimization.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012#include "src/ic/ic.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013#include "src/isolate-inl.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014
15namespace v8 {
16namespace internal {
17
18#define __ ACCESS_MASM(masm)
19
Emily Bernierd0a1eb72015-03-24 16:35:39 -040020void PropertyHandlerCompiler::PushVectorAndSlot(Register vector,
21 Register slot) {
22 MacroAssembler* masm = this->masm();
23 __ Push(vector);
24 __ Push(slot);
25}
26
27
28void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) {
29 MacroAssembler* masm = this->masm();
30 __ Pop(slot);
31 __ Pop(vector);
32}
33
34
35void PropertyHandlerCompiler::DiscardVectorAndSlot() {
36 MacroAssembler* masm = this->masm();
37 // Remove vector and slot.
38 __ Drop(2);
39}
40
Ben Murdochb8a8cc12014-11-26 15:28:44 +000041
42void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
43 MacroAssembler* masm, Label* miss_label, Register receiver,
44 Handle<Name> name, Register scratch0, Register scratch1) {
45 DCHECK(!AreAliased(receiver, scratch0, scratch1));
46 DCHECK(name->IsUniqueName());
47 Counters* counters = masm->isolate()->counters();
48 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
49 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
50
51 Label done;
52
53 const int kInterceptorOrAccessCheckNeededMask =
54 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
55
56 // Bail out if the receiver has a named interceptor or requires access checks.
57 Register map = scratch1;
58 __ Ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
59 __ Ldrb(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
60 __ Tst(scratch0, kInterceptorOrAccessCheckNeededMask);
61 __ B(ne, miss_label);
62
63 // Check that receiver is a JSObject.
64 __ Ldrb(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000065 __ Cmp(scratch0, FIRST_JS_RECEIVER_TYPE);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000066 __ B(lt, miss_label);
67
68 // Load properties array.
69 Register properties = scratch0;
70 __ Ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
71 // Check that the properties array is a dictionary.
72 __ Ldr(map, FieldMemOperand(properties, HeapObject::kMapOffset));
73 __ JumpIfNotRoot(map, Heap::kHashTableMapRootIndex, miss_label);
74
75 NameDictionaryLookupStub::GenerateNegativeLookup(
76 masm, miss_label, &done, receiver, properties, name, scratch1);
77 __ Bind(&done);
78 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
79}
80
81
82void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040083 MacroAssembler* masm, int index, Register result, Label* miss) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000084 __ LoadNativeContextSlot(index, result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000085 // Load its initial map. The global functions all have initial maps.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040086 __ Ldr(result,
87 FieldMemOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000088 // Load the prototype from the initial map.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040089 __ Ldr(result, FieldMemOperand(result, Map::kPrototypeOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000090}
91
92
93void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
94 MacroAssembler* masm, Register receiver, Register scratch1,
95 Register scratch2, Label* miss_label) {
96 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
97 // TryGetFunctionPrototype can't put the result directly in x0 because the
98 // 3 inputs registers can't alias and we call this function from
99 // LoadIC::GenerateFunctionPrototype, where receiver is x0. So we explicitly
100 // move the result in x0.
101 __ Mov(x0, scratch1);
102 __ Ret();
103}
104
105
106// Generate code to check that a global property cell is empty. Create
107// the property cell at compilation time if no cell exists for the
108// property.
109void PropertyHandlerCompiler::GenerateCheckPropertyCell(
110 MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
111 Register scratch, Label* miss) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000112 Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000113 DCHECK(cell->value()->IsTheHole());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000114 Handle<WeakCell> weak_cell = masm->isolate()->factory()->NewWeakCell(cell);
115 __ LoadWeakValue(scratch, weak_cell, miss);
116 __ Ldr(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000117 __ JumpIfNotRoot(scratch, Heap::kTheHoleValueRootIndex, miss);
118}
119
120
121static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
122 Register holder, Register name,
123 Handle<JSObject> holder_obj) {
124 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000125 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
126 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
127 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000128
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000129 __ Push(name, receiver, holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000130}
131
132
133static void CompileCallLoadPropertyWithInterceptor(
134 MacroAssembler* masm, Register receiver, Register holder, Register name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000135 Handle<JSObject> holder_obj, Runtime::FunctionId id) {
136 DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
137 Runtime::FunctionForId(id)->nargs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000138 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000139 __ CallRuntime(id);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000140}
141
142
143// Generate call to api function.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000144void PropertyHandlerCompiler::GenerateApiAccessorCall(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000145 MacroAssembler* masm, const CallOptimization& optimization,
146 Handle<Map> receiver_map, Register receiver, Register scratch,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000147 bool is_store, Register store_parameter, Register accessor_holder,
148 int accessor_index) {
149 DCHECK(!AreAliased(accessor_holder, scratch));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000150 DCHECK(!AreAliased(receiver, scratch));
151
152 MacroAssembler::PushPopQueue queue(masm);
153 queue.Queue(receiver);
154 // Write the arguments to the stack frame.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000155 if (is_store) {
156 DCHECK(!receiver.is(store_parameter));
157 DCHECK(!scratch.is(store_parameter));
158 queue.Queue(store_parameter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000159 }
160 queue.PushQueued();
161
162 DCHECK(optimization.is_simple_api_call());
163
Ben Murdochda12d292016-06-02 14:46:10 +0100164 // Abi for CallApiCallbackStub.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000165 Register callee = x0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000166 Register data = x4;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000167 Register holder = x2;
168 Register api_function_address = x1;
169
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000170 // Put callee in place.
171 __ LoadAccessor(callee, accessor_holder, accessor_index,
172 is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
173
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000174 // Put holder in place.
175 CallOptimization::HolderLookup holder_lookup;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000176 int holder_depth = 0;
177 optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup,
178 &holder_depth);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000179 switch (holder_lookup) {
180 case CallOptimization::kHolderIsReceiver:
181 __ Mov(holder, receiver);
182 break;
183 case CallOptimization::kHolderFound:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000184 __ Ldr(holder, FieldMemOperand(receiver, HeapObject::kMapOffset));
185 __ Ldr(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
186 for (int i = 1; i < holder_depth; i++) {
187 __ Ldr(holder, FieldMemOperand(holder, HeapObject::kMapOffset));
188 __ Ldr(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
189 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000190 break;
191 case CallOptimization::kHolderNotFound:
192 UNREACHABLE();
193 break;
194 }
195
196 Isolate* isolate = masm->isolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000197 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000198 bool call_data_undefined = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000199 // Put call data in place.
200 if (api_call_info->data()->IsUndefined()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000201 call_data_undefined = true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000202 __ LoadRoot(data, Heap::kUndefinedValueRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000203 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100204 if (optimization.is_constant_call()) {
205 __ Ldr(data,
206 FieldMemOperand(callee, JSFunction::kSharedFunctionInfoOffset));
207 __ Ldr(data,
208 FieldMemOperand(data, SharedFunctionInfo::kFunctionDataOffset));
209 __ Ldr(data,
210 FieldMemOperand(data, FunctionTemplateInfo::kCallCodeOffset));
211 } else {
212 __ Ldr(data,
213 FieldMemOperand(callee, FunctionTemplateInfo::kCallCodeOffset));
214 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000215 __ Ldr(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset));
216 }
217
218 if (api_call_info->fast_handler()->IsCode()) {
219 // Just tail call into the fast handler if present.
220 __ Jump(handle(Code::cast(api_call_info->fast_handler())),
221 RelocInfo::CODE_TARGET);
222 return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000223 }
224
225 // Put api_function_address in place.
226 Address function_address = v8::ToCData<Address>(api_call_info->callback());
227 ApiFunction fun(function_address);
228 ExternalReference ref = ExternalReference(
229 &fun, ExternalReference::DIRECT_API_CALL, masm->isolate());
230 __ Mov(api_function_address, ref);
231
232 // Jump to stub.
Ben Murdochda12d292016-06-02 14:46:10 +0100233 CallApiCallbackStub stub(isolate, is_store, call_data_undefined,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100234 !optimization.is_constant_call());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000235 __ TailCallStub(&stub);
236}
237
238
239void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000240 MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
241 int accessor_index, int expected_arguments, Register scratch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000242 // ----------- S t a t e -------------
243 // -- lr : return address
244 // -----------------------------------
245 Label miss;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000246 {
247 FrameScope scope(masm, StackFrame::INTERNAL);
248
Ben Murdochda12d292016-06-02 14:46:10 +0100249 // Save context register
250 __ Push(cp);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000251 // Save value register, so we can restore it later.
252 __ Push(value());
253
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000254 if (accessor_index >= 0) {
255 DCHECK(!AreAliased(holder, scratch));
256 DCHECK(!AreAliased(receiver, scratch));
257 DCHECK(!AreAliased(value(), scratch));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000258 // Call the JavaScript setter with receiver and value on the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000259 if (map->IsJSGlobalObjectMap()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000260 // Swap in the global receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000261 __ Ldr(scratch,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000262 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000263 receiver = scratch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000264 }
265 __ Push(receiver, value());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000266 __ LoadAccessor(x1, holder, accessor_index, ACCESSOR_SETTER);
Ben Murdochda12d292016-06-02 14:46:10 +0100267 __ Mov(x0, 1);
268 __ Call(masm->isolate()->builtins()->CallFunction(
269 ConvertReceiverMode::kNotNullOrUndefined),
270 RelocInfo::CODE_TARGET);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000271 } else {
272 // If we generate a global code snippet for deoptimization only, remember
273 // the place to continue after deoptimization.
274 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
275 }
276
277 // We have to return the passed value, not the return value of the setter.
278 __ Pop(x0);
279
280 // Restore context register.
Ben Murdochda12d292016-06-02 14:46:10 +0100281 __ Pop(cp);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000282 }
283 __ Ret();
284}
285
286
287void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000288 MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
289 int accessor_index, int expected_arguments, Register scratch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000290 {
291 FrameScope scope(masm, StackFrame::INTERNAL);
292
Ben Murdochda12d292016-06-02 14:46:10 +0100293 // Save context register
294 __ Push(cp);
295
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000296 if (accessor_index >= 0) {
297 DCHECK(!AreAliased(holder, scratch));
298 DCHECK(!AreAliased(receiver, scratch));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000299 // Call the JavaScript getter with the receiver on the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000300 if (map->IsJSGlobalObjectMap()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000301 // Swap in the global receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000302 __ Ldr(scratch,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000303 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000304 receiver = scratch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000305 }
306 __ Push(receiver);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000307 __ LoadAccessor(x1, holder, accessor_index, ACCESSOR_GETTER);
Ben Murdochda12d292016-06-02 14:46:10 +0100308 __ Mov(x0, 0);
309 __ Call(masm->isolate()->builtins()->CallFunction(
310 ConvertReceiverMode::kNotNullOrUndefined),
311 RelocInfo::CODE_TARGET);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000312 } else {
313 // If we generate a global code snippet for deoptimization only, remember
314 // the place to continue after deoptimization.
315 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
316 }
317
318 // Restore context register.
Ben Murdochda12d292016-06-02 14:46:10 +0100319 __ Pop(cp);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000320 }
321 __ Ret();
322}
323
324
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000325static void StoreIC_PushArgs(MacroAssembler* masm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000326 __ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000327 StoreDescriptor::ValueRegister(),
328 VectorStoreICDescriptor::SlotRegister(),
329 VectorStoreICDescriptor::VectorRegister());
330}
331
332
333void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
334 StoreIC_PushArgs(masm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000335
336 // The slow case calls into the runtime to complete the store without causing
337 // an IC miss that would otherwise cause a transition to the generic stub.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000338 __ TailCallRuntime(Runtime::kStoreIC_Slow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000339}
340
341
342void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) {
343 ASM_LOCATION("ElementHandlerCompiler::GenerateStoreSlow");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000344 StoreIC_PushArgs(masm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000345
346 // The slow case calls into the runtime to complete the store without causing
347 // an IC miss that would otherwise cause a transition to the generic stub.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000348 __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000349}
350
351
352#undef __
353#define __ ACCESS_MASM(masm())
354
355
356Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
357 Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
358 Label miss;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400359 if (IC::ICUseVector(kind())) {
360 PushVectorAndSlot();
361 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000362 FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000363
364 // Get the value from the cell.
365 Register result = StoreDescriptor::ValueRegister();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400366 Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
367 __ LoadWeakValue(result, weak_cell, &miss);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000368 __ Ldr(result, FieldMemOperand(result, PropertyCell::kValueOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000369
370 // Check for deleted property if property can actually be deleted.
371 if (is_configurable) {
372 __ JumpIfRoot(result, Heap::kTheHoleValueRootIndex, &miss);
373 }
374
375 Counters* counters = isolate()->counters();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100376 __ IncrementCounter(counters->ic_named_load_global_stub(), 1, x1, x3);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400377 if (IC::ICUseVector(kind())) {
378 DiscardVectorAndSlot();
379 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000380 __ Ret();
381
382 FrontendFooter(name, &miss);
383
384 // Return the generated code.
385 return GetCode(kind(), Code::NORMAL, name);
386}
387
388
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000389Register NamedStoreHandlerCompiler::value() {
390 return StoreDescriptor::ValueRegister();
391}
392
393
394void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
395 Handle<Name> name) {
396 if (!label->is_unused()) {
397 __ Bind(label);
398 __ Mov(this->name(), Operand(name));
399 }
400}
401
402
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400403void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
404 __ Mov(this->name(), Operand(name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000405}
406
407
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000408void NamedStoreHandlerCompiler::RearrangeVectorAndSlot(
409 Register current_map, Register destination_map) {
410 DCHECK(false); // Not implemented.
411}
412
413
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400414void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000415 Register map_reg,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400416 Register scratch,
417 Label* miss) {
418 Handle<WeakCell> cell = Map::WeakCellForMap(transition);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400419 DCHECK(!map_reg.is(scratch));
420 __ LoadWeakValue(map_reg, cell, miss);
421 if (transition->CanBeDeprecated()) {
422 __ Ldrsw(scratch, FieldMemOperand(map_reg, Map::kBitField3Offset));
423 __ TestAndBranchIfAnySet(scratch, Map::Deprecated::kMask, miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000424 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400425}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000426
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400427
428void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
429 int descriptor,
430 Register value_reg,
431 Register scratch,
432 Label* miss_label) {
433 DCHECK(!map_reg.is(scratch));
434 DCHECK(!map_reg.is(value_reg));
435 DCHECK(!value_reg.is(scratch));
436 __ LoadInstanceDescriptors(map_reg, scratch);
437 __ Ldr(scratch,
438 FieldMemOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
439 __ Cmp(value_reg, scratch);
440 __ B(ne, miss_label);
441}
442
Ben Murdoch097c5b22016-05-18 11:27:45 +0100443void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400444 Register value_reg,
445 Label* miss_label) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000446 Register map_reg = scratch1();
447 Register scratch = scratch2();
448 DCHECK(!value_reg.is(map_reg));
449 DCHECK(!value_reg.is(scratch));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400450 __ JumpIfSmi(value_reg, miss_label);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100451 if (field_type->IsClass()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000452 __ Ldr(map_reg, FieldMemOperand(value_reg, HeapObject::kMapOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100453 __ CmpWeakValue(map_reg, Map::WeakCellForMap(field_type->AsClass()),
454 scratch);
455 __ B(ne, miss_label);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400456 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000457}
458
459
460Register PropertyHandlerCompiler::CheckPrototypes(
461 Register object_reg, Register holder_reg, Register scratch1,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000462 Register scratch2, Handle<Name> name, Label* miss, PrototypeCheckType check,
463 ReturnHolder return_what) {
464 Handle<Map> receiver_map = map();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000465
466 // object_reg and holder_reg registers can alias.
467 DCHECK(!AreAliased(object_reg, scratch1, scratch2));
468 DCHECK(!AreAliased(holder_reg, scratch1, scratch2));
469
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000470 if (FLAG_eliminate_prototype_chain_checks) {
471 Handle<Cell> validity_cell =
472 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
473 if (!validity_cell.is_null()) {
474 DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid),
475 validity_cell->value());
476 __ Mov(scratch1, Operand(validity_cell));
477 __ Ldr(scratch1, FieldMemOperand(scratch1, Cell::kValueOffset));
478 __ Cmp(scratch1, Operand(Smi::FromInt(Map::kPrototypeChainValid)));
479 __ B(ne, miss);
480 }
481
482 // The prototype chain of primitives (and their JSValue wrappers) depends
483 // on the native context, which can't be guarded by validity cells.
484 // |object_reg| holds the native context specific prototype in this case;
485 // we need to check its map.
486 if (check == CHECK_ALL_MAPS) {
487 __ Ldr(scratch1, FieldMemOperand(object_reg, HeapObject::kMapOffset));
488 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
489 __ CmpWeakValue(scratch1, cell, scratch2);
490 __ B(ne, miss);
491 }
492 }
493
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000494 // Keep track of the current object in register reg.
495 Register reg = object_reg;
496 int depth = 0;
497
498 Handle<JSObject> current = Handle<JSObject>::null();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000499 if (receiver_map->IsJSGlobalObjectMap()) {
500 current = isolate()->global_object();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000501 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000502
503 // Check access rights to the global object. This has to happen after
504 // the map check so that we know that the object is actually a global
505 // object.
506 // This allows us to install generated handlers for accesses to the
507 // global proxy (as opposed to using slow ICs). See corresponding code
508 // in LookupForRead().
509 if (receiver_map->IsJSGlobalProxyMap()) {
510 UseScratchRegisterScope temps(masm());
511 __ CheckAccessGlobalProxy(reg, scratch2, temps.AcquireX(), miss);
512 }
513
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000514 Handle<JSObject> prototype = Handle<JSObject>::null();
515 Handle<Map> current_map = receiver_map;
516 Handle<Map> holder_map(holder()->map());
517 // Traverse the prototype chain and check the maps in the prototype chain for
518 // fast and global objects or do negative lookup for normal objects.
519 while (!current_map.is_identical_to(holder_map)) {
520 ++depth;
521
522 // Only global objects and objects that do not require access
523 // checks are allowed in stubs.
524 DCHECK(current_map->IsJSGlobalProxyMap() ||
525 !current_map->is_access_check_needed());
526
527 prototype = handle(JSObject::cast(current_map->prototype()));
528 if (current_map->is_dictionary_map() &&
529 !current_map->IsJSGlobalObjectMap()) {
530 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
531 if (!name->IsUniqueName()) {
532 DCHECK(name->IsString());
533 name = factory()->InternalizeString(Handle<String>::cast(name));
534 }
535 DCHECK(current.is_null() || (current->property_dictionary()->FindEntry(
536 name) == NameDictionary::kNotFound));
537
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000538 if (FLAG_eliminate_prototype_chain_checks && depth > 1) {
539 // TODO(jkummerow): Cache and re-use weak cell.
540 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
541 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000542 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
543 scratch2);
544
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000545 if (!FLAG_eliminate_prototype_chain_checks) {
546 __ Ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
547 __ Ldr(holder_reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
548 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000549 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000550 Register map_reg = scratch1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000551 if (!FLAG_eliminate_prototype_chain_checks) {
552 __ Ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
553 }
554 if (current_map->IsJSGlobalObjectMap()) {
555 GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
556 name, scratch2, miss);
557 } else if (!FLAG_eliminate_prototype_chain_checks &&
558 (depth != 1 || check == CHECK_ALL_MAPS)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400559 Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
560 __ CmpWeakValue(map_reg, cell, scratch2);
561 __ B(ne, miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000562 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000563 if (!FLAG_eliminate_prototype_chain_checks) {
564 __ Ldr(holder_reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000565 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000566 }
567
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000568 reg = holder_reg; // From now on the object will be in holder_reg.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000569 // Go to the next object in the prototype chain.
570 current = prototype;
571 current_map = handle(current->map());
572 }
573
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000574 DCHECK(!current_map->IsJSGlobalProxyMap());
575
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000576 // Log the check depth.
577 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
578
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000579 if (!FLAG_eliminate_prototype_chain_checks &&
580 (depth != 0 || check == CHECK_ALL_MAPS)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000581 // Check the holder map.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400582 __ Ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
583 Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
584 __ CmpWeakValue(scratch1, cell, scratch2);
585 __ B(ne, miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000586 }
587
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000588 bool return_holder = return_what == RETURN_HOLDER;
589 if (FLAG_eliminate_prototype_chain_checks && return_holder && depth != 0) {
590 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000591 }
592
593 // Return the register containing the holder.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000594 return return_holder ? reg : no_reg;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000595}
596
597
598void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
599 if (!miss->is_unused()) {
600 Label success;
601 __ B(&success);
602
603 __ Bind(miss);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400604 if (IC::ICUseVector(kind())) {
605 DCHECK(kind() == Code::LOAD_IC);
606 PopVectorAndSlot();
607 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000608 TailCallBuiltin(masm(), MissBuiltin(kind()));
609
610 __ Bind(&success);
611 }
612}
613
614
615void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
616 if (!miss->is_unused()) {
617 Label success;
618 __ B(&success);
619
620 GenerateRestoreName(miss, name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000621 if (IC::ICUseVector(kind())) PopVectorAndSlot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000622 TailCallBuiltin(masm(), MissBuiltin(kind()));
623
624 __ Bind(&success);
625 }
626}
627
628
629void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
630 // Return the constant value.
631 __ LoadObject(x0, value);
632 __ Ret();
633}
634
635
636void NamedLoadHandlerCompiler::GenerateLoadCallback(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100637 Register reg, Handle<AccessorInfo> callback) {
638 DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), receiver()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000639 DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), reg));
640
Ben Murdoch097c5b22016-05-18 11:27:45 +0100641 // Build v8::PropertyCallbackInfo::args_ array on the stack and push property
642 // name below the exit frame to make GC aware of them.
643 STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0);
644 STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1);
645 STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2);
646 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3);
647 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4);
648 STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5);
649 STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6);
650 STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000651
652 __ Push(receiver());
653
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000654 Handle<Object> data(callback->data(), isolate());
655 if (data->IsUndefined() || data->IsSmi()) {
656 __ Mov(scratch3(), Operand(data));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000657 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000658 Handle<WeakCell> cell =
659 isolate()->factory()->NewWeakCell(Handle<HeapObject>::cast(data));
660 // The callback is alive if this instruction is executed,
661 // so the weak cell is not cleared and points to data.
662 __ GetWeakValue(scratch3(), cell);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000663 }
664 __ LoadRoot(scratch4(), Heap::kUndefinedValueRootIndex);
665 __ Mov(scratch2(), Operand(ExternalReference::isolate_address(isolate())));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100666 __ Push(scratch3(), scratch4(), scratch4(), scratch2(), reg);
667 __ Push(Smi::FromInt(0)); // should_throw_on_error -> false
668 __ Push(name());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000669
670 // Abi for CallApiGetter.
671 Register getter_address_reg = x2;
672
673 // Set up the call.
674 Address getter_address = v8::ToCData<Address>(callback->getter());
675 ApiFunction fun(getter_address);
676 ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
677 ExternalReference ref = ExternalReference(&fun, type, isolate());
678 __ Mov(getter_address_reg, ref);
679
680 CallApiGetterStub stub(isolate());
681 __ TailCallStub(&stub);
682}
683
684
685void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
686 LookupIterator* it, Register holder_reg) {
687 DCHECK(!AreAliased(receiver(), this->name(), scratch1(), scratch2(),
688 scratch3()));
689 DCHECK(holder()->HasNamedInterceptor());
690 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
691
692 // Compile the interceptor call, followed by inline code to load the
693 // property from further up the prototype chain if the call fails.
694 // Check that the maps haven't changed.
695 DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
696
697 // Preserve the receiver register explicitly whenever it is different from the
698 // holder and it is needed should the interceptor return without any result.
699 // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
700 // case might cause a miss during the prototype check.
701 bool must_perform_prototype_check =
702 !holder().is_identical_to(it->GetHolder<JSObject>());
703 bool must_preserve_receiver_reg =
704 !receiver().is(holder_reg) &&
705 (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
706
707 // Save necessary data before invoking an interceptor.
708 // Requires a frame to make GC aware of pushed pointers.
709 {
710 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
711 if (must_preserve_receiver_reg) {
712 __ Push(receiver(), holder_reg, this->name());
713 } else {
714 __ Push(holder_reg, this->name());
715 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400716 InterceptorVectorSlotPush(holder_reg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000717 // Invoke an interceptor. Note: map checks from receiver to
718 // interceptor's holder has been compiled before (see a caller
719 // of this method.)
720 CompileCallLoadPropertyWithInterceptor(
721 masm(), receiver(), holder_reg, this->name(), holder(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000722 Runtime::kLoadPropertyWithInterceptorOnly);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000723
724 // Check if interceptor provided a value for property. If it's
725 // the case, return immediately.
726 Label interceptor_failed;
727 __ JumpIfRoot(x0, Heap::kNoInterceptorResultSentinelRootIndex,
728 &interceptor_failed);
729 frame_scope.GenerateLeaveFrame();
730 __ Ret();
731
732 __ Bind(&interceptor_failed);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400733 InterceptorVectorSlotPop(holder_reg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000734 if (must_preserve_receiver_reg) {
735 __ Pop(this->name(), holder_reg, receiver());
736 } else {
737 __ Pop(this->name(), holder_reg);
738 }
739 // Leave the internal frame.
740 }
741
742 GenerateLoadPostInterceptor(it, holder_reg);
743}
744
745
746void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
747 // Call the runtime system to load the interceptor.
748 DCHECK(holder()->HasNamedInterceptor());
749 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
750 PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
751 holder());
752
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000753 __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000754}
755
756
757Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100758 Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
759 LanguageMode language_mode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000760 ASM_LOCATION("NamedStoreHandlerCompiler::CompileStoreCallback");
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400761 Register holder_reg = Frontend(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000762
763 // Stub never generated for non-global objects that require access checks.
764 DCHECK(holder()->IsJSGlobalProxy() || !holder()->IsAccessCheckNeeded());
765
766 // receiver() and holder_reg can alias.
767 DCHECK(!AreAliased(receiver(), scratch1(), scratch2(), value()));
768 DCHECK(!AreAliased(holder_reg, scratch1(), scratch2(), value()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000769 // If the callback cannot leak, then push the callback directly,
770 // otherwise wrap it in a weak cell.
771 if (callback->data()->IsUndefined() || callback->data()->IsSmi()) {
772 __ Mov(scratch1(), Operand(callback));
773 } else {
774 Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
775 __ Mov(scratch1(), Operand(cell));
776 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000777 __ Mov(scratch2(), Operand(name));
778 __ Push(receiver(), holder_reg, scratch1(), scratch2(), value());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100779 __ Push(Smi::FromInt(language_mode));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000780
781 // Do tail-call to the runtime system.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000782 __ TailCallRuntime(Runtime::kStoreCallbackProperty);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000783
784 // Return the generated code.
785 return GetCode(kind(), Code::FAST, name);
786}
787
788
789#undef __
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000790} // namespace internal
791} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000792
793#endif // V8_TARGET_ARCH_IA32