LCOV - code coverage report
Current view: top level - src - code-stubs-hydrogen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 139 184 75.5 %
Date: 2017-04-26 Functions: 21 37 56.8 %

          Line data    Source code
       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/assembler-inl.h"
      10             : #include "src/bailout-reason.h"
      11             : #include "src/code-factory.h"
      12             : #include "src/code-stub-assembler.h"
      13             : #include "src/crankshaft/hydrogen.h"
      14             : #include "src/crankshaft/lithium.h"
      15             : #include "src/field-index.h"
      16             : #include "src/ic/ic.h"
      17             : #include "src/objects-inl.h"
      18             : 
      19             : namespace v8 {
      20             : namespace internal {
      21             : 
      22             : 
      23       23533 : static LChunk* OptimizeGraph(HGraph* graph) {
      24             :   DisallowHeapAllocation no_allocation;
      25             :   DisallowHandleAllocation no_handles;
      26             :   DisallowHandleDereference no_deref;
      27             : 
      28             :   DCHECK(graph != NULL);
      29       23533 :   BailoutReason bailout_reason = kNoReason;
      30       23533 :   if (!graph->Optimize(&bailout_reason)) {
      31           0 :     FATAL(GetBailoutReason(bailout_reason));
      32             :   }
      33       23533 :   LChunk* chunk = LChunk::NewChunk(graph);
      34       23533 :   if (chunk == NULL) {
      35           0 :     FATAL(GetBailoutReason(graph->info()->bailout_reason()));
      36             :   }
      37       23533 :   return chunk;
      38             : }
      39             : 
      40             : 
      41       47066 : class CodeStubGraphBuilderBase : public HGraphBuilder {
      42             :  public:
      43       23533 :   explicit CodeStubGraphBuilderBase(CompilationInfo* info, CodeStub* code_stub)
      44       23533 :       : HGraphBuilder(info, code_stub->GetCallInterfaceDescriptor(), false),
      45             :         arguments_length_(NULL),
      46             :         info_(info),
      47             :         code_stub_(code_stub),
      48             :         descriptor_(code_stub),
      49       47066 :         context_(NULL) {
      50             :     int parameter_count = GetParameterCount();
      51       23533 :     parameters_.reset(new HParameter*[parameter_count]);
      52       23533 :   }
      53             :   virtual bool BuildGraph();
      54             : 
      55             :  protected:
      56             :   virtual HValue* BuildCodeStub() = 0;
      57             :   int GetParameterCount() const { return descriptor_.GetParameterCount(); }
      58             :   int GetRegisterParameterCount() const {
      59             :     return descriptor_.GetRegisterParameterCount();
      60             :   }
      61             :   HParameter* GetParameter(int parameter) {
      62             :     DCHECK(parameter < GetParameterCount());
      63       23533 :     return parameters_[parameter];
      64             :   }
      65       37177 :   Representation GetParameterRepresentation(int parameter) {
      66             :     return RepresentationFromMachineType(
      67       37177 :         descriptor_.GetParameterType(parameter));
      68             :   }
      69             :   bool IsParameterCountRegister(int index) const {
      70             :     return descriptor_.GetRegisterParameter(index)
      71             :         .is(descriptor_.stack_parameter_count());
      72             :   }
      73             :   HValue* GetArgumentsLength() {
      74             :     // This is initialized in BuildGraph()
      75             :     DCHECK(arguments_length_ != NULL);
      76             :     return arguments_length_;
      77             :   }
      78             :   CompilationInfo* info() { return info_; }
      79             :   CodeStub* stub() { return code_stub_; }
      80      581974 :   HContext* context() { return context_; }
      81       23587 :   Isolate* isolate() { return info_->isolate(); }
      82             : 
      83             :  private:
      84             :   std::unique_ptr<HParameter* []> parameters_;
      85             :   HValue* arguments_length_;
      86             :   CompilationInfo* info_;
      87             :   CodeStub* code_stub_;
      88             :   CodeStubDescriptor descriptor_;
      89             :   HContext* context_;
      90             : };
      91             : 
      92             : 
      93       23533 : bool CodeStubGraphBuilderBase::BuildGraph() {
      94             :   // Update the static counter each time a new code stub is generated.
      95       23533 :   isolate()->counters()->code_stubs()->Increment();
      96             : 
      97       23533 :   if (FLAG_trace_hydrogen_stubs) {
      98           0 :     const char* name = CodeStub::MajorName(stub()->MajorKey());
      99           0 :     PrintF("-----------------------------------------------------------\n");
     100           0 :     PrintF("Compiling stub %s using hydrogen\n", name);
     101           0 :     isolate()->GetHTracer()->TraceCompilation(info());
     102             :   }
     103             : 
     104             :   int param_count = GetParameterCount();
     105             :   int register_param_count = GetRegisterParameterCount();
     106       70599 :   HEnvironment* start_environment = graph()->start_environment();
     107       23533 :   HBasicBlock* next_block = CreateBasicBlock(start_environment);
     108             :   Goto(next_block);
     109       23533 :   next_block->SetJoinId(BailoutId::StubEntry());
     110             :   set_current_block(next_block);
     111             : 
     112       23533 :   bool runtime_stack_params = descriptor_.stack_parameter_count().is_valid();
     113             :   HInstruction* stack_parameter_count = NULL;
     114       60710 :   for (int i = 0; i < param_count; ++i) {
     115       37177 :     Representation r = GetParameterRepresentation(i);
     116             :     HParameter* param;
     117       37177 :     if (i >= register_param_count) {
     118             :       param = Add<HParameter>(i - register_param_count,
     119           0 :                               HParameter::STACK_PARAMETER, r);
     120             :     } else {
     121       37177 :       param = Add<HParameter>(i, HParameter::REGISTER_PARAMETER, r);
     122             :     }
     123       37177 :     start_environment->Bind(i, param);
     124       74354 :     parameters_[i] = param;
     125       74354 :     if (i < register_param_count && IsParameterCountRegister(i)) {
     126             :       param->set_type(HType::Smi());
     127             :       stack_parameter_count = param;
     128           0 :       arguments_length_ = stack_parameter_count;
     129             :     }
     130             :   }
     131             : 
     132             :   DCHECK(!runtime_stack_params || arguments_length_ != NULL);
     133       23533 :   if (!runtime_stack_params) {
     134             :     stack_parameter_count =
     135       23533 :         Add<HConstant>(param_count - register_param_count - 1);
     136             :     // graph()->GetConstantMinus1();
     137       23533 :     arguments_length_ = graph()->GetConstant0();
     138             :   }
     139             : 
     140       23533 :   context_ = Add<HContext>();
     141             :   start_environment->BindContext(context_);
     142       23533 :   start_environment->Bind(param_count, context_);
     143             : 
     144             :   Add<HSimulate>(BailoutId::StubEntry());
     145             : 
     146             :   NoObservableSideEffectsScope no_effects(this);
     147             : 
     148       23533 :   HValue* return_value = BuildCodeStub();
     149             : 
     150             :   // We might have extra expressions to pop from the stack in addition to the
     151             :   // arguments above.
     152             :   HInstruction* stack_pop_count = stack_parameter_count;
     153       23533 :   if (descriptor_.function_mode() == JS_FUNCTION_STUB_MODE) {
     154           0 :     if (!stack_parameter_count->IsConstant() &&
     155             :         descriptor_.hint_stack_parameter_count() < 0) {
     156           0 :       HInstruction* constant_one = graph()->GetConstant1();
     157           0 :       stack_pop_count = AddUncasted<HAdd>(stack_parameter_count, constant_one);
     158             :       stack_pop_count->ClearFlag(HValue::kCanOverflow);
     159             :       // TODO(mvstanton): verify that stack_parameter_count+1 really fits in a
     160             :       // smi.
     161             :     } else {
     162             :       int count = descriptor_.hint_stack_parameter_count();
     163           0 :       stack_pop_count = Add<HConstant>(count);
     164             :     }
     165             :   }
     166             : 
     167       23533 :   if (current_block() != NULL) {
     168             :     HReturn* hreturn_instruction = New<HReturn>(return_value,
     169       23533 :                                                 stack_pop_count);
     170       23533 :     FinishCurrentBlock(hreturn_instruction);
     171             :   }
     172       23533 :   return true;
     173             : }
     174             : 
     175             : 
     176             : template <class Stub>
     177       23533 : class CodeStubGraphBuilder: public CodeStubGraphBuilderBase {
     178             :  public:
     179             :   explicit CodeStubGraphBuilder(CompilationInfo* info, CodeStub* stub)
     180       23533 :       : CodeStubGraphBuilderBase(info, stub) {}
     181             : 
     182             :   typedef typename Stub::Descriptor Descriptor;
     183             : 
     184             :  protected:
     185       19612 :   virtual HValue* BuildCodeStub() {
     186       39224 :     if (casted_stub()->IsUninitialized()) {
     187           0 :       return BuildCodeUninitializedStub();
     188             :     } else {
     189       19612 :       return BuildCodeInitializedStub();
     190             :     }
     191             :   }
     192             : 
     193           0 :   virtual HValue* BuildCodeInitializedStub() {
     194           0 :     UNIMPLEMENTED();
     195             :     return NULL;
     196             :   }
     197             : 
     198           0 :   virtual HValue* BuildCodeUninitializedStub() {
     199             :     // Force a deopt that falls back to the runtime.
     200           0 :     HValue* undefined = graph()->GetConstantUndefined();
     201           0 :     IfBuilder builder(this);
     202             :     builder.IfNot<HCompareObjectEqAndBranch, HValue*>(undefined, undefined);
     203           0 :     builder.Then();
     204             :     builder.ElseDeopt(DeoptimizeReason::kForcedDeoptToRuntime);
     205           0 :     return undefined;
     206             :   }
     207             : 
     208       43145 :   Stub* casted_stub() { return static_cast<Stub*>(stub()); }
     209             : };
     210             : 
     211             : 
     212        8102 : Handle<Code> HydrogenCodeStub::GenerateLightweightMissCode(
     213             :     ExternalReference miss) {
     214       16204 :   Factory* factory = isolate()->factory();
     215             : 
     216             :   // Generate the new code.
     217        8102 :   MacroAssembler masm(isolate(), NULL, 256, CodeObjectRequired::kYes);
     218             : 
     219             :   {
     220             :     // Update the static counter each time a new code stub is generated.
     221        8102 :     isolate()->counters()->code_stubs()->Increment();
     222             : 
     223             :     // Generate the code for the stub.
     224             :     masm.set_generating_stub(true);
     225             :     // TODO(yangguo): remove this once we can serialize IC stubs.
     226             :     masm.enable_serializer();
     227             :     NoCurrentFrameScope scope(&masm);
     228        8102 :     GenerateLightweightMiss(&masm, miss);
     229             :   }
     230             : 
     231             :   // Create the code object.
     232             :   CodeDesc desc;
     233        8102 :   masm.GetCode(&desc);
     234             : 
     235             :   // Copy the generated code into a heap object.
     236             :   Handle<Code> new_object = factory->NewCode(
     237        8102 :       desc, GetCodeFlags(), masm.CodeObject(), NeedsImmovableCode());
     238       16204 :   return new_object;
     239             : }
     240             : 
     241           0 : Handle<Code> HydrogenCodeStub::GenerateRuntimeTailCall(
     242           0 :     CodeStubDescriptor* descriptor) {
     243           0 :   const char* name = CodeStub::MajorName(MajorKey());
     244           0 :   Zone zone(isolate()->allocator(), ZONE_NAME);
     245           0 :   CallInterfaceDescriptor interface_descriptor(GetCallInterfaceDescriptor());
     246             :   compiler::CodeAssemblerState state(isolate(), &zone, interface_descriptor,
     247           0 :                                      GetCodeFlags(), name);
     248           0 :   CodeStubAssembler assembler(&state);
     249             :   int total_params = interface_descriptor.GetStackParameterCount() +
     250           0 :                      interface_descriptor.GetRegisterParameterCount();
     251           0 :   switch (total_params) {
     252             :     case 0:
     253             :       assembler.TailCallRuntime(descriptor->miss_handler_id(),
     254           0 :                                 assembler.Parameter(0));
     255           0 :       break;
     256             :     case 1:
     257             :       assembler.TailCallRuntime(descriptor->miss_handler_id(),
     258           0 :                                 assembler.Parameter(1), assembler.Parameter(0));
     259           0 :       break;
     260             :     case 2:
     261             :       assembler.TailCallRuntime(descriptor->miss_handler_id(),
     262             :                                 assembler.Parameter(2), assembler.Parameter(0),
     263           0 :                                 assembler.Parameter(1));
     264           0 :       break;
     265             :     case 3:
     266             :       assembler.TailCallRuntime(descriptor->miss_handler_id(),
     267             :                                 assembler.Parameter(3), assembler.Parameter(0),
     268           0 :                                 assembler.Parameter(1), assembler.Parameter(2));
     269           0 :       break;
     270             :     case 4:
     271             :       assembler.TailCallRuntime(descriptor->miss_handler_id(),
     272             :                                 assembler.Parameter(4), assembler.Parameter(0),
     273             :                                 assembler.Parameter(1), assembler.Parameter(2),
     274           0 :                                 assembler.Parameter(3));
     275           0 :       break;
     276             :     default:
     277           0 :       UNIMPLEMENTED();
     278             :       break;
     279             :   }
     280           0 :   return compiler::CodeAssembler::GenerateCode(&state);
     281             : }
     282             : 
     283             : template <class Stub>
     284       31635 : static Handle<Code> DoGenerateCode(Stub* stub) {
     285       55168 :   Isolate* isolate = stub->isolate();
     286       31635 :   CodeStubDescriptor descriptor(stub);
     287             : 
     288       31635 :   if (FLAG_minimal && descriptor.has_miss_handler()) {
     289           0 :     return stub->GenerateRuntimeTailCall(&descriptor);
     290             :   }
     291             : 
     292             :   // If we are uninitialized we can use a light-weight stub to enter
     293             :   // the runtime that is significantly faster than using the standard
     294             :   // stub-failure deopt mechanism.
     295       31635 :   if (stub->IsUninitialized() && descriptor.has_miss_handler()) {
     296             :     DCHECK(!descriptor.stack_parameter_count().is_valid());
     297        8102 :     return stub->GenerateLightweightMissCode(descriptor.miss_handler());
     298             :   }
     299             :   base::ElapsedTimer timer;
     300       23533 :   if (FLAG_profile_hydrogen_code_stub_compilation) {
     301             :     timer.Start();
     302             :   }
     303       47066 :   Zone zone(isolate->allocator(), ZONE_NAME);
     304       19666 :   CompilationInfo info(CStrVector(CodeStub::MajorName(stub->MajorKey())),
     305       90265 :                        isolate, &zone, stub->GetCodeFlags());
     306             :   // Parameter count is number of stack parameters.
     307             :   int parameter_count = descriptor.GetStackParameterCount();
     308       23533 :   if (descriptor.function_mode() == NOT_JS_FUNCTION_STUB_MODE) {
     309       23533 :     parameter_count--;
     310             :   }
     311             :   info.set_parameter_count(parameter_count);
     312             :   CodeStubGraphBuilder<Stub> builder(&info, stub);
     313       23533 :   LChunk* chunk = OptimizeGraph(builder.CreateGraph());
     314       23533 :   Handle<Code> code = chunk->Codegen();
     315       23533 :   if (FLAG_profile_hydrogen_code_stub_compilation) {
     316           0 :     OFStream os(stdout);
     317           0 :     os << "[Lazy compilation of " << stub << " took "
     318           0 :        << timer.Elapsed().InMillisecondsF() << " ms]" << std::endl;
     319             :   }
     320       23533 :   return code;
     321             : }
     322             : 
     323             : template <>
     324          54 : HValue* CodeStubGraphBuilder<TransitionElementsKindStub>::BuildCodeStub() {
     325             :   ElementsKind const from_kind = casted_stub()->from_kind();
     326             :   ElementsKind const to_kind = casted_stub()->to_kind();
     327         108 :   HValue* const object = GetParameter(Descriptor::kObject);
     328             :   HValue* const map = GetParameter(Descriptor::kMap);
     329             : 
     330             :   // The {object} is known to be a JSObject (otherwise it wouldn't have elements
     331             :   // anyways).
     332             :   object->set_type(HType::JSObject());
     333             : 
     334             :   info()->MarkAsSavesCallerDoubles();
     335             : 
     336             :   DCHECK_IMPLIES(IsFastHoleyElementsKind(from_kind),
     337             :                  IsFastHoleyElementsKind(to_kind));
     338             : 
     339          54 :   if (AllocationSite::GetMode(from_kind, to_kind) == TRACK_ALLOCATION_SITE) {
     340          37 :     Add<HTrapAllocationMemento>(object);
     341             :   }
     342             : 
     343          54 :   if (!IsSimpleMapChangeTransition(from_kind, to_kind)) {
     344          54 :     HInstruction* elements = AddLoadElements(object);
     345             : 
     346          54 :     IfBuilder if_objecthaselements(this);
     347             :     if_objecthaselements.IfNot<HCompareObjectEqAndBranch>(
     348          54 :         elements, Add<HConstant>(isolate()->factory()->empty_fixed_array()));
     349          54 :     if_objecthaselements.Then();
     350             :     {
     351             :       // Determine the elements capacity.
     352          54 :       HInstruction* elements_length = AddLoadFixedArrayLength(elements);
     353             : 
     354             :       // Determine the effective (array) length.
     355          54 :       IfBuilder if_objectisarray(this);
     356          54 :       if_objectisarray.If<HHasInstanceTypeAndBranch>(object, JS_ARRAY_TYPE);
     357          54 :       if_objectisarray.Then();
     358             :       {
     359             :         // The {object} is a JSArray, load the special "length" property.
     360             :         Push(Add<HLoadNamedField>(object, nullptr,
     361          54 :                                   HObjectAccess::ForArrayLength(from_kind)));
     362             :       }
     363          54 :       if_objectisarray.Else();
     364             :       {
     365             :         // The {object} is some other JSObject.
     366          54 :         Push(elements_length);
     367             :       }
     368          54 :       if_objectisarray.End();
     369             :       HValue* length = Pop();
     370             : 
     371             :       BuildGrowElementsCapacity(object, elements, from_kind, to_kind, length,
     372          54 :                                 elements_length);
     373             :     }
     374          54 :     if_objecthaselements.End();
     375             :   }
     376             : 
     377          54 :   Add<HStoreNamedField>(object, HObjectAccess::ForMap(), map);
     378             : 
     379          54 :   return object;
     380             : }
     381             : 
     382             : 
     383          54 : Handle<Code> TransitionElementsKindStub::GenerateCode() {
     384          54 :   return DoGenerateCode(this);
     385             : }
     386             : 
     387             : template <>
     388        5856 : HValue* CodeStubGraphBuilder<BinaryOpICStub>::BuildCodeInitializedStub() {
     389             :   BinaryOpICState state = casted_stub()->state();
     390             : 
     391             :   HValue* left = GetParameter(Descriptor::kLeft);
     392             :   HValue* right = GetParameter(Descriptor::kRight);
     393             : 
     394        5856 :   AstType* left_type = state.GetLeftType();
     395        5856 :   AstType* right_type = state.GetRightType();
     396        5856 :   AstType* result_type = state.GetResultType();
     397             : 
     398             :   DCHECK(!left_type->Is(AstType::None()) && !right_type->Is(AstType::None()) &&
     399             :          (state.HasSideEffects() || !result_type->Is(AstType::None())));
     400             : 
     401             :   HValue* result = NULL;
     402             :   HAllocationMode allocation_mode(NOT_TENURED);
     403       13333 :   if (state.op() == Token::ADD && (left_type->Maybe(AstType::String()) ||
     404         997 :                                    right_type->Maybe(AstType::String())) &&
     405        6137 :       !left_type->Is(AstType::String()) && !right_type->Is(AstType::String())) {
     406             :     // For the generic add stub a fast case for string addition is performance
     407             :     // critical.
     408         281 :     if (left_type->Maybe(AstType::String())) {
     409         189 :       IfBuilder if_leftisstring(this);
     410         189 :       if_leftisstring.If<HIsStringAndBranch>(left);
     411         189 :       if_leftisstring.Then();
     412             :       {
     413             :         Push(BuildBinaryOperation(state.op(), left, right, AstType::String(),
     414             :                                   right_type, result_type,
     415         189 :                                   state.fixed_right_arg(), allocation_mode));
     416             :       }
     417         189 :       if_leftisstring.Else();
     418             :       {
     419             :         Push(BuildBinaryOperation(state.op(), left, right, left_type,
     420             :                                   right_type, result_type,
     421         189 :                                   state.fixed_right_arg(), allocation_mode));
     422             :       }
     423         189 :       if_leftisstring.End();
     424             :       result = Pop();
     425             :     } else {
     426          92 :       IfBuilder if_rightisstring(this);
     427          92 :       if_rightisstring.If<HIsStringAndBranch>(right);
     428          92 :       if_rightisstring.Then();
     429             :       {
     430             :         Push(BuildBinaryOperation(state.op(), left, right, left_type,
     431             :                                   AstType::String(), result_type,
     432          92 :                                   state.fixed_right_arg(), allocation_mode));
     433             :       }
     434          92 :       if_rightisstring.Else();
     435             :       {
     436             :         Push(BuildBinaryOperation(state.op(), left, right, left_type,
     437             :                                   right_type, result_type,
     438          92 :                                   state.fixed_right_arg(), allocation_mode));
     439             :       }
     440          92 :       if_rightisstring.End();
     441             :       result = Pop();
     442             :     }
     443             :   } else {
     444             :     result = BuildBinaryOperation(state.op(), left, right, left_type,
     445             :                                   right_type, result_type,
     446        5575 :                                   state.fixed_right_arg(), allocation_mode);
     447             :   }
     448             : 
     449             :   // If we encounter a generic argument, the number conversion is
     450             :   // observable, thus we cannot afford to bail out after the fact.
     451       11712 :   if (!state.HasSideEffects()) {
     452        5083 :     result = EnforceNumberType(result, result_type);
     453             :   }
     454             : 
     455        5856 :   return result;
     456             : }
     457             : 
     458             : 
     459        6372 : Handle<Code> BinaryOpICStub::GenerateCode() {
     460        6372 :   return DoGenerateCode(this);
     461             : }
     462             : 
     463             : 
     464             : template <>
     465        3867 : HValue* CodeStubGraphBuilder<BinaryOpWithAllocationSiteStub>::BuildCodeStub() {
     466             :   BinaryOpICState state = casted_stub()->state();
     467             : 
     468             :   HValue* allocation_site = GetParameter(Descriptor::kAllocationSite);
     469             :   HValue* left = GetParameter(Descriptor::kLeft);
     470             :   HValue* right = GetParameter(Descriptor::kRight);
     471             : 
     472        3867 :   AstType* left_type = state.GetLeftType();
     473        3867 :   AstType* right_type = state.GetRightType();
     474        3867 :   AstType* result_type = state.GetResultType();
     475             :   HAllocationMode allocation_mode(allocation_site);
     476             : 
     477             :   return BuildBinaryOperation(state.op(), left, right, left_type, right_type,
     478             :                               result_type, state.fixed_right_arg(),
     479        3867 :                               allocation_mode);
     480             : }
     481             : 
     482             : 
     483        3867 : Handle<Code> BinaryOpWithAllocationSiteStub::GenerateCode() {
     484        3867 :   return DoGenerateCode(this);
     485             : }
     486             : 
     487             : 
     488             : template <>
     489       13756 : HValue* CodeStubGraphBuilder<ToBooleanICStub>::BuildCodeInitializedStub() {
     490             :   ToBooleanICStub* stub = casted_stub();
     491       41268 :   IfBuilder if_true(this);
     492       13756 :   if_true.If<HBranch>(GetParameter(Descriptor::kArgument), stub->hints());
     493       13756 :   if_true.Then();
     494       13756 :   if_true.Return(graph()->GetConstantTrue());
     495       13756 :   if_true.Else();
     496       13756 :   if_true.End();
     497       27512 :   return graph()->GetConstantFalse();
     498             : }
     499             : 
     500       21342 : Handle<Code> ToBooleanICStub::GenerateCode() { return DoGenerateCode(this); }
     501             : 
     502             : }  // namespace internal
     503             : }  // namespace v8

Generated by: LCOV version 1.10