40 This will change the node weight that requires a subgraph of the IR to |
48 This will change the node weight that requires a subgraph of the IR to |
41 be split into several classes in order not to run out of bytecode space. |
49 be split into several classes in order not to run out of bytecode space. |
42 The default value is 0x8000 (32768). |
50 The default value is 0x8000 (32768). |
43 |
51 |
44 |
52 |
45 SYSTEM PROPERTY: -Dnashorn.compiler.intarithmetic |
53 SYSTEM PROPERTY: -Dnashorn.serialize.compression=<x> |
46 |
54 |
47 (and integer arithmetic in general) |
55 This property sets the compression level used when deflating serialized |
48 |
56 AST structures of anonymous split functions. Valid values range from 0 to 9, |
49 <currently disabled - this is being refactored for update releases> |
57 the default value is 4. Higher values will reduce memory size of serialized |
50 |
58 AST but increase CPU usage required for compression. |
51 Arithmetic operations in Nashorn (except bitwise ones) typically |
59 |
52 coerce the operands to doubles (as per the JavaScript spec). To switch |
60 |
53 this off and remain in integer mode, for example for "var x = a&b; var |
61 SYSTEM PROPERTY: -Dnashorn.codegen.debug.trace=<x> |
54 y = c&d; var z = x*y;", use this flag. This will force the |
|
55 multiplication of variables that are ints to be done with the IMUL |
|
56 bytecode and the result "z" to become an int. |
|
57 |
|
58 WARNING: Note that is is experimental only to ensure that type support |
|
59 exists for all primitive types. The generated code is unsound. This |
|
60 will be the case until we do optimizations based on it. There is a CR |
|
61 in Nashorn to do better range analysis, and ensure that this is only |
|
62 done where the operation can't overflow into a wider type. Currently |
|
63 no overflow checking is done, so at the moment, until range analysis |
|
64 has been completed, this option is turned off. |
|
65 |
|
66 We've experimented by using int arithmetic for everything and putting |
|
67 overflow checks afterwards, which would recompute the operation with |
|
68 the correct precision, but have yet to find a configuration where this |
|
69 is faster than just using doubles directly, even if the int operation |
|
70 does not overflow. Getting access to a JVM intrinsic that does branch |
|
71 on overflow would probably alleviate this. |
|
72 |
|
73 The future: |
|
74 |
|
75 We are transitioning to an optimistic type system that uses int |
|
76 arithmetic everywhere until proven wrong. The problem here is mostly |
|
77 catch an overflow exception and rolling back the state to a new method |
|
78 with less optimistic assumptions for an operation at a particular |
|
79 program point. This will most likely not be in the Java 8.0 release |
|
80 but likely end up in an update release |
|
81 |
|
82 For Java 8, several java.lang.Math methods like addExact, subExact and |
|
83 mulExact are available to help us. Experiments intrinsifying these |
|
84 show a lot of promise, and we have devised a system that basically |
|
85 does on stack replacement with exceptions in bytecode to revert |
|
86 erroneous assumptions. An explanation of how this works and what we |
|
87 are doing can be found here: |
|
88 http://www.slideshare.net/lagergren/lagergren-jvmls2013final |
|
89 |
|
90 Experiments with this show significant ~x2-3 performance increases on |
|
91 pretty much everything, provided that optimistic assumptions don't |
|
92 fail much. It will affect warmup time negatively, depending on how |
|
93 many erroneous too optimistic assumptions are placed in the code at |
|
94 compile time. We don't think this will be much of an issue. |
|
95 |
|
96 For example for a small benchmark that repeatedly executes this |
|
97 method taken from the Crypto Octane benchmark |
|
98 |
|
99 function am3(i,x,w,j,c,n) { |
|
100 var this_array = this.array; |
|
101 var w_array = w.array; |
|
102 var xl = x&0x3fff, xh = x>>14; |
|
103 while(--n >= 0) { |
|
104 var l = this_array[i]&0x3fff; |
|
105 var h = this_array[i++]>>14; |
|
106 var m = xh*l+h*xl; |
|
107 l = xl*l+((m&0x3fff)<<14)+w_array[j]+c; |
|
108 c = (l>>28)+(m>>14)+xh*h; |
|
109 w_array[j++] = l&0xfffffff; |
|
110 } |
|
111 |
|
112 return c; |
|
113 } |
|
114 |
|
115 The performance increase more than doubles. We are also working hard |
|
116 with the code generation team in the Java Virtual Machine to fix |
|
117 things that are lacking in invokedynamic performance, which is another |
|
118 area where a lot of ongoing performance work takes place |
|
119 |
|
120 "Pessimistic" bytecode for am3, guaranteed to be semantically correct: |
|
121 |
|
122 // access flags 0x9 |
|
123 public static am3(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; |
|
124 L0 |
|
125 LINENUMBER 12 L0 |
|
126 ALOAD 0 |
|
127 INVOKEDYNAMIC dyn:getProp|getElem|getMethod:array(Ljava/lang/Object;)Ljava/lang/Object; [ |
|
128 // handle kind 0x6 : INVOKESTATIC |
|
129 jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;) |
|
130 // arguments: |
|
131 0 |
|
132 ] |
|
133 ASTORE 8 |
|
134 L1 |
|
135 LINENUMBER 13 L1 |
|
136 ALOAD 3 |
|
137 INVOKEDYNAMIC dyn:getProp|getElem|getMethod:array(Ljava/lang/Object;)Ljava/lang/Object; [ |
|
138 // handle kind 0x6 : INVOKESTATIC |
|
139 jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;) |
|
140 // arguments: |
|
141 0 |
|
142 ] |
|
143 ASTORE 9 |
|
144 L2 |
|
145 LINENUMBER 14 L2 |
|
146 ALOAD 2 |
|
147 INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toInt32 (Ljava/lang/Object;)I |
|
148 SIPUSH 16383 |
|
149 IAND |
|
150 ISTORE 10 |
|
151 ALOAD 2 |
|
152 INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toInt32 (Ljava/lang/Object;)I |
|
153 BIPUSH 14 |
|
154 ISHR |
|
155 ISTORE 11 |
|
156 L3 |
|
157 LINENUMBER 15 L3 |
|
158 GOTO L4 |
|
159 L5 |
|
160 LINENUMBER 16 L5 |
|
161 FRAME FULL [java/lang/Object java/lang/Object java/lang/Object java/lang/Object java/lang/Object java/lang/Object java/lang/Double T java/lang/Object java/lang/Object I I] [] |
|
162 ALOAD 8 |
|
163 ALOAD 1 |
|
164 INVOKEDYNAMIC dyn:getElem|getProp|getMethod(Ljava/lang/Object;Ljava/lang/Object;)I [ |
|
165 // handle kind 0x6 : INVOKESTATIC |
|
166 jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;) |
|
167 // arguments: |
|
168 0 |
|
169 ] |
|
170 SIPUSH 16383 |
|
171 IAND |
|
172 INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer; |
|
173 ASTORE 12 |
|
174 L6 |
|
175 LINENUMBER 17 L6 |
|
176 ALOAD 8 |
|
177 ALOAD 1 |
|
178 INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toNumber (Ljava/lang/Object;)D |
|
179 DUP2 |
|
180 DCONST_1 |
|
181 DADD |
|
182 INVOKESTATIC java/lang/Double.valueOf (D)Ljava/lang/Double; |
|
183 ASTORE 1 |
|
184 INVOKEDYNAMIC dyn:getElem|getProp|getMethod(Ljava/lang/Object;D)I [ |
|
185 // handle kind 0x6 : INVOKESTATIC |
|
186 jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;) |
|
187 // arguments: |
|
188 0 |
|
189 ] |
|
190 BIPUSH 14 |
|
191 ISHR |
|
192 ISTORE 13 |
|
193 L7 |
|
194 LINENUMBER 18 L7 |
|
195 ILOAD 11 |
|
196 I2D |
|
197 ALOAD 12 |
|
198 INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toNumber (Ljava/lang/Object;)D |
|
199 DMUL |
|
200 ILOAD 13 |
|
201 I2D |
|
202 ILOAD 10 |
|
203 I2D |
|
204 DMUL |
|
205 DADD |
|
206 DSTORE 14 |
|
207 L8 |
|
208 LINENUMBER 19 L8 |
|
209 ILOAD 10 |
|
210 I2D |
|
211 ALOAD 12 |
|
212 INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toNumber (Ljava/lang/Object;)D |
|
213 DMUL |
|
214 DLOAD 14 |
|
215 INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toInt32 (D)I |
|
216 SIPUSH 16383 |
|
217 IAND |
|
218 BIPUSH 14 |
|
219 ISHL |
|
220 I2D |
|
221 DADD |
|
222 ALOAD 9 |
|
223 ALOAD 4 |
|
224 INVOKEDYNAMIC dyn:getElem|getProp|getMethod(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; [ |
|
225 // handle kind 0x6 : INVOKESTATIC |
|
226 jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;) |
|
227 // arguments: |
|
228 0 |
|
229 ] |
|
230 INVOKEDYNAMIC ADD:ODO_D(DLjava/lang/Object;)Ljava/lang/Object; [ |
|
231 // handle kind 0x6 : INVOKESTATIC |
|
232 jdk/nashorn/internal/runtime/linker/Bootstrap.runtimeBootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;) |
|
233 // arguments: none |
|
234 ] |
|
235 ALOAD 5 |
|
236 INVOKEDYNAMIC ADD:OOO_I(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; [ |
|
237 // handle kind 0x6 : INVOKESTATIC |
|
238 jdk/nashorn/internal/runtime/linker/Bootstrap.runtimeBootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;) |
|
239 // arguments: none |
|
240 ] |
|
241 ASTORE 12 |
|
242 L9 |
|
243 LINENUMBER 20 L9 |
|
244 ALOAD 12 |
|
245 INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toInt32 (Ljava/lang/Object;)I |
|
246 BIPUSH 28 |
|
247 ISHR |
|
248 I2D |
|
249 DLOAD 14 |
|
250 INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toInt32 (D)I |
|
251 BIPUSH 14 |
|
252 ISHR |
|
253 I2D |
|
254 DADD |
|
255 ILOAD 11 |
|
256 I2D |
|
257 ILOAD 13 |
|
258 I2D |
|
259 DMUL |
|
260 DADD |
|
261 INVOKESTATIC java/lang/Double.valueOf (D)Ljava/lang/Double; |
|
262 ASTORE 5 |
|
263 L10 |
|
264 LINENUMBER 21 L10 |
|
265 ALOAD 9 |
|
266 ALOAD 4 |
|
267 INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toNumber (Ljava/lang/Object;)D |
|
268 DUP2 |
|
269 DCONST_1 |
|
270 DADD |
|
271 INVOKESTATIC java/lang/Double.valueOf (D)Ljava/lang/Double; |
|
272 ASTORE 4 |
|
273 ALOAD 12 |
|
274 INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toInt32 (Ljava/lang/Object;)I |
|
275 LDC 268435455 |
|
276 IAND |
|
277 INVOKEDYNAMIC dyn:setElem|setProp(Ljava/lang/Object;DI)V [ |
|
278 // handle kind 0x6 : INVOKESTATIC |
|
279 jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;) |
|
280 // arguments: |
|
281 0 |
|
282 ] |
|
283 L4 |
|
284 FRAME FULL [java/lang/Object java/lang/Object java/lang/Object java/lang/Object java/lang/Object java/lang/Object java/lang/Object T java/lang/Object java/lang/Object I I] [] |
|
285 ALOAD 6 |
|
286 INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toNumber (Ljava/lang/Object;)D |
|
287 LDC -1.0 |
|
288 DADD |
|
289 DUP2 |
|
290 INVOKESTATIC java/lang/Double.valueOf (D)Ljava/lang/Double; |
|
291 ASTORE 6 |
|
292 DCONST_0 |
|
293 DCMPL |
|
294 IFGE L5 |
|
295 L11 |
|
296 LINENUMBER 24 L11 |
|
297 ALOAD 5 |
|
298 ARETURN |
|
299 |
|
300 "Optimistic" bytecode that requires invalidation on e.g overflow. Factor |
|
301 x2-3 speedup: |
|
302 |
|
303 public static am3(Ljava/lang/Object;IILjava/lang/Object;III)I |
|
304 L0 |
|
305 LINENUMBER 12 L0 |
|
306 ALOAD 0 |
|
307 INVOKEDYNAMIC dyn:getProp|getElem|getMethod:array(Ljava/lang/Object;)Ljava/lang/Object; [ |
|
308 // handle kind 0x6 : INVOKESTATIC |
|
309 jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;) |
|
310 // arguments: |
|
311 0 |
|
312 ] |
|
313 ASTORE 8 |
|
314 L1 |
|
315 LINENUMBER 13 L1 |
|
316 ALOAD 3 |
|
317 INVOKEDYNAMIC dyn:getProp|getElem|getMethod:array(Ljava/lang/Object;)Ljava/lang/Object; [ |
|
318 // handle kind 0x6 : INVOKESTATIC |
|
319 jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;) |
|
320 // arguments: |
|
321 0 |
|
322 ] |
|
323 ASTORE 9 |
|
324 L2 |
|
325 LINENUMBER 14 L2 |
|
326 ILOAD 2 |
|
327 SIPUSH 16383 |
|
328 IAND |
|
329 ISTORE 10 |
|
330 ILOAD 2 |
|
331 BIPUSH 14 |
|
332 ISHR |
|
333 ISTORE 11 |
|
334 L3 |
|
335 LINENUMBER 15 L3 |
|
336 GOTO L4 |
|
337 L5 |
|
338 LINENUMBER 16 L5 |
|
339 FRAME FULL [java/lang/Object I I java/lang/Object I I I T java/lang/Object java/lang/Object I I] [] |
|
340 ALOAD 8 |
|
341 ILOAD 1 |
|
342 INVOKEDYNAMIC dyn:getElem|getProp|getMethod(Ljava/lang/Object;I)I [ |
|
343 // handle kind 0x6 : INVOKESTATIC |
|
344 jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;) |
|
345 // arguments: |
|
346 0 |
|
347 ] |
|
348 SIPUSH 16383 |
|
349 IAND |
|
350 ISTORE 12 |
|
351 L6 |
|
352 LINENUMBER 17 L6 |
|
353 ALOAD 8 |
|
354 ILOAD 1 |
|
355 DUP |
|
356 ICONST_1 |
|
357 IADD |
|
358 ISTORE 1 |
|
359 INVOKEDYNAMIC dyn:getElem|getProp|getMethod(Ljava/lang/Object;I)I [ |
|
360 // handle kind 0x6 : INVOKESTATIC |
|
361 jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;) |
|
362 // arguments: |
|
363 0 |
|
364 ] |
|
365 BIPUSH 14 |
|
366 ISHR |
|
367 ISTORE 13 |
|
368 L7 |
|
369 LINENUMBER 18 L7 |
|
370 ILOAD 11 |
|
371 ILOAD 12 |
|
372 BIPUSH 8 |
|
373 INVOKESTATIC jdk/nashorn/internal/runtime/JSType.mulExact (III)I |
|
374 ILOAD 13 |
|
375 ILOAD 10 |
|
376 BIPUSH 9 |
|
377 INVOKESTATIC jdk/nashorn/internal/runtime/JSType.mulExact (III)I |
|
378 IADD |
|
379 ISTORE 14 |
|
380 L8 |
|
381 LINENUMBER 19 L8 |
|
382 ILOAD 10 |
|
383 ILOAD 12 |
|
384 BIPUSH 11 |
|
385 INVOKESTATIC jdk/nashorn/internal/runtime/JSType.mulExact (III)I |
|
386 ILOAD 14 |
|
387 SIPUSH 16383 |
|
388 IAND |
|
389 BIPUSH 14 |
|
390 ISHL |
|
391 IADD |
|
392 ALOAD 9 |
|
393 ILOAD 4 |
|
394 INVOKEDYNAMIC dyn:getElem|getProp|getMethod(Ljava/lang/Object;I)I [ |
|
395 // handle kind 0x6 : INVOKESTATIC |
|
396 jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;) |
|
397 // arguments: |
|
398 0 |
|
399 ] |
|
400 IADD |
|
401 ILOAD 5 |
|
402 IADD |
|
403 ISTORE 12 |
|
404 L9 |
|
405 LINENUMBER 20 L9 |
|
406 ILOAD 12 |
|
407 BIPUSH 28 |
|
408 ISHR |
|
409 ILOAD 14 |
|
410 BIPUSH 14 |
|
411 ISHR |
|
412 IADD |
|
413 ILOAD 11 |
|
414 ILOAD 13 |
|
415 BIPUSH 21 |
|
416 INVOKESTATIC jdk/nashorn/internal/runtime/JSType.mulExact (III)I |
|
417 IADD |
|
418 ISTORE 5 |
|
419 L10 |
|
420 LINENUMBER 21 L10 |
|
421 ALOAD 9 |
|
422 ILOAD 4 |
|
423 DUP |
|
424 ICONST_1 |
|
425 IADD |
|
426 ISTORE 4 |
|
427 ILOAD 12 |
|
428 LDC 268435455 |
|
429 IAND |
|
430 INVOKEDYNAMIC dyn:setElem|setProp(Ljava/lang/Object;II)V [ |
|
431 // handle kind 0x6 : INVOKESTATIC |
|
432 jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;) |
|
433 // arguments: |
|
434 0 |
|
435 ] |
|
436 L4 |
|
437 FRAME SAME |
|
438 ILOAD 6 |
|
439 ICONST_M1 |
|
440 IADD |
|
441 DUP |
|
442 ISTORE 6 |
|
443 ICONST_0 |
|
444 IF_ICMPGE L5 |
|
445 L11 |
|
446 LINENUMBER 24 L11 |
|
447 ILOAD 5 |
|
448 IRETURN |
|
449 |
|
450 |
|
451 SYSTEM PROPERTY: -Dnashorn.codegen.debug, -Dnashorn.codegen.debug.trace=<x> |
|
452 |
62 |
453 See the description of the codegen logger below. |
63 See the description of the codegen logger below. |
454 |
64 |
455 |
65 |
456 SYSTEM_PROPERTY: -Dnashorn.fields.debug |
66 SYSTEM PROPERTY: -Dnashorn.fields.objects |
457 |
67 |
458 See the description on the fields logger below. |
68 When this property is true, Nashorn will only use object fields for |
459 |
69 AccessorProperties. This means that primitive values must be boxed |
460 |
70 when stored in a field, which is significantly slower than using |
461 SYSTEM PROPERTY: -Dnashorn.fields.dual |
71 primitive fields. |
462 |
72 |
463 When this property is true, Nashorn will attempt to use primitive |
73 By default, Nashorn uses dual object and long fields. Ints are |
464 fields for AccessorProperties (currently just AccessorProperties, not |
74 represented as the 32 low bits of the long fields. Doubles are |
465 spill properties). Memory footprint for script objects will increase, |
75 represented as the doubleToLongBits of their value. This way a |
466 as we need to maintain both a primitive field (a long) as well as an |
76 single field can be used for all primitive types. Packing and |
467 Object field for the property value. Ints are represented as the 32 |
77 unpacking doubles to their bit representation is intrinsified by |
468 low bits of the long fields. Doubles are represented as the |
78 the JVM and extremely fast. |
469 doubleToLongBits of their value. This way a single field can be used |
|
470 for all primitive types. Packing and unpacking doubles to their bit |
|
471 representation is intrinsified by the JVM and extremely fast. |
|
472 |
|
473 While dual fields in theory runs significantly faster than Object |
|
474 fields due to reduction of boxing and memory allocation overhead, |
|
475 there is still work to be done to make this a general purpose |
|
476 solution. Research is ongoing. |
|
477 |
79 |
478 In the future, this might complement or be replaced by experimental |
80 In the future, this might complement or be replaced by experimental |
479 feature sun.misc.TaggedArray, which has been discussed on the mlvm |
81 feature sun.misc.TaggedArray, which has been discussed on the mlvm |
480 mailing list. TaggedArrays are basically a way to share data space |
82 mailing list. TaggedArrays are basically a way to share data space |
481 between primitives and references, and have the GC understand this. |
83 between primitives and references, and have the GC understand this. |
482 |
|
483 As long as only primitive values are written to the fields and enough |
|
484 type information exists to make sure that any reads don't have to be |
|
485 uselessly boxed and unboxed, this is significantly faster than the |
|
486 standard "Objects only" approach that currently is the default. See |
|
487 test/examples/dual-fields-micro.js for an example that runs twice as |
|
488 fast with dual fields as without them. Here, the compiler, can |
|
489 determine that we are dealing with numbers only throughout the entire |
|
490 property life span of the properties involved. |
|
491 |
|
492 If a "real" object (not a boxed primitive) is written to a field that |
|
493 has a primitive representation, its callsite is relinked and an Object |
|
494 field is used forevermore for that particular field in that |
|
495 PropertyMap and its children, even if primitives are later assigned to |
|
496 it. |
|
497 |
|
498 As the amount of compile time type information is very small in a |
|
499 dynamic language like JavaScript, it is frequently the case that |
|
500 something has to be treated as an object, because we don't know any |
|
501 better. In reality though, it is often a boxed primitive is stored to |
|
502 an AccessorProperty. The fastest way to handle this soundly is to use |
|
503 a callsite typecheck and avoid blowing the field up to an Object. We |
|
504 never revert object fields to primitives. Ping-pong:ing back and forth |
|
505 between primitive representation and Object representation would cause |
|
506 fatal performance overhead, so this is not an option. |
|
507 |
|
508 For a general application the dual fields approach is still slower |
|
509 than objects only fields in some places, about the same in most cases, |
|
510 and significantly faster in very few. This is due the program using |
|
511 primitives, but we still can't prove it. For example "local_var a = |
|
512 call(); field = a;" may very well write a double to the field, but the |
|
513 compiler dare not guess a double type if field is a local variable, |
|
514 due to bytecode variables being strongly typed and later non |
|
515 interchangeable. To get around this, the entire method would have to |
|
516 be replaced and a continuation retained to restart from. We believe |
|
517 that the next steps we should go through are instead: |
|
518 |
|
519 1) Implement method specialization based on callsite, as it's quite |
|
520 frequently the case that numbers are passed around, but currently our |
|
521 function nodes just have object types visible to the compiler. For |
|
522 example "var b = 17; func(a,b,17)" is an example where two parameters |
|
523 can be specialized, but the main version of func might also be called |
|
524 from another callsite with func(x,y,"string"). |
|
525 |
|
526 2) This requires lazy jitting as the functions have to be specialized |
|
527 per callsite. |
|
528 |
|
529 Even though "function square(x) { return x*x }" might look like a |
|
530 trivial function that can always only take doubles, this is not |
|
531 true. Someone might have overridden the valueOf for x so that the |
|
532 toNumber coercion has side effects. To fulfil JavaScript semantics, |
|
533 the coercion has to run twice for both terms of the multiplication |
|
534 even if they are the same object. This means that call site |
|
535 specialization is necessary, not parameter specialization on the form |
|
536 "function square(x) { var xd = (double)x; return xd*xd; }", as one |
|
537 might first think. |
|
538 |
|
539 Generating a method specialization for any variant of a function that |
|
540 we can determine by types at compile time is a combinatorial explosion |
|
541 of byte code (try it e.g. on all the variants of am3 in the Octane |
|
542 benchmark crypto.js). Thus, this needs to be lazy |
|
543 |
|
544 3) Optimistic callsite writes, something on the form |
|
545 |
|
546 x = y; //x is a field known to be a primitive. y is only an object as |
|
547 far as we can tell |
|
548 |
|
549 turns into |
|
550 |
|
551 try { |
|
552 x = (int)y; |
|
553 } catch (X is not an integer field right now | ClassCastException e) { |
|
554 x = y; |
|
555 } |
|
556 |
|
557 Mini POC shows that this is the key to a lot of dual field performance |
|
558 in seemingly trivial micros where one unknown object, in reality |
|
559 actually a primitive, foils it for us. Very common pattern. Once we |
|
560 are "all primitives", dual fields runs a lot faster than Object fields |
|
561 only. |
|
562 |
|
563 We still have to deal with objects vs primitives for local bytecode |
|
564 slots, possibly through code copying and versioning. |
|
565 |
|
566 The Future: |
|
567 |
|
568 We expect the usefulness of dual fields to increase significantly |
|
569 after the optimistic type system described in the section on |
|
570 integer arithmetic above is implemented. |
|
571 |
84 |
572 |
85 |
573 SYSTEM PROPERTY: -Dnashorn.compiler.symbol.trace=[<x>[,*]], |
86 SYSTEM PROPERTY: -Dnashorn.compiler.symbol.trace=[<x>[,*]], |
574 -Dnashorn.compiler.symbol.stacktrace=[<x>[,*]] |
87 -Dnashorn.compiler.symbol.stacktrace=[<x>[,*]] |
575 |
88 |
646 |
162 |
647 Finally we count callsite misses on a per callsite bases, which occur |
163 Finally we count callsite misses on a per callsite bases, which occur |
648 when a callsite has to be relinked, due to a previous assumption of |
164 when a callsite has to be relinked, due to a previous assumption of |
649 object layout being invalidated. |
165 object layout being invalidated. |
650 |
166 |
651 |
167 "getContext" - return the current Nashorn context. |
652 SYSTEM PROPERTY: -Dnashorn.methodhandles.debug, |
168 |
653 -Dnashorn.methodhandles.debug=create |
169 "equalWithoutType" - Returns true if if the two objects are both |
654 |
170 property maps, and they have identical properties in the same order, |
655 If this property is enabled, each MethodHandle related call that uses |
171 but allows the properties to differ in their types. |
656 the java.lang.invoke package gets its MethodHandle intercepted and an |
172 |
657 instrumentation printout of arguments and return value appended to |
173 "diffPropertyMaps" Returns a diagnostic string representing the difference |
658 it. This shows exactly which method handles are executed and from |
174 of two property maps. |
659 where. (Also MethodTypes and SwitchPoints). This can be augmented with |
175 |
660 more information, for example, instance count, by subclassing or |
176 "getClass" - Returns the Java class of an object, or undefined if null. |
661 further extending the TraceMethodHandleFactory implementation in |
177 |
662 MethodHandleFactory.java. |
178 "toJavaString" - Returns the Java toString representation of an object. |
663 |
179 |
664 If the property is specialized with "=create" as its option, |
180 "toIdentString" - Returns a string representation of an object consisting |
665 instrumentation will be shown for method handles upon creation time |
181 of its java class name and hash code. |
666 rather than at runtime usage. |
182 |
|
183 "getListenerCount" - Return the number of property listeners for a |
|
184 script object. |
|
185 |
|
186 "getEventQueueCapacity" - Get the capacity of the event queue. |
|
187 |
|
188 "setEventQueueCapacity" - Set the event queue capacity. |
|
189 |
|
190 "addRuntimeEvent" - Add a runtime event to the runtime event queue. |
|
191 The queue has a fixed size (see -Dnashorn.runtime.event.queue.size) |
|
192 and the oldest entry will be thrown out of the queue is about to overflow. |
|
193 |
|
194 "expandEventQueueCapacity" - Expands the event queue capacity, |
|
195 or truncates if capacity is lower than current capacity. Then only |
|
196 the newest entries are kept. |
|
197 |
|
198 "clearRuntimeEvents" - Clear the runtime event queue. |
|
199 |
|
200 "removeRuntimeEvent" - Remove a specific runtime event from the event queue. |
|
201 |
|
202 "getRuntimeEvents" - Return all runtime events in the queue as an array. |
|
203 |
|
204 "getLastRuntimeEvent" - Return the last runtime event in the queue. |
667 |
205 |
668 |
206 |
669 SYSTEM PROPERTY: -Dnashorn.methodhandles.debug.stacktrace |
207 SYSTEM PROPERTY: -Dnashorn.methodhandles.debug.stacktrace |
670 |
208 |
671 This does the same as nashorn.methodhandles.debug, but when enabled |
209 This enhances methodhandles logging (see below) to also dump the |
672 also dumps the stack trace for every instrumented method handle |
210 stack trace for every instrumented method handle operation. |
673 operation. Warning: This is enormously verbose, but provides a pretty |
211 Warning: This is enormously verbose, but provides a pretty |
674 decent "grep:able" picture of where the calls are coming from. |
212 decent "grep:able" picture of where the calls are coming from. |
675 |
213 |
676 See the description of the codegen logger below for a more verbose |
214 |
677 description of this option |
215 SYSTEM PROPERTY: -Dnashorn.cce |
678 |
216 |
679 |
217 Setting this system property causes the Nashorn linker to rely on |
680 SYSTEM PROPERTY: -Dnashorn.scriptfunction.specialization.disable |
218 ClassCastExceptions for triggering a callsite relink. If not set, the linker |
681 |
219 will add an explicit instanceof guard. |
682 There are several "fast path" implementations of constructors and |
220 |
683 functions in the NativeObject classes that, in their original form, |
221 |
684 take a variable amount of arguments. Said functions are also declared |
222 SYSTEM PROPERTY: -Dnashorn.spill.threshold=<x> |
685 to take Object parameters in their original form, as this is what the |
223 |
686 JavaScript specification mandates. |
224 This property sets the number of fields in an object from which to use |
687 However, we often know quite a lot more at a callsite of one of these |
225 generic array based spill storage instead of Java fields. The default value |
688 functions. For example, Math.min is called with a fixed number (2) of |
226 is 256. |
689 integer arguments. The overhead of boxing these ints to Objects and |
|
690 folding them into an Object array for the generic varargs Math.min |
|
691 function is an order of magnitude slower than calling a specialized |
|
692 implementation of Math.min that takes two integers. Specialized |
|
693 functions and constructors are identified by the tag |
|
694 @SpecializedFunction and @SpecializedConstructor in the Nashorn |
|
695 code. The linker will link in the most appropriate (narrowest types, |
|
696 right number of types and least number of arguments) specialization if |
|
697 specializations are available. |
|
698 |
|
699 Every ScriptFunction may carry specializations that the linker can |
|
700 choose from. This framework will likely be extended for user defined |
|
701 functions. The compiler can often infer enough parameter type info |
|
702 from callsites for in order to generate simpler versions with less |
|
703 generic Object types. This feature depends on future lazy jitting, as |
|
704 there tend to be many calls to user defined functions, some where the |
|
705 callsite can be specialized, some where we mostly see object |
|
706 parameters even at the callsite. |
|
707 |
|
708 If this system property is set to true, the linker will not attempt to |
|
709 use any specialized function or constructor for native objects, but |
|
710 just call the generic one. |
|
711 |
227 |
712 |
228 |
713 SYSTEM PROPERTY: -Dnashorn.tcs.miss.samplePercent=<x> |
229 SYSTEM PROPERTY: -Dnashorn.tcs.miss.samplePercent=<x> |
714 |
230 |
715 When running with the trace callsite option (-tcs), Nashorn will count |
231 When running with the trace callsite option (-tcs), Nashorn will count |