handler-compiler-ia32.cc revision f91f0611dbaf29ca0f1d4aecb357ce243a19d2fa
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_IA32 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::EnsureEmptyPropertyCell( 240 global, name, PropertyCellType::kInvalidated); 241 Isolate* isolate = masm->isolate(); 242 DCHECK(cell->value()->IsTheHole(isolate)); 243 Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell); 244 __ LoadWeakValue(scratch, weak_cell, miss); 245 __ cmp(FieldOperand(scratch, PropertyCell::kValueOffset), 246 Immediate(isolate->factory()->the_hole_value())); 247 __ j(not_equal, miss); 248} 249 250 251void NamedStoreHandlerCompiler::GenerateStoreViaSetter( 252 MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder, 253 int accessor_index, int expected_arguments, Register scratch) { 254 // ----------- S t a t e ------------- 255 // -- esp[0] : return address 256 // ----------------------------------- 257 { 258 FrameScope scope(masm, StackFrame::INTERNAL); 259 260 // Save context register 261 __ push(esi); 262 // Save value register, so we can restore it later. 263 __ push(value()); 264 265 if (accessor_index >= 0) { 266 DCHECK(!holder.is(scratch)); 267 DCHECK(!receiver.is(scratch)); 268 DCHECK(!value().is(scratch)); 269 // Call the JavaScript setter with receiver and value on the stack. 270 if (map->IsJSGlobalObjectMap()) { 271 __ mov(scratch, 272 FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); 273 receiver = scratch; 274 } 275 __ push(receiver); 276 __ push(value()); 277 __ LoadAccessor(edi, holder, accessor_index, ACCESSOR_SETTER); 278 __ Set(eax, 1); 279 __ Call(masm->isolate()->builtins()->CallFunction( 280 ConvertReceiverMode::kNotNullOrUndefined), 281 RelocInfo::CODE_TARGET); 282 } else { 283 // If we generate a global code snippet for deoptimization only, remember 284 // the place to continue after deoptimization. 285 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset()); 286 } 287 288 // We have to return the passed value, not the return value of the setter. 289 __ pop(eax); 290 // Restore context register. 291 __ pop(esi); 292 } 293 __ ret(0); 294} 295 296 297static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, 298 Register holder, Register name, 299 Handle<JSObject> holder_obj) { 300 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); 301 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); 302 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); 303 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); 304 __ push(name); 305 __ push(receiver); 306 __ push(holder); 307} 308 309 310static void CompileCallLoadPropertyWithInterceptor( 311 MacroAssembler* masm, Register receiver, Register holder, Register name, 312 Handle<JSObject> holder_obj, Runtime::FunctionId id) { 313 DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == 314 Runtime::FunctionForId(id)->nargs); 315 PushInterceptorArguments(masm, receiver, holder, name, holder_obj); 316 __ CallRuntime(id); 317} 318 319 320static void StoreIC_PushArgs(MacroAssembler* masm) { 321 Register receiver = StoreDescriptor::ReceiverRegister(); 322 Register name = StoreDescriptor::NameRegister(); 323 Register value = StoreDescriptor::ValueRegister(); 324 Register slot = StoreWithVectorDescriptor::SlotRegister(); 325 Register vector = StoreWithVectorDescriptor::VectorRegister(); 326 327 __ xchg(receiver, Operand(esp, 0)); 328 __ push(name); 329 __ push(value); 330 __ push(slot); 331 __ push(vector); 332 __ push(receiver); // which contains the return address. 333} 334 335 336void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) { 337 // Return address is on the stack. 338 StoreIC_PushArgs(masm); 339 340 // Do tail-call to runtime routine. 341 __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow); 342} 343 344 345#undef __ 346#define __ ACCESS_MASM(masm()) 347 348 349void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label, 350 Handle<Name> name) { 351 if (!label->is_unused()) { 352 __ bind(label); 353 __ mov(this->name(), Immediate(name)); 354 } 355} 356 357 358void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) { 359 __ mov(this->name(), Immediate(name)); 360} 361 362 363void NamedStoreHandlerCompiler::RearrangeVectorAndSlot( 364 Register current_map, Register destination_map) { 365 DCHECK(destination_map.is(StoreTransitionHelper::MapRegister())); 366 DCHECK(current_map.is(StoreTransitionHelper::VectorRegister())); 367 ExternalReference virtual_slot = 368 ExternalReference::virtual_slot_register(isolate()); 369 __ mov(destination_map, current_map); 370 __ pop(current_map); 371 __ mov(Operand::StaticVariable(virtual_slot), current_map); 372 __ pop(current_map); // put vector in place. 373} 374 375 376void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition, 377 Register map_reg, 378 Register scratch, 379 Label* miss) { 380 Handle<WeakCell> cell = Map::WeakCellForMap(transition); 381 DCHECK(!map_reg.is(scratch)); 382 __ LoadWeakValue(map_reg, cell, miss); 383 if (transition->CanBeDeprecated()) { 384 __ mov(scratch, FieldOperand(map_reg, Map::kBitField3Offset)); 385 __ and_(scratch, Immediate(Map::Deprecated::kMask)); 386 __ j(not_zero, miss); 387 } 388} 389 390 391void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg, 392 int descriptor, 393 Register value_reg, 394 Register scratch, 395 Label* miss_label) { 396 DCHECK(!map_reg.is(scratch)); 397 DCHECK(!map_reg.is(value_reg)); 398 DCHECK(!value_reg.is(scratch)); 399 __ LoadInstanceDescriptors(map_reg, scratch); 400 __ mov(scratch, 401 FieldOperand(scratch, DescriptorArray::GetValueOffset(descriptor))); 402 __ cmp(value_reg, scratch); 403 __ j(not_equal, miss_label); 404} 405 406void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type, 407 Register value_reg, 408 Label* miss_label) { 409 Register map_reg = scratch1(); 410 Register scratch = scratch2(); 411 DCHECK(!value_reg.is(map_reg)); 412 DCHECK(!value_reg.is(scratch)); 413 __ JumpIfSmi(value_reg, miss_label); 414 if (field_type->IsClass()) { 415 __ mov(map_reg, FieldOperand(value_reg, HeapObject::kMapOffset)); 416 __ CmpWeakValue(map_reg, Map::WeakCellForMap(field_type->AsClass()), 417 scratch); 418 __ j(not_equal, miss_label); 419 } 420} 421 422 423Register PropertyHandlerCompiler::CheckPrototypes( 424 Register object_reg, Register holder_reg, Register scratch1, 425 Register scratch2, Handle<Name> name, Label* miss, PrototypeCheckType check, 426 ReturnHolder return_what) { 427 Handle<Map> receiver_map = map(); 428 429 // Make sure there's no overlap between holder and object registers. 430 DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); 431 DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && 432 !scratch2.is(scratch1)); 433 434 Handle<Cell> validity_cell = 435 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); 436 if (!validity_cell.is_null()) { 437 DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), validity_cell->value()); 438 // Operand::ForCell(...) points to the cell's payload! 439 __ cmp(Operand::ForCell(validity_cell), 440 Immediate(Smi::FromInt(Map::kPrototypeChainValid))); 441 __ j(not_equal, miss); 442 } 443 444 // The prototype chain of primitives (and their JSValue wrappers) depends 445 // on the native context, which can't be guarded by validity cells. 446 // |object_reg| holds the native context specific prototype in this case; 447 // we need to check its map. 448 if (check == CHECK_ALL_MAPS) { 449 __ mov(scratch1, FieldOperand(object_reg, HeapObject::kMapOffset)); 450 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map); 451 __ CmpWeakValue(scratch1, cell, scratch2); 452 __ j(not_equal, miss); 453 } 454 455 // Keep track of the current object in register reg. 456 Register reg = object_reg; 457 int depth = 0; 458 459 Handle<JSObject> current = Handle<JSObject>::null(); 460 if (receiver_map->IsJSGlobalObjectMap()) { 461 current = isolate()->global_object(); 462 } 463 464 // Check access rights to the global object. This has to happen after 465 // the map check so that we know that the object is actually a global 466 // object. 467 // This allows us to install generated handlers for accesses to the 468 // global proxy (as opposed to using slow ICs). See corresponding code 469 // in LookupForRead(). 470 if (receiver_map->IsJSGlobalProxyMap()) { 471 __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss); 472 } 473 474 Handle<JSObject> prototype = Handle<JSObject>::null(); 475 Handle<Map> current_map = receiver_map; 476 Handle<Map> holder_map(holder()->map()); 477 // Traverse the prototype chain and check the maps in the prototype chain for 478 // fast and global objects or do negative lookup for normal objects. 479 while (!current_map.is_identical_to(holder_map)) { 480 ++depth; 481 482 // Only global objects and objects that do not require access 483 // checks are allowed in stubs. 484 DCHECK(current_map->IsJSGlobalProxyMap() || 485 !current_map->is_access_check_needed()); 486 487 prototype = handle(JSObject::cast(current_map->prototype())); 488 if (current_map->IsJSGlobalObjectMap()) { 489 GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), 490 name, scratch2, miss); 491 } else if (current_map->is_dictionary_map()) { 492 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast. 493 if (!name->IsUniqueName()) { 494 DCHECK(name->IsString()); 495 name = factory()->InternalizeString(Handle<String>::cast(name)); 496 } 497 DCHECK(current.is_null() || 498 current->property_dictionary()->FindEntry(name) == 499 NameDictionary::kNotFound); 500 501 if (depth > 1) { 502 // TODO(jkummerow): Cache and re-use weak cell. 503 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); 504 } 505 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, 506 scratch2); 507 } 508 509 reg = holder_reg; // From now on the object will be in holder_reg. 510 // Go to the next object in the prototype chain. 511 current = prototype; 512 current_map = handle(current->map()); 513 } 514 515 DCHECK(!current_map->IsJSGlobalProxyMap()); 516 517 // Log the check depth. 518 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); 519 520 bool return_holder = return_what == RETURN_HOLDER; 521 if (return_holder && depth != 0) { 522 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); 523 } 524 525 // Return the register containing the holder. 526 return return_holder ? reg : no_reg; 527} 528 529 530void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { 531 if (!miss->is_unused()) { 532 Label success; 533 __ jmp(&success); 534 __ bind(miss); 535 if (IC::ICUseVector(kind())) { 536 DCHECK(kind() == Code::LOAD_IC); 537 PopVectorAndSlot(); 538 } 539 TailCallBuiltin(masm(), MissBuiltin(kind())); 540 __ bind(&success); 541 } 542} 543 544 545void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { 546 if (!miss->is_unused()) { 547 Label success; 548 __ jmp(&success); 549 GenerateRestoreName(miss, name); 550 if (IC::ICUseVector(kind())) PopVectorAndSlot(); 551 TailCallBuiltin(masm(), MissBuiltin(kind())); 552 __ bind(&success); 553 } 554} 555 556 557void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) { 558 // Return the constant value. 559 __ LoadObject(eax, value); 560 __ ret(0); 561} 562 563 564void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( 565 LookupIterator* it, Register holder_reg) { 566 DCHECK(holder()->HasNamedInterceptor()); 567 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); 568 569 // Compile the interceptor call, followed by inline code to load the 570 // property from further up the prototype chain if the call fails. 571 // Check that the maps haven't changed. 572 DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); 573 574 // Preserve the receiver register explicitly whenever it is different from the 575 // holder and it is needed should the interceptor return without any result. 576 // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD 577 // case might cause a miss during the prototype check. 578 bool must_perform_prototype_check = 579 !holder().is_identical_to(it->GetHolder<JSObject>()); 580 bool must_preserve_receiver_reg = 581 !receiver().is(holder_reg) && 582 (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check); 583 584 // Save necessary data before invoking an interceptor. 585 // Requires a frame to make GC aware of pushed pointers. 586 { 587 FrameScope frame_scope(masm(), StackFrame::INTERNAL); 588 589 if (must_preserve_receiver_reg) { 590 __ push(receiver()); 591 } 592 __ push(holder_reg); 593 __ push(this->name()); 594 InterceptorVectorSlotPush(holder_reg); 595 // Invoke an interceptor. Note: map checks from receiver to 596 // interceptor's holder has been compiled before (see a caller 597 // of this method.) 598 CompileCallLoadPropertyWithInterceptor( 599 masm(), receiver(), holder_reg, this->name(), holder(), 600 Runtime::kLoadPropertyWithInterceptorOnly); 601 602 // Check if interceptor provided a value for property. If it's 603 // the case, return immediately. 604 Label interceptor_failed; 605 __ cmp(eax, factory()->no_interceptor_result_sentinel()); 606 __ j(equal, &interceptor_failed); 607 frame_scope.GenerateLeaveFrame(); 608 __ ret(0); 609 610 // Clobber registers when generating debug-code to provoke errors. 611 __ bind(&interceptor_failed); 612 if (FLAG_debug_code) { 613 __ mov(receiver(), Immediate(bit_cast<int32_t>(kZapValue))); 614 __ mov(holder_reg, Immediate(bit_cast<int32_t>(kZapValue))); 615 __ mov(this->name(), Immediate(bit_cast<int32_t>(kZapValue))); 616 } 617 618 InterceptorVectorSlotPop(holder_reg); 619 __ pop(this->name()); 620 __ pop(holder_reg); 621 if (must_preserve_receiver_reg) { 622 __ pop(receiver()); 623 } 624 625 // Leave the internal frame. 626 } 627 628 GenerateLoadPostInterceptor(it, holder_reg); 629} 630 631 632void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { 633 DCHECK(holder()->HasNamedInterceptor()); 634 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); 635 // Call the runtime system to load the interceptor. 636 __ pop(scratch2()); // save old return address 637 PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(), 638 holder()); 639 __ push(scratch2()); // restore old return address 640 641 __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); 642} 643 644 645Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback( 646 Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback, 647 LanguageMode language_mode) { 648 Register holder_reg = Frontend(name); 649 650 __ pop(scratch1()); // remove the return address 651 __ push(receiver()); 652 __ push(holder_reg); 653 // If the callback cannot leak, then push the callback directly, 654 // otherwise wrap it in a weak cell. 655 if (callback->data()->IsUndefined(isolate()) || callback->data()->IsSmi()) { 656 __ Push(callback); 657 } else { 658 Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback); 659 __ Push(cell); 660 } 661 __ Push(name); 662 __ push(value()); 663 __ push(Immediate(Smi::FromInt(language_mode))); 664 __ push(scratch1()); // restore return address 665 666 // Do tail-call to the runtime system. 667 __ TailCallRuntime(Runtime::kStoreCallbackProperty); 668 669 // Return the generated code. 670 return GetCode(kind(), name); 671} 672 673 674Register NamedStoreHandlerCompiler::value() { 675 return StoreDescriptor::ValueRegister(); 676} 677 678 679Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( 680 Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { 681 Label miss; 682 if (IC::ICUseVector(kind())) { 683 PushVectorAndSlot(); 684 } 685 FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); 686 // Get the value from the cell. 687 Register result = StoreDescriptor::ValueRegister(); 688 Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell); 689 __ LoadWeakValue(result, weak_cell, &miss); 690 __ mov(result, FieldOperand(result, PropertyCell::kValueOffset)); 691 692 // Check for deleted property if property can actually be deleted. 693 if (is_configurable) { 694 __ cmp(result, factory()->the_hole_value()); 695 __ j(equal, &miss); 696 } else if (FLAG_debug_code) { 697 __ cmp(result, factory()->the_hole_value()); 698 __ Check(not_equal, kDontDeleteCellsCannotContainTheHole); 699 } 700 701 Counters* counters = isolate()->counters(); 702 __ IncrementCounter(counters->ic_named_load_global_stub(), 1); 703 // The code above already loads the result into the return register. 704 if (IC::ICUseVector(kind())) { 705 DiscardVectorAndSlot(); 706 } 707 __ ret(0); 708 709 FrontendFooter(name, &miss); 710 711 // Return the generated code. 712 return GetCode(kind(), name); 713} 714 715 716#undef __ 717} // namespace internal 718} // namespace v8 719 720#endif // V8_TARGET_ARCH_IA32 721