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_ARM64 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 void PropertyHandlerCompiler::PushVectorAndSlot(Register vector, 21 Register slot) { 22 MacroAssembler* masm = this->masm(); 23 STATIC_ASSERT(LoadWithVectorDescriptor::kSlot < 24 LoadWithVectorDescriptor::kVector); 25 STATIC_ASSERT(StoreWithVectorDescriptor::kSlot < 26 StoreWithVectorDescriptor::kVector); 27 STATIC_ASSERT(StoreTransitionDescriptor::kSlot < 28 StoreTransitionDescriptor::kVector); 29 __ Push(slot); 30 __ Push(vector); 31 } 32 33 34 void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) { 35 MacroAssembler* masm = this->masm(); 36 __ Pop(vector); 37 __ Pop(slot); 38 } 39 40 41 void PropertyHandlerCompiler::DiscardVectorAndSlot() { 42 MacroAssembler* masm = this->masm(); 43 // Remove vector and slot. 44 __ Drop(2); 45 } 46 47 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( 48 MacroAssembler* masm, Label* miss_label, Register receiver, 49 Handle<Name> name, Register scratch0, Register scratch1) { 50 DCHECK(!AreAliased(receiver, scratch0, scratch1)); 51 DCHECK(name->IsUniqueName()); 52 Counters* counters = masm->isolate()->counters(); 53 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1); 54 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); 55 56 Label done; 57 58 const int kInterceptorOrAccessCheckNeededMask = 59 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); 60 61 // Bail out if the receiver has a named interceptor or requires access checks. 62 Register map = scratch1; 63 __ Ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset)); 64 __ Ldrb(scratch0, FieldMemOperand(map, Map::kBitFieldOffset)); 65 __ Tst(scratch0, kInterceptorOrAccessCheckNeededMask); 66 __ B(ne, miss_label); 67 68 // Check that receiver is a JSObject. 69 __ Ldrb(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset)); 70 __ Cmp(scratch0, FIRST_JS_RECEIVER_TYPE); 71 __ B(lt, miss_label); 72 73 // Load properties array. 74 Register properties = scratch0; 75 __ Ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); 76 // Check that the properties array is a dictionary. 77 __ Ldr(map, FieldMemOperand(properties, HeapObject::kMapOffset)); 78 __ JumpIfNotRoot(map, Heap::kHashTableMapRootIndex, miss_label); 79 80 NameDictionaryLookupStub::GenerateNegativeLookup( 81 masm, miss_label, &done, receiver, properties, name, scratch1); 82 __ Bind(&done); 83 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); 84 } 85 86 // Generate code to check that a global property cell is empty. Create 87 // the property cell at compilation time if no cell exists for the 88 // property. 89 void PropertyHandlerCompiler::GenerateCheckPropertyCell( 90 MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name, 91 Register scratch, Label* miss) { 92 Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell( 93 global, name, PropertyCellType::kInvalidated); 94 Isolate* isolate = masm->isolate(); 95 DCHECK(cell->value()->IsTheHole(isolate)); 96 Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell); 97 __ LoadWeakValue(scratch, weak_cell, miss); 98 __ Ldr(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset)); 99 __ JumpIfNotRoot(scratch, Heap::kTheHoleValueRootIndex, miss); 100 } 101 102 static void CompileCallLoadPropertyWithInterceptor( 103 MacroAssembler* masm, Register receiver, Register holder, Register name, 104 Handle<JSObject> holder_obj, Runtime::FunctionId id) { 105 DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == 106 Runtime::FunctionForId(id)->nargs); 107 108 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); 109 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); 110 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); 111 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); 112 __ Push(name, receiver, holder); 113 114 __ CallRuntime(id); 115 } 116 117 118 // Generate call to api function. 119 void PropertyHandlerCompiler::GenerateApiAccessorCall( 120 MacroAssembler* masm, const CallOptimization& optimization, 121 Handle<Map> receiver_map, Register receiver, Register scratch, 122 bool is_store, Register store_parameter, Register accessor_holder, 123 int accessor_index) { 124 DCHECK(!AreAliased(accessor_holder, scratch)); 125 DCHECK(!AreAliased(receiver, scratch)); 126 127 MacroAssembler::PushPopQueue queue(masm); 128 queue.Queue(receiver); 129 // Write the arguments to the stack frame. 130 if (is_store) { 131 DCHECK(!receiver.is(store_parameter)); 132 DCHECK(!scratch.is(store_parameter)); 133 queue.Queue(store_parameter); 134 } 135 queue.PushQueued(); 136 137 DCHECK(optimization.is_simple_api_call()); 138 139 // Abi for CallApiCallbackStub. 140 Register callee = x0; 141 Register data = x4; 142 Register holder = x2; 143 Register api_function_address = x1; 144 145 // Put callee in place. 146 __ LoadAccessor(callee, accessor_holder, accessor_index, 147 is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER); 148 149 // Put holder in place. 150 CallOptimization::HolderLookup holder_lookup; 151 int holder_depth = 0; 152 optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup, 153 &holder_depth); 154 switch (holder_lookup) { 155 case CallOptimization::kHolderIsReceiver: 156 __ Mov(holder, receiver); 157 break; 158 case CallOptimization::kHolderFound: 159 __ Ldr(holder, FieldMemOperand(receiver, HeapObject::kMapOffset)); 160 __ Ldr(holder, FieldMemOperand(holder, Map::kPrototypeOffset)); 161 for (int i = 1; i < holder_depth; i++) { 162 __ Ldr(holder, FieldMemOperand(holder, HeapObject::kMapOffset)); 163 __ Ldr(holder, FieldMemOperand(holder, Map::kPrototypeOffset)); 164 } 165 break; 166 case CallOptimization::kHolderNotFound: 167 UNREACHABLE(); 168 break; 169 } 170 171 Isolate* isolate = masm->isolate(); 172 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); 173 bool call_data_undefined = false; 174 // Put call data in place. 175 if (api_call_info->data()->IsUndefined(isolate)) { 176 call_data_undefined = true; 177 __ LoadRoot(data, Heap::kUndefinedValueRootIndex); 178 } else { 179 if (optimization.is_constant_call()) { 180 __ Ldr(data, 181 FieldMemOperand(callee, JSFunction::kSharedFunctionInfoOffset)); 182 __ Ldr(data, 183 FieldMemOperand(data, SharedFunctionInfo::kFunctionDataOffset)); 184 __ Ldr(data, 185 FieldMemOperand(data, FunctionTemplateInfo::kCallCodeOffset)); 186 } else { 187 __ Ldr(data, 188 FieldMemOperand(callee, FunctionTemplateInfo::kCallCodeOffset)); 189 } 190 __ Ldr(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset)); 191 } 192 193 if (api_call_info->fast_handler()->IsCode()) { 194 // Just tail call into the fast handler if present. 195 __ Jump(handle(Code::cast(api_call_info->fast_handler())), 196 RelocInfo::CODE_TARGET); 197 return; 198 } 199 200 // Put api_function_address in place. 201 Address function_address = v8::ToCData<Address>(api_call_info->callback()); 202 ApiFunction fun(function_address); 203 ExternalReference ref = ExternalReference( 204 &fun, ExternalReference::DIRECT_API_CALL, masm->isolate()); 205 __ Mov(api_function_address, ref); 206 207 // Jump to stub. 208 CallApiCallbackStub stub(isolate, is_store, call_data_undefined, 209 !optimization.is_constant_call()); 210 __ TailCallStub(&stub); 211 } 212 213 214 void NamedStoreHandlerCompiler::GenerateStoreViaSetter( 215 MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder, 216 int accessor_index, int expected_arguments, Register scratch) { 217 // ----------- S t a t e ------------- 218 // -- lr : return address 219 // ----------------------------------- 220 Label miss; 221 { 222 FrameScope scope(masm, StackFrame::INTERNAL); 223 224 // Save context register 225 __ Push(cp); 226 // Save value register, so we can restore it later. 227 __ Push(value()); 228 229 if (accessor_index >= 0) { 230 DCHECK(!AreAliased(holder, scratch)); 231 DCHECK(!AreAliased(receiver, scratch)); 232 DCHECK(!AreAliased(value(), scratch)); 233 // Call the JavaScript setter with receiver and value on the stack. 234 if (map->IsJSGlobalObjectMap()) { 235 // Swap in the global receiver. 236 __ Ldr(scratch, 237 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); 238 receiver = scratch; 239 } 240 __ Push(receiver, value()); 241 __ LoadAccessor(x1, holder, accessor_index, ACCESSOR_SETTER); 242 __ Mov(x0, 1); 243 __ Call(masm->isolate()->builtins()->CallFunction( 244 ConvertReceiverMode::kNotNullOrUndefined), 245 RelocInfo::CODE_TARGET); 246 } else { 247 // If we generate a global code snippet for deoptimization only, remember 248 // the place to continue after deoptimization. 249 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset()); 250 } 251 252 // We have to return the passed value, not the return value of the setter. 253 __ Pop(x0); 254 255 // Restore context register. 256 __ Pop(cp); 257 } 258 __ Ret(); 259 } 260 261 262 void NamedLoadHandlerCompiler::GenerateLoadViaGetter( 263 MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder, 264 int accessor_index, int expected_arguments, Register scratch) { 265 { 266 FrameScope scope(masm, StackFrame::INTERNAL); 267 268 // Save context register 269 __ Push(cp); 270 271 if (accessor_index >= 0) { 272 DCHECK(!AreAliased(holder, scratch)); 273 DCHECK(!AreAliased(receiver, scratch)); 274 // Call the JavaScript getter with the receiver on the stack. 275 if (map->IsJSGlobalObjectMap()) { 276 // Swap in the global receiver. 277 __ Ldr(scratch, 278 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); 279 receiver = scratch; 280 } 281 __ Push(receiver); 282 __ LoadAccessor(x1, holder, accessor_index, ACCESSOR_GETTER); 283 __ Mov(x0, 0); 284 __ Call(masm->isolate()->builtins()->CallFunction( 285 ConvertReceiverMode::kNotNullOrUndefined), 286 RelocInfo::CODE_TARGET); 287 } else { 288 // If we generate a global code snippet for deoptimization only, remember 289 // the place to continue after deoptimization. 290 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); 291 } 292 293 // Restore context register. 294 __ Pop(cp); 295 } 296 __ Ret(); 297 } 298 299 #undef __ 300 #define __ ACCESS_MASM(masm()) 301 302 303 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( 304 Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { 305 Label miss; 306 if (IC::ICUseVector(kind())) { 307 PushVectorAndSlot(); 308 } 309 FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); 310 311 // Get the value from the cell. 312 Register result = StoreDescriptor::ValueRegister(); 313 Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell); 314 __ LoadWeakValue(result, weak_cell, &miss); 315 __ Ldr(result, FieldMemOperand(result, PropertyCell::kValueOffset)); 316 317 // Check for deleted property if property can actually be deleted. 318 if (is_configurable) { 319 __ JumpIfRoot(result, Heap::kTheHoleValueRootIndex, &miss); 320 } 321 322 Counters* counters = isolate()->counters(); 323 __ IncrementCounter(counters->ic_named_load_global_stub(), 1, x1, x3); 324 if (IC::ICUseVector(kind())) { 325 DiscardVectorAndSlot(); 326 } 327 __ Ret(); 328 329 FrontendFooter(name, &miss); 330 331 // Return the generated code. 332 return GetCode(kind(), name); 333 } 334 335 336 Register NamedStoreHandlerCompiler::value() { 337 return StoreDescriptor::ValueRegister(); 338 } 339 340 341 void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label, 342 Handle<Name> name) { 343 if (!label->is_unused()) { 344 __ Bind(label); 345 __ Mov(this->name(), Operand(name)); 346 } 347 } 348 349 void PropertyHandlerCompiler::GenerateAccessCheck( 350 Handle<WeakCell> native_context_cell, Register scratch1, Register scratch2, 351 Label* miss, bool compare_native_contexts_only) { 352 Label done; 353 // Load current native context. 354 __ Ldr(scratch1, NativeContextMemOperand()); 355 // Load expected native context. 356 __ LoadWeakValue(scratch2, native_context_cell, miss); 357 __ Cmp(scratch1, scratch2); 358 359 if (!compare_native_contexts_only) { 360 __ B(eq, &done); 361 362 // Compare security tokens of current and expected native contexts. 363 __ Ldr(scratch1, 364 ContextMemOperand(scratch1, Context::SECURITY_TOKEN_INDEX)); 365 __ Ldr(scratch2, 366 ContextMemOperand(scratch2, Context::SECURITY_TOKEN_INDEX)); 367 __ Cmp(scratch1, scratch2); 368 } 369 __ B(ne, miss); 370 371 __ bind(&done); 372 } 373 374 Register PropertyHandlerCompiler::CheckPrototypes( 375 Register object_reg, Register holder_reg, Register scratch1, 376 Register scratch2, Handle<Name> name, Label* miss, 377 ReturnHolder return_what) { 378 Handle<Map> receiver_map = map(); 379 380 // object_reg and holder_reg registers can alias. 381 DCHECK(!AreAliased(object_reg, scratch1, scratch2)); 382 DCHECK(!AreAliased(holder_reg, scratch1, scratch2)); 383 384 Handle<Cell> validity_cell = 385 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); 386 if (!validity_cell.is_null()) { 387 DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), validity_cell->value()); 388 __ Mov(scratch1, Operand(validity_cell)); 389 __ Ldr(scratch1, FieldMemOperand(scratch1, Cell::kValueOffset)); 390 // Compare scratch1 against Map::kPrototypeChainValid. 391 static_assert(Map::kPrototypeChainValid == 0, 392 "Map::kPrototypeChainValid has unexpected value"); 393 __ Cbnz(scratch1, miss); 394 } 395 396 // Keep track of the current object in register reg. 397 Register reg = object_reg; 398 int depth = 0; 399 400 Handle<JSObject> current = Handle<JSObject>::null(); 401 if (receiver_map->IsJSGlobalObjectMap()) { 402 current = isolate()->global_object(); 403 } 404 405 Handle<Map> current_map(receiver_map->GetPrototypeChainRootMap(isolate()), 406 isolate()); 407 Handle<Map> holder_map(holder()->map()); 408 // Traverse the prototype chain and check the maps in the prototype chain for 409 // fast and global objects or do negative lookup for normal objects. 410 while (!current_map.is_identical_to(holder_map)) { 411 ++depth; 412 413 if (current_map->IsJSGlobalObjectMap()) { 414 GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), 415 name, scratch2, miss); 416 } else if (current_map->is_dictionary_map()) { 417 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast. 418 DCHECK(name->IsUniqueName()); 419 DCHECK(current.is_null() || (current->property_dictionary()->FindEntry( 420 name) == NameDictionary::kNotFound)); 421 422 if (depth > 1) { 423 Handle<WeakCell> weak_cell = 424 Map::GetOrCreatePrototypeWeakCell(current, isolate()); 425 __ LoadWeakValue(reg, weak_cell, miss); 426 } 427 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, 428 scratch2); 429 } 430 431 reg = holder_reg; // From now on the object will be in holder_reg. 432 // Go to the next object in the prototype chain. 433 current = handle(JSObject::cast(current_map->prototype())); 434 current_map = handle(current->map()); 435 } 436 437 DCHECK(!current_map->IsJSGlobalProxyMap()); 438 439 // Log the check depth. 440 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); 441 442 bool return_holder = return_what == RETURN_HOLDER; 443 if (return_holder && depth != 0) { 444 Handle<WeakCell> weak_cell = 445 Map::GetOrCreatePrototypeWeakCell(current, isolate()); 446 __ LoadWeakValue(reg, weak_cell, miss); 447 } 448 449 // Return the register containing the holder. 450 return return_holder ? reg : no_reg; 451 } 452 453 454 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { 455 if (!miss->is_unused()) { 456 Label success; 457 __ B(&success); 458 459 __ Bind(miss); 460 if (IC::ICUseVector(kind())) { 461 DCHECK(kind() == Code::LOAD_IC); 462 PopVectorAndSlot(); 463 } 464 TailCallBuiltin(masm(), MissBuiltin(kind())); 465 466 __ Bind(&success); 467 } 468 } 469 470 471 void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { 472 if (!miss->is_unused()) { 473 Label success; 474 __ B(&success); 475 476 GenerateRestoreName(miss, name); 477 if (IC::ICUseVector(kind())) PopVectorAndSlot(); 478 TailCallBuiltin(masm(), MissBuiltin(kind())); 479 480 __ Bind(&success); 481 } 482 } 483 484 void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( 485 LookupIterator* it, Register holder_reg) { 486 DCHECK(!AreAliased(receiver(), this->name(), scratch1(), scratch2(), 487 scratch3())); 488 DCHECK(holder()->HasNamedInterceptor()); 489 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); 490 491 // Compile the interceptor call, followed by inline code to load the 492 // property from further up the prototype chain if the call fails. 493 // Check that the maps haven't changed. 494 DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); 495 496 // Preserve the receiver register explicitly whenever it is different from the 497 // holder and it is needed should the interceptor return without any result. 498 // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD 499 // case might cause a miss during the prototype check. 500 bool must_perform_prototype_check = 501 !holder().is_identical_to(it->GetHolder<JSObject>()); 502 bool must_preserve_receiver_reg = 503 !receiver().is(holder_reg) && 504 (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check); 505 506 // Save necessary data before invoking an interceptor. 507 // Requires a frame to make GC aware of pushed pointers. 508 { 509 FrameScope frame_scope(masm(), StackFrame::INTERNAL); 510 if (must_preserve_receiver_reg) { 511 __ Push(receiver(), holder_reg, this->name()); 512 } else { 513 __ Push(holder_reg, this->name()); 514 } 515 InterceptorVectorSlotPush(holder_reg); 516 // Invoke an interceptor. Note: map checks from receiver to 517 // interceptor's holder has been compiled before (see a caller 518 // of this method.) 519 CompileCallLoadPropertyWithInterceptor( 520 masm(), receiver(), holder_reg, this->name(), holder(), 521 Runtime::kLoadPropertyWithInterceptorOnly); 522 523 // Check if interceptor provided a value for property. If it's 524 // the case, return immediately. 525 Label interceptor_failed; 526 __ JumpIfRoot(x0, Heap::kNoInterceptorResultSentinelRootIndex, 527 &interceptor_failed); 528 frame_scope.GenerateLeaveFrame(); 529 __ Ret(); 530 531 __ Bind(&interceptor_failed); 532 InterceptorVectorSlotPop(holder_reg); 533 if (must_preserve_receiver_reg) { 534 __ Pop(this->name(), holder_reg, receiver()); 535 } else { 536 __ Pop(this->name(), holder_reg); 537 } 538 // Leave the internal frame. 539 } 540 541 GenerateLoadPostInterceptor(it, holder_reg); 542 } 543 544 545 void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { 546 // Call the runtime system to load the interceptor. 547 DCHECK(holder()->HasNamedInterceptor()); 548 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); 549 550 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); 551 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); 552 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); 553 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); 554 __ Push(name(), receiver(), holder_reg); 555 // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. 556 if (holder_reg.is(receiver())) { 557 __ Push(slot(), vector()); 558 } else { 559 __ Push(scratch3(), scratch2()); // slot, vector 560 } 561 562 __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); 563 } 564 565 void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { 566 STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack); 567 } 568 569 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback( 570 Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback, 571 LanguageMode language_mode) { 572 ASM_LOCATION("NamedStoreHandlerCompiler::CompileStoreCallback"); 573 Register holder_reg = Frontend(name); 574 575 // Stub never generated for non-global objects that require access checks. 576 DCHECK(holder()->IsJSGlobalProxy() || !holder()->IsAccessCheckNeeded()); 577 578 // receiver() and holder_reg can alias. 579 DCHECK(!AreAliased(receiver(), scratch1(), scratch2(), value())); 580 DCHECK(!AreAliased(holder_reg, scratch1(), scratch2(), value())); 581 // If the callback cannot leak, then push the callback directly, 582 // otherwise wrap it in a weak cell. 583 if (callback->data()->IsUndefined(isolate()) || callback->data()->IsSmi()) { 584 __ Mov(scratch1(), Operand(callback)); 585 } else { 586 Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback); 587 __ Mov(scratch1(), Operand(cell)); 588 } 589 __ Mov(scratch2(), Operand(name)); 590 __ Push(receiver(), holder_reg, scratch1(), scratch2(), value()); 591 __ Push(Smi::FromInt(language_mode)); 592 593 // Do tail-call to the runtime system. 594 __ TailCallRuntime(Runtime::kStoreCallbackProperty); 595 596 // Return the generated code. 597 return GetCode(kind(), name); 598 } 599 600 601 #undef __ 602 } // namespace internal 603 } // namespace v8 604 605 #endif // V8_TARGET_ARCH_IA32 606