Commit 38915ed7 authored by mstarzinger's avatar mstarzinger Committed by Commit bot

[fullcodegen] Implement operand stack depth tracking.

This implements a mechanism to track the exact depth of the operand
stack in full-codegen for every sub-expression visitation. So far we
only tracked the depth at statement level, but not at expression level.
With the introduction of do-expressions it will be possible to construct
local control flow (i.e. break, continue and friends) that target labels
at an arbitrary operand stack depth, making this tracking a prerequisite
for full do-expression support.

R=rossberg@chromium.org,jarin@chromium.org
BUG=v8:4755,v8:4488
LOG=n

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

Cr-Commit-Position: refs/heads/master@{#34211}
parent 72ba53b1
...@@ -232,6 +232,7 @@ namespace internal { ...@@ -232,6 +232,7 @@ namespace internal {
"Unexpected number of pre-allocated property fields") \ "Unexpected number of pre-allocated property fields") \
V(kUnexpectedFPCRMode, "Unexpected FPCR mode.") \ V(kUnexpectedFPCRMode, "Unexpected FPCR mode.") \
V(kUnexpectedSmi, "Unexpected smi value") \ V(kUnexpectedSmi, "Unexpected smi value") \
V(kUnexpectedStackDepth, "Unexpected operand stack depth in full-codegen") \
V(kUnexpectedStackPointer, "The stack pointer is not the expected value") \ V(kUnexpectedStackPointer, "The stack pointer is not the expected value") \
V(kUnexpectedStringType, "Unexpected string type") \ V(kUnexpectedStringType, "Unexpected string type") \
V(kUnexpectedTypeForRegExpDataFixedArrayExpected, \ V(kUnexpectedTypeForRegExpDataFixedArrayExpected, \
......
...@@ -637,6 +637,9 @@ DEFINE_INT(max_stack_trace_source_length, 300, ...@@ -637,6 +637,9 @@ DEFINE_INT(max_stack_trace_source_length, 300,
// full-codegen.cc // full-codegen.cc
DEFINE_BOOL(always_inline_smi_code, false, DEFINE_BOOL(always_inline_smi_code, false,
"always inline smi code in non-opt code") "always inline smi code in non-opt code")
DEFINE_BOOL(verify_operand_stack_depth, false,
"emit debug code that verifies the static tracking of the operand "
"stack depth")
// heap.cc // heap.cc
DEFINE_INT(min_semi_space_size, 0, DEFINE_INT(min_semi_space_size, 0,
......
This diff is collapsed.
This diff is collapsed.
...@@ -42,6 +42,7 @@ class FullCodeGenerator: public AstVisitor { ...@@ -42,6 +42,7 @@ class FullCodeGenerator: public AstVisitor {
nesting_stack_(NULL), nesting_stack_(NULL),
loop_depth_(0), loop_depth_(0),
try_catch_depth_(0), try_catch_depth_(0),
operand_stack_depth_(0),
globals_(NULL), globals_(NULL),
context_(NULL), context_(NULL),
bailout_entries_(info->HasDeoptimizationSupport() bailout_entries_(info->HasDeoptimizationSupport()
...@@ -136,11 +137,6 @@ class FullCodeGenerator: public AstVisitor { ...@@ -136,11 +137,6 @@ class FullCodeGenerator: public AstVisitor {
return previous_; return previous_;
} }
// Like the Exit() method above, but limited to accumulating stack depth.
virtual NestedStatement* AccumulateDepth(int* stack_depth) {
return previous_;
}
protected: protected:
MacroAssembler* masm() { return codegen_->masm(); } MacroAssembler* masm() { return codegen_->masm(); }
...@@ -216,10 +212,6 @@ class FullCodeGenerator: public AstVisitor { ...@@ -216,10 +212,6 @@ class FullCodeGenerator: public AstVisitor {
*stack_depth += kElementCount; *stack_depth += kElementCount;
return previous_; return previous_;
} }
NestedStatement* AccumulateDepth(int* stack_depth) override {
*stack_depth += kElementCount;
return previous_;
}
}; };
class DeferredCommands { class DeferredCommands {
...@@ -268,10 +260,6 @@ class FullCodeGenerator: public AstVisitor { ...@@ -268,10 +260,6 @@ class FullCodeGenerator: public AstVisitor {
: NestedStatement(codegen), deferred_commands_(commands) {} : NestedStatement(codegen), deferred_commands_(commands) {}
NestedStatement* Exit(int* stack_depth, int* context_length) override; NestedStatement* Exit(int* stack_depth, int* context_length) override;
NestedStatement* AccumulateDepth(int* stack_depth) override {
*stack_depth += kElementCount;
return previous_;
}
bool IsTryFinally() override { return true; } bool IsTryFinally() override { return true; }
TryFinally* AsTryFinally() override { return this; } TryFinally* AsTryFinally() override { return this; }
...@@ -293,10 +281,6 @@ class FullCodeGenerator: public AstVisitor { ...@@ -293,10 +281,6 @@ class FullCodeGenerator: public AstVisitor {
*stack_depth += kElementCount; *stack_depth += kElementCount;
return previous_; return previous_;
} }
NestedStatement* AccumulateDepth(int* stack_depth) override {
*stack_depth += kElementCount;
return previous_;
}
}; };
// The body of a for/in loop. // The body of a for/in loop.
...@@ -312,10 +296,6 @@ class FullCodeGenerator: public AstVisitor { ...@@ -312,10 +296,6 @@ class FullCodeGenerator: public AstVisitor {
*stack_depth += kElementCount; *stack_depth += kElementCount;
return previous_; return previous_;
} }
NestedStatement* AccumulateDepth(int* stack_depth) override {
*stack_depth += kElementCount;
return previous_;
}
}; };
...@@ -400,18 +380,21 @@ class FullCodeGenerator: public AstVisitor { ...@@ -400,18 +380,21 @@ class FullCodeGenerator: public AstVisitor {
MemOperand VarOperand(Variable* var, Register scratch); MemOperand VarOperand(Variable* var, Register scratch);
void VisitForEffect(Expression* expr) { void VisitForEffect(Expression* expr) {
if (FLAG_verify_operand_stack_depth) EmitOperandStackDepthCheck();
EffectContext context(this); EffectContext context(this);
Visit(expr); Visit(expr);
PrepareForBailout(expr, NO_REGISTERS); PrepareForBailout(expr, NO_REGISTERS);
} }
void VisitForAccumulatorValue(Expression* expr) { void VisitForAccumulatorValue(Expression* expr) {
if (FLAG_verify_operand_stack_depth) EmitOperandStackDepthCheck();
AccumulatorValueContext context(this); AccumulatorValueContext context(this);
Visit(expr); Visit(expr);
PrepareForBailout(expr, TOS_REG); PrepareForBailout(expr, TOS_REG);
} }
void VisitForStackValue(Expression* expr) { void VisitForStackValue(Expression* expr) {
if (FLAG_verify_operand_stack_depth) EmitOperandStackDepthCheck();
StackValueContext context(this); StackValueContext context(this);
Visit(expr); Visit(expr);
PrepareForBailout(expr, NO_REGISTERS); PrepareForBailout(expr, NO_REGISTERS);
...@@ -421,6 +404,7 @@ class FullCodeGenerator: public AstVisitor { ...@@ -421,6 +404,7 @@ class FullCodeGenerator: public AstVisitor {
Label* if_true, Label* if_true,
Label* if_false, Label* if_false,
Label* fall_through) { Label* fall_through) {
if (FLAG_verify_operand_stack_depth) EmitOperandStackDepthCheck();
TestContext context(this, expr, if_true, if_false, fall_through); TestContext context(this, expr, if_true, if_false, fall_through);
Visit(expr); Visit(expr);
// For test contexts, we prepare for bailout before branching, not at // For test contexts, we prepare for bailout before branching, not at
...@@ -435,6 +419,34 @@ class FullCodeGenerator: public AstVisitor { ...@@ -435,6 +419,34 @@ class FullCodeGenerator: public AstVisitor {
void DeclareGlobals(Handle<FixedArray> pairs); void DeclareGlobals(Handle<FixedArray> pairs);
int DeclareGlobalsFlags(); int DeclareGlobalsFlags();
// Push, pop or drop values onto/from the operand stack.
void PushOperand(Register reg);
void PopOperand(Register reg);
void DropOperands(int count);
// Convenience helpers for pushing onto the operand stack.
void PushOperand(MemOperand operand);
void PushOperand(Handle<Object> handle);
void PushOperand(Smi* smi);
// Convenience helpers for pushing/popping multiple operands.
void PushOperands(Register reg1, Register reg2);
void PushOperands(Register reg1, Register reg2, Register reg3);
void PushOperands(Register reg1, Register reg2, Register reg3, Register reg4);
void PopOperands(Register reg1, Register reg2);
// Convenience helper for calling a runtime function that consumes arguments
// from the operand stack (only usable for functions with known arity).
void CallRuntimeWithOperands(Runtime::FunctionId function_id);
// Static tracking of the operand stack depth.
void OperandStackDepthDecrement(int count);
void OperandStackDepthIncrement(int count);
// Generate debug code that verifies that our static tracking of the operand
// stack depth is in sync with the actual operand stack during runtime.
void EmitOperandStackDepthCheck();
// Generate code to create an iterator result object. The "value" property is // Generate code to create an iterator result object. The "value" property is
// set to a value popped from the stack, and "done" is set according to the // set to a value popped from the stack, and "done" is set according to the
// argument. The result object is left in the result register. // argument. The result object is left in the result register.
...@@ -987,6 +999,7 @@ class FullCodeGenerator: public AstVisitor { ...@@ -987,6 +999,7 @@ class FullCodeGenerator: public AstVisitor {
NestedStatement* nesting_stack_; NestedStatement* nesting_stack_;
int loop_depth_; int loop_depth_;
int try_catch_depth_; int try_catch_depth_;
int operand_stack_depth_;
ZoneList<Handle<Object> >* globals_; ZoneList<Handle<Object> >* globals_;
Handle<FixedArray> modules_; Handle<FixedArray> modules_;
int module_index_; int module_index_;
......
This diff is collapsed.
This diff is collapsed.
...@@ -540,21 +540,6 @@ void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const { ...@@ -540,21 +540,6 @@ void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
} }
void FullCodeGenerator::EffectContext::DropAndPlug(int count,
Register reg) const {
DCHECK(count > 0);
__ Drop(count);
}
void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
int count, Register reg) const {
DCHECK(count > 0);
__ Drop(count);
__ Move(result_register(), reg);
}
void FullCodeGenerator::StackValueContext::DropAndPlug(int count, void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
Register reg) const { Register reg) const {
DCHECK(count > 0); DCHECK(count > 0);
...@@ -563,17 +548,6 @@ void FullCodeGenerator::StackValueContext::DropAndPlug(int count, ...@@ -563,17 +548,6 @@ void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
} }
void FullCodeGenerator::TestContext::DropAndPlug(int count,
Register reg) const {
DCHECK(count > 0);
// For simplicity we always test the accumulator register.
__ Drop(count);
__ Move(result_register(), reg);
codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
codegen()->DoTest(this);
}
void FullCodeGenerator::EffectContext::Plug(Label* materialize_true, void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
Label* materialize_false) const { Label* materialize_false) const {
DCHECK(materialize_true == materialize_false); DCHECK(materialize_true == materialize_false);
...@@ -2076,34 +2050,6 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { ...@@ -2076,34 +2050,6 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
} }
void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) {
// Stack: receiver, home_object.
SetExpressionPosition(prop);
Literal* key = prop->key()->AsLiteral();
DCHECK(!key->value()->IsSmi());
DCHECK(prop->IsSuperAccess());
__ Push(key->value());
__ CallRuntime(Runtime::kLoadFromSuper);
}
void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
SetExpressionPosition(prop);
Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
__ mov(LoadDescriptor::SlotRegister(),
Operand(SmiFromSlot(prop->PropertyFeedbackSlot())));
CallIC(ic);
}
void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) {
// Stack: receiver, home_object, key.
SetExpressionPosition(prop);
__ CallRuntime(Runtime::kLoadKeyedFromSuper);
}
void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
Token::Value op, Token::Value op,
Expression* left_expr, Expression* left_expr,
......
This diff is collapsed.
...@@ -507,22 +507,6 @@ void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const { ...@@ -507,22 +507,6 @@ void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
} }
void FullCodeGenerator::EffectContext::DropAndPlug(int count,
Register reg) const {
DCHECK(count > 0);
__ Drop(count);
}
void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
int count,
Register reg) const {
DCHECK(count > 0);
__ Drop(count);
__ Move(result_register(), reg);
}
void FullCodeGenerator::StackValueContext::DropAndPlug(int count, void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
Register reg) const { Register reg) const {
DCHECK(count > 0); DCHECK(count > 0);
...@@ -531,17 +515,6 @@ void FullCodeGenerator::StackValueContext::DropAndPlug(int count, ...@@ -531,17 +515,6 @@ void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
} }
void FullCodeGenerator::TestContext::DropAndPlug(int count,
Register reg) const {
DCHECK(count > 0);
// For simplicity we always test the accumulator register.
__ Drop(count);
__ Move(result_register(), reg);
codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
codegen()->DoTest(this);
}
void FullCodeGenerator::EffectContext::Plug(Label* materialize_true, void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
Label* materialize_false) const { Label* materialize_false) const {
DCHECK(materialize_true == materialize_false); DCHECK(materialize_true == materialize_false);
...@@ -2005,34 +1978,6 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { ...@@ -2005,34 +1978,6 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
} }
void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) {
// Stack: receiver, home_object.
SetExpressionPosition(prop);
Literal* key = prop->key()->AsLiteral();
DCHECK(!key->value()->IsSmi());
DCHECK(prop->IsSuperAccess());
__ push(Immediate(key->value()));
__ CallRuntime(Runtime::kLoadFromSuper);
}
void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
SetExpressionPosition(prop);
Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
__ mov(LoadDescriptor::SlotRegister(),
Immediate(SmiFromSlot(prop->PropertyFeedbackSlot())));
CallIC(ic);
}
void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) {
// Stack: receiver, home_object, key.
SetExpressionPosition(prop);
__ CallRuntime(Runtime::kLoadKeyedFromSuper);
}
void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
Token::Value op, Token::Value op,
Expression* left, Expression* left,
......
...@@ -952,6 +952,7 @@ void WeakCell::WeakCellPrint(std::ostream& os) { // NOLINT ...@@ -952,6 +952,7 @@ void WeakCell::WeakCellPrint(std::ostream& os) { // NOLINT
void Code::CodePrint(std::ostream& os) { // NOLINT void Code::CodePrint(std::ostream& os) { // NOLINT
HeapObject::PrintHeader(os, "Code"); HeapObject::PrintHeader(os, "Code");
os << "\n";
#ifdef ENABLE_DISASSEMBLER #ifdef ENABLE_DISASSEMBLER
if (FLAG_use_verbose_printer) { if (FLAG_use_verbose_printer) {
Disassemble(NULL, os); Disassemble(NULL, os);
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-do-expressions
(function DoTryCatchInsideBinop() {
function f(a, b) {
return a + do { try { throw "boom" } catch(e) { b } }
}
assertEquals(3, f(1, 2));
assertEquals(3, f(1, 2));
%OptimizeFunctionOnNextCall(f);
assertEquals(3, f(1, 2));
})();
(function DoTryCatchInsideCall() {
function f(a, b) {
return Math.max(a, do { try { throw a } catch(e) { e + b } })
}
assertEquals(3, f(1, 2));
assertEquals(3, f(1, 2));
%OptimizeFunctionOnNextCall(f);
assertEquals(3, f(1, 2));
})();
(function DoTryCatchInsideTry() {
function f(a, b) {
try { return do { try { throw a } catch(e) { e + b } } } catch(e) {}
}
assertEquals(3, f(1, 2));
assertEquals(3, f(1, 2));
%OptimizeFunctionOnNextCall(f);
assertEquals(3, f(1, 2));
})();
(function DoTryCatchInsideFinally() {
function f(a, b) {
try {} finally { return do { try { throw a } catch(e) { e + b } } }
}
assertEquals(3, f(1, 2));
assertEquals(3, f(1, 2));
%OptimizeFunctionOnNextCall(f);
assertEquals(3, f(1, 2));
})();
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