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