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/v8.h" 6 7 #include "src/bailout-reason.h" 8 #include "src/code-stubs.h" 9 #include "src/field-index.h" 10 #include "src/hydrogen.h" 11 #include "src/lithium.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 CodeStubGraphBuilderBase(Isolate* isolate, HydrogenCodeStub* stub) 38 : HGraphBuilder(&info_), 39 arguments_length_(NULL), 40 info_(stub, isolate), 41 descriptor_(stub), 42 context_(NULL) { 43 int parameter_count = descriptor_.GetEnvironmentParameterCount(); 44 parameters_.Reset(new HParameter*[parameter_count]); 45 } 46 virtual bool BuildGraph(); 47 48 protected: 49 virtual HValue* BuildCodeStub() = 0; 50 HParameter* GetParameter(int parameter) { 51 DCHECK(parameter < descriptor_.GetEnvironmentParameterCount()); 52 return parameters_[parameter]; 53 } 54 HValue* GetArgumentsLength() { 55 // This is initialized in BuildGraph() 56 DCHECK(arguments_length_ != NULL); 57 return arguments_length_; 58 } 59 CompilationInfo* info() { return &info_; } 60 HydrogenCodeStub* stub() { return info_.code_stub(); } 61 HContext* context() { return context_; } 62 Isolate* isolate() { return info_.isolate(); } 63 64 HLoadNamedField* BuildLoadNamedField(HValue* object, 65 FieldIndex index); 66 void BuildStoreNamedField(HValue* object, HValue* value, FieldIndex index, 67 Representation representation); 68 69 enum ArgumentClass { 70 NONE, 71 SINGLE, 72 MULTIPLE 73 }; 74 75 HValue* UnmappedCase(HValue* elements, HValue* key); 76 77 HValue* BuildArrayConstructor(ElementsKind kind, 78 AllocationSiteOverrideMode override_mode, 79 ArgumentClass argument_class); 80 HValue* BuildInternalArrayConstructor(ElementsKind kind, 81 ArgumentClass argument_class); 82 83 // BuildCheckAndInstallOptimizedCode emits code to install the optimized 84 // function found in the optimized code map at map_index in js_function, if 85 // the function at map_index matches the given native_context. Builder is 86 // left in the "Then()" state after the install. 87 void BuildCheckAndInstallOptimizedCode(HValue* js_function, 88 HValue* native_context, 89 IfBuilder* builder, 90 HValue* optimized_map, 91 HValue* map_index); 92 void BuildInstallCode(HValue* js_function, HValue* shared_info); 93 94 HInstruction* LoadFromOptimizedCodeMap(HValue* optimized_map, 95 HValue* iterator, 96 int field_offset); 97 void BuildInstallFromOptimizedCodeMap(HValue* js_function, 98 HValue* shared_info, 99 HValue* native_context); 100 101 private: 102 HValue* BuildArraySingleArgumentConstructor(JSArrayBuilder* builder); 103 HValue* BuildArrayNArgumentsConstructor(JSArrayBuilder* builder, 104 ElementsKind kind); 105 106 SmartArrayPointer<HParameter*> parameters_; 107 HValue* arguments_length_; 108 CompilationInfoWithZone info_; 109 CodeStubDescriptor descriptor_; 110 HContext* context_; 111 }; 112 113 114 bool CodeStubGraphBuilderBase::BuildGraph() { 115 // Update the static counter each time a new code stub is generated. 116 isolate()->counters()->code_stubs()->Increment(); 117 118 if (FLAG_trace_hydrogen_stubs) { 119 const char* name = CodeStub::MajorName(stub()->MajorKey(), false); 120 PrintF("-----------------------------------------------------------\n"); 121 PrintF("Compiling stub %s using hydrogen\n", name); 122 isolate()->GetHTracer()->TraceCompilation(&info_); 123 } 124 125 int param_count = descriptor_.GetEnvironmentParameterCount(); 126 HEnvironment* start_environment = graph()->start_environment(); 127 HBasicBlock* next_block = CreateBasicBlock(start_environment); 128 Goto(next_block); 129 next_block->SetJoinId(BailoutId::StubEntry()); 130 set_current_block(next_block); 131 132 bool runtime_stack_params = descriptor_.stack_parameter_count().is_valid(); 133 HInstruction* stack_parameter_count = NULL; 134 for (int i = 0; i < param_count; ++i) { 135 Representation r = descriptor_.GetEnvironmentParameterRepresentation(i); 136 HParameter* param = Add<HParameter>(i, 137 HParameter::REGISTER_PARAMETER, r); 138 start_environment->Bind(i, param); 139 parameters_[i] = param; 140 if (descriptor_.IsEnvironmentParameterCountRegister(i)) { 141 param->set_type(HType::Smi()); 142 stack_parameter_count = param; 143 arguments_length_ = stack_parameter_count; 144 } 145 } 146 147 DCHECK(!runtime_stack_params || arguments_length_ != NULL); 148 if (!runtime_stack_params) { 149 stack_parameter_count = graph()->GetConstantMinus1(); 150 arguments_length_ = graph()->GetConstant0(); 151 } 152 153 context_ = Add<HContext>(); 154 start_environment->BindContext(context_); 155 156 Add<HSimulate>(BailoutId::StubEntry()); 157 158 NoObservableSideEffectsScope no_effects(this); 159 160 HValue* return_value = BuildCodeStub(); 161 162 // We might have extra expressions to pop from the stack in addition to the 163 // arguments above. 164 HInstruction* stack_pop_count = stack_parameter_count; 165 if (descriptor_.function_mode() == JS_FUNCTION_STUB_MODE) { 166 if (!stack_parameter_count->IsConstant() && 167 descriptor_.hint_stack_parameter_count() < 0) { 168 HInstruction* constant_one = graph()->GetConstant1(); 169 stack_pop_count = AddUncasted<HAdd>(stack_parameter_count, constant_one); 170 stack_pop_count->ClearFlag(HValue::kCanOverflow); 171 // TODO(mvstanton): verify that stack_parameter_count+1 really fits in a 172 // smi. 173 } else { 174 int count = descriptor_.hint_stack_parameter_count(); 175 stack_pop_count = Add<HConstant>(count); 176 } 177 } 178 179 if (current_block() != NULL) { 180 HReturn* hreturn_instruction = New<HReturn>(return_value, 181 stack_pop_count); 182 FinishCurrentBlock(hreturn_instruction); 183 } 184 return true; 185 } 186 187 188 template <class Stub> 189 class CodeStubGraphBuilder: public CodeStubGraphBuilderBase { 190 public: 191 CodeStubGraphBuilder(Isolate* isolate, Stub* stub) 192 : CodeStubGraphBuilderBase(isolate, stub) {} 193 194 protected: 195 virtual HValue* BuildCodeStub() { 196 if (casted_stub()->IsUninitialized()) { 197 return BuildCodeUninitializedStub(); 198 } else { 199 return BuildCodeInitializedStub(); 200 } 201 } 202 203 virtual HValue* BuildCodeInitializedStub() { 204 UNIMPLEMENTED(); 205 return NULL; 206 } 207 208 virtual HValue* BuildCodeUninitializedStub() { 209 // Force a deopt that falls back to the runtime. 210 HValue* undefined = graph()->GetConstantUndefined(); 211 IfBuilder builder(this); 212 builder.IfNot<HCompareObjectEqAndBranch, HValue*>(undefined, undefined); 213 builder.Then(); 214 builder.ElseDeopt("Forced deopt to runtime"); 215 return undefined; 216 } 217 218 Stub* casted_stub() { return static_cast<Stub*>(stub()); } 219 }; 220 221 222 Handle<Code> HydrogenCodeStub::GenerateLightweightMissCode( 223 ExternalReference miss) { 224 Factory* factory = isolate()->factory(); 225 226 // Generate the new code. 227 MacroAssembler masm(isolate(), NULL, 256); 228 229 { 230 // Update the static counter each time a new code stub is generated. 231 isolate()->counters()->code_stubs()->Increment(); 232 233 // Generate the code for the stub. 234 masm.set_generating_stub(true); 235 NoCurrentFrameScope scope(&masm); 236 GenerateLightweightMiss(&masm, miss); 237 } 238 239 // Create the code object. 240 CodeDesc desc; 241 masm.GetCode(&desc); 242 243 // Copy the generated code into a heap object. 244 Code::Flags flags = Code::ComputeFlags( 245 GetCodeKind(), 246 GetICState(), 247 GetExtraICState(), 248 GetStubType()); 249 Handle<Code> new_object = factory->NewCode( 250 desc, flags, masm.CodeObject(), NeedsImmovableCode()); 251 return new_object; 252 } 253 254 255 template <class Stub> 256 static Handle<Code> DoGenerateCode(Stub* stub) { 257 Isolate* isolate = stub->isolate(); 258 CodeStubDescriptor descriptor(stub); 259 260 // If we are uninitialized we can use a light-weight stub to enter 261 // the runtime that is significantly faster than using the standard 262 // stub-failure deopt mechanism. 263 if (stub->IsUninitialized() && descriptor.has_miss_handler()) { 264 DCHECK(!descriptor.stack_parameter_count().is_valid()); 265 return stub->GenerateLightweightMissCode(descriptor.miss_handler()); 266 } 267 base::ElapsedTimer timer; 268 if (FLAG_profile_hydrogen_code_stub_compilation) { 269 timer.Start(); 270 } 271 CodeStubGraphBuilder<Stub> builder(isolate, stub); 272 LChunk* chunk = OptimizeGraph(builder.CreateGraph()); 273 // TODO(yangguo) remove this once the code serializer handles code stubs. 274 if (FLAG_serialize_toplevel) chunk->info()->PrepareForSerializing(); 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]" << endl; 280 } 281 return code; 282 } 283 284 285 template <> 286 HValue* CodeStubGraphBuilder<ToNumberStub>::BuildCodeStub() { 287 HValue* value = GetParameter(0); 288 289 // Check if the parameter is already a SMI or heap number. 290 IfBuilder if_number(this); 291 if_number.If<HIsSmiAndBranch>(value); 292 if_number.OrIf<HCompareMap>(value, isolate()->factory()->heap_number_map()); 293 if_number.Then(); 294 295 // Return the number. 296 Push(value); 297 298 if_number.Else(); 299 300 // Convert the parameter to number using the builtin. 301 HValue* function = AddLoadJSBuiltin(Builtins::TO_NUMBER); 302 Add<HPushArguments>(value); 303 Push(Add<HInvokeFunction>(function, 1)); 304 305 if_number.End(); 306 307 return Pop(); 308 } 309 310 311 Handle<Code> ToNumberStub::GenerateCode() { 312 return DoGenerateCode(this); 313 } 314 315 316 template <> 317 HValue* CodeStubGraphBuilder<NumberToStringStub>::BuildCodeStub() { 318 info()->MarkAsSavesCallerDoubles(); 319 HValue* number = GetParameter(NumberToStringStub::kNumber); 320 return BuildNumberToString(number, Type::Number(zone())); 321 } 322 323 324 Handle<Code> NumberToStringStub::GenerateCode() { 325 return DoGenerateCode(this); 326 } 327 328 329 template <> 330 HValue* CodeStubGraphBuilder<FastCloneShallowArrayStub>::BuildCodeStub() { 331 Factory* factory = isolate()->factory(); 332 HValue* undefined = graph()->GetConstantUndefined(); 333 AllocationSiteMode alloc_site_mode = casted_stub()->allocation_site_mode(); 334 335 // This stub is very performance sensitive, the generated code must be tuned 336 // so that it doesn't build and eager frame. 337 info()->MarkMustNotHaveEagerFrame(); 338 339 HInstruction* allocation_site = Add<HLoadKeyed>(GetParameter(0), 340 GetParameter(1), 341 static_cast<HValue*>(NULL), 342 FAST_ELEMENTS); 343 IfBuilder checker(this); 344 checker.IfNot<HCompareObjectEqAndBranch, HValue*>(allocation_site, 345 undefined); 346 checker.Then(); 347 348 HObjectAccess access = HObjectAccess::ForAllocationSiteOffset( 349 AllocationSite::kTransitionInfoOffset); 350 HInstruction* boilerplate = Add<HLoadNamedField>( 351 allocation_site, static_cast<HValue*>(NULL), access); 352 HValue* elements = AddLoadElements(boilerplate); 353 HValue* capacity = AddLoadFixedArrayLength(elements); 354 IfBuilder zero_capacity(this); 355 zero_capacity.If<HCompareNumericAndBranch>(capacity, graph()->GetConstant0(), 356 Token::EQ); 357 zero_capacity.Then(); 358 Push(BuildCloneShallowArrayEmpty(boilerplate, 359 allocation_site, 360 alloc_site_mode)); 361 zero_capacity.Else(); 362 IfBuilder if_fixed_cow(this); 363 if_fixed_cow.If<HCompareMap>(elements, factory->fixed_cow_array_map()); 364 if_fixed_cow.Then(); 365 Push(BuildCloneShallowArrayCow(boilerplate, 366 allocation_site, 367 alloc_site_mode, 368 FAST_ELEMENTS)); 369 if_fixed_cow.Else(); 370 IfBuilder if_fixed(this); 371 if_fixed.If<HCompareMap>(elements, factory->fixed_array_map()); 372 if_fixed.Then(); 373 Push(BuildCloneShallowArrayNonEmpty(boilerplate, 374 allocation_site, 375 alloc_site_mode, 376 FAST_ELEMENTS)); 377 378 if_fixed.Else(); 379 Push(BuildCloneShallowArrayNonEmpty(boilerplate, 380 allocation_site, 381 alloc_site_mode, 382 FAST_DOUBLE_ELEMENTS)); 383 if_fixed.End(); 384 if_fixed_cow.End(); 385 zero_capacity.End(); 386 387 checker.ElseDeopt("Uninitialized boilerplate literals"); 388 checker.End(); 389 390 return environment()->Pop(); 391 } 392 393 394 Handle<Code> FastCloneShallowArrayStub::GenerateCode() { 395 return DoGenerateCode(this); 396 } 397 398 399 template <> 400 HValue* CodeStubGraphBuilder<FastCloneShallowObjectStub>::BuildCodeStub() { 401 HValue* undefined = graph()->GetConstantUndefined(); 402 403 HInstruction* allocation_site = Add<HLoadKeyed>(GetParameter(0), 404 GetParameter(1), 405 static_cast<HValue*>(NULL), 406 FAST_ELEMENTS); 407 408 IfBuilder checker(this); 409 checker.IfNot<HCompareObjectEqAndBranch, HValue*>(allocation_site, 410 undefined); 411 checker.And(); 412 413 HObjectAccess access = HObjectAccess::ForAllocationSiteOffset( 414 AllocationSite::kTransitionInfoOffset); 415 HInstruction* boilerplate = Add<HLoadNamedField>( 416 allocation_site, static_cast<HValue*>(NULL), access); 417 418 int size = JSObject::kHeaderSize + casted_stub()->length() * kPointerSize; 419 int object_size = size; 420 if (FLAG_allocation_site_pretenuring) { 421 size += AllocationMemento::kSize; 422 } 423 424 HValue* boilerplate_map = Add<HLoadNamedField>( 425 boilerplate, static_cast<HValue*>(NULL), 426 HObjectAccess::ForMap()); 427 HValue* boilerplate_size = Add<HLoadNamedField>( 428 boilerplate_map, static_cast<HValue*>(NULL), 429 HObjectAccess::ForMapInstanceSize()); 430 HValue* size_in_words = Add<HConstant>(object_size >> kPointerSizeLog2); 431 checker.If<HCompareNumericAndBranch>(boilerplate_size, 432 size_in_words, Token::EQ); 433 checker.Then(); 434 435 HValue* size_in_bytes = Add<HConstant>(size); 436 437 HInstruction* object = Add<HAllocate>(size_in_bytes, HType::JSObject(), 438 NOT_TENURED, JS_OBJECT_TYPE); 439 440 for (int i = 0; i < object_size; i += kPointerSize) { 441 HObjectAccess access = HObjectAccess::ForObservableJSObjectOffset(i); 442 Add<HStoreNamedField>( 443 object, access, Add<HLoadNamedField>( 444 boilerplate, static_cast<HValue*>(NULL), access)); 445 } 446 447 DCHECK(FLAG_allocation_site_pretenuring || (size == object_size)); 448 if (FLAG_allocation_site_pretenuring) { 449 BuildCreateAllocationMemento( 450 object, Add<HConstant>(object_size), allocation_site); 451 } 452 453 environment()->Push(object); 454 checker.ElseDeopt("Uninitialized boilerplate in fast clone"); 455 checker.End(); 456 457 return environment()->Pop(); 458 } 459 460 461 Handle<Code> FastCloneShallowObjectStub::GenerateCode() { 462 return DoGenerateCode(this); 463 } 464 465 466 template <> 467 HValue* CodeStubGraphBuilder<CreateAllocationSiteStub>::BuildCodeStub() { 468 HValue* size = Add<HConstant>(AllocationSite::kSize); 469 HInstruction* object = Add<HAllocate>(size, HType::JSObject(), TENURED, 470 JS_OBJECT_TYPE); 471 472 // Store the map 473 Handle<Map> allocation_site_map = isolate()->factory()->allocation_site_map(); 474 AddStoreMapConstant(object, allocation_site_map); 475 476 // Store the payload (smi elements kind) 477 HValue* initial_elements_kind = Add<HConstant>(GetInitialFastElementsKind()); 478 Add<HStoreNamedField>(object, 479 HObjectAccess::ForAllocationSiteOffset( 480 AllocationSite::kTransitionInfoOffset), 481 initial_elements_kind); 482 483 // Unlike literals, constructed arrays don't have nested sites 484 Add<HStoreNamedField>(object, 485 HObjectAccess::ForAllocationSiteOffset( 486 AllocationSite::kNestedSiteOffset), 487 graph()->GetConstant0()); 488 489 // Pretenuring calculation field. 490 Add<HStoreNamedField>(object, 491 HObjectAccess::ForAllocationSiteOffset( 492 AllocationSite::kPretenureDataOffset), 493 graph()->GetConstant0()); 494 495 // Pretenuring memento creation count field. 496 Add<HStoreNamedField>(object, 497 HObjectAccess::ForAllocationSiteOffset( 498 AllocationSite::kPretenureCreateCountOffset), 499 graph()->GetConstant0()); 500 501 // Store an empty fixed array for the code dependency. 502 HConstant* empty_fixed_array = 503 Add<HConstant>(isolate()->factory()->empty_fixed_array()); 504 Add<HStoreNamedField>( 505 object, 506 HObjectAccess::ForAllocationSiteOffset( 507 AllocationSite::kDependentCodeOffset), 508 empty_fixed_array); 509 510 // Link the object to the allocation site list 511 HValue* site_list = Add<HConstant>( 512 ExternalReference::allocation_sites_list_address(isolate())); 513 HValue* site = Add<HLoadNamedField>( 514 site_list, static_cast<HValue*>(NULL), 515 HObjectAccess::ForAllocationSiteList()); 516 // TODO(mvstanton): This is a store to a weak pointer, which we may want to 517 // mark as such in order to skip the write barrier, once we have a unified 518 // system for weakness. For now we decided to keep it like this because having 519 // an initial write barrier backed store makes this pointer strong until the 520 // next GC, and allocation sites are designed to survive several GCs anyway. 521 Add<HStoreNamedField>( 522 object, 523 HObjectAccess::ForAllocationSiteOffset(AllocationSite::kWeakNextOffset), 524 site); 525 Add<HStoreNamedField>(site_list, HObjectAccess::ForAllocationSiteList(), 526 object); 527 528 HInstruction* feedback_vector = GetParameter(0); 529 HInstruction* slot = GetParameter(1); 530 Add<HStoreKeyed>(feedback_vector, slot, object, FAST_ELEMENTS, 531 INITIALIZING_STORE); 532 return feedback_vector; 533 } 534 535 536 Handle<Code> CreateAllocationSiteStub::GenerateCode() { 537 return DoGenerateCode(this); 538 } 539 540 541 template <> 542 HValue* CodeStubGraphBuilder<LoadFastElementStub>::BuildCodeStub() { 543 HInstruction* load = BuildUncheckedMonomorphicElementAccess( 544 GetParameter(LoadDescriptor::kReceiverIndex), 545 GetParameter(LoadDescriptor::kNameIndex), NULL, 546 casted_stub()->is_js_array(), casted_stub()->elements_kind(), LOAD, 547 NEVER_RETURN_HOLE, STANDARD_STORE); 548 return load; 549 } 550 551 552 Handle<Code> LoadFastElementStub::GenerateCode() { 553 return DoGenerateCode(this); 554 } 555 556 557 HLoadNamedField* CodeStubGraphBuilderBase::BuildLoadNamedField( 558 HValue* object, FieldIndex index) { 559 Representation representation = index.is_double() 560 ? Representation::Double() 561 : Representation::Tagged(); 562 int offset = index.offset(); 563 HObjectAccess access = index.is_inobject() 564 ? HObjectAccess::ForObservableJSObjectOffset(offset, representation) 565 : HObjectAccess::ForBackingStoreOffset(offset, representation); 566 if (index.is_double()) { 567 // Load the heap number. 568 object = Add<HLoadNamedField>( 569 object, static_cast<HValue*>(NULL), 570 access.WithRepresentation(Representation::Tagged())); 571 // Load the double value from it. 572 access = HObjectAccess::ForHeapNumberValue(); 573 } 574 return Add<HLoadNamedField>(object, static_cast<HValue*>(NULL), access); 575 } 576 577 578 template<> 579 HValue* CodeStubGraphBuilder<LoadFieldStub>::BuildCodeStub() { 580 return BuildLoadNamedField(GetParameter(0), casted_stub()->index()); 581 } 582 583 584 Handle<Code> LoadFieldStub::GenerateCode() { 585 return DoGenerateCode(this); 586 } 587 588 589 template <> 590 HValue* CodeStubGraphBuilder<LoadConstantStub>::BuildCodeStub() { 591 HValue* map = AddLoadMap(GetParameter(0), NULL); 592 HObjectAccess descriptors_access = HObjectAccess::ForObservableJSObjectOffset( 593 Map::kDescriptorsOffset, Representation::Tagged()); 594 HValue* descriptors = 595 Add<HLoadNamedField>(map, static_cast<HValue*>(NULL), descriptors_access); 596 HObjectAccess value_access = HObjectAccess::ForObservableJSObjectOffset( 597 DescriptorArray::GetValueOffset(casted_stub()->constant_index())); 598 return Add<HLoadNamedField>(descriptors, static_cast<HValue*>(NULL), 599 value_access); 600 } 601 602 603 Handle<Code> LoadConstantStub::GenerateCode() { return DoGenerateCode(this); } 604 605 606 HValue* CodeStubGraphBuilderBase::UnmappedCase(HValue* elements, HValue* key) { 607 HValue* result; 608 HInstruction* backing_store = Add<HLoadKeyed>( 609 elements, graph()->GetConstant1(), static_cast<HValue*>(NULL), 610 FAST_ELEMENTS, ALLOW_RETURN_HOLE); 611 Add<HCheckMaps>(backing_store, isolate()->factory()->fixed_array_map()); 612 HValue* backing_store_length = 613 Add<HLoadNamedField>(backing_store, static_cast<HValue*>(NULL), 614 HObjectAccess::ForFixedArrayLength()); 615 IfBuilder in_unmapped_range(this); 616 in_unmapped_range.If<HCompareNumericAndBranch>(key, backing_store_length, 617 Token::LT); 618 in_unmapped_range.Then(); 619 { 620 result = Add<HLoadKeyed>(backing_store, key, static_cast<HValue*>(NULL), 621 FAST_HOLEY_ELEMENTS, NEVER_RETURN_HOLE); 622 } 623 in_unmapped_range.ElseDeopt("Outside of range"); 624 in_unmapped_range.End(); 625 return result; 626 } 627 628 629 template <> 630 HValue* CodeStubGraphBuilder<KeyedLoadSloppyArgumentsStub>::BuildCodeStub() { 631 HValue* receiver = GetParameter(LoadDescriptor::kReceiverIndex); 632 HValue* key = GetParameter(LoadDescriptor::kNameIndex); 633 634 // Mapped arguments are actual arguments. Unmapped arguments are values added 635 // to the arguments object after it was created for the call. Mapped arguments 636 // are stored in the context at indexes given by elements[key + 2]. Unmapped 637 // arguments are stored as regular indexed properties in the arguments array, 638 // held at elements[1]. See NewSloppyArguments() in runtime.cc for a detailed 639 // look at argument object construction. 640 // 641 // The sloppy arguments elements array has a special format: 642 // 643 // 0: context 644 // 1: unmapped arguments array 645 // 2: mapped_index0, 646 // 3: mapped_index1, 647 // ... 648 // 649 // length is 2 + min(number_of_actual_arguments, number_of_formal_arguments). 650 // If key + 2 >= elements.length then attempt to look in the unmapped 651 // arguments array (given by elements[1]) and return the value at key, missing 652 // to the runtime if the unmapped arguments array is not a fixed array or if 653 // key >= unmapped_arguments_array.length. 654 // 655 // Otherwise, t = elements[key + 2]. If t is the hole, then look up the value 656 // in the unmapped arguments array, as described above. Otherwise, t is a Smi 657 // index into the context array given at elements[0]. Return the value at 658 // context[t]. 659 660 key = AddUncasted<HForceRepresentation>(key, Representation::Smi()); 661 IfBuilder positive_smi(this); 662 positive_smi.If<HCompareNumericAndBranch>(key, graph()->GetConstant0(), 663 Token::LT); 664 positive_smi.ThenDeopt("key is negative"); 665 positive_smi.End(); 666 667 HValue* constant_two = Add<HConstant>(2); 668 HValue* elements = AddLoadElements(receiver, static_cast<HValue*>(NULL)); 669 HValue* elements_length = 670 Add<HLoadNamedField>(elements, static_cast<HValue*>(NULL), 671 HObjectAccess::ForFixedArrayLength()); 672 HValue* adjusted_length = AddUncasted<HSub>(elements_length, constant_two); 673 IfBuilder in_range(this); 674 in_range.If<HCompareNumericAndBranch>(key, adjusted_length, Token::LT); 675 in_range.Then(); 676 { 677 HValue* index = AddUncasted<HAdd>(key, constant_two); 678 HInstruction* mapped_index = 679 Add<HLoadKeyed>(elements, index, static_cast<HValue*>(NULL), 680 FAST_HOLEY_ELEMENTS, ALLOW_RETURN_HOLE); 681 682 IfBuilder is_valid(this); 683 is_valid.IfNot<HCompareObjectEqAndBranch>(mapped_index, 684 graph()->GetConstantHole()); 685 is_valid.Then(); 686 { 687 // TODO(mvstanton): I'd like to assert from this point, that if the 688 // mapped_index is not the hole that it is indeed, a smi. An unnecessary 689 // smi check is being emitted. 690 HValue* the_context = 691 Add<HLoadKeyed>(elements, graph()->GetConstant0(), 692 static_cast<HValue*>(NULL), FAST_ELEMENTS); 693 DCHECK(Context::kHeaderSize == FixedArray::kHeaderSize); 694 HValue* result = 695 Add<HLoadKeyed>(the_context, mapped_index, static_cast<HValue*>(NULL), 696 FAST_ELEMENTS, ALLOW_RETURN_HOLE); 697 environment()->Push(result); 698 } 699 is_valid.Else(); 700 { 701 HValue* result = UnmappedCase(elements, key); 702 environment()->Push(result); 703 } 704 is_valid.End(); 705 } 706 in_range.Else(); 707 { 708 HValue* result = UnmappedCase(elements, key); 709 environment()->Push(result); 710 } 711 in_range.End(); 712 713 return environment()->Pop(); 714 } 715 716 717 Handle<Code> KeyedLoadSloppyArgumentsStub::GenerateCode() { 718 return DoGenerateCode(this); 719 } 720 721 722 void CodeStubGraphBuilderBase::BuildStoreNamedField( 723 HValue* object, HValue* value, FieldIndex index, 724 Representation representation) { 725 DCHECK(!index.is_double() || representation.IsDouble()); 726 int offset = index.offset(); 727 HObjectAccess access = 728 index.is_inobject() 729 ? HObjectAccess::ForObservableJSObjectOffset(offset, representation) 730 : HObjectAccess::ForBackingStoreOffset(offset, representation); 731 732 if (representation.IsDouble()) { 733 // Load the heap number. 734 object = Add<HLoadNamedField>( 735 object, static_cast<HValue*>(NULL), 736 access.WithRepresentation(Representation::Tagged())); 737 // Store the double value into it. 738 access = HObjectAccess::ForHeapNumberValue(); 739 } else if (representation.IsHeapObject()) { 740 BuildCheckHeapObject(value); 741 } 742 743 Add<HStoreNamedField>(object, access, value, INITIALIZING_STORE); 744 } 745 746 747 template <> 748 HValue* CodeStubGraphBuilder<StoreFieldStub>::BuildCodeStub() { 749 BuildStoreNamedField(GetParameter(0), GetParameter(2), casted_stub()->index(), 750 casted_stub()->representation()); 751 return GetParameter(2); 752 } 753 754 755 Handle<Code> StoreFieldStub::GenerateCode() { return DoGenerateCode(this); } 756 757 758 template <> 759 HValue* CodeStubGraphBuilder<StringLengthStub>::BuildCodeStub() { 760 HValue* string = BuildLoadNamedField(GetParameter(0), 761 FieldIndex::ForInObjectOffset(JSValue::kValueOffset)); 762 return BuildLoadNamedField(string, 763 FieldIndex::ForInObjectOffset(String::kLengthOffset)); 764 } 765 766 767 Handle<Code> StringLengthStub::GenerateCode() { 768 return DoGenerateCode(this); 769 } 770 771 772 template <> 773 HValue* CodeStubGraphBuilder<StoreFastElementStub>::BuildCodeStub() { 774 BuildUncheckedMonomorphicElementAccess( 775 GetParameter(StoreDescriptor::kReceiverIndex), 776 GetParameter(StoreDescriptor::kNameIndex), 777 GetParameter(StoreDescriptor::kValueIndex), casted_stub()->is_js_array(), 778 casted_stub()->elements_kind(), STORE, NEVER_RETURN_HOLE, 779 casted_stub()->store_mode()); 780 781 return GetParameter(2); 782 } 783 784 785 Handle<Code> StoreFastElementStub::GenerateCode() { 786 return DoGenerateCode(this); 787 } 788 789 790 template <> 791 HValue* CodeStubGraphBuilder<TransitionElementsKindStub>::BuildCodeStub() { 792 info()->MarkAsSavesCallerDoubles(); 793 794 BuildTransitionElementsKind(GetParameter(0), 795 GetParameter(1), 796 casted_stub()->from_kind(), 797 casted_stub()->to_kind(), 798 casted_stub()->is_js_array()); 799 800 return GetParameter(0); 801 } 802 803 804 Handle<Code> TransitionElementsKindStub::GenerateCode() { 805 return DoGenerateCode(this); 806 } 807 808 HValue* CodeStubGraphBuilderBase::BuildArrayConstructor( 809 ElementsKind kind, 810 AllocationSiteOverrideMode override_mode, 811 ArgumentClass argument_class) { 812 HValue* constructor = GetParameter(ArrayConstructorStubBase::kConstructor); 813 HValue* alloc_site = GetParameter(ArrayConstructorStubBase::kAllocationSite); 814 JSArrayBuilder array_builder(this, kind, alloc_site, constructor, 815 override_mode); 816 HValue* result = NULL; 817 switch (argument_class) { 818 case NONE: 819 // This stub is very performance sensitive, the generated code must be 820 // tuned so that it doesn't build and eager frame. 821 info()->MarkMustNotHaveEagerFrame(); 822 result = array_builder.AllocateEmptyArray(); 823 break; 824 case SINGLE: 825 result = BuildArraySingleArgumentConstructor(&array_builder); 826 break; 827 case MULTIPLE: 828 result = BuildArrayNArgumentsConstructor(&array_builder, kind); 829 break; 830 } 831 832 return result; 833 } 834 835 836 HValue* CodeStubGraphBuilderBase::BuildInternalArrayConstructor( 837 ElementsKind kind, ArgumentClass argument_class) { 838 HValue* constructor = GetParameter( 839 InternalArrayConstructorStubBase::kConstructor); 840 JSArrayBuilder array_builder(this, kind, constructor); 841 842 HValue* result = NULL; 843 switch (argument_class) { 844 case NONE: 845 // This stub is very performance sensitive, the generated code must be 846 // tuned so that it doesn't build and eager frame. 847 info()->MarkMustNotHaveEagerFrame(); 848 result = array_builder.AllocateEmptyArray(); 849 break; 850 case SINGLE: 851 result = BuildArraySingleArgumentConstructor(&array_builder); 852 break; 853 case MULTIPLE: 854 result = BuildArrayNArgumentsConstructor(&array_builder, kind); 855 break; 856 } 857 return result; 858 } 859 860 861 HValue* CodeStubGraphBuilderBase::BuildArraySingleArgumentConstructor( 862 JSArrayBuilder* array_builder) { 863 // Smi check and range check on the input arg. 864 HValue* constant_one = graph()->GetConstant1(); 865 HValue* constant_zero = graph()->GetConstant0(); 866 867 HInstruction* elements = Add<HArgumentsElements>(false); 868 HInstruction* argument = Add<HAccessArgumentsAt>( 869 elements, constant_one, constant_zero); 870 871 return BuildAllocateArrayFromLength(array_builder, argument); 872 } 873 874 875 HValue* CodeStubGraphBuilderBase::BuildArrayNArgumentsConstructor( 876 JSArrayBuilder* array_builder, ElementsKind kind) { 877 // Insert a bounds check because the number of arguments might exceed 878 // the kInitialMaxFastElementArray limit. This cannot happen for code 879 // that was parsed, but calling via Array.apply(thisArg, [...]) might 880 // trigger it. 881 HValue* length = GetArgumentsLength(); 882 HConstant* max_alloc_length = 883 Add<HConstant>(JSObject::kInitialMaxFastElementArray); 884 HValue* checked_length = Add<HBoundsCheck>(length, max_alloc_length); 885 886 // We need to fill with the hole if it's a smi array in the multi-argument 887 // case because we might have to bail out while copying arguments into 888 // the array because they aren't compatible with a smi array. 889 // If it's a double array, no problem, and if it's fast then no 890 // problem either because doubles are boxed. 891 // 892 // TODO(mvstanton): consider an instruction to memset fill the array 893 // with zero in this case instead. 894 JSArrayBuilder::FillMode fill_mode = IsFastSmiElementsKind(kind) 895 ? JSArrayBuilder::FILL_WITH_HOLE 896 : JSArrayBuilder::DONT_FILL_WITH_HOLE; 897 HValue* new_object = array_builder->AllocateArray(checked_length, 898 max_alloc_length, 899 checked_length, 900 fill_mode); 901 HValue* elements = array_builder->GetElementsLocation(); 902 DCHECK(elements != NULL); 903 904 // Now populate the elements correctly. 905 LoopBuilder builder(this, 906 context(), 907 LoopBuilder::kPostIncrement); 908 HValue* start = graph()->GetConstant0(); 909 HValue* key = builder.BeginBody(start, checked_length, Token::LT); 910 HInstruction* argument_elements = Add<HArgumentsElements>(false); 911 HInstruction* argument = Add<HAccessArgumentsAt>( 912 argument_elements, checked_length, key); 913 914 Add<HStoreKeyed>(elements, key, argument, kind); 915 builder.EndBody(); 916 return new_object; 917 } 918 919 920 template <> 921 HValue* CodeStubGraphBuilder<ArrayNoArgumentConstructorStub>::BuildCodeStub() { 922 ElementsKind kind = casted_stub()->elements_kind(); 923 AllocationSiteOverrideMode override_mode = casted_stub()->override_mode(); 924 return BuildArrayConstructor(kind, override_mode, NONE); 925 } 926 927 928 Handle<Code> ArrayNoArgumentConstructorStub::GenerateCode() { 929 return DoGenerateCode(this); 930 } 931 932 933 template <> 934 HValue* CodeStubGraphBuilder<ArraySingleArgumentConstructorStub>:: 935 BuildCodeStub() { 936 ElementsKind kind = casted_stub()->elements_kind(); 937 AllocationSiteOverrideMode override_mode = casted_stub()->override_mode(); 938 return BuildArrayConstructor(kind, override_mode, SINGLE); 939 } 940 941 942 Handle<Code> ArraySingleArgumentConstructorStub::GenerateCode() { 943 return DoGenerateCode(this); 944 } 945 946 947 template <> 948 HValue* CodeStubGraphBuilder<ArrayNArgumentsConstructorStub>::BuildCodeStub() { 949 ElementsKind kind = casted_stub()->elements_kind(); 950 AllocationSiteOverrideMode override_mode = casted_stub()->override_mode(); 951 return BuildArrayConstructor(kind, override_mode, MULTIPLE); 952 } 953 954 955 Handle<Code> ArrayNArgumentsConstructorStub::GenerateCode() { 956 return DoGenerateCode(this); 957 } 958 959 960 template <> 961 HValue* CodeStubGraphBuilder<InternalArrayNoArgumentConstructorStub>:: 962 BuildCodeStub() { 963 ElementsKind kind = casted_stub()->elements_kind(); 964 return BuildInternalArrayConstructor(kind, NONE); 965 } 966 967 968 Handle<Code> InternalArrayNoArgumentConstructorStub::GenerateCode() { 969 return DoGenerateCode(this); 970 } 971 972 973 template <> 974 HValue* CodeStubGraphBuilder<InternalArraySingleArgumentConstructorStub>:: 975 BuildCodeStub() { 976 ElementsKind kind = casted_stub()->elements_kind(); 977 return BuildInternalArrayConstructor(kind, SINGLE); 978 } 979 980 981 Handle<Code> InternalArraySingleArgumentConstructorStub::GenerateCode() { 982 return DoGenerateCode(this); 983 } 984 985 986 template <> 987 HValue* CodeStubGraphBuilder<InternalArrayNArgumentsConstructorStub>:: 988 BuildCodeStub() { 989 ElementsKind kind = casted_stub()->elements_kind(); 990 return BuildInternalArrayConstructor(kind, MULTIPLE); 991 } 992 993 994 Handle<Code> InternalArrayNArgumentsConstructorStub::GenerateCode() { 995 return DoGenerateCode(this); 996 } 997 998 999 template <> 1000 HValue* CodeStubGraphBuilder<CompareNilICStub>::BuildCodeInitializedStub() { 1001 Isolate* isolate = graph()->isolate(); 1002 CompareNilICStub* stub = casted_stub(); 1003 HIfContinuation continuation; 1004 Handle<Map> sentinel_map(isolate->heap()->meta_map()); 1005 Type* type = stub->GetType(zone(), sentinel_map); 1006 BuildCompareNil(GetParameter(0), type, &continuation); 1007 IfBuilder if_nil(this, &continuation); 1008 if_nil.Then(); 1009 if (continuation.IsFalseReachable()) { 1010 if_nil.Else(); 1011 if_nil.Return(graph()->GetConstant0()); 1012 } 1013 if_nil.End(); 1014 return continuation.IsTrueReachable() 1015 ? graph()->GetConstant1() 1016 : graph()->GetConstantUndefined(); 1017 } 1018 1019 1020 Handle<Code> CompareNilICStub::GenerateCode() { 1021 return DoGenerateCode(this); 1022 } 1023 1024 1025 template <> 1026 HValue* CodeStubGraphBuilder<BinaryOpICStub>::BuildCodeInitializedStub() { 1027 BinaryOpICState state = casted_stub()->state(); 1028 1029 HValue* left = GetParameter(BinaryOpICStub::kLeft); 1030 HValue* right = GetParameter(BinaryOpICStub::kRight); 1031 1032 Type* left_type = state.GetLeftType(zone()); 1033 Type* right_type = state.GetRightType(zone()); 1034 Type* result_type = state.GetResultType(zone()); 1035 1036 DCHECK(!left_type->Is(Type::None()) && !right_type->Is(Type::None()) && 1037 (state.HasSideEffects() || !result_type->Is(Type::None()))); 1038 1039 HValue* result = NULL; 1040 HAllocationMode allocation_mode(NOT_TENURED); 1041 if (state.op() == Token::ADD && 1042 (left_type->Maybe(Type::String()) || right_type->Maybe(Type::String())) && 1043 !left_type->Is(Type::String()) && !right_type->Is(Type::String())) { 1044 // For the generic add stub a fast case for string addition is performance 1045 // critical. 1046 if (left_type->Maybe(Type::String())) { 1047 IfBuilder if_leftisstring(this); 1048 if_leftisstring.If<HIsStringAndBranch>(left); 1049 if_leftisstring.Then(); 1050 { 1051 Push(BuildBinaryOperation( 1052 state.op(), left, right, 1053 Type::String(zone()), right_type, 1054 result_type, state.fixed_right_arg(), 1055 allocation_mode)); 1056 } 1057 if_leftisstring.Else(); 1058 { 1059 Push(BuildBinaryOperation( 1060 state.op(), left, right, 1061 left_type, right_type, result_type, 1062 state.fixed_right_arg(), allocation_mode)); 1063 } 1064 if_leftisstring.End(); 1065 result = Pop(); 1066 } else { 1067 IfBuilder if_rightisstring(this); 1068 if_rightisstring.If<HIsStringAndBranch>(right); 1069 if_rightisstring.Then(); 1070 { 1071 Push(BuildBinaryOperation( 1072 state.op(), left, right, 1073 left_type, Type::String(zone()), 1074 result_type, state.fixed_right_arg(), 1075 allocation_mode)); 1076 } 1077 if_rightisstring.Else(); 1078 { 1079 Push(BuildBinaryOperation( 1080 state.op(), left, right, 1081 left_type, right_type, result_type, 1082 state.fixed_right_arg(), allocation_mode)); 1083 } 1084 if_rightisstring.End(); 1085 result = Pop(); 1086 } 1087 } else { 1088 result = BuildBinaryOperation( 1089 state.op(), left, right, 1090 left_type, right_type, result_type, 1091 state.fixed_right_arg(), allocation_mode); 1092 } 1093 1094 // If we encounter a generic argument, the number conversion is 1095 // observable, thus we cannot afford to bail out after the fact. 1096 if (!state.HasSideEffects()) { 1097 result = EnforceNumberType(result, result_type); 1098 } 1099 1100 // Reuse the double box of one of the operands if we are allowed to (i.e. 1101 // chained binops). 1102 if (state.CanReuseDoubleBox()) { 1103 HValue* operand = (state.mode() == OVERWRITE_LEFT) ? left : right; 1104 IfBuilder if_heap_number(this); 1105 if_heap_number.If<HHasInstanceTypeAndBranch>(operand, HEAP_NUMBER_TYPE); 1106 if_heap_number.Then(); 1107 Add<HStoreNamedField>(operand, HObjectAccess::ForHeapNumberValue(), result); 1108 Push(operand); 1109 if_heap_number.Else(); 1110 Push(result); 1111 if_heap_number.End(); 1112 result = Pop(); 1113 } 1114 1115 return result; 1116 } 1117 1118 1119 Handle<Code> BinaryOpICStub::GenerateCode() { 1120 return DoGenerateCode(this); 1121 } 1122 1123 1124 template <> 1125 HValue* CodeStubGraphBuilder<BinaryOpWithAllocationSiteStub>::BuildCodeStub() { 1126 BinaryOpICState state = casted_stub()->state(); 1127 1128 HValue* allocation_site = GetParameter( 1129 BinaryOpWithAllocationSiteStub::kAllocationSite); 1130 HValue* left = GetParameter(BinaryOpWithAllocationSiteStub::kLeft); 1131 HValue* right = GetParameter(BinaryOpWithAllocationSiteStub::kRight); 1132 1133 Type* left_type = state.GetLeftType(zone()); 1134 Type* right_type = state.GetRightType(zone()); 1135 Type* result_type = state.GetResultType(zone()); 1136 HAllocationMode allocation_mode(allocation_site); 1137 1138 return BuildBinaryOperation(state.op(), left, right, 1139 left_type, right_type, result_type, 1140 state.fixed_right_arg(), allocation_mode); 1141 } 1142 1143 1144 Handle<Code> BinaryOpWithAllocationSiteStub::GenerateCode() { 1145 return DoGenerateCode(this); 1146 } 1147 1148 1149 template <> 1150 HValue* CodeStubGraphBuilder<StringAddStub>::BuildCodeInitializedStub() { 1151 StringAddStub* stub = casted_stub(); 1152 StringAddFlags flags = stub->flags(); 1153 PretenureFlag pretenure_flag = stub->pretenure_flag(); 1154 1155 HValue* left = GetParameter(StringAddStub::kLeft); 1156 HValue* right = GetParameter(StringAddStub::kRight); 1157 1158 // Make sure that both arguments are strings if not known in advance. 1159 if ((flags & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) { 1160 left = BuildCheckString(left); 1161 } 1162 if ((flags & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) { 1163 right = BuildCheckString(right); 1164 } 1165 1166 return BuildStringAdd(left, right, HAllocationMode(pretenure_flag)); 1167 } 1168 1169 1170 Handle<Code> StringAddStub::GenerateCode() { 1171 return DoGenerateCode(this); 1172 } 1173 1174 1175 template <> 1176 HValue* CodeStubGraphBuilder<ToBooleanStub>::BuildCodeInitializedStub() { 1177 ToBooleanStub* stub = casted_stub(); 1178 HValue* true_value = NULL; 1179 HValue* false_value = NULL; 1180 1181 switch (stub->mode()) { 1182 case ToBooleanStub::RESULT_AS_SMI: 1183 true_value = graph()->GetConstant1(); 1184 false_value = graph()->GetConstant0(); 1185 break; 1186 case ToBooleanStub::RESULT_AS_ODDBALL: 1187 true_value = graph()->GetConstantTrue(); 1188 false_value = graph()->GetConstantFalse(); 1189 break; 1190 case ToBooleanStub::RESULT_AS_INVERSE_ODDBALL: 1191 true_value = graph()->GetConstantFalse(); 1192 false_value = graph()->GetConstantTrue(); 1193 break; 1194 } 1195 1196 IfBuilder if_true(this); 1197 if_true.If<HBranch>(GetParameter(0), stub->types()); 1198 if_true.Then(); 1199 if_true.Return(true_value); 1200 if_true.Else(); 1201 if_true.End(); 1202 return false_value; 1203 } 1204 1205 1206 Handle<Code> ToBooleanStub::GenerateCode() { 1207 return DoGenerateCode(this); 1208 } 1209 1210 1211 template <> 1212 HValue* CodeStubGraphBuilder<StoreGlobalStub>::BuildCodeInitializedStub() { 1213 StoreGlobalStub* stub = casted_stub(); 1214 Handle<Object> placeholer_value(Smi::FromInt(0), isolate()); 1215 Handle<PropertyCell> placeholder_cell = 1216 isolate()->factory()->NewPropertyCell(placeholer_value); 1217 1218 HParameter* value = GetParameter(StoreDescriptor::kValueIndex); 1219 1220 if (stub->check_global()) { 1221 // Check that the map of the global has not changed: use a placeholder map 1222 // that will be replaced later with the global object's map. 1223 Handle<Map> placeholder_map = isolate()->factory()->meta_map(); 1224 HValue* global = Add<HConstant>( 1225 StoreGlobalStub::global_placeholder(isolate())); 1226 Add<HCheckMaps>(global, placeholder_map); 1227 } 1228 1229 HValue* cell = Add<HConstant>(placeholder_cell); 1230 HObjectAccess access(HObjectAccess::ForCellPayload(isolate())); 1231 HValue* cell_contents = Add<HLoadNamedField>( 1232 cell, static_cast<HValue*>(NULL), access); 1233 1234 if (stub->is_constant()) { 1235 IfBuilder builder(this); 1236 builder.If<HCompareObjectEqAndBranch>(cell_contents, value); 1237 builder.Then(); 1238 builder.ElseDeopt("Unexpected cell contents in constant global store"); 1239 builder.End(); 1240 } else { 1241 // Load the payload of the global parameter cell. A hole indicates that the 1242 // property has been deleted and that the store must be handled by the 1243 // runtime. 1244 IfBuilder builder(this); 1245 HValue* hole_value = graph()->GetConstantHole(); 1246 builder.If<HCompareObjectEqAndBranch>(cell_contents, hole_value); 1247 builder.Then(); 1248 builder.Deopt("Unexpected cell contents in global store"); 1249 builder.Else(); 1250 Add<HStoreNamedField>(cell, access, value); 1251 builder.End(); 1252 } 1253 1254 return value; 1255 } 1256 1257 1258 Handle<Code> StoreGlobalStub::GenerateCode() { 1259 return DoGenerateCode(this); 1260 } 1261 1262 1263 template<> 1264 HValue* CodeStubGraphBuilder<ElementsTransitionAndStoreStub>::BuildCodeStub() { 1265 HValue* value = GetParameter(ElementsTransitionAndStoreStub::kValueIndex); 1266 HValue* map = GetParameter(ElementsTransitionAndStoreStub::kMapIndex); 1267 HValue* key = GetParameter(ElementsTransitionAndStoreStub::kKeyIndex); 1268 HValue* object = GetParameter(ElementsTransitionAndStoreStub::kObjectIndex); 1269 1270 if (FLAG_trace_elements_transitions) { 1271 // Tracing elements transitions is the job of the runtime. 1272 Add<HDeoptimize>("Tracing elements transitions", Deoptimizer::EAGER); 1273 } else { 1274 info()->MarkAsSavesCallerDoubles(); 1275 1276 BuildTransitionElementsKind(object, map, 1277 casted_stub()->from_kind(), 1278 casted_stub()->to_kind(), 1279 casted_stub()->is_jsarray()); 1280 1281 BuildUncheckedMonomorphicElementAccess(object, key, value, 1282 casted_stub()->is_jsarray(), 1283 casted_stub()->to_kind(), 1284 STORE, ALLOW_RETURN_HOLE, 1285 casted_stub()->store_mode()); 1286 } 1287 1288 return value; 1289 } 1290 1291 1292 Handle<Code> ElementsTransitionAndStoreStub::GenerateCode() { 1293 return DoGenerateCode(this); 1294 } 1295 1296 1297 void CodeStubGraphBuilderBase::BuildCheckAndInstallOptimizedCode( 1298 HValue* js_function, 1299 HValue* native_context, 1300 IfBuilder* builder, 1301 HValue* optimized_map, 1302 HValue* map_index) { 1303 HValue* osr_ast_id_none = Add<HConstant>(BailoutId::None().ToInt()); 1304 HValue* context_slot = LoadFromOptimizedCodeMap( 1305 optimized_map, map_index, SharedFunctionInfo::kContextOffset); 1306 HValue* osr_ast_slot = LoadFromOptimizedCodeMap( 1307 optimized_map, map_index, SharedFunctionInfo::kOsrAstIdOffset); 1308 builder->If<HCompareObjectEqAndBranch>(native_context, 1309 context_slot); 1310 builder->AndIf<HCompareObjectEqAndBranch>(osr_ast_slot, osr_ast_id_none); 1311 builder->Then(); 1312 HValue* code_object = LoadFromOptimizedCodeMap(optimized_map, 1313 map_index, SharedFunctionInfo::kCachedCodeOffset); 1314 // and the literals 1315 HValue* literals = LoadFromOptimizedCodeMap(optimized_map, 1316 map_index, SharedFunctionInfo::kLiteralsOffset); 1317 1318 Counters* counters = isolate()->counters(); 1319 AddIncrementCounter(counters->fast_new_closure_install_optimized()); 1320 1321 // TODO(fschneider): Idea: store proper code pointers in the optimized code 1322 // map and either unmangle them on marking or do nothing as the whole map is 1323 // discarded on major GC anyway. 1324 Add<HStoreCodeEntry>(js_function, code_object); 1325 Add<HStoreNamedField>(js_function, HObjectAccess::ForLiteralsPointer(), 1326 literals); 1327 1328 // Now link a function into a list of optimized functions. 1329 HValue* optimized_functions_list = Add<HLoadNamedField>( 1330 native_context, static_cast<HValue*>(NULL), 1331 HObjectAccess::ForContextSlot(Context::OPTIMIZED_FUNCTIONS_LIST)); 1332 Add<HStoreNamedField>(js_function, 1333 HObjectAccess::ForNextFunctionLinkPointer(), 1334 optimized_functions_list); 1335 1336 // This store is the only one that should have a write barrier. 1337 Add<HStoreNamedField>(native_context, 1338 HObjectAccess::ForContextSlot(Context::OPTIMIZED_FUNCTIONS_LIST), 1339 js_function); 1340 1341 // The builder continues in the "then" after this function. 1342 } 1343 1344 1345 void CodeStubGraphBuilderBase::BuildInstallCode(HValue* js_function, 1346 HValue* shared_info) { 1347 Add<HStoreNamedField>(js_function, 1348 HObjectAccess::ForNextFunctionLinkPointer(), 1349 graph()->GetConstantUndefined()); 1350 HValue* code_object = Add<HLoadNamedField>( 1351 shared_info, static_cast<HValue*>(NULL), HObjectAccess::ForCodeOffset()); 1352 Add<HStoreCodeEntry>(js_function, code_object); 1353 } 1354 1355 1356 HInstruction* CodeStubGraphBuilderBase::LoadFromOptimizedCodeMap( 1357 HValue* optimized_map, 1358 HValue* iterator, 1359 int field_offset) { 1360 // By making sure to express these loads in the form [<hvalue> + constant] 1361 // the keyed load can be hoisted. 1362 DCHECK(field_offset >= 0 && field_offset < SharedFunctionInfo::kEntryLength); 1363 HValue* field_slot = iterator; 1364 if (field_offset > 0) { 1365 HValue* field_offset_value = Add<HConstant>(field_offset); 1366 field_slot = AddUncasted<HAdd>(iterator, field_offset_value); 1367 } 1368 HInstruction* field_entry = Add<HLoadKeyed>(optimized_map, field_slot, 1369 static_cast<HValue*>(NULL), FAST_ELEMENTS); 1370 return field_entry; 1371 } 1372 1373 1374 void CodeStubGraphBuilderBase::BuildInstallFromOptimizedCodeMap( 1375 HValue* js_function, 1376 HValue* shared_info, 1377 HValue* native_context) { 1378 Counters* counters = isolate()->counters(); 1379 IfBuilder is_optimized(this); 1380 HInstruction* optimized_map = Add<HLoadNamedField>( 1381 shared_info, static_cast<HValue*>(NULL), 1382 HObjectAccess::ForOptimizedCodeMap()); 1383 HValue* null_constant = Add<HConstant>(0); 1384 is_optimized.If<HCompareObjectEqAndBranch>(optimized_map, null_constant); 1385 is_optimized.Then(); 1386 { 1387 BuildInstallCode(js_function, shared_info); 1388 } 1389 is_optimized.Else(); 1390 { 1391 AddIncrementCounter(counters->fast_new_closure_try_optimized()); 1392 // optimized_map points to fixed array of 3-element entries 1393 // (native context, optimized code, literals). 1394 // Map must never be empty, so check the first elements. 1395 HValue* first_entry_index = 1396 Add<HConstant>(SharedFunctionInfo::kEntriesStart); 1397 IfBuilder already_in(this); 1398 BuildCheckAndInstallOptimizedCode(js_function, native_context, &already_in, 1399 optimized_map, first_entry_index); 1400 already_in.Else(); 1401 { 1402 // Iterate through the rest of map backwards. Do not double check first 1403 // entry. After the loop, if no matching optimized code was found, 1404 // install unoptimized code. 1405 // for(i = map.length() - SharedFunctionInfo::kEntryLength; 1406 // i > SharedFunctionInfo::kEntriesStart; 1407 // i -= SharedFunctionInfo::kEntryLength) { .. } 1408 HValue* shared_function_entry_length = 1409 Add<HConstant>(SharedFunctionInfo::kEntryLength); 1410 LoopBuilder loop_builder(this, 1411 context(), 1412 LoopBuilder::kPostDecrement, 1413 shared_function_entry_length); 1414 HValue* array_length = Add<HLoadNamedField>( 1415 optimized_map, static_cast<HValue*>(NULL), 1416 HObjectAccess::ForFixedArrayLength()); 1417 HValue* start_pos = AddUncasted<HSub>(array_length, 1418 shared_function_entry_length); 1419 HValue* slot_iterator = loop_builder.BeginBody(start_pos, 1420 first_entry_index, 1421 Token::GT); 1422 { 1423 IfBuilder done_check(this); 1424 BuildCheckAndInstallOptimizedCode(js_function, native_context, 1425 &done_check, 1426 optimized_map, 1427 slot_iterator); 1428 // Fall out of the loop 1429 loop_builder.Break(); 1430 } 1431 loop_builder.EndBody(); 1432 1433 // If slot_iterator equals first entry index, then we failed to find and 1434 // install optimized code 1435 IfBuilder no_optimized_code_check(this); 1436 no_optimized_code_check.If<HCompareNumericAndBranch>( 1437 slot_iterator, first_entry_index, Token::EQ); 1438 no_optimized_code_check.Then(); 1439 { 1440 // Store the unoptimized code 1441 BuildInstallCode(js_function, shared_info); 1442 } 1443 } 1444 } 1445 } 1446 1447 1448 template<> 1449 HValue* CodeStubGraphBuilder<FastNewClosureStub>::BuildCodeStub() { 1450 Counters* counters = isolate()->counters(); 1451 Factory* factory = isolate()->factory(); 1452 HInstruction* empty_fixed_array = 1453 Add<HConstant>(factory->empty_fixed_array()); 1454 HValue* shared_info = GetParameter(0); 1455 1456 AddIncrementCounter(counters->fast_new_closure_total()); 1457 1458 // Create a new closure from the given function info in new space 1459 HValue* size = Add<HConstant>(JSFunction::kSize); 1460 HInstruction* js_function = Add<HAllocate>(size, HType::JSObject(), 1461 NOT_TENURED, JS_FUNCTION_TYPE); 1462 1463 int map_index = Context::FunctionMapIndex(casted_stub()->strict_mode(), 1464 casted_stub()->kind()); 1465 1466 // Compute the function map in the current native context and set that 1467 // as the map of the allocated object. 1468 HInstruction* native_context = BuildGetNativeContext(); 1469 HInstruction* map_slot_value = Add<HLoadNamedField>( 1470 native_context, static_cast<HValue*>(NULL), 1471 HObjectAccess::ForContextSlot(map_index)); 1472 Add<HStoreNamedField>(js_function, HObjectAccess::ForMap(), map_slot_value); 1473 1474 // Initialize the rest of the function. 1475 Add<HStoreNamedField>(js_function, HObjectAccess::ForPropertiesPointer(), 1476 empty_fixed_array); 1477 Add<HStoreNamedField>(js_function, HObjectAccess::ForElementsPointer(), 1478 empty_fixed_array); 1479 Add<HStoreNamedField>(js_function, HObjectAccess::ForLiteralsPointer(), 1480 empty_fixed_array); 1481 Add<HStoreNamedField>(js_function, HObjectAccess::ForPrototypeOrInitialMap(), 1482 graph()->GetConstantHole()); 1483 Add<HStoreNamedField>(js_function, 1484 HObjectAccess::ForSharedFunctionInfoPointer(), 1485 shared_info); 1486 Add<HStoreNamedField>(js_function, HObjectAccess::ForFunctionContextPointer(), 1487 context()); 1488 1489 // Initialize the code pointer in the function to be the one 1490 // found in the shared function info object. 1491 // But first check if there is an optimized version for our context. 1492 if (FLAG_cache_optimized_code) { 1493 BuildInstallFromOptimizedCodeMap(js_function, shared_info, native_context); 1494 } else { 1495 BuildInstallCode(js_function, shared_info); 1496 } 1497 1498 return js_function; 1499 } 1500 1501 1502 Handle<Code> FastNewClosureStub::GenerateCode() { 1503 return DoGenerateCode(this); 1504 } 1505 1506 1507 template<> 1508 HValue* CodeStubGraphBuilder<FastNewContextStub>::BuildCodeStub() { 1509 int length = casted_stub()->slots() + Context::MIN_CONTEXT_SLOTS; 1510 1511 // Get the function. 1512 HParameter* function = GetParameter(FastNewContextStub::kFunction); 1513 1514 // Allocate the context in new space. 1515 HAllocate* function_context = Add<HAllocate>( 1516 Add<HConstant>(length * kPointerSize + FixedArray::kHeaderSize), 1517 HType::HeapObject(), NOT_TENURED, FIXED_ARRAY_TYPE); 1518 1519 // Set up the object header. 1520 AddStoreMapConstant(function_context, 1521 isolate()->factory()->function_context_map()); 1522 Add<HStoreNamedField>(function_context, 1523 HObjectAccess::ForFixedArrayLength(), 1524 Add<HConstant>(length)); 1525 1526 // Set up the fixed slots. 1527 Add<HStoreNamedField>(function_context, 1528 HObjectAccess::ForContextSlot(Context::CLOSURE_INDEX), 1529 function); 1530 Add<HStoreNamedField>(function_context, 1531 HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX), 1532 context()); 1533 Add<HStoreNamedField>(function_context, 1534 HObjectAccess::ForContextSlot(Context::EXTENSION_INDEX), 1535 graph()->GetConstant0()); 1536 1537 // Copy the global object from the previous context. 1538 HValue* global_object = Add<HLoadNamedField>( 1539 context(), static_cast<HValue*>(NULL), 1540 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); 1541 Add<HStoreNamedField>(function_context, 1542 HObjectAccess::ForContextSlot( 1543 Context::GLOBAL_OBJECT_INDEX), 1544 global_object); 1545 1546 // Initialize the rest of the slots to undefined. 1547 for (int i = Context::MIN_CONTEXT_SLOTS; i < length; ++i) { 1548 Add<HStoreNamedField>(function_context, 1549 HObjectAccess::ForContextSlot(i), 1550 graph()->GetConstantUndefined()); 1551 } 1552 1553 return function_context; 1554 } 1555 1556 1557 Handle<Code> FastNewContextStub::GenerateCode() { 1558 return DoGenerateCode(this); 1559 } 1560 1561 1562 template <> 1563 HValue* CodeStubGraphBuilder<LoadDictionaryElementStub>::BuildCodeStub() { 1564 HValue* receiver = GetParameter(LoadDescriptor::kReceiverIndex); 1565 HValue* key = GetParameter(LoadDescriptor::kNameIndex); 1566 1567 Add<HCheckSmi>(key); 1568 1569 HValue* elements = AddLoadElements(receiver); 1570 1571 HValue* hash = BuildElementIndexHash(key); 1572 1573 return BuildUncheckedDictionaryElementLoad(receiver, elements, key, hash); 1574 } 1575 1576 1577 Handle<Code> LoadDictionaryElementStub::GenerateCode() { 1578 return DoGenerateCode(this); 1579 } 1580 1581 1582 template<> 1583 HValue* CodeStubGraphBuilder<RegExpConstructResultStub>::BuildCodeStub() { 1584 // Determine the parameters. 1585 HValue* length = GetParameter(RegExpConstructResultStub::kLength); 1586 HValue* index = GetParameter(RegExpConstructResultStub::kIndex); 1587 HValue* input = GetParameter(RegExpConstructResultStub::kInput); 1588 1589 info()->MarkMustNotHaveEagerFrame(); 1590 1591 return BuildRegExpConstructResult(length, index, input); 1592 } 1593 1594 1595 Handle<Code> RegExpConstructResultStub::GenerateCode() { 1596 return DoGenerateCode(this); 1597 } 1598 1599 1600 template <> 1601 class CodeStubGraphBuilder<KeyedLoadGenericStub> 1602 : public CodeStubGraphBuilderBase { 1603 public: 1604 CodeStubGraphBuilder(Isolate* isolate, KeyedLoadGenericStub* stub) 1605 : CodeStubGraphBuilderBase(isolate, stub) {} 1606 1607 protected: 1608 virtual HValue* BuildCodeStub(); 1609 1610 void BuildElementsKindLimitCheck(HGraphBuilder::IfBuilder* if_builder, 1611 HValue* bit_field2, 1612 ElementsKind kind); 1613 1614 void BuildFastElementLoad(HGraphBuilder::IfBuilder* if_builder, 1615 HValue* receiver, 1616 HValue* key, 1617 HValue* instance_type, 1618 HValue* bit_field2, 1619 ElementsKind kind); 1620 1621 void BuildExternalElementLoad(HGraphBuilder::IfBuilder* if_builder, 1622 HValue* receiver, 1623 HValue* key, 1624 HValue* instance_type, 1625 HValue* bit_field2, 1626 ElementsKind kind); 1627 1628 KeyedLoadGenericStub* casted_stub() { 1629 return static_cast<KeyedLoadGenericStub*>(stub()); 1630 } 1631 }; 1632 1633 1634 void CodeStubGraphBuilder<KeyedLoadGenericStub>::BuildElementsKindLimitCheck( 1635 HGraphBuilder::IfBuilder* if_builder, HValue* bit_field2, 1636 ElementsKind kind) { 1637 ElementsKind next_kind = static_cast<ElementsKind>(kind + 1); 1638 HValue* kind_limit = Add<HConstant>( 1639 static_cast<int>(Map::ElementsKindBits::encode(next_kind))); 1640 1641 if_builder->If<HCompareNumericAndBranch>(bit_field2, kind_limit, Token::LT); 1642 if_builder->Then(); 1643 } 1644 1645 1646 void CodeStubGraphBuilder<KeyedLoadGenericStub>::BuildFastElementLoad( 1647 HGraphBuilder::IfBuilder* if_builder, HValue* receiver, HValue* key, 1648 HValue* instance_type, HValue* bit_field2, ElementsKind kind) { 1649 DCHECK(!IsExternalArrayElementsKind(kind)); 1650 1651 BuildElementsKindLimitCheck(if_builder, bit_field2, kind); 1652 1653 IfBuilder js_array_check(this); 1654 js_array_check.If<HCompareNumericAndBranch>( 1655 instance_type, Add<HConstant>(JS_ARRAY_TYPE), Token::EQ); 1656 js_array_check.Then(); 1657 Push(BuildUncheckedMonomorphicElementAccess(receiver, key, NULL, 1658 true, kind, 1659 LOAD, NEVER_RETURN_HOLE, 1660 STANDARD_STORE)); 1661 js_array_check.Else(); 1662 Push(BuildUncheckedMonomorphicElementAccess(receiver, key, NULL, 1663 false, kind, 1664 LOAD, NEVER_RETURN_HOLE, 1665 STANDARD_STORE)); 1666 js_array_check.End(); 1667 } 1668 1669 1670 void CodeStubGraphBuilder<KeyedLoadGenericStub>::BuildExternalElementLoad( 1671 HGraphBuilder::IfBuilder* if_builder, HValue* receiver, HValue* key, 1672 HValue* instance_type, HValue* bit_field2, ElementsKind kind) { 1673 DCHECK(IsExternalArrayElementsKind(kind)); 1674 1675 BuildElementsKindLimitCheck(if_builder, bit_field2, kind); 1676 1677 Push(BuildUncheckedMonomorphicElementAccess(receiver, key, NULL, 1678 false, kind, 1679 LOAD, NEVER_RETURN_HOLE, 1680 STANDARD_STORE)); 1681 } 1682 1683 1684 HValue* CodeStubGraphBuilder<KeyedLoadGenericStub>::BuildCodeStub() { 1685 HValue* receiver = GetParameter(LoadDescriptor::kReceiverIndex); 1686 HValue* key = GetParameter(LoadDescriptor::kNameIndex); 1687 1688 // Split into a smi/integer case and unique string case. 1689 HIfContinuation index_name_split_continuation(graph()->CreateBasicBlock(), 1690 graph()->CreateBasicBlock()); 1691 1692 BuildKeyedIndexCheck(key, &index_name_split_continuation); 1693 1694 IfBuilder index_name_split(this, &index_name_split_continuation); 1695 index_name_split.Then(); 1696 { 1697 // Key is an index (number) 1698 key = Pop(); 1699 1700 int bit_field_mask = (1 << Map::kIsAccessCheckNeeded) | 1701 (1 << Map::kHasIndexedInterceptor); 1702 BuildJSObjectCheck(receiver, bit_field_mask); 1703 1704 HValue* map = Add<HLoadNamedField>(receiver, static_cast<HValue*>(NULL), 1705 HObjectAccess::ForMap()); 1706 1707 HValue* instance_type = 1708 Add<HLoadNamedField>(map, static_cast<HValue*>(NULL), 1709 HObjectAccess::ForMapInstanceType()); 1710 1711 HValue* bit_field2 = Add<HLoadNamedField>(map, 1712 static_cast<HValue*>(NULL), 1713 HObjectAccess::ForMapBitField2()); 1714 1715 IfBuilder kind_if(this); 1716 BuildFastElementLoad(&kind_if, receiver, key, instance_type, bit_field2, 1717 FAST_HOLEY_ELEMENTS); 1718 1719 kind_if.Else(); 1720 { 1721 BuildFastElementLoad(&kind_if, receiver, key, instance_type, bit_field2, 1722 FAST_HOLEY_DOUBLE_ELEMENTS); 1723 } 1724 kind_if.Else(); 1725 1726 // The DICTIONARY_ELEMENTS check generates a "kind_if.Then" 1727 BuildElementsKindLimitCheck(&kind_if, bit_field2, DICTIONARY_ELEMENTS); 1728 { 1729 HValue* elements = AddLoadElements(receiver); 1730 1731 HValue* hash = BuildElementIndexHash(key); 1732 1733 Push(BuildUncheckedDictionaryElementLoad(receiver, elements, key, hash)); 1734 } 1735 kind_if.Else(); 1736 1737 // The SLOPPY_ARGUMENTS_ELEMENTS check generates a "kind_if.Then" 1738 BuildElementsKindLimitCheck(&kind_if, bit_field2, 1739 SLOPPY_ARGUMENTS_ELEMENTS); 1740 // Non-strict elements are not handled. 1741 Add<HDeoptimize>("non-strict elements in KeyedLoadGenericStub", 1742 Deoptimizer::EAGER); 1743 Push(graph()->GetConstant0()); 1744 1745 kind_if.Else(); 1746 BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, 1747 EXTERNAL_INT8_ELEMENTS); 1748 1749 kind_if.Else(); 1750 BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, 1751 EXTERNAL_UINT8_ELEMENTS); 1752 1753 kind_if.Else(); 1754 BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, 1755 EXTERNAL_INT16_ELEMENTS); 1756 1757 kind_if.Else(); 1758 BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, 1759 EXTERNAL_UINT16_ELEMENTS); 1760 1761 kind_if.Else(); 1762 BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, 1763 EXTERNAL_INT32_ELEMENTS); 1764 1765 kind_if.Else(); 1766 BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, 1767 EXTERNAL_UINT32_ELEMENTS); 1768 1769 kind_if.Else(); 1770 BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, 1771 EXTERNAL_FLOAT32_ELEMENTS); 1772 1773 kind_if.Else(); 1774 BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, 1775 EXTERNAL_FLOAT64_ELEMENTS); 1776 1777 kind_if.Else(); 1778 BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, 1779 EXTERNAL_UINT8_CLAMPED_ELEMENTS); 1780 1781 kind_if.ElseDeopt("ElementsKind unhandled in KeyedLoadGenericStub"); 1782 1783 kind_if.End(); 1784 } 1785 index_name_split.Else(); 1786 { 1787 // Key is a unique string. 1788 key = Pop(); 1789 1790 int bit_field_mask = (1 << Map::kIsAccessCheckNeeded) | 1791 (1 << Map::kHasNamedInterceptor); 1792 BuildJSObjectCheck(receiver, bit_field_mask); 1793 1794 HIfContinuation continuation; 1795 BuildTestForDictionaryProperties(receiver, &continuation); 1796 IfBuilder if_dict_properties(this, &continuation); 1797 if_dict_properties.Then(); 1798 { 1799 // Key is string, properties are dictionary mode 1800 BuildNonGlobalObjectCheck(receiver); 1801 1802 HValue* properties = Add<HLoadNamedField>( 1803 receiver, static_cast<HValue*>(NULL), 1804 HObjectAccess::ForPropertiesPointer()); 1805 1806 HValue* hash = 1807 Add<HLoadNamedField>(key, static_cast<HValue*>(NULL), 1808 HObjectAccess::ForNameHashField()); 1809 1810 hash = AddUncasted<HShr>(hash, Add<HConstant>(Name::kHashShift)); 1811 1812 HValue* value = BuildUncheckedDictionaryElementLoad(receiver, 1813 properties, 1814 key, 1815 hash); 1816 Push(value); 1817 } 1818 if_dict_properties.Else(); 1819 { 1820 // Key is string, properties are fast mode 1821 HValue* hash = BuildKeyedLookupCacheHash(receiver, key); 1822 1823 ExternalReference cache_keys_ref = 1824 ExternalReference::keyed_lookup_cache_keys(isolate()); 1825 HValue* cache_keys = Add<HConstant>(cache_keys_ref); 1826 1827 HValue* map = Add<HLoadNamedField>(receiver, static_cast<HValue*>(NULL), 1828 HObjectAccess::ForMap()); 1829 HValue* base_index = AddUncasted<HMul>(hash, Add<HConstant>(2)); 1830 base_index->ClearFlag(HValue::kCanOverflow); 1831 1832 HIfContinuation inline_or_runtime_continuation( 1833 graph()->CreateBasicBlock(), graph()->CreateBasicBlock()); 1834 { 1835 IfBuilder lookup_ifs[KeyedLookupCache::kEntriesPerBucket]; 1836 for (int probe = 0; probe < KeyedLookupCache::kEntriesPerBucket; 1837 ++probe) { 1838 IfBuilder* lookup_if = &lookup_ifs[probe]; 1839 lookup_if->Initialize(this); 1840 int probe_base = probe * KeyedLookupCache::kEntryLength; 1841 HValue* map_index = AddUncasted<HAdd>( 1842 base_index, 1843 Add<HConstant>(probe_base + KeyedLookupCache::kMapIndex)); 1844 map_index->ClearFlag(HValue::kCanOverflow); 1845 HValue* key_index = AddUncasted<HAdd>( 1846 base_index, 1847 Add<HConstant>(probe_base + KeyedLookupCache::kKeyIndex)); 1848 key_index->ClearFlag(HValue::kCanOverflow); 1849 HValue* map_to_check = 1850 Add<HLoadKeyed>(cache_keys, map_index, static_cast<HValue*>(NULL), 1851 FAST_ELEMENTS, NEVER_RETURN_HOLE, 0); 1852 lookup_if->If<HCompareObjectEqAndBranch>(map_to_check, map); 1853 lookup_if->And(); 1854 HValue* key_to_check = 1855 Add<HLoadKeyed>(cache_keys, key_index, static_cast<HValue*>(NULL), 1856 FAST_ELEMENTS, NEVER_RETURN_HOLE, 0); 1857 lookup_if->If<HCompareObjectEqAndBranch>(key_to_check, key); 1858 lookup_if->Then(); 1859 { 1860 ExternalReference cache_field_offsets_ref = 1861 ExternalReference::keyed_lookup_cache_field_offsets(isolate()); 1862 HValue* cache_field_offsets = 1863 Add<HConstant>(cache_field_offsets_ref); 1864 HValue* index = AddUncasted<HAdd>(hash, Add<HConstant>(probe)); 1865 index->ClearFlag(HValue::kCanOverflow); 1866 HValue* property_index = Add<HLoadKeyed>( 1867 cache_field_offsets, index, static_cast<HValue*>(NULL), 1868 EXTERNAL_INT32_ELEMENTS, NEVER_RETURN_HOLE, 0); 1869 Push(property_index); 1870 } 1871 lookup_if->Else(); 1872 } 1873 for (int i = 0; i < KeyedLookupCache::kEntriesPerBucket; ++i) { 1874 lookup_ifs[i].JoinContinuation(&inline_or_runtime_continuation); 1875 } 1876 } 1877 1878 IfBuilder inline_or_runtime(this, &inline_or_runtime_continuation); 1879 inline_or_runtime.Then(); 1880 { 1881 // Found a cached index, load property inline. 1882 Push(Add<HLoadFieldByIndex>(receiver, Pop())); 1883 } 1884 inline_or_runtime.Else(); 1885 { 1886 // KeyedLookupCache miss; call runtime. 1887 Add<HPushArguments>(receiver, key); 1888 Push(Add<HCallRuntime>( 1889 isolate()->factory()->empty_string(), 1890 Runtime::FunctionForId(Runtime::kKeyedGetProperty), 2)); 1891 } 1892 inline_or_runtime.End(); 1893 } 1894 if_dict_properties.End(); 1895 } 1896 index_name_split.End(); 1897 1898 return Pop(); 1899 } 1900 1901 1902 Handle<Code> KeyedLoadGenericStub::GenerateCode() { 1903 return DoGenerateCode(this); 1904 } 1905 1906 1907 template <> 1908 HValue* CodeStubGraphBuilder<VectorLoadStub>::BuildCodeStub() { 1909 HValue* receiver = GetParameter(VectorLoadICDescriptor::kReceiverIndex); 1910 Add<HDeoptimize>("Always deopt", Deoptimizer::EAGER); 1911 return receiver; 1912 } 1913 1914 1915 Handle<Code> VectorLoadStub::GenerateCode() { return DoGenerateCode(this); } 1916 1917 1918 template <> 1919 HValue* CodeStubGraphBuilder<VectorKeyedLoadStub>::BuildCodeStub() { 1920 HValue* receiver = GetParameter(VectorLoadICDescriptor::kReceiverIndex); 1921 Add<HDeoptimize>("Always deopt", Deoptimizer::EAGER); 1922 return receiver; 1923 } 1924 1925 1926 Handle<Code> VectorKeyedLoadStub::GenerateCode() { 1927 return DoGenerateCode(this); 1928 } 1929 1930 1931 Handle<Code> MegamorphicLoadStub::GenerateCode() { 1932 return DoGenerateCode(this); 1933 } 1934 1935 1936 template <> 1937 HValue* CodeStubGraphBuilder<MegamorphicLoadStub>::BuildCodeStub() { 1938 // The return address is on the stack. 1939 HValue* receiver = GetParameter(LoadDescriptor::kReceiverIndex); 1940 HValue* name = GetParameter(LoadDescriptor::kNameIndex); 1941 1942 // Probe the stub cache. 1943 Code::Flags flags = Code::RemoveTypeAndHolderFromFlags( 1944 Code::ComputeHandlerFlags(Code::LOAD_IC)); 1945 Add<HTailCallThroughMegamorphicCache>(receiver, name, flags); 1946 1947 // We never continue. 1948 return graph()->GetConstant0(); 1949 } 1950 } } // namespace v8::internal 1951