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 {
"Unexpected number of pre-allocated property fields") \
V(kUnexpectedFPCRMode, "Unexpected FPCR mode.") \
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(kUnexpectedStringType, "Unexpected string type") \
V(kUnexpectedTypeForRegExpDataFixedArrayExpected, \
......
......@@ -637,6 +637,9 @@ DEFINE_INT(max_stack_trace_source_length, 300,
// full-codegen.cc
DEFINE_BOOL(always_inline_smi_code, false,
"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
DEFINE_INT(min_semi_space_size, 0,
......
This diff is collapsed.
This diff is collapsed.
......@@ -42,6 +42,7 @@ class FullCodeGenerator: public AstVisitor {
nesting_stack_(NULL),
loop_depth_(0),
try_catch_depth_(0),
operand_stack_depth_(0),
globals_(NULL),
context_(NULL),
bailout_entries_(info->HasDeoptimizationSupport()
......@@ -136,11 +137,6 @@ class FullCodeGenerator: public AstVisitor {
return previous_;
}
// Like the Exit() method above, but limited to accumulating stack depth.
virtual NestedStatement* AccumulateDepth(int* stack_depth) {
return previous_;
}
protected:
MacroAssembler* masm() { return codegen_->masm(); }
......@@ -216,10 +212,6 @@ class FullCodeGenerator: public AstVisitor {
*stack_depth += kElementCount;
return previous_;
}
NestedStatement* AccumulateDepth(int* stack_depth) override {
*stack_depth += kElementCount;
return previous_;
}
};
class DeferredCommands {
......@@ -268,10 +260,6 @@ class FullCodeGenerator: public AstVisitor {
: NestedStatement(codegen), deferred_commands_(commands) {}
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; }
TryFinally* AsTryFinally() override { return this; }
......@@ -293,10 +281,6 @@ class FullCodeGenerator: public AstVisitor {
*stack_depth += kElementCount;
return previous_;
}
NestedStatement* AccumulateDepth(int* stack_depth) override {
*stack_depth += kElementCount;
return previous_;
}
};
// The body of a for/in loop.
......@@ -312,10 +296,6 @@ class FullCodeGenerator: public AstVisitor {
*stack_depth += kElementCount;
return previous_;
}
NestedStatement* AccumulateDepth(int* stack_depth) override {
*stack_depth += kElementCount;
return previous_;
}
};
......@@ -400,18 +380,21 @@ class FullCodeGenerator: public AstVisitor {
MemOperand VarOperand(Variable* var, Register scratch);
void VisitForEffect(Expression* expr) {
if (FLAG_verify_operand_stack_depth) EmitOperandStackDepthCheck();
EffectContext context(this);
Visit(expr);
PrepareForBailout(expr, NO_REGISTERS);
}
void VisitForAccumulatorValue(Expression* expr) {
if (FLAG_verify_operand_stack_depth) EmitOperandStackDepthCheck();
AccumulatorValueContext context(this);
Visit(expr);
PrepareForBailout(expr, TOS_REG);
}
void VisitForStackValue(Expression* expr) {
if (FLAG_verify_operand_stack_depth) EmitOperandStackDepthCheck();
StackValueContext context(this);
Visit(expr);
PrepareForBailout(expr, NO_REGISTERS);
......@@ -421,6 +404,7 @@ class FullCodeGenerator: public AstVisitor {
Label* if_true,
Label* if_false,
Label* fall_through) {
if (FLAG_verify_operand_stack_depth) EmitOperandStackDepthCheck();
TestContext context(this, expr, if_true, if_false, fall_through);
Visit(expr);
// For test contexts, we prepare for bailout before branching, not at
......@@ -435,6 +419,34 @@ class FullCodeGenerator: public AstVisitor {
void DeclareGlobals(Handle<FixedArray> pairs);
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
// 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.
......@@ -987,6 +999,7 @@ class FullCodeGenerator: public AstVisitor {
NestedStatement* nesting_stack_;
int loop_depth_;
int try_catch_depth_;
int operand_stack_depth_;
ZoneList<Handle<Object> >* globals_;
Handle<FixedArray> modules_;
int module_index_;
......
This diff is collapsed.
This diff is collapsed.
......@@ -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,
Register reg) const {
DCHECK(count > 0);
......@@ -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,
Label* materialize_false) const {
DCHECK(materialize_true == materialize_false);
......@@ -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,
Token::Value op,
Expression* left_expr,
......
This diff is collapsed.
......@@ -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,
Register reg) const {
DCHECK(count > 0);
......@@ -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,
Label* materialize_false) const {
DCHECK(materialize_true == materialize_false);
......@@ -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,
Token::Value op,
Expression* left,
......
......@@ -952,6 +952,7 @@ void WeakCell::WeakCellPrint(std::ostream& os) { // NOLINT
void Code::CodePrint(std::ostream& os) { // NOLINT
HeapObject::PrintHeader(os, "Code");
os << "\n";
#ifdef ENABLE_DISASSEMBLER
if (FLAG_use_verbose_printer) {
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