1 // 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
5 #if V8_TARGET_ARCH_MIPS
6
7 #include "src/ic/handler-compiler.h"
8
9 #include "src/api-arguments.h"
10 #include "src/field-type.h"
11 #include "src/ic/call-optimization.h"
12 #include "src/ic/ic.h"
13 #include "src/isolate-inl.h"
14
15 namespace v8 {
16 namespace internal {
17
18 #define __ ACCESS_MASM(masm)
19
20
GenerateLoadViaGetter(MacroAssembler * masm,Handle<Map> map,Register receiver,Register holder,int accessor_index,int expected_arguments,Register scratch)21 void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
22 MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
23 int accessor_index, int expected_arguments, Register scratch) {
24 // ----------- S t a t e -------------
25 // -- a0 : receiver
26 // -- a2 : name
27 // -- ra : return address
28 // -----------------------------------
29 {
30 FrameScope scope(masm, StackFrame::INTERNAL);
31
32 // Save context register
33 __ push(cp);
34
35 if (accessor_index >= 0) {
36 DCHECK(!holder.is(scratch));
37 DCHECK(!receiver.is(scratch));
38 // Call the JavaScript getter with the receiver on the stack.
39 if (map->IsJSGlobalObjectMap()) {
40 // Swap in the global receiver.
41 __ lw(scratch,
42 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
43 receiver = scratch;
44 }
45 __ push(receiver);
46 __ LoadAccessor(a1, holder, accessor_index, ACCESSOR_GETTER);
47 __ li(a0, Operand(0));
48 __ Call(masm->isolate()->builtins()->CallFunction(
49 ConvertReceiverMode::kNotNullOrUndefined),
50 RelocInfo::CODE_TARGET);
51 } 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.
58 __ pop(cp);
59 }
60 __ Ret();
61 }
62
63
GenerateStoreViaSetter(MacroAssembler * masm,Handle<Map> map,Register receiver,Register holder,int accessor_index,int expected_arguments,Register scratch)64 void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
65 MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
66 int accessor_index, int expected_arguments, Register scratch) {
67 // ----------- S t a t e -------------
68 // -- ra : return address
69 // -----------------------------------
70 {
71 FrameScope scope(masm, StackFrame::INTERNAL);
72
73 // Save context and value registers, so we can restore them later.
74 __ Push(cp, value());
75
76 if (accessor_index >= 0) {
77 DCHECK(!holder.is(scratch));
78 DCHECK(!receiver.is(scratch));
79 DCHECK(!value().is(scratch));
80 // Call the JavaScript setter with receiver and value on the stack.
81 if (map->IsJSGlobalObjectMap()) {
82 // Swap in the global receiver.
83 __ lw(scratch,
84 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
85 receiver = scratch;
86 }
87 __ Push(receiver, value());
88 __ LoadAccessor(a1, holder, accessor_index, ACCESSOR_SETTER);
89 __ li(a0, Operand(1));
90 __ Call(masm->isolate()->builtins()->CallFunction(
91 ConvertReceiverMode::kNotNullOrUndefined),
92 RelocInfo::CODE_TARGET);
93 } else {
94 // If we generate a global code snippet for deoptimization only, remember
95 // the place to continue after deoptimization.
96 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
97 }
98
99 // We have to return the passed value, not the return value of the setter.
100 // Restore context register.
101 __ Pop(cp, v0);
102 }
103 __ Ret();
104 }
105
106
PushVectorAndSlot(Register vector,Register slot)107 void PropertyHandlerCompiler::PushVectorAndSlot(Register vector,
108 Register slot) {
109 MacroAssembler* masm = this->masm();
110 STATIC_ASSERT(LoadWithVectorDescriptor::kSlot <
111 LoadWithVectorDescriptor::kVector);
112 STATIC_ASSERT(StoreWithVectorDescriptor::kSlot <
113 StoreWithVectorDescriptor::kVector);
114 STATIC_ASSERT(StoreTransitionDescriptor::kSlot <
115 StoreTransitionDescriptor::kVector);
116 __ Push(slot, vector);
117 }
118
119
PopVectorAndSlot(Register vector,Register slot)120 void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) {
121 MacroAssembler* masm = this->masm();
122 __ Pop(slot, vector);
123 }
124
125
DiscardVectorAndSlot()126 void PropertyHandlerCompiler::DiscardVectorAndSlot() {
127 MacroAssembler* masm = this->masm();
128 // Remove vector and slot.
129 __ Addu(sp, sp, Operand(2 * kPointerSize));
130 }
131
PushReturnAddress(Register tmp)132 void PropertyHandlerCompiler::PushReturnAddress(Register tmp) {
133 // No-op. Return address is in ra register.
134 }
135
PopReturnAddress(Register tmp)136 void PropertyHandlerCompiler::PopReturnAddress(Register tmp) {
137 // No-op. Return address is in ra register.
138 }
139
GenerateDictionaryNegativeLookup(MacroAssembler * masm,Label * miss_label,Register receiver,Handle<Name> name,Register scratch0,Register scratch1)140 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
141 MacroAssembler* masm, Label* miss_label, Register receiver,
142 Handle<Name> name, Register scratch0, Register scratch1) {
143 DCHECK(name->IsUniqueName());
144 DCHECK(!receiver.is(scratch0));
145 Counters* counters = masm->isolate()->counters();
146 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
147 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
148
149 Label done;
150
151 const int kInterceptorOrAccessCheckNeededMask =
152 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
153
154 // Bail out if the receiver has a named interceptor or requires access checks.
155 Register map = scratch1;
156 __ lw(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
157 __ lbu(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
158 __ And(scratch0, scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
159 __ Branch(miss_label, ne, scratch0, Operand(zero_reg));
160
161 // Check that receiver is a JSObject.
162 __ lbu(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
163 __ Branch(miss_label, lt, scratch0, Operand(FIRST_JS_RECEIVER_TYPE));
164
165 // Load properties array.
166 Register properties = scratch0;
167 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
168 // Check that the properties array is a dictionary.
169 __ lw(map, FieldMemOperand(properties, HeapObject::kMapOffset));
170 Register tmp = properties;
171 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
172 __ Branch(miss_label, ne, map, Operand(tmp));
173
174 // Restore the temporarily used register.
175 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
176
177
178 NameDictionaryLookupStub::GenerateNegativeLookup(
179 masm, miss_label, &done, receiver, properties, name, scratch1);
180 __ bind(&done);
181 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
182 }
183
184
GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler * masm,int index,Register result,Label * miss)185 void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
186 MacroAssembler* masm, int index, Register result, Label* miss) {
187 __ LoadNativeContextSlot(index, result);
188 // Load its initial map. The global functions all have initial maps.
189 __ lw(result,
190 FieldMemOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
191 // Load the prototype from the initial map.
192 __ lw(result, FieldMemOperand(result, Map::kPrototypeOffset));
193 }
194
195
GenerateLoadFunctionPrototype(MacroAssembler * masm,Register receiver,Register scratch1,Register scratch2,Label * miss_label)196 void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
197 MacroAssembler* masm, Register receiver, Register scratch1,
198 Register scratch2, Label* miss_label) {
199 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
200 __ Ret(USE_DELAY_SLOT);
201 __ mov(v0, scratch1);
202 }
203
204
205 // Generate code to check that a global property cell is empty. Create
206 // the property cell at compilation time if no cell exists for the
207 // property.
GenerateCheckPropertyCell(MacroAssembler * masm,Handle<JSGlobalObject> global,Handle<Name> name,Register scratch,Label * miss)208 void PropertyHandlerCompiler::GenerateCheckPropertyCell(
209 MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
210 Register scratch, Label* miss) {
211 Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
212 global, name, PropertyCellType::kInvalidated);
213 Isolate* isolate = masm->isolate();
214 DCHECK(cell->value()->IsTheHole(isolate));
215 Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
216 __ LoadWeakValue(scratch, weak_cell, miss);
217 __ lw(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset));
218 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
219 __ Branch(miss, ne, scratch, Operand(at));
220 }
221
222
PushInterceptorArguments(MacroAssembler * masm,Register receiver,Register holder,Register name,Handle<JSObject> holder_obj)223 static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
224 Register holder, Register name,
225 Handle<JSObject> holder_obj) {
226 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
227 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
228 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
229 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
230 __ Push(name, receiver, holder);
231 }
232
233
CompileCallLoadPropertyWithInterceptor(MacroAssembler * masm,Register receiver,Register holder,Register name,Handle<JSObject> holder_obj,Runtime::FunctionId id)234 static void CompileCallLoadPropertyWithInterceptor(
235 MacroAssembler* masm, Register receiver, Register holder, Register name,
236 Handle<JSObject> holder_obj, Runtime::FunctionId id) {
237 DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
238 Runtime::FunctionForId(id)->nargs);
239 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
240 __ CallRuntime(id);
241 }
242
243
244 // Generate call to api function.
GenerateApiAccessorCall(MacroAssembler * masm,const CallOptimization & optimization,Handle<Map> receiver_map,Register receiver,Register scratch_in,bool is_store,Register store_parameter,Register accessor_holder,int accessor_index)245 void PropertyHandlerCompiler::GenerateApiAccessorCall(
246 MacroAssembler* masm, const CallOptimization& optimization,
247 Handle<Map> receiver_map, Register receiver, Register scratch_in,
248 bool is_store, Register store_parameter, Register accessor_holder,
249 int accessor_index) {
250 DCHECK(!accessor_holder.is(scratch_in));
251 DCHECK(!receiver.is(scratch_in));
252 __ push(receiver);
253 // Write the arguments to stack frame.
254 if (is_store) {
255 DCHECK(!receiver.is(store_parameter));
256 DCHECK(!scratch_in.is(store_parameter));
257 __ push(store_parameter);
258 }
259 DCHECK(optimization.is_simple_api_call());
260
261 // Abi for CallApiCallbackStub.
262 Register callee = a0;
263 Register data = t0;
264 Register holder = a2;
265 Register api_function_address = a1;
266
267 // Put callee in place.
268 __ LoadAccessor(callee, accessor_holder, accessor_index,
269 is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
270
271 // Put holder in place.
272 CallOptimization::HolderLookup holder_lookup;
273 int holder_depth = 0;
274 optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup,
275 &holder_depth);
276 switch (holder_lookup) {
277 case CallOptimization::kHolderIsReceiver:
278 __ Move(holder, receiver);
279 break;
280 case CallOptimization::kHolderFound:
281 __ lw(holder, FieldMemOperand(receiver, HeapObject::kMapOffset));
282 __ lw(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
283 for (int i = 1; i < holder_depth; i++) {
284 __ lw(holder, FieldMemOperand(holder, HeapObject::kMapOffset));
285 __ lw(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
286 }
287 break;
288 case CallOptimization::kHolderNotFound:
289 UNREACHABLE();
290 break;
291 }
292
293 Isolate* isolate = masm->isolate();
294 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
295 bool call_data_undefined = false;
296 // Put call data in place.
297 if (api_call_info->data()->IsUndefined(isolate)) {
298 call_data_undefined = true;
299 __ LoadRoot(data, Heap::kUndefinedValueRootIndex);
300 } else {
301 if (optimization.is_constant_call()) {
302 __ lw(data,
303 FieldMemOperand(callee, JSFunction::kSharedFunctionInfoOffset));
304 __ lw(data,
305 FieldMemOperand(data, SharedFunctionInfo::kFunctionDataOffset));
306 __ lw(data, FieldMemOperand(data, FunctionTemplateInfo::kCallCodeOffset));
307 } else {
308 __ lw(data,
309 FieldMemOperand(callee, FunctionTemplateInfo::kCallCodeOffset));
310 }
311 __ lw(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset));
312 }
313
314 if (api_call_info->fast_handler()->IsCode()) {
315 // Just tail call into the fast handler if present.
316 __ Jump(handle(Code::cast(api_call_info->fast_handler())),
317 RelocInfo::CODE_TARGET);
318 return;
319 }
320 // Put api_function_address in place.
321 Address function_address = v8::ToCData<Address>(api_call_info->callback());
322 ApiFunction fun(function_address);
323 ExternalReference::Type type = ExternalReference::DIRECT_API_CALL;
324 ExternalReference ref = ExternalReference(&fun, type, masm->isolate());
325 __ li(api_function_address, Operand(ref));
326
327 // Jump to stub.
328 CallApiCallbackStub stub(isolate, is_store, call_data_undefined,
329 !optimization.is_constant_call());
330 __ TailCallStub(&stub);
331 }
332
333 #undef __
334 #define __ ACCESS_MASM(masm())
335
336
GenerateRestoreName(Label * label,Handle<Name> name)337 void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
338 Handle<Name> name) {
339 if (!label->is_unused()) {
340 __ bind(label);
341 __ li(this->name(), Operand(name));
342 }
343 }
344
345
GenerateRestoreName(Handle<Name> name)346 void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
347 __ li(this->name(), Operand(name));
348 }
349
350
GenerateRestoreMap(Handle<Map> transition,Register map_reg,Register scratch,Label * miss)351 void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
352 Register map_reg,
353 Register scratch,
354 Label* miss) {
355 Handle<WeakCell> cell = Map::WeakCellForMap(transition);
356 DCHECK(!map_reg.is(scratch));
357 __ LoadWeakValue(map_reg, cell, miss);
358 if (transition->CanBeDeprecated()) {
359 __ lw(scratch, FieldMemOperand(map_reg, Map::kBitField3Offset));
360 __ And(at, scratch, Operand(Map::Deprecated::kMask));
361 __ Branch(miss, ne, at, Operand(zero_reg));
362 }
363 }
364
365
GenerateConstantCheck(Register map_reg,int descriptor,Register value_reg,Register scratch,Label * miss_label)366 void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
367 int descriptor,
368 Register value_reg,
369 Register scratch,
370 Label* miss_label) {
371 DCHECK(!map_reg.is(scratch));
372 DCHECK(!map_reg.is(value_reg));
373 DCHECK(!value_reg.is(scratch));
374 __ LoadInstanceDescriptors(map_reg, scratch);
375 __ lw(scratch,
376 FieldMemOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
377 __ Branch(miss_label, ne, value_reg, Operand(scratch));
378 }
379
GenerateFieldTypeChecks(FieldType * field_type,Register value_reg,Label * miss_label)380 void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type,
381 Register value_reg,
382 Label* miss_label) {
383 Register map_reg = scratch1();
384 Register scratch = scratch2();
385 DCHECK(!value_reg.is(map_reg));
386 DCHECK(!value_reg.is(scratch));
387 __ JumpIfSmi(value_reg, miss_label);
388 if (field_type->IsClass()) {
389 __ lw(map_reg, FieldMemOperand(value_reg, HeapObject::kMapOffset));
390 // Compare map directly within the Branch() functions.
391 __ GetWeakValue(scratch, Map::WeakCellForMap(field_type->AsClass()));
392 __ Branch(miss_label, ne, map_reg, Operand(scratch));
393 }
394 }
395
GenerateAccessCheck(Handle<WeakCell> native_context_cell,Register scratch1,Register scratch2,Label * miss,bool compare_native_contexts_only)396 void PropertyHandlerCompiler::GenerateAccessCheck(
397 Handle<WeakCell> native_context_cell, Register scratch1, Register scratch2,
398 Label* miss, bool compare_native_contexts_only) {
399 Label done;
400 // Load current native context.
401 __ lw(scratch1, NativeContextMemOperand());
402 // Load expected native context.
403 __ LoadWeakValue(scratch2, native_context_cell, miss);
404
405 if (!compare_native_contexts_only) {
406 __ Branch(&done, eq, scratch1, Operand(scratch2));
407
408 // Compare security tokens of current and expected native contexts.
409 __ lw(scratch1, ContextMemOperand(scratch1, Context::SECURITY_TOKEN_INDEX));
410 __ lw(scratch2, ContextMemOperand(scratch2, Context::SECURITY_TOKEN_INDEX));
411 }
412 __ Branch(miss, ne, scratch1, Operand(scratch2));
413
414 __ bind(&done);
415 }
416
CheckPrototypes(Register object_reg,Register holder_reg,Register scratch1,Register scratch2,Handle<Name> name,Label * miss,ReturnHolder return_what)417 Register PropertyHandlerCompiler::CheckPrototypes(
418 Register object_reg, Register holder_reg, Register scratch1,
419 Register scratch2, Handle<Name> name, Label* miss,
420 ReturnHolder return_what) {
421 Handle<Map> receiver_map = map();
422
423 // Make sure there's no overlap between holder and object registers.
424 DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
425 DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) &&
426 !scratch2.is(scratch1));
427
428 Handle<Cell> validity_cell =
429 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
430 if (!validity_cell.is_null()) {
431 DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), validity_cell->value());
432 __ li(scratch1, Operand(validity_cell));
433 __ lw(scratch1, FieldMemOperand(scratch1, Cell::kValueOffset));
434 __ Branch(miss, ne, scratch1,
435 Operand(Smi::FromInt(Map::kPrototypeChainValid)));
436 }
437
438 // Keep track of the current object in register reg.
439 Register reg = object_reg;
440 int depth = 0;
441
442 Handle<JSObject> current = Handle<JSObject>::null();
443 if (receiver_map->IsJSGlobalObjectMap()) {
444 current = isolate()->global_object();
445 }
446
447 Handle<Map> current_map(receiver_map->GetPrototypeChainRootMap(isolate()),
448 isolate());
449 Handle<Map> holder_map(holder()->map());
450 // Traverse the prototype chain and check the maps in the prototype chain for
451 // fast and global objects or do negative lookup for normal objects.
452 while (!current_map.is_identical_to(holder_map)) {
453 ++depth;
454
455 if (current_map->IsJSGlobalObjectMap()) {
456 GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
457 name, scratch2, miss);
458 } else if (current_map->is_dictionary_map()) {
459 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
460 DCHECK(name->IsUniqueName());
461 DCHECK(current.is_null() ||
462 current->property_dictionary()->FindEntry(name) ==
463 NameDictionary::kNotFound);
464
465 if (depth > 1) {
466 Handle<WeakCell> weak_cell =
467 Map::GetOrCreatePrototypeWeakCell(current, isolate());
468 __ LoadWeakValue(reg, weak_cell, miss);
469 }
470 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
471 scratch2);
472 }
473
474 reg = holder_reg; // From now on the object will be in holder_reg.
475 // Go to the next object in the prototype chain.
476 current = handle(JSObject::cast(current_map->prototype()));
477 current_map = handle(current->map());
478 }
479
480 DCHECK(!current_map->IsJSGlobalProxyMap());
481
482 // Log the check depth.
483 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
484
485 bool return_holder = return_what == RETURN_HOLDER;
486 if (return_holder && depth != 0) {
487 Handle<WeakCell> weak_cell =
488 Map::GetOrCreatePrototypeWeakCell(current, isolate());
489 __ LoadWeakValue(reg, weak_cell, miss);
490 }
491
492 // Return the register containing the holder.
493 return return_holder ? reg : no_reg;
494 }
495
496
FrontendFooter(Handle<Name> name,Label * miss)497 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
498 if (!miss->is_unused()) {
499 Label success;
500 __ Branch(&success);
501 __ bind(miss);
502 if (IC::ICUseVector(kind())) {
503 DCHECK(kind() == Code::LOAD_IC);
504 PopVectorAndSlot();
505 }
506 TailCallBuiltin(masm(), MissBuiltin(kind()));
507 __ bind(&success);
508 }
509 }
510
511
FrontendFooter(Handle<Name> name,Label * miss)512 void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
513 if (!miss->is_unused()) {
514 Label success;
515 __ Branch(&success);
516 GenerateRestoreName(miss, name);
517 if (IC::ICUseVector(kind())) PopVectorAndSlot();
518 TailCallBuiltin(masm(), MissBuiltin(kind()));
519 __ bind(&success);
520 }
521 }
522
523
GenerateLoadConstant(Handle<Object> value)524 void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
525 // Return the constant value.
526 __ li(v0, value);
527 __ Ret();
528 }
529
530
GenerateLoadInterceptorWithFollowup(LookupIterator * it,Register holder_reg)531 void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
532 LookupIterator* it, Register holder_reg) {
533 DCHECK(holder()->HasNamedInterceptor());
534 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
535
536 // Compile the interceptor call, followed by inline code to load the
537 // property from further up the prototype chain if the call fails.
538 // Check that the maps haven't changed.
539 DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
540
541 // Preserve the receiver register explicitly whenever it is different from the
542 // holder and it is needed should the interceptor return without any result.
543 // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
544 // case might cause a miss during the prototype check.
545 bool must_perform_prototype_check =
546 !holder().is_identical_to(it->GetHolder<JSObject>());
547 bool must_preserve_receiver_reg =
548 !receiver().is(holder_reg) &&
549 (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
550
551 // Save necessary data before invoking an interceptor.
552 // Requires a frame to make GC aware of pushed pointers.
553 {
554 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
555 if (must_preserve_receiver_reg) {
556 __ Push(receiver(), holder_reg, this->name());
557 } else {
558 __ Push(holder_reg, this->name());
559 }
560 InterceptorVectorSlotPush(holder_reg);
561 // Invoke an interceptor. Note: map checks from receiver to
562 // interceptor's holder has been compiled before (see a caller
563 // of this method).
564 CompileCallLoadPropertyWithInterceptor(
565 masm(), receiver(), holder_reg, this->name(), holder(),
566 Runtime::kLoadPropertyWithInterceptorOnly);
567
568 // Check if interceptor provided a value for property. If it's
569 // the case, return immediately.
570 Label interceptor_failed;
571 __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
572 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1()));
573 frame_scope.GenerateLeaveFrame();
574 __ Ret();
575
576 __ bind(&interceptor_failed);
577 InterceptorVectorSlotPop(holder_reg);
578 if (must_preserve_receiver_reg) {
579 __ Pop(receiver(), holder_reg, this->name());
580 } else {
581 __ Pop(holder_reg, this->name());
582 }
583 // Leave the internal frame.
584 }
585
586 GenerateLoadPostInterceptor(it, holder_reg);
587 }
588
589
GenerateLoadInterceptor(Register holder_reg)590 void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
591 // Call the runtime system to load the interceptor.
592 DCHECK(holder()->HasNamedInterceptor());
593 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
594 PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
595 holder());
596
597 __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
598 }
599
ZapStackArgumentsRegisterAliases()600 void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
601 STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
602 }
603
CompileStoreCallback(Handle<JSObject> object,Handle<Name> name,Handle<AccessorInfo> callback,LanguageMode language_mode)604 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
605 Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
606 LanguageMode language_mode) {
607 Register holder_reg = Frontend(name);
608
609 __ Push(receiver(), holder_reg); // Receiver.
610 // If the callback cannot leak, then push the callback directly,
611 // otherwise wrap it in a weak cell.
612 if (callback->data()->IsUndefined(isolate()) || callback->data()->IsSmi()) {
613 __ li(at, Operand(callback));
614 } else {
615 Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
616 __ li(at, Operand(cell));
617 }
618 __ push(at);
619 __ li(at, Operand(name));
620 __ Push(at, value());
621 __ Push(Smi::FromInt(language_mode));
622
623 // Do tail-call to the runtime system.
624 __ TailCallRuntime(Runtime::kStoreCallbackProperty);
625
626 // Return the generated code.
627 return GetCode(kind(), name);
628 }
629
630
value()631 Register NamedStoreHandlerCompiler::value() {
632 return StoreDescriptor::ValueRegister();
633 }
634
635
CompileLoadGlobal(Handle<PropertyCell> cell,Handle<Name> name,bool is_configurable)636 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
637 Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
638 Label miss;
639 if (IC::ICUseVector(kind())) {
640 PushVectorAndSlot();
641 }
642
643 FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
644
645 // Get the value from the cell.
646 Register result = StoreDescriptor::ValueRegister();
647 Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
648 __ LoadWeakValue(result, weak_cell, &miss);
649 __ lw(result, FieldMemOperand(result, PropertyCell::kValueOffset));
650
651 // Check for deleted property if property can actually be deleted.
652 if (is_configurable) {
653 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
654 __ Branch(&miss, eq, result, Operand(at));
655 }
656
657 Counters* counters = isolate()->counters();
658 __ IncrementCounter(counters->ic_named_load_global_stub(), 1, a1, a3);
659 if (IC::ICUseVector(kind())) {
660 DiscardVectorAndSlot();
661 }
662 __ Ret(USE_DELAY_SLOT);
663 __ Move(v0, result); // Ensure the stub returns correct value.
664
665 FrontendFooter(name, &miss);
666
667 // Return the generated code.
668 return GetCode(kind(), name);
669 }
670
671
672 #undef __
673 } // namespace internal
674 } // namespace v8
675
676 #endif // V8_TARGET_ARCH_MIPS
677