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