Commit c8b2fa45 authored by ulan@chromium.org's avatar ulan@chromium.org

Preliminary support for block contexts in hydrogen.

Patch from Steven Keuchel <keuchel@chromium.org>

BUG=v8:2198
LOG=N
TEST=mjsunit/harmony/block-let-crankshaft.js
R=rossberg@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21684 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 13918334
...@@ -2579,4 +2579,20 @@ LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) { ...@@ -2579,4 +2579,20 @@ LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) {
return AssignPointerMap(result); 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 } } // namespace v8::internal
...@@ -21,6 +21,7 @@ class LCodeGen; ...@@ -21,6 +21,7 @@ class LCodeGen;
V(AccessArgumentsAt) \ V(AccessArgumentsAt) \
V(AddI) \ V(AddI) \
V(Allocate) \ V(Allocate) \
V(AllocateBlockContext) \
V(ApplyArguments) \ V(ApplyArguments) \
V(ArgumentsElements) \ V(ArgumentsElements) \
V(ArgumentsLength) \ V(ArgumentsLength) \
...@@ -139,6 +140,7 @@ class LCodeGen; ...@@ -139,6 +140,7 @@ class LCodeGen;
V(StackCheck) \ V(StackCheck) \
V(StoreCodeEntry) \ V(StoreCodeEntry) \
V(StoreContextSlot) \ V(StoreContextSlot) \
V(StoreFrameContext) \
V(StoreGlobalCell) \ V(StoreGlobalCell) \
V(StoreKeyed) \ V(StoreKeyed) \
V(StoreKeyedGeneric) \ V(StoreKeyedGeneric) \
...@@ -2669,6 +2671,35 @@ class LLoadFieldByIndex V8_FINAL : public LTemplateInstruction<1, 2, 0> { ...@@ -2669,6 +2671,35 @@ class LLoadFieldByIndex V8_FINAL : public LTemplateInstruction<1, 2, 0> {
}; };
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 LChunkBuilder;
class LPlatformChunk V8_FINAL : public LChunk { class LPlatformChunk V8_FINAL : public LChunk {
public: public:
......
...@@ -5818,6 +5818,21 @@ void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) { ...@@ -5818,6 +5818,21 @@ void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
} }
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 __ #undef __
} } // namespace v8::internal } } // namespace v8::internal
...@@ -2706,4 +2706,20 @@ LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) { ...@@ -2706,4 +2706,20 @@ LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
} }
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 } } // namespace v8::internal
...@@ -23,6 +23,7 @@ class LCodeGen; ...@@ -23,6 +23,7 @@ class LCodeGen;
V(AddI) \ V(AddI) \
V(AddS) \ V(AddS) \
V(Allocate) \ V(Allocate) \
V(AllocateBlockContext) \
V(ApplyArguments) \ V(ApplyArguments) \
V(ArgumentsElements) \ V(ArgumentsElements) \
V(ArgumentsLength) \ V(ArgumentsLength) \
...@@ -148,6 +149,7 @@ class LCodeGen; ...@@ -148,6 +149,7 @@ class LCodeGen;
V(StackCheck) \ V(StackCheck) \
V(StoreCodeEntry) \ V(StoreCodeEntry) \
V(StoreContextSlot) \ V(StoreContextSlot) \
V(StoreFrameContext) \
V(StoreGlobalCell) \ V(StoreGlobalCell) \
V(StoreKeyedExternal) \ V(StoreKeyedExternal) \
V(StoreKeyedFixed) \ V(StoreKeyedFixed) \
...@@ -2997,6 +2999,35 @@ class LLoadFieldByIndex V8_FINAL : public LTemplateInstruction<1, 2, 0> { ...@@ -2997,6 +2999,35 @@ class LLoadFieldByIndex V8_FINAL : public LTemplateInstruction<1, 2, 0> {
}; };
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> { class LWrapReceiver V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public: public:
LWrapReceiver(LOperand* receiver, LOperand* function) { LWrapReceiver(LOperand* receiver, LOperand* function) {
......
...@@ -6039,4 +6039,21 @@ void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) { ...@@ -6039,4 +6039,21 @@ void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
__ Bind(&done); __ 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 } } // namespace v8::internal
...@@ -441,6 +441,8 @@ class Block V8_FINAL : public BreakableStatement { ...@@ -441,6 +441,8 @@ class Block V8_FINAL : public BreakableStatement {
ZoneList<Statement*>* statements() { return &statements_; } ZoneList<Statement*>* statements() { return &statements_; }
bool is_initializer_block() const { return is_initializer_block_; } bool is_initializer_block() const { return is_initializer_block_; }
BailoutId DeclsId() const { return decls_id_; }
virtual bool IsJump() const V8_OVERRIDE { virtual bool IsJump() const V8_OVERRIDE {
return !statements_.is_empty() && statements_.last()->IsJump() return !statements_.is_empty() && statements_.last()->IsJump()
&& labels() == NULL; // Good enough as an approximation... && labels() == NULL; // Good enough as an approximation...
...@@ -458,12 +460,14 @@ class Block V8_FINAL : public BreakableStatement { ...@@ -458,12 +460,14 @@ class Block V8_FINAL : public BreakableStatement {
: BreakableStatement(zone, labels, TARGET_FOR_NAMED_ONLY, pos), : BreakableStatement(zone, labels, TARGET_FOR_NAMED_ONLY, pos),
statements_(capacity, zone), statements_(capacity, zone),
is_initializer_block_(is_initializer_block), is_initializer_block_(is_initializer_block),
decls_id_(GetNextId(zone)),
scope_(NULL) { scope_(NULL) {
} }
private: private:
ZoneList<Statement*> statements_; ZoneList<Statement*> statements_;
bool is_initializer_block_; bool is_initializer_block_;
const BailoutId decls_id_;
Scope* scope_; Scope* scope_;
}; };
......
...@@ -1052,7 +1052,9 @@ void FullCodeGenerator::VisitBlock(Block* stmt) { ...@@ -1052,7 +1052,9 @@ void FullCodeGenerator::VisitBlock(Block* stmt) {
Scope* saved_scope = scope(); Scope* saved_scope = scope();
// Push a block context when entering a block with block scoped variables. // 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(); scope_ = stmt->scope();
ASSERT(!scope_->is_module_scope()); ASSERT(!scope_->is_module_scope());
{ Comment cmnt(masm_, "[ Extend block context"); { Comment cmnt(masm_, "[ Extend block context");
...@@ -1063,17 +1065,17 @@ void FullCodeGenerator::VisitBlock(Block* stmt) { ...@@ -1063,17 +1065,17 @@ void FullCodeGenerator::VisitBlock(Block* stmt) {
// Replace the context stored in the frame. // Replace the context stored in the frame.
StoreToFrameField(StandardFrameConstants::kContextOffset, StoreToFrameField(StandardFrameConstants::kContextOffset,
context_register()); context_register());
PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
} }
{ Comment cmnt(masm_, "[ Declarations"); { Comment cmnt(masm_, "[ Declarations");
VisitDeclarations(scope_->declarations()); VisitDeclarations(scope_->declarations());
PrepareForBailoutForId(stmt->DeclsId(), NO_REGISTERS);
} }
} }
PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
VisitStatements(stmt->statements()); VisitStatements(stmt->statements());
scope_ = saved_scope; scope_ = saved_scope;
__ bind(nested_block.break_label()); __ bind(nested_block.break_label());
PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
// Pop block context if necessary. // Pop block context if necessary.
if (stmt->scope() != NULL) { if (stmt->scope() != NULL) {
...@@ -1082,6 +1084,7 @@ void FullCodeGenerator::VisitBlock(Block* stmt) { ...@@ -1082,6 +1084,7 @@ void FullCodeGenerator::VisitBlock(Block* stmt) {
StoreToFrameField(StandardFrameConstants::kContextOffset, StoreToFrameField(StandardFrameConstants::kContextOffset,
context_register()); context_register());
} }
PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
} }
......
...@@ -846,6 +846,7 @@ bool HInstruction::CanDeoptimize() { ...@@ -846,6 +846,7 @@ bool HInstruction::CanDeoptimize() {
case HValue::kReturn: case HValue::kReturn:
case HValue::kSeqStringGetChar: case HValue::kSeqStringGetChar:
case HValue::kStoreCodeEntry: case HValue::kStoreCodeEntry:
case HValue::kStoreFrameContext:
case HValue::kStoreKeyed: case HValue::kStoreKeyed:
case HValue::kStoreNamedField: case HValue::kStoreNamedField:
case HValue::kStoreNamedGeneric: case HValue::kStoreNamedGeneric:
...@@ -858,6 +859,7 @@ bool HInstruction::CanDeoptimize() { ...@@ -858,6 +859,7 @@ bool HInstruction::CanDeoptimize() {
return false; return false;
case HValue::kAdd: case HValue::kAdd:
case HValue::kAllocateBlockContext:
case HValue::kApplyArguments: case HValue::kApplyArguments:
case HValue::kBitwise: case HValue::kBitwise:
case HValue::kBoundsCheck: case HValue::kBoundsCheck:
...@@ -1136,6 +1138,13 @@ void HAccessArgumentsAt::PrintDataTo(StringStream* stream) { ...@@ -1136,6 +1138,13 @@ void HAccessArgumentsAt::PrintDataTo(StringStream* stream) {
} }
void HAllocateBlockContext::PrintDataTo(StringStream* stream) {
context()->PrintNameTo(stream);
stream->Add(" ");
function()->PrintNameTo(stream);
}
void HControlInstruction::PrintDataTo(StringStream* stream) { void HControlInstruction::PrintDataTo(StringStream* stream) {
stream->Add(" goto ("); stream->Add(" goto (");
bool first_block = true; bool first_block = true;
......
...@@ -46,6 +46,7 @@ class LChunkBuilder; ...@@ -46,6 +46,7 @@ class LChunkBuilder;
V(AbnormalExit) \ V(AbnormalExit) \
V(AccessArgumentsAt) \ V(AccessArgumentsAt) \
V(Add) \ V(Add) \
V(AllocateBlockContext) \
V(Allocate) \ V(Allocate) \
V(ApplyArguments) \ V(ApplyArguments) \
V(ArgumentsElements) \ V(ArgumentsElements) \
...@@ -140,6 +141,7 @@ class LChunkBuilder; ...@@ -140,6 +141,7 @@ class LChunkBuilder;
V(StackCheck) \ V(StackCheck) \
V(StoreCodeEntry) \ V(StoreCodeEntry) \
V(StoreContextSlot) \ V(StoreContextSlot) \
V(StoreFrameContext) \
V(StoreGlobalCell) \ V(StoreGlobalCell) \
V(StoreKeyed) \ V(StoreKeyed) \
V(StoreKeyedGeneric) \ V(StoreKeyedGeneric) \
...@@ -5798,20 +5800,8 @@ class HLoadContextSlot V8_FINAL : public HUnaryOperation { ...@@ -5798,20 +5800,8 @@ class HLoadContextSlot V8_FINAL : public HUnaryOperation {
kCheckReturnUndefined kCheckReturnUndefined
}; };
HLoadContextSlot(HValue* context, Variable* var) HLoadContextSlot(HValue* context, int slot_index, Mode mode)
: HUnaryOperation(context), slot_index_(var->index()) { : HUnaryOperation(context), slot_index_(slot_index), mode_(mode) {
ASSERT(var->IsContextSlot());
switch (var->mode()) {
case LET:
case CONST:
mode_ = kCheckDeoptimize;
break;
case CONST_LEGACY:
mode_ = kCheckReturnUndefined;
break;
default:
mode_ = kNoCheck;
}
set_representation(Representation::Tagged()); set_representation(Representation::Tagged());
SetFlag(kUseGVN); SetFlag(kUseGVN);
SetDependsOnFlag(kContextSlots); SetDependsOnFlag(kContextSlots);
...@@ -7717,6 +7707,57 @@ class HLoadFieldByIndex V8_FINAL : public HTemplateInstruction<2> { ...@@ -7717,6 +7707,57 @@ class HLoadFieldByIndex V8_FINAL : public HTemplateInstruction<2> {
}; };
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_INSTRUCTION
#undef DECLARE_CONCRETE_INSTRUCTION #undef DECLARE_CONCRETE_INSTRUCTION
......
This diff is collapsed.
...@@ -1042,10 +1042,14 @@ class HGraphBuilder { ...@@ -1042,10 +1042,14 @@ class HGraphBuilder {
: info_(info), : info_(info),
graph_(NULL), graph_(NULL),
current_block_(NULL), current_block_(NULL),
scope_(info->scope()),
position_(HSourcePosition::Unknown()), position_(HSourcePosition::Unknown()),
start_position_(0) {} start_position_(0) {}
virtual ~HGraphBuilder() {} virtual ~HGraphBuilder() {}
Scope* scope() const { return scope_; }
void set_scope(Scope* scope) { scope_ = scope; }
HBasicBlock* current_block() const { return current_block_; } HBasicBlock* current_block() const { return current_block_; }
void set_current_block(HBasicBlock* block) { current_block_ = block; } void set_current_block(HBasicBlock* block) { current_block_ = block; }
HEnvironment* environment() const { HEnvironment* environment() const {
...@@ -1870,6 +1874,7 @@ class HGraphBuilder { ...@@ -1870,6 +1874,7 @@ class HGraphBuilder {
CompilationInfo* info_; CompilationInfo* info_;
HGraph* graph_; HGraph* graph_;
HBasicBlock* current_block_; HBasicBlock* current_block_;
Scope* scope_;
HSourcePosition position_; HSourcePosition position_;
int start_position_; int start_position_;
}; };
...@@ -1997,10 +2002,12 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { ...@@ -1997,10 +2002,12 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
class BreakAndContinueInfo V8_FINAL BASE_EMBEDDED { class BreakAndContinueInfo V8_FINAL BASE_EMBEDDED {
public: public:
explicit BreakAndContinueInfo(BreakableStatement* target, explicit BreakAndContinueInfo(BreakableStatement* target,
Scope* scope,
int drop_extra = 0) int drop_extra = 0)
: target_(target), : target_(target),
break_block_(NULL), break_block_(NULL),
continue_block_(NULL), continue_block_(NULL),
scope_(scope),
drop_extra_(drop_extra) { drop_extra_(drop_extra) {
} }
...@@ -2009,12 +2016,14 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { ...@@ -2009,12 +2016,14 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
void set_break_block(HBasicBlock* block) { break_block_ = block; } void set_break_block(HBasicBlock* block) { break_block_ = block; }
HBasicBlock* continue_block() { return continue_block_; } HBasicBlock* continue_block() { return continue_block_; }
void set_continue_block(HBasicBlock* block) { continue_block_ = block; } void set_continue_block(HBasicBlock* block) { continue_block_ = block; }
Scope* scope() { return scope_; }
int drop_extra() { return drop_extra_; } int drop_extra() { return drop_extra_; }
private: private:
BreakableStatement* target_; BreakableStatement* target_;
HBasicBlock* break_block_; HBasicBlock* break_block_;
HBasicBlock* continue_block_; HBasicBlock* continue_block_;
Scope* scope_;
int drop_extra_; int drop_extra_;
}; };
...@@ -2036,7 +2045,8 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { ...@@ -2036,7 +2045,8 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
// Search the break stack for a break or continue target. // Search the break stack for a break or continue target.
enum BreakType { BREAK, CONTINUE }; 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: private:
BreakAndContinueInfo* info_; BreakAndContinueInfo* info_;
...@@ -2146,8 +2156,7 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { ...@@ -2146,8 +2156,7 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
bool PreProcessOsrEntry(IterationStatement* statement); bool PreProcessOsrEntry(IterationStatement* statement);
void VisitLoopBody(IterationStatement* stmt, void VisitLoopBody(IterationStatement* stmt,
HBasicBlock* loop_entry, HBasicBlock* loop_entry);
BreakAndContinueInfo* break_info);
// Create a back edge in the flow graph. body_exit is the predecessor // 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 // block and loop_entry is the successor block. loop_successor is the
......
...@@ -5644,6 +5644,21 @@ void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) { ...@@ -5644,6 +5644,21 @@ void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
} }
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 __ #undef __
} } // namespace v8::internal } } // namespace v8::internal
......
...@@ -2654,6 +2654,22 @@ LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) { ...@@ -2654,6 +2654,22 @@ LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) {
} }
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 } } // namespace v8::internal
#endif // V8_TARGET_ARCH_IA32 #endif // V8_TARGET_ARCH_IA32
...@@ -20,6 +20,7 @@ class LCodeGen; ...@@ -20,6 +20,7 @@ class LCodeGen;
#define LITHIUM_CONCRETE_INSTRUCTION_LIST(V) \ #define LITHIUM_CONCRETE_INSTRUCTION_LIST(V) \
V(AccessArgumentsAt) \ V(AccessArgumentsAt) \
V(AddI) \ V(AddI) \
V(AllocateBlockContext) \
V(Allocate) \ V(Allocate) \
V(ApplyArguments) \ V(ApplyArguments) \
V(ArgumentsElements) \ V(ArgumentsElements) \
...@@ -137,6 +138,7 @@ class LCodeGen; ...@@ -137,6 +138,7 @@ class LCodeGen;
V(StackCheck) \ V(StackCheck) \
V(StoreCodeEntry) \ V(StoreCodeEntry) \
V(StoreContextSlot) \ V(StoreContextSlot) \
V(StoreFrameContext) \
V(StoreGlobalCell) \ V(StoreGlobalCell) \
V(StoreKeyed) \ V(StoreKeyed) \
V(StoreKeyedGeneric) \ V(StoreKeyedGeneric) \
...@@ -2649,6 +2651,35 @@ class LLoadFieldByIndex V8_FINAL : public LTemplateInstruction<1, 2, 0> { ...@@ -2649,6 +2651,35 @@ class LLoadFieldByIndex V8_FINAL : public LTemplateInstruction<1, 2, 0> {
}; };
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 LChunkBuilder;
class LPlatformChunk V8_FINAL : public LChunk { class LPlatformChunk V8_FINAL : public LChunk {
public: public:
......
...@@ -2948,7 +2948,7 @@ Statement* Parser::DesugarLetBindingsInForStatement( ...@@ -2948,7 +2948,7 @@ Statement* Parser::DesugarLetBindingsInForStatement(
Expression* const1 = factory()->NewLiteral(smi1, RelocInfo::kNoPosition); Expression* const1 = factory()->NewLiteral(smi1, RelocInfo::kNoPosition);
VariableProxy* flag_proxy = factory()->NewVariableProxy(flag); VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
compare = factory()->NewCompareOperation( compare = factory()->NewCompareOperation(
Token::EQ, flag_proxy, const1, RelocInfo::kNoPosition); Token::EQ, flag_proxy, const1, pos);
} }
Statement* clear_flag = NULL; Statement* clear_flag = NULL;
// Make statement: flag = 0. // Make statement: flag = 0.
...@@ -2971,7 +2971,7 @@ Statement* Parser::DesugarLetBindingsInForStatement( ...@@ -2971,7 +2971,7 @@ Statement* Parser::DesugarLetBindingsInForStatement(
BreakableStatement* t = LookupBreakTarget(Handle<String>(), CHECK_OK); BreakableStatement* t = LookupBreakTarget(Handle<String>(), CHECK_OK);
Statement* stop = factory()->NewBreakStatement(t, RelocInfo::kNoPosition); Statement* stop = factory()->NewBreakStatement(t, RelocInfo::kNoPosition);
Statement* if_not_cond_break = factory()->NewIfStatement( 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()); inner_block->AddStatement(if_not_cond_break, zone());
} }
......
...@@ -5685,6 +5685,21 @@ void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) { ...@@ -5685,6 +5685,21 @@ void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
} }
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 __ #undef __
} } // namespace v8::internal } } // namespace v8::internal
......
...@@ -2583,6 +2583,22 @@ LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) { ...@@ -2583,6 +2583,22 @@ LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) {
} }
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 } } // namespace v8::internal
#endif // V8_TARGET_ARCH_X64 #endif // V8_TARGET_ARCH_X64
...@@ -21,6 +21,7 @@ class LCodeGen; ...@@ -21,6 +21,7 @@ class LCodeGen;
V(AccessArgumentsAt) \ V(AccessArgumentsAt) \
V(AddI) \ V(AddI) \
V(Allocate) \ V(Allocate) \
V(AllocateBlockContext) \
V(ApplyArguments) \ V(ApplyArguments) \
V(ArgumentsElements) \ V(ArgumentsElements) \
V(ArgumentsLength) \ V(ArgumentsLength) \
...@@ -137,6 +138,7 @@ class LCodeGen; ...@@ -137,6 +138,7 @@ class LCodeGen;
V(StackCheck) \ V(StackCheck) \
V(StoreCodeEntry) \ V(StoreCodeEntry) \
V(StoreContextSlot) \ V(StoreContextSlot) \
V(StoreFrameContext) \
V(StoreGlobalCell) \ V(StoreGlobalCell) \
V(StoreKeyed) \ V(StoreKeyed) \
V(StoreKeyedGeneric) \ V(StoreKeyedGeneric) \
...@@ -2627,6 +2629,35 @@ class LLoadFieldByIndex V8_FINAL : public LTemplateInstruction<1, 2, 0> { ...@@ -2627,6 +2629,35 @@ class LLoadFieldByIndex V8_FINAL : public LTemplateInstruction<1, 2, 0> {
}; };
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 LChunkBuilder;
class LPlatformChunk V8_FINAL : public LChunk { class LPlatformChunk V8_FINAL : public LChunk {
public: public:
......
...@@ -32,7 +32,8 @@ ...@@ -32,7 +32,8 @@
// Check that the following functions are optimizable. // Check that the following functions are optimizable.
var functions = [ f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, 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) { for (var i = 0; i < functions.length; ++i) {
var func = functions[i]; var func = functions[i];
...@@ -156,6 +157,184 @@ function f23() { ...@@ -156,6 +157,184 @@ function f23() {
(function() { x; }); (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 // Test that temporal dead zone semantics for function and block scoped
// let bindings are handled by the optimizing compiler. // let bindings are handled by the optimizing compiler.
...@@ -208,9 +387,59 @@ function TestFunctionContext(s) { ...@@ -208,9 +387,59 @@ function TestFunctionContext(s) {
} }
} }
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) { function TestAll(s) {
TestFunctionLocal(s); TestFunctionLocal(s);
TestFunctionContext(s); TestFunctionContext(s);
TestBlockLocal(s);
TestBlockContext(s);
} }
// Use before initialization in declaration statement. // Use before initialization in declaration statement.
...@@ -229,34 +458,28 @@ TestAll('x++; let x;'); ...@@ -229,34 +458,28 @@ TestAll('x++; let x;');
TestAll('let y = x; const x = 1;'); TestAll('let y = x; const x = 1;');
function f(x, b) { function f(x) {
let y = (b ? y : x) + 42; let y = x + 42;
return y; return y;
} }
function g(x, b) { function g(x) {
{ {
let y = (b ? y : x) + 42; let y = x + 42;
return y; return y;
} }
} }
for (var i=0; i<10; i++) { for (var i=0; i<10; i++) {
f(i, false); f(i);
g(i, false); g(i);
} }
%OptimizeFunctionOnNextCall(f); %OptimizeFunctionOnNextCall(f);
%OptimizeFunctionOnNextCall(g); %OptimizeFunctionOnNextCall(g);
try { f(12);
f(42, true); g(12);
} catch (e) {
assertInstanceof(e, ReferenceError);
}
try { assertTrue(%GetOptimizationStatus(f) != 2);
g(42, true); assertTrue(%GetOptimizationStatus(g) != 2);
} catch (e) {
assertInstanceof(e, ReferenceError);
}
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
// Flags: --allow-natives-syntax --harmony-scoping // Flags: --allow-natives-syntax --harmony-scoping
// Test functionality of block scopes. // Test functionality of block scopes.
// TODO(ES6): properly activate extended mode
"use strict"; "use strict";
// Hoisting of var declarations. // Hoisting of var declarations.
...@@ -40,8 +39,10 @@ function f1() { ...@@ -40,8 +39,10 @@ function f1() {
assertEquals(1, x) assertEquals(1, x)
assertEquals(undefined, y) assertEquals(undefined, y)
} }
for (var j = 0; j < 5; ++j) f1();
%OptimizeFunctionOnNextCall(f1);
f1(); f1();
assertTrue(%GetOptimizationStatus(f1) != 2);
// Dynamic lookup in and through block contexts. // Dynamic lookup in and through block contexts.
function f2(one) { function f2(one) {
...@@ -59,8 +60,8 @@ function f2(one) { ...@@ -59,8 +60,8 @@ function f2(one) {
assertEquals(6, eval('v')); assertEquals(6, eval('v'));
} }
} }
f2(1);
f2(1);
// Lookup in and through block contexts. // Lookup in and through block contexts.
function f3(one) { function f3(one) {
...@@ -76,10 +77,13 @@ function f3(one) { ...@@ -76,10 +77,13 @@ function f3(one) {
assertEquals(4, z); assertEquals(4, z);
assertEquals(5, u); assertEquals(5, u);
assertEquals(6, v); assertEquals(6, v);
} }
} }
for (var j = 0; j < 5; ++j) f3(1);
%OptimizeFunctionOnNextCall(f3);
f3(1); f3(1);
assertTrue(%GetOptimizationStatus(f3) != 2);
// Dynamic lookup from closure. // Dynamic lookup from closure.
......
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