blob: 379f8b7490263f3cd872a1c8ca3fc0e91850f28f [file] [log] [blame]
// 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"
#include <stack>
#include "src/code-factory.h"
#include "src/compiler/access-builder.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/linkage.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/operator-properties.h"
#include "src/counters.h"
#include "src/objects-inl.h"
#include "src/type-cache.h"
namespace v8 {
namespace internal {
namespace compiler {
JSIntrinsicLowering::JSIntrinsicLowering(Editor* editor, JSGraph* jsgraph,
DeoptimizationMode mode)
: AdvancedReducer(editor),
jsgraph_(jsgraph),
mode_(mode),
type_cache_(TypeCache::Get()) {}
Reduction JSIntrinsicLowering::Reduce(Node* node) {
if (node->opcode() != IrOpcode::kJSCallRuntime) return NoChange();
const Runtime::Function* const f =
Runtime::FunctionForId(CallRuntimeParametersOf(node->op()).id());
if (f->intrinsic_type != Runtime::IntrinsicType::INLINE) return NoChange();
switch (f->function_id) {
case Runtime::kInlineConstructDouble:
return ReduceConstructDouble(node);
case Runtime::kInlineDateField:
return ReduceDateField(node);
case Runtime::kInlineDeoptimizeNow:
return ReduceDeoptimizeNow(node);
case Runtime::kInlineDoubleHi:
return ReduceDoubleHi(node);
case Runtime::kInlineDoubleLo:
return ReduceDoubleLo(node);
case Runtime::kInlineHeapObjectGetMap:
return ReduceHeapObjectGetMap(node);
case Runtime::kInlineIncrementStatsCounter:
return ReduceIncrementStatsCounter(node);
case Runtime::kInlineIsArray:
return ReduceIsInstanceType(node, JS_ARRAY_TYPE);
case Runtime::kInlineIsDate:
return ReduceIsInstanceType(node, JS_DATE_TYPE);
case Runtime::kInlineIsTypedArray:
return ReduceIsInstanceType(node, JS_TYPED_ARRAY_TYPE);
case Runtime::kInlineIsFunction:
return ReduceIsInstanceType(node, JS_FUNCTION_TYPE);
case Runtime::kInlineIsRegExp:
return ReduceIsInstanceType(node, JS_REGEXP_TYPE);
case Runtime::kInlineIsSmi:
return ReduceIsSmi(node);
case Runtime::kInlineJSValueGetValue:
return ReduceJSValueGetValue(node);
case Runtime::kInlineMapGetInstanceType:
return ReduceMapGetInstanceType(node);
case Runtime::kInlineMathClz32:
return ReduceMathClz32(node);
case Runtime::kInlineMathFloor:
return ReduceMathFloor(node);
case Runtime::kInlineMathSqrt:
return ReduceMathSqrt(node);
case Runtime::kInlineOneByteSeqStringGetChar:
return ReduceSeqStringGetChar(node, String::ONE_BYTE_ENCODING);
case Runtime::kInlineOneByteSeqStringSetChar:
return ReduceSeqStringSetChar(node, String::ONE_BYTE_ENCODING);
case Runtime::kInlineStringGetLength:
return ReduceStringGetLength(node);
case Runtime::kInlineTwoByteSeqStringGetChar:
return ReduceSeqStringGetChar(node, String::TWO_BYTE_ENCODING);
case Runtime::kInlineTwoByteSeqStringSetChar:
return ReduceSeqStringSetChar(node, String::TWO_BYTE_ENCODING);
case Runtime::kInlineValueOf:
return ReduceValueOf(node);
case Runtime::kInlineIsMinusZero:
return ReduceIsMinusZero(node);
case Runtime::kInlineFixedArrayGet:
return ReduceFixedArrayGet(node);
case Runtime::kInlineFixedArraySet:
return ReduceFixedArraySet(node);
case Runtime::kInlineGetTypeFeedbackVector:
return ReduceGetTypeFeedbackVector(node);
case Runtime::kInlineGetCallerJSFunction:
return ReduceGetCallerJSFunction(node);
case Runtime::kInlineToInteger:
return ReduceToInteger(node);
case Runtime::kInlineToLength:
return ReduceToLength(node);
case Runtime::kInlineToName:
return ReduceToName(node);
case Runtime::kInlineToNumber:
return ReduceToNumber(node);
case Runtime::kInlineToObject:
return ReduceToObject(node);
case Runtime::kInlineToPrimitive:
return ReduceToPrimitive(node);
case Runtime::kInlineToString:
return ReduceToString(node);
case Runtime::kInlineThrowNotDateError:
return ReduceThrowNotDateError(node);
case Runtime::kInlineCall:
return ReduceCall(node);
default:
break;
}
return NoChange();
}
Reduction JSIntrinsicLowering::ReduceConstructDouble(Node* node) {
Node* high = NodeProperties::GetValueInput(node, 0);
Node* low = NodeProperties::GetValueInput(node, 1);
Node* value =
graph()->NewNode(machine()->Float64InsertHighWord32(),
graph()->NewNode(machine()->Float64InsertLowWord32(),
jsgraph()->Constant(0), low),
high);
ReplaceWithValue(node, value);
return Replace(value);
}
Reduction JSIntrinsicLowering::ReduceDateField(Node* node) {
Node* const value = NodeProperties::GetValueInput(node, 0);
Node* const index = NodeProperties::GetValueInput(node, 1);
Node* const effect = NodeProperties::GetEffectInput(node);
Node* const control = NodeProperties::GetControlInput(node);
NumberMatcher mindex(index);
if (mindex.Is(JSDate::kDateValue)) {
return Change(
node,
simplified()->LoadField(AccessBuilder::ForJSDateField(
static_cast<JSDate::FieldIndex>(static_cast<int>(mindex.Value())))),
value, effect, control);
}
// TODO(turbofan): Optimize more patterns.
return NoChange();
}
Reduction JSIntrinsicLowering::ReduceDeoptimizeNow(Node* node) {
if (mode() != kDeoptimizationEnabled) return NoChange();
Node* const frame_state = NodeProperties::GetFrameStateInput(node, 0);
Node* const effect = NodeProperties::GetEffectInput(node);
Node* const control = NodeProperties::GetControlInput(node);
// TODO(bmeurer): Move MergeControlToEnd() to the AdvancedReducer.
Node* deoptimize =
graph()->NewNode(common()->Deoptimize(), frame_state, effect, control);
NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
node->TrimInputCount(0);
NodeProperties::ChangeOp(node, common()->Dead());
return Changed(node);
}
Reduction JSIntrinsicLowering::ReduceDoubleHi(Node* node) {
return Change(node, machine()->Float64ExtractHighWord32());
}
Reduction JSIntrinsicLowering::ReduceDoubleLo(Node* node) {
return Change(node, machine()->Float64ExtractLowWord32());
}
Reduction JSIntrinsicLowering::ReduceHeapObjectGetMap(Node* node) {
Node* value = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
return Change(node, simplified()->LoadField(AccessBuilder::ForMap()), value,
effect, control);
}
Reduction JSIntrinsicLowering::ReduceIncrementStatsCounter(Node* node) {
if (!FLAG_native_code_counters) return ChangeToUndefined(node);
HeapObjectMatcher m(NodeProperties::GetValueInput(node, 0));
if (!m.HasValue() || !m.Value()->IsString()) {
return ChangeToUndefined(node);
}
base::SmartArrayPointer<char> name =
Handle<String>::cast(m.Value())->ToCString();
StatsCounter counter(jsgraph()->isolate(), name.get());
if (!counter.Enabled()) return ChangeToUndefined(node);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
FieldAccess access = AccessBuilder::ForStatsCounter();
Node* cnt = jsgraph()->ExternalConstant(ExternalReference(&counter));
Node* load =
graph()->NewNode(simplified()->LoadField(access), cnt, effect, control);
Node* inc =
graph()->NewNode(machine()->Int32Add(), load, jsgraph()->OneConstant());
Node* store = graph()->NewNode(simplified()->StoreField(access), cnt, inc,
load, control);
return ChangeToUndefined(node, store);
}
Reduction JSIntrinsicLowering::ReduceIsInstanceType(
Node* node, InstanceType instance_type) {
// if (%_IsSmi(value)) {
// return false;
// } else {
// return %_GetInstanceType(%_GetMap(value)) == instance_type;
// }
MachineType const type = static_cast<MachineType>(kTypeBool | kRepTagged);
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);
Node* efalse = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), value,
effect, if_false),
effect, if_false);
Node* vfalse = graph()->NewNode(machine()->Word32Equal(), efalse,
jsgraph()->Int32Constant(instance_type));
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);
ReplaceWithValue(node, node, ephi);
// Turn the {node} into a Phi.
return Change(node, common()->Phi(type, 2), vtrue, vfalse, merge);
}
Reduction JSIntrinsicLowering::ReduceIsSmi(Node* node) {
return Change(node, simplified()->ObjectIsSmi());
}
Reduction JSIntrinsicLowering::ReduceJSValueGetValue(Node* node) {
Node* value = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
return Change(node, simplified()->LoadField(AccessBuilder::ForValue()), value,
effect, control);
}
Reduction JSIntrinsicLowering::ReduceMapGetInstanceType(Node* node) {
Node* value = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
return Change(node,
simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
value, effect, control);
}
Reduction JSIntrinsicLowering::ReduceMathClz32(Node* node) {
return Change(node, machine()->Word32Clz());
}
Reduction JSIntrinsicLowering::ReduceMathFloor(Node* node) {
if (!machine()->Float64RoundDown().IsSupported()) return NoChange();
return Change(node, machine()->Float64RoundDown().op());
}
Reduction JSIntrinsicLowering::ReduceMathSqrt(Node* node) {
return Change(node, machine()->Float64Sqrt());
}
Reduction JSIntrinsicLowering::ReduceSeqStringGetChar(
Node* node, String::Encoding encoding) {
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
RelaxControls(node);
node->ReplaceInput(2, effect);
node->ReplaceInput(3, control);
node->TrimInputCount(4);
NodeProperties::ChangeOp(
node,
simplified()->LoadElement(AccessBuilder::ForSeqStringChar(encoding)));
return Changed(node);
}
Reduction JSIntrinsicLowering::ReduceSeqStringSetChar(
Node* node, String::Encoding encoding) {
// Note: The intrinsic has a strange argument order, so we need to reshuffle.
Node* index = NodeProperties::GetValueInput(node, 0);
Node* chr = NodeProperties::GetValueInput(node, 1);
Node* string = NodeProperties::GetValueInput(node, 2);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
ReplaceWithValue(node, string, node);
NodeProperties::RemoveType(node);
node->ReplaceInput(0, string);
node->ReplaceInput(1, index);
node->ReplaceInput(2, chr);
node->ReplaceInput(3, effect);
node->ReplaceInput(4, control);
node->TrimInputCount(5);
NodeProperties::ChangeOp(
node,
simplified()->StoreElement(AccessBuilder::ForSeqStringChar(encoding)));
return Changed(node);
}
Reduction JSIntrinsicLowering::ReduceStringGetLength(Node* node) {
Node* value = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
return Change(node, simplified()->LoadField(AccessBuilder::ForStringLength()),
value, effect, control);
}
Reduction JSIntrinsicLowering::ReduceValueOf(Node* node) {
// if (%_IsSmi(value)) {
// return value;
// } else if (%_GetInstanceType(%_GetMap(value)) == JS_VALUE_TYPE) {
// return %_GetValue(value);
// } else {
// return value;
// }
const Operator* const merge_op = common()->Merge(2);
const Operator* const ephi_op = common()->EffectPhi(2);
const Operator* const phi_op = common()->Phi(kMachAnyTagged, 2);
Node* value = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
Node* branch0 = graph()->NewNode(common()->Branch(), check0, control);
Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
Node* etrue0 = effect;
Node* vtrue0 = value;
Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
Node* efalse0;
Node* vfalse0;
{
Node* check1 = graph()->NewNode(
machine()->Word32Equal(),
graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
value, effect, if_false0),
effect, if_false0),
jsgraph()->Int32Constant(JS_VALUE_TYPE));
Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
Node* etrue1 =
graph()->NewNode(simplified()->LoadField(AccessBuilder::ForValue()),
value, effect, if_true1);
Node* vtrue1 = etrue1;
Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
Node* efalse1 = effect;
Node* vfalse1 = value;
Node* merge1 = graph()->NewNode(merge_op, if_true1, if_false1);
efalse0 = graph()->NewNode(ephi_op, etrue1, efalse1, merge1);
vfalse0 = graph()->NewNode(phi_op, vtrue1, vfalse1, merge1);
}
Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
// Replace all effect uses of {node} with the {ephi0}.
Node* ephi0 = graph()->NewNode(ephi_op, etrue0, efalse0, merge0);
ReplaceWithValue(node, node, ephi0);
// Turn the {node} into a Phi.
return Change(node, phi_op, vtrue0, vfalse0, merge0);
}
Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op) {
// Replace all effect uses of {node} with the effect dependency.
RelaxEffectsAndControls(node);
// Remove the inputs corresponding to context, effect and control.
NodeProperties::RemoveNonValueInputs(node);
// Finally update the operator to the new one.
NodeProperties::ChangeOp(node, op);
return Changed(node);
}
Reduction JSIntrinsicLowering::ReduceIsMinusZero(Node* node) {
Node* value = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node);
Node* double_lo =
graph()->NewNode(machine()->Float64ExtractLowWord32(), value);
Node* check1 = graph()->NewNode(machine()->Word32Equal(), double_lo,
jsgraph()->ZeroConstant());
Node* double_hi =
graph()->NewNode(machine()->Float64ExtractHighWord32(), value);
Node* check2 = graph()->NewNode(
machine()->Word32Equal(), double_hi,
jsgraph()->Int32Constant(static_cast<int32_t>(0x80000000)));
ReplaceWithValue(node, node, effect);
Node* and_result = graph()->NewNode(machine()->Word32And(), check1, check2);
return Change(node, machine()->Word32Equal(), and_result,
jsgraph()->Int32Constant(1));
}
Reduction JSIntrinsicLowering::ReduceFixedArrayGet(Node* node) {
Node* base = node->InputAt(0);
Node* index = node->InputAt(1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
return Change(
node, simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
base, index, effect, control);
}
Reduction JSIntrinsicLowering::ReduceFixedArraySet(Node* node) {
Node* base = node->InputAt(0);
Node* index = node->InputAt(1);
Node* value = node->InputAt(2);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* store = (graph()->NewNode(
simplified()->StoreElement(AccessBuilder::ForFixedArrayElement()), base,
index, value, effect, control));
ReplaceWithValue(node, value, store);
return Changed(store);
}
Reduction JSIntrinsicLowering::ReduceGetTypeFeedbackVector(Node* node) {
Node* func = node->InputAt(0);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
FieldAccess access = AccessBuilder::ForJSFunctionSharedFunctionInfo();
Node* load =
graph()->NewNode(simplified()->LoadField(access), func, effect, control);
access = AccessBuilder::ForSharedFunctionInfoTypeFeedbackVector();
return Change(node, simplified()->LoadField(access), load, load, control);
}
Reduction JSIntrinsicLowering::ReduceGetCallerJSFunction(Node* node) {
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* const frame_state = NodeProperties::GetFrameStateInput(node, 0);
Node* outer_frame = frame_state->InputAt(kFrameStateOuterStateInput);
if (outer_frame->opcode() == IrOpcode::kFrameState) {
// Use the runtime implementation to throw the appropriate error if the
// containing function is inlined.
return NoChange();
}
// TODO(danno): This implementation forces intrinsic lowering to happen after
// inlining, which is fine for now, but eventually the frame-querying logic
// probably should go later, e.g. in instruction selection, so that there is
// no phase-ordering dependency.
FieldAccess access = AccessBuilder::ForFrameCallerFramePtr();
Node* fp = graph()->NewNode(machine()->LoadFramePointer());
Node* next_fp =
graph()->NewNode(simplified()->LoadField(access), fp, effect, control);
return Change(node, simplified()->LoadField(AccessBuilder::ForFrameMarker()),
next_fp, effect, control);
}
Reduction JSIntrinsicLowering::ReduceThrowNotDateError(Node* node) {
if (mode() != kDeoptimizationEnabled) return NoChange();
Node* const frame_state = NodeProperties::GetFrameStateInput(node, 1);
Node* const effect = NodeProperties::GetEffectInput(node);
Node* const control = NodeProperties::GetControlInput(node);
// TODO(bmeurer): Move MergeControlToEnd() to the AdvancedReducer.
Node* deoptimize =
graph()->NewNode(common()->Deoptimize(), frame_state, effect, control);
NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
node->TrimInputCount(0);
NodeProperties::ChangeOp(node, common()->Dead());
return Changed(node);
}
Reduction JSIntrinsicLowering::ReduceToInteger(Node* node) {
Node* value = NodeProperties::GetValueInput(node, 0);
Type* value_type = NodeProperties::GetType(value);
if (value_type->Is(type_cache().kIntegerOrMinusZero)) {
ReplaceWithValue(node, value);
return Replace(value);
}
return NoChange();
}
Reduction JSIntrinsicLowering::ReduceToName(Node* node) {
NodeProperties::ChangeOp(node, javascript()->ToName());
return Changed(node);
}
Reduction JSIntrinsicLowering::ReduceToNumber(Node* node) {
NodeProperties::ChangeOp(node, javascript()->ToNumber());
return Changed(node);
}
Reduction JSIntrinsicLowering::ReduceToLength(Node* node) {
Node* value = NodeProperties::GetValueInput(node, 0);
Type* value_type = NodeProperties::GetType(value);
if (value_type->Is(type_cache().kIntegerOrMinusZero)) {
if (value_type->Max() <= 0.0) {
value = jsgraph()->ZeroConstant();
} else if (value_type->Min() >= kMaxSafeInteger) {
value = jsgraph()->Constant(kMaxSafeInteger);
} else {
if (value_type->Min() <= 0.0) {
value = graph()->NewNode(
common()->Select(kMachAnyTagged),
graph()->NewNode(simplified()->NumberLessThanOrEqual(), value,
jsgraph()->ZeroConstant()),
jsgraph()->ZeroConstant(), value);
value_type = Type::Range(0.0, value_type->Max(), graph()->zone());
NodeProperties::SetType(value, value_type);
}
if (value_type->Max() > kMaxSafeInteger) {
value = graph()->NewNode(
common()->Select(kMachAnyTagged),
graph()->NewNode(simplified()->NumberLessThanOrEqual(),
jsgraph()->Constant(kMaxSafeInteger), value),
jsgraph()->Constant(kMaxSafeInteger), value);
value_type =
Type::Range(value_type->Min(), kMaxSafeInteger, graph()->zone());
NodeProperties::SetType(value, value_type);
}
}
ReplaceWithValue(node, value);
return Replace(value);
}
Callable callable = CodeFactory::ToLength(isolate());
CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
isolate(), graph()->zone(), callable.descriptor(), 0,
CallDescriptor::kNeedsFrameState, node->op()->properties());
node->InsertInput(graph()->zone(), 0,
jsgraph()->HeapConstant(callable.code()));
NodeProperties::ChangeOp(node, common()->Call(desc));
return Changed(node);
}
Reduction JSIntrinsicLowering::ReduceToObject(Node* node) {
NodeProperties::ChangeOp(node, javascript()->ToObject());
return Changed(node);
}
Reduction JSIntrinsicLowering::ReduceToPrimitive(Node* node) {
Node* value = NodeProperties::GetValueInput(node, 0);
Type* value_type = NodeProperties::GetType(value);
if (value_type->Is(Type::Primitive())) {
ReplaceWithValue(node, value);
return Replace(value);
}
return NoChange();
}
Reduction JSIntrinsicLowering::ReduceToString(Node* node) {
NodeProperties::ChangeOp(node, javascript()->ToString());
return Changed(node);
}
Reduction JSIntrinsicLowering::ReduceCall(Node* node) {
size_t const arity = CallRuntimeParametersOf(node->op()).arity();
NodeProperties::ChangeOp(
node, javascript()->CallFunction(arity, STRICT, VectorSlotPair(),
ConvertReceiverMode::kAny,
TailCallMode::kAllow));
return Changed(node);
}
Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
Node* b) {
RelaxControls(node);
node->ReplaceInput(0, a);
node->ReplaceInput(1, b);
node->TrimInputCount(2);
NodeProperties::ChangeOp(node, op);
return Changed(node);
}
Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
Node* b, Node* c) {
RelaxControls(node);
node->ReplaceInput(0, a);
node->ReplaceInput(1, b);
node->ReplaceInput(2, c);
node->TrimInputCount(3);
NodeProperties::ChangeOp(node, op);
return Changed(node);
}
Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
Node* b, Node* c, Node* d) {
RelaxControls(node);
node->ReplaceInput(0, a);
node->ReplaceInput(1, b);
node->ReplaceInput(2, c);
node->ReplaceInput(3, d);
node->TrimInputCount(4);
NodeProperties::ChangeOp(node, op);
return Changed(node);
}
Reduction JSIntrinsicLowering::ChangeToUndefined(Node* node, Node* effect) {
ReplaceWithValue(node, jsgraph()->UndefinedConstant(), effect);
return Changed(node);
}
Graph* JSIntrinsicLowering::graph() const { return jsgraph()->graph(); }
Isolate* JSIntrinsicLowering::isolate() const { return jsgraph()->isolate(); }
CommonOperatorBuilder* JSIntrinsicLowering::common() const {
return jsgraph()->common();
}
JSOperatorBuilder* JSIntrinsicLowering::javascript() const {
return jsgraph_->javascript();
}
MachineOperatorBuilder* JSIntrinsicLowering::machine() const {
return jsgraph()->machine();
}
SimplifiedOperatorBuilder* JSIntrinsicLowering::simplified() const {
return jsgraph()->simplified();
}
} // namespace compiler
} // namespace internal
} // namespace v8