Mark returns from inside the try of a try/catch as ones that exit the try.

At construction time, jumps from within the try block of a try/catch are
marked as ones that exit the try block.  This is relied on for correctness.
Specifically, it prevents moving code from outside the try into the scope of
the try.

Return jumps were from within the try were not marked because it was
unnecessary.  In the presence of inlining, returns are turned into jumps to a
local join-point continuation.  These jumps must be marked for correctness.

R=asgerf@google.com
BUG=

Review URL: https://codereview.chromium.org/1414043011 .
This commit is contained in:
Kevin Millikin 2015-11-06 09:31:07 +01:00
parent 95bb2159d9
commit 45004655a1

View file

@ -159,6 +159,13 @@ abstract class JumpCollector {
if (hasExtraArgument) _continuationEnvironment.extend(null, null);
}
/// Construct a collector for collecting only return jumps.
///
/// There is no jump target, it is implicitly the exit from the function.
/// There is no environment at the destination.
JumpCollector.retrn(this._continuation)
: _continuationEnvironment = null, target = null;
/// True if the collector has not recorded any jumps to its continuation.
bool get isEmpty;
@ -175,7 +182,8 @@ abstract class JumpCollector {
/// values to finally blocks for returns inside try/finally and to pass
/// values of expressions that have internal control flow to their join-point
/// continuations.
void addJump(IrBuilder builder, [ir.Primitive value]);
void addJump(IrBuilder builder,
[ir.Primitive value, SourceInformation sourceInformation]);
/// Add a set of variables that were boxed on entry to a try block.
///
@ -259,7 +267,8 @@ class ForwardJumpCollector extends JumpCollector {
return _continuationEnvironment;
}
void addJump(IrBuilder builder, [ir.Primitive value]) {
void addJump(IrBuilder builder,
[ir.Primitive value, SourceInformation sourceInformation]) {
assert(_continuation == null);
_buildTryExit(builder);
ir.InvokeContinuation invoke = new ir.InvokeContinuation.uninitialized(
@ -368,7 +377,8 @@ class BackwardJumpCollector extends JumpCollector {
ir.Continuation get continuation => _continuation;
Environment get environment => _continuationEnvironment;
void addJump(IrBuilder builder, [ir.Primitive value]) {
void addJump(IrBuilder builder,
[ir.Primitive value, SourceInformation sourceInformation]) {
assert(_continuation.parameters.length <= builder.environment.length);
isEmpty = false;
_buildTryExit(builder);
@ -388,6 +398,29 @@ class BackwardJumpCollector extends JumpCollector {
}
}
/// Collect 'return' jumps.
///
/// A return jump is one that targets the return continuation of a function.
/// Thus, returns from inside try/finally are not return jumps because they are
/// intercepted by a block that contains the finally handler code.
class ReturnJumpCollector extends JumpCollector {
bool isEmpty = true;
ir.Continuation get continuation => _continuation;
Environment environment = null;
/// Construct a return jump collector for a given return continuation.
ReturnJumpCollector(ir.Continuation continuation) : super.retrn(continuation);
void addJump(IrBuilder builder,
[ir.Primitive value, SourceInformation sourceInformation]) {
isEmpty = false;
builder.add(new ir.InvokeContinuation(continuation, <ir.Primitive>[value],
isEscapingTry: isEscapingTry,
sourceInformation: sourceInformation));
builder._current = null;
}
}
/// Function for building a node in the context of the current builder.
typedef ir.Node BuildFunction(node);
@ -466,7 +499,7 @@ class IrBuilderSharedState {
/// A null value indicates that the target is the function's return
/// continuation. Otherwise, when inside the try block of try/finally
/// a return is intercepted to give a place to generate the finally code.
JumpCollector returnCollector = null;
JumpCollector returnCollector;
/// Parameter holding the internal value of 'this' passed to the function.
///
@ -483,7 +516,9 @@ class IrBuilderSharedState {
/// the environment.
final Map<Local, ClosureLocation> boxedVariables = {};
IrBuilderSharedState(this.program, this.constants, this.currentElement);
IrBuilderSharedState(this.program, this.constants, this.currentElement) {
returnCollector = new ReturnJumpCollector(returnContinuation);
}
}
class ThisParameterLocal implements Local {
@ -1160,8 +1195,9 @@ class IrBuilder {
}
}
void jumpTo(JumpCollector collector, [ir.Primitive value]) {
collector.addJump(this, value);
void jumpTo(JumpCollector collector,
[ir.Primitive value, SourceInformation sourceInformation]) {
collector.addJump(this, value, sourceInformation);
}
void addRecursiveContinuation(BackwardJumpCollector collector) {
@ -1811,6 +1847,7 @@ class IrBuilder {
}
builder.state.breakCollectors.forEach(interceptJump);
builder.state.continueCollectors.forEach(interceptJump);
interceptJump(builder.state.returnCollector);
}
void leaveTry(IrBuilder builder) {
@ -1821,6 +1858,7 @@ class IrBuilder {
}
builder.state.breakCollectors.forEach(restoreJump);
builder.state.continueCollectors.forEach(restoreJump);
restoreJump(builder.state.returnCollector);
}
List<ir.Parameter> buildCatch(IrBuilder builder,
@ -2029,16 +2067,7 @@ class IrBuilder {
if (value == null) {
value = buildNullConstant();
}
if (state.returnCollector == null) {
add(new ir.InvokeContinuation(state.returnContinuation, [value],
sourceInformation: sourceInformation));
_current = null;
} else {
// Inside the try block of try/finally, all returns go to a join-point
// continuation that contains the finally code. The return value is
// passed as an extra argument.
jumpTo(state.returnCollector, value);
}
jumpTo(state.returnCollector, value, sourceInformation);
}
/// Build a call to the closure conversion helper for the [Function] typed