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 15 namespace v8 { 16 namespace internal { 17 18 #define __ ACCESS_MASM(masm) 19 20 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 // -- 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 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 // -- 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 108 void PropertyHandlerCompiler::PushVectorAndSlot(Register vector, 109 Register slot) { 110 MacroAssembler* masm = this->masm(); 111 STATIC_ASSERT(LoadWithVectorDescriptor::kSlot < 112 LoadWithVectorDescriptor::kVector); 113 STATIC_ASSERT(StoreWithVectorDescriptor::kSlot < 114 StoreWithVectorDescriptor::kVector); 115 STATIC_ASSERT(StoreTransitionDescriptor::kSlot < 116 StoreTransitionDescriptor::kVector); 117 __ Push(slot, vector); 118 } 119 120 121 void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) { 122 MacroAssembler* masm = this->masm(); 123 __ Pop(slot, vector); 124 } 125 126 127 void PropertyHandlerCompiler::DiscardVectorAndSlot() { 128 MacroAssembler* masm = this->masm(); 129 // Remove vector and slot. 130 __ addi(sp, sp, Operand(2 * kPointerSize)); 131 } 132 133 void 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 __ LoadP(map, FieldMemOperand(receiver, HeapObject::kMapOffset)); 150 __ lbz(scratch0, FieldMemOperand(map, Map::kBitFieldOffset)); 151 __ andi(r0, scratch0, Operand(kInterceptorOrAccessCheckNeededMask)); 152 __ bne(miss_label, cr0); 153 154 // Check that receiver is a JSObject. 155 __ lbz(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset)); 156 __ cmpi(scratch0, Operand(FIRST_JS_RECEIVER_TYPE)); 157 __ blt(miss_label); 158 159 // Load properties array. 160 Register properties = scratch0; 161 __ LoadP(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); 162 // Check that the properties array is a dictionary. 163 __ LoadP(map, FieldMemOperand(properties, HeapObject::kMapOffset)); 164 Register tmp = properties; 165 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex); 166 __ cmp(map, tmp); 167 __ bne(miss_label); 168 169 // Restore the temporarily used register. 170 __ LoadP(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 // Generate code to check that a global property cell is empty. Create 180 // the property cell at compilation time if no cell exists for the 181 // property. 182 void PropertyHandlerCompiler::GenerateCheckPropertyCell( 183 MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name, 184 Register scratch, Label* miss) { 185 Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell( 186 global, name, PropertyCellType::kInvalidated); 187 Isolate* isolate = masm->isolate(); 188 DCHECK(cell->value()->IsTheHole(isolate)); 189 Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell); 190 __ LoadWeakValue(scratch, weak_cell, miss); 191 __ LoadP(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset)); 192 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); 193 __ cmp(scratch, ip); 194 __ bne(miss); 195 } 196 197 198 static void CompileCallLoadPropertyWithInterceptor( 199 MacroAssembler* masm, Register receiver, Register holder, Register name, 200 Handle<JSObject> holder_obj, Runtime::FunctionId id) { 201 DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == 202 Runtime::FunctionForId(id)->nargs); 203 204 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); 205 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); 206 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); 207 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); 208 __ Push(name, receiver, holder); 209 210 __ CallRuntime(id); 211 } 212 213 214 // Generate call to api function. 215 void PropertyHandlerCompiler::GenerateApiAccessorCall( 216 MacroAssembler* masm, const CallOptimization& optimization, 217 Handle<Map> receiver_map, Register receiver, Register scratch_in, 218 bool is_store, Register store_parameter, Register accessor_holder, 219 int accessor_index) { 220 DCHECK(!accessor_holder.is(scratch_in)); 221 DCHECK(!receiver.is(scratch_in)); 222 __ push(receiver); 223 // Write the arguments to stack frame. 224 if (is_store) { 225 DCHECK(!receiver.is(store_parameter)); 226 DCHECK(!scratch_in.is(store_parameter)); 227 __ push(store_parameter); 228 } 229 DCHECK(optimization.is_simple_api_call()); 230 231 // Abi for CallApiCallbackStub. 232 Register callee = r3; 233 Register data = r7; 234 Register holder = r5; 235 Register api_function_address = r4; 236 237 // Put callee in place. 238 __ LoadAccessor(callee, accessor_holder, accessor_index, 239 is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER); 240 241 // Put holder in place. 242 CallOptimization::HolderLookup holder_lookup; 243 int holder_depth = 0; 244 optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup, 245 &holder_depth); 246 switch (holder_lookup) { 247 case CallOptimization::kHolderIsReceiver: 248 __ Move(holder, receiver); 249 break; 250 case CallOptimization::kHolderFound: 251 __ LoadP(holder, FieldMemOperand(receiver, HeapObject::kMapOffset)); 252 __ LoadP(holder, FieldMemOperand(holder, Map::kPrototypeOffset)); 253 for (int i = 1; i < holder_depth; i++) { 254 __ LoadP(holder, FieldMemOperand(holder, HeapObject::kMapOffset)); 255 __ LoadP(holder, FieldMemOperand(holder, Map::kPrototypeOffset)); 256 } 257 break; 258 case CallOptimization::kHolderNotFound: 259 UNREACHABLE(); 260 break; 261 } 262 263 Isolate* isolate = masm->isolate(); 264 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); 265 bool call_data_undefined = false; 266 // Put call data in place. 267 if (api_call_info->data()->IsUndefined(isolate)) { 268 call_data_undefined = true; 269 __ LoadRoot(data, Heap::kUndefinedValueRootIndex); 270 } else { 271 if (optimization.is_constant_call()) { 272 __ LoadP(data, 273 FieldMemOperand(callee, JSFunction::kSharedFunctionInfoOffset)); 274 __ LoadP(data, 275 FieldMemOperand(data, SharedFunctionInfo::kFunctionDataOffset)); 276 __ LoadP(data, 277 FieldMemOperand(data, FunctionTemplateInfo::kCallCodeOffset)); 278 } else { 279 __ LoadP(data, 280 FieldMemOperand(callee, FunctionTemplateInfo::kCallCodeOffset)); 281 } 282 __ LoadP(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset)); 283 } 284 285 if (api_call_info->fast_handler()->IsCode()) { 286 // Just tail call into the fast handler if present. 287 __ Jump(handle(Code::cast(api_call_info->fast_handler())), 288 RelocInfo::CODE_TARGET); 289 return; 290 } 291 292 // Put api_function_address in place. 293 Address function_address = v8::ToCData<Address>(api_call_info->callback()); 294 ApiFunction fun(function_address); 295 ExternalReference::Type type = ExternalReference::DIRECT_API_CALL; 296 ExternalReference ref = ExternalReference(&fun, type, masm->isolate()); 297 __ mov(api_function_address, Operand(ref)); 298 299 // Jump to stub. 300 CallApiCallbackStub stub(isolate, is_store, call_data_undefined, 301 !optimization.is_constant_call()); 302 __ TailCallStub(&stub); 303 } 304 305 #undef __ 306 #define __ ACCESS_MASM(masm()) 307 308 309 void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label, 310 Handle<Name> name) { 311 if (!label->is_unused()) { 312 __ bind(label); 313 __ mov(this->name(), Operand(name)); 314 } 315 } 316 317 void PropertyHandlerCompiler::GenerateAccessCheck( 318 Handle<WeakCell> native_context_cell, Register scratch1, Register scratch2, 319 Label* miss, bool compare_native_contexts_only) { 320 Label done; 321 // Load current native context. 322 __ LoadP(scratch1, NativeContextMemOperand()); 323 // Load expected native context. 324 __ LoadWeakValue(scratch2, native_context_cell, miss); 325 __ cmp(scratch1, scratch2); 326 327 if (!compare_native_contexts_only) { 328 __ beq(&done); 329 330 // Compare security tokens of current and expected native contexts. 331 __ LoadP(scratch1, 332 ContextMemOperand(scratch1, Context::SECURITY_TOKEN_INDEX)); 333 __ LoadP(scratch2, 334 ContextMemOperand(scratch2, Context::SECURITY_TOKEN_INDEX)); 335 __ cmp(scratch1, scratch2); 336 } 337 __ bne(miss); 338 339 __ bind(&done); 340 } 341 342 Register PropertyHandlerCompiler::CheckPrototypes( 343 Register object_reg, Register holder_reg, Register scratch1, 344 Register scratch2, Handle<Name> name, Label* miss, 345 ReturnHolder return_what) { 346 Handle<Map> receiver_map = map(); 347 348 // Make sure there's no overlap between holder and object registers. 349 DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); 350 DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && 351 !scratch2.is(scratch1)); 352 353 Handle<Cell> validity_cell = 354 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); 355 if (!validity_cell.is_null()) { 356 DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), validity_cell->value()); 357 __ mov(scratch1, Operand(validity_cell)); 358 __ LoadP(scratch1, FieldMemOperand(scratch1, Cell::kValueOffset)); 359 __ CmpSmiLiteral(scratch1, Smi::FromInt(Map::kPrototypeChainValid), r0); 360 __ bne(miss); 361 } 362 363 // Keep track of the current object in register reg. 364 Register reg = object_reg; 365 int depth = 0; 366 367 Handle<JSObject> current = Handle<JSObject>::null(); 368 if (receiver_map->IsJSGlobalObjectMap()) { 369 current = isolate()->global_object(); 370 } 371 372 Handle<Map> current_map(receiver_map->GetPrototypeChainRootMap(isolate()), 373 isolate()); 374 Handle<Map> holder_map(holder()->map()); 375 // Traverse the prototype chain and check the maps in the prototype chain for 376 // fast and global objects or do negative lookup for normal objects. 377 while (!current_map.is_identical_to(holder_map)) { 378 ++depth; 379 380 // Only global objects and objects that do not require access 381 // checks are allowed in stubs. 382 DCHECK(current_map->IsJSGlobalProxyMap() || 383 !current_map->is_access_check_needed()); 384 385 if (current_map->IsJSGlobalObjectMap()) { 386 GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), 387 name, scratch2, miss); 388 } else if (current_map->is_dictionary_map()) { 389 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast. 390 DCHECK(name->IsUniqueName()); 391 DCHECK(current.is_null() || 392 current->property_dictionary()->FindEntry(name) == 393 NameDictionary::kNotFound); 394 395 if (depth > 1) { 396 Handle<WeakCell> weak_cell = 397 Map::GetOrCreatePrototypeWeakCell(current, isolate()); 398 __ LoadWeakValue(reg, weak_cell, miss); 399 } 400 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, 401 scratch2); 402 } 403 404 reg = holder_reg; // From now on the object will be in holder_reg. 405 // Go to the next object in the prototype chain. 406 current = handle(JSObject::cast(current_map->prototype())); 407 current_map = handle(current->map()); 408 } 409 410 DCHECK(!current_map->IsJSGlobalProxyMap()); 411 412 // Log the check depth. 413 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); 414 415 bool return_holder = return_what == RETURN_HOLDER; 416 if (return_holder && depth != 0) { 417 Handle<WeakCell> weak_cell = 418 Map::GetOrCreatePrototypeWeakCell(current, isolate()); 419 __ LoadWeakValue(reg, weak_cell, miss); 420 } 421 422 // Return the register containing the holder. 423 return return_holder ? reg : no_reg; 424 } 425 426 427 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { 428 if (!miss->is_unused()) { 429 Label success; 430 __ b(&success); 431 __ bind(miss); 432 if (IC::ICUseVector(kind())) { 433 DCHECK(kind() == Code::LOAD_IC); 434 PopVectorAndSlot(); 435 } 436 TailCallBuiltin(masm(), MissBuiltin(kind())); 437 __ bind(&success); 438 } 439 } 440 441 442 void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { 443 if (!miss->is_unused()) { 444 Label success; 445 __ b(&success); 446 GenerateRestoreName(miss, name); 447 if (IC::ICUseVector(kind())) PopVectorAndSlot(); 448 TailCallBuiltin(masm(), MissBuiltin(kind())); 449 __ bind(&success); 450 } 451 } 452 453 void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( 454 LookupIterator* it, Register holder_reg) { 455 DCHECK(holder()->HasNamedInterceptor()); 456 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); 457 458 // Compile the interceptor call, followed by inline code to load the 459 // property from further up the prototype chain if the call fails. 460 // Check that the maps haven't changed. 461 DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); 462 463 // Preserve the receiver register explicitly whenever it is different from the 464 // holder and it is needed should the interceptor return without any result. 465 // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD 466 // case might cause a miss during the prototype check. 467 bool must_perform_prototype_check = 468 !holder().is_identical_to(it->GetHolder<JSObject>()); 469 bool must_preserve_receiver_reg = 470 !receiver().is(holder_reg) && 471 (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check); 472 473 // Save necessary data before invoking an interceptor. 474 // Requires a frame to make GC aware of pushed pointers. 475 { 476 FrameAndConstantPoolScope frame_scope(masm(), StackFrame::INTERNAL); 477 if (must_preserve_receiver_reg) { 478 __ Push(receiver(), holder_reg, this->name()); 479 } else { 480 __ Push(holder_reg, this->name()); 481 } 482 InterceptorVectorSlotPush(holder_reg); 483 // Invoke an interceptor. Note: map checks from receiver to 484 // interceptor's holder has been compiled before (see a caller 485 // of this method.) 486 CompileCallLoadPropertyWithInterceptor( 487 masm(), receiver(), holder_reg, this->name(), holder(), 488 Runtime::kLoadPropertyWithInterceptorOnly); 489 490 // Check if interceptor provided a value for property. If it's 491 // the case, return immediately. 492 Label interceptor_failed; 493 __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex); 494 __ cmp(r3, scratch1()); 495 __ beq(&interceptor_failed); 496 frame_scope.GenerateLeaveFrame(); 497 __ Ret(); 498 499 __ bind(&interceptor_failed); 500 InterceptorVectorSlotPop(holder_reg); 501 __ pop(this->name()); 502 __ pop(holder_reg); 503 if (must_preserve_receiver_reg) { 504 __ pop(receiver()); 505 } 506 // Leave the internal frame. 507 } 508 509 GenerateLoadPostInterceptor(it, holder_reg); 510 } 511 512 513 void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { 514 // Call the runtime system to load the interceptor. 515 DCHECK(holder()->HasNamedInterceptor()); 516 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); 517 518 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); 519 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); 520 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); 521 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); 522 __ Push(name(), receiver(), holder_reg); 523 // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. 524 if (holder_reg.is(receiver())) { 525 __ Push(slot(), vector()); 526 } else { 527 __ Push(scratch3(), scratch2()); // slot, vector 528 } 529 530 __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); 531 } 532 533 void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { 534 STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack); 535 } 536 537 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback( 538 Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback, 539 LanguageMode language_mode) { 540 Register holder_reg = Frontend(name); 541 542 __ Push(receiver(), holder_reg); // receiver 543 544 // If the callback cannot leak, then push the callback directly, 545 // otherwise wrap it in a weak cell. 546 if (callback->data()->IsUndefined(isolate()) || callback->data()->IsSmi()) { 547 __ mov(ip, Operand(callback)); 548 } else { 549 Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback); 550 __ mov(ip, Operand(cell)); 551 } 552 __ push(ip); 553 __ mov(ip, Operand(name)); 554 __ Push(ip, value()); 555 __ Push(Smi::FromInt(language_mode)); 556 557 // Do tail-call to the runtime system. 558 __ TailCallRuntime(Runtime::kStoreCallbackProperty); 559 560 // Return the generated code. 561 return GetCode(kind(), name); 562 } 563 564 565 Register NamedStoreHandlerCompiler::value() { 566 return StoreDescriptor::ValueRegister(); 567 } 568 569 570 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( 571 Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { 572 Label miss; 573 if (IC::ICUseVector(kind())) { 574 PushVectorAndSlot(); 575 } 576 FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); 577 578 // Get the value from the cell. 579 Register result = StoreDescriptor::ValueRegister(); 580 Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell); 581 __ LoadWeakValue(result, weak_cell, &miss); 582 __ LoadP(result, FieldMemOperand(result, PropertyCell::kValueOffset)); 583 584 // Check for deleted property if property can actually be deleted. 585 if (is_configurable) { 586 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); 587 __ cmp(result, ip); 588 __ beq(&miss); 589 } 590 591 Counters* counters = isolate()->counters(); 592 __ IncrementCounter(counters->ic_named_load_global_stub(), 1, r4, r6); 593 if (IC::ICUseVector(kind())) { 594 DiscardVectorAndSlot(); 595 } 596 __ Ret(); 597 598 FrontendFooter(name, &miss); 599 600 // Return the generated code. 601 return GetCode(kind(), name); 602 } 603 604 605 #undef __ 606 } // namespace internal 607 } // namespace v8 608 609 #endif // V8_TARGET_ARCH_ARM 610