blob: c09eca68dd6f96d3bd1c9ef47dff16f76a653314 [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
7#include "src/ic/call-optimization.h"
8#include "src/ic/handler-compiler.h"
9#include "src/ic/ic.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010#include "src/isolate-inl.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011
12namespace v8 {
13namespace internal {
14
15#define __ ACCESS_MASM(masm)
16
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017void PropertyHandlerCompiler::PushVectorAndSlot(Register vector,
18 Register slot) {
19 MacroAssembler* masm = this->masm();
20 __ Push(vector);
21 __ Push(slot);
22}
23
24
25void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) {
26 MacroAssembler* masm = this->masm();
27 __ Pop(slot);
28 __ Pop(vector);
29}
30
31
32void PropertyHandlerCompiler::DiscardVectorAndSlot() {
33 MacroAssembler* masm = this->masm();
34 // Remove vector and slot.
35 __ addp(rsp, Immediate(2 * kPointerSize));
36}
37
38
Ben Murdochb8a8cc12014-11-26 15:28:44 +000039void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
40 MacroAssembler* masm, Label* miss_label, Register receiver,
41 Handle<Name> name, Register scratch0, Register scratch1) {
42 DCHECK(name->IsUniqueName());
43 DCHECK(!receiver.is(scratch0));
44 Counters* counters = masm->isolate()->counters();
45 __ IncrementCounter(counters->negative_lookups(), 1);
46 __ IncrementCounter(counters->negative_lookups_miss(), 1);
47
48 __ movp(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
49
50 const int kInterceptorOrAccessCheckNeededMask =
51 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
52
53 // Bail out if the receiver has a named interceptor or requires access checks.
54 __ testb(FieldOperand(scratch0, Map::kBitFieldOffset),
55 Immediate(kInterceptorOrAccessCheckNeededMask));
56 __ j(not_zero, miss_label);
57
58 // Check that receiver is a JSObject.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000059 __ CmpInstanceType(scratch0, FIRST_JS_RECEIVER_TYPE);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000060 __ j(below, miss_label);
61
62 // Load properties array.
63 Register properties = scratch0;
64 __ movp(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
65
66 // Check that the properties array is a dictionary.
67 __ CompareRoot(FieldOperand(properties, HeapObject::kMapOffset),
68 Heap::kHashTableMapRootIndex);
69 __ j(not_equal, miss_label);
70
71 Label done;
72 NameDictionaryLookupStub::GenerateNegativeLookup(masm, miss_label, &done,
73 properties, name, scratch1);
74 __ bind(&done);
75 __ DecrementCounter(counters->negative_lookups_miss(), 1);
76}
77
78
79void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040080 MacroAssembler* masm, int index, Register result, Label* miss) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000081 __ LoadNativeContextSlot(index, result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000082 // Load its initial map. The global functions all have initial maps.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040083 __ movp(result,
84 FieldOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000085 // Load the prototype from the initial map.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040086 __ movp(result, FieldOperand(result, Map::kPrototypeOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000087}
88
89
90void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
91 MacroAssembler* masm, Register receiver, Register result, Register scratch,
92 Label* miss_label) {
93 __ TryGetFunctionPrototype(receiver, result, miss_label);
94 if (!result.is(rax)) __ movp(rax, result);
95 __ ret(0);
96}
97
98
99static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
100 Register holder, Register name,
101 Handle<JSObject> holder_obj) {
102 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000103 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
104 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
105 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000106 __ Push(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000107 __ Push(receiver);
108 __ Push(holder);
109}
110
111
112static void CompileCallLoadPropertyWithInterceptor(
113 MacroAssembler* masm, Register receiver, Register holder, Register name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000114 Handle<JSObject> holder_obj, Runtime::FunctionId id) {
115 DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
116 Runtime::FunctionForId(id)->nargs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000117 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000118 __ CallRuntime(id);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000119}
120
121
122// Generate call to api function.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000123void PropertyHandlerCompiler::GenerateApiAccessorCall(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000124 MacroAssembler* masm, const CallOptimization& optimization,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000125 Handle<Map> receiver_map, Register receiver, Register scratch,
126 bool is_store, Register store_parameter, Register accessor_holder,
127 int accessor_index) {
128 DCHECK(!accessor_holder.is(scratch));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000129 DCHECK(optimization.is_simple_api_call());
130
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000131 __ PopReturnAddressTo(scratch);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000132 // receiver
133 __ Push(receiver);
134 // Write the arguments to stack frame.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000135 if (is_store) {
136 DCHECK(!receiver.is(store_parameter));
137 DCHECK(!scratch.is(store_parameter));
138 __ Push(store_parameter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000139 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000140 __ PushReturnAddressFrom(scratch);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000141 // Stack now matches JSFunction abi.
142
143 // Abi for CallApiFunctionStub.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000144 Register callee = rdi;
145 Register data = rbx;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000146 Register holder = rcx;
147 Register api_function_address = rdx;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000148 scratch = no_reg;
149
150 // Put callee in place.
151 __ LoadAccessor(callee, accessor_holder, accessor_index,
152 is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000153
154 // Put holder in place.
155 CallOptimization::HolderLookup holder_lookup;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000156 int holder_depth = 0;
157 optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup,
158 &holder_depth);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000159 switch (holder_lookup) {
160 case CallOptimization::kHolderIsReceiver:
161 __ Move(holder, receiver);
162 break;
163 case CallOptimization::kHolderFound:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000164 __ movp(holder, FieldOperand(receiver, HeapObject::kMapOffset));
165 __ movp(holder, FieldOperand(holder, Map::kPrototypeOffset));
166 for (int i = 1; i < holder_depth; i++) {
167 __ movp(holder, FieldOperand(holder, HeapObject::kMapOffset));
168 __ movp(holder, FieldOperand(holder, Map::kPrototypeOffset));
169 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000170 break;
171 case CallOptimization::kHolderNotFound:
172 UNREACHABLE();
173 break;
174 }
175
176 Isolate* isolate = masm->isolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000177 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000178 bool call_data_undefined = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000179 // Put call data in place.
180 if (api_call_info->data()->IsUndefined()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000181 call_data_undefined = true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000182 __ LoadRoot(data, Heap::kUndefinedValueRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000183 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000184 __ movp(data, FieldOperand(callee, JSFunction::kSharedFunctionInfoOffset));
185 __ movp(data, FieldOperand(data, SharedFunctionInfo::kFunctionDataOffset));
186 __ movp(data, FieldOperand(data, FunctionTemplateInfo::kCallCodeOffset));
187 __ movp(data, FieldOperand(data, CallHandlerInfo::kDataOffset));
188 }
189
190 if (api_call_info->fast_handler()->IsCode()) {
191 // Just tail call into the fast handler if present.
192 __ Jump(handle(Code::cast(api_call_info->fast_handler())),
193 RelocInfo::CODE_TARGET);
194 return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000195 }
196
197 // Put api_function_address in place.
198 Address function_address = v8::ToCData<Address>(api_call_info->callback());
199 __ Move(api_function_address, function_address,
200 RelocInfo::EXTERNAL_REFERENCE);
201
202 // Jump to stub.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000203 CallApiAccessorStub stub(isolate, is_store, call_data_undefined);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000204 __ TailCallStub(&stub);
205}
206
207
208void PropertyHandlerCompiler::GenerateCheckPropertyCell(
209 MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
210 Register scratch, Label* miss) {
211 Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
212 DCHECK(cell->value()->IsTheHole());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000213 Factory* factory = masm->isolate()->factory();
214 Handle<WeakCell> weak_cell = factory->NewWeakCell(cell);
215 __ LoadWeakValue(scratch, weak_cell, miss);
216 __ Cmp(FieldOperand(scratch, PropertyCell::kValueOffset),
217 factory->the_hole_value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000218 __ j(not_equal, miss);
219}
220
221
222void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000223 MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
224 int accessor_index, int expected_arguments, Register scratch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000225 // ----------- S t a t e -------------
226 // -- rsp[0] : return address
227 // -----------------------------------
228 {
229 FrameScope scope(masm, StackFrame::INTERNAL);
230
231 // Save value register, so we can restore it later.
232 __ Push(value());
233
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000234 if (accessor_index >= 0) {
235 DCHECK(!holder.is(scratch));
236 DCHECK(!receiver.is(scratch));
237 DCHECK(!value().is(scratch));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000238 // Call the JavaScript setter with receiver and value on the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000239 if (map->IsJSGlobalObjectMap()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000240 // Swap in the global receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000241 __ movp(scratch,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000242 FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000243 receiver = scratch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000244 }
245 __ Push(receiver);
246 __ Push(value());
247 ParameterCount actual(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000248 ParameterCount expected(expected_arguments);
249 __ LoadAccessor(rdi, holder, accessor_index, ACCESSOR_SETTER);
250 __ InvokeFunction(rdi, no_reg, expected, actual, CALL_FUNCTION,
251 CheckDebugStepCallWrapper());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000252 } else {
253 // If we generate a global code snippet for deoptimization only, remember
254 // the place to continue after deoptimization.
255 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
256 }
257
258 // We have to return the passed value, not the return value of the setter.
259 __ Pop(rax);
260
261 // Restore context register.
262 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
263 }
264 __ ret(0);
265}
266
267
268void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000269 MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
270 int accessor_index, int expected_arguments, Register scratch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000271 // ----------- S t a t e -------------
272 // -- rax : receiver
273 // -- rcx : name
274 // -- rsp[0] : return address
275 // -----------------------------------
276 {
277 FrameScope scope(masm, StackFrame::INTERNAL);
278
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000279 if (accessor_index >= 0) {
280 DCHECK(!holder.is(scratch));
281 DCHECK(!receiver.is(scratch));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000282 // Call the JavaScript getter with the receiver on the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000283 if (map->IsJSGlobalObjectMap()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000284 // Swap in the global receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000285 __ movp(scratch,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000286 FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000287 receiver = scratch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000288 }
289 __ Push(receiver);
290 ParameterCount actual(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000291 ParameterCount expected(expected_arguments);
292 __ LoadAccessor(rdi, holder, accessor_index, ACCESSOR_GETTER);
293 __ InvokeFunction(rdi, no_reg, expected, actual, CALL_FUNCTION,
294 CheckDebugStepCallWrapper());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000295 } else {
296 // If we generate a global code snippet for deoptimization only, remember
297 // the place to continue after deoptimization.
298 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
299 }
300
301 // Restore context register.
302 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
303 }
304 __ ret(0);
305}
306
307
308static void StoreIC_PushArgs(MacroAssembler* masm) {
309 Register receiver = StoreDescriptor::ReceiverRegister();
310 Register name = StoreDescriptor::NameRegister();
311 Register value = StoreDescriptor::ValueRegister();
312
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000313 Register slot = VectorStoreICDescriptor::SlotRegister();
314 Register vector = VectorStoreICDescriptor::VectorRegister();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000315
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000316 __ PopReturnAddressTo(r11);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000317 __ Push(receiver);
318 __ Push(name);
319 __ Push(value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000320 __ Push(slot);
321 __ Push(vector);
322 __ PushReturnAddressFrom(r11);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000323}
324
325
326void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
327 // Return address is on the stack.
328 StoreIC_PushArgs(masm);
329
330 // Do tail-call to runtime routine.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000331 __ TailCallRuntime(Runtime::kStoreIC_Slow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000332}
333
334
335void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) {
336 // Return address is on the stack.
337 StoreIC_PushArgs(masm);
338
339 // Do tail-call to runtime routine.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000340 __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000341}
342
343
344#undef __
345#define __ ACCESS_MASM((masm()))
346
347
348void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
349 Handle<Name> name) {
350 if (!label->is_unused()) {
351 __ bind(label);
352 __ Move(this->name(), name);
353 }
354}
355
356
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400357void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
358 __ Move(this->name(), name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000359}
360
361
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000362void NamedStoreHandlerCompiler::RearrangeVectorAndSlot(
363 Register current_map, Register destination_map) {
364 DCHECK(false); // Not implemented.
365}
366
367
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400368void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000369 Register map_reg,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400370 Register scratch,
371 Label* miss) {
372 Handle<WeakCell> cell = Map::WeakCellForMap(transition);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400373 DCHECK(!map_reg.is(scratch));
374 __ LoadWeakValue(map_reg, cell, miss);
375 if (transition->CanBeDeprecated()) {
376 __ movl(scratch, FieldOperand(map_reg, Map::kBitField3Offset));
377 __ andl(scratch, Immediate(Map::Deprecated::kMask));
378 __ j(not_zero, miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000379 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400380}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000381
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400382
383void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
384 int descriptor,
385 Register value_reg,
386 Register scratch,
387 Label* miss_label) {
388 DCHECK(!map_reg.is(scratch));
389 DCHECK(!map_reg.is(value_reg));
390 DCHECK(!value_reg.is(scratch));
391 __ LoadInstanceDescriptors(map_reg, scratch);
392 __ movp(scratch,
393 FieldOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
394 __ cmpp(value_reg, scratch);
395 __ j(not_equal, miss_label);
396}
397
398
399void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(HeapType* field_type,
400 Register value_reg,
401 Label* miss_label) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000402 Register map_reg = scratch1();
403 Register scratch = scratch2();
404 DCHECK(!value_reg.is(map_reg));
405 DCHECK(!value_reg.is(scratch));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400406 __ JumpIfSmi(value_reg, miss_label);
407 HeapType::Iterator<Map> it = field_type->Classes();
408 if (!it.Done()) {
409 Label do_store;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000410 __ movp(map_reg, FieldOperand(value_reg, HeapObject::kMapOffset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400411 while (true) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000412 __ CmpWeakValue(map_reg, Map::WeakCellForMap(it.Current()), scratch);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400413 it.Advance();
414 if (it.Done()) {
415 __ j(not_equal, miss_label);
416 break;
417 }
418 __ j(equal, &do_store, Label::kNear);
419 }
420 __ bind(&do_store);
421 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000422}
423
424
425Register PropertyHandlerCompiler::CheckPrototypes(
426 Register object_reg, Register holder_reg, Register scratch1,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000427 Register scratch2, Handle<Name> name, Label* miss, PrototypeCheckType check,
428 ReturnHolder return_what) {
429 Handle<Map> receiver_map = map();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000430
431 // Make sure there's no overlap between holder and object registers.
432 DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
433 DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) &&
434 !scratch2.is(scratch1));
435
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000436 if (FLAG_eliminate_prototype_chain_checks) {
437 Handle<Cell> validity_cell =
438 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
439 if (!validity_cell.is_null()) {
440 DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid),
441 validity_cell->value());
442 __ Move(scratch1, validity_cell, RelocInfo::CELL);
443 // Move(..., CELL) loads the payload's address!
444 __ SmiCompare(Operand(scratch1, 0),
445 Smi::FromInt(Map::kPrototypeChainValid));
446 __ j(not_equal, miss);
447 }
448
449 // The prototype chain of primitives (and their JSValue wrappers) depends
450 // on the native context, which can't be guarded by validity cells.
451 // |object_reg| holds the native context specific prototype in this case;
452 // we need to check its map.
453 if (check == CHECK_ALL_MAPS) {
454 __ movp(scratch1, FieldOperand(object_reg, HeapObject::kMapOffset));
455 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
456 __ CmpWeakValue(scratch1, cell, scratch2);
457 __ j(not_equal, miss);
458 }
459 }
460
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000461 // Keep track of the current object in register reg. On the first
462 // iteration, reg is an alias for object_reg, on later iterations,
463 // it is an alias for holder_reg.
464 Register reg = object_reg;
465 int depth = 0;
466
467 Handle<JSObject> current = Handle<JSObject>::null();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000468 if (receiver_map->IsJSGlobalObjectMap()) {
469 current = isolate()->global_object();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000470 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000471
472 // Check access rights to the global object. This has to happen after
473 // the map check so that we know that the object is actually a global
474 // object.
475 // This allows us to install generated handlers for accesses to the
476 // global proxy (as opposed to using slow ICs). See corresponding code
477 // in LookupForRead().
478 if (receiver_map->IsJSGlobalProxyMap()) {
479 __ CheckAccessGlobalProxy(reg, scratch2, miss);
480 }
481
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000482 Handle<JSObject> prototype = Handle<JSObject>::null();
483 Handle<Map> current_map = receiver_map;
484 Handle<Map> holder_map(holder()->map());
485 // Traverse the prototype chain and check the maps in the prototype chain for
486 // fast and global objects or do negative lookup for normal objects.
487 while (!current_map.is_identical_to(holder_map)) {
488 ++depth;
489
490 // Only global objects and objects that do not require access
491 // checks are allowed in stubs.
492 DCHECK(current_map->IsJSGlobalProxyMap() ||
493 !current_map->is_access_check_needed());
494
495 prototype = handle(JSObject::cast(current_map->prototype()));
496 if (current_map->is_dictionary_map() &&
497 !current_map->IsJSGlobalObjectMap()) {
498 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
499 if (!name->IsUniqueName()) {
500 DCHECK(name->IsString());
501 name = factory()->InternalizeString(Handle<String>::cast(name));
502 }
503 DCHECK(current.is_null() ||
504 current->property_dictionary()->FindEntry(name) ==
505 NameDictionary::kNotFound);
506
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000507 if (FLAG_eliminate_prototype_chain_checks && depth > 1) {
508 // TODO(jkummerow): Cache and re-use weak cell.
509 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
510 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000511 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
512 scratch2);
513
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000514 if (!FLAG_eliminate_prototype_chain_checks) {
515 __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
516 __ movp(holder_reg, FieldOperand(scratch1, Map::kPrototypeOffset));
517 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000518 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400519 Register map_reg = scratch1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000520 if (!FLAG_eliminate_prototype_chain_checks) {
521 __ movp(map_reg, FieldOperand(reg, HeapObject::kMapOffset));
522 }
523 if (current_map->IsJSGlobalObjectMap()) {
524 GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
525 name, scratch2, miss);
526 } else if (!FLAG_eliminate_prototype_chain_checks &&
527 (depth != 1 || check == CHECK_ALL_MAPS)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400528 Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
529 __ CmpWeakValue(map_reg, cell, scratch2);
530 __ j(not_equal, miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000531 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000532 if (!FLAG_eliminate_prototype_chain_checks) {
533 __ movp(holder_reg, FieldOperand(map_reg, Map::kPrototypeOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000534 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000535 }
536
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000537 reg = holder_reg; // From now on the object will be in holder_reg.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000538 // Go to the next object in the prototype chain.
539 current = prototype;
540 current_map = handle(current->map());
541 }
542
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000543 DCHECK(!current_map->IsJSGlobalProxyMap());
544
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000545 // Log the check depth.
546 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
547
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000548 if (!FLAG_eliminate_prototype_chain_checks &&
549 (depth != 0 || check == CHECK_ALL_MAPS)) {
550 // Check the holder map.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400551 __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
552 Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
553 __ CmpWeakValue(scratch1, cell, scratch2);
554 __ j(not_equal, miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000555 }
556
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000557 bool return_holder = return_what == RETURN_HOLDER;
558 if (FLAG_eliminate_prototype_chain_checks && return_holder && depth != 0) {
559 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000560 }
561
562 // Return the register containing the holder.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000563 return return_holder ? reg : no_reg;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000564}
565
566
567void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
568 if (!miss->is_unused()) {
569 Label success;
570 __ jmp(&success);
571 __ bind(miss);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400572 if (IC::ICUseVector(kind())) {
573 DCHECK(kind() == Code::LOAD_IC);
574 PopVectorAndSlot();
575 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000576 TailCallBuiltin(masm(), MissBuiltin(kind()));
577 __ bind(&success);
578 }
579}
580
581
582void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
583 if (!miss->is_unused()) {
584 Label success;
585 __ jmp(&success);
586 GenerateRestoreName(miss, name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000587 if (IC::ICUseVector(kind())) PopVectorAndSlot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000588 TailCallBuiltin(masm(), MissBuiltin(kind()));
589 __ bind(&success);
590 }
591}
592
593
594void NamedLoadHandlerCompiler::GenerateLoadCallback(
595 Register reg, Handle<ExecutableAccessorInfo> callback) {
596 // Insert additional parameters into the stack frame above return address.
597 DCHECK(!scratch4().is(reg));
598 __ PopReturnAddressTo(scratch4());
599
600 STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0);
601 STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1);
602 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2);
603 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3);
604 STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4);
605 STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5);
606 STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6);
607 __ Push(receiver()); // receiver
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000608 Handle<Object> data(callback->data(), isolate());
609 if (data->IsUndefined() || data->IsSmi()) {
610 __ Push(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000611 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000612 DCHECK(!scratch2().is(reg));
613 Handle<WeakCell> cell =
614 isolate()->factory()->NewWeakCell(Handle<HeapObject>::cast(data));
615 // The callback is alive if this instruction is executed,
616 // so the weak cell is not cleared and points to data.
617 __ GetWeakValue(scratch2(), cell);
618 __ Push(scratch2());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000619 }
620 DCHECK(!kScratchRegister.is(reg));
621 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
622 __ Push(kScratchRegister); // return value
623 __ Push(kScratchRegister); // return value default
624 __ PushAddress(ExternalReference::isolate_address(isolate()));
625 __ Push(reg); // holder
626 __ Push(name()); // name
627 // Save a pointer to where we pushed the arguments pointer. This will be
628 // passed as the const PropertyAccessorInfo& to the C++ callback.
629
630 __ PushReturnAddressFrom(scratch4());
631
632 // Abi for CallApiGetter
633 Register api_function_address = ApiGetterDescriptor::function_address();
634 Address getter_address = v8::ToCData<Address>(callback->getter());
635 __ Move(api_function_address, getter_address, RelocInfo::EXTERNAL_REFERENCE);
636
637 CallApiGetterStub stub(isolate());
638 __ TailCallStub(&stub);
639}
640
641
642void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
643 // Return the constant value.
644 __ Move(rax, value);
645 __ ret(0);
646}
647
648
649void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
650 LookupIterator* it, Register holder_reg) {
651 DCHECK(holder()->HasNamedInterceptor());
652 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
653
654 // Compile the interceptor call, followed by inline code to load the
655 // property from further up the prototype chain if the call fails.
656 // Check that the maps haven't changed.
657 DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
658
659 // Preserve the receiver register explicitly whenever it is different from the
660 // holder and it is needed should the interceptor return without any result.
661 // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
662 // case might cause a miss during the prototype check.
663 bool must_perform_prototype_check =
664 !holder().is_identical_to(it->GetHolder<JSObject>());
665 bool must_preserve_receiver_reg =
666 !receiver().is(holder_reg) &&
667 (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
668
669 // Save necessary data before invoking an interceptor.
670 // Requires a frame to make GC aware of pushed pointers.
671 {
672 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
673
674 if (must_preserve_receiver_reg) {
675 __ Push(receiver());
676 }
677 __ Push(holder_reg);
678 __ Push(this->name());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400679 InterceptorVectorSlotPush(holder_reg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000680
681 // Invoke an interceptor. Note: map checks from receiver to
682 // interceptor's holder has been compiled before (see a caller
683 // of this method.)
684 CompileCallLoadPropertyWithInterceptor(
685 masm(), receiver(), holder_reg, this->name(), holder(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000686 Runtime::kLoadPropertyWithInterceptorOnly);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000687
688 // Check if interceptor provided a value for property. If it's
689 // the case, return immediately.
690 Label interceptor_failed;
691 __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
692 __ j(equal, &interceptor_failed);
693 frame_scope.GenerateLeaveFrame();
694 __ ret(0);
695
696 __ bind(&interceptor_failed);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400697 InterceptorVectorSlotPop(holder_reg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000698 __ Pop(this->name());
699 __ Pop(holder_reg);
700 if (must_preserve_receiver_reg) {
701 __ Pop(receiver());
702 }
703
704 // Leave the internal frame.
705 }
706
707 GenerateLoadPostInterceptor(it, holder_reg);
708}
709
710
711void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
712 // Call the runtime system to load the interceptor.
713 DCHECK(holder()->HasNamedInterceptor());
714 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
715 __ PopReturnAddressTo(scratch2());
716 PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
717 holder());
718 __ PushReturnAddressFrom(scratch2());
719
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000720 __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000721}
722
723
724Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
725 Handle<JSObject> object, Handle<Name> name,
726 Handle<ExecutableAccessorInfo> callback) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400727 Register holder_reg = Frontend(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000728
729 __ PopReturnAddressTo(scratch1());
730 __ Push(receiver());
731 __ Push(holder_reg);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000732 // If the callback cannot leak, then push the callback directly,
733 // otherwise wrap it in a weak cell.
734 if (callback->data()->IsUndefined() || callback->data()->IsSmi()) {
735 __ Push(callback);
736 } else {
737 Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
738 __ Push(cell);
739 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000740 __ Push(name);
741 __ Push(value());
742 __ PushReturnAddressFrom(scratch1());
743
744 // Do tail-call to the runtime system.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000745 __ TailCallRuntime(Runtime::kStoreCallbackProperty);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000746
747 // Return the generated code.
748 return GetCode(kind(), Code::FAST, name);
749}
750
751
752Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor(
753 Handle<Name> name) {
754 __ PopReturnAddressTo(scratch1());
755 __ Push(receiver());
756 __ Push(this->name());
757 __ Push(value());
758 __ PushReturnAddressFrom(scratch1());
759
760 // Do tail-call to the runtime system.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000761 __ TailCallRuntime(Runtime::kStorePropertyWithInterceptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000762
763 // Return the generated code.
764 return GetCode(kind(), Code::FAST, name);
765}
766
767
768Register NamedStoreHandlerCompiler::value() {
769 return StoreDescriptor::ValueRegister();
770}
771
772
773Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
774 Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
775 Label miss;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400776 if (IC::ICUseVector(kind())) {
777 PushVectorAndSlot();
778 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000779 FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000780
781 // Get the value from the cell.
782 Register result = StoreDescriptor::ValueRegister();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400783 Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
784 __ LoadWeakValue(result, weak_cell, &miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000785 __ movp(result, FieldOperand(result, PropertyCell::kValueOffset));
786
787 // Check for deleted property if property can actually be deleted.
788 if (is_configurable) {
789 __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
790 __ j(equal, &miss);
791 } else if (FLAG_debug_code) {
792 __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
793 __ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
794 }
795
796 Counters* counters = isolate()->counters();
797 __ IncrementCounter(counters->named_load_global_stub(), 1);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400798 if (IC::ICUseVector(kind())) {
799 DiscardVectorAndSlot();
800 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000801 __ ret(0);
802
803 FrontendFooter(name, &miss);
804
805 // Return the generated code.
806 return GetCode(kind(), Code::NORMAL, name);
807}
808
809
810#undef __
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000811} // namespace internal
812} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000813
814#endif // V8_TARGET_ARCH_X64