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