js-intrinsic-lowering.cc 15.4 KB
Newer Older
1 2 3 4 5 6
// 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/js-intrinsic-lowering.h"

7 8
#include <stack>

9
#include "src/codegen/code-factory.h"
10 11
#include "src/compiler/access-builder.h"
#include "src/compiler/js-graph.h"
12
#include "src/compiler/js-heap-broker.h"
13
#include "src/compiler/linkage.h"
14
#include "src/compiler/node-matchers.h"
15
#include "src/compiler/node-properties.h"
16
#include "src/compiler/operator-properties.h"
17
#include "src/logging/counters.h"
18
#include "src/objects/js-generator.h"
19
#include "src/objects/objects-inl.h"
20 21 22 23 24

namespace v8 {
namespace internal {
namespace compiler {

25
JSIntrinsicLowering::JSIntrinsicLowering(Editor* editor, JSGraph* jsgraph,
26 27
                                         JSHeapBroker* broker)
    : AdvancedReducer(editor), jsgraph_(jsgraph), broker_(broker) {}
28 29

Reduction JSIntrinsicLowering::Reduce(Node* node) {
30
  DisallowHeapAccessIf no_heap_access(broker()->is_concurrent_inlining());
31

32 33 34
  if (node->opcode() != IrOpcode::kJSCallRuntime) return NoChange();
  const Runtime::Function* const f =
      Runtime::FunctionForId(CallRuntimeParametersOf(node->op()).id());
35
  if (f->function_id == Runtime::kTurbofanStaticAssert) {
36
    return ReduceTurbofanStaticAssert(node);
37 38 39 40
  }
  if (f->function_id == Runtime::kIsBeingInterpreted) {
    return ReduceIsBeingInterpreted(node);
  }
41
  if (f->intrinsic_type != Runtime::IntrinsicType::INLINE) return NoChange();
42
  switch (f->function_id) {
43 44
    case Runtime::kInlineCopyDataProperties:
      return ReduceCopyDataProperties(node);
45 46
    case Runtime::kInlineCreateIterResultObject:
      return ReduceCreateIterResultObject(node);
47
    case Runtime::kInlineDeoptimizeNow:
48
      return ReduceDeoptimizeNow(node);
49 50
    case Runtime::kInlineGeneratorClose:
      return ReduceGeneratorClose(node);
51 52
    case Runtime::kInlineCreateJSGeneratorObject:
      return ReduceCreateJSGeneratorObject(node);
53 54 55 56
    case Runtime::kInlineAsyncFunctionAwaitCaught:
      return ReduceAsyncFunctionAwaitCaught(node);
    case Runtime::kInlineAsyncFunctionAwaitUncaught:
      return ReduceAsyncFunctionAwaitUncaught(node);
57 58 59 60 61 62
    case Runtime::kInlineAsyncFunctionEnter:
      return ReduceAsyncFunctionEnter(node);
    case Runtime::kInlineAsyncFunctionReject:
      return ReduceAsyncFunctionReject(node);
    case Runtime::kInlineAsyncFunctionResolve:
      return ReduceAsyncFunctionResolve(node);
63 64 65 66
    case Runtime::kInlineAsyncGeneratorAwaitCaught:
      return ReduceAsyncGeneratorAwaitCaught(node);
    case Runtime::kInlineAsyncGeneratorAwaitUncaught:
      return ReduceAsyncGeneratorAwaitUncaught(node);
67 68 69 70
    case Runtime::kInlineAsyncGeneratorReject:
      return ReduceAsyncGeneratorReject(node);
    case Runtime::kInlineAsyncGeneratorResolve:
      return ReduceAsyncGeneratorResolve(node);
71 72
    case Runtime::kInlineAsyncGeneratorYield:
      return ReduceAsyncGeneratorYield(node);
73 74
    case Runtime::kInlineGeneratorGetResumeMode:
      return ReduceGeneratorGetResumeMode(node);
75
    case Runtime::kInlineIsArray:
76
      return ReduceIsInstanceType(node, JS_ARRAY_TYPE);
77 78
    case Runtime::kInlineIsJSReceiver:
      return ReduceIsJSReceiver(node);
79 80
    case Runtime::kInlineIsSmi:
      return ReduceIsSmi(node);
81 82
    case Runtime::kInlineToLength:
      return ReduceToLength(node);
83 84
    case Runtime::kInlineToObject:
      return ReduceToObject(node);
Shiyu Zhang's avatar
Shiyu Zhang committed
85
    case Runtime::kInlineToStringRT:
86
      return ReduceToString(node);
87 88
    case Runtime::kInlineCall:
      return ReduceCall(node);
89 90
    case Runtime::kInlineIncBlockCounter:
      return ReduceIncBlockCounter(node);
91 92
    case Runtime::kInlineGetImportMetaObject:
      return ReduceGetImportMetaObject(node);
93 94 95 96 97 98
    default:
      break;
  }
  return NoChange();
}

99 100 101 102
Reduction JSIntrinsicLowering::ReduceCopyDataProperties(Node* node) {
  return Change(
      node, Builtins::CallableFor(isolate(), Builtins::kCopyDataProperties), 0);
}
103

104 105 106 107 108 109 110 111 112
Reduction JSIntrinsicLowering::ReduceCreateIterResultObject(Node* node) {
  Node* const value = NodeProperties::GetValueInput(node, 0);
  Node* const done = NodeProperties::GetValueInput(node, 1);
  Node* const context = NodeProperties::GetContextInput(node);
  Node* const effect = NodeProperties::GetEffectInput(node);
  return Change(node, javascript()->CreateIterResultObject(), value, done,
                context, effect);
}

113
Reduction JSIntrinsicLowering::ReduceDeoptimizeNow(Node* node) {
114
  Node* const frame_state = NodeProperties::GetFrameStateInput(node);
115 116
  Node* const effect = NodeProperties::GetEffectInput(node);
  Node* const control = NodeProperties::GetControlInput(node);
117

118
  // TODO(bmeurer): Move MergeControlToEnd() to the AdvancedReducer.
119
  Node* deoptimize = graph()->NewNode(
120
      common()->Deoptimize(DeoptimizeKind::kEager,
121
                           DeoptimizeReason::kDeoptimizeNow, FeedbackSource()),
122
      frame_state, effect, control);
123
  NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
124
  Revisit(graph()->end());
125

126
  node->TrimInputCount(0);
127
  NodeProperties::ChangeOp(node, common()->Dead());
128
  return Changed(node);
129 130
}

131 132 133 134 135 136 137 138 139 140 141 142 143
Reduction JSIntrinsicLowering::ReduceCreateJSGeneratorObject(Node* node) {
  Node* const closure = NodeProperties::GetValueInput(node, 0);
  Node* const receiver = NodeProperties::GetValueInput(node, 1);
  Node* const context = NodeProperties::GetContextInput(node);
  Node* const effect = NodeProperties::GetEffectInput(node);
  Node* const control = NodeProperties::GetControlInput(node);
  Operator const* const op = javascript()->CreateGeneratorObject();
  Node* create_generator =
      graph()->NewNode(op, closure, receiver, context, effect, control);
  ReplaceWithValue(node, create_generator, create_generator);
  return Changed(create_generator);
}

144 145 146 147 148 149 150 151 152 153 154 155 156
Reduction JSIntrinsicLowering::ReduceGeneratorClose(Node* node) {
  Node* const generator = NodeProperties::GetValueInput(node, 0);
  Node* const effect = NodeProperties::GetEffectInput(node);
  Node* const control = NodeProperties::GetControlInput(node);
  Node* const closed = jsgraph()->Constant(JSGeneratorObject::kGeneratorClosed);
  Node* const undefined = jsgraph()->UndefinedConstant();
  Operator const* const op = simplified()->StoreField(
      AccessBuilder::ForJSGeneratorObjectContinuation());

  ReplaceWithValue(node, undefined, node);
  NodeProperties::RemoveType(node);
  return Change(node, op, generator, closed, effect, control);
}
157

158 159 160 161 162 163 164 165 166 167 168 169 170
Reduction JSIntrinsicLowering::ReduceAsyncFunctionAwaitCaught(Node* node) {
  return Change(
      node,
      Builtins::CallableFor(isolate(), Builtins::kAsyncFunctionAwaitCaught), 0);
}

Reduction JSIntrinsicLowering::ReduceAsyncFunctionAwaitUncaught(Node* node) {
  return Change(
      node,
      Builtins::CallableFor(isolate(), Builtins::kAsyncFunctionAwaitUncaught),
      0);
}

171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
Reduction JSIntrinsicLowering::ReduceAsyncFunctionEnter(Node* node) {
  NodeProperties::ChangeOp(node, javascript()->AsyncFunctionEnter());
  return Changed(node);
}

Reduction JSIntrinsicLowering::ReduceAsyncFunctionReject(Node* node) {
  RelaxControls(node);
  NodeProperties::ChangeOp(node, javascript()->AsyncFunctionReject());
  return Changed(node);
}

Reduction JSIntrinsicLowering::ReduceAsyncFunctionResolve(Node* node) {
  RelaxControls(node);
  NodeProperties::ChangeOp(node, javascript()->AsyncFunctionResolve());
  return Changed(node);
}

188 189 190 191 192 193 194 195 196 197 198 199 200 201
Reduction JSIntrinsicLowering::ReduceAsyncGeneratorAwaitCaught(Node* node) {
  return Change(
      node,
      Builtins::CallableFor(isolate(), Builtins::kAsyncGeneratorAwaitCaught),
      0);
}

Reduction JSIntrinsicLowering::ReduceAsyncGeneratorAwaitUncaught(Node* node) {
  return Change(
      node,
      Builtins::CallableFor(isolate(), Builtins::kAsyncGeneratorAwaitUncaught),
      0);
}

202
Reduction JSIntrinsicLowering::ReduceAsyncGeneratorReject(Node* node) {
203 204 205
  return Change(
      node, Builtins::CallableFor(isolate(), Builtins::kAsyncGeneratorReject),
      0);
206 207 208
}

Reduction JSIntrinsicLowering::ReduceAsyncGeneratorResolve(Node* node) {
209 210 211
  return Change(
      node, Builtins::CallableFor(isolate(), Builtins::kAsyncGeneratorResolve),
      0);
212 213
}

214 215 216 217 218 219
Reduction JSIntrinsicLowering::ReduceAsyncGeneratorYield(Node* node) {
  return Change(
      node, Builtins::CallableFor(isolate(), Builtins::kAsyncGeneratorYield),
      0);
}

220 221 222 223 224 225 226 227 228 229
Reduction JSIntrinsicLowering::ReduceGeneratorGetResumeMode(Node* node) {
  Node* const generator = NodeProperties::GetValueInput(node, 0);
  Node* const effect = NodeProperties::GetEffectInput(node);
  Node* const control = NodeProperties::GetControlInput(node);
  Operator const* const op =
      simplified()->LoadField(AccessBuilder::ForJSGeneratorObjectResumeMode());

  return Change(node, op, generator, effect, control);
}

230
Reduction JSIntrinsicLowering::ReduceIsInstanceType(
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
    Node* node, InstanceType instance_type) {
  // if (%_IsSmi(value)) {
  //   return false;
  // } else {
  //   return %_GetInstanceType(%_GetMap(value)) == instance_type;
  // }
  Node* value = NodeProperties::GetValueInput(node, 0);
  Node* effect = NodeProperties::GetEffectInput(node);
  Node* control = NodeProperties::GetControlInput(node);

  Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
  Node* branch = graph()->NewNode(common()->Branch(), check, control);

  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
  Node* etrue = effect;
  Node* vtrue = jsgraph()->FalseConstant();

  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
249 250
  Node* efalse = effect;
  Node* map = efalse =
251
      graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), value,
252 253 254 255 256 257 258
                       efalse, if_false);
  Node* map_instance_type = efalse = graph()->NewNode(
      simplified()->LoadField(AccessBuilder::ForMapInstanceType()), map, efalse,
      if_false);
  Node* vfalse =
      graph()->NewNode(simplified()->NumberEqual(), map_instance_type,
                       jsgraph()->Constant(instance_type));
259 260 261 262 263

  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);

  // Replace all effect uses of {node} with the {ephi}.
  Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
264
  ReplaceWithValue(node, node, ephi, merge);
265 266

  // Turn the {node} into a Phi.
267 268
  return Change(node, common()->Phi(MachineRepresentation::kTagged, 2), vtrue,
                vfalse, merge);
269 270 271
}


272
Reduction JSIntrinsicLowering::ReduceIsJSReceiver(Node* node) {
273
  return Change(node, simplified()->ObjectIsReceiver());
274 275 276
}


277 278 279 280
Reduction JSIntrinsicLowering::ReduceIsSmi(Node* node) {
  return Change(node, simplified()->ObjectIsSmi());
}

281
Reduction JSIntrinsicLowering::ReduceTurbofanStaticAssert(Node* node) {
282 283 284 285 286 287
  if (FLAG_always_opt) {
    // Ignore static asserts, as we most likely won't have enough information
    RelaxEffectsAndControls(node);
  } else {
    Node* value = NodeProperties::GetValueInput(node, 0);
    Node* effect = NodeProperties::GetEffectInput(node);
288 289
    Node* assert = graph()->NewNode(
        common()->StaticAssert("%TurbofanStaticAssert"), value, effect);
290 291 292 293 294
    ReplaceWithValue(node, node, assert, nullptr);
  }
  return Changed(jsgraph_->UndefinedConstant());
}

295 296 297 298 299
Reduction JSIntrinsicLowering::ReduceIsBeingInterpreted(Node* node) {
  RelaxEffectsAndControls(node);
  return Changed(jsgraph_->FalseConstant());
}

300
Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op) {
301
  // Replace all effect uses of {node} with the effect dependency.
302
  RelaxEffectsAndControls(node);
303 304 305
  // Remove the inputs corresponding to context, effect and control.
  NodeProperties::RemoveNonValueInputs(node);
  // Finally update the operator to the new one.
306
  NodeProperties::ChangeOp(node, op);
307 308 309
  return Changed(node);
}

310 311

Reduction JSIntrinsicLowering::ReduceToLength(Node* node) {
312 313
  NodeProperties::ChangeOp(node, javascript()->ToLength());
  return Changed(node);
314 315 316
}


317
Reduction JSIntrinsicLowering::ReduceToObject(Node* node) {
318
  NodeProperties::ChangeOp(node, javascript()->ToObject());
319 320 321 322
  return Changed(node);
}


323
Reduction JSIntrinsicLowering::ReduceToString(Node* node) {
324 325
  // ToString is unnecessary if the input is a string.
  HeapObjectMatcher m(NodeProperties::GetValueInput(node, 0));
326
  if (m.HasValue() && m.Ref(broker()).IsString()) {
327 328 329
    ReplaceWithValue(node, m.node());
    return Replace(m.node());
  }
330 331 332 333 334
  NodeProperties::ChangeOp(node, javascript()->ToString());
  return Changed(node);
}


335
Reduction JSIntrinsicLowering::ReduceCall(Node* node) {
336 337 338
  int const arity =
      static_cast<int>(CallRuntimeParametersOf(node->op()).arity());
  static constexpr int kTargetAndReceiver = 2;
339
  STATIC_ASSERT(JSCallNode::kFeedbackVectorIsLastInput);
340 341 342 343 344
  Node* feedback = jsgraph()->UndefinedConstant();
  node->InsertInput(graph()->zone(), arity, feedback);
  NodeProperties::ChangeOp(
      node,
      javascript()->Call(JSCallNode::ArityForArgc(arity - kTargetAndReceiver)));
345 346 347
  return Changed(node);
}

348 349 350 351 352 353 354 355
Reduction JSIntrinsicLowering::ReduceIncBlockCounter(Node* node) {
  DCHECK(!Linkage::NeedsFrameStateInput(Runtime::kIncBlockCounter));
  DCHECK(!Linkage::NeedsFrameStateInput(Runtime::kInlineIncBlockCounter));
  return Change(node,
                Builtins::CallableFor(isolate(), Builtins::kIncBlockCounter), 0,
                kDoesNotNeedFrameState);
}

356 357 358 359 360
Reduction JSIntrinsicLowering::ReduceGetImportMetaObject(Node* node) {
  NodeProperties::ChangeOp(node, javascript()->GetImportMeta());
  return Changed(node);
}

361 362
Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
                                      Node* b) {
363
  RelaxControls(node);
364 365 366
  node->ReplaceInput(0, a);
  node->ReplaceInput(1, b);
  node->TrimInputCount(2);
367
  NodeProperties::ChangeOp(node, op);
368 369 370 371
  return Changed(node);
}


372 373
Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
                                      Node* b, Node* c) {
374
  RelaxControls(node);
375 376 377 378
  node->ReplaceInput(0, a);
  node->ReplaceInput(1, b);
  node->ReplaceInput(2, c);
  node->TrimInputCount(3);
379
  NodeProperties::ChangeOp(node, op);
380 381 382 383
  return Changed(node);
}


384 385
Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
                                      Node* b, Node* c, Node* d) {
386
  RelaxControls(node);
387 388 389 390 391
  node->ReplaceInput(0, a);
  node->ReplaceInput(1, b);
  node->ReplaceInput(2, c);
  node->ReplaceInput(3, d);
  node->TrimInputCount(4);
392
  NodeProperties::ChangeOp(node, op);
393 394 395
  return Changed(node);
}

396
Reduction JSIntrinsicLowering::Change(Node* node, Callable const& callable,
397 398 399 400 401
                                      int stack_parameter_count,
                                      enum FrameStateFlag frame_state_flag) {
  CallDescriptor::Flags flags = frame_state_flag == kNeedsFrameState
                                    ? CallDescriptor::kNeedsFrameState
                                    : CallDescriptor::kNoFlags;
402
  auto call_descriptor = Linkage::GetStubCallDescriptor(
403 404
      graph()->zone(), callable.descriptor(), stack_parameter_count, flags,
      node->op()->properties());
405 406
  node->InsertInput(graph()->zone(), 0,
                    jsgraph()->HeapConstant(callable.code()));
407
  NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
408 409 410
  return Changed(node);
}

411 412 413
Graph* JSIntrinsicLowering::graph() const { return jsgraph()->graph(); }


414 415 416
Isolate* JSIntrinsicLowering::isolate() const { return jsgraph()->isolate(); }


417 418 419 420
CommonOperatorBuilder* JSIntrinsicLowering::common() const {
  return jsgraph()->common();
}

421 422 423 424
JSOperatorBuilder* JSIntrinsicLowering::javascript() const {
  return jsgraph_->javascript();
}

425 426 427 428
SimplifiedOperatorBuilder* JSIntrinsicLowering::simplified() const {
  return jsgraph()->simplified();
}

429 430 431
}  // namespace compiler
}  // namespace internal
}  // namespace v8