blob: ac3dd9a36748190297e4fe3dcca7d86ddc58d38b [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_X64
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 __ addp(rsp, Immediate(2 * kPointerSize));
38}
39
40
Ben Murdochb8a8cc12014-11-26 15:28:44 +000041void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
42 MacroAssembler* masm, Label* miss_label, Register receiver,
43 Handle<Name> name, Register scratch0, Register scratch1) {
44 DCHECK(name->IsUniqueName());
45 DCHECK(!receiver.is(scratch0));
46 Counters* counters = masm->isolate()->counters();
47 __ IncrementCounter(counters->negative_lookups(), 1);
48 __ IncrementCounter(counters->negative_lookups_miss(), 1);
49
50 __ movp(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
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 __ testb(FieldOperand(scratch0, Map::kBitFieldOffset),
57 Immediate(kInterceptorOrAccessCheckNeededMask));
58 __ j(not_zero, miss_label);
59
60 // Check that receiver is a JSObject.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000061 __ CmpInstanceType(scratch0, FIRST_JS_RECEIVER_TYPE);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000062 __ j(below, miss_label);
63
64 // Load properties array.
65 Register properties = scratch0;
66 __ movp(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
67
68 // Check that the properties array is a dictionary.
69 __ CompareRoot(FieldOperand(properties, HeapObject::kMapOffset),
70 Heap::kHashTableMapRootIndex);
71 __ j(not_equal, miss_label);
72
73 Label done;
74 NameDictionaryLookupStub::GenerateNegativeLookup(masm, miss_label, &done,
75 properties, name, scratch1);
76 __ bind(&done);
77 __ DecrementCounter(counters->negative_lookups_miss(), 1);
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 __ movp(result,
86 FieldOperand(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 __ movp(result, FieldOperand(result, Map::kPrototypeOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000089}
90
91
92void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
93 MacroAssembler* masm, Register receiver, Register result, Register scratch,
94 Label* miss_label) {
95 __ TryGetFunctionPrototype(receiver, result, miss_label);
96 if (!result.is(rax)) __ movp(rax, result);
97 __ ret(0);
98}
99
100
101static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
102 Register holder, Register name,
103 Handle<JSObject> holder_obj) {
104 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000105 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
106 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
107 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000108 __ Push(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000109 __ Push(receiver);
110 __ Push(holder);
111}
112
113
114static void CompileCallLoadPropertyWithInterceptor(
115 MacroAssembler* masm, Register receiver, Register holder, Register name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000116 Handle<JSObject> holder_obj, Runtime::FunctionId id) {
117 DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
118 Runtime::FunctionForId(id)->nargs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000119 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000120 __ CallRuntime(id);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000121}
122
123
124// Generate call to api function.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000125void PropertyHandlerCompiler::GenerateApiAccessorCall(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000126 MacroAssembler* masm, const CallOptimization& optimization,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000127 Handle<Map> receiver_map, Register receiver, Register scratch,
128 bool is_store, Register store_parameter, Register accessor_holder,
129 int accessor_index) {
130 DCHECK(!accessor_holder.is(scratch));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000131 DCHECK(optimization.is_simple_api_call());
132
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000133 __ PopReturnAddressTo(scratch);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000134 // receiver
135 __ Push(receiver);
136 // Write the arguments to stack frame.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000137 if (is_store) {
138 DCHECK(!receiver.is(store_parameter));
139 DCHECK(!scratch.is(store_parameter));
140 __ Push(store_parameter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000141 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000142 __ PushReturnAddressFrom(scratch);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000143 // Stack now matches JSFunction abi.
144
145 // Abi for CallApiFunctionStub.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000146 Register callee = rdi;
147 Register data = rbx;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000148 Register holder = rcx;
149 Register api_function_address = rdx;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000150 scratch = no_reg;
151
152 // Put callee in place.
153 __ LoadAccessor(callee, accessor_holder, accessor_index,
154 is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000155
156 // Put holder in place.
157 CallOptimization::HolderLookup holder_lookup;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000158 int holder_depth = 0;
159 optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup,
160 &holder_depth);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000161 switch (holder_lookup) {
162 case CallOptimization::kHolderIsReceiver:
163 __ Move(holder, receiver);
164 break;
165 case CallOptimization::kHolderFound:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000166 __ movp(holder, FieldOperand(receiver, HeapObject::kMapOffset));
167 __ movp(holder, FieldOperand(holder, Map::kPrototypeOffset));
168 for (int i = 1; i < holder_depth; i++) {
169 __ movp(holder, FieldOperand(holder, HeapObject::kMapOffset));
170 __ movp(holder, FieldOperand(holder, Map::kPrototypeOffset));
171 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000172 break;
173 case CallOptimization::kHolderNotFound:
174 UNREACHABLE();
175 break;
176 }
177
178 Isolate* isolate = masm->isolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000179 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000180 bool call_data_undefined = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000181 // Put call data in place.
182 if (api_call_info->data()->IsUndefined()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000183 call_data_undefined = true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000184 __ LoadRoot(data, Heap::kUndefinedValueRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000185 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100186 if (optimization.is_constant_call()) {
187 __ movp(data,
188 FieldOperand(callee, JSFunction::kSharedFunctionInfoOffset));
189 __ movp(data,
190 FieldOperand(data, SharedFunctionInfo::kFunctionDataOffset));
191 __ movp(data, FieldOperand(data, FunctionTemplateInfo::kCallCodeOffset));
192 } else {
193 __ movp(data,
194 FieldOperand(callee, FunctionTemplateInfo::kCallCodeOffset));
195 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000196 __ movp(data, FieldOperand(data, CallHandlerInfo::kDataOffset));
197 }
198
199 if (api_call_info->fast_handler()->IsCode()) {
200 // Just tail call into the fast handler if present.
201 __ Jump(handle(Code::cast(api_call_info->fast_handler())),
202 RelocInfo::CODE_TARGET);
203 return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000204 }
205
206 // Put api_function_address in place.
207 Address function_address = v8::ToCData<Address>(api_call_info->callback());
208 __ Move(api_function_address, function_address,
209 RelocInfo::EXTERNAL_REFERENCE);
210
211 // Jump to stub.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100212 CallApiAccessorStub stub(isolate, is_store, call_data_undefined,
213 !optimization.is_constant_call());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000214 __ TailCallStub(&stub);
215}
216
217
218void PropertyHandlerCompiler::GenerateCheckPropertyCell(
219 MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
220 Register scratch, Label* miss) {
221 Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
222 DCHECK(cell->value()->IsTheHole());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000223 Factory* factory = masm->isolate()->factory();
224 Handle<WeakCell> weak_cell = factory->NewWeakCell(cell);
225 __ LoadWeakValue(scratch, weak_cell, miss);
226 __ Cmp(FieldOperand(scratch, PropertyCell::kValueOffset),
227 factory->the_hole_value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000228 __ j(not_equal, miss);
229}
230
231
232void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000233 MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
234 int accessor_index, int expected_arguments, Register scratch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000235 // ----------- S t a t e -------------
236 // -- rsp[0] : return address
237 // -----------------------------------
238 {
239 FrameScope scope(masm, StackFrame::INTERNAL);
240
241 // Save value register, so we can restore it later.
242 __ Push(value());
243
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000244 if (accessor_index >= 0) {
245 DCHECK(!holder.is(scratch));
246 DCHECK(!receiver.is(scratch));
247 DCHECK(!value().is(scratch));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000248 // Call the JavaScript setter with receiver and value on the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000249 if (map->IsJSGlobalObjectMap()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000250 // Swap in the global receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000251 __ movp(scratch,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000252 FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000253 receiver = scratch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000254 }
255 __ Push(receiver);
256 __ Push(value());
257 ParameterCount actual(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000258 ParameterCount expected(expected_arguments);
259 __ LoadAccessor(rdi, holder, accessor_index, ACCESSOR_SETTER);
260 __ InvokeFunction(rdi, no_reg, expected, actual, CALL_FUNCTION,
261 CheckDebugStepCallWrapper());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000262 } else {
263 // If we generate a global code snippet for deoptimization only, remember
264 // the place to continue after deoptimization.
265 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
266 }
267
268 // We have to return the passed value, not the return value of the setter.
269 __ Pop(rax);
270
271 // Restore context register.
272 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
273 }
274 __ ret(0);
275}
276
277
278void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000279 MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
280 int accessor_index, int expected_arguments, Register scratch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000281 // ----------- S t a t e -------------
282 // -- rax : receiver
283 // -- rcx : name
284 // -- rsp[0] : return address
285 // -----------------------------------
286 {
287 FrameScope scope(masm, StackFrame::INTERNAL);
288
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000289 if (accessor_index >= 0) {
290 DCHECK(!holder.is(scratch));
291 DCHECK(!receiver.is(scratch));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000292 // Call the JavaScript getter with the receiver on the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000293 if (map->IsJSGlobalObjectMap()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000294 // Swap in the global receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000295 __ movp(scratch,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000296 FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000297 receiver = scratch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000298 }
299 __ Push(receiver);
300 ParameterCount actual(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000301 ParameterCount expected(expected_arguments);
302 __ LoadAccessor(rdi, holder, accessor_index, ACCESSOR_GETTER);
303 __ InvokeFunction(rdi, no_reg, expected, actual, CALL_FUNCTION,
304 CheckDebugStepCallWrapper());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000305 } else {
306 // If we generate a global code snippet for deoptimization only, remember
307 // the place to continue after deoptimization.
308 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
309 }
310
311 // Restore context register.
312 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
313 }
314 __ ret(0);
315}
316
317
318static void StoreIC_PushArgs(MacroAssembler* masm) {
319 Register receiver = StoreDescriptor::ReceiverRegister();
320 Register name = StoreDescriptor::NameRegister();
321 Register value = StoreDescriptor::ValueRegister();
322
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000323 Register slot = VectorStoreICDescriptor::SlotRegister();
324 Register vector = VectorStoreICDescriptor::VectorRegister();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000325
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000326 __ PopReturnAddressTo(r11);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000327 __ Push(receiver);
328 __ Push(name);
329 __ Push(value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000330 __ Push(slot);
331 __ Push(vector);
332 __ PushReturnAddressFrom(r11);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000333}
334
335
336void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
337 // Return address is on the stack.
338 StoreIC_PushArgs(masm);
339
340 // Do tail-call to runtime routine.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000341 __ TailCallRuntime(Runtime::kStoreIC_Slow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000342}
343
344
345void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) {
346 // Return address is on the stack.
347 StoreIC_PushArgs(masm);
348
349 // Do tail-call to runtime routine.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000350 __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000351}
352
353
354#undef __
355#define __ ACCESS_MASM((masm()))
356
357
358void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
359 Handle<Name> name) {
360 if (!label->is_unused()) {
361 __ bind(label);
362 __ Move(this->name(), name);
363 }
364}
365
366
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400367void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
368 __ Move(this->name(), name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000369}
370
371
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000372void NamedStoreHandlerCompiler::RearrangeVectorAndSlot(
373 Register current_map, Register destination_map) {
374 DCHECK(false); // Not implemented.
375}
376
377
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400378void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000379 Register map_reg,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400380 Register scratch,
381 Label* miss) {
382 Handle<WeakCell> cell = Map::WeakCellForMap(transition);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400383 DCHECK(!map_reg.is(scratch));
384 __ LoadWeakValue(map_reg, cell, miss);
385 if (transition->CanBeDeprecated()) {
386 __ movl(scratch, FieldOperand(map_reg, Map::kBitField3Offset));
387 __ andl(scratch, Immediate(Map::Deprecated::kMask));
388 __ j(not_zero, miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000389 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400390}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000391
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400392
393void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
394 int descriptor,
395 Register value_reg,
396 Register scratch,
397 Label* miss_label) {
398 DCHECK(!map_reg.is(scratch));
399 DCHECK(!map_reg.is(value_reg));
400 DCHECK(!value_reg.is(scratch));
401 __ LoadInstanceDescriptors(map_reg, scratch);
402 __ movp(scratch,
403 FieldOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
404 __ cmpp(value_reg, scratch);
405 __ j(not_equal, miss_label);
406}
407
Ben Murdoch097c5b22016-05-18 11:27:45 +0100408void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400409 Register value_reg,
410 Label* miss_label) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000411 Register map_reg = scratch1();
412 Register scratch = scratch2();
413 DCHECK(!value_reg.is(map_reg));
414 DCHECK(!value_reg.is(scratch));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400415 __ JumpIfSmi(value_reg, miss_label);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100416 if (field_type->IsClass()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400417 Label do_store;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000418 __ movp(map_reg, FieldOperand(value_reg, HeapObject::kMapOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100419 __ CmpWeakValue(map_reg, Map::WeakCellForMap(field_type->AsClass()),
420 scratch);
421 __ j(not_equal, miss_label);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400422 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000423}
424
425
426Register PropertyHandlerCompiler::CheckPrototypes(
427 Register object_reg, Register holder_reg, Register scratch1,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000428 Register scratch2, Handle<Name> name, Label* miss, PrototypeCheckType check,
429 ReturnHolder return_what) {
430 Handle<Map> receiver_map = map();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000431
432 // Make sure there's no overlap between holder and object registers.
433 DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
434 DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) &&
435 !scratch2.is(scratch1));
436
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000437 if (FLAG_eliminate_prototype_chain_checks) {
438 Handle<Cell> validity_cell =
439 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
440 if (!validity_cell.is_null()) {
441 DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid),
442 validity_cell->value());
443 __ Move(scratch1, validity_cell, RelocInfo::CELL);
444 // Move(..., CELL) loads the payload's address!
445 __ SmiCompare(Operand(scratch1, 0),
446 Smi::FromInt(Map::kPrototypeChainValid));
447 __ j(not_equal, miss);
448 }
449
450 // The prototype chain of primitives (and their JSValue wrappers) depends
451 // on the native context, which can't be guarded by validity cells.
452 // |object_reg| holds the native context specific prototype in this case;
453 // we need to check its map.
454 if (check == CHECK_ALL_MAPS) {
455 __ movp(scratch1, FieldOperand(object_reg, HeapObject::kMapOffset));
456 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
457 __ CmpWeakValue(scratch1, cell, scratch2);
458 __ j(not_equal, miss);
459 }
460 }
461
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000462 // Keep track of the current object in register reg. On the first
463 // iteration, reg is an alias for object_reg, on later iterations,
464 // it is an alias for holder_reg.
465 Register reg = object_reg;
466 int depth = 0;
467
468 Handle<JSObject> current = Handle<JSObject>::null();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000469 if (receiver_map->IsJSGlobalObjectMap()) {
470 current = isolate()->global_object();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000471 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000472
473 // Check access rights to the global object. This has to happen after
474 // the map check so that we know that the object is actually a global
475 // object.
476 // This allows us to install generated handlers for accesses to the
477 // global proxy (as opposed to using slow ICs). See corresponding code
478 // in LookupForRead().
479 if (receiver_map->IsJSGlobalProxyMap()) {
480 __ CheckAccessGlobalProxy(reg, scratch2, miss);
481 }
482
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000483 Handle<JSObject> prototype = Handle<JSObject>::null();
484 Handle<Map> current_map = receiver_map;
485 Handle<Map> holder_map(holder()->map());
486 // Traverse the prototype chain and check the maps in the prototype chain for
487 // fast and global objects or do negative lookup for normal objects.
488 while (!current_map.is_identical_to(holder_map)) {
489 ++depth;
490
491 // Only global objects and objects that do not require access
492 // checks are allowed in stubs.
493 DCHECK(current_map->IsJSGlobalProxyMap() ||
494 !current_map->is_access_check_needed());
495
496 prototype = handle(JSObject::cast(current_map->prototype()));
497 if (current_map->is_dictionary_map() &&
498 !current_map->IsJSGlobalObjectMap()) {
499 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
500 if (!name->IsUniqueName()) {
501 DCHECK(name->IsString());
502 name = factory()->InternalizeString(Handle<String>::cast(name));
503 }
504 DCHECK(current.is_null() ||
505 current->property_dictionary()->FindEntry(name) ==
506 NameDictionary::kNotFound);
507
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000508 if (FLAG_eliminate_prototype_chain_checks && depth > 1) {
509 // TODO(jkummerow): Cache and re-use weak cell.
510 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
511 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000512 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
513 scratch2);
514
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000515 if (!FLAG_eliminate_prototype_chain_checks) {
516 __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
517 __ movp(holder_reg, FieldOperand(scratch1, Map::kPrototypeOffset));
518 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000519 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400520 Register map_reg = scratch1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000521 if (!FLAG_eliminate_prototype_chain_checks) {
522 __ movp(map_reg, FieldOperand(reg, HeapObject::kMapOffset));
523 }
524 if (current_map->IsJSGlobalObjectMap()) {
525 GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
526 name, scratch2, miss);
527 } else if (!FLAG_eliminate_prototype_chain_checks &&
528 (depth != 1 || check == CHECK_ALL_MAPS)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400529 Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
530 __ CmpWeakValue(map_reg, cell, scratch2);
531 __ j(not_equal, miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000532 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000533 if (!FLAG_eliminate_prototype_chain_checks) {
534 __ movp(holder_reg, FieldOperand(map_reg, Map::kPrototypeOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000535 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000536 }
537
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000538 reg = holder_reg; // From now on the object will be in holder_reg.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000539 // Go to the next object in the prototype chain.
540 current = prototype;
541 current_map = handle(current->map());
542 }
543
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000544 DCHECK(!current_map->IsJSGlobalProxyMap());
545
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000546 // Log the check depth.
547 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
548
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000549 if (!FLAG_eliminate_prototype_chain_checks &&
550 (depth != 0 || check == CHECK_ALL_MAPS)) {
551 // Check the holder map.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400552 __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
553 Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
554 __ CmpWeakValue(scratch1, cell, scratch2);
555 __ j(not_equal, miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000556 }
557
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000558 bool return_holder = return_what == RETURN_HOLDER;
559 if (FLAG_eliminate_prototype_chain_checks && return_holder && depth != 0) {
560 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000561 }
562
563 // Return the register containing the holder.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000564 return return_holder ? reg : no_reg;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000565}
566
567
568void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
569 if (!miss->is_unused()) {
570 Label success;
571 __ jmp(&success);
572 __ bind(miss);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400573 if (IC::ICUseVector(kind())) {
574 DCHECK(kind() == Code::LOAD_IC);
575 PopVectorAndSlot();
576 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000577 TailCallBuiltin(masm(), MissBuiltin(kind()));
578 __ bind(&success);
579 }
580}
581
582
583void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
584 if (!miss->is_unused()) {
585 Label success;
586 __ jmp(&success);
587 GenerateRestoreName(miss, name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000588 if (IC::ICUseVector(kind())) PopVectorAndSlot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000589 TailCallBuiltin(masm(), MissBuiltin(kind()));
590 __ bind(&success);
591 }
592}
593
594
595void NamedLoadHandlerCompiler::GenerateLoadCallback(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100596 Register reg, Handle<AccessorInfo> callback) {
597 DCHECK(!AreAliased(kScratchRegister, scratch2(), scratch3(), receiver()));
598 DCHECK(!AreAliased(kScratchRegister, scratch2(), scratch3(), reg));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000599
Ben Murdoch097c5b22016-05-18 11:27:45 +0100600 // Insert additional parameters into the stack frame above return address.
601 __ PopReturnAddressTo(scratch3());
602
603 // Build v8::PropertyCallbackInfo::args_ array on the stack and push property
604 // name below the exit frame to make GC aware of them.
605 STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0);
606 STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1);
607 STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2);
608 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3);
609 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4);
610 STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5);
611 STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6);
612 STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7);
613
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000614 __ Push(receiver()); // receiver
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000615 Handle<Object> data(callback->data(), isolate());
616 if (data->IsUndefined() || data->IsSmi()) {
617 __ Push(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000618 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000619 Handle<WeakCell> cell =
620 isolate()->factory()->NewWeakCell(Handle<HeapObject>::cast(data));
621 // The callback is alive if this instruction is executed,
622 // so the weak cell is not cleared and points to data.
623 __ GetWeakValue(scratch2(), cell);
624 __ Push(scratch2());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000625 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000626 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
627 __ Push(kScratchRegister); // return value
628 __ Push(kScratchRegister); // return value default
629 __ PushAddress(ExternalReference::isolate_address(isolate()));
630 __ Push(reg); // holder
Ben Murdoch097c5b22016-05-18 11:27:45 +0100631 __ Push(Smi::FromInt(0)); // should_throw_on_error -> false
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000632
Ben Murdoch097c5b22016-05-18 11:27:45 +0100633 __ Push(name()); // name
634 __ PushReturnAddressFrom(scratch3());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000635
636 // Abi for CallApiGetter
637 Register api_function_address = ApiGetterDescriptor::function_address();
638 Address getter_address = v8::ToCData<Address>(callback->getter());
639 __ Move(api_function_address, getter_address, RelocInfo::EXTERNAL_REFERENCE);
640
641 CallApiGetterStub stub(isolate());
642 __ TailCallStub(&stub);
643}
644
645
646void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
647 // Return the constant value.
648 __ Move(rax, value);
649 __ ret(0);
650}
651
652
653void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
654 LookupIterator* it, Register holder_reg) {
655 DCHECK(holder()->HasNamedInterceptor());
656 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
657
658 // Compile the interceptor call, followed by inline code to load the
659 // property from further up the prototype chain if the call fails.
660 // Check that the maps haven't changed.
661 DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
662
663 // Preserve the receiver register explicitly whenever it is different from the
664 // holder and it is needed should the interceptor return without any result.
665 // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
666 // case might cause a miss during the prototype check.
667 bool must_perform_prototype_check =
668 !holder().is_identical_to(it->GetHolder<JSObject>());
669 bool must_preserve_receiver_reg =
670 !receiver().is(holder_reg) &&
671 (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
672
673 // Save necessary data before invoking an interceptor.
674 // Requires a frame to make GC aware of pushed pointers.
675 {
676 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
677
678 if (must_preserve_receiver_reg) {
679 __ Push(receiver());
680 }
681 __ Push(holder_reg);
682 __ Push(this->name());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400683 InterceptorVectorSlotPush(holder_reg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000684
685 // Invoke an interceptor. Note: map checks from receiver to
686 // interceptor's holder has been compiled before (see a caller
687 // of this method.)
688 CompileCallLoadPropertyWithInterceptor(
689 masm(), receiver(), holder_reg, this->name(), holder(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000690 Runtime::kLoadPropertyWithInterceptorOnly);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000691
692 // Check if interceptor provided a value for property. If it's
693 // the case, return immediately.
694 Label interceptor_failed;
695 __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
696 __ j(equal, &interceptor_failed);
697 frame_scope.GenerateLeaveFrame();
698 __ ret(0);
699
700 __ bind(&interceptor_failed);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400701 InterceptorVectorSlotPop(holder_reg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000702 __ Pop(this->name());
703 __ Pop(holder_reg);
704 if (must_preserve_receiver_reg) {
705 __ Pop(receiver());
706 }
707
708 // Leave the internal frame.
709 }
710
711 GenerateLoadPostInterceptor(it, holder_reg);
712}
713
714
715void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
716 // Call the runtime system to load the interceptor.
717 DCHECK(holder()->HasNamedInterceptor());
718 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
719 __ PopReturnAddressTo(scratch2());
720 PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
721 holder());
722 __ PushReturnAddressFrom(scratch2());
723
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000724 __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000725}
726
727
728Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100729 Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
730 LanguageMode language_mode) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400731 Register holder_reg = Frontend(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000732
733 __ PopReturnAddressTo(scratch1());
734 __ Push(receiver());
735 __ Push(holder_reg);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000736 // If the callback cannot leak, then push the callback directly,
737 // otherwise wrap it in a weak cell.
738 if (callback->data()->IsUndefined() || callback->data()->IsSmi()) {
739 __ Push(callback);
740 } else {
741 Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
742 __ Push(cell);
743 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000744 __ Push(name);
745 __ Push(value());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100746 __ Push(Smi::FromInt(language_mode));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000747 __ PushReturnAddressFrom(scratch1());
748
749 // Do tail-call to the runtime system.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000750 __ TailCallRuntime(Runtime::kStoreCallbackProperty);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000751
752 // Return the generated code.
753 return GetCode(kind(), Code::FAST, name);
754}
755
756
757Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor(
758 Handle<Name> name) {
759 __ PopReturnAddressTo(scratch1());
760 __ Push(receiver());
761 __ Push(this->name());
762 __ Push(value());
763 __ PushReturnAddressFrom(scratch1());
764
765 // Do tail-call to the runtime system.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000766 __ TailCallRuntime(Runtime::kStorePropertyWithInterceptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000767
768 // Return the generated code.
769 return GetCode(kind(), Code::FAST, name);
770}
771
772
773Register NamedStoreHandlerCompiler::value() {
774 return StoreDescriptor::ValueRegister();
775}
776
777
778Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
779 Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
780 Label miss;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400781 if (IC::ICUseVector(kind())) {
782 PushVectorAndSlot();
783 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000784 FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000785
786 // Get the value from the cell.
787 Register result = StoreDescriptor::ValueRegister();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400788 Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
789 __ LoadWeakValue(result, weak_cell, &miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000790 __ movp(result, FieldOperand(result, PropertyCell::kValueOffset));
791
792 // Check for deleted property if property can actually be deleted.
793 if (is_configurable) {
794 __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
795 __ j(equal, &miss);
796 } else if (FLAG_debug_code) {
797 __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
798 __ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
799 }
800
801 Counters* counters = isolate()->counters();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100802 __ IncrementCounter(counters->ic_named_load_global_stub(), 1);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400803 if (IC::ICUseVector(kind())) {
804 DiscardVectorAndSlot();
805 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000806 __ ret(0);
807
808 FrontendFooter(name, &miss);
809
810 // Return the generated code.
811 return GetCode(kind(), Code::NORMAL, name);
812}
813
814
815#undef __
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000816} // namespace internal
817} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000818
819#endif // V8_TARGET_ARCH_X64