Revision: 21684
Author: [email protected]
Date: Thu Jun 5 07:33:01 2014 UTC
Log: Preliminary support for block contexts in hydrogen.
Patch from Steven Keuchel <[email protected]>
BUG=v8:2198
LOG=N
TEST=mjsunit/harmony/block-let-crankshaft.js
[email protected]
Review URL: https://codereview.chromium.org/307593002
http://code.google.com/p/v8/source/detail?r=21684
Modified:
/branches/bleeding_edge/src/arm/lithium-arm.cc
/branches/bleeding_edge/src/arm/lithium-arm.h
/branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
/branches/bleeding_edge/src/arm64/lithium-arm64.cc
/branches/bleeding_edge/src/arm64/lithium-arm64.h
/branches/bleeding_edge/src/arm64/lithium-codegen-arm64.cc
/branches/bleeding_edge/src/ast.h
/branches/bleeding_edge/src/full-codegen.cc
/branches/bleeding_edge/src/hydrogen-instructions.cc
/branches/bleeding_edge/src/hydrogen-instructions.h
/branches/bleeding_edge/src/hydrogen.cc
/branches/bleeding_edge/src/hydrogen.h
/branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
/branches/bleeding_edge/src/ia32/lithium-ia32.cc
/branches/bleeding_edge/src/ia32/lithium-ia32.h
/branches/bleeding_edge/src/parser.cc
/branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
/branches/bleeding_edge/src/x64/lithium-x64.cc
/branches/bleeding_edge/src/x64/lithium-x64.h
/branches/bleeding_edge/test/mjsunit/harmony/block-let-crankshaft.js
/branches/bleeding_edge/test/mjsunit/harmony/block-scoping.js
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.cc Tue Jun 3 08:12:43 2014
UTC
+++ /branches/bleeding_edge/src/arm/lithium-arm.cc Thu Jun 5 07:33:01 2014
UTC
@@ -2578,5 +2578,21 @@
LInstruction* result = DefineSameAsFirst(load);
return AssignPointerMap(result);
}
+
+
+LInstruction* LChunkBuilder::DoStoreFrameContext(HStoreFrameContext*
instr) {
+ LOperand* context = UseRegisterAtStart(instr->context());
+ return new(zone()) LStoreFrameContext(context);
+}
+
+
+LInstruction* LChunkBuilder::DoAllocateBlockContext(
+ HAllocateBlockContext* instr) {
+ LOperand* context = UseFixed(instr->context(), cp);
+ LOperand* function = UseRegisterAtStart(instr->function());
+ LAllocateBlockContext* result =
+ new(zone()) LAllocateBlockContext(context, function);
+ return MarkAsCall(DefineFixed(result, cp), instr);
+}
} } // namespace v8::internal
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.h Tue Jun 3 15:45:38 2014
UTC
+++ /branches/bleeding_edge/src/arm/lithium-arm.h Thu Jun 5 07:33:01 2014
UTC
@@ -21,6 +21,7 @@
V(AccessArgumentsAt) \
V(AddI) \
V(Allocate) \
+ V(AllocateBlockContext) \
V(ApplyArguments) \
V(ArgumentsElements) \
V(ArgumentsLength) \
@@ -139,6 +140,7 @@
V(StackCheck) \
V(StoreCodeEntry) \
V(StoreContextSlot) \
+ V(StoreFrameContext) \
V(StoreGlobalCell) \
V(StoreKeyed) \
V(StoreKeyedGeneric) \
@@ -2669,6 +2671,35 @@
};
+class LStoreFrameContext: public LTemplateInstruction<0, 1, 0> {
+ public:
+ explicit LStoreFrameContext(LOperand* context) {
+ inputs_[0] = context;
+ }
+
+ LOperand* context() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(StoreFrameContext, "store-frame-context")
+};
+
+
+class LAllocateBlockContext: public LTemplateInstruction<1, 2, 0> {
+ public:
+ LAllocateBlockContext(LOperand* context, LOperand* function) {
+ inputs_[0] = context;
+ inputs_[1] = function;
+ }
+
+ LOperand* context() { return inputs_[0]; }
+ LOperand* function() { return inputs_[1]; }
+
+ Handle<ScopeInfo> scope_info() { return hydrogen()->scope_info(); }
+
+
DECLARE_CONCRETE_INSTRUCTION(AllocateBlockContext, "allocate-block-context")
+ DECLARE_HYDROGEN_ACCESSOR(AllocateBlockContext)
+};
+
+
class LChunkBuilder;
class LPlatformChunk V8_FINAL : public LChunk {
public:
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Wed Jun 4
14:57:51 2014 UTC
+++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Thu Jun 5
07:33:01 2014 UTC
@@ -5816,6 +5816,21 @@
__ bind(deferred->exit());
__ bind(&done);
}
+
+
+void LCodeGen::DoStoreFrameContext(LStoreFrameContext* instr) {
+ Register context = ToRegister(instr->context());
+ __ str(context, MemOperand(fp, StandardFrameConstants::kContextOffset));
+}
+
+
+void LCodeGen::DoAllocateBlockContext(LAllocateBlockContext* instr) {
+ Handle<ScopeInfo> scope_info = instr->scope_info();
+ __ Push(scope_info);
+ __ push(ToRegister(instr->function()));
+ CallRuntime(Runtime::kHiddenPushBlockContext, 2, instr);
+ RecordSafepoint(Safepoint::kNoLazyDeopt);
+}
#undef __
=======================================
--- /branches/bleeding_edge/src/arm64/lithium-arm64.cc Tue Jun 3 08:12:43
2014 UTC
+++ /branches/bleeding_edge/src/arm64/lithium-arm64.cc Thu Jun 5 07:33:01
2014 UTC
@@ -2704,6 +2704,22 @@
LWrapReceiver* result = new(zone()) LWrapReceiver(receiver, function);
return AssignEnvironment(DefineAsRegister(result));
}
+
+
+LInstruction* LChunkBuilder::DoStoreFrameContext(HStoreFrameContext*
instr) {
+ LOperand* context = UseRegisterAtStart(instr->context());
+ return new(zone()) LStoreFrameContext(context);
+}
+
+
+LInstruction* LChunkBuilder::DoAllocateBlockContext(
+ HAllocateBlockContext* instr) {
+ LOperand* context = UseFixed(instr->context(), cp);
+ LOperand* function = UseRegisterAtStart(instr->function());
+ LAllocateBlockContext* result =
+ new(zone()) LAllocateBlockContext(context, function);
+ return MarkAsCall(DefineFixed(result, cp), instr);
+}
} } // namespace v8::internal
=======================================
--- /branches/bleeding_edge/src/arm64/lithium-arm64.h Tue Jun 3 15:45:38
2014 UTC
+++ /branches/bleeding_edge/src/arm64/lithium-arm64.h Thu Jun 5 07:33:01
2014 UTC
@@ -23,6 +23,7 @@
V(AddI) \
V(AddS) \
V(Allocate) \
+ V(AllocateBlockContext) \
V(ApplyArguments) \
V(ArgumentsElements) \
V(ArgumentsLength) \
@@ -148,6 +149,7 @@
V(StackCheck) \
V(StoreCodeEntry) \
V(StoreContextSlot) \
+ V(StoreFrameContext) \
V(StoreGlobalCell) \
V(StoreKeyedExternal) \
V(StoreKeyedFixed) \
@@ -2997,6 +2999,35 @@
};
+class LStoreFrameContext: public LTemplateInstruction<0, 1, 0> {
+ public:
+ explicit LStoreFrameContext(LOperand* context) {
+ inputs_[0] = context;
+ }
+
+ LOperand* context() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(StoreFrameContext, "store-frame-context")
+};
+
+
+class LAllocateBlockContext: public LTemplateInstruction<1, 2, 0> {
+ public:
+ LAllocateBlockContext(LOperand* context, LOperand* function) {
+ inputs_[0] = context;
+ inputs_[1] = function;
+ }
+
+ LOperand* context() { return inputs_[0]; }
+ LOperand* function() { return inputs_[1]; }
+
+ Handle<ScopeInfo> scope_info() { return hydrogen()->scope_info(); }
+
+
DECLARE_CONCRETE_INSTRUCTION(AllocateBlockContext, "allocate-block-context")
+ DECLARE_HYDROGEN_ACCESSOR(AllocateBlockContext)
+};
+
+
class LWrapReceiver V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
LWrapReceiver(LOperand* receiver, LOperand* function) {
=======================================
--- /branches/bleeding_edge/src/arm64/lithium-codegen-arm64.cc Wed Jun 4
14:57:51 2014 UTC
+++ /branches/bleeding_edge/src/arm64/lithium-codegen-arm64.cc Thu Jun 5
07:33:01 2014 UTC
@@ -6038,5 +6038,22 @@
__ Bind(deferred->exit());
__ Bind(&done);
}
+
+
+void LCodeGen::DoStoreFrameContext(LStoreFrameContext* instr) {
+ Register context = ToRegister(instr->context());
+ __ Str(context, MemOperand(fp, StandardFrameConstants::kContextOffset));
+}
+
+
+void LCodeGen::DoAllocateBlockContext(LAllocateBlockContext* instr) {
+ Handle<ScopeInfo> scope_info = instr->scope_info();
+ __ Push(scope_info);
+ __ Push(ToRegister(instr->function()));
+ CallRuntime(Runtime::kHiddenPushBlockContext, 2, instr);
+ RecordSafepoint(Safepoint::kNoLazyDeopt);
+}
+
+
} } // namespace v8::internal
=======================================
--- /branches/bleeding_edge/src/ast.h Tue Jun 3 08:12:43 2014 UTC
+++ /branches/bleeding_edge/src/ast.h Thu Jun 5 07:33:01 2014 UTC
@@ -440,6 +440,8 @@
ZoneList<Statement*>* statements() { return &statements_; }
bool is_initializer_block() const { return is_initializer_block_; }
+
+ BailoutId DeclsId() const { return decls_id_; }
virtual bool IsJump() const V8_OVERRIDE {
return !statements_.is_empty() && statements_.last()->IsJump()
@@ -458,12 +460,14 @@
: BreakableStatement(zone, labels, TARGET_FOR_NAMED_ONLY, pos),
statements_(capacity, zone),
is_initializer_block_(is_initializer_block),
+ decls_id_(GetNextId(zone)),
scope_(NULL) {
}
private:
ZoneList<Statement*> statements_;
bool is_initializer_block_;
+ const BailoutId decls_id_;
Scope* scope_;
};
=======================================
--- /branches/bleeding_edge/src/full-codegen.cc Tue Jun 3 08:12:43 2014 UTC
+++ /branches/bleeding_edge/src/full-codegen.cc Thu Jun 5 07:33:01 2014 UTC
@@ -1052,7 +1052,9 @@
Scope* saved_scope = scope();
// Push a block context when entering a block with block scoped
variables.
- if (stmt->scope() != NULL) {
+ if (stmt->scope() == NULL) {
+ PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
+ } else {
scope_ = stmt->scope();
ASSERT(!scope_->is_module_scope());
{ Comment cmnt(masm_, "[ Extend block context");
@@ -1063,17 +1065,17 @@
// Replace the context stored in the frame.
StoreToFrameField(StandardFrameConstants::kContextOffset,
context_register());
+ PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
}
{ Comment cmnt(masm_, "[ Declarations");
VisitDeclarations(scope_->declarations());
+ PrepareForBailoutForId(stmt->DeclsId(), NO_REGISTERS);
}
}
- PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
VisitStatements(stmt->statements());
scope_ = saved_scope;
__ bind(nested_block.break_label());
- PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
// Pop block context if necessary.
if (stmt->scope() != NULL) {
@@ -1082,6 +1084,7 @@
StoreToFrameField(StandardFrameConstants::kContextOffset,
context_register());
}
+ PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
}
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.cc Wed Jun 4
15:21:35 2014 UTC
+++ /branches/bleeding_edge/src/hydrogen-instructions.cc Thu Jun 5
07:33:01 2014 UTC
@@ -846,6 +846,7 @@
case HValue::kReturn:
case HValue::kSeqStringGetChar:
case HValue::kStoreCodeEntry:
+ case HValue::kStoreFrameContext:
case HValue::kStoreKeyed:
case HValue::kStoreNamedField:
case HValue::kStoreNamedGeneric:
@@ -858,6 +859,7 @@
return false;
case HValue::kAdd:
+ case HValue::kAllocateBlockContext:
case HValue::kApplyArguments:
case HValue::kBitwise:
case HValue::kBoundsCheck:
@@ -1134,6 +1136,13 @@
stream->Add("], length ");
length()->PrintNameTo(stream);
}
+
+
+void HAllocateBlockContext::PrintDataTo(StringStream* stream) {
+ context()->PrintNameTo(stream);
+ stream->Add(" ");
+ function()->PrintNameTo(stream);
+}
void HControlInstruction::PrintDataTo(StringStream* stream) {
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Wed Jun 4 15:21:35
2014 UTC
+++ /branches/bleeding_edge/src/hydrogen-instructions.h Thu Jun 5 07:33:01
2014 UTC
@@ -46,6 +46,7 @@
V(AbnormalExit) \
V(AccessArgumentsAt) \
V(Add) \
+ V(AllocateBlockContext) \
V(Allocate) \
V(ApplyArguments) \
V(ArgumentsElements) \
@@ -140,6 +141,7 @@
V(StackCheck) \
V(StoreCodeEntry) \
V(StoreContextSlot) \
+ V(StoreFrameContext) \
V(StoreGlobalCell) \
V(StoreKeyed) \
V(StoreKeyedGeneric) \
@@ -5798,20 +5800,8 @@
kCheckReturnUndefined
};
- HLoadContextSlot(HValue* context, Variable* var)
- : HUnaryOperation(context), slot_index_(var->index()) {
- ASSERT(var->IsContextSlot());
- switch (var->mode()) {
- case LET:
- case CONST:
- mode_ = kCheckDeoptimize;
- break;
- case CONST_LEGACY:
- mode_ = kCheckReturnUndefined;
- break;
- default:
- mode_ = kNoCheck;
- }
+ HLoadContextSlot(HValue* context, int slot_index, Mode mode)
+ : HUnaryOperation(context), slot_index_(slot_index), mode_(mode) {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetDependsOnFlag(kContextSlots);
@@ -7717,6 +7707,57 @@
};
+class HStoreFrameContext: public HUnaryOperation {
+ public:
+ DECLARE_INSTRUCTION_FACTORY_P1(HStoreFrameContext, HValue*);
+
+ HValue* context() { return OperandAt(0); }
+
+ virtual Representation RequiredInputRepresentation(int index) {
+ return Representation::Tagged();
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(StoreFrameContext)
+ private:
+ explicit HStoreFrameContext(HValue* context)
+ : HUnaryOperation(context) {
+ set_representation(Representation::Tagged());
+ SetChangesFlag(kContextSlots);
+ }
+};
+
+
+class HAllocateBlockContext: public HTemplateInstruction<2> {
+ public:
+ DECLARE_INSTRUCTION_FACTORY_P3(HAllocateBlockContext, HValue*,
+ HValue*, Handle<ScopeInfo>);
+ HValue* context() { return OperandAt(0); }
+ HValue* function() { return OperandAt(1); }
+ Handle<ScopeInfo> scope_info() { return scope_info_; }
+
+ virtual Representation RequiredInputRepresentation(int index) {
+ return Representation::Tagged();
+ }
+
+ virtual void PrintDataTo(StringStream* stream);
+
+ DECLARE_CONCRETE_INSTRUCTION(AllocateBlockContext)
+
+ private:
+ HAllocateBlockContext(HValue* context,
+ HValue* function,
+ Handle<ScopeInfo> scope_info)
+ : scope_info_(scope_info) {
+ SetOperandAt(0, context);
+ SetOperandAt(1, function);
+ set_representation(Representation::Tagged());
+ }
+
+ Handle<ScopeInfo> scope_info_;
+};
+
+
+
#undef DECLARE_INSTRUCTION
#undef DECLARE_CONCRETE_INSTRUCTION
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc Wed Jun 4 09:35:41 2014 UTC
+++ /branches/bleeding_edge/src/hydrogen.cc Thu Jun 5 07:33:01 2014 UTC
@@ -4247,13 +4247,52 @@
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
- if (stmt->scope() != NULL) {
- return Bailout(kScopedBlock);
- }
- BreakAndContinueInfo break_info(stmt);
+
+ Scope* outer_scope = scope();
+ Scope* scope = stmt->scope();
+ BreakAndContinueInfo break_info(stmt, outer_scope);
+
{ BreakAndContinueScope push(&break_info, this);
+ if (scope != NULL) {
+ // Load the function object.
+ Scope* declaration_scope = scope->DeclarationScope();
+ HInstruction* function;
+ HValue* outer_context = environment()->context();
+ if (declaration_scope->is_global_scope() ||
+ declaration_scope->is_eval_scope()) {
+ function = new(zone()) HLoadContextSlot(
+ outer_context, Context::CLOSURE_INDEX,
HLoadContextSlot::kNoCheck);
+ } else {
+ function = New<HThisFunction>();
+ }
+ AddInstruction(function);
+ // Allocate a block context and store it to the stack frame.
+ HInstruction* inner_context = Add<HAllocateBlockContext>(
+ outer_context, function, scope->GetScopeInfo());
+ HInstruction* instr = Add<HStoreFrameContext>(inner_context);
+ if (instr->HasObservableSideEffects()) {
+ AddSimulate(stmt->EntryId(), REMOVABLE_SIMULATE);
+ }
+ set_scope(scope);
+ environment()->BindContext(inner_context);
+ VisitDeclarations(scope->declarations());
+ AddSimulate(stmt->DeclsId(), REMOVABLE_SIMULATE);
+ }
CHECK_BAILOUT(VisitStatements(stmt->statements()));
}
+ set_scope(outer_scope);
+ if (scope != NULL && current_block() != NULL) {
+ HValue* inner_context = environment()->context();
+ HValue* outer_context = Add<HLoadNamedField>(
+ inner_context, static_cast<HValue*>(NULL),
+ HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
+
+ HInstruction* instr = Add<HStoreFrameContext>(outer_context);
+ if (instr->HasObservableSideEffects()) {
+ AddSimulate(stmt->ExitId(), REMOVABLE_SIMULATE);
+ }
+ environment()->BindContext(outer_context);
+ }
HBasicBlock* break_block = break_info.break_block();
if (break_block != NULL) {
if (current_block() != NULL) Goto(break_block);
@@ -4321,6 +4360,7 @@
HBasicBlock* HOptimizedGraphBuilder::BreakAndContinueScope::Get(
BreakableStatement* stmt,
BreakType type,
+ Scope** scope,
int* drop_extra) {
*drop_extra = 0;
BreakAndContinueScope* current = this;
@@ -4329,6 +4369,7 @@
current = current->next();
}
ASSERT(current != NULL); // Always found (unless stack is malformed).
+ *scope = current->info()->scope();
if (type == BREAK) {
*drop_extra += current->info()->drop_extra();
@@ -4362,10 +4403,29 @@
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
+ Scope* outer_scope = NULL;
+ Scope* inner_scope = scope();
int drop_extra = 0;
HBasicBlock* continue_block = break_scope()->Get(
- stmt->target(), BreakAndContinueScope::CONTINUE, &drop_extra);
+ stmt->target(), BreakAndContinueScope::CONTINUE,
+ &outer_scope, &drop_extra);
+ HValue* context = environment()->context();
Drop(drop_extra);
+ int context_pop_count = inner_scope->ContextChainLength(outer_scope);
+ if (context_pop_count > 0) {
+ while (context_pop_count-- > 0) {
+ HInstruction* context_instruction = Add<HLoadNamedField>(
+ context, static_cast<HValue*>(NULL),
+ HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
+ context = context_instruction;
+ }
+ HInstruction* instr = Add<HStoreFrameContext>(context);
+ if (instr->HasObservableSideEffects()) {
+ AddSimulate(stmt->target()->EntryId(), REMOVABLE_SIMULATE);
+ }
+ environment()->BindContext(context);
+ }
+
Goto(continue_block);
set_current_block(NULL);
}
@@ -4375,10 +4435,28 @@
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
+ Scope* outer_scope = NULL;
+ Scope* inner_scope = scope();
int drop_extra = 0;
HBasicBlock* break_block = break_scope()->Get(
- stmt->target(), BreakAndContinueScope::BREAK, &drop_extra);
+ stmt->target(), BreakAndContinueScope::BREAK,
+ &outer_scope, &drop_extra);
+ HValue* context = environment()->context();
Drop(drop_extra);
+ int context_pop_count = inner_scope->ContextChainLength(outer_scope);
+ if (context_pop_count > 0) {
+ while (context_pop_count-- > 0) {
+ HInstruction* context_instruction = Add<HLoadNamedField>(
+ context, static_cast<HValue*>(NULL),
+ HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
+ context = context_instruction;
+ }
+ HInstruction* instr = Add<HStoreFrameContext>(context);
+ if (instr->HasObservableSideEffects()) {
+ AddSimulate(stmt->target()->ExitId(), REMOVABLE_SIMULATE);
+ }
+ environment()->BindContext(context);
+ }
Goto(break_block);
set_current_block(NULL);
}
@@ -4533,7 +4611,7 @@
// translating the clause bodies.
HBasicBlock* fall_through_block = NULL;
- BreakAndContinueInfo break_info(stmt);
+ BreakAndContinueInfo break_info(stmt, scope());
{ BreakAndContinueScope push(&break_info, this);
for (int i = 0; i < clause_count; ++i) {
CaseClause* clause = clauses->at(i);
@@ -4580,9 +4658,7 @@
void HOptimizedGraphBuilder::VisitLoopBody(IterationStatement* stmt,
- HBasicBlock* loop_entry,
- BreakAndContinueInfo*
break_info) {
- BreakAndContinueScope push(break_info, this);
+ HBasicBlock* loop_entry) {
Add<HSimulate>(stmt->StackCheckId());
HStackCheck* stack_check =
HStackCheck::cast(Add<HStackCheck>(HStackCheck::kBackwardsBranch));
@@ -4599,8 +4675,11 @@
ASSERT(current_block() != NULL);
HBasicBlock* loop_entry = BuildLoopEntry(stmt);
- BreakAndContinueInfo break_info(stmt);
- CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
+ BreakAndContinueInfo break_info(stmt, scope());
+ {
+ BreakAndContinueScope push(&break_info, this);
+ CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry));
+ }
HBasicBlock* body_exit =
JoinContinue(stmt, current_block(), break_info.continue_block());
HBasicBlock* loop_successor = NULL;
@@ -4661,9 +4740,10 @@
}
}
- BreakAndContinueInfo break_info(stmt);
+ BreakAndContinueInfo break_info(stmt, scope());
if (current_block() != NULL) {
- CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
+ BreakAndContinueScope push(&break_info, this);
+ CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry));
}
HBasicBlock* body_exit =
JoinContinue(stmt, current_block(), break_info.continue_block());
@@ -4702,9 +4782,10 @@
}
}
- BreakAndContinueInfo break_info(stmt);
+ BreakAndContinueInfo break_info(stmt, scope());
if (current_block() != NULL) {
- CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
+ BreakAndContinueScope push(&break_info, this);
+ CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry));
}
HBasicBlock* body_exit =
JoinContinue(stmt, current_block(), break_info.continue_block());
@@ -4803,8 +4884,11 @@
Bind(each_var, key);
- BreakAndContinueInfo break_info(stmt, 5);
- CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
+ BreakAndContinueInfo break_info(stmt, scope(), 5);
+ {
+ BreakAndContinueScope push(&break_info, this);
+ CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry));
+ }
HBasicBlock* body_exit =
JoinContinue(stmt, current_block(), break_info.continue_block());
@@ -4949,7 +5033,7 @@
HValue* HOptimizedGraphBuilder::BuildContextChainWalk(Variable* var) {
ASSERT(var->IsContextSlot());
HValue* context = environment()->context();
- int length = current_info()->scope()->ContextChainLength(var->scope());
+ int length = scope()->ContextChainLength(var->scope());
while (length-- > 0) {
context = Add<HLoadNamedField>(
context, static_cast<HValue*>(NULL),
@@ -5033,7 +5117,21 @@
case Variable::CONTEXT: {
HValue* context = BuildContextChainWalk(variable);
- HLoadContextSlot* instr = new(zone()) HLoadContextSlot(context,
variable);
+ HLoadContextSlot::Mode mode;
+ switch (variable->mode()) {
+ case LET:
+ case CONST:
+ mode = HLoadContextSlot::kCheckDeoptimize;
+ break;
+ case CONST_LEGACY:
+ mode = HLoadContextSlot::kCheckReturnUndefined;
+ break;
+ default:
+ mode = HLoadContextSlot::kNoCheck;
+ break;
+ }
+ HLoadContextSlot* instr =
+ new(zone()) HLoadContextSlot(context, variable->index(), mode);
return ast_context()->ReturnInstruction(instr, expr->id());
}
@@ -7462,7 +7560,8 @@
Add<HSimulate>(BailoutId::None());
current_block()->UpdateEnvironment(inner_env);
-
+ Scope* saved_scope = scope();
+ set_scope(target_info.scope());
HEnterInlined* enter_inlined =
Add<HEnterInlined>(return_id, target, arguments_count, function,
function_state()->inlining_kind(),
@@ -7472,6 +7571,7 @@
VisitDeclarations(target_info.scope()->declarations());
VisitStatements(function->body());
+ set_scope(saved_scope);
if (HasStackOverflow()) {
// Bail out if the inline function did, as we cannot residualize a call
// instead.
@@ -11432,7 +11532,9 @@
push_count_(0),
ast_id_(BailoutId::None()),
zone_(zone) {
- Initialize(scope->num_parameters() + 1, scope->num_stack_slots(), 0);
+ Scope* declaration_scope = scope->DeclarationScope();
+ Initialize(declaration_scope->num_parameters() + 1,
+ declaration_scope->num_stack_slots(), 0);
}
=======================================
--- /branches/bleeding_edge/src/hydrogen.h Wed Jun 4 09:35:41 2014 UTC
+++ /branches/bleeding_edge/src/hydrogen.h Thu Jun 5 07:33:01 2014 UTC
@@ -1042,9 +1042,13 @@
: info_(info),
graph_(NULL),
current_block_(NULL),
+ scope_(info->scope()),
position_(HSourcePosition::Unknown()),
start_position_(0) {}
virtual ~HGraphBuilder() {}
+
+ Scope* scope() const { return scope_; }
+ void set_scope(Scope* scope) { scope_ = scope; }
HBasicBlock* current_block() const { return current_block_; }
void set_current_block(HBasicBlock* block) { current_block_ = block; }
@@ -1870,6 +1874,7 @@
CompilationInfo* info_;
HGraph* graph_;
HBasicBlock* current_block_;
+ Scope* scope_;
HSourcePosition position_;
int start_position_;
};
@@ -1997,10 +2002,12 @@
class BreakAndContinueInfo V8_FINAL BASE_EMBEDDED {
public:
explicit BreakAndContinueInfo(BreakableStatement* target,
+ Scope* scope,
int drop_extra = 0)
: target_(target),
break_block_(NULL),
continue_block_(NULL),
+ scope_(scope),
drop_extra_(drop_extra) {
}
@@ -2009,12 +2016,14 @@
void set_break_block(HBasicBlock* block) { break_block_ = block; }
HBasicBlock* continue_block() { return continue_block_; }
void set_continue_block(HBasicBlock* block) { continue_block_ = block;
}
+ Scope* scope() { return scope_; }
int drop_extra() { return drop_extra_; }
private:
BreakableStatement* target_;
HBasicBlock* break_block_;
HBasicBlock* continue_block_;
+ Scope* scope_;
int drop_extra_;
};
@@ -2036,7 +2045,8 @@
// Search the break stack for a break or continue target.
enum BreakType { BREAK, CONTINUE };
- HBasicBlock* Get(BreakableStatement* stmt, BreakType type, int*
drop_extra);
+ HBasicBlock* Get(BreakableStatement* stmt, BreakType type,
+ Scope** scope, int* drop_extra);
private:
BreakAndContinueInfo* info_;
@@ -2146,8 +2156,7 @@
bool PreProcessOsrEntry(IterationStatement* statement);
void VisitLoopBody(IterationStatement* stmt,
- HBasicBlock* loop_entry,
- BreakAndContinueInfo* break_info);
+ HBasicBlock* loop_entry);
// Create a back edge in the flow graph. body_exit is the predecessor
// block and loop_entry is the successor block. loop_successor is the
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Wed Jun 4
14:57:51 2014 UTC
+++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Thu Jun 5
07:33:01 2014 UTC
@@ -5642,6 +5642,21 @@
__ bind(deferred->exit());
__ bind(&done);
}
+
+
+void LCodeGen::DoStoreFrameContext(LStoreFrameContext* instr) {
+ Register context = ToRegister(instr->context());
+ __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), context);
+}
+
+
+void LCodeGen::DoAllocateBlockContext(LAllocateBlockContext* instr) {
+ Handle<ScopeInfo> scope_info = instr->scope_info();
+ __ Push(scope_info);
+ __ push(ToRegister(instr->function()));
+ CallRuntime(Runtime::kHiddenPushBlockContext, 2, instr);
+ RecordSafepoint(Safepoint::kNoLazyDeopt);
+}
#undef __
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.cc Tue Jun 3 08:12:43
2014 UTC
+++ /branches/bleeding_edge/src/ia32/lithium-ia32.cc Thu Jun 5 07:33:01
2014 UTC
@@ -2652,6 +2652,22 @@
LInstruction* result = DefineSameAsFirst(load);
return AssignPointerMap(result);
}
+
+
+LInstruction* LChunkBuilder::DoStoreFrameContext(HStoreFrameContext*
instr) {
+ LOperand* context = UseRegisterAtStart(instr->context());
+ return new(zone()) LStoreFrameContext(context);
+}
+
+
+LInstruction* LChunkBuilder::DoAllocateBlockContext(
+ HAllocateBlockContext* instr) {
+ LOperand* context = UseFixed(instr->context(), esi);
+ LOperand* function = UseRegisterAtStart(instr->function());
+ LAllocateBlockContext* result =
+ new(zone()) LAllocateBlockContext(context, function);
+ return MarkAsCall(DefineFixed(result, esi), instr);
+}
} } // namespace v8::internal
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.h Tue Jun 3 15:45:38
2014 UTC
+++ /branches/bleeding_edge/src/ia32/lithium-ia32.h Thu Jun 5 07:33:01
2014 UTC
@@ -20,6 +20,7 @@
#define LITHIUM_CONCRETE_INSTRUCTION_LIST(V) \
V(AccessArgumentsAt) \
V(AddI) \
+ V(AllocateBlockContext) \
V(Allocate) \
V(ApplyArguments) \
V(ArgumentsElements) \
@@ -137,6 +138,7 @@
V(StackCheck) \
V(StoreCodeEntry) \
V(StoreContextSlot) \
+ V(StoreFrameContext) \
V(StoreGlobalCell) \
V(StoreKeyed) \
V(StoreKeyedGeneric) \
@@ -2649,6 +2651,35 @@
};
+class LStoreFrameContext: public LTemplateInstruction<0, 1, 0> {
+ public:
+ explicit LStoreFrameContext(LOperand* context) {
+ inputs_[0] = context;
+ }
+
+ LOperand* context() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(StoreFrameContext, "store-frame-context")
+};
+
+
+class LAllocateBlockContext: public LTemplateInstruction<1, 2, 0> {
+ public:
+ LAllocateBlockContext(LOperand* context, LOperand* function) {
+ inputs_[0] = context;
+ inputs_[1] = function;
+ }
+
+ LOperand* context() { return inputs_[0]; }
+ LOperand* function() { return inputs_[1]; }
+
+ Handle<ScopeInfo> scope_info() { return hydrogen()->scope_info(); }
+
+
DECLARE_CONCRETE_INSTRUCTION(AllocateBlockContext, "allocate-block-context")
+ DECLARE_HYDROGEN_ACCESSOR(AllocateBlockContext)
+};
+
+
class LChunkBuilder;
class LPlatformChunk V8_FINAL : public LChunk {
public:
=======================================
--- /branches/bleeding_edge/src/parser.cc Tue Jun 3 16:12:48 2014 UTC
+++ /branches/bleeding_edge/src/parser.cc Thu Jun 5 07:33:01 2014 UTC
@@ -2948,7 +2948,7 @@
Expression* const1 = factory()->NewLiteral(smi1,
RelocInfo::kNoPosition);
VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
compare = factory()->NewCompareOperation(
- Token::EQ, flag_proxy, const1, RelocInfo::kNoPosition);
+ Token::EQ, flag_proxy, const1, pos);
}
Statement* clear_flag = NULL;
// Make statement: flag = 0.
@@ -2971,7 +2971,7 @@
BreakableStatement* t = LookupBreakTarget(Handle<String>(), CHECK_OK);
Statement* stop = factory()->NewBreakStatement(t,
RelocInfo::kNoPosition);
Statement* if_not_cond_break = factory()->NewIfStatement(
- cond, empty, stop, RelocInfo::kNoPosition);
+ cond, empty, stop, cond->position());
inner_block->AddStatement(if_not_cond_break, zone());
}
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Wed Jun 4
14:57:51 2014 UTC
+++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Thu Jun 5
07:33:01 2014 UTC
@@ -5683,6 +5683,21 @@
__ bind(deferred->exit());
__ bind(&done);
}
+
+
+void LCodeGen::DoStoreFrameContext(LStoreFrameContext* instr) {
+ Register context = ToRegister(instr->context());
+ __ movp(Operand(rbp, StandardFrameConstants::kContextOffset), context);
+}
+
+
+void LCodeGen::DoAllocateBlockContext(LAllocateBlockContext* instr) {
+ Handle<ScopeInfo> scope_info = instr->scope_info();
+ __ Push(scope_info);
+ __ Push(ToRegister(instr->function()));
+ CallRuntime(Runtime::kHiddenPushBlockContext, 2, instr);
+ RecordSafepoint(Safepoint::kNoLazyDeopt);
+}
#undef __
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.cc Tue Jun 3 08:12:43 2014
UTC
+++ /branches/bleeding_edge/src/x64/lithium-x64.cc Thu Jun 5 07:33:01 2014
UTC
@@ -2581,6 +2581,22 @@
LInstruction* result = DefineSameAsFirst(load);
return AssignPointerMap(result);
}
+
+
+LInstruction* LChunkBuilder::DoStoreFrameContext(HStoreFrameContext*
instr) {
+ LOperand* context = UseRegisterAtStart(instr->context());
+ return new(zone()) LStoreFrameContext(context);
+}
+
+
+LInstruction* LChunkBuilder::DoAllocateBlockContext(
+ HAllocateBlockContext* instr) {
+ LOperand* context = UseFixed(instr->context(), rsi);
+ LOperand* function = UseRegisterAtStart(instr->function());
+ LAllocateBlockContext* result =
+ new(zone()) LAllocateBlockContext(context, function);
+ return MarkAsCall(DefineFixed(result, rsi), instr);
+}
} } // namespace v8::internal
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.h Tue Jun 3 15:45:38 2014
UTC
+++ /branches/bleeding_edge/src/x64/lithium-x64.h Thu Jun 5 07:33:01 2014
UTC
@@ -21,6 +21,7 @@
V(AccessArgumentsAt) \
V(AddI) \
V(Allocate) \
+ V(AllocateBlockContext) \
V(ApplyArguments) \
V(ArgumentsElements) \
V(ArgumentsLength) \
@@ -137,6 +138,7 @@
V(StackCheck) \
V(StoreCodeEntry) \
V(StoreContextSlot) \
+ V(StoreFrameContext) \
V(StoreGlobalCell) \
V(StoreKeyed) \
V(StoreKeyedGeneric) \
@@ -2627,6 +2629,35 @@
};
+class LStoreFrameContext: public LTemplateInstruction<0, 1, 0> {
+ public:
+ explicit LStoreFrameContext(LOperand* context) {
+ inputs_[0] = context;
+ }
+
+ LOperand* context() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(StoreFrameContext, "store-frame-context")
+};
+
+
+class LAllocateBlockContext: public LTemplateInstruction<1, 2, 0> {
+ public:
+ LAllocateBlockContext(LOperand* context, LOperand* function) {
+ inputs_[0] = context;
+ inputs_[1] = function;
+ }
+
+ LOperand* context() { return inputs_[0]; }
+ LOperand* function() { return inputs_[1]; }
+
+ Handle<ScopeInfo> scope_info() { return hydrogen()->scope_info(); }
+
+
DECLARE_CONCRETE_INSTRUCTION(AllocateBlockContext, "allocate-block-context")
+ DECLARE_HYDROGEN_ACCESSOR(AllocateBlockContext)
+};
+
+
class LChunkBuilder;
class LPlatformChunk V8_FINAL : public LChunk {
public:
=======================================
--- /branches/bleeding_edge/test/mjsunit/harmony/block-let-crankshaft.js
Mon Jul 22 09:16:33 2013 UTC
+++ /branches/bleeding_edge/test/mjsunit/harmony/block-let-crankshaft.js
Thu Jun 5 07:33:01 2014 UTC
@@ -32,7 +32,8 @@
// Check that the following functions are optimizable.
var functions = [ f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13,
f14,
- f15, f16, f17, f18, f19, f20, f21, f22, f23 ];
+ f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25,
f26,
+ f27, f28, f29, f30, f31, f32, f33];
for (var i = 0; i < functions.length; ++i) {
var func = functions[i];
@@ -156,6 +157,184 @@
(function() { x; });
}
+function f24() {
+ let x = 1;
+ {
+ let x = 2;
+ {
+ let x = 3;
+ assertEquals(3, x);
+ }
+ assertEquals(2, x);
+ }
+ assertEquals(1, x);
+}
+
+function f25() {
+ {
+ let x = 2;
+ L: {
+ let x = 3;
+ assertEquals(3, x);
+ break L;
+ assertTrue(false);
+ }
+ assertEquals(2, x);
+ }
+ assertTrue(true);
+}
+
+function f26() {
+ {
+ let x = 1;
+ L: {
+ let x = 2;
+ {
+ let x = 3;
+ assertEquals(3, x);
+ break L;
+ assertTrue(false);
+ }
+ assertTrue(false);
+ }
+ assertEquals(1, x);
+ }
+}
+
+
+function f27() {
+ do {
+ let x = 4;
+ assertEquals(4,x);
+ {
+ let x = 5;
+ assertEquals(5, x);
+ continue;
+ assertTrue(false);
+ }
+ } while (false);
+}
+
+function f28() {
+ label: for (var i = 0; i < 10; ++i) {
+ let x = 'middle' + i;
+ for (var j = 0; j < 10; ++j) {
+ let x = 'inner' + j;
+ continue label;
+ }
+ }
+}
+
+function f29() {
+ // Verify that the context is correctly set in the stack frame after
exiting
+ // from with.
+
+ let x = 'outer';
+ label: {
+ let x = 'inner';
+ break label;
+ }
+ f(); // The context could be restored from the stack after the call.
+ assertEquals('outer', x);
+
+ function f() {
+ assertEquals('outer', x);
+ };
+}
+
+function f30() {
+ let x = 'outer';
+ for (var i = 0; i < 10; ++i) {
+ let x = 'inner';
+ continue;
+ }
+ f();
+ assertEquals('outer', x);
+
+ function f() {
+ assertEquals('outer', x);
+ };
+}
+
+function f31() {
+ {
+ let x = 'outer';
+ label: for (var i = 0; assertEquals('outer', x), i < 10; ++i) {
+ let x = 'middle' + i;
+ {
+ let x = 'inner' + j;
+ continue label;
+ }
+ }
+ assertEquals('outer', x);
+ }
+}
+
+var c = true;
+
+function f32() {
+ {
+ let x = 'outer';
+ L: {
+ {
+ let x = 'inner';
+ if (c) {
+ break L;
+ }
+ }
+ foo();
+ }
+ }
+
+ function foo() {
+ return 'bar';
+ }
+}
+
+function f33() {
+ {
+ let x = 'outer';
+ L: {
+ {
+ let x = 'inner';
+ if (c) {
+ break L;
+ }
+ foo();
+ }
+ }
+ }
+
+ function foo() {
+ return 'bar';
+ }
+}
+
+function TestThrow() {
+ function f() {
+ let x = 'outer';
+ {
+ let x = 'inner';
+ throw x;
+ }
+ }
+ for (var i = 0; i < 5; i++) {
+ try {
+ f();
+ } catch (e) {
+ assertEquals('inner', e);
+ }
+ }
+ %OptimizeFunctionOnNextCall(f);
+ try {
+ f();
+ } catch (e) {
+ assertEquals('inner', e);
+ }
+ assertOptimized(f);
+}
+
+TestThrow();
// Test that temporal dead zone semantics for function and block scoped
// let bindings are handled by the optimizing compiler.
@@ -207,10 +386,60 @@
assertInstanceof(e, ReferenceError);
}
}
+
+function TestBlockLocal(s) {
+ 'use strict';
+ var func = eval("(function baz(){ { " + s + "; } })");
+ print("Testing:");
+ print(func);
+ for (var i = 0; i < 5; ++i) {
+ try {
+ func();
+ assertUnreachable();
+ } catch (e) {
+ assertInstanceof(e, ReferenceError);
+ }
+ }
+ %OptimizeFunctionOnNextCall(func);
+ try {
+ func();
+ assertUnreachable();
+ } catch (e) {
+ assertInstanceof(e, ReferenceError);
+ }
+}
+
+function TestBlockContext(s) {
+ 'use strict';
+ var func = eval("(function baz(){ { " + s + "; (function() { x; }); }
})");
+ print("Testing:");
+ print(func);
+ for (var i = 0; i < 5; ++i) {
+ print(i);
+ try {
+ func();
+ assertUnreachable();
+ } catch (e) {
+ assertInstanceof(e, ReferenceError);
+ }
+ }
+ print("optimize");
+ %OptimizeFunctionOnNextCall(func);
+ try {
+ print("call");
+ func();
+ assertUnreachable();
+ } catch (e) {
+ print("catch");
+ assertInstanceof(e, ReferenceError);
+ }
+}
function TestAll(s) {
TestFunctionLocal(s);
TestFunctionContext(s);
+ TestBlockLocal(s);
+ TestBlockContext(s);
}
// Use before initialization in declaration statement.
@@ -229,34 +458,28 @@
TestAll('let y = x; const x = 1;');
-function f(x, b) {
- let y = (b ? y : x) + 42;
+function f(x) {
+ let y = x + 42;
return y;
}
-function g(x, b) {
+function g(x) {
{
- let y = (b ? y : x) + 42;
+ let y = x + 42;
return y;
}
}
for (var i=0; i<10; i++) {
- f(i, false);
- g(i, false);
+ f(i);
+ g(i);
}
%OptimizeFunctionOnNextCall(f);
%OptimizeFunctionOnNextCall(g);
-try {
- f(42, true);
-} catch (e) {
- assertInstanceof(e, ReferenceError);
-}
+f(12);
+g(12);
-try {
- g(42, true);
-} catch (e) {
- assertInstanceof(e, ReferenceError);
-}
+assertTrue(%GetOptimizationStatus(f) != 2);
+assertTrue(%GetOptimizationStatus(g) != 2);
=======================================
--- /branches/bleeding_edge/test/mjsunit/harmony/block-scoping.js Thu Nov
24 15:17:04 2011 UTC
+++ /branches/bleeding_edge/test/mjsunit/harmony/block-scoping.js Thu Jun
5 07:33:01 2014 UTC
@@ -28,7 +28,6 @@
// Flags: --allow-natives-syntax --harmony-scoping
// Test functionality of block scopes.
-// TODO(ES6): properly activate extended mode
"use strict";
// Hoisting of var declarations.
@@ -40,8 +39,10 @@
assertEquals(1, x)
assertEquals(undefined, y)
}
+for (var j = 0; j < 5; ++j) f1();
+%OptimizeFunctionOnNextCall(f1);
f1();
-
+assertTrue(%GetOptimizationStatus(f1) != 2);
// Dynamic lookup in and through block contexts.
function f2(one) {
@@ -59,8 +60,8 @@
assertEquals(6, eval('v'));
}
}
-f2(1);
+f2(1);
// Lookup in and through block contexts.
function f3(one) {
@@ -76,10 +77,13 @@
assertEquals(4, z);
assertEquals(5, u);
assertEquals(6, v);
-
}
}
+for (var j = 0; j < 5; ++j) f3(1);
+%OptimizeFunctionOnNextCall(f3);
f3(1);
+assertTrue(%GetOptimizationStatus(f3) != 2);
+
// Dynamic lookup from closure.
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.