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 |