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