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