[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}
This commit is contained in:
bmeurer 2015-11-26 06:29:36 -08:00 committed by Commit bot
parent 3c2bec8d70
commit e3a46bc766
6 changed files with 42 additions and 43 deletions

View File

@ -1007,8 +1007,9 @@ class WithStatement final : public Statement {
void set_statement(Statement* s) { statement_ = s; } void set_statement(Statement* s) { statement_ = s; }
void set_base_id(int id) { base_id_ = id; } void set_base_id(int id) { base_id_ = id; }
static int num_ids() { return parent_num_ids() + 1; } static int num_ids() { return parent_num_ids() + 2; }
BailoutId EntryId() const { return BailoutId(local_id(0)); } BailoutId ToObjectId() const { return BailoutId(local_id(0)); }
BailoutId EntryId() const { return BailoutId(local_id(1)); }
protected: protected:
WithStatement(Zone* zone, Scope* scope, Expression* expression, WithStatement(Zone* zone, Scope* scope, Expression* expression,

View File

@ -1199,8 +1199,9 @@ void AstGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
void AstGraphBuilder::VisitWithStatement(WithStatement* stmt) { void AstGraphBuilder::VisitWithStatement(WithStatement* stmt) {
VisitForValue(stmt->expression()); VisitForValue(stmt->expression());
Node* value = environment()->Pop(); Node* value = environment()->Pop();
Node* object = BuildToObject(value, stmt->ToObjectId());
const Operator* op = javascript()->CreateWithContext(); const Operator* op = javascript()->CreateWithContext();
Node* context = NewNode(op, value, GetFunctionClosureForContext()); Node* context = NewNode(op, object, GetFunctionClosureForContext());
PrepareFrameState(context, stmt->EntryId()); PrepareFrameState(context, stmt->EntryId());
VisitInScope(stmt->statement(), stmt->scope(), context); VisitInScope(stmt->statement(), stmt->scope(), context);
} }

View File

@ -1885,33 +1885,25 @@ Reduction JSTypedLowering::ReduceJSCreateFunctionContext(Node* node) {
Reduction JSTypedLowering::ReduceJSCreateWithContext(Node* node) { Reduction JSTypedLowering::ReduceJSCreateWithContext(Node* node) {
DCHECK_EQ(IrOpcode::kJSCreateWithContext, node->opcode()); DCHECK_EQ(IrOpcode::kJSCreateWithContext, node->opcode());
Node* const input = NodeProperties::GetValueInput(node, 0); Node* object = NodeProperties::GetValueInput(node, 0);
Node* const closure = NodeProperties::GetValueInput(node, 1); Node* closure = NodeProperties::GetValueInput(node, 1);
Type* const input_type = NodeProperties::GetType(input); Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
// Use inline allocation for with contexts for regular objects. Node* context = NodeProperties::GetContextInput(node);
if (input_type->Is(Type::Receiver())) { Node* global = effect = graph()->NewNode(
// JSCreateWithContext(o:receiver, fun) simplified()->LoadField(
Node* const effect = NodeProperties::GetEffectInput(node); AccessBuilder::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)),
Node* const control = NodeProperties::GetControlInput(node); context, effect, control);
Node* const context = NodeProperties::GetContextInput(node); AllocationBuilder a(jsgraph(), effect, control);
Node* const load = graph()->NewNode( STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
simplified()->LoadField( a.AllocateArray(Context::MIN_CONTEXT_SLOTS, factory()->with_context_map());
AccessBuilder::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)), a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
context, effect, control); a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
AllocationBuilder a(jsgraph(), effect, control); a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), object);
STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered. a.Store(AccessBuilder::ForContextSlot(Context::GLOBAL_OBJECT_INDEX), global);
a.AllocateArray(Context::MIN_CONTEXT_SLOTS, factory()->with_context_map()); RelaxControls(node);
a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure); a.FinishAndChange(node);
a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context); return Changed(node);
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();
} }

View File

@ -952,7 +952,12 @@ void FullCodeGenerator::VisitWithStatement(WithStatement* stmt) {
Comment cmnt(masm_, "[ WithStatement"); Comment cmnt(masm_, "[ WithStatement");
SetStatementPosition(stmt); 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(); PushFunctionArgumentForContextAllocation();
__ CallRuntime(Runtime::kPushWithContext, 2); __ CallRuntime(Runtime::kPushWithContext, 2);
StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());

View File

@ -706,13 +706,8 @@ RUNTIME_FUNCTION(Runtime_NewFunctionContext) {
RUNTIME_FUNCTION(Runtime_PushWithContext) { RUNTIME_FUNCTION(Runtime_PushWithContext) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK_EQ(2, args.length()); 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); 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> current(isolate->context());
Handle<Context> context = Handle<Context> context =
isolate->factory()->NewWithContext(function, current, extension_object); isolate->factory()->NewWithContext(function, current, extension_object);

View File

@ -1186,7 +1186,7 @@ TEST_F(JSTypedLoweringTest, JSCreateFunctionContextViaStub) {
TEST_F(JSTypedLoweringTest, JSCreateWithContext) { TEST_F(JSTypedLoweringTest, JSCreateWithContext) {
Node* const object = Parameter(Type::Receiver()); 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 context = Parameter(Type::Any());
Node* const frame_state = EmptyFrameState(); Node* const frame_state = EmptyFrameState();
Node* const effect = graph()->start(); Node* const effect = graph()->start();
@ -1195,11 +1195,16 @@ TEST_F(JSTypedLoweringTest, JSCreateWithContext) {
Reduce(graph()->NewNode(javascript()->CreateWithContext(), object, Reduce(graph()->NewNode(javascript()->CreateWithContext(), object,
closure, context, frame_state, effect, control)); closure, context, frame_state, effect, control));
ASSERT_TRUE(r.Changed()); ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), EXPECT_THAT(
IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor( r.replacement(),
Context::MIN_CONTEXT_SLOTS)), IsFinishRegion(
IsBeginRegion(effect), control), IsAllocate(
_)); IsNumberConstant(Context::SizeFor(Context::MIN_CONTEXT_SLOTS)),
IsBeginRegion(IsLoadField(
AccessBuilder::ForContextSlot(Context::GLOBAL_OBJECT_INDEX),
context, effect, control)),
control),
_));
} }