blob: 3bdddf9b6d1e54631d40b721701f465b562b53b3 [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_IA32
6
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007#include "src/ic/handler-compiler.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +01008
9#include "src/field-type.h"
10#include "src/ic/call-optimization.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011#include "src/ic/ic.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012#include "src/isolate-inl.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013
14namespace v8 {
15namespace internal {
16
17#define __ ACCESS_MASM(masm)
18
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) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000023 {
24 FrameScope scope(masm, StackFrame::INTERNAL);
25
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000026 if (accessor_index >= 0) {
27 DCHECK(!holder.is(scratch));
28 DCHECK(!receiver.is(scratch));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000029 // Call the JavaScript getter with the receiver on the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000030 if (map->IsJSGlobalObjectMap()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000031 // Swap in the global receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000032 __ mov(scratch,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000033 FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000034 receiver = scratch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000035 }
36 __ push(receiver);
37 ParameterCount actual(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000038 ParameterCount expected(expected_arguments);
39 __ LoadAccessor(edi, holder, accessor_index, ACCESSOR_GETTER);
40 __ InvokeFunction(edi, expected, actual, CALL_FUNCTION,
41 CheckDebugStepCallWrapper());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000042 } else {
43 // If we generate a global code snippet for deoptimization only, remember
44 // the place to continue after deoptimization.
45 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
46 }
47
48 // Restore context register.
49 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
50 }
51 __ ret(0);
52}
53
54
Emily Bernierd0a1eb72015-03-24 16:35:39 -040055void PropertyHandlerCompiler::PushVectorAndSlot(Register vector,
56 Register slot) {
57 MacroAssembler* masm = this->masm();
58 __ push(vector);
59 __ push(slot);
60}
61
62
63void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) {
64 MacroAssembler* masm = this->masm();
65 __ pop(slot);
66 __ pop(vector);
67}
68
69
70void PropertyHandlerCompiler::DiscardVectorAndSlot() {
71 MacroAssembler* masm = this->masm();
72 // Remove vector and slot.
73 __ add(esp, Immediate(2 * kPointerSize));
74}
75
76
Ben Murdochb8a8cc12014-11-26 15:28:44 +000077void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
78 MacroAssembler* masm, Label* miss_label, Register receiver,
79 Handle<Name> name, Register scratch0, Register scratch1) {
80 DCHECK(name->IsUniqueName());
81 DCHECK(!receiver.is(scratch0));
82 Counters* counters = masm->isolate()->counters();
83 __ IncrementCounter(counters->negative_lookups(), 1);
84 __ IncrementCounter(counters->negative_lookups_miss(), 1);
85
86 __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
87
88 const int kInterceptorOrAccessCheckNeededMask =
89 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
90
91 // Bail out if the receiver has a named interceptor or requires access checks.
92 __ test_b(FieldOperand(scratch0, Map::kBitFieldOffset),
93 kInterceptorOrAccessCheckNeededMask);
94 __ j(not_zero, miss_label);
95
96 // Check that receiver is a JSObject.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000097 __ CmpInstanceType(scratch0, FIRST_JS_RECEIVER_TYPE);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000098 __ j(below, miss_label);
99
100 // Load properties array.
101 Register properties = scratch0;
102 __ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
103
104 // Check that the properties array is a dictionary.
105 __ cmp(FieldOperand(properties, HeapObject::kMapOffset),
106 Immediate(masm->isolate()->factory()->hash_table_map()));
107 __ j(not_equal, miss_label);
108
109 Label done;
110 NameDictionaryLookupStub::GenerateNegativeLookup(masm, miss_label, &done,
111 properties, name, scratch1);
112 __ bind(&done);
113 __ DecrementCounter(counters->negative_lookups_miss(), 1);
114}
115
116
117void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400118 MacroAssembler* masm, int index, Register result, Label* miss) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000119 __ LoadGlobalFunction(index, result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000120 // Load its initial map. The global functions all have initial maps.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400121 __ mov(result,
122 FieldOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000123 // Load the prototype from the initial map.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400124 __ mov(result, FieldOperand(result, Map::kPrototypeOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000125}
126
127
128void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
129 MacroAssembler* masm, Register receiver, Register scratch1,
130 Register scratch2, Label* miss_label) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000131 // TODO(mvstanton): This isn't used on ia32. Move all the other
132 // platform implementations into a code stub so this method can be removed.
133 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000134}
135
136
137// Generate call to api function.
138// This function uses push() to generate smaller, faster code than
139// the version above. It is an optimization that should will be removed
140// when api call ICs are generated in hydrogen.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000141void PropertyHandlerCompiler::GenerateApiAccessorCall(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000142 MacroAssembler* masm, const CallOptimization& optimization,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000143 Handle<Map> receiver_map, Register receiver, Register scratch,
144 bool is_store, Register store_parameter, Register accessor_holder,
145 int accessor_index) {
146 DCHECK(!accessor_holder.is(scratch));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000147 // Copy return value.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000148 __ pop(scratch);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000149 // receiver
150 __ push(receiver);
151 // Write the arguments to stack frame.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000152 if (is_store) {
153 DCHECK(!receiver.is(store_parameter));
154 DCHECK(!scratch.is(store_parameter));
155 __ push(store_parameter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000156 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000157 __ push(scratch);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000158 // Stack now matches JSFunction abi.
159 DCHECK(optimization.is_simple_api_call());
160
161 // Abi for CallApiFunctionStub.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000162 Register callee = edi;
163 Register data = ebx;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000164 Register holder = ecx;
165 Register api_function_address = edx;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000166 scratch = no_reg;
167
168 // Put callee in place.
169 __ LoadAccessor(callee, accessor_holder, accessor_index,
170 is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000171
172 // Put holder in place.
173 CallOptimization::HolderLookup holder_lookup;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000174 int holder_depth = 0;
175 optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup,
176 &holder_depth);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000177 switch (holder_lookup) {
178 case CallOptimization::kHolderIsReceiver:
179 __ Move(holder, receiver);
180 break;
181 case CallOptimization::kHolderFound:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000182 __ mov(holder, FieldOperand(receiver, HeapObject::kMapOffset));
183 __ mov(holder, FieldOperand(holder, Map::kPrototypeOffset));
184 for (int i = 1; i < holder_depth; i++) {
185 __ mov(holder, FieldOperand(holder, HeapObject::kMapOffset));
186 __ mov(holder, FieldOperand(holder, Map::kPrototypeOffset));
187 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000188 break;
189 case CallOptimization::kHolderNotFound:
190 UNREACHABLE();
191 break;
192 }
193
194 Isolate* isolate = masm->isolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000195 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000196 bool call_data_undefined = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000197 // Put call data in place.
198 if (api_call_info->data()->IsUndefined()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000199 call_data_undefined = true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000200 __ mov(data, Immediate(isolate->factory()->undefined_value()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000201 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100202 if (optimization.is_constant_call()) {
203 __ mov(data, FieldOperand(callee, JSFunction::kSharedFunctionInfoOffset));
204 __ mov(data, FieldOperand(data, SharedFunctionInfo::kFunctionDataOffset));
205 __ mov(data, FieldOperand(data, FunctionTemplateInfo::kCallCodeOffset));
206 } else {
207 __ mov(data, FieldOperand(callee, FunctionTemplateInfo::kCallCodeOffset));
208 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000209 __ mov(data, FieldOperand(data, CallHandlerInfo::kDataOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000210 }
211
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000212 if (api_call_info->fast_handler()->IsCode()) {
213 // Just tail call into the code.
214 __ Jump(handle(Code::cast(api_call_info->fast_handler())),
215 RelocInfo::CODE_TARGET);
216 return;
217 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000218 // Put api_function_address in place.
219 Address function_address = v8::ToCData<Address>(api_call_info->callback());
220 __ mov(api_function_address, Immediate(function_address));
221
222 // Jump to stub.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100223 CallApiAccessorStub stub(isolate, is_store, call_data_undefined,
224 !optimization.is_constant_call());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000225 __ TailCallStub(&stub);
226}
227
228
229// Generate code to check that a global property cell is empty. Create
230// the property cell at compilation time if no cell exists for the
231// property.
232void PropertyHandlerCompiler::GenerateCheckPropertyCell(
233 MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
234 Register scratch, Label* miss) {
235 Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
236 DCHECK(cell->value()->IsTheHole());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000237 Factory* factory = masm->isolate()->factory();
238 Handle<WeakCell> weak_cell = factory->NewWeakCell(cell);
239 __ LoadWeakValue(scratch, weak_cell, miss);
240 __ cmp(FieldOperand(scratch, PropertyCell::kValueOffset),
241 Immediate(factory->the_hole_value()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000242 __ j(not_equal, miss);
243}
244
245
246void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000247 MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
248 int accessor_index, int expected_arguments, Register scratch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000249 // ----------- S t a t e -------------
250 // -- esp[0] : return address
251 // -----------------------------------
252 {
253 FrameScope scope(masm, StackFrame::INTERNAL);
254
255 // Save value register, so we can restore it later.
256 __ push(value());
257
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000258 if (accessor_index >= 0) {
259 DCHECK(!holder.is(scratch));
260 DCHECK(!receiver.is(scratch));
261 DCHECK(!value().is(scratch));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000262 // Call the JavaScript setter with receiver and value on the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000263 if (map->IsJSGlobalObjectMap()) {
264 __ mov(scratch,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000265 FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000266 receiver = scratch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000267 }
268 __ push(receiver);
269 __ push(value());
270 ParameterCount actual(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000271 ParameterCount expected(expected_arguments);
272 __ LoadAccessor(edi, holder, accessor_index, ACCESSOR_SETTER);
273 __ InvokeFunction(edi, expected, actual, CALL_FUNCTION,
274 CheckDebugStepCallWrapper());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000275 } else {
276 // If we generate a global code snippet for deoptimization only, remember
277 // the place to continue after deoptimization.
278 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
279 }
280
281 // We have to return the passed value, not the return value of the setter.
282 __ pop(eax);
283
284 // Restore context register.
285 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
286 }
287 __ ret(0);
288}
289
290
291static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
292 Register holder, Register name,
293 Handle<JSObject> holder_obj) {
294 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000295 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
296 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
297 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000298 __ push(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000299 __ push(receiver);
300 __ push(holder);
301}
302
303
304static void CompileCallLoadPropertyWithInterceptor(
305 MacroAssembler* masm, Register receiver, Register holder, Register name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000306 Handle<JSObject> holder_obj, Runtime::FunctionId id) {
307 DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
308 Runtime::FunctionForId(id)->nargs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000309 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000310 __ CallRuntime(id);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000311}
312
313
314static void StoreIC_PushArgs(MacroAssembler* masm) {
315 Register receiver = StoreDescriptor::ReceiverRegister();
316 Register name = StoreDescriptor::NameRegister();
317 Register value = StoreDescriptor::ValueRegister();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000318 Register slot = VectorStoreICDescriptor::SlotRegister();
319 Register vector = VectorStoreICDescriptor::VectorRegister();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000320
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000321 __ xchg(receiver, Operand(esp, 0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000322 __ push(name);
323 __ push(value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000324 __ push(slot);
325 __ push(vector);
326 __ push(receiver); // which contains the return address.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000327}
328
329
330void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
331 // Return address is on the stack.
332 StoreIC_PushArgs(masm);
333
334 // Do tail-call to runtime routine.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000335 __ TailCallRuntime(Runtime::kStoreIC_Slow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000336}
337
338
339void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) {
340 // Return address is on the stack.
341 StoreIC_PushArgs(masm);
342
343 // Do tail-call to runtime routine.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000344 __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000345}
346
347
348#undef __
349#define __ ACCESS_MASM(masm())
350
351
352void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
353 Handle<Name> name) {
354 if (!label->is_unused()) {
355 __ bind(label);
356 __ mov(this->name(), Immediate(name));
357 }
358}
359
360
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400361void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
362 __ mov(this->name(), Immediate(name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000363}
364
365
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000366void NamedStoreHandlerCompiler::RearrangeVectorAndSlot(
367 Register current_map, Register destination_map) {
368 DCHECK(destination_map.is(StoreTransitionHelper::MapRegister()));
369 DCHECK(current_map.is(StoreTransitionHelper::VectorRegister()));
370 ExternalReference virtual_slot =
371 ExternalReference::virtual_slot_register(isolate());
372 __ mov(destination_map, current_map);
373 __ pop(current_map);
374 __ mov(Operand::StaticVariable(virtual_slot), current_map);
375 __ pop(current_map); // put vector in place.
376}
377
378
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400379void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000380 Register map_reg,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400381 Register scratch,
382 Label* miss) {
383 Handle<WeakCell> cell = Map::WeakCellForMap(transition);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400384 DCHECK(!map_reg.is(scratch));
385 __ LoadWeakValue(map_reg, cell, miss);
386 if (transition->CanBeDeprecated()) {
387 __ mov(scratch, FieldOperand(map_reg, Map::kBitField3Offset));
388 __ and_(scratch, Immediate(Map::Deprecated::kMask));
389 __ j(not_zero, miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000390 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400391}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000392
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400393
394void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
395 int descriptor,
396 Register value_reg,
397 Register scratch,
398 Label* miss_label) {
399 DCHECK(!map_reg.is(scratch));
400 DCHECK(!map_reg.is(value_reg));
401 DCHECK(!value_reg.is(scratch));
402 __ LoadInstanceDescriptors(map_reg, scratch);
403 __ mov(scratch,
404 FieldOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
405 __ cmp(value_reg, scratch);
406 __ j(not_equal, miss_label);
407}
408
Ben Murdoch097c5b22016-05-18 11:27:45 +0100409void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400410 Register value_reg,
411 Label* miss_label) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000412 Register map_reg = scratch1();
413 Register scratch = scratch2();
414 DCHECK(!value_reg.is(map_reg));
415 DCHECK(!value_reg.is(scratch));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400416 __ JumpIfSmi(value_reg, miss_label);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100417 if (field_type->IsClass()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000418 __ mov(map_reg, FieldOperand(value_reg, HeapObject::kMapOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100419 __ CmpWeakValue(map_reg, Map::WeakCellForMap(field_type->AsClass()),
420 scratch);
421 __ j(not_equal, miss_label);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400422 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000423}
424
425
426Register PropertyHandlerCompiler::CheckPrototypes(
427 Register object_reg, Register holder_reg, Register scratch1,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000428 Register scratch2, Handle<Name> name, Label* miss, PrototypeCheckType check,
429 ReturnHolder return_what) {
430 Handle<Map> receiver_map = map();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000431
432 // Make sure there's no overlap between holder and object registers.
433 DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
434 DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) &&
435 !scratch2.is(scratch1));
436
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000437 if (FLAG_eliminate_prototype_chain_checks) {
438 Handle<Cell> validity_cell =
439 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
440 if (!validity_cell.is_null()) {
441 DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid),
442 validity_cell->value());
443 // Operand::ForCell(...) points to the cell's payload!
444 __ cmp(Operand::ForCell(validity_cell),
445 Immediate(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 __ mov(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.
462 Register reg = object_reg;
463 int depth = 0;
464
465 Handle<JSObject> current = Handle<JSObject>::null();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000466 if (receiver_map->IsJSGlobalObjectMap()) {
467 current = isolate()->global_object();
468 }
469
470 // Check access rights to the global object. This has to happen after
471 // the map check so that we know that the object is actually a global
472 // object.
473 // This allows us to install generated handlers for accesses to the
474 // global proxy (as opposed to using slow ICs). See corresponding code
475 // in LookupForRead().
476 if (receiver_map->IsJSGlobalProxyMap()) {
477 __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
478 }
479
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000480 Handle<JSObject> prototype = Handle<JSObject>::null();
481 Handle<Map> current_map = receiver_map;
482 Handle<Map> holder_map(holder()->map());
483 // Traverse the prototype chain and check the maps in the prototype chain for
484 // fast and global objects or do negative lookup for normal objects.
485 while (!current_map.is_identical_to(holder_map)) {
486 ++depth;
487
488 // Only global objects and objects that do not require access
489 // checks are allowed in stubs.
490 DCHECK(current_map->IsJSGlobalProxyMap() ||
491 !current_map->is_access_check_needed());
492
493 prototype = handle(JSObject::cast(current_map->prototype()));
494 if (current_map->is_dictionary_map() &&
495 !current_map->IsJSGlobalObjectMap()) {
496 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
497 if (!name->IsUniqueName()) {
498 DCHECK(name->IsString());
499 name = factory()->InternalizeString(Handle<String>::cast(name));
500 }
501 DCHECK(current.is_null() ||
502 current->property_dictionary()->FindEntry(name) ==
503 NameDictionary::kNotFound);
504
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000505 if (FLAG_eliminate_prototype_chain_checks && depth > 1) {
506 // TODO(jkummerow): Cache and re-use weak cell.
507 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
508 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000509 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
510 scratch2);
511
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000512 if (!FLAG_eliminate_prototype_chain_checks) {
513 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
514 __ mov(holder_reg, FieldOperand(scratch1, Map::kPrototypeOffset));
515 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000516 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400517 Register map_reg = scratch1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000518 if (!FLAG_eliminate_prototype_chain_checks) {
519 __ mov(map_reg, FieldOperand(reg, HeapObject::kMapOffset));
520 }
521 if (current_map->IsJSGlobalObjectMap()) {
522 GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
523 name, scratch2, miss);
524 } else if (!FLAG_eliminate_prototype_chain_checks &&
525 (depth != 1 || check == CHECK_ALL_MAPS)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400526 Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
527 __ CmpWeakValue(map_reg, cell, scratch2);
528 __ j(not_equal, miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000529 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000530 if (!FLAG_eliminate_prototype_chain_checks) {
531 __ mov(holder_reg, FieldOperand(map_reg, Map::kPrototypeOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000532 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000533 }
534
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000535 reg = holder_reg; // From now on the object will be in holder_reg.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000536 // Go to the next object in the prototype chain.
537 current = prototype;
538 current_map = handle(current->map());
539 }
540
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000541 DCHECK(!current_map->IsJSGlobalProxyMap());
542
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000543 // Log the check depth.
544 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
545
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000546 if (!FLAG_eliminate_prototype_chain_checks &&
547 (depth != 0 || check == CHECK_ALL_MAPS)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000548 // Check the holder map.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400549 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
550 Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
551 __ CmpWeakValue(scratch1, cell, scratch2);
552 __ j(not_equal, miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000553 }
554
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000555 bool return_holder = return_what == RETURN_HOLDER;
556 if (FLAG_eliminate_prototype_chain_checks && return_holder && depth != 0) {
557 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000558 }
559
560 // Return the register containing the holder.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000561 return return_holder ? reg : no_reg;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000562}
563
564
565void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
566 if (!miss->is_unused()) {
567 Label success;
568 __ jmp(&success);
569 __ bind(miss);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400570 if (IC::ICUseVector(kind())) {
571 DCHECK(kind() == Code::LOAD_IC);
572 PopVectorAndSlot();
573 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000574 TailCallBuiltin(masm(), MissBuiltin(kind()));
575 __ bind(&success);
576 }
577}
578
579
580void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
581 if (!miss->is_unused()) {
582 Label success;
583 __ jmp(&success);
584 GenerateRestoreName(miss, name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000585 if (IC::ICUseVector(kind())) PopVectorAndSlot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000586 TailCallBuiltin(masm(), MissBuiltin(kind()));
587 __ bind(&success);
588 }
589}
590
591
592void NamedLoadHandlerCompiler::GenerateLoadCallback(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100593 Register reg, Handle<AccessorInfo> callback) {
594 DCHECK(!AreAliased(scratch2(), scratch3(), receiver()));
595 DCHECK(!AreAliased(scratch2(), scratch3(), reg));
596
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000597 // Insert additional parameters into the stack frame above return address.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000598 __ pop(scratch3()); // Get return address to place it below.
599
Ben Murdoch097c5b22016-05-18 11:27:45 +0100600 // Build v8::PropertyCallbackInfo::args_ array on the stack and push property
601 // name below the exit frame to make GC aware of them.
602 STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0);
603 STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1);
604 STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2);
605 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3);
606 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4);
607 STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5);
608 STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6);
609 STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7);
610
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000611 __ push(receiver()); // receiver
Ben Murdoch097c5b22016-05-18 11:27:45 +0100612 // Push data from AccessorInfo.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000613 Handle<Object> data(callback->data(), isolate());
614 if (data->IsUndefined() || data->IsSmi()) {
615 __ push(Immediate(data));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000616 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000617 Handle<WeakCell> cell =
618 isolate()->factory()->NewWeakCell(Handle<HeapObject>::cast(data));
619 // The callback is alive if this instruction is executed,
620 // so the weak cell is not cleared and points to data.
621 __ GetWeakValue(scratch2(), cell);
622 __ push(scratch2());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000623 }
624 __ push(Immediate(isolate()->factory()->undefined_value())); // ReturnValue
625 // ReturnValue default value
626 __ push(Immediate(isolate()->factory()->undefined_value()));
627 __ push(Immediate(reinterpret_cast<int>(isolate())));
628 __ push(reg); // holder
Ben Murdoch097c5b22016-05-18 11:27:45 +0100629 __ push(Immediate(Smi::FromInt(0))); // should_throw_on_error -> false
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000630
631 __ push(name()); // name
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000632 __ push(scratch3()); // Restore return address.
633
634 // Abi for CallApiGetter
635 Register getter_address = ApiGetterDescriptor::function_address();
636 Address function_address = v8::ToCData<Address>(callback->getter());
637 __ mov(getter_address, Immediate(function_address));
638
639 CallApiGetterStub stub(isolate());
640 __ TailCallStub(&stub);
641}
642
643
644void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
645 // Return the constant value.
646 __ LoadObject(eax, value);
647 __ ret(0);
648}
649
650
651void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
652 LookupIterator* it, Register holder_reg) {
653 DCHECK(holder()->HasNamedInterceptor());
654 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
655
656 // Compile the interceptor call, followed by inline code to load the
657 // property from further up the prototype chain if the call fails.
658 // Check that the maps haven't changed.
659 DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
660
661 // Preserve the receiver register explicitly whenever it is different from the
662 // holder and it is needed should the interceptor return without any result.
663 // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
664 // case might cause a miss during the prototype check.
665 bool must_perform_prototype_check =
666 !holder().is_identical_to(it->GetHolder<JSObject>());
667 bool must_preserve_receiver_reg =
668 !receiver().is(holder_reg) &&
669 (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
670
671 // Save necessary data before invoking an interceptor.
672 // Requires a frame to make GC aware of pushed pointers.
673 {
674 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
675
676 if (must_preserve_receiver_reg) {
677 __ push(receiver());
678 }
679 __ push(holder_reg);
680 __ push(this->name());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400681 InterceptorVectorSlotPush(holder_reg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000682 // Invoke an interceptor. Note: map checks from receiver to
683 // interceptor's holder has been compiled before (see a caller
684 // of this method.)
685 CompileCallLoadPropertyWithInterceptor(
686 masm(), receiver(), holder_reg, this->name(), holder(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000687 Runtime::kLoadPropertyWithInterceptorOnly);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000688
689 // Check if interceptor provided a value for property. If it's
690 // the case, return immediately.
691 Label interceptor_failed;
692 __ cmp(eax, factory()->no_interceptor_result_sentinel());
693 __ j(equal, &interceptor_failed);
694 frame_scope.GenerateLeaveFrame();
695 __ ret(0);
696
697 // Clobber registers when generating debug-code to provoke errors.
698 __ bind(&interceptor_failed);
699 if (FLAG_debug_code) {
700 __ mov(receiver(), Immediate(bit_cast<int32_t>(kZapValue)));
701 __ mov(holder_reg, Immediate(bit_cast<int32_t>(kZapValue)));
702 __ mov(this->name(), Immediate(bit_cast<int32_t>(kZapValue)));
703 }
704
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400705 InterceptorVectorSlotPop(holder_reg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000706 __ pop(this->name());
707 __ pop(holder_reg);
708 if (must_preserve_receiver_reg) {
709 __ pop(receiver());
710 }
711
712 // Leave the internal frame.
713 }
714
715 GenerateLoadPostInterceptor(it, holder_reg);
716}
717
718
719void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
720 DCHECK(holder()->HasNamedInterceptor());
721 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
722 // Call the runtime system to load the interceptor.
723 __ pop(scratch2()); // save old return address
724 PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
725 holder());
726 __ push(scratch2()); // restore old return address
727
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000728 __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000729}
730
731
732Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100733 Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
734 LanguageMode language_mode) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400735 Register holder_reg = Frontend(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000736
737 __ pop(scratch1()); // remove the return address
738 __ push(receiver());
739 __ push(holder_reg);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000740 // If the callback cannot leak, then push the callback directly,
741 // otherwise wrap it in a weak cell.
742 if (callback->data()->IsUndefined() || callback->data()->IsSmi()) {
743 __ Push(callback);
744 } else {
745 Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
746 __ Push(cell);
747 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000748 __ Push(name);
749 __ push(value());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100750 __ push(Immediate(Smi::FromInt(language_mode)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000751 __ push(scratch1()); // restore return address
752
753 // Do tail-call to the runtime system.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000754 __ TailCallRuntime(Runtime::kStoreCallbackProperty);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000755
756 // Return the generated code.
757 return GetCode(kind(), Code::FAST, name);
758}
759
760
761Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor(
762 Handle<Name> name) {
763 __ pop(scratch1()); // remove the return address
764 __ push(receiver());
765 __ push(this->name());
766 __ push(value());
767 __ push(scratch1()); // restore return address
768
769 // Do tail-call to the runtime system.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000770 __ TailCallRuntime(Runtime::kStorePropertyWithInterceptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000771
772 // Return the generated code.
773 return GetCode(kind(), Code::FAST, name);
774}
775
776
777Register NamedStoreHandlerCompiler::value() {
778 return StoreDescriptor::ValueRegister();
779}
780
781
782Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
783 Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
784 Label miss;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400785 if (IC::ICUseVector(kind())) {
786 PushVectorAndSlot();
787 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000788 FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000789 // Get the value from the cell.
790 Register result = StoreDescriptor::ValueRegister();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400791 Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
792 __ LoadWeakValue(result, weak_cell, &miss);
793 __ mov(result, FieldOperand(result, PropertyCell::kValueOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000794
795 // Check for deleted property if property can actually be deleted.
796 if (is_configurable) {
797 __ cmp(result, factory()->the_hole_value());
798 __ j(equal, &miss);
799 } else if (FLAG_debug_code) {
800 __ cmp(result, factory()->the_hole_value());
801 __ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
802 }
803
804 Counters* counters = isolate()->counters();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100805 __ IncrementCounter(counters->ic_named_load_global_stub(), 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000806 // The code above already loads the result into the return register.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400807 if (IC::ICUseVector(kind())) {
808 DiscardVectorAndSlot();
809 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000810 __ ret(0);
811
812 FrontendFooter(name, &miss);
813
814 // Return the generated code.
815 return GetCode(kind(), Code::NORMAL, name);
816}
817
818
819#undef __
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000820} // namespace internal
821} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000822
823#endif // V8_TARGET_ARCH_IA32