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 15 namespace v8 { 16 namespace internal { 17 18 #define __ ACCESS_MASM(masm) 19 20 21 void 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 59 void 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 73 void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) { 74 MacroAssembler* masm = this->masm(); 75 __ pop(vector); 76 __ pop(slot); 77 } 78 79 80 void PropertyHandlerCompiler::DiscardVectorAndSlot() { 81 MacroAssembler* masm = this->masm(); 82 // Remove vector and slot. 83 __ add(esp, Immediate(2 * kPointerSize)); 84 } 85 86 void PropertyHandlerCompiler::PushReturnAddress(Register tmp) { 87 MacroAssembler* masm = this->masm(); 88 __ push(tmp); 89 } 90 91 void PropertyHandlerCompiler::PopReturnAddress(Register tmp) { 92 MacroAssembler* masm = this->masm(); 93 __ pop(tmp); 94 } 95 96 void 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 136 void 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 147 void 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. 160 void 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. 255 void 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 270 void 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 328 static 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 341 static 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 354 void 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 363 void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) { 364 __ mov(this->name(), Immediate(name)); 365 } 366 367 368 void 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 383 void 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 398 void 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 void PropertyHandlerCompiler::GenerateAccessCheck( 415 Handle<WeakCell> native_context_cell, Register scratch1, Register scratch2, 416 Label* miss, bool compare_native_contexts_only) { 417 Label done; 418 // Load current native context. 419 __ mov(scratch1, NativeContextOperand()); 420 // Load expected native context. 421 __ LoadWeakValue(scratch2, native_context_cell, miss); 422 __ cmp(scratch1, scratch2); 423 424 if (!compare_native_contexts_only) { 425 __ j(equal, &done); 426 427 // Compare security tokens of current and expected native contexts. 428 __ mov(scratch1, ContextOperand(scratch1, Context::SECURITY_TOKEN_INDEX)); 429 __ mov(scratch2, ContextOperand(scratch2, Context::SECURITY_TOKEN_INDEX)); 430 __ cmp(scratch1, scratch2); 431 } 432 __ j(not_equal, miss); 433 434 __ bind(&done); 435 } 436 437 Register PropertyHandlerCompiler::CheckPrototypes( 438 Register object_reg, Register holder_reg, Register scratch1, 439 Register scratch2, Handle<Name> name, Label* miss, 440 ReturnHolder return_what) { 441 Handle<Map> receiver_map = map(); 442 443 // Make sure there's no overlap between holder and object registers. 444 DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); 445 DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && 446 !scratch2.is(scratch1)); 447 448 Handle<Cell> validity_cell = 449 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); 450 if (!validity_cell.is_null()) { 451 DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), validity_cell->value()); 452 // Operand::ForCell(...) points to the cell's payload! 453 __ cmp(Operand::ForCell(validity_cell), 454 Immediate(Smi::FromInt(Map::kPrototypeChainValid))); 455 __ j(not_equal, miss); 456 } 457 458 // Keep track of the current object in register reg. 459 Register reg = object_reg; 460 int depth = 0; 461 462 Handle<JSObject> current = Handle<JSObject>::null(); 463 if (receiver_map->IsJSGlobalObjectMap()) { 464 current = isolate()->global_object(); 465 } 466 467 Handle<Map> current_map(receiver_map->GetPrototypeChainRootMap(isolate()), 468 isolate()); 469 Handle<Map> holder_map(holder()->map()); 470 // Traverse the prototype chain and check the maps in the prototype chain for 471 // fast and global objects or do negative lookup for normal objects. 472 while (!current_map.is_identical_to(holder_map)) { 473 ++depth; 474 475 if (current_map->IsJSGlobalObjectMap()) { 476 GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), 477 name, scratch2, miss); 478 } else if (current_map->is_dictionary_map()) { 479 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast. 480 DCHECK(name->IsUniqueName()); 481 DCHECK(current.is_null() || 482 current->property_dictionary()->FindEntry(name) == 483 NameDictionary::kNotFound); 484 485 if (depth > 1) { 486 Handle<WeakCell> weak_cell = 487 Map::GetOrCreatePrototypeWeakCell(current, isolate()); 488 __ LoadWeakValue(reg, weak_cell, miss); 489 } 490 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, 491 scratch2); 492 } 493 494 reg = holder_reg; // From now on the object will be in holder_reg. 495 // Go to the next object in the prototype chain. 496 current = handle(JSObject::cast(current_map->prototype())); 497 current_map = handle(current->map()); 498 } 499 500 DCHECK(!current_map->IsJSGlobalProxyMap()); 501 502 // Log the check depth. 503 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); 504 505 bool return_holder = return_what == RETURN_HOLDER; 506 if (return_holder && depth != 0) { 507 Handle<WeakCell> weak_cell = 508 Map::GetOrCreatePrototypeWeakCell(current, isolate()); 509 __ LoadWeakValue(reg, weak_cell, miss); 510 } 511 512 // Return the register containing the holder. 513 return return_holder ? reg : no_reg; 514 } 515 516 517 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { 518 if (!miss->is_unused()) { 519 Label success; 520 __ jmp(&success); 521 __ bind(miss); 522 if (IC::ShouldPushPopSlotAndVector(kind())) { 523 DCHECK(kind() == Code::LOAD_IC); 524 PopVectorAndSlot(); 525 } 526 TailCallBuiltin(masm(), MissBuiltin(kind())); 527 __ bind(&success); 528 } 529 } 530 531 532 void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { 533 if (!miss->is_unused()) { 534 Label success; 535 __ jmp(&success); 536 GenerateRestoreName(miss, name); 537 DCHECK(!IC::ShouldPushPopSlotAndVector(kind())); 538 TailCallBuiltin(masm(), MissBuiltin(kind())); 539 __ bind(&success); 540 } 541 } 542 543 544 void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) { 545 // Return the constant value. 546 __ LoadObject(eax, value); 547 __ ret(0); 548 } 549 550 551 void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( 552 LookupIterator* it, Register holder_reg) { 553 DCHECK(holder()->HasNamedInterceptor()); 554 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); 555 556 // Compile the interceptor call, followed by inline code to load the 557 // property from further up the prototype chain if the call fails. 558 // Check that the maps haven't changed. 559 DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); 560 561 // Preserve the receiver register explicitly whenever it is different from the 562 // holder and it is needed should the interceptor return without any result. 563 // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD 564 // case might cause a miss during the prototype check. 565 bool must_perform_prototype_check = 566 !holder().is_identical_to(it->GetHolder<JSObject>()); 567 bool must_preserve_receiver_reg = 568 !receiver().is(holder_reg) && 569 (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check); 570 571 // Save necessary data before invoking an interceptor. 572 // Requires a frame to make GC aware of pushed pointers. 573 { 574 FrameScope frame_scope(masm(), StackFrame::INTERNAL); 575 576 if (must_preserve_receiver_reg) { 577 __ push(receiver()); 578 } 579 __ push(holder_reg); 580 __ push(this->name()); 581 InterceptorVectorSlotPush(holder_reg); 582 // Invoke an interceptor. Note: map checks from receiver to 583 // interceptor's holder has been compiled before (see a caller 584 // of this method.) 585 CompileCallLoadPropertyWithInterceptor( 586 masm(), receiver(), holder_reg, this->name(), holder(), 587 Runtime::kLoadPropertyWithInterceptorOnly); 588 589 // Check if interceptor provided a value for property. If it's 590 // the case, return immediately. 591 Label interceptor_failed; 592 __ cmp(eax, factory()->no_interceptor_result_sentinel()); 593 __ j(equal, &interceptor_failed); 594 frame_scope.GenerateLeaveFrame(); 595 __ ret(0); 596 597 // Clobber registers when generating debug-code to provoke errors. 598 __ bind(&interceptor_failed); 599 if (FLAG_debug_code) { 600 __ mov(receiver(), Immediate(bit_cast<int32_t>(kZapValue))); 601 __ mov(holder_reg, Immediate(bit_cast<int32_t>(kZapValue))); 602 __ mov(this->name(), Immediate(bit_cast<int32_t>(kZapValue))); 603 } 604 605 InterceptorVectorSlotPop(holder_reg); 606 __ pop(this->name()); 607 __ pop(holder_reg); 608 if (must_preserve_receiver_reg) { 609 __ pop(receiver()); 610 } 611 612 // Leave the internal frame. 613 } 614 615 GenerateLoadPostInterceptor(it, holder_reg); 616 } 617 618 619 void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { 620 DCHECK(holder()->HasNamedInterceptor()); 621 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); 622 // Call the runtime system to load the interceptor. 623 __ pop(scratch2()); // save old return address 624 PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(), 625 holder()); 626 __ push(scratch2()); // restore old return address 627 628 __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); 629 } 630 631 void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { 632 // Zap register aliases of the arguments passed on the stack to ensure they 633 // are properly loaded by the handler (debug-only). 634 STATIC_ASSERT(Descriptor::kPassLastArgsOnStack); 635 STATIC_ASSERT(Descriptor::kStackArgumentsCount == 3); 636 __ mov(Descriptor::ValueRegister(), Immediate(kDebugZapValue)); 637 __ mov(Descriptor::SlotRegister(), Immediate(kDebugZapValue)); 638 __ mov(Descriptor::VectorRegister(), Immediate(kDebugZapValue)); 639 } 640 641 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback( 642 Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback, 643 LanguageMode language_mode) { 644 Register holder_reg = Frontend(name); 645 __ LoadParameterFromStack<Descriptor>(value(), Descriptor::kValue); 646 647 __ pop(scratch1()); // remove the return address 648 // Discard stack arguments. 649 __ add(esp, Immediate(StoreWithVectorDescriptor::kStackArgumentsCount * 650 kPointerSize)); 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 674 Register NamedStoreHandlerCompiler::value() { 675 return StoreDescriptor::ValueRegister(); 676 } 677 678 679 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( 680 Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { 681 Label miss; 682 if (IC::ShouldPushPopSlotAndVector(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::ShouldPushPopSlotAndVector(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