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