// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/ast.h"
#include "src/ast-numbering.h"
#include "src/compiler/access-builder.h"
#include "src/compiler/ast-graph-builder.h"
#include "src/compiler/common-operator.h"
#include "src/compiler/generic-node-inl.h"
#include "src/compiler/graph-inl.h"
#include "src/compiler/graph-visualizer.h"
#include "src/compiler/js-inlining.h"
#include "src/compiler/js-intrinsic-builder.h"
#include "src/compiler/js-operator.h"
#include "src/compiler/node-aux-data-inl.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties-inl.h"
#include "src/compiler/simplified-operator.h"
#include "src/compiler/typer.h"
#include "src/full-codegen.h"
#include "src/parser.h"
#include "src/rewriter.h"
#include "src/scopes.h"


namespace v8 {
namespace internal {
namespace compiler {

class InlinerVisitor : public NullNodeVisitor {
 public:
  explicit InlinerVisitor(JSInliner* inliner) : inliner_(inliner) {}

  void Post(Node* node) {
    switch (node->opcode()) {
      case IrOpcode::kJSCallFunction:
        inliner_->TryInlineJSCall(node);
        break;
      case IrOpcode::kJSCallRuntime:
        if (FLAG_turbo_inlining_intrinsics) {
          inliner_->TryInlineRuntimeCall(node);
        }
        break;
      default:
        break;
    }
  }

 private:
  JSInliner* inliner_;
};


void JSInliner::Inline() {
  InlinerVisitor visitor(this);
  jsgraph_->graph()->VisitNodeInputsFromEnd(&visitor);
}


// A facade on a JSFunction's graph to facilitate inlining. It assumes the
// that the function graph has only one return statement, and provides
// {UnifyReturn} to convert a function graph to that end.
class Inlinee {
 public:
  Inlinee(Node* start, Node* end) : start_(start), end_(end) {}

  // Returns the last regular control node, that is
  // the last control node before the end node.
  Node* end_block() { return NodeProperties::GetControlInput(unique_return()); }

  // Return the effect output of the graph,
  // that is the effect input of the return statement of the inlinee.
  Node* effect_output() {
    return NodeProperties::GetEffectInput(unique_return());
  }
  // Return the value output of the graph,
  // that is the value input of the return statement of the inlinee.
  Node* value_output() {
    return NodeProperties::GetValueInput(unique_return(), 0);
  }
  // Return the unique return statement of the graph.
  Node* unique_return() {
    Node* unique_return = NodeProperties::GetControlInput(end_);
    DCHECK_EQ(IrOpcode::kReturn, unique_return->opcode());
    return unique_return;
  }

  // Counts JSFunction, Receiver, arguments, context but not effect, control.
  size_t total_parameters() { return start_->op()->OutputCount(); }

  // Counts only formal parameters.
  size_t formal_parameters() {
    DCHECK_GE(total_parameters(), 3);
    return total_parameters() - 3;
  }

  // Inline this graph at {call}, use {jsgraph} and its zone to create
  // any new nodes.
  void InlineAtCall(JSGraph* jsgraph, Node* call);

  // Ensure that only a single return reaches the end node.
  static void UnifyReturn(JSGraph* jsgraph);

 private:
  Node* start_;
  Node* end_;
};


void Inlinee::UnifyReturn(JSGraph* jsgraph) {
  Graph* graph = jsgraph->graph();

  Node* final_merge = NodeProperties::GetControlInput(graph->end(), 0);
  if (final_merge->opcode() == IrOpcode::kReturn) {
    // nothing to do
    return;
  }
  DCHECK_EQ(IrOpcode::kMerge, final_merge->opcode());

  int predecessors = final_merge->op()->ControlInputCount();

  const Operator* op_phi = jsgraph->common()->Phi(kMachAnyTagged, predecessors);
  const Operator* op_ephi = jsgraph->common()->EffectPhi(predecessors);

  NodeVector values(jsgraph->zone());
  NodeVector effects(jsgraph->zone());
  // Iterate over all control flow predecessors,
  // which must be return statements.
  InputIter iter = final_merge->inputs().begin();
  while (iter != final_merge->inputs().end()) {
    Node* input = *iter;
    switch (input->opcode()) {
      case IrOpcode::kReturn:
        values.push_back(NodeProperties::GetValueInput(input, 0));
        effects.push_back(NodeProperties::GetEffectInput(input));
        iter.UpdateToAndIncrement(NodeProperties::GetControlInput(input));
        input->RemoveAllInputs();
        break;
      default:
        UNREACHABLE();
        ++iter;
        break;
    }
  }
  values.push_back(final_merge);
  effects.push_back(final_merge);
  Node* phi =
      graph->NewNode(op_phi, static_cast<int>(values.size()), &values.front());
  Node* ephi = graph->NewNode(op_ephi, static_cast<int>(effects.size()),
                              &effects.front());
  Node* new_return =
      graph->NewNode(jsgraph->common()->Return(), phi, ephi, final_merge);
  graph->end()->ReplaceInput(0, new_return);
}


class CopyVisitor : public NullNodeVisitor {
 public:
  CopyVisitor(Graph* source_graph, Graph* target_graph, Zone* temp_zone)
      : copies_(source_graph->NodeCount(), NULL, temp_zone),
        sentinels_(source_graph->NodeCount(), NULL, temp_zone),
        source_graph_(source_graph),
        target_graph_(target_graph),
        temp_zone_(temp_zone),
        sentinel_op_(IrOpcode::kDead, Operator::kNoProperties, "sentinel", 0, 0,
                     0, 0, 0, 0) {}

  void Post(Node* original) {
    NodeVector inputs(temp_zone_);
    for (InputIter it = original->inputs().begin();
         it != original->inputs().end(); ++it) {
      inputs.push_back(GetCopy(*it));
    }

    // Reuse the operator in the copy. This assumes that op lives in a zone
    // that lives longer than graph()'s zone.
    Node* copy =
        target_graph_->NewNode(original->op(), static_cast<int>(inputs.size()),
                               (inputs.empty() ? NULL : &inputs.front()));
    copies_[original->id()] = copy;
  }

  Node* GetCopy(Node* original) {
    Node* copy = copies_[original->id()];
    if (copy == NULL) {
      copy = GetSentinel(original);
    }
    DCHECK_NE(NULL, copy);
    return copy;
  }

  void CopyGraph() {
    source_graph_->VisitNodeInputsFromEnd(this);
    ReplaceSentinels();
  }

  const NodeVector& copies() { return copies_; }

 private:
  void ReplaceSentinels() {
    for (NodeId id = 0; id < source_graph_->NodeCount(); ++id) {
      Node* sentinel = sentinels_[id];
      if (sentinel == NULL) continue;
      Node* copy = copies_[id];
      DCHECK_NE(NULL, copy);
      sentinel->ReplaceUses(copy);
    }
  }

  Node* GetSentinel(Node* original) {
    Node* sentinel = sentinels_[original->id()];
    if (sentinel == NULL) {
      sentinel = target_graph_->NewNode(&sentinel_op_);
    }
    return sentinel;
  }

  NodeVector copies_;
  NodeVector sentinels_;
  Graph* source_graph_;
  Graph* target_graph_;
  Zone* temp_zone_;
  Operator sentinel_op_;
};


void Inlinee::InlineAtCall(JSGraph* jsgraph, Node* call) {
  // The scheduler is smart enough to place our code; we just ensure {control}
  // becomes the control input of the start of the inlinee.
  Node* control = NodeProperties::GetControlInput(call);

  // The inlinee uses the context from the JSFunction object. This will
  // also be the effect dependency for the inlinee as it produces an effect.
  SimplifiedOperatorBuilder simplified(jsgraph->zone());
  Node* context = jsgraph->graph()->NewNode(
      simplified.LoadField(AccessBuilder::ForJSFunctionContext()),
      NodeProperties::GetValueInput(call, 0),
      NodeProperties::GetEffectInput(call), control);

  // Context is last argument.
  int inlinee_context_index = static_cast<int>(total_parameters()) - 1;
  // {inliner_inputs} counts JSFunction, Receiver, arguments, but not
  // context, effect, control.
  int inliner_inputs = call->op()->ValueInputCount();
  // Iterate over all uses of the start node.
  UseIter iter = start_->uses().begin();
  while (iter != start_->uses().end()) {
    Node* use = *iter;
    switch (use->opcode()) {
      case IrOpcode::kParameter: {
        int index = 1 + OpParameter<int>(use->op());
        if (index < inliner_inputs && index < inlinee_context_index) {
          // There is an input from the call, and the index is a value
          // projection but not the context, so rewire the input.
          NodeProperties::ReplaceWithValue(*iter, call->InputAt(index));
        } else if (index == inlinee_context_index) {
          // This is the context projection, rewire it to the context from the
          // JSFunction object.
          NodeProperties::ReplaceWithValue(*iter, context);
        } else if (index < inlinee_context_index) {
          // Call has fewer arguments than required, fill with undefined.
          NodeProperties::ReplaceWithValue(*iter, jsgraph->UndefinedConstant());
        } else {
          // We got too many arguments, discard for now.
          // TODO(sigurds): Fix to treat arguments array correctly.
        }
        ++iter;
        break;
      }
      default:
        if (NodeProperties::IsEffectEdge(iter.edge())) {
          iter.UpdateToAndIncrement(context);
        } else if (NodeProperties::IsControlEdge(iter.edge())) {
          iter.UpdateToAndIncrement(control);
        } else {
          UNREACHABLE();
        }
        break;
    }
  }

  NodeProperties::ReplaceWithValue(call, value_output(), effect_output());
  call->RemoveAllInputs();
  DCHECK_EQ(0, call->UseCount());
}


// TODO(turbofan) Provide such accessors for every node, possibly even
// generate them.
class JSCallFunctionAccessor {
 public:
  explicit JSCallFunctionAccessor(Node* call) : call_(call) {
    DCHECK_EQ(IrOpcode::kJSCallFunction, call->opcode());
  }

  Node* jsfunction() { return call_->InputAt(0); }

  Node* receiver() { return call_->InputAt(1); }

  Node* formal_argument(size_t index) {
    DCHECK(index < formal_arguments());
    return call_->InputAt(static_cast<int>(2 + index));
  }

  size_t formal_arguments() {
    // {value_inputs} includes jsfunction and receiver.
    size_t value_inputs = call_->op()->ValueInputCount();
    DCHECK_GE(call_->InputCount(), 2);
    return value_inputs - 2;
  }

  Node* frame_state() { return NodeProperties::GetFrameStateInput(call_); }

 private:
  Node* call_;
};


void JSInliner::AddClosureToFrameState(Node* frame_state,
                                       Handle<JSFunction> jsfunction) {
  FrameStateCallInfo call_info = OpParameter<FrameStateCallInfo>(frame_state);
  const Operator* op = jsgraph_->common()->FrameState(
      FrameStateType::JS_FRAME, call_info.bailout_id(),
      call_info.state_combine(), jsfunction);
  frame_state->set_op(op);
}


Node* JSInliner::CreateArgumentsAdaptorFrameState(JSCallFunctionAccessor* call,
                                                  Handle<JSFunction> jsfunction,
                                                  Zone* temp_zone) {
  const Operator* op = jsgraph_->common()->FrameState(
      FrameStateType::ARGUMENTS_ADAPTOR, BailoutId(-1),
      OutputFrameStateCombine::Ignore(), jsfunction);
  const Operator* op0 = jsgraph_->common()->StateValues(0);
  Node* node0 = jsgraph_->graph()->NewNode(op0);
  NodeVector params(temp_zone);
  params.push_back(call->receiver());
  for (size_t argument = 0; argument != call->formal_arguments(); ++argument) {
    params.push_back(call->formal_argument(argument));
  }
  const Operator* op_param =
      jsgraph_->common()->StateValues(static_cast<int>(params.size()));
  Node* params_node = jsgraph_->graph()->NewNode(
      op_param, static_cast<int>(params.size()), &params.front());
  return jsgraph_->graph()->NewNode(op, params_node, node0, node0,
                                    jsgraph_->UndefinedConstant(),
                                    call->frame_state());
}


void JSInliner::TryInlineJSCall(Node* call_node) {
  JSCallFunctionAccessor call(call_node);

  HeapObjectMatcher<JSFunction> match(call.jsfunction());
  if (!match.HasValue()) {
    return;
  }

  Handle<JSFunction> function = match.Value().handle();

  if (function->shared()->native()) {
    if (FLAG_trace_turbo_inlining) {
      SmartArrayPointer<char> name =
          function->shared()->DebugName()->ToCString();
      PrintF("Not Inlining %s into %s because inlinee is native\n", name.get(),
             info_->shared_info()->DebugName()->ToCString().get());
    }
    return;
  }

  CompilationInfoWithZone info(function);
  // TODO(wingo): ParseAndAnalyze can fail due to stack overflow.
  CHECK(Compiler::ParseAndAnalyze(&info));
  CHECK(Compiler::EnsureDeoptimizationSupport(&info));

  if (info.scope()->arguments() != NULL && info.strict_mode() != STRICT) {
    // For now do not inline functions that use their arguments array.
    SmartArrayPointer<char> name = function->shared()->DebugName()->ToCString();
    if (FLAG_trace_turbo_inlining) {
      PrintF(
          "Not Inlining %s into %s because inlinee uses arguments "
          "array\n",
          name.get(), info_->shared_info()->DebugName()->ToCString().get());
    }
    return;
  }

  if (FLAG_trace_turbo_inlining) {
    SmartArrayPointer<char> name = function->shared()->DebugName()->ToCString();
    PrintF("Inlining %s into %s\n", name.get(),
           info_->shared_info()->DebugName()->ToCString().get());
  }

  Graph graph(info.zone());
  JSGraph jsgraph(&graph, jsgraph_->common(), jsgraph_->javascript(),
                  jsgraph_->machine());

  AstGraphBuilder graph_builder(local_zone_, &info, &jsgraph);
  graph_builder.CreateGraph();
  Inlinee::UnifyReturn(&jsgraph);

  CopyVisitor visitor(&graph, jsgraph_->graph(), info.zone());
  visitor.CopyGraph();

  Inlinee inlinee(visitor.GetCopy(graph.start()), visitor.GetCopy(graph.end()));

  Node* outer_frame_state = call.frame_state();
  // Insert argument adaptor frame if required.
  if (call.formal_arguments() != inlinee.formal_parameters()) {
    outer_frame_state =
        CreateArgumentsAdaptorFrameState(&call, function, info.zone());
  }

  for (NodeVectorConstIter it = visitor.copies().begin();
       it != visitor.copies().end(); ++it) {
    Node* node = *it;
    if (node != NULL && node->opcode() == IrOpcode::kFrameState) {
      AddClosureToFrameState(node, function);
      NodeProperties::ReplaceFrameStateInput(node, outer_frame_state);
    }
  }

  inlinee.InlineAtCall(jsgraph_, call_node);
}


class JSCallRuntimeAccessor {
 public:
  explicit JSCallRuntimeAccessor(Node* call) : call_(call) {
    DCHECK_EQ(IrOpcode::kJSCallRuntime, call->opcode());
  }

  Node* formal_argument(size_t index) {
    DCHECK(index < formal_arguments());
    return call_->InputAt(static_cast<int>(index));
  }

  size_t formal_arguments() {
    size_t value_inputs = call_->op()->ValueInputCount();
    return value_inputs;
  }

  Node* frame_state() const {
    return NodeProperties::GetFrameStateInput(call_);
  }
  Node* context() const { return NodeProperties::GetContextInput(call_); }
  Node* control() const { return NodeProperties::GetControlInput(call_); }
  Node* effect() const { return NodeProperties::GetEffectInput(call_); }

  const Runtime::Function* function() const {
    return Runtime::FunctionForId(CallRuntimeParametersOf(call_->op()).id());
  }

  NodeVector inputs(Zone* zone) const {
    NodeVector inputs(zone);
    for (InputIter it = call_->inputs().begin(); it != call_->inputs().end();
         ++it) {
      inputs.push_back(*it);
    }
    return inputs;
  }

 private:
  Node* call_;
};


void JSInliner::TryInlineRuntimeCall(Node* call_node) {
  JSCallRuntimeAccessor call(call_node);
  const Runtime::Function* f = call.function();

  if (f->intrinsic_type != Runtime::IntrinsicType::INLINE) {
    return;
  }

  JSIntrinsicBuilder intrinsic_builder(jsgraph_);

  ResultAndEffect r = intrinsic_builder.BuildGraphFor(
      f->function_id, call.inputs(jsgraph_->zone()));

  if (r.first != NULL) {
    if (FLAG_trace_turbo_inlining) {
      PrintF("Inlining %s into %s\n", f->name,
             info_->shared_info()->DebugName()->ToCString().get());
    }
    NodeProperties::ReplaceWithValue(call_node, r.first, r.second);
    call_node->RemoveAllInputs();
    DCHECK_EQ(0, call_node->UseCount());
  }
}
}
}
}  // namespace v8::internal::compiler
