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
This commit is contained in:
parent
13918334f8
commit
c8b2fa454a
@ -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;
|
|||||||
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;
|
|||||||
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> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
|||||||
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;
|
|||||||
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> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
|||||||
__ 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 {
|
|||||||
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 {
|
|||||||
: 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) {
|
|||||||
|
|
||||||
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) {
|
|||||||
// 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) {
|
|||||||
StoreToFrameField(StandardFrameConstants::kContextOffset,
|
StoreToFrameField(StandardFrameConstants::kContextOffset,
|
||||||
context_register());
|
context_register());
|
||||||
}
|
}
|
||||||
|
PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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() {
|
|||||||
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
|||||||
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;
|
|||||||
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 {
|
|||||||
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> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
146
src/hydrogen.cc
146
src/hydrogen.cc
@ -4247,13 +4247,52 @@ void HOptimizedGraphBuilder::VisitBlock(Block* stmt) {
|
|||||||
ASSERT(!HasStackOverflow());
|
ASSERT(!HasStackOverflow());
|
||||||
ASSERT(current_block() != NULL);
|
ASSERT(current_block() != NULL);
|
||||||
ASSERT(current_block()->HasPredecessor());
|
ASSERT(current_block()->HasPredecessor());
|
||||||
if (stmt->scope() != NULL) {
|
|
||||||
return Bailout(kScopedBlock);
|
Scope* outer_scope = scope();
|
||||||
}
|
Scope* scope = stmt->scope();
|
||||||
BreakAndContinueInfo break_info(stmt);
|
BreakAndContinueInfo break_info(stmt, outer_scope);
|
||||||
|
|
||||||
{ BreakAndContinueScope push(&break_info, this);
|
{ 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()));
|
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();
|
HBasicBlock* break_block = break_info.break_block();
|
||||||
if (break_block != NULL) {
|
if (break_block != NULL) {
|
||||||
if (current_block() != NULL) Goto(break_block);
|
if (current_block() != NULL) Goto(break_block);
|
||||||
@ -4321,6 +4360,7 @@ void HOptimizedGraphBuilder::VisitIfStatement(IfStatement* stmt) {
|
|||||||
HBasicBlock* HOptimizedGraphBuilder::BreakAndContinueScope::Get(
|
HBasicBlock* HOptimizedGraphBuilder::BreakAndContinueScope::Get(
|
||||||
BreakableStatement* stmt,
|
BreakableStatement* stmt,
|
||||||
BreakType type,
|
BreakType type,
|
||||||
|
Scope** scope,
|
||||||
int* drop_extra) {
|
int* drop_extra) {
|
||||||
*drop_extra = 0;
|
*drop_extra = 0;
|
||||||
BreakAndContinueScope* current = this;
|
BreakAndContinueScope* current = this;
|
||||||
@ -4329,6 +4369,7 @@ HBasicBlock* HOptimizedGraphBuilder::BreakAndContinueScope::Get(
|
|||||||
current = current->next();
|
current = current->next();
|
||||||
}
|
}
|
||||||
ASSERT(current != NULL); // Always found (unless stack is malformed).
|
ASSERT(current != NULL); // Always found (unless stack is malformed).
|
||||||
|
*scope = current->info()->scope();
|
||||||
|
|
||||||
if (type == BREAK) {
|
if (type == BREAK) {
|
||||||
*drop_extra += current->info()->drop_extra();
|
*drop_extra += current->info()->drop_extra();
|
||||||
@ -4362,10 +4403,29 @@ void HOptimizedGraphBuilder::VisitContinueStatement(
|
|||||||
ASSERT(!HasStackOverflow());
|
ASSERT(!HasStackOverflow());
|
||||||
ASSERT(current_block() != NULL);
|
ASSERT(current_block() != NULL);
|
||||||
ASSERT(current_block()->HasPredecessor());
|
ASSERT(current_block()->HasPredecessor());
|
||||||
|
Scope* outer_scope = NULL;
|
||||||
|
Scope* inner_scope = scope();
|
||||||
int drop_extra = 0;
|
int drop_extra = 0;
|
||||||
HBasicBlock* continue_block = break_scope()->Get(
|
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);
|
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);
|
Goto(continue_block);
|
||||||
set_current_block(NULL);
|
set_current_block(NULL);
|
||||||
}
|
}
|
||||||
@ -4375,10 +4435,28 @@ void HOptimizedGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
|
|||||||
ASSERT(!HasStackOverflow());
|
ASSERT(!HasStackOverflow());
|
||||||
ASSERT(current_block() != NULL);
|
ASSERT(current_block() != NULL);
|
||||||
ASSERT(current_block()->HasPredecessor());
|
ASSERT(current_block()->HasPredecessor());
|
||||||
|
Scope* outer_scope = NULL;
|
||||||
|
Scope* inner_scope = scope();
|
||||||
int drop_extra = 0;
|
int drop_extra = 0;
|
||||||
HBasicBlock* break_block = break_scope()->Get(
|
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);
|
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);
|
Goto(break_block);
|
||||||
set_current_block(NULL);
|
set_current_block(NULL);
|
||||||
}
|
}
|
||||||
@ -4533,7 +4611,7 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
|
|||||||
// translating the clause bodies.
|
// translating the clause bodies.
|
||||||
HBasicBlock* fall_through_block = NULL;
|
HBasicBlock* fall_through_block = NULL;
|
||||||
|
|
||||||
BreakAndContinueInfo break_info(stmt);
|
BreakAndContinueInfo break_info(stmt, scope());
|
||||||
{ BreakAndContinueScope push(&break_info, this);
|
{ BreakAndContinueScope push(&break_info, this);
|
||||||
for (int i = 0; i < clause_count; ++i) {
|
for (int i = 0; i < clause_count; ++i) {
|
||||||
CaseClause* clause = clauses->at(i);
|
CaseClause* clause = clauses->at(i);
|
||||||
@ -4580,9 +4658,7 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
|
|||||||
|
|
||||||
|
|
||||||
void HOptimizedGraphBuilder::VisitLoopBody(IterationStatement* stmt,
|
void HOptimizedGraphBuilder::VisitLoopBody(IterationStatement* stmt,
|
||||||
HBasicBlock* loop_entry,
|
HBasicBlock* loop_entry) {
|
||||||
BreakAndContinueInfo* break_info) {
|
|
||||||
BreakAndContinueScope push(break_info, this);
|
|
||||||
Add<HSimulate>(stmt->StackCheckId());
|
Add<HSimulate>(stmt->StackCheckId());
|
||||||
HStackCheck* stack_check =
|
HStackCheck* stack_check =
|
||||||
HStackCheck::cast(Add<HStackCheck>(HStackCheck::kBackwardsBranch));
|
HStackCheck::cast(Add<HStackCheck>(HStackCheck::kBackwardsBranch));
|
||||||
@ -4599,8 +4675,11 @@ void HOptimizedGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
|
|||||||
ASSERT(current_block() != NULL);
|
ASSERT(current_block() != NULL);
|
||||||
HBasicBlock* loop_entry = BuildLoopEntry(stmt);
|
HBasicBlock* loop_entry = BuildLoopEntry(stmt);
|
||||||
|
|
||||||
BreakAndContinueInfo break_info(stmt);
|
BreakAndContinueInfo break_info(stmt, scope());
|
||||||
CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
|
{
|
||||||
|
BreakAndContinueScope push(&break_info, this);
|
||||||
|
CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry));
|
||||||
|
}
|
||||||
HBasicBlock* body_exit =
|
HBasicBlock* body_exit =
|
||||||
JoinContinue(stmt, current_block(), break_info.continue_block());
|
JoinContinue(stmt, current_block(), break_info.continue_block());
|
||||||
HBasicBlock* loop_successor = NULL;
|
HBasicBlock* loop_successor = NULL;
|
||||||
@ -4661,9 +4740,10 @@ void HOptimizedGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BreakAndContinueInfo break_info(stmt);
|
BreakAndContinueInfo break_info(stmt, scope());
|
||||||
if (current_block() != NULL) {
|
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 =
|
HBasicBlock* body_exit =
|
||||||
JoinContinue(stmt, current_block(), break_info.continue_block());
|
JoinContinue(stmt, current_block(), break_info.continue_block());
|
||||||
@ -4702,9 +4782,10 @@ void HOptimizedGraphBuilder::VisitForStatement(ForStatement* stmt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BreakAndContinueInfo break_info(stmt);
|
BreakAndContinueInfo break_info(stmt, scope());
|
||||||
if (current_block() != NULL) {
|
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 =
|
HBasicBlock* body_exit =
|
||||||
JoinContinue(stmt, current_block(), break_info.continue_block());
|
JoinContinue(stmt, current_block(), break_info.continue_block());
|
||||||
@ -4803,8 +4884,11 @@ void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
|
|||||||
|
|
||||||
Bind(each_var, key);
|
Bind(each_var, key);
|
||||||
|
|
||||||
BreakAndContinueInfo break_info(stmt, 5);
|
BreakAndContinueInfo break_info(stmt, scope(), 5);
|
||||||
CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
|
{
|
||||||
|
BreakAndContinueScope push(&break_info, this);
|
||||||
|
CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry));
|
||||||
|
}
|
||||||
|
|
||||||
HBasicBlock* body_exit =
|
HBasicBlock* body_exit =
|
||||||
JoinContinue(stmt, current_block(), break_info.continue_block());
|
JoinContinue(stmt, current_block(), break_info.continue_block());
|
||||||
@ -4949,7 +5033,7 @@ HOptimizedGraphBuilder::GlobalPropertyAccess
|
|||||||
HValue* HOptimizedGraphBuilder::BuildContextChainWalk(Variable* var) {
|
HValue* HOptimizedGraphBuilder::BuildContextChainWalk(Variable* var) {
|
||||||
ASSERT(var->IsContextSlot());
|
ASSERT(var->IsContextSlot());
|
||||||
HValue* context = environment()->context();
|
HValue* context = environment()->context();
|
||||||
int length = current_info()->scope()->ContextChainLength(var->scope());
|
int length = scope()->ContextChainLength(var->scope());
|
||||||
while (length-- > 0) {
|
while (length-- > 0) {
|
||||||
context = Add<HLoadNamedField>(
|
context = Add<HLoadNamedField>(
|
||||||
context, static_cast<HValue*>(NULL),
|
context, static_cast<HValue*>(NULL),
|
||||||
@ -5033,7 +5117,21 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
|
|||||||
|
|
||||||
case Variable::CONTEXT: {
|
case Variable::CONTEXT: {
|
||||||
HValue* context = BuildContextChainWalk(variable);
|
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());
|
return ast_context()->ReturnInstruction(instr, expr->id());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7462,7 +7560,8 @@ bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target,
|
|||||||
Add<HSimulate>(BailoutId::None());
|
Add<HSimulate>(BailoutId::None());
|
||||||
|
|
||||||
current_block()->UpdateEnvironment(inner_env);
|
current_block()->UpdateEnvironment(inner_env);
|
||||||
|
Scope* saved_scope = scope();
|
||||||
|
set_scope(target_info.scope());
|
||||||
HEnterInlined* enter_inlined =
|
HEnterInlined* enter_inlined =
|
||||||
Add<HEnterInlined>(return_id, target, arguments_count, function,
|
Add<HEnterInlined>(return_id, target, arguments_count, function,
|
||||||
function_state()->inlining_kind(),
|
function_state()->inlining_kind(),
|
||||||
@ -7472,6 +7571,7 @@ bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target,
|
|||||||
|
|
||||||
VisitDeclarations(target_info.scope()->declarations());
|
VisitDeclarations(target_info.scope()->declarations());
|
||||||
VisitStatements(function->body());
|
VisitStatements(function->body());
|
||||||
|
set_scope(saved_scope);
|
||||||
if (HasStackOverflow()) {
|
if (HasStackOverflow()) {
|
||||||
// Bail out if the inline function did, as we cannot residualize a call
|
// Bail out if the inline function did, as we cannot residualize a call
|
||||||
// instead.
|
// instead.
|
||||||
@ -11432,7 +11532,9 @@ HEnvironment::HEnvironment(HEnvironment* outer,
|
|||||||
push_count_(0),
|
push_count_(0),
|
||||||
ast_id_(BailoutId::None()),
|
ast_id_(BailoutId::None()),
|
||||||
zone_(zone) {
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
|
|
||||||
// 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 {
|
|||||||
|
|
||||||
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
|||||||
#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;
|
|||||||
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> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
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(
|
|||||||
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(
|
|||||||
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
|||||||
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;
|
|||||||
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> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
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 @@
|
|||||||
|
|
||||||
// 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() {
|
|||||||
(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) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;');
|
|||||||
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 @@
|
|||||||
// 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() {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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.
|
||||||
|
Loading…
Reference in New Issue
Block a user