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_PPC 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 15namespace v8 { 16namespace internal { 17 18#define __ ACCESS_MASM(masm) 19 20 21void 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 // -- r3 : receiver 26 // -- r5 : name 27 // -- lr : return address 28 // ----------------------------------- 29 { 30 FrameAndConstantPoolScope 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 __ LoadP(scratch, 42 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); 43 receiver = scratch; 44 } 45 __ push(receiver); 46 __ LoadAccessor(r4, holder, accessor_index, ACCESSOR_GETTER); 47 __ li(r3, Operand::Zero()); 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 64void 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 // -- lr : return address 69 // ----------------------------------- 70 { 71 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); 72 73 // Save context register 74 // Save value register, so we can restore it later. 75 __ Push(cp, value()); 76 77 if (accessor_index >= 0) { 78 DCHECK(!holder.is(scratch)); 79 DCHECK(!receiver.is(scratch)); 80 DCHECK(!value().is(scratch)); 81 // Call the JavaScript setter with receiver and value on the stack. 82 if (map->IsJSGlobalObjectMap()) { 83 // Swap in the global receiver. 84 __ LoadP(scratch, 85 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); 86 receiver = scratch; 87 } 88 __ Push(receiver, value()); 89 __ LoadAccessor(r4, holder, accessor_index, ACCESSOR_SETTER); 90 __ li(r3, Operand(1)); 91 __ Call(masm->isolate()->builtins()->CallFunction( 92 ConvertReceiverMode::kNotNullOrUndefined), 93 RelocInfo::CODE_TARGET); 94 } 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. 101 // Restore context register. 102 __ Pop(cp, r3); 103 } 104 __ Ret(); 105} 106 107 108void 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 128void 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)); 151 __ cmpi(scratch0, Operand(FIRST_JS_RECEIVER_TYPE)); 152 __ 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( 176 MacroAssembler* masm, int index, Register result, Label* miss) { 177 __ LoadNativeContextSlot(index, result); 178 // Load its initial map. The global functions all have initial maps. 179 __ LoadP(result, 180 FieldMemOperand(result, JSFunction::kPrototypeOrInitialMapOffset)); 181 // Load the prototype from the initial map. 182 __ LoadP(result, FieldMemOperand(result, Map::kPrototypeOffset)); 183} 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) { 201 Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name); 202 Isolate* isolate = masm->isolate(); 203 DCHECK(cell->value()->IsTheHole(isolate)); 204 Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell); 205 __ LoadWeakValue(scratch, weak_cell, miss); 206 __ LoadP(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset)); 207 __ 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); 217 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); 218 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); 219 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); 220 __ push(name); 221 __ push(receiver); 222 __ push(holder); 223} 224 225 226static void CompileCallLoadPropertyWithInterceptor( 227 MacroAssembler* masm, Register receiver, Register holder, Register name, 228 Handle<JSObject> holder_obj, Runtime::FunctionId id) { 229 DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == 230 Runtime::FunctionForId(id)->nargs); 231 PushInterceptorArguments(masm, receiver, holder, name, holder_obj); 232 __ CallRuntime(id); 233} 234 235 236// Generate call to api function. 237void PropertyHandlerCompiler::GenerateApiAccessorCall( 238 MacroAssembler* masm, const CallOptimization& optimization, 239 Handle<Map> receiver_map, Register receiver, Register scratch_in, 240 bool is_store, Register store_parameter, Register accessor_holder, 241 int accessor_index) { 242 DCHECK(!accessor_holder.is(scratch_in)); 243 DCHECK(!receiver.is(scratch_in)); 244 __ push(receiver); 245 // Write the arguments to stack frame. 246 if (is_store) { 247 DCHECK(!receiver.is(store_parameter)); 248 DCHECK(!scratch_in.is(store_parameter)); 249 __ push(store_parameter); 250 } 251 DCHECK(optimization.is_simple_api_call()); 252 253 // Abi for CallApiCallbackStub. 254 Register callee = r3; 255 Register data = r7; 256 Register holder = r5; 257 Register api_function_address = r4; 258 259 // Put callee in place. 260 __ LoadAccessor(callee, accessor_holder, accessor_index, 261 is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER); 262 263 // Put holder in place. 264 CallOptimization::HolderLookup holder_lookup; 265 int holder_depth = 0; 266 optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup, 267 &holder_depth); 268 switch (holder_lookup) { 269 case CallOptimization::kHolderIsReceiver: 270 __ Move(holder, receiver); 271 break; 272 case CallOptimization::kHolderFound: 273 __ 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 } 279 break; 280 case CallOptimization::kHolderNotFound: 281 UNREACHABLE(); 282 break; 283 } 284 285 Isolate* isolate = masm->isolate(); 286 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); 287 bool call_data_undefined = false; 288 // Put call data in place. 289 if (api_call_info->data()->IsUndefined(isolate)) { 290 call_data_undefined = true; 291 __ LoadRoot(data, Heap::kUndefinedValueRootIndex); 292 } else { 293 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 } 304 __ 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; 312 } 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. 322 CallApiCallbackStub stub(isolate, is_store, call_data_undefined, 323 !optimization.is_constant_call()); 324 __ TailCallStub(&stub); 325} 326 327 328static void StoreIC_PushArgs(MacroAssembler* masm) { 329 __ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(), 330 StoreDescriptor::ValueRegister(), 331 VectorStoreICDescriptor::SlotRegister(), 332 VectorStoreICDescriptor::VectorRegister()); 333} 334 335 336void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) { 337 StoreIC_PushArgs(masm); 338 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. 341 __ TailCallRuntime(Runtime::kStoreIC_Slow); 342} 343 344 345void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) { 346 StoreIC_PushArgs(masm); 347 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. 350 __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow); 351} 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 367void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) { 368 __ mov(this->name(), Operand(name)); 369} 370 371 372void 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, 395 Register value_reg, 396 Register scratch, 397 Label* miss_label) { 398 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); 405 __ bne(miss_label); 406} 407 408void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type, 409 Register value_reg, 410 Label* miss_label) { 411 Register map_reg = scratch1(); 412 Register scratch = scratch2(); 413 DCHECK(!value_reg.is(map_reg)); 414 DCHECK(!value_reg.is(scratch)); 415 __ JumpIfSmi(value_reg, miss_label); 416 if (field_type->IsClass()) { 417 __ LoadP(map_reg, FieldMemOperand(value_reg, HeapObject::kMapOffset)); 418 __ CmpWeakValue(map_reg, Map::WeakCellForMap(field_type->AsClass()), 419 scratch); 420 __ bne(miss_label); 421 } 422} 423 424 425Register PropertyHandlerCompiler::CheckPrototypes( 426 Register object_reg, Register holder_reg, Register scratch1, 427 Register scratch2, Handle<Name> name, Label* miss, PrototypeCheckType check, 428 ReturnHolder return_what) { 429 Handle<Map> receiver_map = map(); 430 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 436 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 } 445 446 // 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); 455 } 456 457 // 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(); 462 if (receiver_map->IsJSGlobalObjectMap()) { 463 current = isolate()->global_object(); 464 } 465 // 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 475 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())); 489 if (current_map->IsJSGlobalObjectMap()) { 490 GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), 491 name, scratch2, miss); 492 } else if (current_map->is_dictionary_map()) { 493 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 502 if (depth > 1) { 503 // TODO(jkummerow): Cache and re-use weak cell. 504 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); 505 } 506 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, 507 scratch2); 508 } 509 510 reg = holder_reg; // From now on the object will be in holder_reg. 511 // Go to the next object in the prototype chain. 512 current = prototype; 513 current_map = handle(current->map()); 514 } 515 516 DCHECK(!current_map->IsJSGlobalProxyMap()); 517 518 // Log the check depth. 519 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); 520 521 bool return_holder = return_what == RETURN_HOLDER; 522 if (return_holder && depth != 0) { 523 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); 524 } 525 526 // Return the register containing the holder. 527 return return_holder ? reg : no_reg; 528} 529 530 531void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { 532 if (!miss->is_unused()) { 533 Label success; 534 __ b(&success); 535 __ bind(miss); 536 if (IC::ICUseVector(kind())) { 537 DCHECK(kind() == Code::LOAD_IC); 538 PopVectorAndSlot(); 539 } 540 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); 551 if (IC::ICUseVector(kind())) PopVectorAndSlot(); 552 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 565void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( 566 LookupIterator* it, Register holder_reg) { 567 DCHECK(holder()->HasNamedInterceptor()); 568 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); 569 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 } 594 InterceptorVectorSlotPush(holder_reg); 595 // 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(), 600 Runtime::kLoadPropertyWithInterceptorOnly); 601 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); 612 InterceptorVectorSlotPop(holder_reg); 613 __ 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()); 628 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); 629 PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(), 630 holder()); 631 632 __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); 633} 634 635 636Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback( 637 Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback, 638 LanguageMode language_mode) { 639 Register holder_reg = Frontend(name); 640 641 __ Push(receiver(), holder_reg); // receiver 642 643 // If the callback cannot leak, then push the callback directly, 644 // otherwise wrap it in a weak cell. 645 if (callback->data()->IsUndefined(isolate()) || callback->data()->IsSmi()) { 646 __ mov(ip, Operand(callback)); 647 } else { 648 Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback); 649 __ mov(ip, Operand(cell)); 650 } 651 __ push(ip); 652 __ mov(ip, Operand(name)); 653 __ Push(ip, value()); 654 __ Push(Smi::FromInt(language_mode)); 655 656 // Do tail-call to the runtime system. 657 __ TailCallRuntime(Runtime::kStoreCallbackProperty); 658 659 // Return the generated code. 660 return GetCode(kind(), name); 661} 662 663 664Register 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; 672 if (IC::ICUseVector(kind())) { 673 PushVectorAndSlot(); 674 } 675 FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); 676 677 // Get the value from the cell. 678 Register result = StoreDescriptor::ValueRegister(); 679 Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell); 680 __ LoadWeakValue(result, weak_cell, &miss); 681 __ LoadP(result, FieldMemOperand(result, PropertyCell::kValueOffset)); 682 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(); 691 __ IncrementCounter(counters->ic_named_load_global_stub(), 1, r4, r6); 692 if (IC::ICUseVector(kind())) { 693 DiscardVectorAndSlot(); 694 } 695 __ Ret(); 696 697 FrontendFooter(name, &miss); 698 699 // Return the generated code. 700 return GetCode(kind(), name); 701} 702 703 704#undef __ 705} // namespace internal 706} // namespace v8 707 708#endif // V8_TARGET_ARCH_ARM 709