blob: 3293d824e8db03862974718a8bed7ed85e7f43ef [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
Ben Murdochda12d292016-06-02 14:46:10 +01009#include "src/api-arguments.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010010#include "src/field-type.h"
11#include "src/ic/call-optimization.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012#include "src/ic/ic.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013#include "src/isolate-inl.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014
15namespace v8 {
16namespace internal {
17
18#define __ ACCESS_MASM(masm)
19
20
21void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000022 MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
23 int accessor_index, int expected_arguments, Register scratch) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040024 // ----------- S t a t e -------------
25 // -- r3 : receiver
26 // -- r5 : name
27 // -- lr : return address
28 // -----------------------------------
29 {
30 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
31
Ben Murdochda12d292016-06-02 14:46:10 +010032 // Save context register
33 __ push(cp);
34
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000035 if (accessor_index >= 0) {
36 DCHECK(!holder.is(scratch));
37 DCHECK(!receiver.is(scratch));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040038 // Call the JavaScript getter with the receiver on the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000039 if (map->IsJSGlobalObjectMap()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040040 // Swap in the global receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000041 __ LoadP(scratch,
Emily Bernierd0a1eb72015-03-24 16:35:39 -040042 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000043 receiver = scratch;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040044 }
45 __ push(receiver);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000046 __ LoadAccessor(r4, holder, accessor_index, ACCESSOR_GETTER);
Ben Murdochda12d292016-06-02 14:46:10 +010047 __ li(r3, Operand::Zero());
48 __ Call(masm->isolate()->builtins()->CallFunction(
49 ConvertReceiverMode::kNotNullOrUndefined),
50 RelocInfo::CODE_TARGET);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040051 } else {
52 // If we generate a global code snippet for deoptimization only, remember
53 // the place to continue after deoptimization.
54 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
55 }
56
57 // Restore context register.
Ben Murdochda12d292016-06-02 14:46:10 +010058 __ pop(cp);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040059 }
60 __ Ret();
61}
62
63
64void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000065 MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
66 int accessor_index, int expected_arguments, Register scratch) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040067 // ----------- S t a t e -------------
68 // -- lr : return address
69 // -----------------------------------
70 {
71 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
72
Ben Murdochda12d292016-06-02 14:46:10 +010073 // Save context register
Emily Bernierd0a1eb72015-03-24 16:35:39 -040074 // Save value register, so we can restore it later.
Ben Murdochda12d292016-06-02 14:46:10 +010075 __ Push(cp, value());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040076
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000077 if (accessor_index >= 0) {
78 DCHECK(!holder.is(scratch));
79 DCHECK(!receiver.is(scratch));
80 DCHECK(!value().is(scratch));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040081 // Call the JavaScript setter with receiver and value on the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000082 if (map->IsJSGlobalObjectMap()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040083 // Swap in the global receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000084 __ LoadP(scratch,
Emily Bernierd0a1eb72015-03-24 16:35:39 -040085 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000086 receiver = scratch;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040087 }
88 __ Push(receiver, value());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000089 __ LoadAccessor(r4, holder, accessor_index, ACCESSOR_SETTER);
Ben Murdochda12d292016-06-02 14:46:10 +010090 __ li(r3, Operand(1));
91 __ Call(masm->isolate()->builtins()->CallFunction(
92 ConvertReceiverMode::kNotNullOrUndefined),
93 RelocInfo::CODE_TARGET);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040094 } else {
95 // If we generate a global code snippet for deoptimization only, remember
96 // the place to continue after deoptimization.
97 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
98 }
99
100 // We have to return the passed value, not the return value of the setter.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400101 // Restore context register.
Ben Murdochda12d292016-06-02 14:46:10 +0100102 __ Pop(cp, r3);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400103 }
104 __ Ret();
105}
106
107
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000108void PropertyHandlerCompiler::PushVectorAndSlot(Register vector,
109 Register slot) {
110 MacroAssembler* masm = this->masm();
111 __ Push(vector, slot);
112}
113
114
115void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) {
116 MacroAssembler* masm = this->masm();
117 __ Pop(vector, slot);
118}
119
120
121void PropertyHandlerCompiler::DiscardVectorAndSlot() {
122 MacroAssembler* masm = this->masm();
123 // Remove vector and slot.
124 __ addi(sp, sp, Operand(2 * kPointerSize));
125}
126
127
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400128void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
129 MacroAssembler* masm, Label* miss_label, Register receiver,
130 Handle<Name> name, Register scratch0, Register scratch1) {
131 DCHECK(name->IsUniqueName());
132 DCHECK(!receiver.is(scratch0));
133 Counters* counters = masm->isolate()->counters();
134 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
135 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
136
137 Label done;
138
139 const int kInterceptorOrAccessCheckNeededMask =
140 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
141
142 // Bail out if the receiver has a named interceptor or requires access checks.
143 Register map = scratch1;
144 __ LoadP(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
145 __ lbz(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
146 __ andi(r0, scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
147 __ bne(miss_label, cr0);
148
149 // Check that receiver is a JSObject.
150 __ lbz(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000151 __ cmpi(scratch0, Operand(FIRST_JS_RECEIVER_TYPE));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400152 __ blt(miss_label);
153
154 // Load properties array.
155 Register properties = scratch0;
156 __ LoadP(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
157 // Check that the properties array is a dictionary.
158 __ LoadP(map, FieldMemOperand(properties, HeapObject::kMapOffset));
159 Register tmp = properties;
160 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
161 __ cmp(map, tmp);
162 __ bne(miss_label);
163
164 // Restore the temporarily used register.
165 __ LoadP(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
166
167
168 NameDictionaryLookupStub::GenerateNegativeLookup(
169 masm, miss_label, &done, receiver, properties, name, scratch1);
170 __ bind(&done);
171 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
172}
173
174
175void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000176 MacroAssembler* masm, int index, Register result, Label* miss) {
177 __ LoadNativeContextSlot(index, result);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400178 // Load its initial map. The global functions all have initial maps.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000179 __ LoadP(result,
180 FieldMemOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400181 // Load the prototype from the initial map.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000182 __ LoadP(result, FieldMemOperand(result, Map::kPrototypeOffset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400183}
184
185
186void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
187 MacroAssembler* masm, Register receiver, Register scratch1,
188 Register scratch2, Label* miss_label) {
189 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
190 __ mr(r3, scratch1);
191 __ Ret();
192}
193
194
195// Generate code to check that a global property cell is empty. Create
196// the property cell at compilation time if no cell exists for the
197// property.
198void PropertyHandlerCompiler::GenerateCheckPropertyCell(
199 MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
200 Register scratch, Label* miss) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000201 Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100202 Isolate* isolate = masm->isolate();
203 DCHECK(cell->value()->IsTheHole(isolate));
204 Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000205 __ LoadWeakValue(scratch, weak_cell, miss);
206 __ LoadP(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400207 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
208 __ cmp(scratch, ip);
209 __ bne(miss);
210}
211
212
213static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
214 Register holder, Register name,
215 Handle<JSObject> holder_obj) {
216 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000217 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
218 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
219 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400220 __ push(name);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400221 __ push(receiver);
222 __ push(holder);
223}
224
225
226static void CompileCallLoadPropertyWithInterceptor(
227 MacroAssembler* masm, Register receiver, Register holder, Register name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000228 Handle<JSObject> holder_obj, Runtime::FunctionId id) {
229 DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
230 Runtime::FunctionForId(id)->nargs);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400231 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000232 __ CallRuntime(id);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400233}
234
235
236// Generate call to api function.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000237void PropertyHandlerCompiler::GenerateApiAccessorCall(
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400238 MacroAssembler* masm, const CallOptimization& optimization,
239 Handle<Map> receiver_map, Register receiver, Register scratch_in,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000240 bool is_store, Register store_parameter, Register accessor_holder,
241 int accessor_index) {
242 DCHECK(!accessor_holder.is(scratch_in));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400243 DCHECK(!receiver.is(scratch_in));
244 __ push(receiver);
245 // Write the arguments to stack frame.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000246 if (is_store) {
247 DCHECK(!receiver.is(store_parameter));
248 DCHECK(!scratch_in.is(store_parameter));
249 __ push(store_parameter);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400250 }
251 DCHECK(optimization.is_simple_api_call());
252
Ben Murdochda12d292016-06-02 14:46:10 +0100253 // Abi for CallApiCallbackStub.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400254 Register callee = r3;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000255 Register data = r7;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400256 Register holder = r5;
257 Register api_function_address = r4;
258
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000259 // Put callee in place.
260 __ LoadAccessor(callee, accessor_holder, accessor_index,
261 is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
262
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400263 // Put holder in place.
264 CallOptimization::HolderLookup holder_lookup;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000265 int holder_depth = 0;
266 optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup,
267 &holder_depth);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400268 switch (holder_lookup) {
269 case CallOptimization::kHolderIsReceiver:
270 __ Move(holder, receiver);
271 break;
272 case CallOptimization::kHolderFound:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000273 __ LoadP(holder, FieldMemOperand(receiver, HeapObject::kMapOffset));
274 __ LoadP(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
275 for (int i = 1; i < holder_depth; i++) {
276 __ LoadP(holder, FieldMemOperand(holder, HeapObject::kMapOffset));
277 __ LoadP(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
278 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400279 break;
280 case CallOptimization::kHolderNotFound:
281 UNREACHABLE();
282 break;
283 }
284
285 Isolate* isolate = masm->isolate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400286 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400287 bool call_data_undefined = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000288 // Put call data in place.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100289 if (api_call_info->data()->IsUndefined(isolate)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400290 call_data_undefined = true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000291 __ LoadRoot(data, Heap::kUndefinedValueRootIndex);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400292 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100293 if (optimization.is_constant_call()) {
294 __ LoadP(data,
295 FieldMemOperand(callee, JSFunction::kSharedFunctionInfoOffset));
296 __ LoadP(data,
297 FieldMemOperand(data, SharedFunctionInfo::kFunctionDataOffset));
298 __ LoadP(data,
299 FieldMemOperand(data, FunctionTemplateInfo::kCallCodeOffset));
300 } else {
301 __ LoadP(data,
302 FieldMemOperand(callee, FunctionTemplateInfo::kCallCodeOffset));
303 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000304 __ LoadP(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset));
305 }
306
307 if (api_call_info->fast_handler()->IsCode()) {
308 // Just tail call into the fast handler if present.
309 __ Jump(handle(Code::cast(api_call_info->fast_handler())),
310 RelocInfo::CODE_TARGET);
311 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400312 }
313
314 // Put api_function_address in place.
315 Address function_address = v8::ToCData<Address>(api_call_info->callback());
316 ApiFunction fun(function_address);
317 ExternalReference::Type type = ExternalReference::DIRECT_API_CALL;
318 ExternalReference ref = ExternalReference(&fun, type, masm->isolate());
319 __ mov(api_function_address, Operand(ref));
320
321 // Jump to stub.
Ben Murdochda12d292016-06-02 14:46:10 +0100322 CallApiCallbackStub stub(isolate, is_store, call_data_undefined,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100323 !optimization.is_constant_call());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400324 __ TailCallStub(&stub);
325}
326
327
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000328static void StoreIC_PushArgs(MacroAssembler* masm) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400329 __ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000330 StoreDescriptor::ValueRegister(),
331 VectorStoreICDescriptor::SlotRegister(),
332 VectorStoreICDescriptor::VectorRegister());
333}
334
335
336void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
337 StoreIC_PushArgs(masm);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400338
339 // The slow case calls into the runtime to complete the store without causing
340 // an IC miss that would otherwise cause a transition to the generic stub.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000341 __ TailCallRuntime(Runtime::kStoreIC_Slow);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400342}
343
344
345void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000346 StoreIC_PushArgs(masm);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400347
348 // The slow case calls into the runtime to complete the store without causing
349 // an IC miss that would otherwise cause a transition to the generic stub.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000350 __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400351}
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 __ mov(this->name(), Operand(name));
363 }
364}
365
366
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000367void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400368 __ mov(this->name(), Operand(name));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400369}
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
378void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
379 Register map_reg,
380 Register scratch,
381 Label* miss) {
382 Handle<WeakCell> cell = Map::WeakCellForMap(transition);
383 DCHECK(!map_reg.is(scratch));
384 __ LoadWeakValue(map_reg, cell, miss);
385 if (transition->CanBeDeprecated()) {
386 __ lwz(scratch, FieldMemOperand(map_reg, Map::kBitField3Offset));
387 __ DecodeField<Map::Deprecated>(r0, scratch, SetRC);
388 __ bne(miss, cr0);
389 }
390}
391
392
393void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
394 int descriptor,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400395 Register value_reg,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000396 Register scratch,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400397 Label* miss_label) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000398 DCHECK(!map_reg.is(scratch));
399 DCHECK(!map_reg.is(value_reg));
400 DCHECK(!value_reg.is(scratch));
401 __ LoadInstanceDescriptors(map_reg, scratch);
402 __ LoadP(scratch, FieldMemOperand(
403 scratch, DescriptorArray::GetValueOffset(descriptor)));
404 __ cmp(value_reg, scratch);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400405 __ bne(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()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000417 __ LoadP(map_reg, FieldMemOperand(value_reg, HeapObject::kMapOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100418 __ CmpWeakValue(map_reg, Map::WeakCellForMap(field_type->AsClass()),
419 scratch);
420 __ bne(miss_label);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400421 }
422}
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();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400430
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 Murdoch61f157c2016-09-16 13:49:30 +0100436 Handle<Cell> validity_cell =
437 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
438 if (!validity_cell.is_null()) {
439 DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), validity_cell->value());
440 __ mov(scratch1, Operand(validity_cell));
441 __ LoadP(scratch1, FieldMemOperand(scratch1, Cell::kValueOffset));
442 __ CmpSmiLiteral(scratch1, Smi::FromInt(Map::kPrototypeChainValid), r0);
443 __ bne(miss);
444 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000445
Ben Murdoch61f157c2016-09-16 13:49:30 +0100446 // The prototype chain of primitives (and their JSValue wrappers) depends
447 // on the native context, which can't be guarded by validity cells.
448 // |object_reg| holds the native context specific prototype in this case;
449 // we need to check its map.
450 if (check == CHECK_ALL_MAPS) {
451 __ LoadP(scratch1, FieldMemOperand(object_reg, HeapObject::kMapOffset));
452 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
453 __ CmpWeakValue(scratch1, cell, scratch2);
454 __ b(ne, miss);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000455 }
456
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400457 // Keep track of the current object in register reg.
458 Register reg = object_reg;
459 int depth = 0;
460
461 Handle<JSObject> current = Handle<JSObject>::null();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000462 if (receiver_map->IsJSGlobalObjectMap()) {
463 current = isolate()->global_object();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400464 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000465 // Check access rights to the global object. This has to happen after
466 // the map check so that we know that the object is actually a global
467 // object.
468 // This allows us to install generated handlers for accesses to the
469 // global proxy (as opposed to using slow ICs). See corresponding code
470 // in LookupForRead().
471 if (receiver_map->IsJSGlobalProxyMap()) {
472 __ CheckAccessGlobalProxy(reg, scratch2, miss);
473 }
474
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400475 Handle<JSObject> prototype = Handle<JSObject>::null();
476 Handle<Map> current_map = receiver_map;
477 Handle<Map> holder_map(holder()->map());
478 // Traverse the prototype chain and check the maps in the prototype chain for
479 // fast and global objects or do negative lookup for normal objects.
480 while (!current_map.is_identical_to(holder_map)) {
481 ++depth;
482
483 // Only global objects and objects that do not require access
484 // checks are allowed in stubs.
485 DCHECK(current_map->IsJSGlobalProxyMap() ||
486 !current_map->is_access_check_needed());
487
488 prototype = handle(JSObject::cast(current_map->prototype()));
Ben Murdoch61f157c2016-09-16 13:49:30 +0100489 if (current_map->IsJSGlobalObjectMap()) {
490 GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
491 name, scratch2, miss);
492 } else if (current_map->is_dictionary_map()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400493 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
494 if (!name->IsUniqueName()) {
495 DCHECK(name->IsString());
496 name = factory()->InternalizeString(Handle<String>::cast(name));
497 }
498 DCHECK(current.is_null() ||
499 current->property_dictionary()->FindEntry(name) ==
500 NameDictionary::kNotFound);
501
Ben Murdoch61f157c2016-09-16 13:49:30 +0100502 if (depth > 1) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000503 // TODO(jkummerow): Cache and re-use weak cell.
504 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
505 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400506 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
507 scratch2);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400508 }
509
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000510 reg = holder_reg; // From now on the object will be in holder_reg.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400511 // Go to the next object in the prototype chain.
512 current = prototype;
513 current_map = handle(current->map());
514 }
515
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000516 DCHECK(!current_map->IsJSGlobalProxyMap());
517
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400518 // Log the check depth.
519 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
520
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000521 bool return_holder = return_what == RETURN_HOLDER;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100522 if (return_holder && depth != 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000523 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400524 }
525
526 // Return the register containing the holder.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000527 return return_holder ? reg : no_reg;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400528}
529
530
531void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
532 if (!miss->is_unused()) {
533 Label success;
534 __ b(&success);
535 __ bind(miss);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000536 if (IC::ICUseVector(kind())) {
537 DCHECK(kind() == Code::LOAD_IC);
538 PopVectorAndSlot();
539 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400540 TailCallBuiltin(masm(), MissBuiltin(kind()));
541 __ bind(&success);
542 }
543}
544
545
546void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
547 if (!miss->is_unused()) {
548 Label success;
549 __ b(&success);
550 GenerateRestoreName(miss, name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000551 if (IC::ICUseVector(kind())) PopVectorAndSlot();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400552 TailCallBuiltin(masm(), MissBuiltin(kind()));
553 __ bind(&success);
554 }
555}
556
557
558void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
559 // Return the constant value.
560 __ Move(r3, value);
561 __ Ret();
562}
563
564
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400565void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
566 LookupIterator* it, Register holder_reg) {
567 DCHECK(holder()->HasNamedInterceptor());
Ben Murdoch61f157c2016-09-16 13:49:30 +0100568 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400569
570 // Compile the interceptor call, followed by inline code to load the
571 // property from further up the prototype chain if the call fails.
572 // Check that the maps haven't changed.
573 DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
574
575 // Preserve the receiver register explicitly whenever it is different from the
576 // holder and it is needed should the interceptor return without any result.
577 // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
578 // case might cause a miss during the prototype check.
579 bool must_perform_prototype_check =
580 !holder().is_identical_to(it->GetHolder<JSObject>());
581 bool must_preserve_receiver_reg =
582 !receiver().is(holder_reg) &&
583 (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
584
585 // Save necessary data before invoking an interceptor.
586 // Requires a frame to make GC aware of pushed pointers.
587 {
588 FrameAndConstantPoolScope frame_scope(masm(), StackFrame::INTERNAL);
589 if (must_preserve_receiver_reg) {
590 __ Push(receiver(), holder_reg, this->name());
591 } else {
592 __ Push(holder_reg, this->name());
593 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000594 InterceptorVectorSlotPush(holder_reg);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400595 // Invoke an interceptor. Note: map checks from receiver to
596 // interceptor's holder has been compiled before (see a caller
597 // of this method.)
598 CompileCallLoadPropertyWithInterceptor(
599 masm(), receiver(), holder_reg, this->name(), holder(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000600 Runtime::kLoadPropertyWithInterceptorOnly);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400601
602 // Check if interceptor provided a value for property. If it's
603 // the case, return immediately.
604 Label interceptor_failed;
605 __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
606 __ cmp(r3, scratch1());
607 __ beq(&interceptor_failed);
608 frame_scope.GenerateLeaveFrame();
609 __ Ret();
610
611 __ bind(&interceptor_failed);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000612 InterceptorVectorSlotPop(holder_reg);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400613 __ pop(this->name());
614 __ pop(holder_reg);
615 if (must_preserve_receiver_reg) {
616 __ pop(receiver());
617 }
618 // Leave the internal frame.
619 }
620
621 GenerateLoadPostInterceptor(it, holder_reg);
622}
623
624
625void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
626 // Call the runtime system to load the interceptor.
627 DCHECK(holder()->HasNamedInterceptor());
Ben Murdoch61f157c2016-09-16 13:49:30 +0100628 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400629 PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
630 holder());
631
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000632 __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400633}
634
635
636Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100637 Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
638 LanguageMode language_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000639 Register holder_reg = Frontend(name);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400640
641 __ Push(receiver(), holder_reg); // receiver
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000642
643 // If the callback cannot leak, then push the callback directly,
644 // otherwise wrap it in a weak cell.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100645 if (callback->data()->IsUndefined(isolate()) || callback->data()->IsSmi()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000646 __ mov(ip, Operand(callback));
647 } else {
648 Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
649 __ mov(ip, Operand(cell));
650 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400651 __ push(ip);
652 __ mov(ip, Operand(name));
653 __ Push(ip, value());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100654 __ Push(Smi::FromInt(language_mode));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400655
656 // Do tail-call to the runtime system.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000657 __ TailCallRuntime(Runtime::kStoreCallbackProperty);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400658
659 // Return the generated code.
Ben Murdochc5610432016-08-08 18:44:38 +0100660 return GetCode(kind(), name);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400661}
662
663
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400664Register NamedStoreHandlerCompiler::value() {
665 return StoreDescriptor::ValueRegister();
666}
667
668
669Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
670 Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
671 Label miss;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000672 if (IC::ICUseVector(kind())) {
673 PushVectorAndSlot();
674 }
675 FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400676
677 // Get the value from the cell.
678 Register result = StoreDescriptor::ValueRegister();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000679 Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
680 __ LoadWeakValue(result, weak_cell, &miss);
681 __ LoadP(result, FieldMemOperand(result, PropertyCell::kValueOffset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400682
683 // Check for deleted property if property can actually be deleted.
684 if (is_configurable) {
685 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
686 __ cmp(result, ip);
687 __ beq(&miss);
688 }
689
690 Counters* counters = isolate()->counters();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100691 __ IncrementCounter(counters->ic_named_load_global_stub(), 1, r4, r6);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000692 if (IC::ICUseVector(kind())) {
693 DiscardVectorAndSlot();
694 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400695 __ Ret();
696
697 FrontendFooter(name, &miss);
698
699 // Return the generated code.
Ben Murdochc5610432016-08-08 18:44:38 +0100700 return GetCode(kind(), name);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400701}
702
703
704#undef __
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000705} // namespace internal
706} // namespace v8
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400707
708#endif // V8_TARGET_ARCH_ARM