Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(213)

Unified Diff: pkg/compiler/lib/src/native/js.dart

Issue 1074043003: Compute default throws behavior from JavaScript. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/compiler/lib/src/native/behavior.dart ('k') | pkg/compiler/lib/src/ssa/builder.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/native/js.dart
diff --git a/pkg/compiler/lib/src/native/js.dart b/pkg/compiler/lib/src/native/js.dart
index 1cbe8da5c8fb978d81a05f35d7e040febc8b2e19..2203b55f19394d1e10bb928db11461a0dee10283 100644
--- a/pkg/compiler/lib/src/native/js.dart
+++ b/pkg/compiler/lib/src/native/js.dart
@@ -81,3 +81,187 @@ class SideEffectsVisitor extends js.BaseVisitor {
node.visitChildren(this);
}
}
+
+
+/// ThrowBehaviorVisitor generates a NativeThrowBehavior describing the
+/// exception behavior of a JavaScript expression.
+///
+/// The result is semi-conservative, giving reasonable results for many simple
+/// JS fragments. The non-conservative part is the assumption that binary
+/// operators are used on 'good' operands that do not force arbirary code to be
+/// executed via conversions (valueOf() and toString() methods).
+///
+/// In many cases a JS fragment has more precise behavior. In these cases the
+/// behavior should be described as a property of the JS fragment. For example,
+/// Object.keys(#) has a TypeError on null / undefined, which can only be known
+/// in the calling context.
+///
+class ThrowBehaviorVisitor extends js.BaseVisitor<NativeThrowBehavior> {
+
+ ThrowBehaviorVisitor();
+
+ NativeThrowBehavior analyze(js.Node node) {
+ return visit(node);
+ }
+
+ // TODO(sra): Add [sequence] functionality to NativeThrowBehavior.
+ /// Returns the combined behavior of sequential execution of code having
+ /// behavior [first] followed by code having behavior [second].
+ static NativeThrowBehavior sequence(NativeThrowBehavior first,
+ NativeThrowBehavior second) {
+ if (first == NativeThrowBehavior.MUST) return first;
+ if (second == NativeThrowBehavior.MUST) return second;
+ if (second == NativeThrowBehavior.NEVER) return first;
+ if (first == NativeThrowBehavior.NEVER) return second;
+ // Both are one of MAY or MAY_THROW_ONLY_ON_FIRST_ARGUMENT_ACCESS.
+ return NativeThrowBehavior.MAY;
+ }
+
+ // TODO(sra): Add [choice] functionality to NativeThrowBehavior.
+ /// Returns the combined behavior of a choice between two paths with behaviors
+ /// [first] and [second].
+ static NativeThrowBehavior choice(NativeThrowBehavior first,
+ NativeThrowBehavior second) {
+ if (first == second) return first; // Both paths have same behaviour.
+ return NativeThrowBehavior.MAY;
+ }
+
+ NativeThrowBehavior visit(js.Node node) {
+ return node.accept(this);
+ }
+
+ NativeThrowBehavior visitNode(js.Node node) {
+ return NativeThrowBehavior.MAY;
+ }
+
+ NativeThrowBehavior visitLiteral(js.Literal node) {
+ return NativeThrowBehavior.NEVER;
+ }
+
+ NativeThrowBehavior visitInterpolatedExpression(js.InterpolatedNode node) {
+ return NativeThrowBehavior.NEVER;
+ }
+
+ NativeThrowBehavior visitInterpolatedSelector(js.InterpolatedNode node) {
+ return NativeThrowBehavior.NEVER;
+ }
+
+ NativeThrowBehavior visitObjectInitializer(js.ObjectInitializer node) {
+ NativeThrowBehavior result = NativeThrowBehavior.NEVER;
+ for (js.Property property in node.properties) {
+ result = sequence(result, visit(property));
+ }
+ return result;
+ }
+
+ NativeThrowBehavior visitProperty(js.Property node) {
+ return sequence(visit(node.name), visit(node.value));
+ }
+
+ NativeThrowBehavior visitAssignment(js.Assignment node) {
+ // TODO(sra): Can we make "#.p = #" be null(1)?
+ return NativeThrowBehavior.MAY;
+ }
+
+ NativeThrowBehavior visitCall(js.Call node) {
+ return NativeThrowBehavior.MAY;
+ }
+
+ NativeThrowBehavior visitNew(js.New node) {
+ // TODO(sra): `new Array(x)` where `x` is a small number.
+ return NativeThrowBehavior.MAY;
+ }
+
+ NativeThrowBehavior visitBinary(js.Binary node) {
+ NativeThrowBehavior left = visit(node.left);
+ NativeThrowBehavior right = visit(node.right);
+ switch (node.op) {
+ // We make the non-conservative assumption that these operations are not
+ // used in ways that force calling arbitrary code via valueOf or
+ // toString().
+ case "*":
+ case "/":
+ case "%":
+ case "+":
+ case "-":
+ case "<<":
+ case ">>":
+ case ">>>":
+ case "<":
+ case ">":
+ case "<=":
+ case ">=":
+ case "==":
+ case "===":
+ case "!=":
+ case "!==":
+ case "&":
+ case "^":
+ case "|":
+ return sequence(left, right);
+
+ case ',':
+ return sequence(left, right);
+
+ case "&&":
+ case "||":
+ return choice(left, sequence(left, right));
+
+ case "instanceof":
+ case "in":
+ default:
+ return NativeThrowBehavior.MAY;
+ }
+ }
+
+ NativeThrowBehavior visitThrow(js.Throw node) {
+ return NativeThrowBehavior.MUST;
+ }
+
+ NativeThrowBehavior visitPrefix(js.Prefix node) {
+ if (node.op == 'typeof' && node.argument is js.VariableUse)
+ return NativeThrowBehavior.NEVER;
+ NativeThrowBehavior result = visit(node.argument);
+ switch (node.op) {
+ case '!':
+ case '~':
+ case 'void':
+ case 'typeof':
+ return result;
+ default:
+ return NativeThrowBehavior.MAY;
+ }
+ }
+
+ NativeThrowBehavior visitVariableUse(js.VariableUse node) {
+ // We could get a ReferenceError unless the variable is in scope. The AST
+ // could distinguish in-scope and out-of scope references. For JS fragments,
+ // the only use of VariableUse should be for global references. Certain
+ // global names are almost certainly not reference errors, e.g 'Array'.
+ switch (node.name) {
+ case 'Array':
+ case 'Object':
+ return NativeThrowBehavior.NEVER;
+ default:
+ return NativeThrowBehavior.MAY;
+ }
+ }
+
+ NativeThrowBehavior visitAccess(js.PropertyAccess node) {
+ // TODO(sra): We need a representation where the nsm guard behaviour is
+ // maintained when combined with other throwing behaviour.
+ js.Node receiver = node.receiver;
+ NativeThrowBehavior first = visit(receiver);
+ NativeThrowBehavior second = visit(node.selector);
+
+ if (receiver is js.InterpolatedExpression &&
+ receiver.isPositional &&
+ receiver.nameOrPosition == 0) {
+ first = NativeThrowBehavior.MAY_THROW_ONLY_ON_FIRST_ARGUMENT_ACCESS;
+ } else {
+ first = NativeThrowBehavior.MAY;
+ }
+
+ return sequence(first, second);
+ }
+}
« no previous file with comments | « pkg/compiler/lib/src/native/behavior.dart ('k') | pkg/compiler/lib/src/ssa/builder.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698