mirror of https://github.com/lukechilds/node.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
684 lines
24 KiB
684 lines
24 KiB
// 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
|
|
|