OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
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. | |
4 | |
5 library _foreign_helper; | |
6 | |
7 import 'dart:_js_embedded_names' show JsGetName, JsBuiltin; | |
8 | |
9 /** | |
10 * Emits a JavaScript code fragment parameterized by arguments. | |
11 * | |
12 * Hash characters `#` in the [codeTemplate] are replaced in left-to-right order | |
13 * with expressions that contain the values of, or evaluate to, the arguments. | |
14 * The number of hash marks must match the number or arguments. Although | |
15 * declared with arguments [arg0] through [arg2], the form actually has no limit | |
16 * on the number of arguments. | |
17 * | |
18 * The [typeDescription] argument is interpreted as a description of the | |
19 * behavior of the JavaScript code. Currently it describes the side effects | |
20 * types that may be returned by the expression, with the additional behavior | |
21 * that the returned values may be fresh instances of the types. The type | |
22 * information must be correct as it is trusted by the compiler in | |
23 * optimizations, and it must be precise as possible since it is used for native | |
24 * live type analysis to tree-shake large parts of the DOM libraries. If poorly | |
25 * written, the [typeDescription] will cause unnecessarily bloated programs. | |
26 * (You can check for this by compiling with `--verbose`; there is an info | |
27 * message describing the number of native (DOM) types that can be removed, | |
28 * which usually should be greater than zero.) | |
29 * | |
30 * The [typeDescription] must be a [String]. Two forms of it are supported: | |
31 * | |
32 * 1) a union of types separated by vertical bar `|` symbols, e.g. | |
33 * `"num|String"` describes the union of numbers and Strings. There is no | |
34 * type in Dart that is this precise. The Dart alternative would be `Object` | |
35 * or `dynamic`, but these types imply that the JS-code might also be | |
36 * creating instances of all the DOM types. | |
37 * | |
38 * If `null` is possible, it must be specified explicitly, e.g. | |
39 * `"String|Null"`. [typeDescription] has several extensions to help describe | |
40 * the behavior more accurately. In addition to the union type already | |
41 * described: | |
42 * | |
43 * + `=Object` is a plain JavaScript object. Some DOM methods return | |
44 * instances that have no corresponding Dart type (e.g. cross-frame | |
45 * documents), `=Object` can be used to describe these untyped' values. | |
46 * | |
47 * + `var` (or empty string). If the entire [typeDescription] is `var` (or | |
48 * empty string) then the type is `dynamic` but the code is known to not | |
49 * create any instances. | |
50 * | |
51 * Examples: | |
52 * | |
53 * // Parent window might be an opaque cross-frame window. | |
54 * var thing = JS('=Object|Window', '#.parent', myWindow); | |
55 * | |
56 * 2) a sequence of the form `<tag>:<value>;` where `<tag>` is one of | |
57 * `creates`, `returns`, `effects` or `depends`. | |
58 * | |
59 * The first two tags are used to specify the created and returned types of | |
60 * the expression. The value of `creates` and `returns` is a type string as | |
61 * defined in 1). | |
62 * | |
63 * The tags `effects` and `depends` encode the side effects of this call. | |
64 * They can be omitted, in which case the expression is parsed and a safe | |
65 * conservative side-effect estimation is computed. | |
66 * | |
67 * The values of `effects` and `depends` may be 'all', 'none' or a | |
68 * comma-separated list of 'no-index', 'no-instance' and 'no-static'. | |
69 * | |
70 * The value 'all' indicates that the call affects/depends on every | |
71 * side-effect. The flag 'none' signals that the call does not affect | |
72 * (resp. depends on) anything. | |
73 * | |
74 * The value 'no-index' indicates that the call does *not* do (resp. depends | |
75 * on) any array index-store. The flag 'no-instance' indicates that the call | |
76 * does not modify (resp. depends on) any instance variable. Similarly, | |
77 * the 'no-static' value indicates that the call does not modify (resp. | |
78 * depends on) any static variable. | |
79 * | |
80 * The `effects` and `depends` flag must be used in tandem. Either both are | |
81 * specified or none is. | |
82 * | |
83 * Each tag (including the type tags) may only occur once in the sequence. | |
84 * | |
85 * Guidelines: | |
86 * | |
87 * + Do not use any parameter, local, method or field names in the | |
88 * [codeTemplate]. These names are all subject to arbitrary renaming by the | |
89 * compiler. Pass the values in via `#` substition, and test with the | |
90 * `--minify` dart2js command-line option. | |
91 * | |
92 * + The substituted expressions are values, not locations. | |
93 * | |
94 * JS('void', '# += "x"', this.field); | |
95 * | |
96 * `this.field` might not be a substituted as a reference to the field. The | |
97 * generated code might accidentally work as intended, but it also might be | |
98 * | |
99 * var t1 = this.field; | |
100 * t1 += "x"; | |
101 * | |
102 * or | |
103 * | |
104 * this.get$field() += "x"; | |
105 * | |
106 * The remedy in this case is to expand the `+=` operator, leaving all | |
107 * references to the Dart field as Dart code: | |
108 * | |
109 * this.field = JS('String', '# + "x"', this.field); | |
110 * | |
111 * + Never use `#` in function bodies. | |
112 * | |
113 * This is a variation on the previous guideline. Since `#` is replaced with | |
114 * an *expression* and the expression is only valid in the immediate context, | |
115 * `#` should never appear in a function body. Doing so might defer the | |
116 * evaluation of the expression, and its side effects, until the function is | |
117 * called. | |
118 * | |
119 * For example, | |
120 * | |
121 * var value = foo(); | |
122 * var f = JS('', 'function(){return #}', value) | |
123 * | |
124 * might result in no immediate call to `foo` and a call to `foo` on every | |
125 * call to the JavaScript function bound to `f`. This is better: | |
126 * | |
127 * var f = JS('', | |
128 * '(function(val) { return function(){return val}; })(#)', value); | |
129 * | |
130 * Since `#` occurs in the immediately evaluated expression, the expression | |
131 * is immediately evaluated and bound to `val` in the immediate call. | |
132 * | |
133 * | |
134 * Additional notes. | |
135 * | |
136 * In the future we may extend [typeDescription] to include other aspects of the | |
137 * behavior, for example, separating the returned types from the instantiated | |
138 * types to allow the compiler to perform more optimizations around the code. | |
139 * | |
140 * This might be an extension of [JS] or a new function similar to [JS] with | |
141 * additional arguments for the new information. | |
142 */ | |
143 // Add additional optional arguments if needed. The method is treated internally | |
144 // as a variable argument method. | |
145 external JS(String typeDescription, String codeTemplate, | |
146 [arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11]); | |
147 | |
148 /** | |
149 * Returns the isolate in which this code is running. | |
150 */ | |
151 external IsolateContext JS_CURRENT_ISOLATE_CONTEXT(); | |
152 | |
153 abstract class IsolateContext { | |
154 /// Holds a (native) JavaScript instance of Isolate, see | |
155 /// finishIsolateConstructorFunction in emitter.dart. | |
156 get isolateStatics; | |
157 } | |
158 | |
159 /** | |
160 * Invokes [function] in the context of [isolate]. | |
161 */ | |
162 external JS_CALL_IN_ISOLATE(isolate, Function function); | |
163 | |
164 /** | |
165 * Converts the Dart closure [function] into a JavaScript closure. | |
166 * | |
167 * Warning: This is no different from [RAW_DART_FUNCTION_REF] which means care | |
168 * must be taken to store the current isolate. | |
169 */ | |
170 external DART_CLOSURE_TO_JS(Function function); | |
171 | |
172 /** | |
173 * Returns a raw reference to the JavaScript function which implements | |
174 * [function]. | |
175 * | |
176 * Warning: this is dangerous, you should probably use | |
177 * [DART_CLOSURE_TO_JS] instead. The returned object is not a valid | |
178 * Dart closure, does not store the isolate context or arity. | |
179 * | |
180 * A valid example of where this can be used is as the second argument | |
181 * to V8's Error.captureStackTrace. See | |
182 * https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi. | |
183 */ | |
184 external RAW_DART_FUNCTION_REF(Function function); | |
185 | |
186 /** | |
187 * Sets the current isolate to [isolate]. | |
188 */ | |
189 external void JS_SET_CURRENT_ISOLATE(isolate); | |
190 | |
191 /** | |
192 * Returns the interceptor for class [type]. The interceptor is the type's | |
193 * constructor's `prototype` property. [type] will typically be the class, not | |
194 * an interface, e.g. `JS_INTERCEPTOR_CONSTANT(JSInt)`, not | |
195 * `JS_INTERCEPTOR_CONSTANT(int)`. | |
196 */ | |
197 external JS_INTERCEPTOR_CONSTANT(Type type); | |
198 | |
199 /** | |
200 * Returns the object corresponding to Namer.CURRENT_ISOLATE. | |
201 */ | |
202 external JS_CURRENT_ISOLATE(); | |
203 | |
204 /// Returns the JS name for [name] from the Namer. | |
205 external String JS_GET_NAME(JsGetName name); | |
206 | |
207 /// Reads an embedded global. | |
208 /// | |
209 /// The [name] should be a constant defined in the `_embedded_names` library. | |
210 external JS_EMBEDDED_GLOBAL(String typeDescription, String name); | |
211 | |
212 /// Instructs the compiler to execute the [builtinName] action at the call-site. | |
213 /// | |
214 /// The [builtin] should be a constant defined in the `_embedded_names` | |
215 /// library. | |
216 // Add additional optional arguments if needed. The method is treated internally | |
217 // as a variable argument method. | |
218 external JS_BUILTIN(String typeDescription, JsBuiltin builtin, | |
219 [arg0, arg1, arg2, arg3, arg4, arg5, arg6, | |
220 arg7, arg8, arg9, arg10, arg11]); | |
221 | |
222 /// Returns the state of a flag that is determined by the state of the compiler | |
223 /// when the program has been analyzed. | |
224 external bool JS_GET_FLAG(String name); | |
225 | |
226 /** | |
227 * Pretend [code] is executed. Generates no executable code. This is used to | |
228 * model effects at some other point in external code. For example, the | |
229 * following models an assignment to foo with an unknown value. | |
230 * | |
231 * var foo; | |
232 * | |
233 * main() { | |
234 * JS_EFFECT((_){ foo = _; }) | |
235 * } | |
236 * | |
237 * TODO(sra): Replace this hack with something to mark the volatile or | |
238 * externally initialized elements. | |
239 */ | |
240 void JS_EFFECT(Function code) { code(null); } | |
241 | |
242 /** | |
243 * Use this class for creating constants that hold JavaScript code. | |
244 * For example: | |
245 * | |
246 * const constant = JS_CONST('typeof window != "undefined"); | |
247 * | |
248 * This code will generate: | |
249 * $.JS_CONST_1 = typeof window != "undefined"; | |
250 */ | |
251 class JS_CONST { | |
252 final String code; | |
253 const JS_CONST(this.code); | |
254 } | |
255 | |
256 /** | |
257 * JavaScript string concatenation. Inputs must be Strings. Corresponds to the | |
258 * HStringConcat SSA instruction and may be constant-folded. | |
259 */ | |
260 String JS_STRING_CONCAT(String a, String b) { | |
261 // This body is unused, only here for type analysis. | |
262 return JS('String', '# + #', a, b); | |
263 } | |
OLD | NEW |