Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of native; | 5 part of native; |
| 6 | 6 |
| 7 class SideEffectsVisitor extends js.BaseVisitor { | 7 class SideEffectsVisitor extends js.BaseVisitor { |
| 8 final SideEffects sideEffects; | 8 final SideEffects sideEffects; |
| 9 SideEffectsVisitor(this.sideEffects); | 9 SideEffectsVisitor(this.sideEffects); |
| 10 | 10 |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 74 node.visitChildren(this); | 74 node.visitChildren(this); |
| 75 } | 75 } |
| 76 | 76 |
| 77 void visitAccess(js.PropertyAccess node) { | 77 void visitAccess(js.PropertyAccess node) { |
| 78 sideEffects.setDependsOnIndexStore(); | 78 sideEffects.setDependsOnIndexStore(); |
| 79 sideEffects.setDependsOnInstancePropertyStore(); | 79 sideEffects.setDependsOnInstancePropertyStore(); |
| 80 sideEffects.setDependsOnStaticPropertyStore(); | 80 sideEffects.setDependsOnStaticPropertyStore(); |
| 81 node.visitChildren(this); | 81 node.visitChildren(this); |
| 82 } | 82 } |
| 83 } | 83 } |
| 84 | |
| 85 | |
| 86 /// ThrowBehaviorVisitor generates a NativeThrowBehavior describing the | |
| 87 /// exception behavior of a JavaScript expression. | |
| 88 /// | |
| 89 /// The result is semi-conservative, giving reasonable results for many simple | |
| 90 /// JS fragments. The non-conservative part is the assumption that binary | |
| 91 /// operators are used on 'good' operands thatdo not force arbirary code to be | |
|
floitsch
2015/04/10 13:34:16
that do
sra1
2015/04/10 15:57:48
Done.
| |
| 92 /// executed via conversions (valueOf() and toString() methods). | |
| 93 /// | |
| 94 /// In many cases a JS fragment has more precise behavior. In these cases the | |
| 95 /// behavior should be described as a property of the JS fragment. | |
| 96 /// | |
| 97 class ThrowBehaviorVisitor extends js.BaseVisitor<NativeThrowBehavior> { | |
| 98 | |
| 99 ThrowBehaviorVisitor(); | |
| 100 | |
| 101 NativeThrowBehavior analyze(js.Node node) { | |
| 102 return visit(node); | |
| 103 } | |
| 104 | |
| 105 // TODO(sra): Add [sequence] functionality to NativeThrowBehavior. | |
| 106 static NativeThrowBehavior sequence(NativeThrowBehavior first, | |
|
floitsch
2015/04/10 13:34:16
Add comment explaining what this is.
(probably my
sra1
2015/04/10 15:57:48
Done.
| |
| 107 NativeThrowBehavior second) { | |
| 108 if (first == NativeThrowBehavior.MUST) return first; | |
| 109 if (second == NativeThrowBehavior.MUST) return second; | |
| 110 if (second == NativeThrowBehavior.NEVER) return first; | |
| 111 if (first == NativeThrowBehavior.NEVER) return second; | |
| 112 // Both are one of MAY or MAY_THROW_ONLY_ON_FIRST_ARGUMENT_ACCESS. | |
| 113 return NativeThrowBehavior.MAY; | |
| 114 } | |
| 115 | |
| 116 // TODO(sra): Add [choice] functionality to NativeThrowBehavior. | |
| 117 static NativeThrowBehavior choice(NativeThrowBehavior first, | |
| 118 NativeThrowBehavior second) { | |
| 119 if (first == second) return first; // Both paths have same behaviour. | |
| 120 return NativeThrowBehavior.MAY; | |
| 121 } | |
| 122 | |
| 123 NativeThrowBehavior visit(js.Node node) { | |
| 124 return node.accept(this); | |
| 125 } | |
| 126 | |
| 127 NativeThrowBehavior visitNode(js.Node node) { | |
| 128 return NativeThrowBehavior.MAY; | |
| 129 } | |
| 130 | |
| 131 NativeThrowBehavior visitLiteral(js.Literal node) { | |
| 132 return NativeThrowBehavior.NEVER; | |
| 133 } | |
| 134 | |
| 135 NativeThrowBehavior visitInterpolatedExpression(js.InterpolatedNode node) { | |
| 136 return NativeThrowBehavior.NEVER; | |
| 137 } | |
| 138 | |
| 139 NativeThrowBehavior visitInterpolatedSelector(js.InterpolatedNode node) { | |
| 140 return NativeThrowBehavior.NEVER; | |
| 141 } | |
| 142 | |
| 143 NativeThrowBehavior visitObjectInitializer(js.ObjectInitializer node) { | |
| 144 NativeThrowBehavior result = NativeThrowBehavior.NEVER; | |
| 145 for (js.Property property in node.properties) { | |
| 146 result = sequence(result, visit(property)); | |
| 147 } | |
| 148 return result; | |
| 149 } | |
| 150 | |
| 151 NativeThrowBehavior visitProperty(js.Property node) { | |
| 152 return sequence(visit(node.name), visit(node.value)); | |
| 153 } | |
| 154 | |
| 155 NativeThrowBehavior visitAssignment(js.Assignment node) { | |
| 156 // TODO(sra): Can we make "#.p = #" be null(1)? | |
| 157 return NativeThrowBehavior.MAY; | |
| 158 } | |
| 159 | |
| 160 NativeThrowBehavior visitCall(js.Call node) { | |
| 161 return NativeThrowBehavior.MAY; | |
| 162 } | |
| 163 | |
| 164 NativeThrowBehavior visitNew(js.New node) { | |
| 165 // TODO(sra): `new Array(x)` where `x` is is a small number. | |
|
floitsch
2015/04/10 13:34:16
-is-
sra1
2015/04/10 15:57:48
Done.
| |
| 166 return NativeThrowBehavior.MAY; | |
| 167 } | |
| 168 | |
| 169 NativeThrowBehavior visitBinary(js.Binary node) { | |
| 170 NativeThrowBehavior left = visit(node.left); | |
| 171 NativeThrowBehavior right = visit(node.right); | |
| 172 switch (node.op) { | |
| 173 // We make the non-conservative assumption that these operations are not | |
| 174 // used in ways that force calling arbitrary code via valueOf or | |
| 175 // toString(). | |
| 176 case "*": | |
| 177 case "/": | |
| 178 case "%": | |
| 179 case "+": | |
| 180 case "-": | |
| 181 case "<<": | |
| 182 case ">>": | |
| 183 case ">>>": | |
| 184 case "<": | |
| 185 case ">": | |
| 186 case "<=": | |
| 187 case ">=": | |
| 188 case "==": | |
| 189 case "===": | |
| 190 case "!=": | |
| 191 case "!==": | |
| 192 case "&": | |
| 193 case "^": | |
| 194 case "|": | |
| 195 return sequence(left, right); | |
| 196 | |
| 197 case ',': | |
| 198 return sequence(left, right); | |
| 199 | |
| 200 case "&&": | |
| 201 case "||": | |
| 202 return choice(left, sequence(left, right)); | |
| 203 | |
| 204 case "instanceof": | |
| 205 case "in": | |
| 206 default: | |
| 207 return NativeThrowBehavior.MAY; | |
| 208 } | |
| 209 } | |
| 210 | |
| 211 NativeThrowBehavior visitThrow(js.Throw node) { | |
| 212 return NativeThrowBehavior.MUST; | |
| 213 } | |
| 214 | |
| 215 NativeThrowBehavior visitPrefix(js.Prefix node) { | |
| 216 NativeThrowBehavior result = visit(node.argument); | |
| 217 switch (node.op) { | |
| 218 case '!': | |
| 219 case '~': | |
| 220 case 'void': | |
| 221 case 'typeof': | |
| 222 return result; | |
| 223 default: | |
| 224 return NativeThrowBehavior.MAY; | |
| 225 } | |
| 226 } | |
| 227 | |
| 228 NativeThrowBehavior visitVariableUse(js.VariableUse node) { | |
| 229 // We could get a ReferenceError unless the variable is in scope. The AST | |
| 230 // could distinguish in-scope and out-of scope references. For JS | |
| 231 // fragments, the only use of VariableUse should be for gloabl references. | |
|
floitsch
2015/04/10 13:34:16
global
sra1
2015/04/10 15:57:48
Done.
| |
| 232 // Certain global names are almost certainly not reference errors, e.g | |
| 233 // 'Array'. | |
| 234 switch (node.name) { | |
| 235 case 'Array': | |
|
floitsch
2015/04/10 13:34:16
add
case 'Object':
sra1
2015/04/10 15:57:49
Done, but it is not really useful, since most uses
| |
| 236 return NativeThrowBehavior.NEVER; | |
| 237 default: | |
| 238 return NativeThrowBehavior.MAY; | |
| 239 } | |
| 240 } | |
| 241 | |
| 242 NativeThrowBehavior visitAccess(js.PropertyAccess node) { | |
| 243 // TODO(sra): We need a representation where the nsm guard behaviour is | |
| 244 // maintained when combined with other throwing behaviour. | |
| 245 js.Node receiver = node.receiver; | |
| 246 NativeThrowBehavior first = visit(receiver); | |
| 247 NativeThrowBehavior second = visit(node.selector); | |
| 248 | |
| 249 if (receiver is js.InterpolatedExpression && | |
| 250 receiver.isPositional && | |
| 251 receiver.nameOrPosition == 0) { | |
| 252 first = NativeThrowBehavior.MAY_THROW_ONLY_ON_FIRST_ARGUMENT_ACCESS; | |
| 253 } else { | |
| 254 first = NativeThrowBehavior.MAY; | |
| 255 } | |
| 256 | |
| 257 return sequence(first, second); | |
| 258 } | |
| 259 } | |
| OLD | NEW |