Commit e3a46bc7 authored by bmeurer's avatar bmeurer Committed by Commit bot

[compiler] Decouple ToObject from CreateWithContext.

Decouple the implicit ToObject for with statements from the actual
creation of the with context. This way we can handle/optimize those
constructs separately.

R=mstarzinger@chromium.org

Review URL: https://codereview.chromium.org/1481753003

Cr-Commit-Position: refs/heads/master@{#32341}
parent 3c2bec8d
......@@ -1007,8 +1007,9 @@ class WithStatement final : public Statement {
void set_statement(Statement* s) { statement_ = s; }
void set_base_id(int id) { base_id_ = id; }
static int num_ids() { return parent_num_ids() + 1; }
BailoutId EntryId() const { return BailoutId(local_id(0)); }
static int num_ids() { return parent_num_ids() + 2; }
BailoutId ToObjectId() const { return BailoutId(local_id(0)); }
BailoutId EntryId() const { return BailoutId(local_id(1)); }
protected:
WithStatement(Zone* zone, Scope* scope, Expression* expression,
......
......@@ -1199,8 +1199,9 @@ void AstGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
void AstGraphBuilder::VisitWithStatement(WithStatement* stmt) {
VisitForValue(stmt->expression());
Node* value = environment()->Pop();
Node* object = BuildToObject(value, stmt->ToObjectId());
const Operator* op = javascript()->CreateWithContext();
Node* context = NewNode(op, value, GetFunctionClosureForContext());
Node* context = NewNode(op, object, GetFunctionClosureForContext());
PrepareFrameState(context, stmt->EntryId());
VisitInScope(stmt->statement(), stmt->scope(), context);
}
......
......@@ -1885,33 +1885,25 @@ Reduction JSTypedLowering::ReduceJSCreateFunctionContext(Node* node) {
Reduction JSTypedLowering::ReduceJSCreateWithContext(Node* node) {
DCHECK_EQ(IrOpcode::kJSCreateWithContext, node->opcode());
Node* const input = NodeProperties::GetValueInput(node, 0);
Node* const closure = NodeProperties::GetValueInput(node, 1);
Type* const input_type = NodeProperties::GetType(input);
// Use inline allocation for with contexts for regular objects.
if (input_type->Is(Type::Receiver())) {
// JSCreateWithContext(o:receiver, fun)
Node* const effect = NodeProperties::GetEffectInput(node);
Node* const control = NodeProperties::GetControlInput(node);
Node* const context = NodeProperties::GetContextInput(node);
Node* const load = graph()->NewNode(
simplified()->LoadField(
AccessBuilder::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)),
context, effect, control);
AllocationBuilder a(jsgraph(), effect, control);
STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
a.AllocateArray(Context::MIN_CONTEXT_SLOTS, factory()->with_context_map());
a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), input);
a.Store(AccessBuilder::ForContextSlot(Context::GLOBAL_OBJECT_INDEX), load);
RelaxControls(node);
a.FinishAndChange(node);
return Changed(node);
}
return NoChange();
Node* object = NodeProperties::GetValueInput(node, 0);
Node* closure = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* context = NodeProperties::GetContextInput(node);
Node* global = effect = graph()->NewNode(
simplified()->LoadField(
AccessBuilder::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)),
context, effect, control);
AllocationBuilder a(jsgraph(), effect, control);
STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
a.AllocateArray(Context::MIN_CONTEXT_SLOTS, factory()->with_context_map());
a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), object);
a.Store(AccessBuilder::ForContextSlot(Context::GLOBAL_OBJECT_INDEX), global);
RelaxControls(node);
a.FinishAndChange(node);
return Changed(node);
}
......
......@@ -952,7 +952,12 @@ void FullCodeGenerator::VisitWithStatement(WithStatement* stmt) {
Comment cmnt(masm_, "[ WithStatement");
SetStatementPosition(stmt);
VisitForStackValue(stmt->expression());
VisitForAccumulatorValue(stmt->expression());
Callable callable = CodeFactory::ToObject(isolate());
__ Move(callable.descriptor().GetRegisterParameter(0), result_register());
__ Call(callable.code(), RelocInfo::CODE_TARGET);
PrepareForBailoutForId(stmt->ToObjectId(), NO_REGISTERS);
__ Push(result_register());
PushFunctionArgumentForContextAllocation();
__ CallRuntime(Runtime::kPushWithContext, 2);
StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
......
......@@ -706,13 +706,8 @@ RUNTIME_FUNCTION(Runtime_NewFunctionContext) {
RUNTIME_FUNCTION(Runtime_PushWithContext) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, extension_object, 0);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 1);
Handle<JSReceiver> extension_object;
if (!Object::ToObject(isolate, value).ToHandle(&extension_object)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kUndefinedOrNullToObject));
}
Handle<Context> current(isolate->context());
Handle<Context> context =
isolate->factory()->NewWithContext(function, current, extension_object);
......
......@@ -1186,7 +1186,7 @@ TEST_F(JSTypedLoweringTest, JSCreateFunctionContextViaStub) {
TEST_F(JSTypedLoweringTest, JSCreateWithContext) {
Node* const object = Parameter(Type::Receiver());
Node* const closure = Parameter(Type::Any());
Node* const closure = Parameter(Type::Function());
Node* const context = Parameter(Type::Any());
Node* const frame_state = EmptyFrameState();
Node* const effect = graph()->start();
......@@ -1195,11 +1195,16 @@ TEST_F(JSTypedLoweringTest, JSCreateWithContext) {
Reduce(graph()->NewNode(javascript()->CreateWithContext(), object,
closure, context, frame_state, effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor(
Context::MIN_CONTEXT_SLOTS)),
IsBeginRegion(effect), control),
_));
EXPECT_THAT(
r.replacement(),
IsFinishRegion(
IsAllocate(
IsNumberConstant(Context::SizeFor(Context::MIN_CONTEXT_SLOTS)),
IsBeginRegion(IsLoadField(
AccessBuilder::ForContextSlot(Context::GLOBAL_OBJECT_INDEX),
context, effect, control)),
control),
_));
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment