blob: 6e7d78afd3ef315a75899cc95339680d9be31751 [file] [log] [blame]
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001// 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
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005#if V8_TARGET_ARCH_PPC
6
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007#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"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011#include "src/ic/ic.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012#include "src/isolate-inl.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013
14namespace v8 {
15namespace internal {
16
17#define __ ACCESS_MASM(masm)
18
19
20void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000021 MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
22 int accessor_index, int expected_arguments, Register scratch) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040023 // ----------- S t a t e -------------
24 // -- r3 : receiver
25 // -- r5 : name
26 // -- lr : return address
27 // -----------------------------------
28 {
29 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
30
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000031 if (accessor_index >= 0) {
32 DCHECK(!holder.is(scratch));
33 DCHECK(!receiver.is(scratch));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040034 // Call the JavaScript getter with the receiver on the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000035 if (map->IsJSGlobalObjectMap()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040036 // Swap in the global receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000037 __ LoadP(scratch,
Emily Bernierd0a1eb72015-03-24 16:35:39 -040038 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000039 receiver = scratch;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040040 }
41 __ push(receiver);
42 ParameterCount actual(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000043 ParameterCount expected(expected_arguments);
44 __ LoadAccessor(r4, holder, accessor_index, ACCESSOR_GETTER);
45 __ InvokeFunction(r4, expected, actual, CALL_FUNCTION,
46 CheckDebugStepCallWrapper());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040047 } else {
48 // If we generate a global code snippet for deoptimization only, remember
49 // the place to continue after deoptimization.
50 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
51 }
52
53 // Restore context register.
54 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
55 }
56 __ Ret();
57}
58
59
60void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000061 MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
62 int accessor_index, int expected_arguments, Register scratch) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040063 // ----------- S t a t e -------------
64 // -- lr : return address
65 // -----------------------------------
66 {
67 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
68
69 // Save value register, so we can restore it later.
70 __ push(value());
71
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000072 if (accessor_index >= 0) {
73 DCHECK(!holder.is(scratch));
74 DCHECK(!receiver.is(scratch));
75 DCHECK(!value().is(scratch));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040076 // Call the JavaScript setter with receiver and value on the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000077 if (map->IsJSGlobalObjectMap()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040078 // Swap in the global receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000079 __ LoadP(scratch,
Emily Bernierd0a1eb72015-03-24 16:35:39 -040080 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000081 receiver = scratch;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040082 }
83 __ Push(receiver, value());
84 ParameterCount actual(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000085 ParameterCount expected(expected_arguments);
86 __ LoadAccessor(r4, holder, accessor_index, ACCESSOR_SETTER);
87 __ InvokeFunction(r4, expected, actual, CALL_FUNCTION,
88 CheckDebugStepCallWrapper());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040089 } else {
90 // If we generate a global code snippet for deoptimization only, remember
91 // the place to continue after deoptimization.
92 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
93 }
94
95 // We have to return the passed value, not the return value of the setter.
96 __ pop(r3);
97
98 // Restore context register.
99 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
100 }
101 __ Ret();
102}
103
104
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000105void PropertyHandlerCompiler::PushVectorAndSlot(Register vector,
106 Register slot) {
107 MacroAssembler* masm = this->masm();
108 __ Push(vector, slot);
109}
110
111
112void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) {
113 MacroAssembler* masm = this->masm();
114 __ Pop(vector, slot);
115}
116
117
118void PropertyHandlerCompiler::DiscardVectorAndSlot() {
119 MacroAssembler* masm = this->masm();
120 // Remove vector and slot.
121 __ addi(sp, sp, Operand(2 * kPointerSize));
122}
123
124
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400125void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
126 MacroAssembler* masm, Label* miss_label, Register receiver,
127 Handle<Name> name, Register scratch0, Register scratch1) {
128 DCHECK(name->IsUniqueName());
129 DCHECK(!receiver.is(scratch0));
130 Counters* counters = masm->isolate()->counters();
131 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
132 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
133
134 Label done;
135
136 const int kInterceptorOrAccessCheckNeededMask =
137 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
138
139 // Bail out if the receiver has a named interceptor or requires access checks.
140 Register map = scratch1;
141 __ LoadP(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
142 __ lbz(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
143 __ andi(r0, scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
144 __ bne(miss_label, cr0);
145
146 // Check that receiver is a JSObject.
147 __ lbz(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000148 __ cmpi(scratch0, Operand(FIRST_JS_RECEIVER_TYPE));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400149 __ blt(miss_label);
150
151 // Load properties array.
152 Register properties = scratch0;
153 __ LoadP(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
154 // Check that the properties array is a dictionary.
155 __ LoadP(map, FieldMemOperand(properties, HeapObject::kMapOffset));
156 Register tmp = properties;
157 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
158 __ cmp(map, tmp);
159 __ bne(miss_label);
160
161 // Restore the temporarily used register.
162 __ LoadP(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
163
164
165 NameDictionaryLookupStub::GenerateNegativeLookup(
166 masm, miss_label, &done, receiver, properties, name, scratch1);
167 __ bind(&done);
168 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
169}
170
171
172void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000173 MacroAssembler* masm, int index, Register result, Label* miss) {
174 __ LoadNativeContextSlot(index, result);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400175 // Load its initial map. The global functions all have initial maps.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000176 __ LoadP(result,
177 FieldMemOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400178 // Load the prototype from the initial map.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000179 __ LoadP(result, FieldMemOperand(result, Map::kPrototypeOffset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400180}
181
182
183void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
184 MacroAssembler* masm, Register receiver, Register scratch1,
185 Register scratch2, Label* miss_label) {
186 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
187 __ mr(r3, scratch1);
188 __ Ret();
189}
190
191
192// Generate code to check that a global property cell is empty. Create
193// the property cell at compilation time if no cell exists for the
194// property.
195void PropertyHandlerCompiler::GenerateCheckPropertyCell(
196 MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
197 Register scratch, Label* miss) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000198 Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400199 DCHECK(cell->value()->IsTheHole());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000200 Handle<WeakCell> weak_cell = masm->isolate()->factory()->NewWeakCell(cell);
201 __ LoadWeakValue(scratch, weak_cell, miss);
202 __ LoadP(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400203 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
204 __ cmp(scratch, ip);
205 __ bne(miss);
206}
207
208
209static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
210 Register holder, Register name,
211 Handle<JSObject> holder_obj) {
212 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000213 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
214 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
215 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400216 __ push(name);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400217 __ push(receiver);
218 __ push(holder);
219}
220
221
222static void CompileCallLoadPropertyWithInterceptor(
223 MacroAssembler* masm, Register receiver, Register holder, Register name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000224 Handle<JSObject> holder_obj, Runtime::FunctionId id) {
225 DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
226 Runtime::FunctionForId(id)->nargs);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400227 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000228 __ CallRuntime(id);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400229}
230
231
232// Generate call to api function.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000233void PropertyHandlerCompiler::GenerateApiAccessorCall(
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400234 MacroAssembler* masm, const CallOptimization& optimization,
235 Handle<Map> receiver_map, Register receiver, Register scratch_in,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000236 bool is_store, Register store_parameter, Register accessor_holder,
237 int accessor_index) {
238 DCHECK(!accessor_holder.is(scratch_in));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400239 DCHECK(!receiver.is(scratch_in));
240 __ push(receiver);
241 // Write the arguments to stack frame.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000242 if (is_store) {
243 DCHECK(!receiver.is(store_parameter));
244 DCHECK(!scratch_in.is(store_parameter));
245 __ push(store_parameter);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400246 }
247 DCHECK(optimization.is_simple_api_call());
248
249 // Abi for CallApiFunctionStub.
250 Register callee = r3;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000251 Register data = r7;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400252 Register holder = r5;
253 Register api_function_address = r4;
254
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000255 // Put callee in place.
256 __ LoadAccessor(callee, accessor_holder, accessor_index,
257 is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
258
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400259 // Put holder in place.
260 CallOptimization::HolderLookup holder_lookup;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000261 int holder_depth = 0;
262 optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup,
263 &holder_depth);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400264 switch (holder_lookup) {
265 case CallOptimization::kHolderIsReceiver:
266 __ Move(holder, receiver);
267 break;
268 case CallOptimization::kHolderFound:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000269 __ LoadP(holder, FieldMemOperand(receiver, HeapObject::kMapOffset));
270 __ LoadP(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
271 for (int i = 1; i < holder_depth; i++) {
272 __ LoadP(holder, FieldMemOperand(holder, HeapObject::kMapOffset));
273 __ LoadP(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
274 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400275 break;
276 case CallOptimization::kHolderNotFound:
277 UNREACHABLE();
278 break;
279 }
280
281 Isolate* isolate = masm->isolate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400282 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400283 bool call_data_undefined = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000284 // Put call data in place.
285 if (api_call_info->data()->IsUndefined()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400286 call_data_undefined = true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000287 __ LoadRoot(data, Heap::kUndefinedValueRootIndex);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400288 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100289 if (optimization.is_constant_call()) {
290 __ LoadP(data,
291 FieldMemOperand(callee, JSFunction::kSharedFunctionInfoOffset));
292 __ LoadP(data,
293 FieldMemOperand(data, SharedFunctionInfo::kFunctionDataOffset));
294 __ LoadP(data,
295 FieldMemOperand(data, FunctionTemplateInfo::kCallCodeOffset));
296 } else {
297 __ LoadP(data,
298 FieldMemOperand(callee, FunctionTemplateInfo::kCallCodeOffset));
299 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000300 __ LoadP(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset));
301 }
302
303 if (api_call_info->fast_handler()->IsCode()) {
304 // Just tail call into the fast handler if present.
305 __ Jump(handle(Code::cast(api_call_info->fast_handler())),
306 RelocInfo::CODE_TARGET);
307 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400308 }
309
310 // Put api_function_address in place.
311 Address function_address = v8::ToCData<Address>(api_call_info->callback());
312 ApiFunction fun(function_address);
313 ExternalReference::Type type = ExternalReference::DIRECT_API_CALL;
314 ExternalReference ref = ExternalReference(&fun, type, masm->isolate());
315 __ mov(api_function_address, Operand(ref));
316
317 // Jump to stub.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100318 CallApiAccessorStub stub(isolate, is_store, call_data_undefined,
319 !optimization.is_constant_call());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400320 __ TailCallStub(&stub);
321}
322
323
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000324static void StoreIC_PushArgs(MacroAssembler* masm) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400325 __ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000326 StoreDescriptor::ValueRegister(),
327 VectorStoreICDescriptor::SlotRegister(),
328 VectorStoreICDescriptor::VectorRegister());
329}
330
331
332void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
333 StoreIC_PushArgs(masm);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400334
335 // The slow case calls into the runtime to complete the store without causing
336 // an IC miss that would otherwise cause a transition to the generic stub.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000337 __ TailCallRuntime(Runtime::kStoreIC_Slow);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400338}
339
340
341void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000342 StoreIC_PushArgs(masm);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400343
344 // The slow case calls into the runtime to complete the store without causing
345 // an IC miss that would otherwise cause a transition to the generic stub.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000346 __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400347}
348
349
350#undef __
351#define __ ACCESS_MASM(masm())
352
353
354void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
355 Handle<Name> name) {
356 if (!label->is_unused()) {
357 __ bind(label);
358 __ mov(this->name(), Operand(name));
359 }
360}
361
362
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000363void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400364 __ mov(this->name(), Operand(name));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400365}
366
367
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000368void NamedStoreHandlerCompiler::RearrangeVectorAndSlot(
369 Register current_map, Register destination_map) {
370 DCHECK(false); // Not implemented.
371}
372
373
374void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
375 Register map_reg,
376 Register scratch,
377 Label* miss) {
378 Handle<WeakCell> cell = Map::WeakCellForMap(transition);
379 DCHECK(!map_reg.is(scratch));
380 __ LoadWeakValue(map_reg, cell, miss);
381 if (transition->CanBeDeprecated()) {
382 __ lwz(scratch, FieldMemOperand(map_reg, Map::kBitField3Offset));
383 __ DecodeField<Map::Deprecated>(r0, scratch, SetRC);
384 __ bne(miss, cr0);
385 }
386}
387
388
389void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
390 int descriptor,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400391 Register value_reg,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000392 Register scratch,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400393 Label* miss_label) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000394 DCHECK(!map_reg.is(scratch));
395 DCHECK(!map_reg.is(value_reg));
396 DCHECK(!value_reg.is(scratch));
397 __ LoadInstanceDescriptors(map_reg, scratch);
398 __ LoadP(scratch, FieldMemOperand(
399 scratch, DescriptorArray::GetValueOffset(descriptor)));
400 __ cmp(value_reg, scratch);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400401 __ bne(miss_label);
402}
403
Ben Murdoch097c5b22016-05-18 11:27:45 +0100404void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400405 Register value_reg,
406 Label* miss_label) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000407 Register map_reg = scratch1();
408 Register scratch = scratch2();
409 DCHECK(!value_reg.is(map_reg));
410 DCHECK(!value_reg.is(scratch));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400411 __ JumpIfSmi(value_reg, miss_label);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100412 if (field_type->IsClass()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000413 __ LoadP(map_reg, FieldMemOperand(value_reg, HeapObject::kMapOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100414 __ CmpWeakValue(map_reg, Map::WeakCellForMap(field_type->AsClass()),
415 scratch);
416 __ bne(miss_label);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400417 }
418}
419
420
421Register PropertyHandlerCompiler::CheckPrototypes(
422 Register object_reg, Register holder_reg, Register scratch1,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000423 Register scratch2, Handle<Name> name, Label* miss, PrototypeCheckType check,
424 ReturnHolder return_what) {
425 Handle<Map> receiver_map = map();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400426
427 // Make sure there's no overlap between holder and object registers.
428 DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
429 DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) &&
430 !scratch2.is(scratch1));
431
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000432 if (FLAG_eliminate_prototype_chain_checks) {
433 Handle<Cell> validity_cell =
434 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
435 if (!validity_cell.is_null()) {
436 DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid),
437 validity_cell->value());
438 __ mov(scratch1, Operand(validity_cell));
439 __ LoadP(scratch1, FieldMemOperand(scratch1, Cell::kValueOffset));
440 __ CmpSmiLiteral(scratch1, Smi::FromInt(Map::kPrototypeChainValid), r0);
441 __ bne(miss);
442 }
443
444 // The prototype chain of primitives (and their JSValue wrappers) depends
445 // on the native context, which can't be guarded by validity cells.
446 // |object_reg| holds the native context specific prototype in this case;
447 // we need to check its map.
448 if (check == CHECK_ALL_MAPS) {
449 __ LoadP(scratch1, FieldMemOperand(object_reg, HeapObject::kMapOffset));
450 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
451 __ CmpWeakValue(scratch1, cell, scratch2);
452 __ b(ne, miss);
453 }
454 }
455
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400456 // Keep track of the current object in register reg.
457 Register reg = object_reg;
458 int depth = 0;
459
460 Handle<JSObject> current = Handle<JSObject>::null();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000461 if (receiver_map->IsJSGlobalObjectMap()) {
462 current = isolate()->global_object();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400463 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000464 // Check access rights to the global object. This has to happen after
465 // the map check so that we know that the object is actually a global
466 // object.
467 // This allows us to install generated handlers for accesses to the
468 // global proxy (as opposed to using slow ICs). See corresponding code
469 // in LookupForRead().
470 if (receiver_map->IsJSGlobalProxyMap()) {
471 __ CheckAccessGlobalProxy(reg, scratch2, miss);
472 }
473
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400474 Handle<JSObject> prototype = Handle<JSObject>::null();
475 Handle<Map> current_map = receiver_map;
476 Handle<Map> holder_map(holder()->map());
477 // Traverse the prototype chain and check the maps in the prototype chain for
478 // fast and global objects or do negative lookup for normal objects.
479 while (!current_map.is_identical_to(holder_map)) {
480 ++depth;
481
482 // Only global objects and objects that do not require access
483 // checks are allowed in stubs.
484 DCHECK(current_map->IsJSGlobalProxyMap() ||
485 !current_map->is_access_check_needed());
486
487 prototype = handle(JSObject::cast(current_map->prototype()));
488 if (current_map->is_dictionary_map() &&
489 !current_map->IsJSGlobalObjectMap()) {
490 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
491 if (!name->IsUniqueName()) {
492 DCHECK(name->IsString());
493 name = factory()->InternalizeString(Handle<String>::cast(name));
494 }
495 DCHECK(current.is_null() ||
496 current->property_dictionary()->FindEntry(name) ==
497 NameDictionary::kNotFound);
498
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000499 if (FLAG_eliminate_prototype_chain_checks && depth > 1) {
500 // TODO(jkummerow): Cache and re-use weak cell.
501 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
502 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400503 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
504 scratch2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000505 if (!FLAG_eliminate_prototype_chain_checks) {
506 __ LoadP(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
507 __ LoadP(holder_reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
508 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400509 } else {
510 Register map_reg = scratch1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000511 if (!FLAG_eliminate_prototype_chain_checks) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400512 __ LoadP(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
513 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000514 if (current_map->IsJSGlobalObjectMap()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400515 GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
516 name, scratch2, miss);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000517 } else if (!FLAG_eliminate_prototype_chain_checks &&
518 (depth != 1 || check == CHECK_ALL_MAPS)) {
519 Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
520 __ CmpWeakValue(map_reg, cell, scratch2);
521 __ bne(miss);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400522 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000523 if (!FLAG_eliminate_prototype_chain_checks) {
524 __ LoadP(holder_reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400525 }
526 }
527
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000528 reg = holder_reg; // From now on the object will be in holder_reg.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400529 // Go to the next object in the prototype chain.
530 current = prototype;
531 current_map = handle(current->map());
532 }
533
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000534 DCHECK(!current_map->IsJSGlobalProxyMap());
535
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400536 // Log the check depth.
537 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
538
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000539 if (!FLAG_eliminate_prototype_chain_checks &&
540 (depth != 0 || check == CHECK_ALL_MAPS)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400541 // Check the holder map.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000542 __ LoadP(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
543 Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
544 __ CmpWeakValue(scratch1, cell, scratch2);
545 __ bne(miss);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400546 }
547
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000548 bool return_holder = return_what == RETURN_HOLDER;
549 if (FLAG_eliminate_prototype_chain_checks && return_holder && depth != 0) {
550 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400551 }
552
553 // Return the register containing the holder.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000554 return return_holder ? reg : no_reg;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400555}
556
557
558void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
559 if (!miss->is_unused()) {
560 Label success;
561 __ b(&success);
562 __ bind(miss);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000563 if (IC::ICUseVector(kind())) {
564 DCHECK(kind() == Code::LOAD_IC);
565 PopVectorAndSlot();
566 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400567 TailCallBuiltin(masm(), MissBuiltin(kind()));
568 __ bind(&success);
569 }
570}
571
572
573void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
574 if (!miss->is_unused()) {
575 Label success;
576 __ b(&success);
577 GenerateRestoreName(miss, name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000578 if (IC::ICUseVector(kind())) PopVectorAndSlot();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400579 TailCallBuiltin(masm(), MissBuiltin(kind()));
580 __ bind(&success);
581 }
582}
583
584
585void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
586 // Return the constant value.
587 __ Move(r3, value);
588 __ Ret();
589}
590
591
592void NamedLoadHandlerCompiler::GenerateLoadCallback(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100593 Register reg, Handle<AccessorInfo> callback) {
594 DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), receiver()));
595 DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), reg));
596
597 // Build v8::PropertyCallbackInfo::args_ array on the stack and push property
598 // name below the exit frame to make GC aware of them.
599 STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0);
600 STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1);
601 STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2);
602 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3);
603 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4);
604 STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5);
605 STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6);
606 STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7);
607
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400608 __ push(receiver());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100609 // Push data from AccessorInfo.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000610 Handle<Object> data(callback->data(), isolate());
611 if (data->IsUndefined() || data->IsSmi()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100612 __ Move(scratch2(), data);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400613 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000614 Handle<WeakCell> cell =
615 isolate()->factory()->NewWeakCell(Handle<HeapObject>::cast(data));
616 // The callback is alive if this instruction is executed,
617 // so the weak cell is not cleared and points to data.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100618 __ GetWeakValue(scratch2(), cell);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400619 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100620 __ push(scratch2());
621 __ LoadRoot(scratch2(), Heap::kUndefinedValueRootIndex);
622 __ Push(scratch2(), scratch2());
623 __ mov(scratch2(), Operand(ExternalReference::isolate_address(isolate())));
624 // should_throw_on_error -> false
625 __ mov(scratch3(), Operand(Smi::FromInt(0)));
626 __ Push(scratch2(), reg, scratch3(), name());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400627
628 // Abi for CallApiGetter
629 Register getter_address_reg = ApiGetterDescriptor::function_address();
630
631 Address getter_address = v8::ToCData<Address>(callback->getter());
632 ApiFunction fun(getter_address);
633 ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
634 ExternalReference ref = ExternalReference(&fun, type, isolate());
635 __ mov(getter_address_reg, Operand(ref));
636
637 CallApiGetterStub stub(isolate());
638 __ TailCallStub(&stub);
639}
640
641
642void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
643 LookupIterator* it, Register holder_reg) {
644 DCHECK(holder()->HasNamedInterceptor());
645 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
646
647 // Compile the interceptor call, followed by inline code to load the
648 // property from further up the prototype chain if the call fails.
649 // Check that the maps haven't changed.
650 DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
651
652 // Preserve the receiver register explicitly whenever it is different from the
653 // holder and it is needed should the interceptor return without any result.
654 // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
655 // case might cause a miss during the prototype check.
656 bool must_perform_prototype_check =
657 !holder().is_identical_to(it->GetHolder<JSObject>());
658 bool must_preserve_receiver_reg =
659 !receiver().is(holder_reg) &&
660 (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
661
662 // Save necessary data before invoking an interceptor.
663 // Requires a frame to make GC aware of pushed pointers.
664 {
665 FrameAndConstantPoolScope frame_scope(masm(), StackFrame::INTERNAL);
666 if (must_preserve_receiver_reg) {
667 __ Push(receiver(), holder_reg, this->name());
668 } else {
669 __ Push(holder_reg, this->name());
670 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000671 InterceptorVectorSlotPush(holder_reg);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400672 // Invoke an interceptor. Note: map checks from receiver to
673 // interceptor's holder has been compiled before (see a caller
674 // of this method.)
675 CompileCallLoadPropertyWithInterceptor(
676 masm(), receiver(), holder_reg, this->name(), holder(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000677 Runtime::kLoadPropertyWithInterceptorOnly);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400678
679 // Check if interceptor provided a value for property. If it's
680 // the case, return immediately.
681 Label interceptor_failed;
682 __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
683 __ cmp(r3, scratch1());
684 __ beq(&interceptor_failed);
685 frame_scope.GenerateLeaveFrame();
686 __ Ret();
687
688 __ bind(&interceptor_failed);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000689 InterceptorVectorSlotPop(holder_reg);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400690 __ pop(this->name());
691 __ pop(holder_reg);
692 if (must_preserve_receiver_reg) {
693 __ pop(receiver());
694 }
695 // Leave the internal frame.
696 }
697
698 GenerateLoadPostInterceptor(it, holder_reg);
699}
700
701
702void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
703 // Call the runtime system to load the interceptor.
704 DCHECK(holder()->HasNamedInterceptor());
705 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
706 PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
707 holder());
708
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000709 __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400710}
711
712
713Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100714 Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
715 LanguageMode language_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000716 Register holder_reg = Frontend(name);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400717
718 __ Push(receiver(), holder_reg); // receiver
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000719
720 // If the callback cannot leak, then push the callback directly,
721 // otherwise wrap it in a weak cell.
722 if (callback->data()->IsUndefined() || callback->data()->IsSmi()) {
723 __ mov(ip, Operand(callback));
724 } else {
725 Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
726 __ mov(ip, Operand(cell));
727 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400728 __ push(ip);
729 __ mov(ip, Operand(name));
730 __ Push(ip, value());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100731 __ Push(Smi::FromInt(language_mode));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400732
733 // Do tail-call to the runtime system.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000734 __ TailCallRuntime(Runtime::kStoreCallbackProperty);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400735
736 // Return the generated code.
737 return GetCode(kind(), Code::FAST, name);
738}
739
740
741Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor(
742 Handle<Name> name) {
743 __ Push(receiver(), this->name(), value());
744
745 // Do tail-call to the runtime system.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000746 __ TailCallRuntime(Runtime::kStorePropertyWithInterceptor);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400747
748 // Return the generated code.
749 return GetCode(kind(), Code::FAST, name);
750}
751
752
753Register NamedStoreHandlerCompiler::value() {
754 return StoreDescriptor::ValueRegister();
755}
756
757
758Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
759 Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
760 Label miss;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000761 if (IC::ICUseVector(kind())) {
762 PushVectorAndSlot();
763 }
764 FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400765
766 // Get the value from the cell.
767 Register result = StoreDescriptor::ValueRegister();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000768 Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
769 __ LoadWeakValue(result, weak_cell, &miss);
770 __ LoadP(result, FieldMemOperand(result, PropertyCell::kValueOffset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400771
772 // Check for deleted property if property can actually be deleted.
773 if (is_configurable) {
774 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
775 __ cmp(result, ip);
776 __ beq(&miss);
777 }
778
779 Counters* counters = isolate()->counters();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100780 __ IncrementCounter(counters->ic_named_load_global_stub(), 1, r4, r6);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000781 if (IC::ICUseVector(kind())) {
782 DiscardVectorAndSlot();
783 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400784 __ Ret();
785
786 FrontendFooter(name, &miss);
787
788 // Return the generated code.
789 return GetCode(kind(), Code::NORMAL, name);
790}
791
792
793#undef __
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000794} // namespace internal
795} // namespace v8
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400796
797#endif // V8_TARGET_ARCH_ARM