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 <memory> 8 9 #include "src/bailout-reason.h" 10 #include "src/code-factory.h" 11 #include "src/crankshaft/hydrogen.h" 12 #include "src/crankshaft/lithium.h" 13 #include "src/field-index.h" 14 #include "src/ic/ic.h" 15 16 namespace v8 { 17 namespace internal { 18 19 20 static LChunk* OptimizeGraph(HGraph* graph) { 21 DisallowHeapAllocation no_allocation; 22 DisallowHandleAllocation no_handles; 23 DisallowHandleDereference no_deref; 24 25 DCHECK(graph != NULL); 26 BailoutReason bailout_reason = kNoReason; 27 if (!graph->Optimize(&bailout_reason)) { 28 FATAL(GetBailoutReason(bailout_reason)); 29 } 30 LChunk* chunk = LChunk::NewChunk(graph); 31 if (chunk == NULL) { 32 FATAL(GetBailoutReason(graph->info()->bailout_reason())); 33 } 34 return chunk; 35 } 36 37 38 class CodeStubGraphBuilderBase : public HGraphBuilder { 39 public: 40 explicit CodeStubGraphBuilderBase(CompilationInfo* info, CodeStub* code_stub) 41 : HGraphBuilder(info, code_stub->GetCallInterfaceDescriptor(), false), 42 arguments_length_(NULL), 43 info_(info), 44 code_stub_(code_stub), 45 descriptor_(code_stub), 46 context_(NULL) { 47 int parameter_count = GetParameterCount(); 48 parameters_.reset(new HParameter*[parameter_count]); 49 } 50 virtual bool BuildGraph(); 51 52 protected: 53 virtual HValue* BuildCodeStub() = 0; 54 int GetParameterCount() const { return descriptor_.GetParameterCount(); } 55 int GetRegisterParameterCount() const { 56 return descriptor_.GetRegisterParameterCount(); 57 } 58 HParameter* GetParameter(int parameter) { 59 DCHECK(parameter < GetParameterCount()); 60 return parameters_[parameter]; 61 } 62 Representation GetParameterRepresentation(int parameter) { 63 return RepresentationFromMachineType( 64 descriptor_.GetParameterType(parameter)); 65 } 66 bool IsParameterCountRegister(int index) const { 67 return descriptor_.GetRegisterParameter(index) 68 .is(descriptor_.stack_parameter_count()); 69 } 70 HValue* GetArgumentsLength() { 71 // This is initialized in BuildGraph() 72 DCHECK(arguments_length_ != NULL); 73 return arguments_length_; 74 } 75 CompilationInfo* info() { return info_; } 76 CodeStub* stub() { return code_stub_; } 77 HContext* context() { return context_; } 78 Isolate* isolate() { return info_->isolate(); } 79 80 HLoadNamedField* BuildLoadNamedField(HValue* object, FieldIndex index); 81 void BuildStoreNamedField(HValue* object, HValue* value, FieldIndex index, 82 Representation representation, 83 bool transition_to_field); 84 85 HValue* BuildPushElement(HValue* object, HValue* argc, 86 HValue* argument_elements, ElementsKind kind); 87 88 HValue* BuildToString(HValue* input, bool convert); 89 HValue* BuildToPrimitive(HValue* input, HValue* input_map); 90 91 private: 92 std::unique_ptr<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 } 131 start_environment->Bind(i, param); 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 typedef typename Stub::Descriptor Descriptor; 191 192 protected: 193 virtual HValue* BuildCodeStub() { 194 if (casted_stub()->IsUninitialized()) { 195 return BuildCodeUninitializedStub(); 196 } else { 197 return BuildCodeInitializedStub(); 198 } 199 } 200 201 virtual HValue* BuildCodeInitializedStub() { 202 UNIMPLEMENTED(); 203 return NULL; 204 } 205 206 virtual HValue* BuildCodeUninitializedStub() { 207 // Force a deopt that falls back to the runtime. 208 HValue* undefined = graph()->GetConstantUndefined(); 209 IfBuilder builder(this); 210 builder.IfNot<HCompareObjectEqAndBranch, HValue*>(undefined, undefined); 211 builder.Then(); 212 builder.ElseDeopt(DeoptimizeReason::kForcedDeoptToRuntime); 213 return undefined; 214 } 215 216 Stub* casted_stub() { return static_cast<Stub*>(stub()); } 217 }; 218 219 220 Handle<Code> HydrogenCodeStub::GenerateLightweightMissCode( 221 ExternalReference miss) { 222 Factory* factory = isolate()->factory(); 223 224 // Generate the new code. 225 MacroAssembler masm(isolate(), NULL, 256, CodeObjectRequired::kYes); 226 227 { 228 // Update the static counter each time a new code stub is generated. 229 isolate()->counters()->code_stubs()->Increment(); 230 231 // Generate the code for the stub. 232 masm.set_generating_stub(true); 233 // TODO(yangguo): remove this once we can serialize IC stubs. 234 masm.enable_serializer(); 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 Handle<Code> new_object = factory->NewCode( 245 desc, GetCodeFlags(), masm.CodeObject(), NeedsImmovableCode()); 246 return new_object; 247 } 248 249 Handle<Code> HydrogenCodeStub::GenerateRuntimeTailCall( 250 CodeStubDescriptor* descriptor) { 251 const char* name = CodeStub::MajorName(MajorKey()); 252 Zone zone(isolate()->allocator(), ZONE_NAME); 253 CallInterfaceDescriptor interface_descriptor(GetCallInterfaceDescriptor()); 254 CodeStubAssembler assembler(isolate(), &zone, interface_descriptor, 255 GetCodeFlags(), name); 256 int total_params = interface_descriptor.GetStackParameterCount() + 257 interface_descriptor.GetRegisterParameterCount(); 258 switch (total_params) { 259 case 0: 260 assembler.TailCallRuntime(descriptor->miss_handler_id(), 261 assembler.Parameter(0)); 262 break; 263 case 1: 264 assembler.TailCallRuntime(descriptor->miss_handler_id(), 265 assembler.Parameter(1), assembler.Parameter(0)); 266 break; 267 case 2: 268 assembler.TailCallRuntime(descriptor->miss_handler_id(), 269 assembler.Parameter(2), assembler.Parameter(0), 270 assembler.Parameter(1)); 271 break; 272 case 3: 273 assembler.TailCallRuntime(descriptor->miss_handler_id(), 274 assembler.Parameter(3), assembler.Parameter(0), 275 assembler.Parameter(1), assembler.Parameter(2)); 276 break; 277 case 4: 278 assembler.TailCallRuntime(descriptor->miss_handler_id(), 279 assembler.Parameter(4), assembler.Parameter(0), 280 assembler.Parameter(1), assembler.Parameter(2), 281 assembler.Parameter(3)); 282 break; 283 default: 284 UNIMPLEMENTED(); 285 break; 286 } 287 return assembler.GenerateCode(); 288 } 289 290 template <class Stub> 291 static Handle<Code> DoGenerateCode(Stub* stub) { 292 Isolate* isolate = stub->isolate(); 293 CodeStubDescriptor descriptor(stub); 294 295 if (FLAG_minimal && descriptor.has_miss_handler()) { 296 return stub->GenerateRuntimeTailCall(&descriptor); 297 } 298 299 // If we are uninitialized we can use a light-weight stub to enter 300 // the runtime that is significantly faster than using the standard 301 // stub-failure deopt mechanism. 302 if (stub->IsUninitialized() && descriptor.has_miss_handler()) { 303 DCHECK(!descriptor.stack_parameter_count().is_valid()); 304 return stub->GenerateLightweightMissCode(descriptor.miss_handler()); 305 } 306 base::ElapsedTimer timer; 307 if (FLAG_profile_hydrogen_code_stub_compilation) { 308 timer.Start(); 309 } 310 Zone zone(isolate->allocator(), ZONE_NAME); 311 CompilationInfo info(CStrVector(CodeStub::MajorName(stub->MajorKey())), 312 isolate, &zone, stub->GetCodeFlags()); 313 // Parameter count is number of stack parameters. 314 int parameter_count = descriptor.GetStackParameterCount(); 315 if (descriptor.function_mode() == NOT_JS_FUNCTION_STUB_MODE) { 316 parameter_count--; 317 } 318 info.set_parameter_count(parameter_count); 319 CodeStubGraphBuilder<Stub> builder(&info, stub); 320 LChunk* chunk = OptimizeGraph(builder.CreateGraph()); 321 Handle<Code> code = chunk->Codegen(); 322 if (FLAG_profile_hydrogen_code_stub_compilation) { 323 OFStream os(stdout); 324 os << "[Lazy compilation of " << stub << " took " 325 << timer.Elapsed().InMillisecondsF() << " ms]" << std::endl; 326 } 327 return code; 328 } 329 330 331 HValue* CodeStubGraphBuilderBase::BuildPushElement(HValue* object, HValue* argc, 332 HValue* argument_elements, 333 ElementsKind kind) { 334 // Precheck whether all elements fit into the array. 335 if (!IsFastObjectElementsKind(kind)) { 336 LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement); 337 HValue* start = graph()->GetConstant0(); 338 HValue* key = builder.BeginBody(start, argc, Token::LT); 339 { 340 HInstruction* argument = 341 Add<HAccessArgumentsAt>(argument_elements, argc, key); 342 IfBuilder can_store(this); 343 can_store.IfNot<HIsSmiAndBranch>(argument); 344 if (IsFastDoubleElementsKind(kind)) { 345 can_store.And(); 346 can_store.IfNot<HCompareMap>(argument, 347 isolate()->factory()->heap_number_map()); 348 } 349 can_store.ThenDeopt(DeoptimizeReason::kFastPathFailed); 350 can_store.End(); 351 } 352 builder.EndBody(); 353 } 354 355 HValue* length = Add<HLoadNamedField>(object, nullptr, 356 HObjectAccess::ForArrayLength(kind)); 357 HValue* new_length = AddUncasted<HAdd>(length, argc); 358 HValue* max_key = AddUncasted<HSub>(new_length, graph()->GetConstant1()); 359 360 HValue* elements = Add<HLoadNamedField>(object, nullptr, 361 HObjectAccess::ForElementsPointer()); 362 elements = BuildCheckForCapacityGrow(object, elements, kind, length, max_key, 363 true, STORE); 364 365 LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement); 366 HValue* start = graph()->GetConstant0(); 367 HValue* key = builder.BeginBody(start, argc, Token::LT); 368 { 369 HValue* argument = Add<HAccessArgumentsAt>(argument_elements, argc, key); 370 HValue* index = AddUncasted<HAdd>(key, length); 371 AddElementAccess(elements, index, argument, object, nullptr, kind, STORE); 372 } 373 builder.EndBody(); 374 return new_length; 375 } 376 377 template <> 378 HValue* CodeStubGraphBuilder<FastArrayPushStub>::BuildCodeStub() { 379 // TODO(verwaest): Fix deoptimizer messages. 380 HValue* argc = GetArgumentsLength(); 381 382 HInstruction* argument_elements = Add<HArgumentsElements>(false, false); 383 HInstruction* object = Add<HAccessArgumentsAt>(argument_elements, argc, 384 graph()->GetConstantMinus1()); 385 BuildCheckHeapObject(object); 386 HValue* map = Add<HLoadNamedField>(object, nullptr, HObjectAccess::ForMap()); 387 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_JS_ARRAY); 388 389 // Disallow pushing onto prototypes. It might be the JSArray prototype. 390 // Disallow pushing onto non-extensible objects. 391 { 392 HValue* bit_field2 = 393 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField2()); 394 HValue* mask = 395 Add<HConstant>(static_cast<int>(Map::IsPrototypeMapBits::kMask) | 396 (1 << Map::kIsExtensible)); 397 HValue* bits = AddUncasted<HBitwise>(Token::BIT_AND, bit_field2, mask); 398 IfBuilder check(this); 399 check.If<HCompareNumericAndBranch>( 400 bits, Add<HConstant>(1 << Map::kIsExtensible), Token::NE); 401 check.ThenDeopt(DeoptimizeReason::kFastPathFailed); 402 check.End(); 403 } 404 405 // Disallow pushing onto arrays in dictionary named property mode. We need to 406 // figure out whether the length property is still writable. 407 { 408 HValue* bit_field3 = 409 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField3()); 410 HValue* mask = Add<HConstant>(static_cast<int>(Map::DictionaryMap::kMask)); 411 HValue* bit = AddUncasted<HBitwise>(Token::BIT_AND, bit_field3, mask); 412 IfBuilder check(this); 413 check.If<HCompareNumericAndBranch>(bit, mask, Token::EQ); 414 check.ThenDeopt(DeoptimizeReason::kFastPathFailed); 415 check.End(); 416 } 417 418 // Check whether the length property is writable. The length property is the 419 // only default named property on arrays. It's nonconfigurable, hence is 420 // guaranteed to stay the first property. 421 { 422 HValue* descriptors = 423 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapDescriptors()); 424 HValue* details = Add<HLoadKeyed>( 425 descriptors, Add<HConstant>(DescriptorArray::ToDetailsIndex(0)), 426 nullptr, nullptr, FAST_SMI_ELEMENTS); 427 HValue* mask = 428 Add<HConstant>(READ_ONLY << PropertyDetails::AttributesField::kShift); 429 HValue* bit = AddUncasted<HBitwise>(Token::BIT_AND, details, mask); 430 IfBuilder readonly(this); 431 readonly.If<HCompareNumericAndBranch>(bit, mask, Token::EQ); 432 readonly.ThenDeopt(DeoptimizeReason::kFastPathFailed); 433 readonly.End(); 434 } 435 436 HValue* null = Add<HLoadRoot>(Heap::kNullValueRootIndex); 437 HValue* empty = Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex); 438 environment()->Push(map); 439 LoopBuilder check_prototypes(this); 440 check_prototypes.BeginBody(1); 441 { 442 HValue* parent_map = environment()->Pop(); 443 HValue* prototype = Add<HLoadNamedField>(parent_map, nullptr, 444 HObjectAccess::ForPrototype()); 445 446 IfBuilder is_null(this); 447 is_null.If<HCompareObjectEqAndBranch>(prototype, null); 448 is_null.Then(); 449 check_prototypes.Break(); 450 is_null.End(); 451 452 HValue* prototype_map = 453 Add<HLoadNamedField>(prototype, nullptr, HObjectAccess::ForMap()); 454 HValue* instance_type = Add<HLoadNamedField>( 455 prototype_map, nullptr, HObjectAccess::ForMapInstanceType()); 456 IfBuilder check_instance_type(this); 457 check_instance_type.If<HCompareNumericAndBranch>( 458 instance_type, Add<HConstant>(LAST_CUSTOM_ELEMENTS_RECEIVER), 459 Token::LTE); 460 check_instance_type.ThenDeopt(DeoptimizeReason::kFastPathFailed); 461 check_instance_type.End(); 462 463 HValue* elements = Add<HLoadNamedField>( 464 prototype, nullptr, HObjectAccess::ForElementsPointer()); 465 IfBuilder no_elements(this); 466 no_elements.IfNot<HCompareObjectEqAndBranch>(elements, empty); 467 no_elements.ThenDeopt(DeoptimizeReason::kFastPathFailed); 468 no_elements.End(); 469 470 environment()->Push(prototype_map); 471 } 472 check_prototypes.EndBody(); 473 474 HValue* bit_field2 = 475 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField2()); 476 HValue* kind = BuildDecodeField<Map::ElementsKindBits>(bit_field2); 477 478 // Below we only check the upper bound of the relevant ranges to include both 479 // holey and non-holey versions. We check them in order smi, object, double 480 // since smi < object < double. 481 STATIC_ASSERT(FAST_SMI_ELEMENTS < FAST_HOLEY_SMI_ELEMENTS); 482 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS < FAST_HOLEY_ELEMENTS); 483 STATIC_ASSERT(FAST_ELEMENTS < FAST_HOLEY_ELEMENTS); 484 STATIC_ASSERT(FAST_HOLEY_ELEMENTS < FAST_HOLEY_DOUBLE_ELEMENTS); 485 STATIC_ASSERT(FAST_DOUBLE_ELEMENTS < FAST_HOLEY_DOUBLE_ELEMENTS); 486 IfBuilder has_smi_elements(this); 487 has_smi_elements.If<HCompareNumericAndBranch>( 488 kind, Add<HConstant>(FAST_HOLEY_SMI_ELEMENTS), Token::LTE); 489 has_smi_elements.Then(); 490 { 491 HValue* new_length = BuildPushElement(object, argc, argument_elements, 492 FAST_HOLEY_SMI_ELEMENTS); 493 environment()->Push(new_length); 494 } 495 has_smi_elements.Else(); 496 { 497 IfBuilder has_object_elements(this); 498 has_object_elements.If<HCompareNumericAndBranch>( 499 kind, Add<HConstant>(FAST_HOLEY_ELEMENTS), Token::LTE); 500 has_object_elements.Then(); 501 { 502 HValue* new_length = BuildPushElement(object, argc, argument_elements, 503 FAST_HOLEY_ELEMENTS); 504 environment()->Push(new_length); 505 } 506 has_object_elements.Else(); 507 { 508 IfBuilder has_double_elements(this); 509 has_double_elements.If<HCompareNumericAndBranch>( 510 kind, Add<HConstant>(FAST_HOLEY_DOUBLE_ELEMENTS), Token::LTE); 511 has_double_elements.Then(); 512 { 513 HValue* new_length = BuildPushElement(object, argc, argument_elements, 514 FAST_HOLEY_DOUBLE_ELEMENTS); 515 environment()->Push(new_length); 516 } 517 has_double_elements.ElseDeopt(DeoptimizeReason::kFastPathFailed); 518 has_double_elements.End(); 519 } 520 has_object_elements.End(); 521 } 522 has_smi_elements.End(); 523 524 return environment()->Pop(); 525 } 526 527 Handle<Code> FastArrayPushStub::GenerateCode() { return DoGenerateCode(this); } 528 529 template <> 530 HValue* CodeStubGraphBuilder<FastFunctionBindStub>::BuildCodeStub() { 531 // TODO(verwaest): Fix deoptimizer messages. 532 HValue* argc = GetArgumentsLength(); 533 HInstruction* argument_elements = Add<HArgumentsElements>(false, false); 534 HInstruction* object = Add<HAccessArgumentsAt>(argument_elements, argc, 535 graph()->GetConstantMinus1()); 536 BuildCheckHeapObject(object); 537 HValue* map = Add<HLoadNamedField>(object, nullptr, HObjectAccess::ForMap()); 538 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_JS_FUNCTION); 539 540 // Disallow binding of slow-mode functions. We need to figure out whether the 541 // length and name property are in the original state. 542 { 543 HValue* bit_field3 = 544 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField3()); 545 HValue* mask = Add<HConstant>(static_cast<int>(Map::DictionaryMap::kMask)); 546 HValue* bit = AddUncasted<HBitwise>(Token::BIT_AND, bit_field3, mask); 547 IfBuilder check(this); 548 check.If<HCompareNumericAndBranch>(bit, mask, Token::EQ); 549 check.ThenDeopt(DeoptimizeReason::kFastPathFailed); 550 check.End(); 551 } 552 553 // Check whether the length and name properties are still present as 554 // AccessorInfo objects. In that case, their value can be recomputed even if 555 // the actual value on the object changes. 556 { 557 HValue* descriptors = 558 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapDescriptors()); 559 560 HValue* descriptors_length = Add<HLoadNamedField>( 561 descriptors, nullptr, HObjectAccess::ForFixedArrayLength()); 562 IfBuilder range(this); 563 range.If<HCompareNumericAndBranch>(descriptors_length, 564 graph()->GetConstant1(), Token::LTE); 565 range.ThenDeopt(DeoptimizeReason::kFastPathFailed); 566 range.End(); 567 568 // Verify .length. 569 const int length_index = JSFunction::kLengthDescriptorIndex; 570 HValue* maybe_length = Add<HLoadKeyed>( 571 descriptors, Add<HConstant>(DescriptorArray::ToKeyIndex(length_index)), 572 nullptr, nullptr, FAST_ELEMENTS); 573 Unique<Name> length_string = Unique<Name>::CreateUninitialized( 574 isolate()->factory()->length_string()); 575 Add<HCheckValue>(maybe_length, length_string, false); 576 577 HValue* maybe_length_accessor = Add<HLoadKeyed>( 578 descriptors, 579 Add<HConstant>(DescriptorArray::ToValueIndex(length_index)), nullptr, 580 nullptr, FAST_ELEMENTS); 581 BuildCheckHeapObject(maybe_length_accessor); 582 Add<HCheckMaps>(maybe_length_accessor, 583 isolate()->factory()->accessor_info_map()); 584 585 // Verify .name. 586 const int name_index = JSFunction::kNameDescriptorIndex; 587 HValue* maybe_name = Add<HLoadKeyed>( 588 descriptors, Add<HConstant>(DescriptorArray::ToKeyIndex(name_index)), 589 nullptr, nullptr, FAST_ELEMENTS); 590 Unique<Name> name_string = 591 Unique<Name>::CreateUninitialized(isolate()->factory()->name_string()); 592 Add<HCheckValue>(maybe_name, name_string, false); 593 594 HValue* maybe_name_accessor = Add<HLoadKeyed>( 595 descriptors, Add<HConstant>(DescriptorArray::ToValueIndex(name_index)), 596 nullptr, nullptr, FAST_ELEMENTS); 597 BuildCheckHeapObject(maybe_name_accessor); 598 Add<HCheckMaps>(maybe_name_accessor, 599 isolate()->factory()->accessor_info_map()); 600 } 601 602 // Choose the right bound function map based on whether the target is 603 // constructable. 604 { 605 HValue* bit_field = 606 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField()); 607 HValue* mask = Add<HConstant>(static_cast<int>(1 << Map::kIsConstructor)); 608 HValue* bits = AddUncasted<HBitwise>(Token::BIT_AND, bit_field, mask); 609 610 HValue* native_context = BuildGetNativeContext(); 611 IfBuilder is_constructor(this); 612 is_constructor.If<HCompareNumericAndBranch>(bits, mask, Token::EQ); 613 is_constructor.Then(); 614 { 615 HValue* map = Add<HLoadNamedField>( 616 native_context, nullptr, 617 HObjectAccess::ForContextSlot( 618 Context::BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX)); 619 environment()->Push(map); 620 } 621 is_constructor.Else(); 622 { 623 HValue* map = Add<HLoadNamedField>( 624 native_context, nullptr, 625 HObjectAccess::ForContextSlot( 626 Context::BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX)); 627 environment()->Push(map); 628 } 629 is_constructor.End(); 630 } 631 HValue* bound_function_map = environment()->Pop(); 632 633 // Verify that __proto__ matches that of a the target bound function. 634 { 635 HValue* prototype = 636 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForPrototype()); 637 HValue* expected_prototype = Add<HLoadNamedField>( 638 bound_function_map, nullptr, HObjectAccess::ForPrototype()); 639 IfBuilder equal_prototype(this); 640 equal_prototype.IfNot<HCompareObjectEqAndBranch>(prototype, 641 expected_prototype); 642 equal_prototype.ThenDeopt(DeoptimizeReason::kFastPathFailed); 643 equal_prototype.End(); 644 } 645 646 // Allocate the arguments array. 647 IfBuilder empty_args(this); 648 empty_args.If<HCompareNumericAndBranch>(argc, graph()->GetConstant1(), 649 Token::LTE); 650 empty_args.Then(); 651 { environment()->Push(Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex)); } 652 empty_args.Else(); 653 { 654 HValue* elements_length = AddUncasted<HSub>(argc, graph()->GetConstant1()); 655 HValue* elements = 656 BuildAllocateAndInitializeArray(FAST_ELEMENTS, elements_length); 657 658 LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement); 659 HValue* start = graph()->GetConstant1(); 660 HValue* key = builder.BeginBody(start, argc, Token::LT); 661 { 662 HValue* argument = Add<HAccessArgumentsAt>(argument_elements, argc, key); 663 HValue* index = AddUncasted<HSub>(key, graph()->GetConstant1()); 664 AddElementAccess(elements, index, argument, elements, nullptr, 665 FAST_ELEMENTS, STORE); 666 } 667 builder.EndBody(); 668 environment()->Push(elements); 669 } 670 empty_args.End(); 671 HValue* elements = environment()->Pop(); 672 673 // Find the 'this' to bind. 674 IfBuilder no_receiver(this); 675 no_receiver.If<HCompareNumericAndBranch>(argc, graph()->GetConstant0(), 676 Token::EQ); 677 no_receiver.Then(); 678 { environment()->Push(Add<HLoadRoot>(Heap::kUndefinedValueRootIndex)); } 679 no_receiver.Else(); 680 { 681 environment()->Push(Add<HAccessArgumentsAt>(argument_elements, argc, 682 graph()->GetConstant0())); 683 } 684 no_receiver.End(); 685 HValue* receiver = environment()->Pop(); 686 687 // Allocate the resulting bound function. 688 HValue* size = Add<HConstant>(JSBoundFunction::kSize); 689 HValue* bound_function = 690 Add<HAllocate>(size, HType::JSObject(), NOT_TENURED, 691 JS_BOUND_FUNCTION_TYPE, graph()->GetConstant0()); 692 Add<HStoreNamedField>(bound_function, HObjectAccess::ForMap(), 693 bound_function_map); 694 HValue* empty_fixed_array = Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex); 695 Add<HStoreNamedField>(bound_function, HObjectAccess::ForPropertiesPointer(), 696 empty_fixed_array); 697 Add<HStoreNamedField>(bound_function, HObjectAccess::ForElementsPointer(), 698 empty_fixed_array); 699 Add<HStoreNamedField>(bound_function, HObjectAccess::ForBoundTargetFunction(), 700 object); 701 702 Add<HStoreNamedField>(bound_function, HObjectAccess::ForBoundThis(), 703 receiver); 704 Add<HStoreNamedField>(bound_function, HObjectAccess::ForBoundArguments(), 705 elements); 706 707 return bound_function; 708 } 709 710 Handle<Code> FastFunctionBindStub::GenerateCode() { 711 return DoGenerateCode(this); 712 } 713 714 template <> 715 HValue* CodeStubGraphBuilder<LoadFastElementStub>::BuildCodeStub() { 716 LoadKeyedHoleMode hole_mode = casted_stub()->convert_hole_to_undefined() 717 ? CONVERT_HOLE_TO_UNDEFINED 718 : NEVER_RETURN_HOLE; 719 720 HInstruction* load = BuildUncheckedMonomorphicElementAccess( 721 GetParameter(Descriptor::kReceiver), GetParameter(Descriptor::kName), 722 NULL, casted_stub()->is_js_array(), casted_stub()->elements_kind(), LOAD, 723 hole_mode, STANDARD_STORE); 724 return load; 725 } 726 727 728 Handle<Code> LoadFastElementStub::GenerateCode() { 729 return DoGenerateCode(this); 730 } 731 732 733 HLoadNamedField* CodeStubGraphBuilderBase::BuildLoadNamedField( 734 HValue* object, FieldIndex index) { 735 Representation representation = index.is_double() 736 ? Representation::Double() 737 : Representation::Tagged(); 738 int offset = index.offset(); 739 HObjectAccess access = index.is_inobject() 740 ? HObjectAccess::ForObservableJSObjectOffset(offset, representation) 741 : HObjectAccess::ForBackingStoreOffset(offset, representation); 742 if (index.is_double() && 743 (!FLAG_unbox_double_fields || !index.is_inobject())) { 744 // Load the heap number. 745 object = Add<HLoadNamedField>( 746 object, nullptr, access.WithRepresentation(Representation::Tagged())); 747 // Load the double value from it. 748 access = HObjectAccess::ForHeapNumberValue(); 749 } 750 return Add<HLoadNamedField>(object, nullptr, access); 751 } 752 753 754 template<> 755 HValue* CodeStubGraphBuilder<LoadFieldStub>::BuildCodeStub() { 756 return BuildLoadNamedField(GetParameter(Descriptor::kReceiver), 757 casted_stub()->index()); 758 } 759 760 761 Handle<Code> LoadFieldStub::GenerateCode() { 762 return DoGenerateCode(this); 763 } 764 765 766 template <> 767 HValue* CodeStubGraphBuilder<LoadConstantStub>::BuildCodeStub() { 768 HValue* map = AddLoadMap(GetParameter(Descriptor::kReceiver), NULL); 769 HObjectAccess descriptors_access = HObjectAccess::ForObservableJSObjectOffset( 770 Map::kDescriptorsOffset, Representation::Tagged()); 771 HValue* descriptors = Add<HLoadNamedField>(map, nullptr, descriptors_access); 772 HObjectAccess value_access = HObjectAccess::ForObservableJSObjectOffset( 773 DescriptorArray::GetValueOffset(casted_stub()->constant_index())); 774 return Add<HLoadNamedField>(descriptors, nullptr, value_access); 775 } 776 777 778 Handle<Code> LoadConstantStub::GenerateCode() { return DoGenerateCode(this); } 779 780 781 void CodeStubGraphBuilderBase::BuildStoreNamedField( 782 HValue* object, HValue* value, FieldIndex index, 783 Representation representation, bool transition_to_field) { 784 DCHECK(!index.is_double() || representation.IsDouble()); 785 int offset = index.offset(); 786 HObjectAccess access = 787 index.is_inobject() 788 ? HObjectAccess::ForObservableJSObjectOffset(offset, representation) 789 : HObjectAccess::ForBackingStoreOffset(offset, representation); 790 791 if (representation.IsDouble()) { 792 if (!FLAG_unbox_double_fields || !index.is_inobject()) { 793 HObjectAccess heap_number_access = 794 access.WithRepresentation(Representation::Tagged()); 795 if (transition_to_field) { 796 // The store requires a mutable HeapNumber to be allocated. 797 NoObservableSideEffectsScope no_side_effects(this); 798 HInstruction* heap_number_size = Add<HConstant>(HeapNumber::kSize); 799 800 // TODO(hpayer): Allocation site pretenuring support. 801 HInstruction* heap_number = 802 Add<HAllocate>(heap_number_size, HType::HeapObject(), NOT_TENURED, 803 MUTABLE_HEAP_NUMBER_TYPE, graph()->GetConstant0()); 804 AddStoreMapConstant(heap_number, 805 isolate()->factory()->mutable_heap_number_map()); 806 Add<HStoreNamedField>(heap_number, HObjectAccess::ForHeapNumberValue(), 807 value); 808 // Store the new mutable heap number into the object. 809 access = heap_number_access; 810 value = heap_number; 811 } else { 812 // Load the heap number. 813 object = Add<HLoadNamedField>(object, nullptr, heap_number_access); 814 // Store the double value into it. 815 access = HObjectAccess::ForHeapNumberValue(); 816 } 817 } 818 } else if (representation.IsHeapObject()) { 819 BuildCheckHeapObject(value); 820 } 821 822 Add<HStoreNamedField>(object, access, value, INITIALIZING_STORE); 823 } 824 825 826 template <> 827 HValue* CodeStubGraphBuilder<TransitionElementsKindStub>::BuildCodeStub() { 828 ElementsKind const from_kind = casted_stub()->from_kind(); 829 ElementsKind const to_kind = casted_stub()->to_kind(); 830 HValue* const object = GetParameter(Descriptor::kObject); 831 HValue* const map = GetParameter(Descriptor::kMap); 832 833 // The {object} is known to be a JSObject (otherwise it wouldn't have elements 834 // anyways). 835 object->set_type(HType::JSObject()); 836 837 info()->MarkAsSavesCallerDoubles(); 838 839 DCHECK_IMPLIES(IsFastHoleyElementsKind(from_kind), 840 IsFastHoleyElementsKind(to_kind)); 841 842 if (AllocationSite::GetMode(from_kind, to_kind) == TRACK_ALLOCATION_SITE) { 843 Add<HTrapAllocationMemento>(object); 844 } 845 846 if (!IsSimpleMapChangeTransition(from_kind, to_kind)) { 847 HInstruction* elements = AddLoadElements(object); 848 849 IfBuilder if_objecthaselements(this); 850 if_objecthaselements.IfNot<HCompareObjectEqAndBranch>( 851 elements, Add<HConstant>(isolate()->factory()->empty_fixed_array())); 852 if_objecthaselements.Then(); 853 { 854 // Determine the elements capacity. 855 HInstruction* elements_length = AddLoadFixedArrayLength(elements); 856 857 // Determine the effective (array) length. 858 IfBuilder if_objectisarray(this); 859 if_objectisarray.If<HHasInstanceTypeAndBranch>(object, JS_ARRAY_TYPE); 860 if_objectisarray.Then(); 861 { 862 // The {object} is a JSArray, load the special "length" property. 863 Push(Add<HLoadNamedField>(object, nullptr, 864 HObjectAccess::ForArrayLength(from_kind))); 865 } 866 if_objectisarray.Else(); 867 { 868 // The {object} is some other JSObject. 869 Push(elements_length); 870 } 871 if_objectisarray.End(); 872 HValue* length = Pop(); 873 874 BuildGrowElementsCapacity(object, elements, from_kind, to_kind, length, 875 elements_length); 876 } 877 if_objecthaselements.End(); 878 } 879 880 Add<HStoreNamedField>(object, HObjectAccess::ForMap(), map); 881 882 return object; 883 } 884 885 886 Handle<Code> TransitionElementsKindStub::GenerateCode() { 887 return DoGenerateCode(this); 888 } 889 890 template <> 891 HValue* CodeStubGraphBuilder<BinaryOpICStub>::BuildCodeInitializedStub() { 892 BinaryOpICState state = casted_stub()->state(); 893 894 HValue* left = GetParameter(Descriptor::kLeft); 895 HValue* right = GetParameter(Descriptor::kRight); 896 897 AstType* left_type = state.GetLeftType(); 898 AstType* right_type = state.GetRightType(); 899 AstType* result_type = state.GetResultType(); 900 901 DCHECK(!left_type->Is(AstType::None()) && !right_type->Is(AstType::None()) && 902 (state.HasSideEffects() || !result_type->Is(AstType::None()))); 903 904 HValue* result = NULL; 905 HAllocationMode allocation_mode(NOT_TENURED); 906 if (state.op() == Token::ADD && (left_type->Maybe(AstType::String()) || 907 right_type->Maybe(AstType::String())) && 908 !left_type->Is(AstType::String()) && !right_type->Is(AstType::String())) { 909 // For the generic add stub a fast case for string addition is performance 910 // critical. 911 if (left_type->Maybe(AstType::String())) { 912 IfBuilder if_leftisstring(this); 913 if_leftisstring.If<HIsStringAndBranch>(left); 914 if_leftisstring.Then(); 915 { 916 Push(BuildBinaryOperation(state.op(), left, right, AstType::String(), 917 right_type, result_type, 918 state.fixed_right_arg(), allocation_mode)); 919 } 920 if_leftisstring.Else(); 921 { 922 Push(BuildBinaryOperation(state.op(), left, right, left_type, 923 right_type, result_type, 924 state.fixed_right_arg(), allocation_mode)); 925 } 926 if_leftisstring.End(); 927 result = Pop(); 928 } else { 929 IfBuilder if_rightisstring(this); 930 if_rightisstring.If<HIsStringAndBranch>(right); 931 if_rightisstring.Then(); 932 { 933 Push(BuildBinaryOperation(state.op(), left, right, left_type, 934 AstType::String(), result_type, 935 state.fixed_right_arg(), allocation_mode)); 936 } 937 if_rightisstring.Else(); 938 { 939 Push(BuildBinaryOperation(state.op(), left, right, left_type, 940 right_type, result_type, 941 state.fixed_right_arg(), allocation_mode)); 942 } 943 if_rightisstring.End(); 944 result = Pop(); 945 } 946 } else { 947 result = BuildBinaryOperation(state.op(), left, right, left_type, 948 right_type, result_type, 949 state.fixed_right_arg(), allocation_mode); 950 } 951 952 // If we encounter a generic argument, the number conversion is 953 // observable, thus we cannot afford to bail out after the fact. 954 if (!state.HasSideEffects()) { 955 result = EnforceNumberType(result, result_type); 956 } 957 958 return result; 959 } 960 961 962 Handle<Code> BinaryOpICStub::GenerateCode() { 963 return DoGenerateCode(this); 964 } 965 966 967 template <> 968 HValue* CodeStubGraphBuilder<BinaryOpWithAllocationSiteStub>::BuildCodeStub() { 969 BinaryOpICState state = casted_stub()->state(); 970 971 HValue* allocation_site = GetParameter(Descriptor::kAllocationSite); 972 HValue* left = GetParameter(Descriptor::kLeft); 973 HValue* right = GetParameter(Descriptor::kRight); 974 975 AstType* left_type = state.GetLeftType(); 976 AstType* right_type = state.GetRightType(); 977 AstType* result_type = state.GetResultType(); 978 HAllocationMode allocation_mode(allocation_site); 979 980 return BuildBinaryOperation(state.op(), left, right, left_type, right_type, 981 result_type, state.fixed_right_arg(), 982 allocation_mode); 983 } 984 985 986 Handle<Code> BinaryOpWithAllocationSiteStub::GenerateCode() { 987 return DoGenerateCode(this); 988 } 989 990 991 HValue* CodeStubGraphBuilderBase::BuildToString(HValue* input, bool convert) { 992 if (!convert) return BuildCheckString(input); 993 IfBuilder if_inputissmi(this); 994 HValue* inputissmi = if_inputissmi.If<HIsSmiAndBranch>(input); 995 if_inputissmi.Then(); 996 { 997 // Convert the input smi to a string. 998 Push(BuildNumberToString(input, AstType::SignedSmall())); 999 } 1000 if_inputissmi.Else(); 1001 { 1002 HValue* input_map = 1003 Add<HLoadNamedField>(input, inputissmi, HObjectAccess::ForMap()); 1004 HValue* input_instance_type = Add<HLoadNamedField>( 1005 input_map, inputissmi, HObjectAccess::ForMapInstanceType()); 1006 IfBuilder if_inputisstring(this); 1007 if_inputisstring.If<HCompareNumericAndBranch>( 1008 input_instance_type, Add<HConstant>(FIRST_NONSTRING_TYPE), Token::LT); 1009 if_inputisstring.Then(); 1010 { 1011 // The input is already a string. 1012 Push(input); 1013 } 1014 if_inputisstring.Else(); 1015 { 1016 // Convert to primitive first (if necessary), see 1017 // ES6 section 12.7.3 The Addition operator. 1018 IfBuilder if_inputisprimitive(this); 1019 STATIC_ASSERT(FIRST_PRIMITIVE_TYPE == FIRST_TYPE); 1020 if_inputisprimitive.If<HCompareNumericAndBranch>( 1021 input_instance_type, Add<HConstant>(LAST_PRIMITIVE_TYPE), Token::LTE); 1022 if_inputisprimitive.Then(); 1023 { 1024 // The input is already a primitive. 1025 Push(input); 1026 } 1027 if_inputisprimitive.Else(); 1028 { 1029 // Convert the input to a primitive. 1030 Push(BuildToPrimitive(input, input_map)); 1031 } 1032 if_inputisprimitive.End(); 1033 // Convert the primitive to a string value. 1034 HValue* values[] = {Pop()}; 1035 Callable toString = CodeFactory::ToString(isolate()); 1036 Push(AddUncasted<HCallWithDescriptor>(Add<HConstant>(toString.code()), 0, 1037 toString.descriptor(), 1038 ArrayVector(values))); 1039 } 1040 if_inputisstring.End(); 1041 } 1042 if_inputissmi.End(); 1043 return Pop(); 1044 } 1045 1046 1047 HValue* CodeStubGraphBuilderBase::BuildToPrimitive(HValue* input, 1048 HValue* input_map) { 1049 // Get the native context of the caller. 1050 HValue* native_context = BuildGetNativeContext(); 1051 1052 // Determine the initial map of the %ObjectPrototype%. 1053 HValue* object_function_prototype_map = 1054 Add<HLoadNamedField>(native_context, nullptr, 1055 HObjectAccess::ForContextSlot( 1056 Context::OBJECT_FUNCTION_PROTOTYPE_MAP_INDEX)); 1057 1058 // Determine the initial map of the %StringPrototype%. 1059 HValue* string_function_prototype_map = 1060 Add<HLoadNamedField>(native_context, nullptr, 1061 HObjectAccess::ForContextSlot( 1062 Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX)); 1063 1064 // Determine the initial map of the String function. 1065 HValue* string_function = Add<HLoadNamedField>( 1066 native_context, nullptr, 1067 HObjectAccess::ForContextSlot(Context::STRING_FUNCTION_INDEX)); 1068 HValue* string_function_initial_map = Add<HLoadNamedField>( 1069 string_function, nullptr, HObjectAccess::ForPrototypeOrInitialMap()); 1070 1071 // Determine the map of the [[Prototype]] of {input}. 1072 HValue* input_prototype = 1073 Add<HLoadNamedField>(input_map, nullptr, HObjectAccess::ForPrototype()); 1074 HValue* input_prototype_map = 1075 Add<HLoadNamedField>(input_prototype, nullptr, HObjectAccess::ForMap()); 1076 1077 // For string wrappers (JSValue instances with [[StringData]] internal 1078 // fields), we can shortcirciut the ToPrimitive if 1079 // 1080 // (a) the {input} map matches the initial map of the String function, 1081 // (b) the {input} [[Prototype]] is the unmodified %StringPrototype% (i.e. 1082 // no one monkey-patched toString, @@toPrimitive or valueOf), and 1083 // (c) the %ObjectPrototype% (i.e. the [[Prototype]] of the 1084 // %StringPrototype%) is also unmodified, that is no one sneaked a 1085 // @@toPrimitive into the %ObjectPrototype%. 1086 // 1087 // If all these assumptions hold, we can just take the [[StringData]] value 1088 // and return it. 1089 // TODO(bmeurer): This just repairs a regression introduced by removing the 1090 // weird (and broken) intrinsic %_IsStringWrapperSafeForDefaultValue, which 1091 // was intendend to something similar to this, although less efficient and 1092 // wrong in the presence of @@toPrimitive. Long-term we might want to move 1093 // into the direction of having a ToPrimitiveStub that can do common cases 1094 // while staying in JavaScript land (i.e. not going to C++). 1095 IfBuilder if_inputisstringwrapper(this); 1096 if_inputisstringwrapper.If<HCompareObjectEqAndBranch>( 1097 input_map, string_function_initial_map); 1098 if_inputisstringwrapper.And(); 1099 if_inputisstringwrapper.If<HCompareObjectEqAndBranch>( 1100 input_prototype_map, string_function_prototype_map); 1101 if_inputisstringwrapper.And(); 1102 if_inputisstringwrapper.If<HCompareObjectEqAndBranch>( 1103 Add<HLoadNamedField>(Add<HLoadNamedField>(input_prototype_map, nullptr, 1104 HObjectAccess::ForPrototype()), 1105 nullptr, HObjectAccess::ForMap()), 1106 object_function_prototype_map); 1107 if_inputisstringwrapper.Then(); 1108 { 1109 Push(BuildLoadNamedField( 1110 input, FieldIndex::ForInObjectOffset(JSValue::kValueOffset))); 1111 } 1112 if_inputisstringwrapper.Else(); 1113 { 1114 // TODO(bmeurer): Add support for fast ToPrimitive conversion using 1115 // a dedicated ToPrimitiveStub. 1116 Add<HPushArguments>(input); 1117 Push(Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kToPrimitive), 1)); 1118 } 1119 if_inputisstringwrapper.End(); 1120 return Pop(); 1121 } 1122 1123 template <> 1124 HValue* CodeStubGraphBuilder<ToBooleanICStub>::BuildCodeInitializedStub() { 1125 ToBooleanICStub* stub = casted_stub(); 1126 IfBuilder if_true(this); 1127 if_true.If<HBranch>(GetParameter(Descriptor::kArgument), stub->hints()); 1128 if_true.Then(); 1129 if_true.Return(graph()->GetConstantTrue()); 1130 if_true.Else(); 1131 if_true.End(); 1132 return graph()->GetConstantFalse(); 1133 } 1134 1135 Handle<Code> ToBooleanICStub::GenerateCode() { return DoGenerateCode(this); } 1136 1137 template <> 1138 HValue* CodeStubGraphBuilder<LoadDictionaryElementStub>::BuildCodeStub() { 1139 HValue* receiver = GetParameter(Descriptor::kReceiver); 1140 HValue* key = GetParameter(Descriptor::kName); 1141 1142 Add<HCheckSmi>(key); 1143 1144 HValue* elements = AddLoadElements(receiver); 1145 1146 HValue* hash = BuildElementIndexHash(key); 1147 1148 return BuildUncheckedDictionaryElementLoad(receiver, elements, key, hash); 1149 } 1150 1151 1152 Handle<Code> LoadDictionaryElementStub::GenerateCode() { 1153 return DoGenerateCode(this); 1154 } 1155 1156 } // namespace internal 1157 } // namespace v8 1158