6d31b3a15f
Reviewed-by: attila, jlaskey
1046 lines
38 KiB
Plaintext
1046 lines
38 KiB
Plaintext
This document describes system properties that are used for internal
|
|
debugging and instrumentation purposes, along with the system loggers,
|
|
which are used for the same thing.
|
|
|
|
This document is intended as a developer resource, and it is not
|
|
needed as Nashorn documentation for normal usage. Flags and system
|
|
properties described herein are subject to change without notice.
|
|
|
|
=====================================
|
|
1. System properties used internally
|
|
=====================================
|
|
|
|
This documentation of the system property flags assume that the
|
|
default value of the flag is false, unless otherwise specified.
|
|
|
|
SYSTEM PROPERTY: -Dnashorn.args=<string>
|
|
|
|
This property takes as its value a space separated list of Nashorn
|
|
command line options that should be passed to Nashorn. This might be
|
|
useful in environments where it is hard to tell how a nashorn.jar is
|
|
launched.
|
|
|
|
Example:
|
|
|
|
> java -Dnashorn.args="--lazy-complation --log=compiler" large-java-app-with-nashorn.jar
|
|
> ant -Dnashorn.args="--log=codegen" antjob
|
|
|
|
SYSTEM PROPERTY: -Dnashorn.unstable.relink.threshold=x
|
|
|
|
This property controls how many call site misses are allowed before a
|
|
callsite is relinked with "apply" semantics to never change again.
|
|
In the case of megamorphic callsites, this is necessary, or the
|
|
program would spend all its time swapping out callsite targets. Dynalink
|
|
has a default value (currently 8 relinks) for this property if it
|
|
is not explicitly set.
|
|
|
|
|
|
SYSTEM PROPERTY: -Dnashorn.compiler.splitter.threshold=x
|
|
|
|
This will change the node weight that requires a subgraph of the IR to
|
|
be split into several classes in order not to run out of bytecode space.
|
|
The default value is 0x8000 (32768).
|
|
|
|
|
|
SYSTEM PROPERTY: -Dnashorn.compiler.intarithmetic
|
|
|
|
(and integer arithmetic in general)
|
|
|
|
<currently disabled - this is being refactored for update releases>
|
|
|
|
Arithmetic operations in Nashorn (except bitwise ones) typically
|
|
coerce the operands to doubles (as per the JavaScript spec). To switch
|
|
this off and remain in integer mode, for example for "var x = a&b; var
|
|
y = c&d; var z = x*y;", use this flag. This will force the
|
|
multiplication of variables that are ints to be done with the IMUL
|
|
bytecode and the result "z" to become an int.
|
|
|
|
WARNING: Note that is is experimental only to ensure that type support
|
|
exists for all primitive types. The generated code is unsound. This
|
|
will be the case until we do optimizations based on it. There is a CR
|
|
in Nashorn to do better range analysis, and ensure that this is only
|
|
done where the operation can't overflow into a wider type. Currently
|
|
no overflow checking is done, so at the moment, until range analysis
|
|
has been completed, this option is turned off.
|
|
|
|
We've experimented by using int arithmetic for everything and putting
|
|
overflow checks afterwards, which would recompute the operation with
|
|
the correct precision, but have yet to find a configuration where this
|
|
is faster than just using doubles directly, even if the int operation
|
|
does not overflow. Getting access to a JVM intrinsic that does branch
|
|
on overflow would probably alleviate this.
|
|
|
|
The future:
|
|
|
|
We are transitioning to an optimistic type system that uses int
|
|
arithmetic everywhere until proven wrong. The problem here is mostly
|
|
catch an overflow exception and rolling back the state to a new method
|
|
with less optimistic assumptions for an operation at a particular
|
|
program point. This will most likely not be in the Java 8.0 release
|
|
but likely end up in an update release
|
|
|
|
For Java 8, several java.lang.Math methods like addExact, subExact and
|
|
mulExact are available to help us. Experiments intrinsifying these
|
|
show a lot of promise, and we have devised a system that basically
|
|
does on stack replacement with exceptions in bytecode to revert
|
|
erroneous assumptions. An explanation of how this works and what we
|
|
are doing can be found here:
|
|
http://www.slideshare.net/lagergren/lagergren-jvmls2013final
|
|
|
|
Experiments with this show significant ~x2-3 performance increases on
|
|
pretty much everything, provided that optimistic assumptions don't
|
|
fail much. It will affect warmup time negatively, depending on how
|
|
many erroneous too optimistic assumptions are placed in the code at
|
|
compile time. We don't think this will be much of an issue.
|
|
|
|
For example for a small benchmark that repeatedly executes this
|
|
method taken from the Crypto Octane benchmark
|
|
|
|
function am3(i,x,w,j,c,n) {
|
|
var this_array = this.array;
|
|
var w_array = w.array;
|
|
var xl = x&0x3fff, xh = x>>14;
|
|
while(--n >= 0) {
|
|
var l = this_array[i]&0x3fff;
|
|
var h = this_array[i++]>>14;
|
|
var m = xh*l+h*xl;
|
|
l = xl*l+((m&0x3fff)<<14)+w_array[j]+c;
|
|
c = (l>>28)+(m>>14)+xh*h;
|
|
w_array[j++] = l&0xfffffff;
|
|
}
|
|
|
|
return c;
|
|
}
|
|
|
|
The performance increase more than doubles. We are also working hard
|
|
with the code generation team in the Java Virtual Machine to fix
|
|
things that are lacking in invokedynamic performance, which is another
|
|
area where a lot of ongoing performance work takes place
|
|
|
|
"Pessimistic" bytecode for am3, guaranteed to be semantically correct:
|
|
|
|
// access flags 0x9
|
|
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;
|
|
L0
|
|
LINENUMBER 12 L0
|
|
ALOAD 0
|
|
INVOKEDYNAMIC dyn:getProp|getElem|getMethod:array(Ljava/lang/Object;)Ljava/lang/Object; [
|
|
// handle kind 0x6 : INVOKESTATIC
|
|
jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
|
|
// arguments:
|
|
0
|
|
]
|
|
ASTORE 8
|
|
L1
|
|
LINENUMBER 13 L1
|
|
ALOAD 3
|
|
INVOKEDYNAMIC dyn:getProp|getElem|getMethod:array(Ljava/lang/Object;)Ljava/lang/Object; [
|
|
// handle kind 0x6 : INVOKESTATIC
|
|
jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
|
|
// arguments:
|
|
0
|
|
]
|
|
ASTORE 9
|
|
L2
|
|
LINENUMBER 14 L2
|
|
ALOAD 2
|
|
INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toInt32 (Ljava/lang/Object;)I
|
|
SIPUSH 16383
|
|
IAND
|
|
ISTORE 10
|
|
ALOAD 2
|
|
INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toInt32 (Ljava/lang/Object;)I
|
|
BIPUSH 14
|
|
ISHR
|
|
ISTORE 11
|
|
L3
|
|
LINENUMBER 15 L3
|
|
GOTO L4
|
|
L5
|
|
LINENUMBER 16 L5
|
|
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] []
|
|
ALOAD 8
|
|
ALOAD 1
|
|
INVOKEDYNAMIC dyn:getElem|getProp|getMethod(Ljava/lang/Object;Ljava/lang/Object;)I [
|
|
// handle kind 0x6 : INVOKESTATIC
|
|
jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
|
|
// arguments:
|
|
0
|
|
]
|
|
SIPUSH 16383
|
|
IAND
|
|
INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
|
|
ASTORE 12
|
|
L6
|
|
LINENUMBER 17 L6
|
|
ALOAD 8
|
|
ALOAD 1
|
|
INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toNumber (Ljava/lang/Object;)D
|
|
DUP2
|
|
DCONST_1
|
|
DADD
|
|
INVOKESTATIC java/lang/Double.valueOf (D)Ljava/lang/Double;
|
|
ASTORE 1
|
|
INVOKEDYNAMIC dyn:getElem|getProp|getMethod(Ljava/lang/Object;D)I [
|
|
// handle kind 0x6 : INVOKESTATIC
|
|
jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
|
|
// arguments:
|
|
0
|
|
]
|
|
BIPUSH 14
|
|
ISHR
|
|
ISTORE 13
|
|
L7
|
|
LINENUMBER 18 L7
|
|
ILOAD 11
|
|
I2D
|
|
ALOAD 12
|
|
INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toNumber (Ljava/lang/Object;)D
|
|
DMUL
|
|
ILOAD 13
|
|
I2D
|
|
ILOAD 10
|
|
I2D
|
|
DMUL
|
|
DADD
|
|
DSTORE 14
|
|
L8
|
|
LINENUMBER 19 L8
|
|
ILOAD 10
|
|
I2D
|
|
ALOAD 12
|
|
INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toNumber (Ljava/lang/Object;)D
|
|
DMUL
|
|
DLOAD 14
|
|
INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toInt32 (D)I
|
|
SIPUSH 16383
|
|
IAND
|
|
BIPUSH 14
|
|
ISHL
|
|
I2D
|
|
DADD
|
|
ALOAD 9
|
|
ALOAD 4
|
|
INVOKEDYNAMIC dyn:getElem|getProp|getMethod(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; [
|
|
// handle kind 0x6 : INVOKESTATIC
|
|
jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
|
|
// arguments:
|
|
0
|
|
]
|
|
INVOKEDYNAMIC ADD:ODO_D(DLjava/lang/Object;)Ljava/lang/Object; [
|
|
// handle kind 0x6 : INVOKESTATIC
|
|
jdk/nashorn/internal/runtime/linker/Bootstrap.runtimeBootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;)
|
|
// arguments: none
|
|
]
|
|
ALOAD 5
|
|
INVOKEDYNAMIC ADD:OOO_I(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; [
|
|
// handle kind 0x6 : INVOKESTATIC
|
|
jdk/nashorn/internal/runtime/linker/Bootstrap.runtimeBootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;)
|
|
// arguments: none
|
|
]
|
|
ASTORE 12
|
|
L9
|
|
LINENUMBER 20 L9
|
|
ALOAD 12
|
|
INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toInt32 (Ljava/lang/Object;)I
|
|
BIPUSH 28
|
|
ISHR
|
|
I2D
|
|
DLOAD 14
|
|
INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toInt32 (D)I
|
|
BIPUSH 14
|
|
ISHR
|
|
I2D
|
|
DADD
|
|
ILOAD 11
|
|
I2D
|
|
ILOAD 13
|
|
I2D
|
|
DMUL
|
|
DADD
|
|
INVOKESTATIC java/lang/Double.valueOf (D)Ljava/lang/Double;
|
|
ASTORE 5
|
|
L10
|
|
LINENUMBER 21 L10
|
|
ALOAD 9
|
|
ALOAD 4
|
|
INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toNumber (Ljava/lang/Object;)D
|
|
DUP2
|
|
DCONST_1
|
|
DADD
|
|
INVOKESTATIC java/lang/Double.valueOf (D)Ljava/lang/Double;
|
|
ASTORE 4
|
|
ALOAD 12
|
|
INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toInt32 (Ljava/lang/Object;)I
|
|
LDC 268435455
|
|
IAND
|
|
INVOKEDYNAMIC dyn:setElem|setProp(Ljava/lang/Object;DI)V [
|
|
// handle kind 0x6 : INVOKESTATIC
|
|
jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
|
|
// arguments:
|
|
0
|
|
]
|
|
L4
|
|
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] []
|
|
ALOAD 6
|
|
INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toNumber (Ljava/lang/Object;)D
|
|
LDC -1.0
|
|
DADD
|
|
DUP2
|
|
INVOKESTATIC java/lang/Double.valueOf (D)Ljava/lang/Double;
|
|
ASTORE 6
|
|
DCONST_0
|
|
DCMPL
|
|
IFGE L5
|
|
L11
|
|
LINENUMBER 24 L11
|
|
ALOAD 5
|
|
ARETURN
|
|
|
|
"Optimistic" bytecode that requires invalidation on e.g overflow. Factor
|
|
x2-3 speedup:
|
|
|
|
public static am3(Ljava/lang/Object;IILjava/lang/Object;III)I
|
|
L0
|
|
LINENUMBER 12 L0
|
|
ALOAD 0
|
|
INVOKEDYNAMIC dyn:getProp|getElem|getMethod:array(Ljava/lang/Object;)Ljava/lang/Object; [
|
|
// handle kind 0x6 : INVOKESTATIC
|
|
jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
|
|
// arguments:
|
|
0
|
|
]
|
|
ASTORE 8
|
|
L1
|
|
LINENUMBER 13 L1
|
|
ALOAD 3
|
|
INVOKEDYNAMIC dyn:getProp|getElem|getMethod:array(Ljava/lang/Object;)Ljava/lang/Object; [
|
|
// handle kind 0x6 : INVOKESTATIC
|
|
jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
|
|
// arguments:
|
|
0
|
|
]
|
|
ASTORE 9
|
|
L2
|
|
LINENUMBER 14 L2
|
|
ILOAD 2
|
|
SIPUSH 16383
|
|
IAND
|
|
ISTORE 10
|
|
ILOAD 2
|
|
BIPUSH 14
|
|
ISHR
|
|
ISTORE 11
|
|
L3
|
|
LINENUMBER 15 L3
|
|
GOTO L4
|
|
L5
|
|
LINENUMBER 16 L5
|
|
FRAME FULL [java/lang/Object I I java/lang/Object I I I T java/lang/Object java/lang/Object I I] []
|
|
ALOAD 8
|
|
ILOAD 1
|
|
INVOKEDYNAMIC dyn:getElem|getProp|getMethod(Ljava/lang/Object;I)I [
|
|
// handle kind 0x6 : INVOKESTATIC
|
|
jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
|
|
// arguments:
|
|
0
|
|
]
|
|
SIPUSH 16383
|
|
IAND
|
|
ISTORE 12
|
|
L6
|
|
LINENUMBER 17 L6
|
|
ALOAD 8
|
|
ILOAD 1
|
|
DUP
|
|
ICONST_1
|
|
IADD
|
|
ISTORE 1
|
|
INVOKEDYNAMIC dyn:getElem|getProp|getMethod(Ljava/lang/Object;I)I [
|
|
// handle kind 0x6 : INVOKESTATIC
|
|
jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
|
|
// arguments:
|
|
0
|
|
]
|
|
BIPUSH 14
|
|
ISHR
|
|
ISTORE 13
|
|
L7
|
|
LINENUMBER 18 L7
|
|
ILOAD 11
|
|
ILOAD 12
|
|
BIPUSH 8
|
|
INVOKESTATIC jdk/nashorn/internal/runtime/JSType.mulExact (III)I
|
|
ILOAD 13
|
|
ILOAD 10
|
|
BIPUSH 9
|
|
INVOKESTATIC jdk/nashorn/internal/runtime/JSType.mulExact (III)I
|
|
IADD
|
|
ISTORE 14
|
|
L8
|
|
LINENUMBER 19 L8
|
|
ILOAD 10
|
|
ILOAD 12
|
|
BIPUSH 11
|
|
INVOKESTATIC jdk/nashorn/internal/runtime/JSType.mulExact (III)I
|
|
ILOAD 14
|
|
SIPUSH 16383
|
|
IAND
|
|
BIPUSH 14
|
|
ISHL
|
|
IADD
|
|
ALOAD 9
|
|
ILOAD 4
|
|
INVOKEDYNAMIC dyn:getElem|getProp|getMethod(Ljava/lang/Object;I)I [
|
|
// handle kind 0x6 : INVOKESTATIC
|
|
jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
|
|
// arguments:
|
|
0
|
|
]
|
|
IADD
|
|
ILOAD 5
|
|
IADD
|
|
ISTORE 12
|
|
L9
|
|
LINENUMBER 20 L9
|
|
ILOAD 12
|
|
BIPUSH 28
|
|
ISHR
|
|
ILOAD 14
|
|
BIPUSH 14
|
|
ISHR
|
|
IADD
|
|
ILOAD 11
|
|
ILOAD 13
|
|
BIPUSH 21
|
|
INVOKESTATIC jdk/nashorn/internal/runtime/JSType.mulExact (III)I
|
|
IADD
|
|
ISTORE 5
|
|
L10
|
|
LINENUMBER 21 L10
|
|
ALOAD 9
|
|
ILOAD 4
|
|
DUP
|
|
ICONST_1
|
|
IADD
|
|
ISTORE 4
|
|
ILOAD 12
|
|
LDC 268435455
|
|
IAND
|
|
INVOKEDYNAMIC dyn:setElem|setProp(Ljava/lang/Object;II)V [
|
|
// handle kind 0x6 : INVOKESTATIC
|
|
jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
|
|
// arguments:
|
|
0
|
|
]
|
|
L4
|
|
FRAME SAME
|
|
ILOAD 6
|
|
ICONST_M1
|
|
IADD
|
|
DUP
|
|
ISTORE 6
|
|
ICONST_0
|
|
IF_ICMPGE L5
|
|
L11
|
|
LINENUMBER 24 L11
|
|
ILOAD 5
|
|
IRETURN
|
|
|
|
|
|
SYSTEM PROPERTY: -Dnashorn.codegen.debug, -Dnashorn.codegen.debug.trace=<x>
|
|
|
|
See the description of the codegen logger below.
|
|
|
|
|
|
SYSTEM_PROPERTY: -Dnashorn.fields.debug
|
|
|
|
See the description on the fields logger below.
|
|
|
|
|
|
SYSTEM PROPERTY: -Dnashorn.fields.dual
|
|
|
|
When this property is true, Nashorn will attempt to use primitive
|
|
fields for AccessorProperties (currently just AccessorProperties, not
|
|
spill properties). Memory footprint for script objects will increase,
|
|
as we need to maintain both a primitive field (a long) as well as an
|
|
Object field for the property value. Ints are represented as the 32
|
|
low bits of the long fields. Doubles are represented as the
|
|
doubleToLongBits of their value. This way a single field can be used
|
|
for all primitive types. Packing and unpacking doubles to their bit
|
|
representation is intrinsified by the JVM and extremely fast.
|
|
|
|
While dual fields in theory runs significantly faster than Object
|
|
fields due to reduction of boxing and memory allocation overhead,
|
|
there is still work to be done to make this a general purpose
|
|
solution. Research is ongoing.
|
|
|
|
In the future, this might complement or be replaced by experimental
|
|
feature sun.misc.TaggedArray, which has been discussed on the mlvm
|
|
mailing list. TaggedArrays are basically a way to share data space
|
|
between primitives and references, and have the GC understand this.
|
|
|
|
As long as only primitive values are written to the fields and enough
|
|
type information exists to make sure that any reads don't have to be
|
|
uselessly boxed and unboxed, this is significantly faster than the
|
|
standard "Objects only" approach that currently is the default. See
|
|
test/examples/dual-fields-micro.js for an example that runs twice as
|
|
fast with dual fields as without them. Here, the compiler, can
|
|
determine that we are dealing with numbers only throughout the entire
|
|
property life span of the properties involved.
|
|
|
|
If a "real" object (not a boxed primitive) is written to a field that
|
|
has a primitive representation, its callsite is relinked and an Object
|
|
field is used forevermore for that particular field in that
|
|
PropertyMap and its children, even if primitives are later assigned to
|
|
it.
|
|
|
|
As the amount of compile time type information is very small in a
|
|
dynamic language like JavaScript, it is frequently the case that
|
|
something has to be treated as an object, because we don't know any
|
|
better. In reality though, it is often a boxed primitive is stored to
|
|
an AccessorProperty. The fastest way to handle this soundly is to use
|
|
a callsite typecheck and avoid blowing the field up to an Object. We
|
|
never revert object fields to primitives. Ping-pong:ing back and forth
|
|
between primitive representation and Object representation would cause
|
|
fatal performance overhead, so this is not an option.
|
|
|
|
For a general application the dual fields approach is still slower
|
|
than objects only fields in some places, about the same in most cases,
|
|
and significantly faster in very few. This is due the program using
|
|
primitives, but we still can't prove it. For example "local_var a =
|
|
call(); field = a;" may very well write a double to the field, but the
|
|
compiler dare not guess a double type if field is a local variable,
|
|
due to bytecode variables being strongly typed and later non
|
|
interchangeable. To get around this, the entire method would have to
|
|
be replaced and a continuation retained to restart from. We believe
|
|
that the next steps we should go through are instead:
|
|
|
|
1) Implement method specialization based on callsite, as it's quite
|
|
frequently the case that numbers are passed around, but currently our
|
|
function nodes just have object types visible to the compiler. For
|
|
example "var b = 17; func(a,b,17)" is an example where two parameters
|
|
can be specialized, but the main version of func might also be called
|
|
from another callsite with func(x,y,"string").
|
|
|
|
2) This requires lazy jitting as the functions have to be specialized
|
|
per callsite.
|
|
|
|
Even though "function square(x) { return x*x }" might look like a
|
|
trivial function that can always only take doubles, this is not
|
|
true. Someone might have overridden the valueOf for x so that the
|
|
toNumber coercion has side effects. To fulfil JavaScript semantics,
|
|
the coercion has to run twice for both terms of the multiplication
|
|
even if they are the same object. This means that call site
|
|
specialization is necessary, not parameter specialization on the form
|
|
"function square(x) { var xd = (double)x; return xd*xd; }", as one
|
|
might first think.
|
|
|
|
Generating a method specialization for any variant of a function that
|
|
we can determine by types at compile time is a combinatorial explosion
|
|
of byte code (try it e.g. on all the variants of am3 in the Octane
|
|
benchmark crypto.js). Thus, this needs to be lazy
|
|
|
|
3) Optimistic callsite writes, something on the form
|
|
|
|
x = y; //x is a field known to be a primitive. y is only an object as
|
|
far as we can tell
|
|
|
|
turns into
|
|
|
|
try {
|
|
x = (int)y;
|
|
} catch (X is not an integer field right now | ClassCastException e) {
|
|
x = y;
|
|
}
|
|
|
|
Mini POC shows that this is the key to a lot of dual field performance
|
|
in seemingly trivial micros where one unknown object, in reality
|
|
actually a primitive, foils it for us. Very common pattern. Once we
|
|
are "all primitives", dual fields runs a lot faster than Object fields
|
|
only.
|
|
|
|
We still have to deal with objects vs primitives for local bytecode
|
|
slots, possibly through code copying and versioning.
|
|
|
|
The Future:
|
|
|
|
We expect the usefulness of dual fields to increase significantly
|
|
after the optimistic type system described in the section on
|
|
integer arithmetic above is implemented.
|
|
|
|
|
|
SYSTEM PROPERTY: -Dnashorn.compiler.symbol.trace=[<x>[,*]],
|
|
-Dnashorn.compiler.symbol.stacktrace=[<x>[,*]]
|
|
|
|
When this property is set, creation and manipulation of any symbol
|
|
named "x" will show information about when the compiler changes its
|
|
type assumption, bytecode local variable slot assignment and other
|
|
data. This is useful if, for example, a symbol shows up as an Object,
|
|
when you believe it should be a primitive. Usually there is an
|
|
explanation for this, for example that it exists in the global scope
|
|
and type analysis has to be more conservative.
|
|
|
|
Several symbols names to watch can be specified by comma separation.
|
|
|
|
If no variable name is specified (and no equals sign), all symbols
|
|
will be watched
|
|
|
|
By using "stacktrace" instead of or together with "trace", stack
|
|
traces will be displayed upon symbol changes according to the same
|
|
semantics.
|
|
|
|
|
|
SYSTEM PROPERTY: -Dnashorn.lexer.xmlliterals
|
|
|
|
If this property it set, it means that the Lexer should attempt to
|
|
parse XML literals, which would otherwise generate syntax
|
|
errors. Warning: there are currently no unit tests for this
|
|
functionality.
|
|
|
|
XML literals, when this is enabled, end up as standard LiteralNodes in
|
|
the IR.
|
|
|
|
|
|
SYSTEM_PROPERTY: -Dnashorn.debug
|
|
|
|
If this property is set to true, Nashorn runs in Debug mode. Debug
|
|
mode is slightly slower, as for example statistics counters are enabled
|
|
during the run. Debug mode makes available a NativeDebug instance
|
|
called "Debug" in the global space that can be used to print property
|
|
maps and layout for script objects, as well as a "dumpCounters" method
|
|
that will print the current values of the previously mentioned stats
|
|
counters.
|
|
|
|
These functions currently exists for Debug:
|
|
|
|
"map" - print(Debug.map(x)) will dump the PropertyMap for object x to
|
|
stdout (currently there also exist functions called "embedX", where X
|
|
is a value from 0 to 3, that will dump the contents of the embed pool
|
|
for the first spill properties in any script object and "spill", that
|
|
will dump the contents of the growing spill pool of spill properties
|
|
in any script object. This is of course subject to change without
|
|
notice, should we change the script object layout.
|
|
|
|
"methodHandle" - this method returns the method handle that is used
|
|
for invoking a particular script function.
|
|
|
|
"identical" - this method compares two script objects for reference
|
|
equality. It is a == Java comparison
|
|
|
|
"dumpCounters" - will dump the debug counters' current values to
|
|
stdout.
|
|
|
|
Currently we count number of ScriptObjects in the system, number of
|
|
Scope objects in the system, number of ScriptObject listeners added,
|
|
removed and dead (without references).
|
|
|
|
We also count number of ScriptFunctions, ScriptFunction invocations
|
|
and ScriptFunction allocations.
|
|
|
|
Furthermore we count PropertyMap statistics: how many property maps
|
|
exist, how many times were property maps cloned, how many times did
|
|
the property map history cache hit, prevent new allocations, how many
|
|
prototype invalidations were done, how many time the property map
|
|
proto cache hit.
|
|
|
|
Finally we count callsite misses on a per callsite bases, which occur
|
|
when a callsite has to be relinked, due to a previous assumption of
|
|
object layout being invalidated.
|
|
|
|
|
|
SYSTEM PROPERTY: -Dnashorn.methodhandles.debug,
|
|
-Dnashorn.methodhandles.debug=create
|
|
|
|
If this property is enabled, each MethodHandle related call that uses
|
|
the java.lang.invoke package gets its MethodHandle intercepted and an
|
|
instrumentation printout of arguments and return value appended to
|
|
it. This shows exactly which method handles are executed and from
|
|
where. (Also MethodTypes and SwitchPoints). This can be augmented with
|
|
more information, for example, instance count, by subclassing or
|
|
further extending the TraceMethodHandleFactory implementation in
|
|
MethodHandleFactory.java.
|
|
|
|
If the property is specialized with "=create" as its option,
|
|
instrumentation will be shown for method handles upon creation time
|
|
rather than at runtime usage.
|
|
|
|
|
|
SYSTEM PROPERTY: -Dnashorn.methodhandles.debug.stacktrace
|
|
|
|
This does the same as nashorn.methodhandles.debug, but when enabled
|
|
also dumps the stack trace for every instrumented method handle
|
|
operation. Warning: This is enormously verbose, but provides a pretty
|
|
decent "grep:able" picture of where the calls are coming from.
|
|
|
|
See the description of the codegen logger below for a more verbose
|
|
description of this option
|
|
|
|
|
|
SYSTEM PROPERTY: -Dnashorn.scriptfunction.specialization.disable
|
|
|
|
There are several "fast path" implementations of constructors and
|
|
functions in the NativeObject classes that, in their original form,
|
|
take a variable amount of arguments. Said functions are also declared
|
|
to take Object parameters in their original form, as this is what the
|
|
JavaScript specification mandates.
|
|
However, we often know quite a lot more at a callsite of one of these
|
|
functions. For example, Math.min is called with a fixed number (2) of
|
|
integer arguments. The overhead of boxing these ints to Objects and
|
|
folding them into an Object array for the generic varargs Math.min
|
|
function is an order of magnitude slower than calling a specialized
|
|
implementation of Math.min that takes two integers. Specialized
|
|
functions and constructors are identified by the tag
|
|
@SpecializedFunction and @SpecializedConstructor in the Nashorn
|
|
code. The linker will link in the most appropriate (narrowest types,
|
|
right number of types and least number of arguments) specialization if
|
|
specializations are available.
|
|
|
|
Every ScriptFunction may carry specializations that the linker can
|
|
choose from. This framework will likely be extended for user defined
|
|
functions. The compiler can often infer enough parameter type info
|
|
from callsites for in order to generate simpler versions with less
|
|
generic Object types. This feature depends on future lazy jitting, as
|
|
there tend to be many calls to user defined functions, some where the
|
|
callsite can be specialized, some where we mostly see object
|
|
parameters even at the callsite.
|
|
|
|
If this system property is set to true, the linker will not attempt to
|
|
use any specialized function or constructor for native objects, but
|
|
just call the generic one.
|
|
|
|
|
|
SYSTEM PROPERTY: -Dnashorn.tcs.miss.samplePercent=<x>
|
|
|
|
When running with the trace callsite option (-tcs), Nashorn will count
|
|
and instrument any callsite misses that require relinking. As the
|
|
number of relinks is large and usually produces a lot of output, this
|
|
system property can be used to constrain the percentage of misses that
|
|
should be logged. Typically this is set to 1 or 5 (percent). 1% is the
|
|
default value.
|
|
|
|
|
|
SYSTEM_PROPERTY: -Dnashorn.profilefile=<filename>
|
|
|
|
When running with the profile callsite options (-pcs), Nashorn will
|
|
dump profiling data for all callsites to stderr as a shutdown hook. To
|
|
instead redirect this to a file, specify the path to the file using
|
|
this system property.
|
|
|
|
|
|
SYSTEM_PROPERTY: -Dnashorn.regexp.impl=[jdk|joni]
|
|
|
|
This property defines the regular expression engine to be used by
|
|
Nashorn. Set this flag to "jdk" to get an implementation based on the
|
|
JDK's java.util.regex package. Set this property to "joni" to install
|
|
an implementation based on Joni, the regular expression engine used by
|
|
the JRuby project. The default value for this flag is "joni"
|
|
|
|
|
|
SYSTEM PROPERTY: -Dnashorn.time
|
|
|
|
This enables timers for various phases of script compilation. The timers
|
|
will be dumped when the Nashorn process exits. We see a percentage value
|
|
of how much time was spent not executing bytecode (i.e. compilation and
|
|
internal tasks) at the end of the report.
|
|
|
|
Here is an example:
|
|
|
|
[JavaScript Parsing] 61 ms
|
|
[Constant Folding] 11 ms
|
|
[Control Flow Lowering] 26 ms
|
|
[Type Attribution] 81 ms
|
|
[Range Analysis] 0 ms
|
|
[Code Splitting] 29 ms
|
|
[Type Finalization] 19 ms
|
|
[Bytecode Generation] 189 ms
|
|
[Code Installation] 7 ms
|
|
Total runtime: 508 ms (Non-runtime: 423 ms [83%])
|
|
|
|
===============
|
|
2. The loggers.
|
|
===============
|
|
|
|
It is very simple to create your own logger. Use the DebugLogger class
|
|
and give the subsystem name as a constructor argument.
|
|
|
|
The Nashorn loggers can be used to print per-module or per-subsystem
|
|
debug information with different levels of verbosity. The loggers for
|
|
a given subsystem are available are enabled by using
|
|
|
|
--log=<systemname>[:<level>]
|
|
|
|
on the command line.
|
|
|
|
Here <systemname> identifies the name of the subsystem to be logged
|
|
and the optional colon and level argument is a standard
|
|
java.util.logging.Level name (severe, warning, info, config, fine,
|
|
finer, finest). If the level is left out for a particular subsystem,
|
|
it defaults to "info". Any log message logged as the level or a level
|
|
that is more important will be output to stderr by the logger.
|
|
|
|
Several loggers can be enabled by a single command line option, by
|
|
putting a comma after each subsystem/level tuple (or each subsystem if
|
|
level is unspecified). The --log option can also be given multiple
|
|
times on the same command line, with the same effect.
|
|
|
|
For example: --log=codegen,fields:finest is equivalent to
|
|
--log=codegen:info --log=fields:finest
|
|
|
|
The subsystems that currently support logging are:
|
|
|
|
|
|
* compiler
|
|
|
|
The compiler is in charge of turning source code and function nodes
|
|
into byte code, and installs the classes into a class loader
|
|
controlled from the Context. Log messages are, for example, about
|
|
things like new compile units being allocated. The compiler has global
|
|
settings that all the tiers of codegen (e.g. Lower and CodeGenerator)
|
|
use.s
|
|
|
|
|
|
* codegen
|
|
|
|
The code generator is the emitter stage of the code pipeline, and
|
|
turns the lowest tier of a FunctionNode into bytecode. Codegen logging
|
|
shows byte codes as they are being emitted, line number information
|
|
and jumps. It also shows the contents of the bytecode stack prior to
|
|
each instruction being emitted. This is a good debugging aid. For
|
|
example:
|
|
|
|
[codegen] #41 line:2 (f)_afc824e
|
|
[codegen] #42 load symbol x slot=2
|
|
[codegen] #43 {1:O} load int 0
|
|
[codegen] #44 {2:I O} dynamic_runtime_call GT:ZOI_I args=2 returnType=boolean
|
|
[codegen] #45 signature (Ljava/lang/Object;I)Z
|
|
[codegen] #46 {1:Z} ifeq ternary_false_5402fe28
|
|
[codegen] #47 load symbol x slot=2
|
|
[codegen] #48 {1:O} goto ternary_exit_107c1f2f
|
|
[codegen] #49 ternary_false_5402fe28
|
|
[codegen] #50 load symbol x slot=2
|
|
[codegen] #51 {1:O} convert object -> double
|
|
[codegen] #52 {1:D} neg
|
|
[codegen] #53 {1:D} convert double -> object
|
|
[codegen] #54 {1:O} ternary_exit_107c1f2f
|
|
[codegen] #55 {1:O} return object
|
|
|
|
shows a ternary node being generated for the sequence "return x > 0 ?
|
|
x : -x"
|
|
|
|
The first number on the log line is a unique monotonically increasing
|
|
emission id per bytecode. There is no guarantee this is the same id
|
|
between runs. depending on non deterministic code
|
|
execution/compilation, but for small applications it usually is. If
|
|
the system variable -Dnashorn.codegen.debug.trace=<x> is set, where x
|
|
is a bytecode emission id, a stack trace will be shown as the
|
|
particular bytecode is about to be emitted. This can be a quick way to
|
|
determine where it comes from without attaching the debugger. "Who
|
|
generated that neg?"
|
|
|
|
The --log=codegen option is equivalent to setting the system variable
|
|
"nashorn.codegen.debug" to true.
|
|
|
|
* fold
|
|
|
|
Shows constant folding taking place before lowering
|
|
|
|
* lower
|
|
|
|
This is the first lowering pass.
|
|
|
|
Lower is a code generation pass that turns high level IR nodes into
|
|
lower level one, for example substituting comparisons to RuntimeNodes
|
|
and inlining finally blocks.
|
|
|
|
Lower is also responsible for determining control flow information
|
|
like end points.
|
|
|
|
|
|
* attr
|
|
|
|
The lowering annotates a FunctionNode with symbols for each identifier
|
|
and transforms high level constructs into lower level ones, that the
|
|
CodeGenerator consumes.
|
|
|
|
Lower logging typically outputs things like post pass actions,
|
|
insertions of casts because symbol types have been changed and type
|
|
specialization information. Currently very little info is generated by
|
|
this logger. This will probably change.
|
|
|
|
|
|
* finalize
|
|
|
|
This --log=finalize log option outputs information for type finalization,
|
|
the third tier of the compiler. This means things like placement of
|
|
specialized scope nodes or explicit conversions.
|
|
|
|
|
|
* fields
|
|
|
|
The --log=fields option (at info level) is equivalent to setting the
|
|
system variable "nashorn.fields.debug" to true. At the info level it
|
|
will only show info about type assumptions that were invalidated. If
|
|
the level is set to finest, it will also trace every AccessorProperty
|
|
getter and setter in the program, show arguments, return values
|
|
etc. It will also show the internal representation of respective field
|
|
(Object in the normal case, unless running with the dual field
|
|
representation)
|
|
|
|
|
|
=======================
|
|
3. Undocumented options
|
|
=======================
|
|
|
|
Here follows a short description of undocumented options for Nashorn.
|
|
To see a list of all undocumented options, use the (undocumented) flag
|
|
"-xhelp".
|
|
|
|
i.e. jjs -xhelp or java -jar nashorn.jar -xhelp
|
|
|
|
Undocumented options are not guaranteed to work, run correctly or be
|
|
bug free. They are experimental and for internal or debugging use.
|
|
They are also subject to change without notice.
|
|
|
|
In practice, though, all options below not explicitly documented as
|
|
EXPERIMENTAL can be relied upon, for example --dump-on-error is useful
|
|
for any JavaScript/Nashorn developer, but there is no guarantee.
|
|
|
|
A short summary follows:
|
|
|
|
-D (-Dname=value. Set a system property. This option can be repeated.)
|
|
|
|
-ccs, --class-cache-size (Size of the Class cache size per global scope.)
|
|
|
|
-cp, -classpath (-cp path. Specify where to find user class files.)
|
|
|
|
-co, --compile-only (Compile script without running. Exit after compilation)
|
|
param: [true|false] default: false
|
|
|
|
-d, --dump-debug-dir (specify a destination directory to dump class files.
|
|
This must be combined with the --compile-only option to work)
|
|
param: <path>
|
|
|
|
--debug-lines (Generate line number table in .class files.)
|
|
param: [true|false] default: true
|
|
|
|
--debug-locals (Generate local variable table in .class files.)
|
|
param: [true|false] default: false
|
|
|
|
-doe, -dump-on-error (Dump a stack trace on errors.)
|
|
param: [true|false] default: false
|
|
|
|
--early-lvalue-error (invalid lvalue expressions should be reported as early errors.)
|
|
param: [true|false] default: true
|
|
|
|
--empty-statements (Preserve empty statements in AST.)
|
|
param: [true|false] default: false
|
|
|
|
-fv, -fullversion (Print full version info of Nashorn.)
|
|
param: [true|false] default: false
|
|
|
|
--function-statement-error (Report an error when function declaration is used as a statement.)
|
|
param: [true|false] default: false
|
|
|
|
--function-statement-warning (Warn when function declaration is used as a statement.)
|
|
param: [true|false] default: false
|
|
|
|
-fx (Launch script as an fx application.)
|
|
param: [true|false] default: false
|
|
|
|
--global-per-engine (Use single Global instance per script engine instance.)
|
|
param: [true|false] default: false
|
|
|
|
-h, -help (Print help for command line flags.)
|
|
param: [true|false] default: false
|
|
|
|
--lazy-compilation (EXPERIMENTAL: Use lazy code generation strategies - do not compile
|
|
the entire script at once.)
|
|
param: [true|false] default: false
|
|
|
|
--loader-per-compile (Create a new class loader per compile.)
|
|
param: [true|false] default: true
|
|
|
|
-l, --locale (Set Locale for script execution.)
|
|
param: <locale> default: en-US
|
|
|
|
--log (Enable logging of a given level for a given number of sub systems.
|
|
[for example: --log=fields:finest,codegen:info])
|
|
param: <module:level>,*
|
|
|
|
-nj, --no-java (No Java support)
|
|
param: [true|false] default: false
|
|
|
|
-nse, --no-syntax-extensions (No non-standard syntax extensions)
|
|
param: [true|false] default: false
|
|
|
|
-nta, --no-typed-arrays (No Typed arrays support)
|
|
param: [true|false] default: false
|
|
|
|
--parse-only (Parse without compiling.)
|
|
param: [true|false] default: false
|
|
|
|
--print-ast (Print abstract syntax tree.)
|
|
param: [true|false] default: false
|
|
|
|
--print-code (Print bytecode.)
|
|
param: [true|false] default: false
|
|
|
|
--print-lower-ast (Print lowered abstract syntax tree.)
|
|
param: [true|false] default: false
|
|
|
|
--print-lower-parse (Print the parse tree after lowering.)
|
|
param: [true|false] default: false
|
|
|
|
--print-mem-usage (Print memory usage of IR after each compile stage.)
|
|
param: [true|false] default: false
|
|
|
|
--print-no-newline (Print function will not print new line char.)
|
|
param: [true|false] default: false
|
|
|
|
--print-parse (Print the parse tree.)
|
|
param: [true|false] default: false
|
|
|
|
--print-symbols (Print the symbol table.)
|
|
param: [true|false] default: false
|
|
|
|
-pcs, --profile-callsites (Dump callsite profile data.)
|
|
param: [true|false] default: false
|
|
|
|
--range-analysis (EXPERIMENTAL: Do range analysis using known compile time types,
|
|
and try to narrow number types)
|
|
param: [true|false] default: false
|
|
|
|
-scripting (Enable scripting features.)
|
|
param: [true|false] default: false
|
|
|
|
--specialize-calls (EXPERIMENTAL: Specialize all or a set of method according
|
|
to callsite parameter types)
|
|
param: [=function_1,...,function_n]
|
|
|
|
--stderr (Redirect stderr to a filename or to another tty, e.g. stdout)
|
|
param: <output console>
|
|
|
|
--stdout (Redirect stdout to a filename or to another tty, e.g. stderr)
|
|
param: <output console>
|
|
|
|
-strict (Run scripts in strict mode.)
|
|
param: [true|false] default: false
|
|
|
|
-t, -timezone (Set timezone for script execution.)
|
|
param: <timezone> default: Europe/Stockholm
|
|
|
|
-tcs, --trace-callsites (Enable callsite trace mode. Options are: miss [trace callsite misses]
|
|
enterexit [trace callsite enter/exit], objects [print object properties])
|
|
param: [=[option,]*]
|
|
|
|
--verify-code (Verify byte code before running.)
|
|
param: [true|false] default: false
|
|
|
|
-v, -version (Print version info of Nashorn.)
|
|
param: [true|false] default: false
|
|
|
|
-xhelp (Print extended help for command line flags.)
|
|
param: [true|false] default: false
|
|
|