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