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