| Index: src/compiler/js-typed-lowering.cc
|
| diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc
|
| index 1fcb0f272e7422d191e8cab62bd0cbe44bbe91e8..0d83d2baf1949a94def00b654b5abd74e10bcc47 100644
|
| --- a/src/compiler/js-typed-lowering.cc
|
| +++ b/src/compiler/js-typed-lowering.cc
|
| @@ -844,6 +844,85 @@ Reduction JSTypedLowering::ReduceJSToString(Node* node) {
|
| }
|
|
|
|
|
| +Reduction JSTypedLowering::ReduceJSToObject(Node* node) {
|
| + DCHECK_EQ(IrOpcode::kJSToObject, node->opcode());
|
| + Node* receiver = NodeProperties::GetValueInput(node, 0);
|
| + Type* receiver_type = NodeProperties::GetType(receiver);
|
| + Node* context = NodeProperties::GetContextInput(node);
|
| + Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
|
| + Node* effect = NodeProperties::GetEffectInput(node);
|
| + Node* control = NodeProperties::GetControlInput(node);
|
| + if (!receiver_type->Is(Type::Receiver())) {
|
| + // TODO(bmeurer/mstarzinger): Add support for lowering inside try blocks.
|
| + if (receiver_type->Maybe(Type::NullOrUndefined()) &&
|
| + NodeProperties::IsExceptionalCall(node)) {
|
| + // ToObject throws for null or undefined inputs.
|
| + return NoChange();
|
| + }
|
| +
|
| + // Check whether {receiver} is a Smi.
|
| + Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
|
| + Node* branch0 =
|
| + graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
|
| + Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
|
| + Node* etrue0 = effect;
|
| +
|
| + Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
|
| + Node* efalse0 = effect;
|
| +
|
| + // Determine the instance type of {receiver}.
|
| + Node* receiver_map = efalse0 =
|
| + graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
|
| + receiver, efalse0, if_false0);
|
| + Node* receiver_instance_type = efalse0 = graph()->NewNode(
|
| + simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
|
| + receiver_map, efalse0, if_false0);
|
| +
|
| + // Check whether {receiver} is a spec object.
|
| + STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
| + Node* check1 =
|
| + graph()->NewNode(machine()->Uint32LessThanOrEqual(),
|
| + jsgraph()->Uint32Constant(FIRST_JS_RECEIVER_TYPE),
|
| + receiver_instance_type);
|
| + Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
|
| + check1, if_false0);
|
| + Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
|
| + Node* etrue1 = efalse0;
|
| +
|
| + Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
|
| + Node* efalse1 = efalse0;
|
| +
|
| + // Convert {receiver} using the ToObjectStub.
|
| + Node* if_convert =
|
| + graph()->NewNode(common()->Merge(2), if_true0, if_false1);
|
| + Node* econvert =
|
| + graph()->NewNode(common()->EffectPhi(2), etrue0, efalse1, if_convert);
|
| + Node* rconvert;
|
| + {
|
| + Callable callable = CodeFactory::ToObject(isolate());
|
| + CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
|
| + isolate(), graph()->zone(), callable.descriptor(), 0,
|
| + CallDescriptor::kNeedsFrameState, node->op()->properties());
|
| + rconvert = econvert = graph()->NewNode(
|
| + common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
|
| + receiver, context, frame_state, econvert, if_convert);
|
| + }
|
| +
|
| + // The {receiver} is already a spec object.
|
| + Node* if_done = if_true1;
|
| + Node* edone = etrue1;
|
| + Node* rdone = receiver;
|
| +
|
| + control = graph()->NewNode(common()->Merge(2), if_convert, if_done);
|
| + effect = graph()->NewNode(common()->EffectPhi(2), econvert, edone, control);
|
| + receiver = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), rconvert,
|
| + rdone, control);
|
| + }
|
| + ReplaceWithValue(node, receiver, effect, control);
|
| + return Changed(receiver);
|
| +}
|
| +
|
| +
|
| Reduction JSTypedLowering::ReduceJSLoadNamed(Node* node) {
|
| DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
|
| Node* receiver = NodeProperties::GetValueInput(node, 0);
|
| @@ -1181,7 +1260,62 @@ Reduction JSTypedLowering::ReduceJSConvertReceiver(Node* node) {
|
| graph()->NewNode(javascript()->ToObject(), receiver, context,
|
| frame_state, effect, control);
|
| } else {
|
| - return NoChange();
|
| + // Check {receiver} for undefined.
|
| + Node* check0 =
|
| + graph()->NewNode(simplified()->ReferenceEqual(receiver_type),
|
| + receiver, jsgraph()->UndefinedConstant());
|
| + Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
|
| + check0, control);
|
| + Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
|
| + Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
|
| +
|
| + // Check {receiver} for null.
|
| + Node* check1 =
|
| + graph()->NewNode(simplified()->ReferenceEqual(receiver_type),
|
| + receiver, jsgraph()->NullConstant());
|
| + Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
|
| + check1, if_false0);
|
| + Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
|
| + Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
|
| +
|
| + // Convert {receiver} using ToObject.
|
| + Node* if_convert = if_false1;
|
| + Node* econvert = effect;
|
| + Node* rconvert;
|
| + {
|
| + rconvert = econvert =
|
| + graph()->NewNode(javascript()->ToObject(), receiver, context,
|
| + frame_state, econvert, if_convert);
|
| + }
|
| +
|
| + // Replace {receiver} with global proxy of {context}.
|
| + Node* if_global =
|
| + graph()->NewNode(common()->Merge(2), if_true0, if_true1);
|
| + Node* eglobal = effect;
|
| + Node* rglobal;
|
| + {
|
| + if (context_type->IsConstant()) {
|
| + Handle<JSObject> global_proxy(
|
| + Handle<Context>::cast(context_type->AsConstant()->Value())
|
| + ->global_proxy(),
|
| + isolate());
|
| + rglobal = jsgraph()->Constant(global_proxy);
|
| + } else {
|
| + Node* global_object = eglobal = graph()->NewNode(
|
| + javascript()->LoadContext(0, Context::GLOBAL_OBJECT_INDEX, true),
|
| + context, context, eglobal);
|
| + rglobal = eglobal =
|
| + graph()->NewNode(simplified()->LoadField(
|
| + AccessBuilder::ForGlobalObjectGlobalProxy()),
|
| + global_object, eglobal, if_global);
|
| + }
|
| + }
|
| +
|
| + control = graph()->NewNode(common()->Merge(2), if_convert, if_global);
|
| + effect =
|
| + graph()->NewNode(common()->EffectPhi(2), econvert, eglobal, control);
|
| + receiver = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), rconvert,
|
| + rglobal, control);
|
| }
|
| }
|
| ReplaceWithValue(node, receiver, effect, control);
|
| @@ -1554,10 +1688,14 @@ Reduction JSTypedLowering::ReduceJSCallFunction(Node* node) {
|
| DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
|
| CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
|
| int const arity = static_cast<int>(p.arity() - 2);
|
| + ConvertReceiverMode const convert_mode = p.convert_mode();
|
| Node* target = NodeProperties::GetValueInput(node, 0);
|
| Type* target_type = NodeProperties::GetType(target);
|
| Node* receiver = NodeProperties::GetValueInput(node, 1);
|
| Type* receiver_type = NodeProperties::GetType(receiver);
|
| + Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
|
| + Node* effect = NodeProperties::GetEffectInput(node);
|
| + Node* control = NodeProperties::GetControlInput(node);
|
|
|
| // Check if {target} is a known JSFunction.
|
| if (target_type->IsConstant() &&
|
| @@ -1566,28 +1704,27 @@ Reduction JSTypedLowering::ReduceJSCallFunction(Node* node) {
|
| Handle<JSFunction>::cast(target_type->AsConstant()->Value());
|
| Handle<SharedFunctionInfo> shared(function->shared(), isolate());
|
| if (shared->internal_formal_parameter_count() == arity) {
|
| - // Check if we need to wrap the {receiver}.
|
| - if (is_sloppy(shared->language_mode()) && !shared->native()) {
|
| - if (receiver_type->Is(Type::NullOrUndefined())) {
|
| - // Change {receiver} to global proxy of {function}.
|
| - receiver =
|
| - jsgraph()->Constant(handle(function->global_proxy(), isolate()));
|
| - } else if (!receiver_type->Is(Type::Receiver())) {
|
| - // TODO(bmeurer): Add support for wrapping abitrary receivers.
|
| - return NoChange();
|
| - }
|
| - NodeProperties::ReplaceValueInput(node, receiver, 1);
|
| - }
|
| -
|
| // Grab the context from the {function}.
|
| Node* context =
|
| jsgraph()->Constant(handle(function->context(), isolate()));
|
| NodeProperties::ReplaceContextInput(node, context);
|
| - CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
|
| - if (p.AllowTailCalls()) {
|
| - flags |= CallDescriptor::kSupportsTailCalls;
|
| +
|
| + // Check if we need to convert the {receiver}.
|
| + if (is_sloppy(shared->language_mode()) && !shared->native() &&
|
| + !receiver_type->Is(Type::Receiver())) {
|
| + receiver = effect =
|
| + graph()->NewNode(javascript()->ConvertReceiver(convert_mode),
|
| + receiver, context, frame_state, effect, control);
|
| + NodeProperties::ReplaceEffectInput(node, effect);
|
| + NodeProperties::ReplaceValueInput(node, receiver, 1);
|
| }
|
| +
|
| + // Remove the eager bailout frame state.
|
| NodeProperties::RemoveFrameStateInput(node, 1);
|
| +
|
| + // Patch {node} to a direct call.
|
| + CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
|
| + if (p.AllowTailCalls()) flags |= CallDescriptor::kSupportsTailCalls;
|
| NodeProperties::ChangeOp(node,
|
| common()->Call(Linkage::GetJSCallDescriptor(
|
| graph()->zone(), false, 1 + arity, flags)));
|
| @@ -1943,6 +2080,8 @@ Reduction JSTypedLowering::Reduce(Node* node) {
|
| return ReduceJSToNumber(node);
|
| case IrOpcode::kJSToString:
|
| return ReduceJSToString(node);
|
| + case IrOpcode::kJSToObject:
|
| + return ReduceJSToObject(node);
|
| case IrOpcode::kJSLoadNamed:
|
| return ReduceJSLoadNamed(node);
|
| case IrOpcode::kJSLoadProperty:
|
|
|