frame-states.cc 10.1 KB
Newer Older
1 2 3 4 5
// Copyright 2015 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/compiler/frame-states.h"
6 7

#include "src/base/functional.h"
8
#include "src/codegen/callable.h"
9 10 11
#include "src/compiler/graph.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/node.h"
12
#include "src/handles/handles-inl.h"
13
#include "src/objects/objects-inl.h"
14 15

#if V8_ENABLE_WEBASSEMBLY
16
#include "src/wasm/value-type.h"
17
#endif  // V8_ENABLE_WEBASSEMBLY
18 19 20 21 22 23

namespace v8 {
namespace internal {
namespace compiler {

size_t hash_value(OutputFrameStateCombine const& sc) {
24
  return base::hash_value(sc.parameter_);
25 26 27 28
}


std::ostream& operator<<(std::ostream& os, OutputFrameStateCombine const& sc) {
29 30 31
  if (sc.parameter_ == OutputFrameStateCombine::kInvalidIndex)
    return os << "Ignore";
  return os << "PokeAt(" << sc.parameter_ << ")";
32 33 34
}


35
bool operator==(FrameStateInfo const& lhs, FrameStateInfo const& rhs) {
36
  return lhs.type() == rhs.type() && lhs.bailout_id() == rhs.bailout_id() &&
37 38
         lhs.state_combine() == rhs.state_combine() &&
         lhs.function_info() == rhs.function_info();
39 40 41
}


42
bool operator!=(FrameStateInfo const& lhs, FrameStateInfo const& rhs) {
43 44 45 46
  return !(lhs == rhs);
}


47 48
size_t hash_value(FrameStateInfo const& info) {
  return base::hash_combine(static_cast<int>(info.type()), info.bailout_id(),
49 50 51 52
                            info.state_combine());
}


53 54
std::ostream& operator<<(std::ostream& os, FrameStateType type) {
  switch (type) {
55 56
    case FrameStateType::kUnoptimizedFunction:
      os << "UNOPTIMIZED_FRAME";
57
      break;
58 59
    case FrameStateType::kInlinedExtraArguments:
      os << "INLINED_EXTRA_ARGUMENTS";
60
      break;
61 62 63
    case FrameStateType::kConstructStub:
      os << "CONSTRUCT_STUB";
      break;
64 65 66
    case FrameStateType::kBuiltinContinuation:
      os << "BUILTIN_CONTINUATION_FRAME";
      break;
67
#if V8_ENABLE_WEBASSEMBLY
68 69 70
    case FrameStateType::kJSToWasmBuiltinContinuation:
      os << "JS_TO_WASM_BUILTIN_CONTINUATION_FRAME";
      break;
71
#endif  // V8_ENABLE_WEBASSEMBLY
72 73 74
    case FrameStateType::kJavaScriptBuiltinContinuation:
      os << "JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME";
      break;
75 76 77
    case FrameStateType::kJavaScriptBuiltinContinuationWithCatch:
      os << "JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME";
      break;
78 79 80 81 82 83
  }
  return os;
}


std::ostream& operator<<(std::ostream& os, FrameStateInfo const& info) {
84 85 86 87 88 89 90
  os << info.type() << ", " << info.bailout_id() << ", "
     << info.state_combine();
  Handle<SharedFunctionInfo> shared_info;
  if (info.shared_info().ToHandle(&shared_info)) {
    os << ", " << Brief(*shared_info);
  }
  return os;
91
}
92

93
namespace {
94

95
// Lazy deopt points where the frame state is associated with a call get an
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
// additional parameter for the return result from the call. The return result
// is added by the deoptimizer and not explicitly specified in the frame state.
// Lazy deopt points which can catch exceptions further get an additional
// parameter, namely the exception thrown. The exception is also added by the
// deoptimizer.
uint8_t DeoptimizerParameterCountFor(ContinuationFrameStateMode mode) {
  switch (mode) {
    case ContinuationFrameStateMode::EAGER:
      return 0;
    case ContinuationFrameStateMode::LAZY:
      return 1;
    case ContinuationFrameStateMode::LAZY_WITH_CATCH:
      return 2;
  }
  UNREACHABLE();
}

113
FrameState CreateBuiltinContinuationFrameStateCommon(
114 115
    JSGraph* jsgraph, FrameStateType frame_type, Builtin name, Node* closure,
    Node* context, Node** parameters, int parameter_count,
116
    Node* outer_frame_state,
117 118
    Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>(),
    const wasm::FunctionSig* signature = nullptr) {
119 120
  Graph* const graph = jsgraph->graph();
  CommonOperatorBuilder* const common = jsgraph->common();
121 122 123 124 125

  const Operator* op_param =
      common->StateValues(parameter_count, SparseInputMask::Dense());
  Node* params_node = graph->NewNode(op_param, parameter_count, parameters);

126
  BytecodeOffset bailout_id = Builtins::GetContinuationBytecodeOffset(name);
127
#if V8_ENABLE_WEBASSEMBLY
128
  const FrameStateFunctionInfo* state_info =
129 130 131 132
      signature ? common->CreateJSToWasmFrameStateFunctionInfo(
                      frame_type, parameter_count, 0, shared, signature)
                : common->CreateFrameStateFunctionInfo(
                      frame_type, parameter_count, 0, shared);
133
#else
134
  DCHECK_NULL(signature);
135 136 137 138
  const FrameStateFunctionInfo* state_info =
      common->CreateFrameStateFunctionInfo(frame_type, parameter_count, 0,
                                           shared);
#endif  // V8_ENABLE_WEBASSEMBLY
139

140 141
  const Operator* op = common->FrameState(
      bailout_id, OutputFrameStateCombine::Ignore(), state_info);
142 143 144
  return FrameState(graph->NewNode(op, params_node, jsgraph->EmptyStateValues(),
                                   jsgraph->EmptyStateValues(), context,
                                   closure, outer_frame_state));
145
}
146

147 148
}  // namespace

149
FrameState CreateStubBuiltinContinuationFrameState(
150 151
    JSGraph* jsgraph, Builtin name, Node* context, Node* const* parameters,
    int parameter_count, Node* outer_frame_state,
152
    ContinuationFrameStateMode mode, const wasm::FunctionSig* signature) {
153
  Callable callable = Builtins::CallableFor(jsgraph->isolate(), name);
154 155 156
  CallInterfaceDescriptor descriptor = callable.descriptor();

  std::vector<Node*> actual_parameters;
157 158
  // Stack parameters first. Depending on {mode}, final parameters are added
  // by the deoptimizer and aren't explicitly passed in the frame state.
159
  int stack_parameter_count =
160 161 162 163 164 165 166 167 168 169 170
      descriptor.GetStackParameterCount() - DeoptimizerParameterCountFor(mode);

  // Ensure the parameters added by the deoptimizer are passed on the stack.
  // This check prevents using TFS builtins as continuations while doing the
  // lazy deopt. Use TFC or TFJ builtin as a lazy deopt continuation which
  // would pass the result parameter on the stack.
  DCHECK_GE(stack_parameter_count, 0);

  // Reserving space in the vector.
  actual_parameters.reserve(stack_parameter_count +
                            descriptor.GetRegisterParameterCount());
171
  for (int i = 0; i < stack_parameter_count; ++i) {
172 173 174 175 176 177 178 179 180
    actual_parameters.push_back(
        parameters[descriptor.GetRegisterParameterCount() + i]);
  }
  // Register parameters follow, context will be added by instruction selector
  // during FrameState translation.
  for (int i = 0; i < descriptor.GetRegisterParameterCount(); ++i) {
    actual_parameters.push_back(parameters[i]);
  }

181
  FrameStateType frame_state_type = FrameStateType::kBuiltinContinuation;
182
#if V8_ENABLE_WEBASSEMBLY
183
  if (name == Builtin::kJSToWasmLazyDeoptContinuation) {
184 185 186
    CHECK_NOT_NULL(signature);
    frame_state_type = FrameStateType::kJSToWasmBuiltinContinuation;
  }
187
#endif  // V8_ENABLE_WEBASSEMBLY
188
  return CreateBuiltinContinuationFrameStateCommon(
189 190 191 192 193
      jsgraph, frame_state_type, name, jsgraph->UndefinedConstant(), context,
      actual_parameters.data(), static_cast<int>(actual_parameters.size()),
      outer_frame_state, Handle<SharedFunctionInfo>(), signature);
}

194
#if V8_ENABLE_WEBASSEMBLY
195 196 197
FrameState CreateJSWasmCallBuiltinContinuationFrameState(
    JSGraph* jsgraph, Node* context, Node* outer_frame_state,
    const wasm::FunctionSig* signature) {
198
  base::Optional<wasm::ValueKind> wasm_return_kind =
199 200
      wasm::WasmReturnTypeFromSignature(signature);
  Node* node_return_type =
201
      jsgraph->SmiConstant(wasm_return_kind ? wasm_return_kind.value() : -1);
202 203
  Node* lazy_deopt_parameters[] = {node_return_type};
  return CreateStubBuiltinContinuationFrameState(
204
      jsgraph, Builtin::kJSToWasmLazyDeoptContinuation, context,
205 206
      lazy_deopt_parameters, arraysize(lazy_deopt_parameters),
      outer_frame_state, ContinuationFrameStateMode::LAZY, signature);
207
}
208
#endif  // V8_ENABLE_WEBASSEMBLY
209

210
FrameState CreateJavaScriptBuiltinContinuationFrameState(
211
    JSGraph* jsgraph, const SharedFunctionInfoRef& shared, Builtin name,
212
    Node* target, Node* context, Node* const* stack_parameters,
213 214
    int stack_parameter_count, Node* outer_frame_state,
    ContinuationFrameStateMode mode) {
215 216
  // Depending on {mode}, final parameters are added by the deoptimizer
  // and aren't explicitly passed in the frame state.
217 218
  DCHECK_EQ(Builtins::GetStackParameterCount(name),
            stack_parameter_count + DeoptimizerParameterCountFor(mode));
219

220
  Node* argc = jsgraph->Constant(Builtins::GetStackParameterCount(name));
221 222 223 224 225

  // Stack parameters first. They must be first because the receiver is expected
  // to be the second value in the translation when creating stack crawls
  // (e.g. Error.stack) of optimized JavaScript frames.
  std::vector<Node*> actual_parameters;
226
  actual_parameters.reserve(stack_parameter_count);
227 228 229 230
  for (int i = 0; i < stack_parameter_count; ++i) {
    actual_parameters.push_back(stack_parameters[i]);
  }

231 232 233
  Node* new_target = jsgraph->UndefinedConstant();

  // Register parameters follow stack parameters. The context will be added by
234
  // instruction selector during FrameState translation.
235 236 237
  actual_parameters.push_back(target);      // kJavaScriptCallTargetRegister
  actual_parameters.push_back(new_target);  // kJavaScriptCallNewTargetRegister
  actual_parameters.push_back(argc);        // kJavaScriptCallArgCountRegister
238 239

  return CreateBuiltinContinuationFrameStateCommon(
240 241 242 243 244
      jsgraph,
      mode == ContinuationFrameStateMode::LAZY_WITH_CATCH
          ? FrameStateType::kJavaScriptBuiltinContinuationWithCatch
          : FrameStateType::kJavaScriptBuiltinContinuation,
      name, target, context, &actual_parameters[0],
245 246
      static_cast<int>(actual_parameters.size()), outer_frame_state,
      shared.object());
247 248
}

249
FrameState CreateGenericLazyDeoptContinuationFrameState(
250 251 252 253 254
    JSGraph* graph, const SharedFunctionInfoRef& shared, Node* target,
    Node* context, Node* receiver, Node* outer_frame_state) {
  Node* stack_parameters[]{receiver};
  const int stack_parameter_count = arraysize(stack_parameters);
  return CreateJavaScriptBuiltinContinuationFrameState(
255
      graph, shared, Builtin::kGenericLazyDeoptContinuation, target, context,
256 257 258 259
      stack_parameters, stack_parameter_count, outer_frame_state,
      ContinuationFrameStateMode::LAZY);
}

260 261 262
}  // namespace compiler
}  // namespace internal
}  // namespace v8