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 #include "src/code-stubs.h" 6 7 #include "src/bailout-reason.h" 8 #include "src/crankshaft/hydrogen.h" 9 #include "src/crankshaft/lithium.h" 10 #include "src/field-index.h" 11 #include "src/ic/ic.h" 12 13 namespace v8 { 14 namespace internal { 15 16 17 static LChunk* OptimizeGraph(HGraph* graph) { 18 DisallowHeapAllocation no_allocation; 19 DisallowHandleAllocation no_handles; 20 DisallowHandleDereference no_deref; 21 22 DCHECK(graph != NULL); 23 BailoutReason bailout_reason = kNoReason; 24 if (!graph->Optimize(&bailout_reason)) { 25 FATAL(GetBailoutReason(bailout_reason)); 26 } 27 LChunk* chunk = LChunk::NewChunk(graph); 28 if (chunk == NULL) { 29 FATAL(GetBailoutReason(graph->info()->bailout_reason())); 30 } 31 return chunk; 32 } 33 34 35 class CodeStubGraphBuilderBase : public HGraphBuilder { 36 public: 37 explicit CodeStubGraphBuilderBase(CompilationInfo* info, CodeStub* code_stub) 38 : HGraphBuilder(info, code_stub->GetCallInterfaceDescriptor()), 39 arguments_length_(NULL), 40 info_(info), 41 code_stub_(code_stub), 42 descriptor_(code_stub), 43 context_(NULL) { 44 int parameter_count = GetParameterCount(); 45 parameters_.Reset(new HParameter*[parameter_count]); 46 } 47 virtual bool BuildGraph(); 48 49 protected: 50 virtual HValue* BuildCodeStub() = 0; 51 int GetParameterCount() const { return descriptor_.GetParameterCount(); } 52 int GetRegisterParameterCount() const { 53 return descriptor_.GetRegisterParameterCount(); 54 } 55 HParameter* GetParameter(int parameter) { 56 DCHECK(parameter < GetParameterCount()); 57 return parameters_[parameter]; 58 } 59 Representation GetParameterRepresentation(int parameter) { 60 return RepresentationFromType(descriptor_.GetParameterType(parameter)); 61 } 62 bool IsParameterCountRegister(int index) const { 63 return descriptor_.GetRegisterParameter(index) 64 .is(descriptor_.stack_parameter_count()); 65 } 66 HValue* GetArgumentsLength() { 67 // This is initialized in BuildGraph() 68 DCHECK(arguments_length_ != NULL); 69 return arguments_length_; 70 } 71 CompilationInfo* info() { return info_; } 72 CodeStub* stub() { return code_stub_; } 73 HContext* context() { return context_; } 74 Isolate* isolate() { return info_->isolate(); } 75 76 HLoadNamedField* BuildLoadNamedField(HValue* object, FieldIndex index); 77 void BuildStoreNamedField(HValue* object, HValue* value, FieldIndex index, 78 Representation representation, 79 bool transition_to_field); 80 81 HValue* BuildPushElement(HValue* object, HValue* argc, 82 HValue* argument_elements, ElementsKind kind); 83 84 HValue* UnmappedCase(HValue* elements, HValue* key, HValue* value); 85 HValue* EmitKeyedSloppyArguments(HValue* receiver, HValue* key, 86 HValue* value); 87 88 HValue* BuildToString(HValue* input, bool convert); 89 HValue* BuildToPrimitive(HValue* input, HValue* input_map); 90 91 private: 92 base::SmartArrayPointer<HParameter*> parameters_; 93 HValue* arguments_length_; 94 CompilationInfo* info_; 95 CodeStub* code_stub_; 96 CodeStubDescriptor descriptor_; 97 HContext* context_; 98 }; 99 100 101 bool CodeStubGraphBuilderBase::BuildGraph() { 102 // Update the static counter each time a new code stub is generated. 103 isolate()->counters()->code_stubs()->Increment(); 104 105 if (FLAG_trace_hydrogen_stubs) { 106 const char* name = CodeStub::MajorName(stub()->MajorKey()); 107 PrintF("-----------------------------------------------------------\n"); 108 PrintF("Compiling stub %s using hydrogen\n", name); 109 isolate()->GetHTracer()->TraceCompilation(info()); 110 } 111 112 int param_count = GetParameterCount(); 113 int register_param_count = GetRegisterParameterCount(); 114 HEnvironment* start_environment = graph()->start_environment(); 115 HBasicBlock* next_block = CreateBasicBlock(start_environment); 116 Goto(next_block); 117 next_block->SetJoinId(BailoutId::StubEntry()); 118 set_current_block(next_block); 119 120 bool runtime_stack_params = descriptor_.stack_parameter_count().is_valid(); 121 HInstruction* stack_parameter_count = NULL; 122 for (int i = 0; i < param_count; ++i) { 123 Representation r = GetParameterRepresentation(i); 124 HParameter* param; 125 if (i >= register_param_count) { 126 param = Add<HParameter>(i - register_param_count, 127 HParameter::STACK_PARAMETER, r); 128 } else { 129 param = Add<HParameter>(i, HParameter::REGISTER_PARAMETER, r); 130 start_environment->Bind(i, param); 131 } 132 parameters_[i] = param; 133 if (i < register_param_count && IsParameterCountRegister(i)) { 134 param->set_type(HType::Smi()); 135 stack_parameter_count = param; 136 arguments_length_ = stack_parameter_count; 137 } 138 } 139 140 DCHECK(!runtime_stack_params || arguments_length_ != NULL); 141 if (!runtime_stack_params) { 142 stack_parameter_count = 143 Add<HConstant>(param_count - register_param_count - 1); 144 // graph()->GetConstantMinus1(); 145 arguments_length_ = graph()->GetConstant0(); 146 } 147 148 context_ = Add<HContext>(); 149 start_environment->BindContext(context_); 150 start_environment->Bind(param_count, context_); 151 152 Add<HSimulate>(BailoutId::StubEntry()); 153 154 NoObservableSideEffectsScope no_effects(this); 155 156 HValue* return_value = BuildCodeStub(); 157 158 // We might have extra expressions to pop from the stack in addition to the 159 // arguments above. 160 HInstruction* stack_pop_count = stack_parameter_count; 161 if (descriptor_.function_mode() == JS_FUNCTION_STUB_MODE) { 162 if (!stack_parameter_count->IsConstant() && 163 descriptor_.hint_stack_parameter_count() < 0) { 164 HInstruction* constant_one = graph()->GetConstant1(); 165 stack_pop_count = AddUncasted<HAdd>(stack_parameter_count, constant_one); 166 stack_pop_count->ClearFlag(HValue::kCanOverflow); 167 // TODO(mvstanton): verify that stack_parameter_count+1 really fits in a 168 // smi. 169 } else { 170 int count = descriptor_.hint_stack_parameter_count(); 171 stack_pop_count = Add<HConstant>(count); 172 } 173 } 174 175 if (current_block() != NULL) { 176 HReturn* hreturn_instruction = New<HReturn>(return_value, 177 stack_pop_count); 178 FinishCurrentBlock(hreturn_instruction); 179 } 180 return true; 181 } 182 183 184 template <class Stub> 185 class CodeStubGraphBuilder: public CodeStubGraphBuilderBase { 186 public: 187 explicit CodeStubGraphBuilder(CompilationInfo* info, CodeStub* stub) 188 : CodeStubGraphBuilderBase(info, stub) {} 189 190 protected: 191 virtual HValue* BuildCodeStub() { 192 if (casted_stub()->IsUninitialized()) { 193 return BuildCodeUninitializedStub(); 194 } else { 195 return BuildCodeInitializedStub(); 196 } 197 } 198 199 virtual HValue* BuildCodeInitializedStub() { 200 UNIMPLEMENTED(); 201 return NULL; 202 } 203 204 virtual HValue* BuildCodeUninitializedStub() { 205 // Force a deopt that falls back to the runtime. 206 HValue* undefined = graph()->GetConstantUndefined(); 207 IfBuilder builder(this); 208 builder.IfNot<HCompareObjectEqAndBranch, HValue*>(undefined, undefined); 209 builder.Then(); 210 builder.ElseDeopt(Deoptimizer::kForcedDeoptToRuntime); 211 return undefined; 212 } 213 214 Stub* casted_stub() { return static_cast<Stub*>(stub()); } 215 }; 216 217 218 Handle<Code> HydrogenCodeStub::GenerateLightweightMissCode( 219 ExternalReference miss) { 220 Factory* factory = isolate()->factory(); 221 222 // Generate the new code. 223 MacroAssembler masm(isolate(), NULL, 256, CodeObjectRequired::kYes); 224 225 { 226 // Update the static counter each time a new code stub is generated. 227 isolate()->counters()->code_stubs()->Increment(); 228 229 // Generate the code for the stub. 230 masm.set_generating_stub(true); 231 // TODO(yangguo): remove this once we can serialize IC stubs. 232 masm.enable_serializer(); 233 NoCurrentFrameScope scope(&masm); 234 GenerateLightweightMiss(&masm, miss); 235 } 236 237 // Create the code object. 238 CodeDesc desc; 239 masm.GetCode(&desc); 240 241 // Copy the generated code into a heap object. 242 Handle<Code> new_object = factory->NewCode( 243 desc, GetCodeFlags(), masm.CodeObject(), NeedsImmovableCode()); 244 return new_object; 245 } 246 247 248 template <class Stub> 249 static Handle<Code> DoGenerateCode(Stub* stub) { 250 Isolate* isolate = stub->isolate(); 251 CodeStubDescriptor descriptor(stub); 252 253 // If we are uninitialized we can use a light-weight stub to enter 254 // the runtime that is significantly faster than using the standard 255 // stub-failure deopt mechanism. 256 if (stub->IsUninitialized() && descriptor.has_miss_handler()) { 257 DCHECK(!descriptor.stack_parameter_count().is_valid()); 258 return stub->GenerateLightweightMissCode(descriptor.miss_handler()); 259 } 260 base::ElapsedTimer timer; 261 if (FLAG_profile_hydrogen_code_stub_compilation) { 262 timer.Start(); 263 } 264 Zone zone(isolate->allocator()); 265 CompilationInfo info(CStrVector(CodeStub::MajorName(stub->MajorKey())), 266 isolate, &zone, stub->GetCodeFlags()); 267 // Parameter count is number of stack parameters. 268 int parameter_count = descriptor.GetStackParameterCount(); 269 if (descriptor.function_mode() == NOT_JS_FUNCTION_STUB_MODE) { 270 parameter_count--; 271 } 272 info.set_parameter_count(parameter_count); 273 CodeStubGraphBuilder<Stub> builder(&info, stub); 274 LChunk* chunk = OptimizeGraph(builder.CreateGraph()); 275 Handle<Code> code = chunk->Codegen(); 276 if (FLAG_profile_hydrogen_code_stub_compilation) { 277 OFStream os(stdout); 278 os << "[Lazy compilation of " << stub << " took " 279 << timer.Elapsed().InMillisecondsF() << " ms]" << std::endl; 280 } 281 return code; 282 } 283 284 285 template <> 286 HValue* CodeStubGraphBuilder<NumberToStringStub>::BuildCodeStub() { 287 info()->MarkAsSavesCallerDoubles(); 288 HValue* number = GetParameter(NumberToStringStub::kNumber); 289 return BuildNumberToString(number, Type::Number()); 290 } 291 292 293 Handle<Code> NumberToStringStub::GenerateCode() { 294 return DoGenerateCode(this); 295 } 296 297 298 // Returns the type string of a value; see ECMA-262, 11.4.3 (p 47). 299 template <> 300 HValue* CodeStubGraphBuilder<TypeofStub>::BuildCodeStub() { 301 Factory* factory = isolate()->factory(); 302 HConstant* number_string = Add<HConstant>(factory->number_string()); 303 HValue* object = GetParameter(TypeofStub::kObject); 304 305 IfBuilder is_smi(this); 306 HValue* smi_check = is_smi.If<HIsSmiAndBranch>(object); 307 is_smi.Then(); 308 { Push(number_string); } 309 is_smi.Else(); 310 { 311 IfBuilder is_number(this); 312 is_number.If<HCompareMap>(object, isolate()->factory()->heap_number_map()); 313 is_number.Then(); 314 { Push(number_string); } 315 is_number.Else(); 316 { 317 HValue* map = AddLoadMap(object, smi_check); 318 HValue* instance_type = Add<HLoadNamedField>( 319 map, nullptr, HObjectAccess::ForMapInstanceType()); 320 IfBuilder is_string(this); 321 is_string.If<HCompareNumericAndBranch>( 322 instance_type, Add<HConstant>(FIRST_NONSTRING_TYPE), Token::LT); 323 is_string.Then(); 324 { Push(Add<HConstant>(factory->string_string())); } 325 is_string.Else(); 326 { 327 HConstant* object_string = Add<HConstant>(factory->object_string()); 328 IfBuilder is_oddball(this); 329 is_oddball.If<HCompareNumericAndBranch>( 330 instance_type, Add<HConstant>(ODDBALL_TYPE), Token::EQ); 331 is_oddball.Then(); 332 { 333 Push(Add<HLoadNamedField>(object, nullptr, 334 HObjectAccess::ForOddballTypeOf())); 335 } 336 is_oddball.Else(); 337 { 338 IfBuilder is_symbol(this); 339 is_symbol.If<HCompareNumericAndBranch>( 340 instance_type, Add<HConstant>(SYMBOL_TYPE), Token::EQ); 341 is_symbol.Then(); 342 { Push(Add<HConstant>(factory->symbol_string())); } 343 is_symbol.Else(); 344 { 345 HValue* bit_field = Add<HLoadNamedField>( 346 map, nullptr, HObjectAccess::ForMapBitField()); 347 HValue* bit_field_masked = AddUncasted<HBitwise>( 348 Token::BIT_AND, bit_field, 349 Add<HConstant>((1 << Map::kIsCallable) | 350 (1 << Map::kIsUndetectable))); 351 IfBuilder is_function(this); 352 is_function.If<HCompareNumericAndBranch>( 353 bit_field_masked, Add<HConstant>(1 << Map::kIsCallable), 354 Token::EQ); 355 is_function.Then(); 356 { Push(Add<HConstant>(factory->function_string())); } 357 is_function.Else(); 358 { 359 #define SIMD128_BUILDER_OPEN(TYPE, Type, type, lane_count, lane_type) \ 360 IfBuilder is_##type(this); \ 361 is_##type.If<HCompareObjectEqAndBranch>( \ 362 map, Add<HConstant>(factory->type##_map())); \ 363 is_##type.Then(); \ 364 { Push(Add<HConstant>(factory->type##_string())); } \ 365 is_##type.Else(); { 366 SIMD128_TYPES(SIMD128_BUILDER_OPEN) 367 #undef SIMD128_BUILDER_OPEN 368 // Is it an undetectable object? 369 IfBuilder is_undetectable(this); 370 is_undetectable.If<HCompareNumericAndBranch>( 371 bit_field_masked, graph()->GetConstant0(), Token::NE); 372 is_undetectable.Then(); 373 { 374 // typeof an undetectable object is 'undefined'. 375 Push(Add<HConstant>(factory->undefined_string())); 376 } 377 is_undetectable.Else(); 378 { 379 // For any kind of object not handled above, the spec rule for 380 // host objects gives that it is okay to return "object". 381 Push(object_string); 382 } 383 #define SIMD128_BUILDER_CLOSE(TYPE, Type, type, lane_count, lane_type) } 384 SIMD128_TYPES(SIMD128_BUILDER_CLOSE) 385 #undef SIMD128_BUILDER_CLOSE 386 } 387 is_function.End(); 388 } 389 is_symbol.End(); 390 } 391 is_oddball.End(); 392 } 393 is_string.End(); 394 } 395 is_number.End(); 396 } 397 is_smi.End(); 398 399 return environment()->Pop(); 400 } 401 402 403 Handle<Code> TypeofStub::GenerateCode() { return DoGenerateCode(this); } 404 405 406 template <> 407 HValue* CodeStubGraphBuilder<FastCloneRegExpStub>::BuildCodeStub() { 408 HValue* closure = GetParameter(0); 409 HValue* literal_index = GetParameter(1); 410 411 // This stub is very performance sensitive, the generated code must be tuned 412 // so that it doesn't build and eager frame. 413 info()->MarkMustNotHaveEagerFrame(); 414 415 HValue* literals_array = Add<HLoadNamedField>( 416 closure, nullptr, HObjectAccess::ForLiteralsPointer()); 417 HInstruction* boilerplate = Add<HLoadKeyed>( 418 literals_array, literal_index, nullptr, nullptr, FAST_ELEMENTS, 419 NEVER_RETURN_HOLE, LiteralsArray::kOffsetToFirstLiteral - kHeapObjectTag); 420 421 IfBuilder if_notundefined(this); 422 if_notundefined.IfNot<HCompareObjectEqAndBranch>( 423 boilerplate, graph()->GetConstantUndefined()); 424 if_notundefined.Then(); 425 { 426 int result_size = 427 JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize; 428 HValue* result = 429 Add<HAllocate>(Add<HConstant>(result_size), HType::JSObject(), 430 NOT_TENURED, JS_REGEXP_TYPE, graph()->GetConstant0()); 431 Add<HStoreNamedField>( 432 result, HObjectAccess::ForMap(), 433 Add<HLoadNamedField>(boilerplate, nullptr, HObjectAccess::ForMap())); 434 Add<HStoreNamedField>( 435 result, HObjectAccess::ForPropertiesPointer(), 436 Add<HLoadNamedField>(boilerplate, nullptr, 437 HObjectAccess::ForPropertiesPointer())); 438 Add<HStoreNamedField>( 439 result, HObjectAccess::ForElementsPointer(), 440 Add<HLoadNamedField>(boilerplate, nullptr, 441 HObjectAccess::ForElementsPointer())); 442 for (int offset = JSObject::kHeaderSize; offset < result_size; 443 offset += kPointerSize) { 444 HObjectAccess access = HObjectAccess::ForObservableJSObjectOffset(offset); 445 Add<HStoreNamedField>(result, access, 446 Add<HLoadNamedField>(boilerplate, nullptr, access)); 447 } 448 Push(result); 449 } 450 if_notundefined.ElseDeopt(Deoptimizer::kUninitializedBoilerplateInFastClone); 451 if_notundefined.End(); 452 453 return Pop(); 454 } 455 456 457 Handle<Code> FastCloneRegExpStub::GenerateCode() { 458 return DoGenerateCode(this); 459 } 460 461 462 template <> 463 HValue* CodeStubGraphBuilder<FastCloneShallowArrayStub>::BuildCodeStub() { 464 Factory* factory = isolate()->factory(); 465 HValue* undefined = graph()->GetConstantUndefined(); 466 AllocationSiteMode alloc_site_mode = casted_stub()->allocation_site_mode(); 467 HValue* closure = GetParameter(0); 468 HValue* literal_index = GetParameter(1); 469 470 // TODO(turbofan): This codestub has regressed to need a frame on ia32 at some 471 // point and wasn't caught since it wasn't built in the snapshot. We should 472 // probably just replace with a TurboFan stub rather than fixing it. 473 #if !(V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87) 474 // This stub is very performance sensitive, the generated code must be tuned 475 // so that it doesn't build and eager frame. 476 info()->MarkMustNotHaveEagerFrame(); 477 #endif 478 479 HValue* literals_array = Add<HLoadNamedField>( 480 closure, nullptr, HObjectAccess::ForLiteralsPointer()); 481 482 HInstruction* allocation_site = Add<HLoadKeyed>( 483 literals_array, literal_index, nullptr, nullptr, FAST_ELEMENTS, 484 NEVER_RETURN_HOLE, LiteralsArray::kOffsetToFirstLiteral - kHeapObjectTag); 485 IfBuilder checker(this); 486 checker.IfNot<HCompareObjectEqAndBranch, HValue*>(allocation_site, 487 undefined); 488 checker.Then(); 489 490 HObjectAccess access = HObjectAccess::ForAllocationSiteOffset( 491 AllocationSite::kTransitionInfoOffset); 492 HInstruction* boilerplate = 493 Add<HLoadNamedField>(allocation_site, nullptr, access); 494 HValue* elements = AddLoadElements(boilerplate); 495 HValue* capacity = AddLoadFixedArrayLength(elements); 496 IfBuilder zero_capacity(this); 497 zero_capacity.If<HCompareNumericAndBranch>(capacity, graph()->GetConstant0(), 498 Token::EQ); 499 zero_capacity.Then(); 500 Push(BuildCloneShallowArrayEmpty(boilerplate, 501 allocation_site, 502 alloc_site_mode)); 503 zero_capacity.Else(); 504 IfBuilder if_fixed_cow(this); 505 if_fixed_cow.If<HCompareMap>(elements, factory->fixed_cow_array_map()); 506 if_fixed_cow.Then(); 507 Push(BuildCloneShallowArrayCow(boilerplate, 508 allocation_site, 509 alloc_site_mode, 510 FAST_ELEMENTS)); 511 if_fixed_cow.Else(); 512 IfBuilder if_fixed(this); 513 if_fixed.If<HCompareMap>(elements, factory->fixed_array_map()); 514 if_fixed.Then(); 515 Push(BuildCloneShallowArrayNonEmpty(boilerplate, 516 allocation_site, 517 alloc_site_mode, 518 FAST_ELEMENTS)); 519 520 if_fixed.Else(); 521 Push(BuildCloneShallowArrayNonEmpty(boilerplate, 522 allocation_site, 523 alloc_site_mode, 524 FAST_DOUBLE_ELEMENTS)); 525 if_fixed.End(); 526 if_fixed_cow.End(); 527 zero_capacity.End(); 528 529 checker.ElseDeopt(Deoptimizer::kUninitializedBoilerplateLiterals); 530 checker.End(); 531 532 return environment()->Pop(); 533 } 534 535 536 Handle<Code> FastCloneShallowArrayStub::GenerateCode() { 537 return DoGenerateCode(this); 538 } 539 540 541 template <> 542 HValue* CodeStubGraphBuilder<CreateAllocationSiteStub>::BuildCodeStub() { 543 // This stub is performance sensitive, the generated code must be tuned 544 // so that it doesn't build an eager frame. 545 info()->MarkMustNotHaveEagerFrame(); 546 547 HValue* size = Add<HConstant>(AllocationSite::kSize); 548 HInstruction* object = 549 Add<HAllocate>(size, HType::JSObject(), TENURED, JS_OBJECT_TYPE, 550 graph()->GetConstant0()); 551 552 // Store the map 553 Handle<Map> allocation_site_map = isolate()->factory()->allocation_site_map(); 554 AddStoreMapConstant(object, allocation_site_map); 555 556 // Store the payload (smi elements kind) 557 HValue* initial_elements_kind = Add<HConstant>(GetInitialFastElementsKind()); 558 Add<HStoreNamedField>(object, 559 HObjectAccess::ForAllocationSiteOffset( 560 AllocationSite::kTransitionInfoOffset), 561 initial_elements_kind); 562 563 // Unlike literals, constructed arrays don't have nested sites 564 Add<HStoreNamedField>(object, 565 HObjectAccess::ForAllocationSiteOffset( 566 AllocationSite::kNestedSiteOffset), 567 graph()->GetConstant0()); 568 569 // Pretenuring calculation field. 570 Add<HStoreNamedField>(object, 571 HObjectAccess::ForAllocationSiteOffset( 572 AllocationSite::kPretenureDataOffset), 573 graph()->GetConstant0()); 574 575 // Pretenuring memento creation count field. 576 Add<HStoreNamedField>(object, 577 HObjectAccess::ForAllocationSiteOffset( 578 AllocationSite::kPretenureCreateCountOffset), 579 graph()->GetConstant0()); 580 581 // Store an empty fixed array for the code dependency. 582 HConstant* empty_fixed_array = 583 Add<HConstant>(isolate()->factory()->empty_fixed_array()); 584 Add<HStoreNamedField>( 585 object, 586 HObjectAccess::ForAllocationSiteOffset( 587 AllocationSite::kDependentCodeOffset), 588 empty_fixed_array); 589 590 // Link the object to the allocation site list 591 HValue* site_list = Add<HConstant>( 592 ExternalReference::allocation_sites_list_address(isolate())); 593 HValue* site = Add<HLoadNamedField>(site_list, nullptr, 594 HObjectAccess::ForAllocationSiteList()); 595 // TODO(mvstanton): This is a store to a weak pointer, which we may want to 596 // mark as such in order to skip the write barrier, once we have a unified 597 // system for weakness. For now we decided to keep it like this because having 598 // an initial write barrier backed store makes this pointer strong until the 599 // next GC, and allocation sites are designed to survive several GCs anyway. 600 Add<HStoreNamedField>( 601 object, 602 HObjectAccess::ForAllocationSiteOffset(AllocationSite::kWeakNextOffset), 603 site); 604 Add<HStoreNamedField>(site_list, HObjectAccess::ForAllocationSiteList(), 605 object); 606 607 HInstruction* feedback_vector = GetParameter(0); 608 HInstruction* slot = GetParameter(1); 609 Add<HStoreKeyed>(feedback_vector, slot, object, nullptr, FAST_ELEMENTS, 610 INITIALIZING_STORE); 611 return feedback_vector; 612 } 613 614 615 Handle<Code> CreateAllocationSiteStub::GenerateCode() { 616 return DoGenerateCode(this); 617 } 618 619 620 template <> 621 HValue* CodeStubGraphBuilder<CreateWeakCellStub>::BuildCodeStub() { 622 // This stub is performance sensitive, the generated code must be tuned 623 // so that it doesn't build an eager frame. 624 info()->MarkMustNotHaveEagerFrame(); 625 626 HValue* size = Add<HConstant>(WeakCell::kSize); 627 HInstruction* object = 628 Add<HAllocate>(size, HType::JSObject(), TENURED, JS_OBJECT_TYPE, 629 graph()->GetConstant0()); 630 631 Handle<Map> weak_cell_map = isolate()->factory()->weak_cell_map(); 632 AddStoreMapConstant(object, weak_cell_map); 633 634 HInstruction* value = GetParameter(CreateWeakCellDescriptor::kValueIndex); 635 Add<HStoreNamedField>(object, HObjectAccess::ForWeakCellValue(), value); 636 Add<HStoreNamedField>(object, HObjectAccess::ForWeakCellNext(), 637 graph()->GetConstantHole()); 638 639 HInstruction* feedback_vector = 640 GetParameter(CreateWeakCellDescriptor::kVectorIndex); 641 HInstruction* slot = GetParameter(CreateWeakCellDescriptor::kSlotIndex); 642 Add<HStoreKeyed>(feedback_vector, slot, object, nullptr, FAST_ELEMENTS, 643 INITIALIZING_STORE); 644 return graph()->GetConstant0(); 645 } 646 647 648 Handle<Code> CreateWeakCellStub::GenerateCode() { return DoGenerateCode(this); } 649 650 651 template <> 652 HValue* CodeStubGraphBuilder<LoadScriptContextFieldStub>::BuildCodeStub() { 653 int context_index = casted_stub()->context_index(); 654 int slot_index = casted_stub()->slot_index(); 655 656 HValue* script_context = BuildGetScriptContext(context_index); 657 return Add<HLoadNamedField>(script_context, nullptr, 658 HObjectAccess::ForContextSlot(slot_index)); 659 } 660 661 662 Handle<Code> LoadScriptContextFieldStub::GenerateCode() { 663 return DoGenerateCode(this); 664 } 665 666 667 template <> 668 HValue* CodeStubGraphBuilder<StoreScriptContextFieldStub>::BuildCodeStub() { 669 int context_index = casted_stub()->context_index(); 670 int slot_index = casted_stub()->slot_index(); 671 672 HValue* script_context = BuildGetScriptContext(context_index); 673 Add<HStoreNamedField>(script_context, 674 HObjectAccess::ForContextSlot(slot_index), 675 GetParameter(2), STORE_TO_INITIALIZED_ENTRY); 676 return GetParameter(2); 677 } 678 679 680 Handle<Code> StoreScriptContextFieldStub::GenerateCode() { 681 return DoGenerateCode(this); 682 } 683 684 HValue* CodeStubGraphBuilderBase::BuildPushElement(HValue* object, HValue* argc, 685 HValue* argument_elements, 686 ElementsKind kind) { 687 // Precheck whether all elements fit into the array. 688 if (!IsFastObjectElementsKind(kind)) { 689 LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement); 690 HValue* start = graph()->GetConstant0(); 691 HValue* key = builder.BeginBody(start, argc, Token::LT); 692 { 693 HInstruction* argument = 694 Add<HAccessArgumentsAt>(argument_elements, argc, key); 695 IfBuilder can_store(this); 696 can_store.IfNot<HIsSmiAndBranch>(argument); 697 if (IsFastDoubleElementsKind(kind)) { 698 can_store.And(); 699 can_store.IfNot<HCompareMap>(argument, 700 isolate()->factory()->heap_number_map()); 701 } 702 can_store.ThenDeopt(Deoptimizer::kFastPathFailed); 703 can_store.End(); 704 } 705 builder.EndBody(); 706 } 707 708 HValue* length = Add<HLoadNamedField>(object, nullptr, 709 HObjectAccess::ForArrayLength(kind)); 710 HValue* new_length = AddUncasted<HAdd>(length, argc); 711 HValue* max_key = AddUncasted<HSub>(new_length, graph()->GetConstant1()); 712 713 HValue* elements = Add<HLoadNamedField>(object, nullptr, 714 HObjectAccess::ForElementsPointer()); 715 elements = BuildCheckForCapacityGrow(object, elements, kind, length, max_key, 716 true, STORE); 717 718 LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement); 719 HValue* start = graph()->GetConstant0(); 720 HValue* key = builder.BeginBody(start, argc, Token::LT); 721 { 722 HValue* argument = Add<HAccessArgumentsAt>(argument_elements, argc, key); 723 HValue* index = AddUncasted<HAdd>(key, length); 724 AddElementAccess(elements, index, argument, object, nullptr, kind, STORE); 725 } 726 builder.EndBody(); 727 return new_length; 728 } 729 730 template <> 731 HValue* CodeStubGraphBuilder<FastArrayPushStub>::BuildCodeStub() { 732 // TODO(verwaest): Fix deoptimizer messages. 733 HValue* argc = GetArgumentsLength(); 734 HInstruction* argument_elements = Add<HArgumentsElements>(false, false); 735 HInstruction* object = Add<HAccessArgumentsAt>(argument_elements, argc, 736 graph()->GetConstantMinus1()); 737 BuildCheckHeapObject(object); 738 HValue* map = Add<HLoadNamedField>(object, nullptr, HObjectAccess::ForMap()); 739 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_JS_ARRAY); 740 741 // Disallow pushing onto prototypes. It might be the JSArray prototype. 742 // Disallow pushing onto non-extensible objects. 743 { 744 HValue* bit_field2 = 745 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField2()); 746 HValue* mask = 747 Add<HConstant>(static_cast<int>(Map::IsPrototypeMapBits::kMask) | 748 (1 << Map::kIsExtensible)); 749 HValue* bits = AddUncasted<HBitwise>(Token::BIT_AND, bit_field2, mask); 750 IfBuilder check(this); 751 check.If<HCompareNumericAndBranch>( 752 bits, Add<HConstant>(1 << Map::kIsExtensible), Token::NE); 753 check.ThenDeopt(Deoptimizer::kFastPathFailed); 754 check.End(); 755 } 756 757 // Disallow pushing onto arrays in dictionary named property mode. We need to 758 // figure out whether the length property is still writable. 759 { 760 HValue* bit_field3 = 761 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField3()); 762 HValue* mask = Add<HConstant>(static_cast<int>(Map::DictionaryMap::kMask)); 763 HValue* bit = AddUncasted<HBitwise>(Token::BIT_AND, bit_field3, mask); 764 IfBuilder check(this); 765 check.If<HCompareNumericAndBranch>(bit, mask, Token::EQ); 766 check.ThenDeopt(Deoptimizer::kFastPathFailed); 767 check.End(); 768 } 769 770 // Check whether the length property is writable. The length property is the 771 // only default named property on arrays. It's nonconfigurable, hence is 772 // guaranteed to stay the first property. 773 { 774 HValue* descriptors = 775 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapDescriptors()); 776 HValue* details = Add<HLoadKeyed>( 777 descriptors, Add<HConstant>(DescriptorArray::ToDetailsIndex(0)), 778 nullptr, nullptr, FAST_SMI_ELEMENTS); 779 HValue* mask = 780 Add<HConstant>(READ_ONLY << PropertyDetails::AttributesField::kShift); 781 HValue* bit = AddUncasted<HBitwise>(Token::BIT_AND, details, mask); 782 IfBuilder readonly(this); 783 readonly.If<HCompareNumericAndBranch>(bit, mask, Token::EQ); 784 readonly.ThenDeopt(Deoptimizer::kFastPathFailed); 785 readonly.End(); 786 } 787 788 HValue* null = Add<HLoadRoot>(Heap::kNullValueRootIndex); 789 HValue* empty = Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex); 790 environment()->Push(map); 791 LoopBuilder check_prototypes(this); 792 check_prototypes.BeginBody(1); 793 { 794 HValue* parent_map = environment()->Pop(); 795 HValue* prototype = Add<HLoadNamedField>(parent_map, nullptr, 796 HObjectAccess::ForPrototype()); 797 798 IfBuilder is_null(this); 799 is_null.If<HCompareObjectEqAndBranch>(prototype, null); 800 is_null.Then(); 801 check_prototypes.Break(); 802 is_null.End(); 803 804 HValue* prototype_map = 805 Add<HLoadNamedField>(prototype, nullptr, HObjectAccess::ForMap()); 806 HValue* instance_type = Add<HLoadNamedField>( 807 prototype_map, nullptr, HObjectAccess::ForMapInstanceType()); 808 IfBuilder check_instance_type(this); 809 check_instance_type.If<HCompareNumericAndBranch>( 810 instance_type, Add<HConstant>(LAST_CUSTOM_ELEMENTS_RECEIVER), 811 Token::LTE); 812 check_instance_type.ThenDeopt(Deoptimizer::kFastPathFailed); 813 check_instance_type.End(); 814 815 HValue* elements = Add<HLoadNamedField>( 816 prototype, nullptr, HObjectAccess::ForElementsPointer()); 817 IfBuilder no_elements(this); 818 no_elements.IfNot<HCompareObjectEqAndBranch>(elements, empty); 819 no_elements.ThenDeopt(Deoptimizer::kFastPathFailed); 820 no_elements.End(); 821 822 environment()->Push(prototype_map); 823 } 824 check_prototypes.EndBody(); 825 826 HValue* bit_field2 = 827 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField2()); 828 HValue* kind = BuildDecodeField<Map::ElementsKindBits>(bit_field2); 829 830 // Below we only check the upper bound of the relevant ranges to include both 831 // holey and non-holey versions. We check them in order smi, object, double 832 // since smi < object < double. 833 STATIC_ASSERT(FAST_SMI_ELEMENTS < FAST_HOLEY_SMI_ELEMENTS); 834 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS < FAST_HOLEY_ELEMENTS); 835 STATIC_ASSERT(FAST_ELEMENTS < FAST_HOLEY_ELEMENTS); 836 STATIC_ASSERT(FAST_HOLEY_ELEMENTS < FAST_HOLEY_DOUBLE_ELEMENTS); 837 STATIC_ASSERT(FAST_DOUBLE_ELEMENTS < FAST_HOLEY_DOUBLE_ELEMENTS); 838 IfBuilder has_smi_elements(this); 839 has_smi_elements.If<HCompareNumericAndBranch>( 840 kind, Add<HConstant>(FAST_HOLEY_SMI_ELEMENTS), Token::LTE); 841 has_smi_elements.Then(); 842 { 843 HValue* new_length = BuildPushElement(object, argc, argument_elements, 844 FAST_HOLEY_SMI_ELEMENTS); 845 environment()->Push(new_length); 846 } 847 has_smi_elements.Else(); 848 { 849 IfBuilder has_object_elements(this); 850 has_object_elements.If<HCompareNumericAndBranch>( 851 kind, Add<HConstant>(FAST_HOLEY_ELEMENTS), Token::LTE); 852 has_object_elements.Then(); 853 { 854 HValue* new_length = BuildPushElement(object, argc, argument_elements, 855 FAST_HOLEY_ELEMENTS); 856 environment()->Push(new_length); 857 } 858 has_object_elements.Else(); 859 { 860 IfBuilder has_double_elements(this); 861 has_double_elements.If<HCompareNumericAndBranch>( 862 kind, Add<HConstant>(FAST_HOLEY_DOUBLE_ELEMENTS), Token::LTE); 863 has_double_elements.Then(); 864 { 865 HValue* new_length = BuildPushElement(object, argc, argument_elements, 866 FAST_HOLEY_DOUBLE_ELEMENTS); 867 environment()->Push(new_length); 868 } 869 has_double_elements.ElseDeopt(Deoptimizer::kFastPathFailed); 870 has_double_elements.End(); 871 } 872 has_object_elements.End(); 873 } 874 has_smi_elements.End(); 875 876 return environment()->Pop(); 877 } 878 879 Handle<Code> FastArrayPushStub::GenerateCode() { return DoGenerateCode(this); } 880 881 template <> 882 HValue* CodeStubGraphBuilder<FastFunctionBindStub>::BuildCodeStub() { 883 // TODO(verwaest): Fix deoptimizer messages. 884 HValue* argc = GetArgumentsLength(); 885 HInstruction* argument_elements = Add<HArgumentsElements>(false, false); 886 HInstruction* object = Add<HAccessArgumentsAt>(argument_elements, argc, 887 graph()->GetConstantMinus1()); 888 BuildCheckHeapObject(object); 889 HValue* map = Add<HLoadNamedField>(object, nullptr, HObjectAccess::ForMap()); 890 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_JS_FUNCTION); 891 892 // Disallow binding of slow-mode functions. We need to figure out whether the 893 // length and name property are in the original state. 894 { 895 HValue* bit_field3 = 896 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField3()); 897 HValue* mask = Add<HConstant>(static_cast<int>(Map::DictionaryMap::kMask)); 898 HValue* bit = AddUncasted<HBitwise>(Token::BIT_AND, bit_field3, mask); 899 IfBuilder check(this); 900 check.If<HCompareNumericAndBranch>(bit, mask, Token::EQ); 901 check.ThenDeopt(Deoptimizer::kFastPathFailed); 902 check.End(); 903 } 904 905 // Check whether the length and name properties are still present as 906 // AccessorInfo objects. In that case, their value can be recomputed even if 907 // the actual value on the object changes. 908 { 909 HValue* descriptors = 910 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapDescriptors()); 911 912 HValue* descriptors_length = Add<HLoadNamedField>( 913 descriptors, nullptr, HObjectAccess::ForFixedArrayLength()); 914 IfBuilder range(this); 915 range.If<HCompareNumericAndBranch>(descriptors_length, 916 graph()->GetConstant1(), Token::LTE); 917 range.ThenDeopt(Deoptimizer::kFastPathFailed); 918 range.End(); 919 920 // Verify .length. 921 const int length_index = JSFunction::kLengthDescriptorIndex; 922 HValue* maybe_length = Add<HLoadKeyed>( 923 descriptors, Add<HConstant>(DescriptorArray::ToKeyIndex(length_index)), 924 nullptr, nullptr, FAST_ELEMENTS); 925 Unique<Name> length_string = Unique<Name>::CreateUninitialized( 926 isolate()->factory()->length_string()); 927 Add<HCheckValue>(maybe_length, length_string, false); 928 929 HValue* maybe_length_accessor = Add<HLoadKeyed>( 930 descriptors, 931 Add<HConstant>(DescriptorArray::ToValueIndex(length_index)), nullptr, 932 nullptr, FAST_ELEMENTS); 933 BuildCheckHeapObject(maybe_length_accessor); 934 Add<HCheckMaps>(maybe_length_accessor, 935 isolate()->factory()->accessor_info_map()); 936 937 // Verify .name. 938 const int name_index = JSFunction::kNameDescriptorIndex; 939 HValue* maybe_name = Add<HLoadKeyed>( 940 descriptors, Add<HConstant>(DescriptorArray::ToKeyIndex(name_index)), 941 nullptr, nullptr, FAST_ELEMENTS); 942 Unique<Name> name_string = 943 Unique<Name>::CreateUninitialized(isolate()->factory()->name_string()); 944 Add<HCheckValue>(maybe_name, name_string, false); 945 946 HValue* maybe_name_accessor = Add<HLoadKeyed>( 947 descriptors, Add<HConstant>(DescriptorArray::ToValueIndex(name_index)), 948 nullptr, nullptr, FAST_ELEMENTS); 949 BuildCheckHeapObject(maybe_name_accessor); 950 Add<HCheckMaps>(maybe_name_accessor, 951 isolate()->factory()->accessor_info_map()); 952 } 953 954 // Choose the right bound function map based on whether the target is 955 // constructable. 956 { 957 HValue* bit_field = 958 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField()); 959 HValue* mask = Add<HConstant>(static_cast<int>(1 << Map::kIsConstructor)); 960 HValue* bits = AddUncasted<HBitwise>(Token::BIT_AND, bit_field, mask); 961 962 HValue* native_context = BuildGetNativeContext(); 963 IfBuilder is_constructor(this); 964 is_constructor.If<HCompareNumericAndBranch>(bits, mask, Token::EQ); 965 is_constructor.Then(); 966 { 967 HValue* map = Add<HLoadNamedField>( 968 native_context, nullptr, 969 HObjectAccess::ForContextSlot( 970 Context::BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX)); 971 environment()->Push(map); 972 } 973 is_constructor.Else(); 974 { 975 HValue* map = Add<HLoadNamedField>( 976 native_context, nullptr, 977 HObjectAccess::ForContextSlot( 978 Context::BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX)); 979 environment()->Push(map); 980 } 981 is_constructor.End(); 982 } 983 HValue* bound_function_map = environment()->Pop(); 984 985 // Verify that __proto__ matches that of a the target bound function. 986 { 987 HValue* prototype = 988 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForPrototype()); 989 HValue* expected_prototype = Add<HLoadNamedField>( 990 bound_function_map, nullptr, HObjectAccess::ForPrototype()); 991 IfBuilder equal_prototype(this); 992 equal_prototype.IfNot<HCompareObjectEqAndBranch>(prototype, 993 expected_prototype); 994 equal_prototype.ThenDeopt(Deoptimizer::kFastPathFailed); 995 equal_prototype.End(); 996 } 997 998 // Allocate the arguments array. 999 IfBuilder empty_args(this); 1000 empty_args.If<HCompareNumericAndBranch>(argc, graph()->GetConstant1(), 1001 Token::LTE); 1002 empty_args.Then(); 1003 { environment()->Push(Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex)); } 1004 empty_args.Else(); 1005 { 1006 HValue* elements_length = AddUncasted<HSub>(argc, graph()->GetConstant1()); 1007 HValue* elements = 1008 BuildAllocateAndInitializeArray(FAST_ELEMENTS, elements_length); 1009 1010 LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement); 1011 HValue* start = graph()->GetConstant1(); 1012 HValue* key = builder.BeginBody(start, argc, Token::LT); 1013 { 1014 HValue* argument = Add<HAccessArgumentsAt>(argument_elements, argc, key); 1015 HValue* index = AddUncasted<HSub>(key, graph()->GetConstant1()); 1016 AddElementAccess(elements, index, argument, elements, nullptr, 1017 FAST_ELEMENTS, STORE); 1018 } 1019 builder.EndBody(); 1020 environment()->Push(elements); 1021 } 1022 empty_args.End(); 1023 HValue* elements = environment()->Pop(); 1024 1025 // Find the 'this' to bind. 1026 IfBuilder no_receiver(this); 1027 no_receiver.If<HCompareNumericAndBranch>(argc, graph()->GetConstant0(), 1028 Token::EQ); 1029 no_receiver.Then(); 1030 { environment()->Push(Add<HLoadRoot>(Heap::kUndefinedValueRootIndex)); } 1031 no_receiver.Else(); 1032 { 1033 environment()->Push(Add<HAccessArgumentsAt>(argument_elements, argc, 1034 graph()->GetConstant0())); 1035 } 1036 no_receiver.End(); 1037 HValue* receiver = environment()->Pop(); 1038 1039 // Allocate the resulting bound function. 1040 HValue* size = Add<HConstant>(JSBoundFunction::kSize); 1041 HValue* bound_function = 1042 Add<HAllocate>(size, HType::JSObject(), NOT_TENURED, 1043 JS_BOUND_FUNCTION_TYPE, graph()->GetConstant0()); 1044 Add<HStoreNamedField>(bound_function, HObjectAccess::ForMap(), 1045 bound_function_map); 1046 HValue* empty_fixed_array = Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex); 1047 Add<HStoreNamedField>(bound_function, HObjectAccess::ForPropertiesPointer(), 1048 empty_fixed_array); 1049 Add<HStoreNamedField>(bound_function, HObjectAccess::ForElementsPointer(), 1050 empty_fixed_array); 1051 Add<HStoreNamedField>(bound_function, HObjectAccess::ForBoundTargetFunction(), 1052 object); 1053 1054 Add<HStoreNamedField>(bound_function, HObjectAccess::ForBoundThis(), 1055 receiver); 1056 Add<HStoreNamedField>(bound_function, HObjectAccess::ForBoundArguments(), 1057 elements); 1058 1059 return bound_function; 1060 } 1061 1062 Handle<Code> FastFunctionBindStub::GenerateCode() { 1063 return DoGenerateCode(this); 1064 } 1065 1066 template <> 1067 HValue* CodeStubGraphBuilder<GrowArrayElementsStub>::BuildCodeStub() { 1068 ElementsKind kind = casted_stub()->elements_kind(); 1069 if (IsFastDoubleElementsKind(kind)) { 1070 info()->MarkAsSavesCallerDoubles(); 1071 } 1072 1073 HValue* object = GetParameter(GrowArrayElementsDescriptor::kObjectIndex); 1074 HValue* key = GetParameter(GrowArrayElementsDescriptor::kKeyIndex); 1075 1076 HValue* elements = AddLoadElements(object); 1077 HValue* current_capacity = Add<HLoadNamedField>( 1078 elements, nullptr, HObjectAccess::ForFixedArrayLength()); 1079 1080 HValue* length = 1081 casted_stub()->is_js_array() 1082 ? Add<HLoadNamedField>(object, static_cast<HValue*>(NULL), 1083 HObjectAccess::ForArrayLength(kind)) 1084 : current_capacity; 1085 1086 return BuildCheckAndGrowElementsCapacity(object, elements, kind, length, 1087 current_capacity, key); 1088 } 1089 1090 1091 Handle<Code> GrowArrayElementsStub::GenerateCode() { 1092 return DoGenerateCode(this); 1093 } 1094 1095 1096 template <> 1097 HValue* CodeStubGraphBuilder<LoadFastElementStub>::BuildCodeStub() { 1098 LoadKeyedHoleMode hole_mode = casted_stub()->convert_hole_to_undefined() 1099 ? CONVERT_HOLE_TO_UNDEFINED 1100 : NEVER_RETURN_HOLE; 1101 1102 HInstruction* load = BuildUncheckedMonomorphicElementAccess( 1103 GetParameter(LoadDescriptor::kReceiverIndex), 1104 GetParameter(LoadDescriptor::kNameIndex), NULL, 1105 casted_stub()->is_js_array(), casted_stub()->elements_kind(), LOAD, 1106 hole_mode, STANDARD_STORE); 1107 return load; 1108 } 1109 1110 1111 Handle<Code> LoadFastElementStub::GenerateCode() { 1112 return DoGenerateCode(this); 1113 } 1114 1115 1116 HLoadNamedField* CodeStubGraphBuilderBase::BuildLoadNamedField( 1117 HValue* object, FieldIndex index) { 1118 Representation representation = index.is_double() 1119 ? Representation::Double() 1120 : Representation::Tagged(); 1121 int offset = index.offset(); 1122 HObjectAccess access = index.is_inobject() 1123 ? HObjectAccess::ForObservableJSObjectOffset(offset, representation) 1124 : HObjectAccess::ForBackingStoreOffset(offset, representation); 1125 if (index.is_double() && 1126 (!FLAG_unbox_double_fields || !index.is_inobject())) { 1127 // Load the heap number. 1128 object = Add<HLoadNamedField>( 1129 object, nullptr, access.WithRepresentation(Representation::Tagged())); 1130 // Load the double value from it. 1131 access = HObjectAccess::ForHeapNumberValue(); 1132 } 1133 return Add<HLoadNamedField>(object, nullptr, access); 1134 } 1135 1136 1137 template<> 1138 HValue* CodeStubGraphBuilder<LoadFieldStub>::BuildCodeStub() { 1139 return BuildLoadNamedField(GetParameter(0), casted_stub()->index()); 1140 } 1141 1142 1143 Handle<Code> LoadFieldStub::GenerateCode() { 1144 return DoGenerateCode(this); 1145 } 1146 1147 1148 template <> 1149 HValue* CodeStubGraphBuilder<LoadConstantStub>::BuildCodeStub() { 1150 HValue* map = AddLoadMap(GetParameter(0), NULL); 1151 HObjectAccess descriptors_access = HObjectAccess::ForObservableJSObjectOffset( 1152 Map::kDescriptorsOffset, Representation::Tagged()); 1153 HValue* descriptors = Add<HLoadNamedField>(map, nullptr, descriptors_access); 1154 HObjectAccess value_access = HObjectAccess::ForObservableJSObjectOffset( 1155 DescriptorArray::GetValueOffset(casted_stub()->constant_index())); 1156 return Add<HLoadNamedField>(descriptors, nullptr, value_access); 1157 } 1158 1159 1160 Handle<Code> LoadConstantStub::GenerateCode() { return DoGenerateCode(this); } 1161 1162 1163 HValue* CodeStubGraphBuilderBase::UnmappedCase(HValue* elements, HValue* key, 1164 HValue* value) { 1165 HValue* result = NULL; 1166 HInstruction* backing_store = 1167 Add<HLoadKeyed>(elements, graph()->GetConstant1(), nullptr, nullptr, 1168 FAST_ELEMENTS, ALLOW_RETURN_HOLE); 1169 Add<HCheckMaps>(backing_store, isolate()->factory()->fixed_array_map()); 1170 HValue* backing_store_length = Add<HLoadNamedField>( 1171 backing_store, nullptr, HObjectAccess::ForFixedArrayLength()); 1172 IfBuilder in_unmapped_range(this); 1173 in_unmapped_range.If<HCompareNumericAndBranch>(key, backing_store_length, 1174 Token::LT); 1175 in_unmapped_range.Then(); 1176 { 1177 if (value == NULL) { 1178 result = Add<HLoadKeyed>(backing_store, key, nullptr, nullptr, 1179 FAST_HOLEY_ELEMENTS, NEVER_RETURN_HOLE); 1180 } else { 1181 Add<HStoreKeyed>(backing_store, key, value, nullptr, FAST_HOLEY_ELEMENTS); 1182 } 1183 } 1184 in_unmapped_range.ElseDeopt(Deoptimizer::kOutsideOfRange); 1185 in_unmapped_range.End(); 1186 return result; 1187 } 1188 1189 1190 HValue* CodeStubGraphBuilderBase::EmitKeyedSloppyArguments(HValue* receiver, 1191 HValue* key, 1192 HValue* value) { 1193 // Mapped arguments are actual arguments. Unmapped arguments are values added 1194 // to the arguments object after it was created for the call. Mapped arguments 1195 // are stored in the context at indexes given by elements[key + 2]. Unmapped 1196 // arguments are stored as regular indexed properties in the arguments array, 1197 // held at elements[1]. See NewSloppyArguments() in runtime.cc for a detailed 1198 // look at argument object construction. 1199 // 1200 // The sloppy arguments elements array has a special format: 1201 // 1202 // 0: context 1203 // 1: unmapped arguments array 1204 // 2: mapped_index0, 1205 // 3: mapped_index1, 1206 // ... 1207 // 1208 // length is 2 + min(number_of_actual_arguments, number_of_formal_arguments). 1209 // If key + 2 >= elements.length then attempt to look in the unmapped 1210 // arguments array (given by elements[1]) and return the value at key, missing 1211 // to the runtime if the unmapped arguments array is not a fixed array or if 1212 // key >= unmapped_arguments_array.length. 1213 // 1214 // Otherwise, t = elements[key + 2]. If t is the hole, then look up the value 1215 // in the unmapped arguments array, as described above. Otherwise, t is a Smi 1216 // index into the context array given at elements[0]. Return the value at 1217 // context[t]. 1218 1219 bool is_load = value == NULL; 1220 1221 key = AddUncasted<HForceRepresentation>(key, Representation::Smi()); 1222 IfBuilder positive_smi(this); 1223 positive_smi.If<HCompareNumericAndBranch>(key, graph()->GetConstant0(), 1224 Token::LT); 1225 positive_smi.ThenDeopt(Deoptimizer::kKeyIsNegative); 1226 positive_smi.End(); 1227 1228 HValue* constant_two = Add<HConstant>(2); 1229 HValue* elements = AddLoadElements(receiver, nullptr); 1230 HValue* elements_length = Add<HLoadNamedField>( 1231 elements, nullptr, HObjectAccess::ForFixedArrayLength()); 1232 HValue* adjusted_length = AddUncasted<HSub>(elements_length, constant_two); 1233 IfBuilder in_range(this); 1234 in_range.If<HCompareNumericAndBranch>(key, adjusted_length, Token::LT); 1235 in_range.Then(); 1236 { 1237 HValue* index = AddUncasted<HAdd>(key, constant_two); 1238 HInstruction* mapped_index = 1239 Add<HLoadKeyed>(elements, index, nullptr, nullptr, FAST_HOLEY_ELEMENTS, 1240 ALLOW_RETURN_HOLE); 1241 1242 IfBuilder is_valid(this); 1243 is_valid.IfNot<HCompareObjectEqAndBranch>(mapped_index, 1244 graph()->GetConstantHole()); 1245 is_valid.Then(); 1246 { 1247 // TODO(mvstanton): I'd like to assert from this point, that if the 1248 // mapped_index is not the hole that it is indeed, a smi. An unnecessary 1249 // smi check is being emitted. 1250 HValue* the_context = Add<HLoadKeyed>(elements, graph()->GetConstant0(), 1251 nullptr, nullptr, FAST_ELEMENTS); 1252 STATIC_ASSERT(Context::kHeaderSize == FixedArray::kHeaderSize); 1253 if (is_load) { 1254 HValue* result = 1255 Add<HLoadKeyed>(the_context, mapped_index, nullptr, nullptr, 1256 FAST_ELEMENTS, ALLOW_RETURN_HOLE); 1257 environment()->Push(result); 1258 } else { 1259 DCHECK(value != NULL); 1260 Add<HStoreKeyed>(the_context, mapped_index, value, nullptr, 1261 FAST_ELEMENTS); 1262 environment()->Push(value); 1263 } 1264 } 1265 is_valid.Else(); 1266 { 1267 HValue* result = UnmappedCase(elements, key, value); 1268 environment()->Push(is_load ? result : value); 1269 } 1270 is_valid.End(); 1271 } 1272 in_range.Else(); 1273 { 1274 HValue* result = UnmappedCase(elements, key, value); 1275 environment()->Push(is_load ? result : value); 1276 } 1277 in_range.End(); 1278 1279 return environment()->Pop(); 1280 } 1281 1282 1283 template <> 1284 HValue* CodeStubGraphBuilder<KeyedLoadSloppyArgumentsStub>::BuildCodeStub() { 1285 HValue* receiver = GetParameter(LoadDescriptor::kReceiverIndex); 1286 HValue* key = GetParameter(LoadDescriptor::kNameIndex); 1287 1288 return EmitKeyedSloppyArguments(receiver, key, NULL); 1289 } 1290 1291 1292 Handle<Code> KeyedLoadSloppyArgumentsStub::GenerateCode() { 1293 return DoGenerateCode(this); 1294 } 1295 1296 1297 template <> 1298 HValue* CodeStubGraphBuilder<KeyedStoreSloppyArgumentsStub>::BuildCodeStub() { 1299 HValue* receiver = GetParameter(StoreDescriptor::kReceiverIndex); 1300 HValue* key = GetParameter(StoreDescriptor::kNameIndex); 1301 HValue* value = GetParameter(StoreDescriptor::kValueIndex); 1302 1303 return EmitKeyedSloppyArguments(receiver, key, value); 1304 } 1305 1306 1307 Handle<Code> KeyedStoreSloppyArgumentsStub::GenerateCode() { 1308 return DoGenerateCode(this); 1309 } 1310 1311 1312 void CodeStubGraphBuilderBase::BuildStoreNamedField( 1313 HValue* object, HValue* value, FieldIndex index, 1314 Representation representation, bool transition_to_field) { 1315 DCHECK(!index.is_double() || representation.IsDouble()); 1316 int offset = index.offset(); 1317 HObjectAccess access = 1318 index.is_inobject() 1319 ? HObjectAccess::ForObservableJSObjectOffset(offset, representation) 1320 : HObjectAccess::ForBackingStoreOffset(offset, representation); 1321 1322 if (representation.IsDouble()) { 1323 if (!FLAG_unbox_double_fields || !index.is_inobject()) { 1324 HObjectAccess heap_number_access = 1325 access.WithRepresentation(Representation::Tagged()); 1326 if (transition_to_field) { 1327 // The store requires a mutable HeapNumber to be allocated. 1328 NoObservableSideEffectsScope no_side_effects(this); 1329 HInstruction* heap_number_size = Add<HConstant>(HeapNumber::kSize); 1330 1331 // TODO(hpayer): Allocation site pretenuring support. 1332 HInstruction* heap_number = 1333 Add<HAllocate>(heap_number_size, HType::HeapObject(), NOT_TENURED, 1334 MUTABLE_HEAP_NUMBER_TYPE, graph()->GetConstant0()); 1335 AddStoreMapConstant(heap_number, 1336 isolate()->factory()->mutable_heap_number_map()); 1337 Add<HStoreNamedField>(heap_number, HObjectAccess::ForHeapNumberValue(), 1338 value); 1339 // Store the new mutable heap number into the object. 1340 access = heap_number_access; 1341 value = heap_number; 1342 } else { 1343 // Load the heap number. 1344 object = Add<HLoadNamedField>(object, nullptr, heap_number_access); 1345 // Store the double value into it. 1346 access = HObjectAccess::ForHeapNumberValue(); 1347 } 1348 } 1349 } else if (representation.IsHeapObject()) { 1350 BuildCheckHeapObject(value); 1351 } 1352 1353 Add<HStoreNamedField>(object, access, value, INITIALIZING_STORE); 1354 } 1355 1356 1357 template <> 1358 HValue* CodeStubGraphBuilder<StoreFieldStub>::BuildCodeStub() { 1359 BuildStoreNamedField(GetParameter(0), GetParameter(2), casted_stub()->index(), 1360 casted_stub()->representation(), false); 1361 return GetParameter(2); 1362 } 1363 1364 1365 Handle<Code> StoreFieldStub::GenerateCode() { return DoGenerateCode(this); } 1366 1367 1368 template <> 1369 HValue* CodeStubGraphBuilder<StoreTransitionStub>::BuildCodeStub() { 1370 HValue* object = GetParameter(StoreTransitionHelper::ReceiverIndex()); 1371 HValue* value = GetParameter(StoreTransitionHelper::ValueIndex()); 1372 StoreTransitionStub::StoreMode store_mode = casted_stub()->store_mode(); 1373 1374 if (store_mode != StoreTransitionStub::StoreMapOnly) { 1375 value = GetParameter(StoreTransitionHelper::ValueIndex()); 1376 Representation representation = casted_stub()->representation(); 1377 if (representation.IsDouble()) { 1378 // In case we are storing a double, assure that the value is a double 1379 // before manipulating the properties backing store. Otherwise the actual 1380 // store may deopt, leaving the backing store in an overallocated state. 1381 value = AddUncasted<HForceRepresentation>(value, representation); 1382 } 1383 } 1384 1385 switch (store_mode) { 1386 case StoreTransitionStub::ExtendStorageAndStoreMapAndValue: { 1387 HValue* properties = Add<HLoadNamedField>( 1388 object, nullptr, HObjectAccess::ForPropertiesPointer()); 1389 HValue* length = AddLoadFixedArrayLength(properties); 1390 HValue* delta = 1391 Add<HConstant>(static_cast<int32_t>(JSObject::kFieldsAdded)); 1392 HValue* new_capacity = AddUncasted<HAdd>(length, delta); 1393 1394 // Grow properties array. 1395 ElementsKind kind = FAST_ELEMENTS; 1396 Add<HBoundsCheck>(new_capacity, 1397 Add<HConstant>((Page::kMaxRegularHeapObjectSize - 1398 FixedArray::kHeaderSize) >> 1399 ElementsKindToShiftSize(kind))); 1400 1401 // Reuse this code for properties backing store allocation. 1402 HValue* new_properties = 1403 BuildAllocateAndInitializeArray(kind, new_capacity); 1404 1405 BuildCopyProperties(properties, new_properties, length, new_capacity); 1406 1407 Add<HStoreNamedField>(object, HObjectAccess::ForPropertiesPointer(), 1408 new_properties); 1409 } 1410 // Fall through. 1411 case StoreTransitionStub::StoreMapAndValue: 1412 // Store the new value into the "extended" object. 1413 BuildStoreNamedField(object, value, casted_stub()->index(), 1414 casted_stub()->representation(), true); 1415 // Fall through. 1416 1417 case StoreTransitionStub::StoreMapOnly: 1418 // And finally update the map. 1419 Add<HStoreNamedField>(object, HObjectAccess::ForMap(), 1420 GetParameter(StoreTransitionHelper::MapIndex())); 1421 break; 1422 } 1423 return value; 1424 } 1425 1426 1427 Handle<Code> StoreTransitionStub::GenerateCode() { 1428 return DoGenerateCode(this); 1429 } 1430 1431 1432 template <> 1433 HValue* CodeStubGraphBuilder<StoreFastElementStub>::BuildCodeStub() { 1434 BuildUncheckedMonomorphicElementAccess( 1435 GetParameter(StoreDescriptor::kReceiverIndex), 1436 GetParameter(StoreDescriptor::kNameIndex), 1437 GetParameter(StoreDescriptor::kValueIndex), casted_stub()->is_js_array(), 1438 casted_stub()->elements_kind(), STORE, NEVER_RETURN_HOLE, 1439 casted_stub()->store_mode()); 1440 1441 return GetParameter(2); 1442 } 1443 1444 1445 Handle<Code> StoreFastElementStub::GenerateCode() { 1446 return DoGenerateCode(this); 1447 } 1448 1449 1450 template <> 1451 HValue* CodeStubGraphBuilder<TransitionElementsKindStub>::BuildCodeStub() { 1452 ElementsKind const from_kind = casted_stub()->from_kind(); 1453 ElementsKind const to_kind = casted_stub()->to_kind(); 1454 HValue* const object = GetParameter(0); 1455 HValue* const map = GetParameter(1); 1456 1457 // The {object} is known to be a JSObject (otherwise it wouldn't have elements 1458 // anyways). 1459 object->set_type(HType::JSObject()); 1460 1461 info()->MarkAsSavesCallerDoubles(); 1462 1463 DCHECK_IMPLIES(IsFastHoleyElementsKind(from_kind), 1464 IsFastHoleyElementsKind(to_kind)); 1465 1466 if (AllocationSite::GetMode(from_kind, to_kind) == TRACK_ALLOCATION_SITE) { 1467 Add<HTrapAllocationMemento>(object); 1468 } 1469 1470 if (!IsSimpleMapChangeTransition(from_kind, to_kind)) { 1471 HInstruction* elements = AddLoadElements(object); 1472 1473 IfBuilder if_objecthaselements(this); 1474 if_objecthaselements.IfNot<HCompareObjectEqAndBranch>( 1475 elements, Add<HConstant>(isolate()->factory()->empty_fixed_array())); 1476 if_objecthaselements.Then(); 1477 { 1478 // Determine the elements capacity. 1479 HInstruction* elements_length = AddLoadFixedArrayLength(elements); 1480 1481 // Determine the effective (array) length. 1482 IfBuilder if_objectisarray(this); 1483 if_objectisarray.If<HHasInstanceTypeAndBranch>(object, JS_ARRAY_TYPE); 1484 if_objectisarray.Then(); 1485 { 1486 // The {object} is a JSArray, load the special "length" property. 1487 Push(Add<HLoadNamedField>(object, nullptr, 1488 HObjectAccess::ForArrayLength(from_kind))); 1489 } 1490 if_objectisarray.Else(); 1491 { 1492 // The {object} is some other JSObject. 1493 Push(elements_length); 1494 } 1495 if_objectisarray.End(); 1496 HValue* length = Pop(); 1497 1498 BuildGrowElementsCapacity(object, elements, from_kind, to_kind, length, 1499 elements_length); 1500 } 1501 if_objecthaselements.End(); 1502 } 1503 1504 Add<HStoreNamedField>(object, HObjectAccess::ForMap(), map); 1505 1506 return object; 1507 } 1508 1509 1510 Handle<Code> TransitionElementsKindStub::GenerateCode() { 1511 return DoGenerateCode(this); 1512 } 1513 1514 template <> 1515 HValue* CodeStubGraphBuilder<BinaryOpICStub>::BuildCodeInitializedStub() { 1516 BinaryOpICState state = casted_stub()->state(); 1517 1518 HValue* left = GetParameter(BinaryOpICStub::kLeft); 1519 HValue* right = GetParameter(BinaryOpICStub::kRight); 1520 1521 Type* left_type = state.GetLeftType(); 1522 Type* right_type = state.GetRightType(); 1523 Type* result_type = state.GetResultType(); 1524 1525 DCHECK(!left_type->Is(Type::None()) && !right_type->Is(Type::None()) && 1526 (state.HasSideEffects() || !result_type->Is(Type::None()))); 1527 1528 HValue* result = NULL; 1529 HAllocationMode allocation_mode(NOT_TENURED); 1530 if (state.op() == Token::ADD && 1531 (left_type->Maybe(Type::String()) || right_type->Maybe(Type::String())) && 1532 !left_type->Is(Type::String()) && !right_type->Is(Type::String())) { 1533 // For the generic add stub a fast case for string addition is performance 1534 // critical. 1535 if (left_type->Maybe(Type::String())) { 1536 IfBuilder if_leftisstring(this); 1537 if_leftisstring.If<HIsStringAndBranch>(left); 1538 if_leftisstring.Then(); 1539 { 1540 Push(BuildBinaryOperation(state.op(), left, right, Type::String(), 1541 right_type, result_type, 1542 state.fixed_right_arg(), allocation_mode)); 1543 } 1544 if_leftisstring.Else(); 1545 { 1546 Push(BuildBinaryOperation(state.op(), left, right, left_type, 1547 right_type, result_type, 1548 state.fixed_right_arg(), allocation_mode)); 1549 } 1550 if_leftisstring.End(); 1551 result = Pop(); 1552 } else { 1553 IfBuilder if_rightisstring(this); 1554 if_rightisstring.If<HIsStringAndBranch>(right); 1555 if_rightisstring.Then(); 1556 { 1557 Push(BuildBinaryOperation(state.op(), left, right, left_type, 1558 Type::String(), result_type, 1559 state.fixed_right_arg(), allocation_mode)); 1560 } 1561 if_rightisstring.Else(); 1562 { 1563 Push(BuildBinaryOperation(state.op(), left, right, left_type, 1564 right_type, result_type, 1565 state.fixed_right_arg(), allocation_mode)); 1566 } 1567 if_rightisstring.End(); 1568 result = Pop(); 1569 } 1570 } else { 1571 result = BuildBinaryOperation(state.op(), left, right, left_type, 1572 right_type, result_type, 1573 state.fixed_right_arg(), allocation_mode); 1574 } 1575 1576 // If we encounter a generic argument, the number conversion is 1577 // observable, thus we cannot afford to bail out after the fact. 1578 if (!state.HasSideEffects()) { 1579 result = EnforceNumberType(result, result_type); 1580 } 1581 1582 return result; 1583 } 1584 1585 1586 Handle<Code> BinaryOpICStub::GenerateCode() { 1587 return DoGenerateCode(this); 1588 } 1589 1590 1591 template <> 1592 HValue* CodeStubGraphBuilder<BinaryOpWithAllocationSiteStub>::BuildCodeStub() { 1593 BinaryOpICState state = casted_stub()->state(); 1594 1595 HValue* allocation_site = GetParameter( 1596 BinaryOpWithAllocationSiteStub::kAllocationSite); 1597 HValue* left = GetParameter(BinaryOpWithAllocationSiteStub::kLeft); 1598 HValue* right = GetParameter(BinaryOpWithAllocationSiteStub::kRight); 1599 1600 Type* left_type = state.GetLeftType(); 1601 Type* right_type = state.GetRightType(); 1602 Type* result_type = state.GetResultType(); 1603 HAllocationMode allocation_mode(allocation_site); 1604 1605 return BuildBinaryOperation(state.op(), left, right, left_type, right_type, 1606 result_type, state.fixed_right_arg(), 1607 allocation_mode); 1608 } 1609 1610 1611 Handle<Code> BinaryOpWithAllocationSiteStub::GenerateCode() { 1612 return DoGenerateCode(this); 1613 } 1614 1615 1616 HValue* CodeStubGraphBuilderBase::BuildToString(HValue* input, bool convert) { 1617 if (!convert) return BuildCheckString(input); 1618 IfBuilder if_inputissmi(this); 1619 HValue* inputissmi = if_inputissmi.If<HIsSmiAndBranch>(input); 1620 if_inputissmi.Then(); 1621 { 1622 // Convert the input smi to a string. 1623 Push(BuildNumberToString(input, Type::SignedSmall())); 1624 } 1625 if_inputissmi.Else(); 1626 { 1627 HValue* input_map = 1628 Add<HLoadNamedField>(input, inputissmi, HObjectAccess::ForMap()); 1629 HValue* input_instance_type = Add<HLoadNamedField>( 1630 input_map, inputissmi, HObjectAccess::ForMapInstanceType()); 1631 IfBuilder if_inputisstring(this); 1632 if_inputisstring.If<HCompareNumericAndBranch>( 1633 input_instance_type, Add<HConstant>(FIRST_NONSTRING_TYPE), Token::LT); 1634 if_inputisstring.Then(); 1635 { 1636 // The input is already a string. 1637 Push(input); 1638 } 1639 if_inputisstring.Else(); 1640 { 1641 // Convert to primitive first (if necessary), see 1642 // ES6 section 12.7.3 The Addition operator. 1643 IfBuilder if_inputisprimitive(this); 1644 STATIC_ASSERT(FIRST_PRIMITIVE_TYPE == FIRST_TYPE); 1645 if_inputisprimitive.If<HCompareNumericAndBranch>( 1646 input_instance_type, Add<HConstant>(LAST_PRIMITIVE_TYPE), Token::LTE); 1647 if_inputisprimitive.Then(); 1648 { 1649 // The input is already a primitive. 1650 Push(input); 1651 } 1652 if_inputisprimitive.Else(); 1653 { 1654 // Convert the input to a primitive. 1655 Push(BuildToPrimitive(input, input_map)); 1656 } 1657 if_inputisprimitive.End(); 1658 // Convert the primitive to a string value. 1659 ToStringStub stub(isolate()); 1660 HValue* values[] = {context(), Pop()}; 1661 Push(AddUncasted<HCallWithDescriptor>(Add<HConstant>(stub.GetCode()), 0, 1662 stub.GetCallInterfaceDescriptor(), 1663 ArrayVector(values))); 1664 } 1665 if_inputisstring.End(); 1666 } 1667 if_inputissmi.End(); 1668 return Pop(); 1669 } 1670 1671 1672 HValue* CodeStubGraphBuilderBase::BuildToPrimitive(HValue* input, 1673 HValue* input_map) { 1674 // Get the native context of the caller. 1675 HValue* native_context = BuildGetNativeContext(); 1676 1677 // Determine the initial map of the %ObjectPrototype%. 1678 HValue* object_function_prototype_map = 1679 Add<HLoadNamedField>(native_context, nullptr, 1680 HObjectAccess::ForContextSlot( 1681 Context::OBJECT_FUNCTION_PROTOTYPE_MAP_INDEX)); 1682 1683 // Determine the initial map of the %StringPrototype%. 1684 HValue* string_function_prototype_map = 1685 Add<HLoadNamedField>(native_context, nullptr, 1686 HObjectAccess::ForContextSlot( 1687 Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX)); 1688 1689 // Determine the initial map of the String function. 1690 HValue* string_function = Add<HLoadNamedField>( 1691 native_context, nullptr, 1692 HObjectAccess::ForContextSlot(Context::STRING_FUNCTION_INDEX)); 1693 HValue* string_function_initial_map = Add<HLoadNamedField>( 1694 string_function, nullptr, HObjectAccess::ForPrototypeOrInitialMap()); 1695 1696 // Determine the map of the [[Prototype]] of {input}. 1697 HValue* input_prototype = 1698 Add<HLoadNamedField>(input_map, nullptr, HObjectAccess::ForPrototype()); 1699 HValue* input_prototype_map = 1700 Add<HLoadNamedField>(input_prototype, nullptr, HObjectAccess::ForMap()); 1701 1702 // For string wrappers (JSValue instances with [[StringData]] internal 1703 // fields), we can shortcirciut the ToPrimitive if 1704 // 1705 // (a) the {input} map matches the initial map of the String function, 1706 // (b) the {input} [[Prototype]] is the unmodified %StringPrototype% (i.e. 1707 // no one monkey-patched toString, @@toPrimitive or valueOf), and 1708 // (c) the %ObjectPrototype% (i.e. the [[Prototype]] of the 1709 // %StringPrototype%) is also unmodified, that is no one sneaked a 1710 // @@toPrimitive into the %ObjectPrototype%. 1711 // 1712 // If all these assumptions hold, we can just take the [[StringData]] value 1713 // and return it. 1714 // TODO(bmeurer): This just repairs a regression introduced by removing the 1715 // weird (and broken) intrinsic %_IsStringWrapperSafeForDefaultValue, which 1716 // was intendend to something similar to this, although less efficient and 1717 // wrong in the presence of @@toPrimitive. Long-term we might want to move 1718 // into the direction of having a ToPrimitiveStub that can do common cases 1719 // while staying in JavaScript land (i.e. not going to C++). 1720 IfBuilder if_inputisstringwrapper(this); 1721 if_inputisstringwrapper.If<HCompareObjectEqAndBranch>( 1722 input_map, string_function_initial_map); 1723 if_inputisstringwrapper.And(); 1724 if_inputisstringwrapper.If<HCompareObjectEqAndBranch>( 1725 input_prototype_map, string_function_prototype_map); 1726 if_inputisstringwrapper.And(); 1727 if_inputisstringwrapper.If<HCompareObjectEqAndBranch>( 1728 Add<HLoadNamedField>(Add<HLoadNamedField>(input_prototype_map, nullptr, 1729 HObjectAccess::ForPrototype()), 1730 nullptr, HObjectAccess::ForMap()), 1731 object_function_prototype_map); 1732 if_inputisstringwrapper.Then(); 1733 { 1734 Push(BuildLoadNamedField( 1735 input, FieldIndex::ForInObjectOffset(JSValue::kValueOffset))); 1736 } 1737 if_inputisstringwrapper.Else(); 1738 { 1739 // TODO(bmeurer): Add support for fast ToPrimitive conversion using 1740 // a dedicated ToPrimitiveStub. 1741 Add<HPushArguments>(input); 1742 Push(Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kToPrimitive), 1)); 1743 } 1744 if_inputisstringwrapper.End(); 1745 return Pop(); 1746 } 1747 1748 1749 template <> 1750 HValue* CodeStubGraphBuilder<StringAddStub>::BuildCodeInitializedStub() { 1751 StringAddStub* stub = casted_stub(); 1752 StringAddFlags flags = stub->flags(); 1753 PretenureFlag pretenure_flag = stub->pretenure_flag(); 1754 1755 HValue* left = GetParameter(StringAddStub::kLeft); 1756 HValue* right = GetParameter(StringAddStub::kRight); 1757 1758 // Make sure that both arguments are strings if not known in advance. 1759 if ((flags & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) { 1760 left = 1761 BuildToString(left, (flags & STRING_ADD_CONVERT) == STRING_ADD_CONVERT); 1762 } 1763 if ((flags & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) { 1764 right = BuildToString(right, 1765 (flags & STRING_ADD_CONVERT) == STRING_ADD_CONVERT); 1766 } 1767 1768 return BuildStringAdd(left, right, HAllocationMode(pretenure_flag)); 1769 } 1770 1771 1772 Handle<Code> StringAddStub::GenerateCode() { 1773 return DoGenerateCode(this); 1774 } 1775 1776 template <> 1777 HValue* CodeStubGraphBuilder<ToBooleanICStub>::BuildCodeInitializedStub() { 1778 ToBooleanICStub* stub = casted_stub(); 1779 IfBuilder if_true(this); 1780 if_true.If<HBranch>(GetParameter(0), stub->types()); 1781 if_true.Then(); 1782 if_true.Return(graph()->GetConstantTrue()); 1783 if_true.Else(); 1784 if_true.End(); 1785 return graph()->GetConstantFalse(); 1786 } 1787 1788 Handle<Code> ToBooleanICStub::GenerateCode() { return DoGenerateCode(this); } 1789 1790 template <> 1791 HValue* CodeStubGraphBuilder<StoreGlobalStub>::BuildCodeInitializedStub() { 1792 StoreGlobalStub* stub = casted_stub(); 1793 HParameter* value = GetParameter(StoreDescriptor::kValueIndex); 1794 if (stub->check_global()) { 1795 // Check that the map of the global has not changed: use a placeholder map 1796 // that will be replaced later with the global object's map. 1797 HParameter* proxy = GetParameter(StoreDescriptor::kReceiverIndex); 1798 HValue* proxy_map = 1799 Add<HLoadNamedField>(proxy, nullptr, HObjectAccess::ForMap()); 1800 HValue* global = 1801 Add<HLoadNamedField>(proxy_map, nullptr, HObjectAccess::ForPrototype()); 1802 HValue* map_cell = Add<HConstant>(isolate()->factory()->NewWeakCell( 1803 StoreGlobalStub::global_map_placeholder(isolate()))); 1804 HValue* expected_map = Add<HLoadNamedField>( 1805 map_cell, nullptr, HObjectAccess::ForWeakCellValue()); 1806 HValue* map = 1807 Add<HLoadNamedField>(global, nullptr, HObjectAccess::ForMap()); 1808 IfBuilder map_check(this); 1809 map_check.IfNot<HCompareObjectEqAndBranch>(expected_map, map); 1810 map_check.ThenDeopt(Deoptimizer::kUnknownMap); 1811 map_check.End(); 1812 } 1813 1814 HValue* weak_cell = Add<HConstant>(isolate()->factory()->NewWeakCell( 1815 StoreGlobalStub::property_cell_placeholder(isolate()))); 1816 HValue* cell = Add<HLoadNamedField>(weak_cell, nullptr, 1817 HObjectAccess::ForWeakCellValue()); 1818 Add<HCheckHeapObject>(cell); 1819 HObjectAccess access = HObjectAccess::ForPropertyCellValue(); 1820 // Load the payload of the global parameter cell. A hole indicates that the 1821 // cell has been invalidated and that the store must be handled by the 1822 // runtime. 1823 HValue* cell_contents = Add<HLoadNamedField>(cell, nullptr, access); 1824 1825 auto cell_type = stub->cell_type(); 1826 if (cell_type == PropertyCellType::kConstant || 1827 cell_type == PropertyCellType::kUndefined) { 1828 // This is always valid for all states a cell can be in. 1829 IfBuilder builder(this); 1830 builder.If<HCompareObjectEqAndBranch>(cell_contents, value); 1831 builder.Then(); 1832 builder.ElseDeopt( 1833 Deoptimizer::kUnexpectedCellContentsInConstantGlobalStore); 1834 builder.End(); 1835 } else { 1836 IfBuilder builder(this); 1837 HValue* hole_value = graph()->GetConstantHole(); 1838 builder.If<HCompareObjectEqAndBranch>(cell_contents, hole_value); 1839 builder.Then(); 1840 builder.Deopt(Deoptimizer::kUnexpectedCellContentsInGlobalStore); 1841 builder.Else(); 1842 // When dealing with constant types, the type may be allowed to change, as 1843 // long as optimized code remains valid. 1844 if (cell_type == PropertyCellType::kConstantType) { 1845 switch (stub->constant_type()) { 1846 case PropertyCellConstantType::kSmi: 1847 access = access.WithRepresentation(Representation::Smi()); 1848 break; 1849 case PropertyCellConstantType::kStableMap: { 1850 // It is sufficient here to check that the value and cell contents 1851 // have identical maps, no matter if they are stable or not or if they 1852 // are the maps that were originally in the cell or not. If optimized 1853 // code will deopt when a cell has a unstable map and if it has a 1854 // dependency on a stable map, it will deopt if the map destabilizes. 1855 Add<HCheckHeapObject>(value); 1856 Add<HCheckHeapObject>(cell_contents); 1857 HValue* expected_map = Add<HLoadNamedField>(cell_contents, nullptr, 1858 HObjectAccess::ForMap()); 1859 HValue* map = 1860 Add<HLoadNamedField>(value, nullptr, HObjectAccess::ForMap()); 1861 IfBuilder map_check(this); 1862 map_check.IfNot<HCompareObjectEqAndBranch>(expected_map, map); 1863 map_check.ThenDeopt(Deoptimizer::kUnknownMap); 1864 map_check.End(); 1865 access = access.WithRepresentation(Representation::HeapObject()); 1866 break; 1867 } 1868 } 1869 } 1870 Add<HStoreNamedField>(cell, access, value); 1871 builder.End(); 1872 } 1873 1874 return value; 1875 } 1876 1877 1878 Handle<Code> StoreGlobalStub::GenerateCode() { 1879 return DoGenerateCode(this); 1880 } 1881 1882 1883 template <> 1884 HValue* CodeStubGraphBuilder<ElementsTransitionAndStoreStub>::BuildCodeStub() { 1885 HValue* object = GetParameter(StoreTransitionHelper::ReceiverIndex()); 1886 HValue* key = GetParameter(StoreTransitionHelper::NameIndex()); 1887 HValue* value = GetParameter(StoreTransitionHelper::ValueIndex()); 1888 HValue* map = GetParameter(StoreTransitionHelper::MapIndex()); 1889 1890 if (FLAG_trace_elements_transitions) { 1891 // Tracing elements transitions is the job of the runtime. 1892 Add<HDeoptimize>(Deoptimizer::kTracingElementsTransitions, 1893 Deoptimizer::EAGER); 1894 } else { 1895 info()->MarkAsSavesCallerDoubles(); 1896 1897 BuildTransitionElementsKind(object, map, 1898 casted_stub()->from_kind(), 1899 casted_stub()->to_kind(), 1900 casted_stub()->is_jsarray()); 1901 1902 BuildUncheckedMonomorphicElementAccess(object, key, value, 1903 casted_stub()->is_jsarray(), 1904 casted_stub()->to_kind(), 1905 STORE, ALLOW_RETURN_HOLE, 1906 casted_stub()->store_mode()); 1907 } 1908 1909 return value; 1910 } 1911 1912 1913 Handle<Code> ElementsTransitionAndStoreStub::GenerateCode() { 1914 return DoGenerateCode(this); 1915 } 1916 1917 1918 template <> 1919 HValue* CodeStubGraphBuilder<ToObjectStub>::BuildCodeStub() { 1920 HValue* receiver = GetParameter(TypeConversionDescriptor::kArgumentIndex); 1921 return BuildToObject(receiver); 1922 } 1923 1924 1925 Handle<Code> ToObjectStub::GenerateCode() { return DoGenerateCode(this); } 1926 1927 1928 template<> 1929 HValue* CodeStubGraphBuilder<FastNewClosureStub>::BuildCodeStub() { 1930 Counters* counters = isolate()->counters(); 1931 Factory* factory = isolate()->factory(); 1932 HInstruction* empty_fixed_array = 1933 Add<HConstant>(factory->empty_fixed_array()); 1934 HInstruction* empty_literals_array = 1935 Add<HConstant>(factory->empty_literals_array()); 1936 HValue* shared_info = GetParameter(0); 1937 1938 AddIncrementCounter(counters->fast_new_closure_total()); 1939 1940 // Create a new closure from the given function info in new space 1941 HValue* size = Add<HConstant>(JSFunction::kSize); 1942 HInstruction* js_function = 1943 Add<HAllocate>(size, HType::JSObject(), NOT_TENURED, JS_FUNCTION_TYPE, 1944 graph()->GetConstant0()); 1945 1946 int map_index = Context::FunctionMapIndex(casted_stub()->language_mode(), 1947 casted_stub()->kind()); 1948 1949 // Compute the function map in the current native context and set that 1950 // as the map of the allocated object. 1951 HInstruction* native_context = BuildGetNativeContext(); 1952 HInstruction* map_slot_value = Add<HLoadNamedField>( 1953 native_context, nullptr, HObjectAccess::ForContextSlot(map_index)); 1954 Add<HStoreNamedField>(js_function, HObjectAccess::ForMap(), map_slot_value); 1955 1956 // Initialize the rest of the function. 1957 Add<HStoreNamedField>(js_function, HObjectAccess::ForPropertiesPointer(), 1958 empty_fixed_array); 1959 Add<HStoreNamedField>(js_function, HObjectAccess::ForElementsPointer(), 1960 empty_fixed_array); 1961 Add<HStoreNamedField>(js_function, HObjectAccess::ForLiteralsPointer(), 1962 empty_literals_array); 1963 Add<HStoreNamedField>(js_function, HObjectAccess::ForPrototypeOrInitialMap(), 1964 graph()->GetConstantHole()); 1965 Add<HStoreNamedField>( 1966 js_function, HObjectAccess::ForSharedFunctionInfoPointer(), shared_info); 1967 Add<HStoreNamedField>(js_function, HObjectAccess::ForFunctionContextPointer(), 1968 context()); 1969 1970 Handle<Code> lazy_builtin( 1971 isolate()->builtins()->builtin(Builtins::kCompileLazy)); 1972 HConstant* lazy = Add<HConstant>(lazy_builtin); 1973 Add<HStoreCodeEntry>(js_function, lazy); 1974 Add<HStoreNamedField>(js_function, 1975 HObjectAccess::ForNextFunctionLinkPointer(), 1976 graph()->GetConstantUndefined()); 1977 1978 return js_function; 1979 } 1980 1981 1982 Handle<Code> FastNewClosureStub::GenerateCode() { 1983 return DoGenerateCode(this); 1984 } 1985 1986 1987 template<> 1988 HValue* CodeStubGraphBuilder<FastNewContextStub>::BuildCodeStub() { 1989 int length = casted_stub()->slots() + Context::MIN_CONTEXT_SLOTS; 1990 1991 // Get the function. 1992 HParameter* function = GetParameter(FastNewContextStub::kFunction); 1993 1994 // Allocate the context in new space. 1995 HAllocate* function_context = Add<HAllocate>( 1996 Add<HConstant>(length * kPointerSize + FixedArray::kHeaderSize), 1997 HType::HeapObject(), NOT_TENURED, FIXED_ARRAY_TYPE, 1998 graph()->GetConstant0()); 1999 2000 // Set up the object header. 2001 AddStoreMapConstant(function_context, 2002 isolate()->factory()->function_context_map()); 2003 Add<HStoreNamedField>(function_context, 2004 HObjectAccess::ForFixedArrayLength(), 2005 Add<HConstant>(length)); 2006 2007 // Set up the fixed slots. 2008 Add<HStoreNamedField>(function_context, 2009 HObjectAccess::ForContextSlot(Context::CLOSURE_INDEX), 2010 function); 2011 Add<HStoreNamedField>(function_context, 2012 HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX), 2013 context()); 2014 Add<HStoreNamedField>(function_context, 2015 HObjectAccess::ForContextSlot(Context::EXTENSION_INDEX), 2016 graph()->GetConstantHole()); 2017 2018 // Copy the native context from the previous context. 2019 HValue* native_context = Add<HLoadNamedField>( 2020 context(), nullptr, 2021 HObjectAccess::ForContextSlot(Context::NATIVE_CONTEXT_INDEX)); 2022 Add<HStoreNamedField>(function_context, HObjectAccess::ForContextSlot( 2023 Context::NATIVE_CONTEXT_INDEX), 2024 native_context); 2025 2026 // Initialize the rest of the slots to undefined. 2027 for (int i = Context::MIN_CONTEXT_SLOTS; i < length; ++i) { 2028 Add<HStoreNamedField>(function_context, 2029 HObjectAccess::ForContextSlot(i), 2030 graph()->GetConstantUndefined()); 2031 } 2032 2033 return function_context; 2034 } 2035 2036 2037 Handle<Code> FastNewContextStub::GenerateCode() { 2038 return DoGenerateCode(this); 2039 } 2040 2041 2042 template <> 2043 HValue* CodeStubGraphBuilder<LoadDictionaryElementStub>::BuildCodeStub() { 2044 HValue* receiver = GetParameter(LoadDescriptor::kReceiverIndex); 2045 HValue* key = GetParameter(LoadDescriptor::kNameIndex); 2046 2047 Add<HCheckSmi>(key); 2048 2049 HValue* elements = AddLoadElements(receiver); 2050 2051 HValue* hash = BuildElementIndexHash(key); 2052 2053 return BuildUncheckedDictionaryElementLoad(receiver, elements, key, hash); 2054 } 2055 2056 2057 Handle<Code> LoadDictionaryElementStub::GenerateCode() { 2058 return DoGenerateCode(this); 2059 } 2060 2061 2062 template<> 2063 HValue* CodeStubGraphBuilder<RegExpConstructResultStub>::BuildCodeStub() { 2064 // Determine the parameters. 2065 HValue* length = GetParameter(RegExpConstructResultStub::kLength); 2066 HValue* index = GetParameter(RegExpConstructResultStub::kIndex); 2067 HValue* input = GetParameter(RegExpConstructResultStub::kInput); 2068 2069 // TODO(turbofan): This codestub has regressed to need a frame on ia32 at some 2070 // point and wasn't caught since it wasn't built in the snapshot. We should 2071 // probably just replace with a TurboFan stub rather than fixing it. 2072 #if !(V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87) 2073 info()->MarkMustNotHaveEagerFrame(); 2074 #endif 2075 2076 return BuildRegExpConstructResult(length, index, input); 2077 } 2078 2079 2080 Handle<Code> RegExpConstructResultStub::GenerateCode() { 2081 return DoGenerateCode(this); 2082 } 2083 2084 2085 template <> 2086 class CodeStubGraphBuilder<KeyedLoadGenericStub> 2087 : public CodeStubGraphBuilderBase { 2088 public: 2089 explicit CodeStubGraphBuilder(CompilationInfo* info, CodeStub* stub) 2090 : CodeStubGraphBuilderBase(info, stub) {} 2091 2092 protected: 2093 virtual HValue* BuildCodeStub(); 2094 2095 void BuildElementsKindLimitCheck(HGraphBuilder::IfBuilder* if_builder, 2096 HValue* bit_field2, 2097 ElementsKind kind); 2098 2099 void BuildFastElementLoad(HGraphBuilder::IfBuilder* if_builder, 2100 HValue* receiver, 2101 HValue* key, 2102 HValue* instance_type, 2103 HValue* bit_field2, 2104 ElementsKind kind); 2105 2106 KeyedLoadGenericStub* casted_stub() { 2107 return static_cast<KeyedLoadGenericStub*>(stub()); 2108 } 2109 }; 2110 2111 2112 void CodeStubGraphBuilder<KeyedLoadGenericStub>::BuildElementsKindLimitCheck( 2113 HGraphBuilder::IfBuilder* if_builder, HValue* bit_field2, 2114 ElementsKind kind) { 2115 ElementsKind next_kind = static_cast<ElementsKind>(kind + 1); 2116 HValue* kind_limit = Add<HConstant>( 2117 static_cast<int>(Map::ElementsKindBits::encode(next_kind))); 2118 2119 if_builder->If<HCompareNumericAndBranch>(bit_field2, kind_limit, Token::LT); 2120 if_builder->Then(); 2121 } 2122 2123 2124 void CodeStubGraphBuilder<KeyedLoadGenericStub>::BuildFastElementLoad( 2125 HGraphBuilder::IfBuilder* if_builder, HValue* receiver, HValue* key, 2126 HValue* instance_type, HValue* bit_field2, ElementsKind kind) { 2127 BuildElementsKindLimitCheck(if_builder, bit_field2, kind); 2128 2129 IfBuilder js_array_check(this); 2130 js_array_check.If<HCompareNumericAndBranch>( 2131 instance_type, Add<HConstant>(JS_ARRAY_TYPE), Token::EQ); 2132 js_array_check.Then(); 2133 Push(BuildUncheckedMonomorphicElementAccess(receiver, key, NULL, 2134 true, kind, 2135 LOAD, NEVER_RETURN_HOLE, 2136 STANDARD_STORE)); 2137 js_array_check.Else(); 2138 Push(BuildUncheckedMonomorphicElementAccess(receiver, key, NULL, 2139 false, kind, 2140 LOAD, NEVER_RETURN_HOLE, 2141 STANDARD_STORE)); 2142 js_array_check.End(); 2143 } 2144 2145 2146 HValue* CodeStubGraphBuilder<KeyedLoadGenericStub>::BuildCodeStub() { 2147 HValue* receiver = GetParameter(LoadDescriptor::kReceiverIndex); 2148 HValue* key = GetParameter(LoadDescriptor::kNameIndex); 2149 // Split into a smi/integer case and unique string case. 2150 HIfContinuation index_name_split_continuation(graph()->CreateBasicBlock(), 2151 graph()->CreateBasicBlock()); 2152 2153 BuildKeyedIndexCheck(key, &index_name_split_continuation); 2154 2155 IfBuilder index_name_split(this, &index_name_split_continuation); 2156 index_name_split.Then(); 2157 { 2158 // Key is an index (number) 2159 key = Pop(); 2160 2161 int bit_field_mask = (1 << Map::kIsAccessCheckNeeded) | 2162 (1 << Map::kHasIndexedInterceptor); 2163 BuildJSObjectCheck(receiver, bit_field_mask); 2164 2165 HValue* map = 2166 Add<HLoadNamedField>(receiver, nullptr, HObjectAccess::ForMap()); 2167 2168 HValue* instance_type = 2169 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapInstanceType()); 2170 2171 HValue* bit_field2 = 2172 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField2()); 2173 2174 IfBuilder kind_if(this); 2175 BuildFastElementLoad(&kind_if, receiver, key, instance_type, bit_field2, 2176 FAST_HOLEY_ELEMENTS); 2177 2178 kind_if.Else(); 2179 { 2180 BuildFastElementLoad(&kind_if, receiver, key, instance_type, bit_field2, 2181 FAST_HOLEY_DOUBLE_ELEMENTS); 2182 } 2183 kind_if.Else(); 2184 2185 // The DICTIONARY_ELEMENTS check generates a "kind_if.Then" 2186 BuildElementsKindLimitCheck(&kind_if, bit_field2, DICTIONARY_ELEMENTS); 2187 { 2188 HValue* elements = AddLoadElements(receiver); 2189 2190 HValue* hash = BuildElementIndexHash(key); 2191 2192 Push(BuildUncheckedDictionaryElementLoad(receiver, elements, key, hash)); 2193 } 2194 kind_if.Else(); 2195 2196 // The SLOW_SLOPPY_ARGUMENTS_ELEMENTS check generates a "kind_if.Then" 2197 STATIC_ASSERT(FAST_SLOPPY_ARGUMENTS_ELEMENTS < 2198 SLOW_SLOPPY_ARGUMENTS_ELEMENTS); 2199 BuildElementsKindLimitCheck(&kind_if, bit_field2, 2200 SLOW_SLOPPY_ARGUMENTS_ELEMENTS); 2201 // Non-strict elements are not handled. 2202 Add<HDeoptimize>(Deoptimizer::kNonStrictElementsInKeyedLoadGenericStub, 2203 Deoptimizer::EAGER); 2204 Push(graph()->GetConstant0()); 2205 2206 kind_if.ElseDeopt( 2207 Deoptimizer::kElementsKindUnhandledInKeyedLoadGenericStub); 2208 2209 kind_if.End(); 2210 } 2211 index_name_split.Else(); 2212 { 2213 // Key is a unique string. 2214 key = Pop(); 2215 2216 int bit_field_mask = (1 << Map::kIsAccessCheckNeeded) | 2217 (1 << Map::kHasNamedInterceptor); 2218 BuildJSObjectCheck(receiver, bit_field_mask); 2219 2220 HIfContinuation continuation; 2221 BuildTestForDictionaryProperties(receiver, &continuation); 2222 IfBuilder if_dict_properties(this, &continuation); 2223 if_dict_properties.Then(); 2224 { 2225 // Key is string, properties are dictionary mode 2226 BuildNonGlobalObjectCheck(receiver); 2227 2228 HValue* properties = Add<HLoadNamedField>( 2229 receiver, nullptr, HObjectAccess::ForPropertiesPointer()); 2230 2231 HValue* hash = 2232 Add<HLoadNamedField>(key, nullptr, HObjectAccess::ForNameHashField()); 2233 2234 hash = AddUncasted<HShr>(hash, Add<HConstant>(Name::kHashShift)); 2235 2236 HValue* value = 2237 BuildUncheckedDictionaryElementLoad(receiver, properties, key, hash); 2238 Push(value); 2239 } 2240 if_dict_properties.Else(); 2241 { 2242 // TODO(dcarney): don't use keyed lookup cache, but convert to use 2243 // megamorphic stub cache. 2244 UNREACHABLE(); 2245 // Key is string, properties are fast mode 2246 HValue* hash = BuildKeyedLookupCacheHash(receiver, key); 2247 2248 ExternalReference cache_keys_ref = 2249 ExternalReference::keyed_lookup_cache_keys(isolate()); 2250 HValue* cache_keys = Add<HConstant>(cache_keys_ref); 2251 2252 HValue* map = 2253 Add<HLoadNamedField>(receiver, nullptr, HObjectAccess::ForMap()); 2254 HValue* base_index = AddUncasted<HMul>(hash, Add<HConstant>(2)); 2255 base_index->ClearFlag(HValue::kCanOverflow); 2256 2257 HIfContinuation inline_or_runtime_continuation( 2258 graph()->CreateBasicBlock(), graph()->CreateBasicBlock()); 2259 { 2260 IfBuilder lookup_ifs[KeyedLookupCache::kEntriesPerBucket]; 2261 for (int probe = 0; probe < KeyedLookupCache::kEntriesPerBucket; 2262 ++probe) { 2263 IfBuilder* lookup_if = &lookup_ifs[probe]; 2264 lookup_if->Initialize(this); 2265 int probe_base = probe * KeyedLookupCache::kEntryLength; 2266 HValue* map_index = AddUncasted<HAdd>( 2267 base_index, 2268 Add<HConstant>(probe_base + KeyedLookupCache::kMapIndex)); 2269 map_index->ClearFlag(HValue::kCanOverflow); 2270 HValue* key_index = AddUncasted<HAdd>( 2271 base_index, 2272 Add<HConstant>(probe_base + KeyedLookupCache::kKeyIndex)); 2273 key_index->ClearFlag(HValue::kCanOverflow); 2274 HValue* map_to_check = 2275 Add<HLoadKeyed>(cache_keys, map_index, nullptr, nullptr, 2276 FAST_ELEMENTS, NEVER_RETURN_HOLE, 0); 2277 lookup_if->If<HCompareObjectEqAndBranch>(map_to_check, map); 2278 lookup_if->And(); 2279 HValue* key_to_check = 2280 Add<HLoadKeyed>(cache_keys, key_index, nullptr, nullptr, 2281 FAST_ELEMENTS, NEVER_RETURN_HOLE, 0); 2282 lookup_if->If<HCompareObjectEqAndBranch>(key_to_check, key); 2283 lookup_if->Then(); 2284 { 2285 ExternalReference cache_field_offsets_ref = 2286 ExternalReference::keyed_lookup_cache_field_offsets(isolate()); 2287 HValue* cache_field_offsets = 2288 Add<HConstant>(cache_field_offsets_ref); 2289 HValue* index = AddUncasted<HAdd>(hash, Add<HConstant>(probe)); 2290 index->ClearFlag(HValue::kCanOverflow); 2291 HValue* property_index = 2292 Add<HLoadKeyed>(cache_field_offsets, index, nullptr, cache_keys, 2293 INT32_ELEMENTS, NEVER_RETURN_HOLE, 0); 2294 Push(property_index); 2295 } 2296 lookup_if->Else(); 2297 } 2298 for (int i = 0; i < KeyedLookupCache::kEntriesPerBucket; ++i) { 2299 lookup_ifs[i].JoinContinuation(&inline_or_runtime_continuation); 2300 } 2301 } 2302 2303 IfBuilder inline_or_runtime(this, &inline_or_runtime_continuation); 2304 inline_or_runtime.Then(); 2305 { 2306 // Found a cached index, load property inline. 2307 Push(Add<HLoadFieldByIndex>(receiver, Pop())); 2308 } 2309 inline_or_runtime.Else(); 2310 { 2311 // KeyedLookupCache miss; call runtime. 2312 Add<HPushArguments>(receiver, key); 2313 Push(Add<HCallRuntime>( 2314 Runtime::FunctionForId(Runtime::kKeyedGetProperty), 2)); 2315 } 2316 inline_or_runtime.End(); 2317 } 2318 if_dict_properties.End(); 2319 } 2320 index_name_split.End(); 2321 2322 return Pop(); 2323 } 2324 2325 2326 Handle<Code> KeyedLoadGenericStub::GenerateCode() { 2327 return DoGenerateCode(this); 2328 } 2329 2330 } // namespace internal 2331 } // namespace v8 2332