Merge
This commit is contained in:
commit
acaf7ca35c
nashorn
buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen
docs
src/jdk
internal/dynalink
nashorn
api/scripting
internal
codegen
objects
NativeArray.javaNativeArrayBuffer.javaNativeFloat32Array.javaNativeFloat64Array.javaNativeInt16Array.javaNativeInt32Array.javaNativeInt8Array.javaNativeJava.javaNativeObject.javaNativeRegExp.javaNativeString.javaNativeUint16Array.javaNativeUint32Array.javaNativeUint8Array.javaNativeUint8ClampedArray.java
parser
runtime
Context.javaDebuggerSupport.javaJSType.javaPropertyListener.javaPropertyListenerManager.javaPropertyMap.javaScriptEnvironment.javaScriptObject.javaScriptRuntime.javaWithObject.java
linker
Bootstrap.javaBoundDynamicMethodLinker.javaJavaAdapterBytecodeGenerator.javaJavaAdapterClassLoader.javaJavaSuperAdapter.javaJavaSuperAdapterLinker.java
regexp
RegExp.java
joni
resources
tools
test
script/basic
JDK-8019987.jsJDK-8022903.jsJDK-8022903.js.EXPECTEDJDK-8023368.jsJDK-8023368.js.EXPECTEDJDK-8023368_2.jsJDK-8023368_2.js.EXPECTEDJDK-8023373.jsJDK-8023373.js.EXPECTEDJDK-8023531.jsJDK-8023551.jsJDK-8023551.js.EXPECTEDJDK-8023630.jsJDK-8023630.js.EXPECTEDJDK-8023650.jsJDK-8023780.jsJDK-8023780.js.EXPECTEDJDK-8023784.jsJDK-8023784.js.EXPECTEDNASHORN-377.js.EXPECTEDNASHORN-397.jscircular_proto.jscircular_proto.js.EXPECTEDmirror_proto_assign.jsmirror_proto_assign.js.EXPECTEDnonextensible_proto_assign.jsnonextensible_proto_assign.js.EXPECTED
src/jdk/nashorn
api/scripting
internal/runtime
tools/fxshell/jdk/nashorn/tools
@ -27,7 +27,6 @@ package jdk.nashorn.internal.tools.nasgen;
|
||||
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_FINAL;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.V1_7;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.CONSTRUCTOR_SUFFIX;
|
||||
|
@ -27,7 +27,6 @@ package jdk.nashorn.internal.tools.nasgen;
|
||||
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DUP;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.GETSTATIC;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.NEW;
|
||||
|
@ -16,8 +16,9 @@ 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.
|
||||
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:
|
||||
|
||||
@ -43,6 +44,10 @@ 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
|
||||
@ -65,13 +70,382 @@ 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.
|
||||
|
||||
There is also a problem with this optimistic approach if the symbol
|
||||
happens to reside in a local variable slot in the bytecode, as those
|
||||
are strongly typed. Then we would need to split large sections of
|
||||
control flow, so this is probably not the right way to go, while range
|
||||
analysis is. There is a large difference between integer bytecode
|
||||
without overflow checks and double bytecode. The former is
|
||||
significantly faster.
|
||||
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>
|
||||
@ -167,7 +541,7 @@ 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) Possibly optimistic callsite writes, something on the form
|
||||
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
|
||||
@ -189,6 +563,12 @@ 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>[,*]]
|
||||
@ -211,7 +591,7 @@ traces will be displayed upon symbol changes according to the same
|
||||
semantics.
|
||||
|
||||
|
||||
SYSTEM PROPERTY: nashorn.lexer.xmlliterals
|
||||
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
|
||||
@ -222,7 +602,7 @@ XML literals, when this is enabled, end up as standard LiteralNodes in
|
||||
the IR.
|
||||
|
||||
|
||||
SYSTEM_PROPERTY: nashorn.debug
|
||||
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
|
||||
@ -269,8 +649,8 @@ when a callsite has to be relinked, due to a previous assumption of
|
||||
object layout being invalidated.
|
||||
|
||||
|
||||
SYSTEM PROPERTY: nashorn.methodhandles.debug,
|
||||
nashorn.methodhandles.debug=create
|
||||
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
|
||||
@ -286,7 +666,7 @@ instrumentation will be shown for method handles upon creation time
|
||||
rather than at runtime usage.
|
||||
|
||||
|
||||
SYSTEM PROPERTY: nashorn.methodhandles.debug.stacktrace
|
||||
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
|
||||
@ -297,14 +677,13 @@ See the description of the codegen logger below for a more verbose
|
||||
description of this option
|
||||
|
||||
|
||||
SYSTEM PROPERTY: nashorn.scriptfunction.specialization.disable
|
||||
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
|
||||
@ -331,7 +710,7 @@ use any specialized function or constructor for native objects, but
|
||||
just call the generic one.
|
||||
|
||||
|
||||
SYSTEM PROPERTY: nashorn.tcs.miss.samplePercent=<x>
|
||||
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
|
||||
@ -341,7 +720,7 @@ should be logged. Typically this is set to 1 or 5 (percent). 1% is the
|
||||
default value.
|
||||
|
||||
|
||||
SYSTEM_PROPERTY: nashorn.profilefile=<filename>
|
||||
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
|
||||
@ -349,15 +728,35 @@ instead redirect this to a file, specify the path to the file using
|
||||
this system property.
|
||||
|
||||
|
||||
SYSTEM_PROPERTY: nashorn.regexp.impl=[jdk|joni]
|
||||
SYSTEM_PROPERTY: -Dnashorn.regexp.impl=[jdk|joni]
|
||||
|
||||
This property defines the regular expression engine to be used by
|
||||
Nashorn. The default implementation is "jdk" which is based on the
|
||||
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 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.
|
||||
===============
|
||||
@ -442,6 +841,9 @@ 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
|
||||
|
||||
@ -484,3 +886,160 @@ 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
|
||||
|
||||
|
@ -121,7 +121,6 @@ public class ChainedCallSite extends AbstractRelinkableCallSite {
|
||||
* to change the value. If your override returns a value less than 1, the code will break.
|
||||
* @return the maximum number of method handles in the chain.
|
||||
*/
|
||||
@SuppressWarnings("static-method")
|
||||
protected int getMaxChainLength() {
|
||||
return 8;
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ public class DefaultBootstrapper {
|
||||
* @param type the method signature at the call site
|
||||
* @return a new {@link MonomorphicCallSite} linked with the default dynamic linker.
|
||||
*/
|
||||
public static CallSite publicBootstrap(@SuppressWarnings("unused") MethodHandles.Lookup caller, String name, MethodType type) {
|
||||
public static CallSite publicBootstrap(MethodHandles.Lookup caller, String name, MethodType type) {
|
||||
return bootstrapInternal(MethodHandles.publicLookup(), name, type);
|
||||
}
|
||||
|
||||
|
@ -97,6 +97,7 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import jdk.internal.dynalink.CallSiteDescriptor;
|
||||
import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType;
|
||||
import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||
|
@ -148,6 +148,7 @@ class OverloadedDynamicMethod extends DynamicMethod {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("fallthrough")
|
||||
@Override
|
||||
public MethodHandle getInvocation(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) {
|
||||
final MethodType callSiteType = callSiteDescriptor.getMethodType();
|
||||
|
@ -55,6 +55,7 @@ import javax.script.ScriptContext;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineFactory;
|
||||
import javax.script.ScriptException;
|
||||
import javax.script.SimpleBindings;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
import jdk.nashorn.internal.runtime.ErrorManager;
|
||||
import jdk.nashorn.internal.runtime.GlobalObject;
|
||||
@ -74,6 +75,12 @@ import jdk.nashorn.internal.runtime.options.Options;
|
||||
*/
|
||||
|
||||
public final class NashornScriptEngine extends AbstractScriptEngine implements Compilable, Invocable {
|
||||
/**
|
||||
* Key used to associate Nashorn global object mirror with arbitrary Bindings instance.
|
||||
*/
|
||||
public static final String NASHORN_GLOBAL = "nashorn.global";
|
||||
|
||||
// commonly used access control context objects
|
||||
private static AccessControlContext createPermAccCtxt(final String permName) {
|
||||
final Permissions perms = new Permissions();
|
||||
perms.add(new RuntimePermission(permName));
|
||||
@ -83,16 +90,23 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
||||
private static final AccessControlContext CREATE_CONTEXT_ACC_CTXT = createPermAccCtxt(Context.NASHORN_CREATE_CONTEXT);
|
||||
private static final AccessControlContext CREATE_GLOBAL_ACC_CTXT = createPermAccCtxt(Context.NASHORN_CREATE_GLOBAL);
|
||||
|
||||
// the factory that created this engine
|
||||
private final ScriptEngineFactory factory;
|
||||
// underlying nashorn Context - 1:1 with engine instance
|
||||
private final Context nashornContext;
|
||||
// do we want to share single Nashorn global instance across ENGINE_SCOPEs?
|
||||
private final boolean _global_per_engine;
|
||||
// This is the initial default Nashorn global object.
|
||||
// This is used as "shared" global if above option is true.
|
||||
private final ScriptObject global;
|
||||
// initialized bit late to be made 'final'. Property object for "context"
|
||||
// property of global object
|
||||
private Property contextProperty;
|
||||
// initialized bit late to be made 'final'.
|
||||
// Property object for "context" property of global object.
|
||||
private volatile Property contextProperty;
|
||||
|
||||
// default options passed to Nashorn Options object
|
||||
private static final String[] DEFAULT_OPTIONS = new String[] { "-scripting", "-doe" };
|
||||
|
||||
// Nashorn script engine error message management
|
||||
private static final String MESSAGES_RESOURCE = "jdk.nashorn.api.scripting.resources.Messages";
|
||||
|
||||
private static final ResourceBundle MESSAGES_BUNDLE;
|
||||
@ -100,6 +114,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
||||
MESSAGES_BUNDLE = ResourceBundle.getBundle(MESSAGES_RESOURCE, Locale.getDefault());
|
||||
}
|
||||
|
||||
// helper to get Nashorn script engine error message
|
||||
private static String getMessage(final String msgId, final String... args) {
|
||||
try {
|
||||
return new MessageFormat(MESSAGES_BUNDLE.getString(msgId)).format(args);
|
||||
@ -108,6 +123,31 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
||||
}
|
||||
}
|
||||
|
||||
// load engine.js and return content as a char[]
|
||||
@SuppressWarnings("resource")
|
||||
private static char[] loadEngineJSSource() {
|
||||
final String script = "resources/engine.js";
|
||||
try {
|
||||
final InputStream is = AccessController.doPrivileged(
|
||||
new PrivilegedExceptionAction<InputStream>() {
|
||||
@Override
|
||||
public InputStream run() throws Exception {
|
||||
final URL url = NashornScriptEngine.class.getResource(script);
|
||||
return url.openStream();
|
||||
}
|
||||
});
|
||||
return Source.readFully(new InputStreamReader(is));
|
||||
} catch (final PrivilegedActionException | IOException e) {
|
||||
if (Context.DEBUG) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Source object for engine.js
|
||||
private static final Source ENGINE_SCRIPT_SRC = new Source(NashornException.ENGINE_SCRIPT_SOURCE_NAME, loadEngineJSSource());
|
||||
|
||||
NashornScriptEngine(final NashornScriptEngineFactory factory, final ClassLoader appLoader) {
|
||||
this(factory, DEFAULT_OPTIONS, appLoader);
|
||||
}
|
||||
@ -134,20 +174,13 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
||||
}
|
||||
}, CREATE_CONTEXT_ACC_CTXT);
|
||||
|
||||
// create new global object
|
||||
this.global = createNashornGlobal();
|
||||
// set the default engine scope for the default context
|
||||
context.setBindings(new ScriptObjectMirror(global, global), ScriptContext.ENGINE_SCOPE);
|
||||
// cache this option that is used often
|
||||
this._global_per_engine = nashornContext.getEnv()._global_per_engine;
|
||||
|
||||
// evaluate engine initial script
|
||||
try {
|
||||
evalEngineScript();
|
||||
} catch (final ScriptException e) {
|
||||
if (Context.DEBUG) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
// create new global object
|
||||
this.global = createNashornGlobal(context);
|
||||
// set the default ENGINE_SCOPE object for the default context
|
||||
context.setBindings(new ScriptObjectMirror(global, global), ScriptContext.ENGINE_SCOPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -176,8 +209,12 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
||||
|
||||
@Override
|
||||
public Bindings createBindings() {
|
||||
final ScriptObject newGlobal = createNashornGlobal();
|
||||
return new ScriptObjectMirror(newGlobal, newGlobal);
|
||||
if (_global_per_engine) {
|
||||
// just create normal SimpleBindings.
|
||||
// We use same 'global' for all Bindings.
|
||||
return new SimpleBindings();
|
||||
}
|
||||
return createGlobalMirror(null);
|
||||
}
|
||||
|
||||
// Compilable methods
|
||||
@ -213,6 +250,48 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
||||
return invokeImpl(thiz, name, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getInterface(final Class<T> clazz) {
|
||||
return getInterfaceInner(null, clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getInterface(final Object thiz, final Class<T> clazz) {
|
||||
if (thiz == null) {
|
||||
throw new IllegalArgumentException(getMessage("thiz.cannot.be.null"));
|
||||
}
|
||||
return getInterfaceInner(thiz, clazz);
|
||||
}
|
||||
|
||||
// These are called from the "engine.js" script
|
||||
|
||||
/**
|
||||
* This hook is used to search js global variables exposed from Java code.
|
||||
*
|
||||
* @param self 'this' passed from the script
|
||||
* @param ctxt current ScriptContext in which name is searched
|
||||
* @param name name of the variable searched
|
||||
* @return the value of the named variable
|
||||
*/
|
||||
public Object __noSuchProperty__(final Object self, final ScriptContext ctxt, final String name) {
|
||||
if (ctxt != null) {
|
||||
final int scope = ctxt.getAttributesScope(name);
|
||||
final ScriptObject ctxtGlobal = getNashornGlobalFrom(ctxt);
|
||||
if (scope != -1) {
|
||||
return ScriptObjectMirror.unwrap(ctxt.getAttribute(name, scope), ctxtGlobal);
|
||||
}
|
||||
|
||||
if (self == UNDEFINED) {
|
||||
// scope access and so throw ReferenceError
|
||||
throw referenceError(ctxtGlobal, "not.defined", name);
|
||||
}
|
||||
}
|
||||
|
||||
return UNDEFINED;
|
||||
}
|
||||
|
||||
// Implementation only below this point
|
||||
|
||||
private <T> T getInterfaceInner(final Object thiz, final Class<T> clazz) {
|
||||
if (clazz == null || !clazz.isInterface()) {
|
||||
throw new IllegalArgumentException(getMessage("interface.class.expected"));
|
||||
@ -280,58 +359,56 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getInterface(final Class<T> clazz) {
|
||||
return getInterfaceInner(null, clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getInterface(final Object thiz, final Class<T> clazz) {
|
||||
if (thiz == null) {
|
||||
throw new IllegalArgumentException(getMessage("thiz.cannot.be.null"));
|
||||
}
|
||||
return getInterfaceInner(thiz, clazz);
|
||||
}
|
||||
|
||||
// These are called from the "engine.js" script
|
||||
|
||||
/**
|
||||
* This hook is used to search js global variables exposed from Java code.
|
||||
*
|
||||
* @param self 'this' passed from the script
|
||||
* @param ctxt current ScriptContext in which name is searched
|
||||
* @param name name of the variable searched
|
||||
* @return the value of the named variable
|
||||
*/
|
||||
public Object __noSuchProperty__(final Object self, final ScriptContext ctxt, final String name) {
|
||||
final int scope = ctxt.getAttributesScope(name);
|
||||
final ScriptObject ctxtGlobal = getNashornGlobalFrom(ctxt);
|
||||
if (scope != -1) {
|
||||
return ScriptObjectMirror.unwrap(ctxt.getAttribute(name, scope), ctxtGlobal);
|
||||
}
|
||||
|
||||
if (self == UNDEFINED) {
|
||||
// scope access and so throw ReferenceError
|
||||
throw referenceError(ctxtGlobal, "not.defined", name);
|
||||
}
|
||||
|
||||
return UNDEFINED;
|
||||
}
|
||||
|
||||
// Retrieve nashorn Global object for a given ScriptContext object
|
||||
private ScriptObject getNashornGlobalFrom(final ScriptContext ctxt) {
|
||||
final Bindings bindings = ctxt.getBindings(ScriptContext.ENGINE_SCOPE);
|
||||
if (bindings instanceof ScriptObjectMirror) {
|
||||
ScriptObject sobj = ((ScriptObjectMirror)bindings).getScriptObject();
|
||||
if (sobj instanceof GlobalObject) {
|
||||
return sobj;
|
||||
}
|
||||
if (_global_per_engine) {
|
||||
// shared single global object for all ENGINE_SCOPE Bindings
|
||||
return global;
|
||||
}
|
||||
|
||||
// didn't find global object from context given - return the engine-wide global
|
||||
return global;
|
||||
final Bindings bindings = ctxt.getBindings(ScriptContext.ENGINE_SCOPE);
|
||||
// is this Nashorn's own Bindings implementation?
|
||||
if (bindings instanceof ScriptObjectMirror) {
|
||||
final ScriptObject sobj = globalFromMirror((ScriptObjectMirror)bindings);
|
||||
if (sobj != null) {
|
||||
return sobj;
|
||||
}
|
||||
}
|
||||
|
||||
// Arbitrary user Bindings implementation. Look for NASHORN_GLOBAL in it!
|
||||
Object scope = bindings.get(NASHORN_GLOBAL);
|
||||
if (scope instanceof ScriptObjectMirror) {
|
||||
final ScriptObject sobj = globalFromMirror((ScriptObjectMirror)scope);
|
||||
if (sobj != null) {
|
||||
return sobj;
|
||||
}
|
||||
}
|
||||
|
||||
// We didn't find associated nashorn global mirror in the Bindings given!
|
||||
// Create new global instance mirror and associate with the Bindings.
|
||||
final ScriptObjectMirror mirror = createGlobalMirror(ctxt);
|
||||
bindings.put(NASHORN_GLOBAL, mirror);
|
||||
return mirror.getScriptObject();
|
||||
}
|
||||
|
||||
private ScriptObject createNashornGlobal() {
|
||||
// Retrieve nashorn Global object from a given ScriptObjectMirror
|
||||
private ScriptObject globalFromMirror(final ScriptObjectMirror mirror) {
|
||||
ScriptObject sobj = mirror.getScriptObject();
|
||||
if (sobj instanceof GlobalObject && sobj.isOfContext(nashornContext)) {
|
||||
return sobj;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Create a new ScriptObjectMirror wrapping a newly created Nashorn Global object
|
||||
private ScriptObjectMirror createGlobalMirror(final ScriptContext ctxt) {
|
||||
final ScriptObject newGlobal = createNashornGlobal(ctxt);
|
||||
return new ScriptObjectMirror(newGlobal, newGlobal);
|
||||
}
|
||||
|
||||
// Create a new Nashorn Global object
|
||||
private ScriptObject createNashornGlobal(final ScriptContext ctxt) {
|
||||
final ScriptObject newGlobal = AccessController.doPrivileged(new PrivilegedAction<ScriptObject>() {
|
||||
@Override
|
||||
public ScriptObject run() {
|
||||
@ -352,7 +429,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
||||
// current ScriptContext exposed as "context"
|
||||
// "context" is non-writable from script - but script engine still
|
||||
// needs to set it and so save the context Property object
|
||||
contextProperty = newGlobal.addOwnProperty("context", NON_ENUMERABLE_CONSTANT, UNDEFINED);
|
||||
contextProperty = newGlobal.addOwnProperty("context", NON_ENUMERABLE_CONSTANT, null);
|
||||
// current ScriptEngine instance exposed as "engine". We added @SuppressWarnings("LeakingThisInConstructor") as
|
||||
// NetBeans identifies this assignment as such a leak - this is a false positive as we're setting this property
|
||||
// in the Global of a Context we just created - both the Context and the Global were just created and can not be
|
||||
@ -362,38 +439,17 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
||||
newGlobal.addOwnProperty("arguments", Property.NOT_ENUMERABLE, UNDEFINED);
|
||||
// file name default is null
|
||||
newGlobal.addOwnProperty(ScriptEngine.FILENAME, Property.NOT_ENUMERABLE, null);
|
||||
// evaluate engine.js initialization script this new global object
|
||||
try {
|
||||
evalImpl(compileImpl(ENGINE_SCRIPT_SRC, newGlobal), ctxt, newGlobal);
|
||||
} catch (final ScriptException exp) {
|
||||
throw new RuntimeException(exp);
|
||||
}
|
||||
return newGlobal;
|
||||
}
|
||||
|
||||
private void evalEngineScript() throws ScriptException {
|
||||
final String script = "resources/engine.js";
|
||||
final String name = NashornException.ENGINE_SCRIPT_SOURCE_NAME;
|
||||
try {
|
||||
final InputStream is = AccessController.doPrivileged(
|
||||
new PrivilegedExceptionAction<InputStream>() {
|
||||
@Override
|
||||
public InputStream run() throws Exception {
|
||||
final URL url = NashornScriptEngine.class.getResource(script);
|
||||
return url.openStream();
|
||||
}
|
||||
});
|
||||
put(ScriptEngine.FILENAME, name);
|
||||
try (final InputStreamReader isr = new InputStreamReader(is)) {
|
||||
eval(isr);
|
||||
}
|
||||
} catch (final PrivilegedActionException | IOException e) {
|
||||
if (Context.DEBUG) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
throw new ScriptException(e);
|
||||
} finally {
|
||||
put(ScriptEngine.FILENAME, null);
|
||||
}
|
||||
}
|
||||
|
||||
// scripts should see "context" and "engine" as variables
|
||||
private void setContextVariables(final ScriptContext ctxt) {
|
||||
final ScriptObject ctxtGlobal = getNashornGlobalFrom(ctxt);
|
||||
// scripts should see "context" and "engine" as variables in the given global object
|
||||
private void setContextVariables(final ScriptObject ctxtGlobal, final ScriptContext ctxt) {
|
||||
// set "context" global variable via contextProperty - because this
|
||||
// property is non-writable
|
||||
contextProperty.setObjectValue(ctxtGlobal, ctxtGlobal, ctxt, false);
|
||||
@ -402,8 +458,10 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
||||
args = ScriptRuntime.EMPTY_ARRAY;
|
||||
}
|
||||
// if no arguments passed, expose it
|
||||
args = ((GlobalObject)ctxtGlobal).wrapAsObject(args);
|
||||
ctxtGlobal.set("arguments", args, false);
|
||||
if (! (args instanceof ScriptObject)) {
|
||||
args = ((GlobalObject)ctxtGlobal).wrapAsObject(args);
|
||||
ctxtGlobal.set("arguments", args, false);
|
||||
}
|
||||
}
|
||||
|
||||
private Object invokeImpl(final Object selfObject, final String name, final Object... args) throws ScriptException, NoSuchMethodException {
|
||||
@ -456,18 +514,24 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
||||
}
|
||||
|
||||
private Object evalImpl(final ScriptFunction script, final ScriptContext ctxt) throws ScriptException {
|
||||
return evalImpl(script, ctxt, getNashornGlobalFrom(ctxt));
|
||||
}
|
||||
|
||||
private Object evalImpl(final ScriptFunction script, final ScriptContext ctxt, final ScriptObject ctxtGlobal) throws ScriptException {
|
||||
if (script == null) {
|
||||
return null;
|
||||
}
|
||||
final ScriptObject oldGlobal = Context.getGlobal();
|
||||
final ScriptObject ctxtGlobal = getNashornGlobalFrom(ctxt);
|
||||
final boolean globalChanged = (oldGlobal != ctxtGlobal);
|
||||
try {
|
||||
if (globalChanged) {
|
||||
Context.setGlobal(ctxtGlobal);
|
||||
}
|
||||
|
||||
setContextVariables(ctxt);
|
||||
// set ScriptContext variables if ctxt is non-null
|
||||
if (ctxt != null) {
|
||||
setContextVariables(ctxtGlobal, ctxt);
|
||||
}
|
||||
return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(ScriptRuntime.apply(script, ctxtGlobal), ctxtGlobal));
|
||||
} catch (final Exception e) {
|
||||
throwAsScriptException(e);
|
||||
@ -517,15 +581,18 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
||||
}
|
||||
|
||||
private ScriptFunction compileImpl(final Source source, final ScriptContext ctxt) throws ScriptException {
|
||||
return compileImpl(source, getNashornGlobalFrom(ctxt));
|
||||
}
|
||||
|
||||
private ScriptFunction compileImpl(final Source source, final ScriptObject newGlobal) throws ScriptException {
|
||||
final ScriptObject oldGlobal = Context.getGlobal();
|
||||
final ScriptObject ctxtGlobal = getNashornGlobalFrom(ctxt);
|
||||
final boolean globalChanged = (oldGlobal != ctxtGlobal);
|
||||
final boolean globalChanged = (oldGlobal != newGlobal);
|
||||
try {
|
||||
if (globalChanged) {
|
||||
Context.setGlobal(ctxtGlobal);
|
||||
Context.setGlobal(newGlobal);
|
||||
}
|
||||
|
||||
return nashornContext.compileScript(source, ctxtGlobal);
|
||||
return nashornContext.compileScript(source, newGlobal);
|
||||
} catch (final Exception e) {
|
||||
throwAsScriptException(e);
|
||||
throw new AssertionError("should not reach here");
|
||||
|
@ -99,12 +99,14 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
|
||||
}
|
||||
|
||||
final Object val = functionName == null? sobj : sobj.get(functionName);
|
||||
if (! (val instanceof ScriptFunction)) {
|
||||
throw new NoSuchMethodException("No such function " + ((functionName != null)? functionName : ""));
|
||||
if (val instanceof ScriptFunction) {
|
||||
final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
|
||||
return wrap(ScriptRuntime.checkAndApply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)), global);
|
||||
} else if (val instanceof ScriptObjectMirror && ((ScriptObjectMirror)val).isFunction()) {
|
||||
return ((ScriptObjectMirror)val).call(null, args);
|
||||
}
|
||||
|
||||
final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
|
||||
return wrap(ScriptRuntime.checkAndApply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)), global);
|
||||
throw new NoSuchMethodException("No such function " + ((functionName != null)? functionName : ""));
|
||||
} catch (final RuntimeException | Error e) {
|
||||
throw e;
|
||||
} catch (final Throwable t) {
|
||||
@ -127,12 +129,14 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
|
||||
}
|
||||
|
||||
final Object val = functionName == null? sobj : sobj.get(functionName);
|
||||
if (! (val instanceof ScriptFunction)) {
|
||||
throw new RuntimeException("not a constructor " + ((functionName != null)? functionName : ""));
|
||||
if (val instanceof ScriptFunction) {
|
||||
final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
|
||||
return wrap(ScriptRuntime.checkAndConstruct((ScriptFunction)val, unwrapArray(modArgs, global)), global);
|
||||
} else if (val instanceof ScriptObjectMirror && ((ScriptObjectMirror)val).isFunction()) {
|
||||
return ((ScriptObjectMirror)val).newObject(null, args);
|
||||
}
|
||||
|
||||
final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
|
||||
return wrap(ScriptRuntime.checkAndConstruct((ScriptFunction)val, unwrapArray(modArgs, global)), global);
|
||||
throw new RuntimeException("not a constructor " + ((functionName != null)? functionName : ""));
|
||||
} catch (final RuntimeException | Error e) {
|
||||
throw e;
|
||||
} catch (final Throwable t) {
|
||||
@ -373,6 +377,28 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the __proto__ of this object.
|
||||
* @param proto new proto for this object
|
||||
*/
|
||||
public void setProto(final Object proto) {
|
||||
inGlobal(new Callable<Void>() {
|
||||
@Override public Void call() {
|
||||
sobj.setProtoCheck(unwrap(proto, global));
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* ECMA [[Class]] property
|
||||
*
|
||||
* @return ECMA [[Class]] property value of this object
|
||||
*/
|
||||
public String getClassName() {
|
||||
return sobj.getClassName();
|
||||
}
|
||||
|
||||
/**
|
||||
* ECMA 8.12.1 [[GetOwnProperty]] (P)
|
||||
*
|
||||
|
@ -23,10 +23,9 @@
|
||||
|
||||
/**
|
||||
* This script file is executed by script engine at the construction
|
||||
* of the engine. The functions here assume global variables "context"
|
||||
* of type javax.script.ScriptContext and "engine" of the type
|
||||
* of the every new Global object. The functions here assume global variables
|
||||
* "context" of type javax.script.ScriptContext and "engine" of the type
|
||||
* jdk.nashorn.api.scripting.NashornScriptEngine.
|
||||
*
|
||||
**/
|
||||
|
||||
Object.defineProperty(this, "__noSuchProperty__", {
|
||||
@ -40,7 +39,7 @@ Object.defineProperty(this, "__noSuchProperty__", {
|
||||
});
|
||||
|
||||
function print() {
|
||||
var writer = context.getWriter();
|
||||
var writer = context != null? context.writer : engine.context.writer;
|
||||
if (! (writer instanceof java.io.PrintWriter)) {
|
||||
writer = new java.io.PrintWriter(writer);
|
||||
}
|
||||
|
@ -543,8 +543,6 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
|
||||
public Node leaveIdentNode(final IdentNode identNode) {
|
||||
final String name = identNode.getName();
|
||||
|
||||
start(identNode);
|
||||
|
||||
if (identNode.isPropertyName()) {
|
||||
// assign a pseudo symbol to property name
|
||||
final Symbol pseudoSymbol = pseudoSymbol(name);
|
||||
@ -1850,9 +1848,10 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
|
||||
append("] ").
|
||||
append(printNode ? node.toString() : "").
|
||||
append(" in '").
|
||||
append(lc.getCurrentFunction().getName());
|
||||
append(lc.getCurrentFunction().getName()).
|
||||
append('\'');
|
||||
|
||||
if(node instanceof Expression) {
|
||||
if (node instanceof Expression) {
|
||||
final Symbol symbol = ((Expression)node).getSymbol();
|
||||
if (symbol == null) {
|
||||
sb.append(" <NO SYMBOL>");
|
||||
|
@ -414,30 +414,34 @@ enum CompilationPhase {
|
||||
compiler.getCodeInstaller().verify(bytecode);
|
||||
}
|
||||
|
||||
// should code be dumped to disk - only valid in compile_only
|
||||
// mode?
|
||||
// should code be dumped to disk - only valid in compile_only mode?
|
||||
if (env._dest_dir != null && env._compile_only) {
|
||||
final String fileName = className.replace('.', File.separatorChar) + ".class";
|
||||
final int index = fileName.lastIndexOf(File.separatorChar);
|
||||
final int index = fileName.lastIndexOf(File.separatorChar);
|
||||
|
||||
final File dir;
|
||||
if (index != -1) {
|
||||
final File dir = new File(fileName.substring(0, index));
|
||||
try {
|
||||
if (!dir.exists() && !dir.mkdirs()) {
|
||||
throw new IOException(dir.toString());
|
||||
}
|
||||
final File file = new File(env._dest_dir, fileName);
|
||||
try (final FileOutputStream fos = new FileOutputStream(file)) {
|
||||
fos.write(bytecode);
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
Compiler.LOG.warning("Skipping class dump for ",
|
||||
className,
|
||||
": ",
|
||||
ECMAErrors.getMessage(
|
||||
"io.error.cant.write",
|
||||
dir.toString()));
|
||||
dir = new File(env._dest_dir, fileName.substring(0, index));
|
||||
} else {
|
||||
dir = new File(env._dest_dir);
|
||||
}
|
||||
|
||||
try {
|
||||
if (!dir.exists() && !dir.mkdirs()) {
|
||||
throw new IOException(dir.toString());
|
||||
}
|
||||
final File file = new File(env._dest_dir, fileName);
|
||||
try (final FileOutputStream fos = new FileOutputStream(file)) {
|
||||
fos.write(bytecode);
|
||||
}
|
||||
Compiler.LOG.info("Wrote class to '" + file.getAbsolutePath() + '\'');
|
||||
} catch (final IOException e) {
|
||||
Compiler.LOG.warning("Skipping class dump for ",
|
||||
className,
|
||||
": ",
|
||||
ECMAErrors.getMessage(
|
||||
"io.error.cant.write",
|
||||
dir.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import jdk.nashorn.api.scripting.ScriptObjectMirror;
|
||||
import jdk.nashorn.internal.objects.annotations.Attribute;
|
||||
import jdk.nashorn.internal.objects.annotations.Constructor;
|
||||
@ -632,6 +633,7 @@ public final class NativeArray extends ScriptObject {
|
||||
return new NativeArray(list.toArray());
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
private static void concatToList(final ArrayList<Object> list, final Object obj) {
|
||||
final boolean isScriptArray = isArray(obj);
|
||||
final boolean isScriptObject = isScriptArray || obj instanceof ScriptObject;
|
||||
|
@ -73,6 +73,11 @@ final class NativeArrayBuffer extends ScriptObject {
|
||||
this(Arrays.copyOfRange(other.buffer, begin, end));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return "ArrayBuffer";
|
||||
}
|
||||
|
||||
@Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
|
||||
public static Object byteLength(final Object self) {
|
||||
return ((NativeArrayBuffer)self).buffer.length;
|
||||
|
@ -144,6 +144,11 @@ public final class NativeFloat32Array extends ArrayBufferView {
|
||||
super(buffer, byteOffset, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return "Float32Array";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Factory factory() {
|
||||
return FACTORY;
|
||||
|
@ -154,6 +154,11 @@ public final class NativeFloat64Array extends ArrayBufferView {
|
||||
super(buffer, byteOffset, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return "Float64Array";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Factory factory() {
|
||||
return FACTORY;
|
||||
|
@ -108,6 +108,11 @@ public final class NativeInt16Array extends ArrayBufferView {
|
||||
super(buffer, byteOffset, byteLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return "Int16Array";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Factory factory() {
|
||||
return FACTORY;
|
||||
|
@ -111,6 +111,11 @@ public final class NativeInt32Array extends ArrayBufferView {
|
||||
super(buffer, byteOffset, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return "Int32Array";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Factory factory() {
|
||||
return FACTORY;
|
||||
|
@ -101,6 +101,11 @@ public final class NativeInt8Array extends ArrayBufferView {
|
||||
super(buffer, byteOffset, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return "Int8Array";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Factory factory() {
|
||||
return FACTORY;
|
||||
|
@ -32,7 +32,6 @@ import java.lang.reflect.Array;
|
||||
import java.util.Collection;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.internal.dynalink.beans.StaticClass;
|
||||
import jdk.internal.dynalink.support.TypeUtilities;
|
||||
import jdk.nashorn.internal.objects.annotations.Attribute;
|
||||
@ -44,6 +43,7 @@ import jdk.nashorn.internal.runtime.JSType;
|
||||
import jdk.nashorn.internal.runtime.ListAdapter;
|
||||
import jdk.nashorn.internal.runtime.PropertyMap;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.linker.Bootstrap;
|
||||
import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory;
|
||||
|
||||
/**
|
||||
@ -539,4 +539,25 @@ public final class NativeJava {
|
||||
}
|
||||
return JavaAdapterFactory.getAdapterClassFor(stypes, classOverrides);
|
||||
}
|
||||
|
||||
/**
|
||||
* When given an object created using {@code Java.extend()} or equivalent mechanism (that is, any JavaScript-to-Java
|
||||
* adapter), returns an object that can be used to invoke superclass methods on that object. E.g.:
|
||||
* <pre>
|
||||
* var cw = new FilterWriterAdapter(sw) {
|
||||
* write: function(s, off, len) {
|
||||
* s = capitalize(s, off, len)
|
||||
* cw_super.write(s, 0, s.length())
|
||||
* }
|
||||
* }
|
||||
* var cw_super = Java.super(cw)
|
||||
* </pre>
|
||||
* @param self the {@code Java} object itself - not used.
|
||||
* @param adapter the original Java adapter instance for which the super adapter is created.
|
||||
* @return a super adapter for the original adapter
|
||||
*/
|
||||
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR, name="super")
|
||||
public static Object _super(final Object self, final Object adapter) {
|
||||
return Bootstrap.createSuperAdapter(adapter);
|
||||
}
|
||||
}
|
||||
|
@ -124,6 +124,28 @@ public final class NativeObject {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Nashorn extension: Object.setPrototypeOf ( O, proto )
|
||||
* Also found in ES6 draft specification.
|
||||
*
|
||||
* @param self self reference
|
||||
* @param obj object to set prototype for
|
||||
* @param proto prototype object to be used
|
||||
* @return object whose prototype is set
|
||||
*/
|
||||
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
|
||||
public static Object setPrototypeOf(final Object self, final Object obj, final Object proto) {
|
||||
if (obj instanceof ScriptObject) {
|
||||
((ScriptObject)obj).setProtoCheck(proto);
|
||||
return obj;
|
||||
} else if (obj instanceof ScriptObjectMirror) {
|
||||
((ScriptObjectMirror)obj).setProto(proto);
|
||||
return obj;
|
||||
}
|
||||
|
||||
throw notAnObject(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* ECMA 15.2.3.3 Object.getOwnPropertyDescriptor ( O, P )
|
||||
*
|
||||
@ -184,7 +206,7 @@ public final class NativeObject {
|
||||
// FIXME: should we create a proper object with correct number of
|
||||
// properties?
|
||||
final ScriptObject newObj = Global.newEmptyInstance();
|
||||
newObj.setProtoCheck(proto);
|
||||
newObj.setProto((ScriptObject)proto);
|
||||
if (props != UNDEFINED) {
|
||||
NativeObject.defineProperties(self, newObj, props);
|
||||
}
|
||||
@ -647,15 +669,43 @@ public final class NativeObject {
|
||||
|
||||
final List<AccessorProperty> properties = new ArrayList<>(propertyNames.size() + methodNames.size());
|
||||
for(final String methodName: methodNames) {
|
||||
properties.add(AccessorProperty.create(methodName, Property.NOT_WRITABLE,
|
||||
getBoundBeanMethodGetter(source, getBeanOperation(linker, "dyn:getMethod:" + methodName, getterType, source)),
|
||||
null));
|
||||
final MethodHandle method;
|
||||
try {
|
||||
method = getBeanOperation(linker, "dyn:getMethod:" + methodName, getterType, source);
|
||||
} catch(final IllegalAccessError e) {
|
||||
// Presumably, this was a caller sensitive method. Ignore it and carry on.
|
||||
continue;
|
||||
}
|
||||
properties.add(AccessorProperty.create(methodName, Property.NOT_WRITABLE, getBoundBeanMethodGetter(source,
|
||||
method), null));
|
||||
}
|
||||
for(final String propertyName: propertyNames) {
|
||||
MethodHandle getter;
|
||||
if(readablePropertyNames.contains(propertyName)) {
|
||||
try {
|
||||
getter = getBeanOperation(linker, "dyn:getProp:" + propertyName, getterType, source);
|
||||
} catch(final IllegalAccessError e) {
|
||||
// Presumably, this was a caller sensitive method. Ignore it and carry on.
|
||||
getter = Lookup.EMPTY_GETTER;
|
||||
}
|
||||
} else {
|
||||
getter = Lookup.EMPTY_GETTER;
|
||||
}
|
||||
final boolean isWritable = writablePropertyNames.contains(propertyName);
|
||||
properties.add(AccessorProperty.create(propertyName, isWritable ? 0 : Property.NOT_WRITABLE,
|
||||
readablePropertyNames.contains(propertyName) ? getBeanOperation(linker, "dyn:getProp:" + propertyName, getterType, source) : Lookup.EMPTY_GETTER,
|
||||
isWritable ? getBeanOperation(linker, "dyn:setProp:" + propertyName, setterType, source) : Lookup.EMPTY_SETTER));
|
||||
MethodHandle setter;
|
||||
if(isWritable) {
|
||||
try {
|
||||
setter = getBeanOperation(linker, "dyn:setProp:" + propertyName, setterType, source);
|
||||
} catch(final IllegalAccessError e) {
|
||||
// Presumably, this was a caller sensitive method. Ignore it and carry on.
|
||||
setter = Lookup.EMPTY_SETTER;
|
||||
}
|
||||
} else {
|
||||
setter = Lookup.EMPTY_SETTER;
|
||||
}
|
||||
if(getter != Lookup.EMPTY_GETTER || setter != Lookup.EMPTY_SETTER) {
|
||||
properties.add(AccessorProperty.create(propertyName, isWritable ? 0 : Property.NOT_WRITABLE, getter, setter));
|
||||
}
|
||||
}
|
||||
|
||||
targetObj.addBoundProperties(source, properties.toArray(new AccessorProperty[properties.size()]));
|
||||
|
@ -65,10 +65,9 @@ public final class NativeRegExp extends ScriptObject {
|
||||
private RegExp regexp;
|
||||
|
||||
// Reference to global object needed to support static RegExp properties
|
||||
private Global globalObject;
|
||||
private final Global globalObject;
|
||||
|
||||
// initialized by nasgen
|
||||
@SuppressWarnings("unused")
|
||||
private static PropertyMap $nasgenmap$;
|
||||
|
||||
static PropertyMap getInitialMap() {
|
||||
|
@ -1058,9 +1058,8 @@ public final class NativeString extends ScriptObject {
|
||||
public static Object trim(final Object self) {
|
||||
|
||||
final String str = checkObjectToString(self);
|
||||
final int len = str.length();
|
||||
int start = 0;
|
||||
int end = len - 1;
|
||||
int end = str.length() - 1;
|
||||
|
||||
while (start <= end && ScriptRuntime.isJSWhitespace(str.charAt(start))) {
|
||||
start++;
|
||||
@ -1069,7 +1068,45 @@ public final class NativeString extends ScriptObject {
|
||||
end--;
|
||||
}
|
||||
|
||||
return start == 0 && end + 1 == len ? str : str.substring(start, end + 1);
|
||||
return str.substring(start, end + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Nashorn extension: String.prototype.trimLeft ( )
|
||||
* @param self self reference
|
||||
* @return string trimmed left from whitespace
|
||||
*/
|
||||
@Function(attributes = Attribute.NOT_ENUMERABLE)
|
||||
public static Object trimLeft(final Object self) {
|
||||
|
||||
final String str = checkObjectToString(self);
|
||||
int start = 0;
|
||||
int end = str.length() - 1;
|
||||
|
||||
while (start <= end && ScriptRuntime.isJSWhitespace(str.charAt(start))) {
|
||||
start++;
|
||||
}
|
||||
|
||||
return str.substring(start, end + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Nashorn extension: String.prototype.trimRight ( )
|
||||
* @param self self reference
|
||||
* @return string trimmed right from whitespace
|
||||
*/
|
||||
@Function(attributes = Attribute.NOT_ENUMERABLE)
|
||||
public static Object trimRight(final Object self) {
|
||||
|
||||
final String str = checkObjectToString(self);
|
||||
int start = 0;
|
||||
int end = str.length() - 1;
|
||||
|
||||
while (end >= start && ScriptRuntime.isJSWhitespace(str.charAt(end))) {
|
||||
end--;
|
||||
}
|
||||
|
||||
return str.substring(start, end + 1);
|
||||
}
|
||||
|
||||
private static Object newObj(final Object self, final CharSequence str) {
|
||||
|
@ -107,6 +107,11 @@ public final class NativeUint16Array extends ArrayBufferView {
|
||||
super(buffer, byteOffset, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return "Uint16Array";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Factory factory() {
|
||||
return FACTORY;
|
||||
|
@ -126,6 +126,11 @@ public final class NativeUint32Array extends ArrayBufferView {
|
||||
super(buffer, byteOffset, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return "Uint32Array";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Factory factory() {
|
||||
return FACTORY;
|
||||
|
@ -100,6 +100,11 @@ public final class NativeUint8Array extends ArrayBufferView {
|
||||
super(buffer, byteOffset, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return "Uint8Array";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Factory factory() {
|
||||
return FACTORY;
|
||||
|
@ -117,6 +117,11 @@ public final class NativeUint8ClampedArray extends ArrayBufferView {
|
||||
super(buffer, byteOffset, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return "Uint8ClampedArray";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Factory factory() {
|
||||
return FACTORY;
|
||||
|
@ -284,7 +284,7 @@ public enum TokenType {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
return getNameOrType();
|
||||
}
|
||||
|
||||
static {
|
||||
|
@ -91,6 +91,11 @@ public final class Context {
|
||||
*/
|
||||
public static final String NASHORN_JAVA_REFLECTION = "nashorn.JavaReflection";
|
||||
|
||||
/* Force DebuggerSupport to be loaded. */
|
||||
static {
|
||||
DebuggerSupport.FORCELOAD = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* ContextCodeInstaller that has the privilege of installing classes in the Context.
|
||||
* Can only be instantiated from inside the context and is opaque to other classes
|
||||
@ -889,7 +894,6 @@ public final class Context {
|
||||
return script;
|
||||
}
|
||||
|
||||
@SuppressWarnings("static-method")
|
||||
private ScriptLoader createNewLoader() {
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedAction<ScriptLoader>() {
|
||||
|
330
nashorn/src/jdk/nashorn/internal/runtime/DebuggerSupport.java
Normal file
330
nashorn/src/jdk/nashorn/internal/runtime/DebuggerSupport.java
Normal file
@ -0,0 +1,330 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.nashorn.internal.runtime;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* This class provides support for external debuggers. Its primary purpose is
|
||||
* is to simplify the debugger tasks and provide better performance.
|
||||
*/
|
||||
final class DebuggerSupport {
|
||||
/**
|
||||
* Hook to force the loading of the DebuggerSupport class so that it is
|
||||
* available to external debuggers.
|
||||
*/
|
||||
static boolean FORCELOAD = true;
|
||||
|
||||
static {
|
||||
/**
|
||||
* Hook to force the loading of the DebuggerValueDesc class so that it is
|
||||
* available to external debuggers.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
DebuggerValueDesc forceLoad = new DebuggerValueDesc(null, false, null, null);
|
||||
}
|
||||
|
||||
/** This class is used to send a bulk description of a value. */
|
||||
static class DebuggerValueDesc {
|
||||
/** Property key (or index) or field name. */
|
||||
final String key;
|
||||
|
||||
/** If the value is expandable. */
|
||||
final boolean expandable;
|
||||
|
||||
/** Property or field value as object. */
|
||||
final Object valueAsObject;
|
||||
|
||||
/** Property or field value as string. */
|
||||
final String valueAsString;
|
||||
|
||||
DebuggerValueDesc(final String key, final boolean expandable, final Object valueAsObject, final String valueAsString) {
|
||||
this.key = key;
|
||||
this.expandable = expandable;
|
||||
this.valueAsObject = valueAsObject;
|
||||
this.valueAsString = valueAsString;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current context global.
|
||||
* @return context global.
|
||||
*/
|
||||
static Object getGlobal() {
|
||||
return Context.getGlobalTrusted();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call eval on the current global.
|
||||
* @param scope Scope to use.
|
||||
* @param self Receiver to use.
|
||||
* @param string String to evaluate.
|
||||
* @param returnException true if exceptions are to be returned.
|
||||
* @return Result of eval as string, or, an exception or null depending on returnException.
|
||||
*/
|
||||
static Object eval(final ScriptObject scope, final Object self, final String string, final boolean returnException) {
|
||||
final ScriptObject global = Context.getGlobalTrusted();
|
||||
final ScriptObject initialScope = scope != null ? scope : global;
|
||||
final Object callThis = self != null ? self : global;
|
||||
final Context context = global.getContext();
|
||||
|
||||
try {
|
||||
return context.eval(initialScope, string, callThis, ScriptRuntime.UNDEFINED, false);
|
||||
} catch (Throwable ex) {
|
||||
return returnException ? ex : null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a bulk description of an object's properties.
|
||||
* @param object Script object to be displayed by the debugger.
|
||||
* @param all true if to include non-enumerable values.
|
||||
* @return An array of DebuggerValueDesc.
|
||||
*/
|
||||
static DebuggerValueDesc[] valueInfos(final Object object, final boolean all) {
|
||||
assert object instanceof ScriptObject;
|
||||
return getDebuggerValueDescs((ScriptObject)object, all, new HashSet<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a debugger description of the value.
|
||||
* @param name Name of value (property name).
|
||||
* @param value Data value.
|
||||
* @param all true if to include non-enumerable values.
|
||||
* @return A DebuggerValueDesc.
|
||||
*/
|
||||
static DebuggerValueDesc valueInfo(final String name, final Object value, final boolean all) {
|
||||
return valueInfo(name, value, all, new HashSet<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a debugger description of the value.
|
||||
* @param name Name of value (property name).
|
||||
* @param value Data value.
|
||||
* @param all true if to include non-enumerable values.
|
||||
* @param duplicates Duplication set to avoid cycles.
|
||||
* @return A DebuggerValueDesc.
|
||||
*/
|
||||
private static DebuggerValueDesc valueInfo(final String name, final Object value, final boolean all, final Set<Object> duplicates) {
|
||||
if (value instanceof ScriptObject && !(value instanceof ScriptFunction)) {
|
||||
final ScriptObject object = (ScriptObject)value;
|
||||
return new DebuggerValueDesc(name, !object.isEmpty(), value, objectAsString(object, all, duplicates));
|
||||
}
|
||||
return new DebuggerValueDesc(name, false, value, valueAsString(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the descriptions for an object's properties.
|
||||
* @param object Object to introspect.
|
||||
* @param all true if to include non-enumerable values.
|
||||
* @param duplicates Duplication set to avoid cycles.
|
||||
* @return An array of DebuggerValueDesc.
|
||||
*/
|
||||
private static DebuggerValueDesc[] getDebuggerValueDescs(final ScriptObject object, final boolean all, final Set<Object> duplicates) {
|
||||
if (duplicates.contains(object)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
duplicates.add(object);
|
||||
|
||||
final String[] keys = object.getOwnKeys(all);
|
||||
final DebuggerValueDesc[] descs = new DebuggerValueDesc[keys.length];
|
||||
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
final String key = keys[i];
|
||||
descs[i] = valueInfo(key, object.get(key), all, duplicates);
|
||||
}
|
||||
|
||||
duplicates.remove(object);
|
||||
|
||||
return descs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a string representation of a Script object.
|
||||
* @param object Script object to represent.
|
||||
* @param all true if to include non-enumerable values.
|
||||
* @param duplicates Duplication set to avoid cycles.
|
||||
* @return String representation.
|
||||
*/
|
||||
private static String objectAsString(final ScriptObject object, final boolean all, final Set<Object> duplicates) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (ScriptObject.isArray(object)) {
|
||||
sb.append('[');
|
||||
final long length = object.getLong("length");
|
||||
|
||||
for (long i = 0; i < length; i++) {
|
||||
if (object.has(i)) {
|
||||
final Object valueAsObject = object.get(i);
|
||||
final boolean isUndefined = JSType.of(valueAsObject) == JSType.UNDEFINED;
|
||||
|
||||
if (isUndefined) {
|
||||
if (i != 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
} else {
|
||||
if (i != 0) {
|
||||
sb.append(", ");
|
||||
}
|
||||
|
||||
if (valueAsObject instanceof ScriptObject && !(valueAsObject instanceof ScriptFunction)) {
|
||||
final String objectString = objectAsString((ScriptObject)valueAsObject, all, duplicates);
|
||||
sb.append(objectString != null ? objectString : "{...}");
|
||||
} else {
|
||||
sb.append(valueAsString(valueAsObject));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (i != 0) {
|
||||
sb.append(',');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sb.append(']');
|
||||
} else {
|
||||
sb.append('{');
|
||||
final DebuggerValueDesc[] descs = getDebuggerValueDescs(object, all, duplicates);
|
||||
|
||||
if (descs != null) {
|
||||
for (int i = 0; i < descs.length; i++) {
|
||||
if (i != 0) {
|
||||
sb.append(", ");
|
||||
}
|
||||
|
||||
final String valueAsString = descs[i].valueAsString;
|
||||
sb.append(descs[i].key);
|
||||
sb.append(": ");
|
||||
sb.append(valueAsString);
|
||||
}
|
||||
}
|
||||
|
||||
sb.append('}');
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a string representation of a value.
|
||||
* @param value Arbitrary value to be displayed by the debugger.
|
||||
* @return A string representation of the value or an array of DebuggerValueDesc.
|
||||
*/
|
||||
private static String valueAsString(final Object value) {
|
||||
final JSType type = JSType.of(value);
|
||||
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
return value.toString();
|
||||
|
||||
case STRING:
|
||||
return escape((String)value);
|
||||
|
||||
case NUMBER:
|
||||
return JSType.toString(((Number)value).doubleValue());
|
||||
|
||||
case NULL:
|
||||
return "null";
|
||||
|
||||
case UNDEFINED:
|
||||
return "undefined";
|
||||
|
||||
case OBJECT:
|
||||
return ScriptRuntime.safeToString(value);
|
||||
|
||||
case FUNCTION:
|
||||
if (value instanceof ScriptFunction) {
|
||||
return ((ScriptFunction)value).toSource();
|
||||
}
|
||||
return value.toString();
|
||||
|
||||
default:
|
||||
return value.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape a string into a form that can be parsed by JavaScript.
|
||||
* @param value String to be escaped.
|
||||
* @return Escaped string.
|
||||
*/
|
||||
private static String escape(final String value) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("\"");
|
||||
|
||||
for (final char ch : value.toCharArray()) {
|
||||
switch (ch) {
|
||||
case '\\':
|
||||
sb.append("\\\\");
|
||||
break;
|
||||
case '"':
|
||||
sb.append("\\\"");
|
||||
break;
|
||||
case '\'':
|
||||
sb.append("\\\'");
|
||||
break;
|
||||
case '\b':
|
||||
sb.append("\\b");
|
||||
break;
|
||||
case '\f':
|
||||
sb.append("\\f");
|
||||
break;
|
||||
case '\n':
|
||||
sb.append("\\n");
|
||||
break;
|
||||
case '\r':
|
||||
sb.append("\\r");
|
||||
break;
|
||||
case '\t':
|
||||
sb.append("\\t");
|
||||
break;
|
||||
default:
|
||||
if (ch < ' ' || ch >= 0xFF) {
|
||||
sb.append("\\u");
|
||||
|
||||
final String hex = Integer.toHexString(ch);
|
||||
for (int i = hex.length(); i < 4; i++) {
|
||||
sb.append('0');
|
||||
}
|
||||
sb.append(hex);
|
||||
} else {
|
||||
sb.append(ch);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sb.append("\"");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,11 +30,10 @@ import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.Locale;
|
||||
import jdk.internal.dynalink.beans.BeansLinker;
|
||||
import jdk.internal.dynalink.beans.StaticClass;
|
||||
import jdk.nashorn.api.scripting.ScriptObjectMirror;
|
||||
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
|
||||
import jdk.nashorn.internal.parser.Lexer;
|
||||
import jdk.nashorn.internal.runtime.linker.Bootstrap;
|
||||
|
||||
/**
|
||||
* Representation for ECMAScript types - this maps directly to the ECMA script standard
|
||||
@ -148,22 +147,10 @@ public enum JSType {
|
||||
return JSType.STRING;
|
||||
}
|
||||
|
||||
if (obj instanceof ScriptObject) {
|
||||
return (obj instanceof ScriptFunction) ? JSType.FUNCTION : JSType.OBJECT;
|
||||
}
|
||||
|
||||
if (obj instanceof StaticClass) {
|
||||
if (Bootstrap.isCallable(obj)) {
|
||||
return JSType.FUNCTION;
|
||||
}
|
||||
|
||||
if (BeansLinker.isDynamicMethod(obj)) {
|
||||
return JSType.FUNCTION;
|
||||
}
|
||||
|
||||
if (obj instanceof ScriptObjectMirror) {
|
||||
return ((ScriptObjectMirror)obj).isFunction()? JSType.FUNCTION : JSType.OBJECT;
|
||||
}
|
||||
|
||||
return JSType.OBJECT;
|
||||
}
|
||||
|
||||
|
@ -54,4 +54,13 @@ public interface PropertyListener {
|
||||
*
|
||||
*/
|
||||
public void propertyModified(ScriptObject object, Property oldProp, Property newProp);
|
||||
|
||||
/**
|
||||
* Given object's __proto__ has changed.
|
||||
*
|
||||
* @param object object whose __proto__ has changed.
|
||||
* @param oldProto old __proto__
|
||||
* @param newProto new __proto__
|
||||
*/
|
||||
public void protoChanged(ScriptObject object, ScriptObject oldProto, ScriptObject newProto);
|
||||
}
|
||||
|
@ -140,6 +140,21 @@ public class PropertyListenerManager implements PropertyListener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method can be called to notify __proto__ modification to this object's listeners.
|
||||
*
|
||||
* @param object The ScriptObject whose __proto__ was changed.
|
||||
* @param oldProto old __proto__
|
||||
* @param newProto new __proto__
|
||||
*/
|
||||
protected synchronized final void notifyProtoChanged(final ScriptObject object, final ScriptObject oldProto, final ScriptObject newProto) {
|
||||
if (listeners != null) {
|
||||
for (PropertyListener listener : listeners.keySet()) {
|
||||
listener.protoChanged(object, oldProto, newProto);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PropertyListener methods
|
||||
|
||||
@Override
|
||||
@ -156,4 +171,9 @@ public class PropertyListenerManager implements PropertyListener {
|
||||
public final void propertyModified(final ScriptObject object, final Property oldProp, final Property newProp) {
|
||||
notifyPropertyModified(object, oldProp, newProp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void protoChanged(final ScriptObject object, final ScriptObject oldProto, final ScriptObject newProto) {
|
||||
notifyProtoChanged(object, oldProto, newProto);
|
||||
}
|
||||
}
|
||||
|
@ -230,7 +230,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that a prototype property hash changed.
|
||||
* Indicate that a prototype property has changed.
|
||||
*
|
||||
* @param property {@link Property} to invalidate.
|
||||
*/
|
||||
@ -250,6 +250,18 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that proto itself has changed in hierachy somewhere.
|
||||
*/
|
||||
private void invalidateAllProtoGetSwitchPoints() {
|
||||
assert !isShared() : "proto invalidation on a shared PropertyMap";
|
||||
|
||||
if (protoGetSwitches != null) {
|
||||
final Collection<SwitchPoint> sws = protoGetSwitches.values();
|
||||
SwitchPoint.invalidateAll(sws.toArray(new SwitchPoint[sws.size()]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a property to the map, re-binding its getters and setters,
|
||||
* if available, to a given receiver. This is typically the global scope. See
|
||||
@ -878,6 +890,15 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
|
||||
invalidateProtoGetSwitchPoint(oldProp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void protoChanged(final ScriptObject object, final ScriptObject oldProto, final ScriptObject newProto) {
|
||||
// We may walk and invalidate SwitchPoints for properties inherited
|
||||
// from 'object' or it's old proto chain. But, it may not be worth it.
|
||||
// For example, a new proto may have a user defined getter/setter for
|
||||
// a data property down the chain. So, invalidating all is better.
|
||||
invalidateAllProtoGetSwitchPoints();
|
||||
}
|
||||
|
||||
/*
|
||||
* Debugging and statistics.
|
||||
*/
|
||||
|
@ -86,6 +86,9 @@ public final class ScriptEnvironment {
|
||||
/** Launch using as fx application */
|
||||
public final boolean _fx;
|
||||
|
||||
/** Use single Global instance per jsr223 engine instance. */
|
||||
public final boolean _global_per_engine;
|
||||
|
||||
/**
|
||||
* Behavior when encountering a function declaration in a lexical context where only statements are acceptable
|
||||
* (function declarations are source elements, but not statements).
|
||||
@ -128,9 +131,6 @@ public final class ScriptEnvironment {
|
||||
/** Do not support typed arrays. */
|
||||
public final boolean _no_typed_arrays;
|
||||
|
||||
/** Package to which generated class files are added */
|
||||
public final String _package;
|
||||
|
||||
/** Only parse the source code, do not compile */
|
||||
public final boolean _parse_only;
|
||||
|
||||
@ -211,12 +211,12 @@ public final class ScriptEnvironment {
|
||||
_function_statement = FunctionStatementBehavior.ACCEPT;
|
||||
}
|
||||
_fx = options.getBoolean("fx");
|
||||
_global_per_engine = options.getBoolean("global.per.engine");
|
||||
_lazy_compilation = options.getBoolean("lazy.compilation");
|
||||
_loader_per_compile = options.getBoolean("loader.per.compile");
|
||||
_no_java = options.getBoolean("no.java");
|
||||
_no_syntax_extensions = options.getBoolean("no.syntax.extensions");
|
||||
_no_typed_arrays = options.getBoolean("no.typed.arrays");
|
||||
_package = options.getString("package");
|
||||
_parse_only = options.getBoolean("parse.only");
|
||||
_print_ast = options.getBoolean("print.ast");
|
||||
_print_lower_ast = options.getBoolean("print.lower.ast");
|
||||
|
@ -52,6 +52,7 @@ import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import jdk.internal.dynalink.CallSiteDescriptor;
|
||||
import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||
import jdk.internal.dynalink.linker.LinkRequest;
|
||||
@ -1008,10 +1009,6 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return getMap().findProperty(key);
|
||||
}
|
||||
|
||||
static String convertKey(final Object key) {
|
||||
return (key instanceof String) ? (String)key : JSType.toString(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden by {@link jdk.nashorn.internal.objects.NativeArguments} class (internal use.)
|
||||
* Used for argument access in a vararg function using parameter name.
|
||||
@ -1129,6 +1126,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
proto = newProto;
|
||||
|
||||
if (isPrototype()) {
|
||||
// tell listeners that my __proto__ has been changed
|
||||
notifyProtoChanged(this, oldProto, newProto);
|
||||
|
||||
if (oldProto != null) {
|
||||
oldProto.removePropertyListener(this);
|
||||
}
|
||||
@ -1144,7 +1144,19 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
* @param newProto Prototype to set.
|
||||
*/
|
||||
public final void setProtoCheck(final Object newProto) {
|
||||
if (!isExtensible()) {
|
||||
throw typeError("__proto__.set.non.extensible", ScriptRuntime.safeToString(this));
|
||||
}
|
||||
|
||||
if (newProto == null || newProto instanceof ScriptObject) {
|
||||
// check for circularity
|
||||
ScriptObject p = (ScriptObject)newProto;
|
||||
while (p != null) {
|
||||
if (p == this) {
|
||||
throw typeError("circular.__proto__.set", ScriptRuntime.safeToString(this));
|
||||
}
|
||||
p = p.getProto();
|
||||
}
|
||||
setProto((ScriptObject)newProto);
|
||||
} else {
|
||||
final ScriptObject global = Context.getGlobalTrusted();
|
||||
@ -2006,6 +2018,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
* @param request the link request
|
||||
* @return GuardedInvocation to be invoked at call site.
|
||||
*/
|
||||
@SuppressWarnings("null")
|
||||
public GuardedInvocation noSuchProperty(final CallSiteDescriptor desc, final LinkRequest request) {
|
||||
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
|
||||
final FindProperty find = findProperty(NO_SUCH_PROPERTY_NAME, true);
|
||||
@ -2359,7 +2372,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return array.getInt(index);
|
||||
}
|
||||
|
||||
return getInt(index, convertKey(key));
|
||||
return getInt(index, JSType.toString(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -2371,7 +2384,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return array.getInt(index);
|
||||
}
|
||||
|
||||
return getInt(index, convertKey(key));
|
||||
return getInt(index, JSType.toString(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -2383,7 +2396,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return array.getInt(index);
|
||||
}
|
||||
|
||||
return getInt(index, convertKey(key));
|
||||
return getInt(index, JSType.toString(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -2394,7 +2407,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return array.getInt(key);
|
||||
}
|
||||
|
||||
return getInt(key, convertKey(key));
|
||||
return getInt(key, JSType.toString(key));
|
||||
}
|
||||
|
||||
private long getLong(final int index, final String key) {
|
||||
@ -2436,7 +2449,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return array.getLong(index);
|
||||
}
|
||||
|
||||
return getLong(index, convertKey(key));
|
||||
return getLong(index, JSType.toString(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -2448,7 +2461,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return array.getLong(index);
|
||||
}
|
||||
|
||||
return getLong(index, convertKey(key));
|
||||
return getLong(index, JSType.toString(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -2460,7 +2473,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return array.getLong(index);
|
||||
}
|
||||
|
||||
return getLong(index, convertKey(key));
|
||||
return getLong(index, JSType.toString(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -2471,7 +2484,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return array.getLong(key);
|
||||
}
|
||||
|
||||
return getLong(key, convertKey(key));
|
||||
return getLong(key, JSType.toString(key));
|
||||
}
|
||||
|
||||
private double getDouble(final int index, final String key) {
|
||||
@ -2513,7 +2526,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return array.getDouble(index);
|
||||
}
|
||||
|
||||
return getDouble(index, convertKey(key));
|
||||
return getDouble(index, JSType.toString(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -2525,7 +2538,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return array.getDouble(index);
|
||||
}
|
||||
|
||||
return getDouble(index, convertKey(key));
|
||||
return getDouble(index, JSType.toString(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -2537,7 +2550,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return array.getDouble(index);
|
||||
}
|
||||
|
||||
return getDouble(index, convertKey(key));
|
||||
return getDouble(index, JSType.toString(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -2548,7 +2561,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return array.getDouble(key);
|
||||
}
|
||||
|
||||
return getDouble(key, convertKey(key));
|
||||
return getDouble(key, JSType.toString(key));
|
||||
}
|
||||
|
||||
private Object get(final int index, final String key) {
|
||||
@ -2590,7 +2603,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return array.getObject(index);
|
||||
}
|
||||
|
||||
return get(index, convertKey(key));
|
||||
return get(index, JSType.toString(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -2602,7 +2615,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return array.getObject(index);
|
||||
}
|
||||
|
||||
return get(index, convertKey(key));
|
||||
return get(index, JSType.toString(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -2614,7 +2627,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return array.getObject(index);
|
||||
}
|
||||
|
||||
return get(index, convertKey(key));
|
||||
return get(index, JSType.toString(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -2625,7 +2638,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return array.getObject(key);
|
||||
}
|
||||
|
||||
return get(key, convertKey(key));
|
||||
return get(key, JSType.toString(key));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2640,7 +2653,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
final long longIndex = index & JSType.MAX_UINT;
|
||||
|
||||
if (!getArray().has(index)) {
|
||||
final String key = convertKey(longIndex);
|
||||
final String key = JSType.toString(longIndex);
|
||||
final FindProperty find = findProperty(key, true);
|
||||
|
||||
if (find != null) {
|
||||
@ -2786,7 +2799,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return;
|
||||
}
|
||||
|
||||
final String propName = convertKey(key);
|
||||
final String propName = JSType.toString(key);
|
||||
final FindProperty find = findProperty(propName, true);
|
||||
|
||||
setObject(find, strict, propName, value);
|
||||
@ -3008,7 +3021,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
}
|
||||
}
|
||||
|
||||
final FindProperty find = findProperty(convertKey(key), true);
|
||||
final FindProperty find = findProperty(JSType.toString(key), true);
|
||||
|
||||
return find != null;
|
||||
}
|
||||
@ -3025,7 +3038,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
}
|
||||
}
|
||||
|
||||
final FindProperty find = findProperty(convertKey(key), true);
|
||||
final FindProperty find = findProperty(JSType.toString(key), true);
|
||||
|
||||
return find != null;
|
||||
}
|
||||
@ -3042,7 +3055,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
}
|
||||
}
|
||||
|
||||
final FindProperty find = findProperty(convertKey(key), true);
|
||||
final FindProperty find = findProperty(JSType.toString(key), true);
|
||||
|
||||
return find != null;
|
||||
}
|
||||
@ -3059,7 +3072,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
}
|
||||
}
|
||||
|
||||
final FindProperty find = findProperty(convertKey(key), true);
|
||||
final FindProperty find = findProperty(JSType.toString(key), true);
|
||||
|
||||
return find != null;
|
||||
}
|
||||
@ -3072,7 +3085,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return true;
|
||||
}
|
||||
|
||||
final FindProperty find = findProperty(convertKey(key), false);
|
||||
final FindProperty find = findProperty(JSType.toString(key), false);
|
||||
|
||||
return find != null;
|
||||
}
|
||||
@ -3085,7 +3098,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return true;
|
||||
}
|
||||
|
||||
final FindProperty find = findProperty(convertKey(key), false);
|
||||
final FindProperty find = findProperty(JSType.toString(key), false);
|
||||
|
||||
return find != null;
|
||||
}
|
||||
@ -3098,7 +3111,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return true;
|
||||
}
|
||||
|
||||
final FindProperty find = findProperty(convertKey(key), false);
|
||||
final FindProperty find = findProperty(JSType.toString(key), false);
|
||||
|
||||
return find != null;
|
||||
}
|
||||
@ -3111,7 +3124,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return true;
|
||||
}
|
||||
|
||||
final FindProperty find = findProperty(convertKey(key), false);
|
||||
final FindProperty find = findProperty(JSType.toString(key), false);
|
||||
|
||||
return find != null;
|
||||
}
|
||||
@ -3181,7 +3194,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
}
|
||||
|
||||
private boolean deleteObject(final Object key, final boolean strict) {
|
||||
final String propName = convertKey(key);
|
||||
final String propName = JSType.toString(key);
|
||||
final FindProperty find = findProperty(propName, false);
|
||||
|
||||
if (find == null) {
|
||||
|
@ -37,7 +37,9 @@ import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import jdk.internal.dynalink.beans.StaticClass;
|
||||
@ -188,6 +190,8 @@ public final class ScriptRuntime {
|
||||
case FUNCTION:
|
||||
if (self instanceof ScriptObject) {
|
||||
className = ((ScriptObject)self).getClassName();
|
||||
} else if (self instanceof ScriptObjectMirror) {
|
||||
className = ((ScriptObjectMirror)self).getClassName();
|
||||
} else {
|
||||
className = self.getClass().getName();
|
||||
}
|
||||
@ -221,49 +225,71 @@ public final class ScriptRuntime {
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to determine property iterator used in for in.
|
||||
* @param obj Object to iterate on.
|
||||
* @return Iterator.
|
||||
* Returns an iterator over property identifiers used in the {@code for...in} statement. Note that the ECMAScript
|
||||
* 5.1 specification, chapter 12.6.4. uses the terminology "property names", which seems to imply that the property
|
||||
* identifiers are expected to be strings, but this is not actually spelled out anywhere, and Nashorn will in some
|
||||
* cases deviate from this. Namely, we guarantee to always return an iterator over {@link String} values for any
|
||||
* built-in JavaScript object. We will however return an iterator over {@link Integer} objects for native Java
|
||||
* arrays and {@link List} objects, as well as arbitrary objects representing keys of a {@link Map}. Therefore, the
|
||||
* expression {@code typeof i} within a {@code for(i in obj)} statement can return something other than
|
||||
* {@code string} when iterating over native Java arrays, {@code List}, and {@code Map} objects.
|
||||
* @param obj object to iterate on.
|
||||
* @return iterator over the object's property names.
|
||||
*/
|
||||
public static Iterator<String> toPropertyIterator(final Object obj) {
|
||||
public static Iterator<?> toPropertyIterator(final Object obj) {
|
||||
if (obj instanceof ScriptObject) {
|
||||
return ((ScriptObject)obj).propertyIterator();
|
||||
}
|
||||
|
||||
if (obj != null && obj.getClass().isArray()) {
|
||||
final int length = Array.getLength(obj);
|
||||
|
||||
return new Iterator<String>() {
|
||||
private int index = 0;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return index < length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String next() {
|
||||
return "" + index++; //TODO numeric property iterator?
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
return new RangeIterator(Array.getLength(obj));
|
||||
}
|
||||
|
||||
if (obj instanceof ScriptObjectMirror) {
|
||||
return ((ScriptObjectMirror)obj).keySet().iterator();
|
||||
}
|
||||
|
||||
if (obj instanceof List) {
|
||||
return new RangeIterator(((List<?>)obj).size());
|
||||
}
|
||||
|
||||
if (obj instanceof Map) {
|
||||
return ((Map<?,?>)obj).keySet().iterator();
|
||||
}
|
||||
|
||||
return Collections.emptyIterator();
|
||||
}
|
||||
|
||||
private static final class RangeIterator implements Iterator<Integer> {
|
||||
private final int length;
|
||||
private int index;
|
||||
|
||||
RangeIterator(int length) {
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return index < length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer next() {
|
||||
return index++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to determine property value iterator used in for each in.
|
||||
* @param obj Object to iterate on.
|
||||
* @return Iterator.
|
||||
* Returns an iterator over property values used in the {@code for each...in} statement. Aside from built-in JS
|
||||
* objects, it also operates on Java arrays, any {@link Iterable}, as well as on {@link Map} objects, iterating over
|
||||
* map values.
|
||||
* @param obj object to iterate on.
|
||||
* @return iterator over the object's property values.
|
||||
*/
|
||||
public static Iterator<?> toValueIterator(final Object obj) {
|
||||
if (obj instanceof ScriptObject) {
|
||||
@ -301,6 +327,10 @@ public final class ScriptRuntime {
|
||||
return ((ScriptObjectMirror)obj).values().iterator();
|
||||
}
|
||||
|
||||
if (obj instanceof Map) {
|
||||
return ((Map<?,?>)obj).values().iterator();
|
||||
}
|
||||
|
||||
if (obj instanceof Iterable) {
|
||||
return ((Iterable<?>)obj).iterator();
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ public final class WithObject extends ScriptObject implements Scope {
|
||||
public boolean delete(final Object key, final boolean strict) {
|
||||
if (expression instanceof ScriptObject) {
|
||||
final ScriptObject self = (ScriptObject)expression;
|
||||
final String propName = ScriptObject.convertKey(key);
|
||||
final String propName = JSType.toString(key);
|
||||
|
||||
final FindProperty find = self.findProperty(propName, true);
|
||||
|
||||
|
@ -36,6 +36,7 @@ import jdk.internal.dynalink.CallSiteDescriptor;
|
||||
import jdk.internal.dynalink.DynamicLinker;
|
||||
import jdk.internal.dynalink.DynamicLinkerFactory;
|
||||
import jdk.internal.dynalink.beans.BeansLinker;
|
||||
import jdk.internal.dynalink.beans.StaticClass;
|
||||
import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||
import jdk.internal.dynalink.linker.LinkerServices;
|
||||
import jdk.nashorn.api.scripting.ScriptObjectMirror;
|
||||
@ -61,7 +62,7 @@ public final class Bootstrap {
|
||||
static {
|
||||
final DynamicLinkerFactory factory = new DynamicLinkerFactory();
|
||||
factory.setPrioritizedLinkers(new NashornLinker(), new NashornPrimitiveLinker(), new NashornStaticClassLinker(),
|
||||
new BoundDynamicMethodLinker(), new JSObjectLinker(), new ReflectionCheckLinker());
|
||||
new BoundDynamicMethodLinker(), new JavaSuperAdapterLinker(), new JSObjectLinker(), new ReflectionCheckLinker());
|
||||
factory.setFallbackLinkers(new BeansLinker(), new NashornBottomLinker());
|
||||
factory.setSyncOnRelink(true);
|
||||
final int relinkThreshold = Options.getIntProperty("nashorn.unstable.relink.threshold", -1);
|
||||
@ -88,7 +89,8 @@ public final class Bootstrap {
|
||||
return obj instanceof ScriptFunction ||
|
||||
((obj instanceof ScriptObjectMirror) && ((ScriptObjectMirror)obj).isFunction()) ||
|
||||
isDynamicMethod(obj) ||
|
||||
isFunctionalInterfaceObject(obj);
|
||||
isFunctionalInterfaceObject(obj) ||
|
||||
obj instanceof StaticClass;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -261,6 +263,16 @@ public final class Bootstrap {
|
||||
return new BoundDynamicMethod(dynamicMethod, boundThis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a super-adapter for an adapter, that is, an adapter to the adapter that allows invocation of superclass
|
||||
* methods on it.
|
||||
* @param adapter the original adapter
|
||||
* @return a new adapter that can be used to invoke super methods on the original adapter.
|
||||
*/
|
||||
public static Object createSuperAdapter(final Object adapter) {
|
||||
return new JavaSuperAdapter(adapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the given class is a reflection-specific class (anything in {@code java.lang.reflect} and
|
||||
* {@code java.lang.invoke} package, as well a {@link Class} and any subclass of {@link ClassLoader}) and there is
|
||||
|
@ -67,11 +67,12 @@ final class BoundDynamicMethodLinker implements TypeBasedGuardingDynamicLinker {
|
||||
// BeansLinker.
|
||||
final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor();
|
||||
final MethodType type = descriptor.getMethodType();
|
||||
final Class<?> dynamicMethodClass = dynamicMethod.getClass();
|
||||
final CallSiteDescriptor newDescriptor = descriptor.changeMethodType(
|
||||
type.changeParameterType(0, dynamicMethod.getClass()).changeParameterType(1, boundThis.getClass()));
|
||||
type.changeParameterType(0, dynamicMethodClass).changeParameterType(1, boundThis.getClass()));
|
||||
|
||||
// Delegate to BeansLinker
|
||||
final GuardedInvocation inv = BeansLinker.getLinkerForClass(dynamicMethod.getClass()).getGuardedInvocation(
|
||||
final GuardedInvocation inv = BeansLinker.getLinkerForClass(dynamicMethodClass).getGuardedInvocation(
|
||||
linkRequest.replaceArguments(newDescriptor, args), linkerServices);
|
||||
if(inv == null) {
|
||||
return null;
|
||||
|
@ -173,6 +173,9 @@ final class JavaAdapterBytecodeGenerator {
|
||||
private static final String CLASS_INIT = "<clinit>";
|
||||
private static final String STATIC_GLOBAL_FIELD_NAME = "staticGlobal";
|
||||
|
||||
// Method name prefix for invoking super-methods
|
||||
static final String SUPER_PREFIX = "super$";
|
||||
|
||||
/**
|
||||
* Collection of methods we never override: Object.clone(), Object.finalize().
|
||||
*/
|
||||
@ -240,6 +243,7 @@ final class JavaAdapterBytecodeGenerator {
|
||||
}
|
||||
generateConstructors();
|
||||
generateMethods();
|
||||
generateSuperMethods();
|
||||
// }
|
||||
cw.visitEnd();
|
||||
}
|
||||
@ -507,6 +511,10 @@ final class JavaAdapterBytecodeGenerator {
|
||||
|
||||
private static void endInitMethod(final InstructionAdapter mv) {
|
||||
mv.visitInsn(RETURN);
|
||||
endMethod(mv);
|
||||
}
|
||||
|
||||
private static void endMethod(final InstructionAdapter mv) {
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
@ -603,13 +611,8 @@ final class JavaAdapterBytecodeGenerator {
|
||||
*/
|
||||
private void generateMethod(final MethodInfo mi) {
|
||||
final Method method = mi.method;
|
||||
final int mod = method.getModifiers();
|
||||
final int access = ACC_PUBLIC | (method.isVarArgs() ? ACC_VARARGS : 0);
|
||||
final Class<?>[] exceptions = method.getExceptionTypes();
|
||||
final String[] exceptionNames = new String[exceptions.length];
|
||||
for (int i = 0; i < exceptions.length; ++i) {
|
||||
exceptionNames[i] = Type.getInternalName(exceptions[i]);
|
||||
}
|
||||
final String[] exceptionNames = getExceptionNames(exceptions);
|
||||
final MethodType type = mi.type;
|
||||
final String methodDesc = type.toMethodDescriptorString();
|
||||
final String name = mi.getName();
|
||||
@ -617,14 +620,8 @@ final class JavaAdapterBytecodeGenerator {
|
||||
final Type asmType = Type.getMethodType(methodDesc);
|
||||
final Type[] asmArgTypes = asmType.getArgumentTypes();
|
||||
|
||||
// Determine the first index for a local variable
|
||||
int nextLocalVar = 1; // this
|
||||
for(final Type t: asmArgTypes) {
|
||||
nextLocalVar += t.getSize();
|
||||
}
|
||||
|
||||
final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(access, name, methodDesc, null,
|
||||
exceptionNames));
|
||||
final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(getAccessModifiers(method), name,
|
||||
methodDesc, null, exceptionNames));
|
||||
mv.visitCode();
|
||||
|
||||
final Label instanceHandleDefined = new Label();
|
||||
@ -646,7 +643,7 @@ final class JavaAdapterBytecodeGenerator {
|
||||
}
|
||||
|
||||
// No handle is available, fall back to default behavior
|
||||
if(Modifier.isAbstract(mod)) {
|
||||
if(Modifier.isAbstract(method.getModifiers())) {
|
||||
// If the super method is abstract, throw an exception
|
||||
mv.anew(UNSUPPORTED_OPERATION_TYPE);
|
||||
mv.dup();
|
||||
@ -654,14 +651,7 @@ final class JavaAdapterBytecodeGenerator {
|
||||
mv.athrow();
|
||||
} else {
|
||||
// If the super method is not abstract, delegate to it.
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
int nextParam = 1;
|
||||
for(final Type t: asmArgTypes) {
|
||||
mv.load(nextParam, t);
|
||||
nextParam += t.getSize();
|
||||
}
|
||||
mv.invokespecial(superClassName, name, methodDesc);
|
||||
mv.areturn(asmReturnType);
|
||||
emitSuperCall(mv, name, methodDesc);
|
||||
}
|
||||
|
||||
final Label setupGlobal = new Label();
|
||||
@ -685,6 +675,12 @@ final class JavaAdapterBytecodeGenerator {
|
||||
// stack: [creatingGlobal, someHandle]
|
||||
mv.visitLabel(setupGlobal);
|
||||
|
||||
// Determine the first index for a local variable
|
||||
int nextLocalVar = 1; // "this" is at 0
|
||||
for(final Type t: asmArgTypes) {
|
||||
nextLocalVar += t.getSize();
|
||||
}
|
||||
// Set our local variable indices
|
||||
final int currentGlobalVar = nextLocalVar++;
|
||||
final int globalsDifferVar = nextLocalVar++;
|
||||
|
||||
@ -775,8 +771,7 @@ final class JavaAdapterBytecodeGenerator {
|
||||
}
|
||||
mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, throwableHandler, THROWABLE_TYPE_NAME);
|
||||
}
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
endMethod(mv);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -817,6 +812,53 @@ final class JavaAdapterBytecodeGenerator {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void generateSuperMethods() {
|
||||
for(final MethodInfo mi: methodInfos) {
|
||||
if(!Modifier.isAbstract(mi.method.getModifiers())) {
|
||||
generateSuperMethod(mi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void generateSuperMethod(MethodInfo mi) {
|
||||
final Method method = mi.method;
|
||||
|
||||
final String methodDesc = mi.type.toMethodDescriptorString();
|
||||
final String name = mi.getName();
|
||||
|
||||
final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(getAccessModifiers(method),
|
||||
SUPER_PREFIX + name, methodDesc, null, getExceptionNames(method.getExceptionTypes())));
|
||||
mv.visitCode();
|
||||
|
||||
emitSuperCall(mv, name, methodDesc);
|
||||
|
||||
endMethod(mv);
|
||||
}
|
||||
|
||||
private void emitSuperCall(final InstructionAdapter mv, final String name, final String methodDesc) {
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
int nextParam = 1;
|
||||
final Type methodType = Type.getMethodType(methodDesc);
|
||||
for(final Type t: methodType.getArgumentTypes()) {
|
||||
mv.load(nextParam, t);
|
||||
nextParam += t.getSize();
|
||||
}
|
||||
mv.invokespecial(superClassName, name, methodDesc);
|
||||
mv.areturn(methodType.getReturnType());
|
||||
}
|
||||
|
||||
private static String[] getExceptionNames(final Class<?>[] exceptions) {
|
||||
final String[] exceptionNames = new String[exceptions.length];
|
||||
for (int i = 0; i < exceptions.length; ++i) {
|
||||
exceptionNames[i] = Type.getInternalName(exceptions[i]);
|
||||
}
|
||||
return exceptionNames;
|
||||
}
|
||||
|
||||
private static int getAccessModifiers(final Method method) {
|
||||
return ACC_PUBLIC | (method.isVarArgs() ? ACC_VARARGS : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gathers methods that can be implemented or overridden from the specified type into this factory's
|
||||
* {@link #methodInfos} set. It will add all non-final, non-static methods that are either public or protected from
|
||||
|
@ -34,7 +34,6 @@ import java.security.Permissions;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.security.SecureClassLoader;
|
||||
|
||||
import jdk.internal.dynalink.beans.StaticClass;
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.nashorn.internal.runtime.linker;
|
||||
|
||||
/**
|
||||
* Represents a an adapter for invoking superclass methods on an adapter instance generated by
|
||||
* {@link JavaAdapterBytecodeGenerator}. Note that objects of this class are just wrappers around the adapter instances,
|
||||
* without any behavior. All the behavior is defined in the {@code JavaSuperAdapterLinker}.
|
||||
*/
|
||||
class JavaSuperAdapter {
|
||||
private final Object adapter;
|
||||
|
||||
JavaSuperAdapter(final Object adapter) {
|
||||
adapter.getClass(); // NPE check
|
||||
this.adapter = adapter;
|
||||
}
|
||||
|
||||
public Object getAdapter() {
|
||||
return adapter;
|
||||
}
|
||||
}
|
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.nashorn.internal.runtime.linker;
|
||||
|
||||
import static jdk.nashorn.internal.lookup.Lookup.EMPTY_GETTER;
|
||||
import static jdk.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.SUPER_PREFIX;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import jdk.internal.dynalink.CallSiteDescriptor;
|
||||
import jdk.internal.dynalink.beans.BeansLinker;
|
||||
import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||
import jdk.internal.dynalink.linker.LinkRequest;
|
||||
import jdk.internal.dynalink.linker.LinkerServices;
|
||||
import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
|
||||
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
|
||||
import jdk.internal.dynalink.support.Lookup;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
|
||||
/**
|
||||
* A linker for instances of {@link JavaSuperAdapter}. Only links {@code getMethod} calls, by forwarding them to the
|
||||
* bean linker for the adapter class and prepending {@code super$} to method names.
|
||||
*
|
||||
*/
|
||||
final class JavaSuperAdapterLinker implements TypeBasedGuardingDynamicLinker {
|
||||
private static final String GET_METHOD = "getMethod";
|
||||
private static final String DYN_GET_METHOD = "dyn:" + GET_METHOD;
|
||||
private static final String DYN_GET_METHOD_FIXED = DYN_GET_METHOD + ":" + SUPER_PREFIX;
|
||||
|
||||
private static final MethodHandle ADD_PREFIX_TO_METHOD_NAME;
|
||||
private static final MethodHandle BIND_DYNAMIC_METHOD;
|
||||
private static final MethodHandle GET_ADAPTER;
|
||||
private static final MethodHandle IS_ADAPTER_OF_CLASS;
|
||||
|
||||
static {
|
||||
final Lookup lookup = new Lookup(MethodHandles.lookup());
|
||||
ADD_PREFIX_TO_METHOD_NAME = lookup.findOwnStatic("addPrefixToMethodName", Object.class, Object.class);
|
||||
BIND_DYNAMIC_METHOD = lookup.findOwnStatic("bindDynamicMethod", Object.class, Object.class, Object.class);
|
||||
GET_ADAPTER = lookup.findVirtual(JavaSuperAdapter.class, "getAdapter", MethodType.methodType(Object.class));
|
||||
IS_ADAPTER_OF_CLASS = lookup.findOwnStatic("isAdapterOfClass", boolean.class, Class.class, Object.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canLinkType(final Class<?> type) {
|
||||
return type == JavaSuperAdapter.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices)
|
||||
throws Exception {
|
||||
final Object objSuperAdapter = linkRequest.getReceiver();
|
||||
if(!(objSuperAdapter instanceof JavaSuperAdapter)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor();
|
||||
if(!CallSiteDescriptorFactory.tokenizeOperators(descriptor).contains(GET_METHOD)) {
|
||||
// We only handle getMethod
|
||||
return null;
|
||||
}
|
||||
|
||||
final Object adapter = ((JavaSuperAdapter)objSuperAdapter).getAdapter();
|
||||
|
||||
// Replace argument (javaSuperAdapter, ...) => (adapter, ...) when delegating to BeansLinker
|
||||
final Object[] args = linkRequest.getArguments();
|
||||
args[0] = adapter;
|
||||
|
||||
// Use R(T0, ...) => R(adapter.class, ...) call site type when delegating to BeansLinker.
|
||||
final MethodType type = descriptor.getMethodType();
|
||||
final Class<?> adapterClass = adapter.getClass();
|
||||
final boolean hasFixedName = descriptor.getNameTokenCount() > 2;
|
||||
final String opName = hasFixedName ? (DYN_GET_METHOD_FIXED + descriptor.getNameToken(
|
||||
CallSiteDescriptor.NAME_OPERAND)) : DYN_GET_METHOD;
|
||||
|
||||
final CallSiteDescriptor newDescriptor = NashornCallSiteDescriptor.get(descriptor.getLookup(), opName,
|
||||
type.changeParameterType(0, adapterClass), 0);
|
||||
|
||||
// Delegate to BeansLinker
|
||||
final GuardedInvocation guardedInv = BeansLinker.getLinkerForClass(adapterClass).getGuardedInvocation(
|
||||
linkRequest.replaceArguments(newDescriptor, args), linkerServices);
|
||||
|
||||
final MethodHandle guard = IS_ADAPTER_OF_CLASS.bindTo(adapterClass);
|
||||
if(guardedInv == null) {
|
||||
// Short circuit the lookup here for non-existent methods by linking an empty getter. If we just returned
|
||||
// null instead, BeansLinker would find final methods on the JavaSuperAdapter instead: getClass() and
|
||||
// wait().
|
||||
return new GuardedInvocation(MethodHandles.dropArguments(EMPTY_GETTER, 1,type.parameterList().subList(1,
|
||||
type.parameterCount())), guard).asType(descriptor);
|
||||
}
|
||||
|
||||
final MethodHandle invocation = guardedInv.getInvocation();
|
||||
final MethodType invType = invocation.type();
|
||||
// For invocation typed R(T0, ...) create a dynamic method binder of type R(R, T0)
|
||||
final MethodHandle typedBinder = BIND_DYNAMIC_METHOD.asType(MethodType.methodType(invType.returnType(),
|
||||
invType.returnType(), invType.parameterType(0)));
|
||||
// For invocation typed R(T0, T1, ...) create a dynamic method binder of type R(R, T0, T1, ...)
|
||||
final MethodHandle droppingBinder = MethodHandles.dropArguments(typedBinder, 2,
|
||||
invType.parameterList().subList(1, invType.parameterCount()));
|
||||
// Finally, fold the invocation into the binder to produce a method handle that will bind every returned
|
||||
// DynamicMethod object from dyn:getMethod calls to the actual receiver
|
||||
// R(R(T0, T1, ...), T0, T1, ...)
|
||||
final MethodHandle bindingInvocation = MethodHandles.foldArguments(droppingBinder, invocation);
|
||||
|
||||
final MethodHandle typedGetAdapter = asFilterType(GET_ADAPTER, 0, invType, type);
|
||||
final MethodHandle adaptedInvocation;
|
||||
if(hasFixedName) {
|
||||
adaptedInvocation = MethodHandles.filterArguments(bindingInvocation, 0, typedGetAdapter);
|
||||
} else {
|
||||
// Add a filter that'll prepend "super$" to each name passed to the variable-name "dyn:getMethod".
|
||||
final MethodHandle typedAddPrefix = asFilterType(ADD_PREFIX_TO_METHOD_NAME, 1, invType, type);
|
||||
adaptedInvocation = MethodHandles.filterArguments(bindingInvocation, 0, typedGetAdapter, typedAddPrefix);
|
||||
}
|
||||
|
||||
return guardedInv.replaceMethods(adaptedInvocation, guard).asType(descriptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts the type of a method handle used as a filter in a position from a source method type to a target method type.
|
||||
* @param filter the filter method handle
|
||||
* @param pos the position in the argument list that it's filtering
|
||||
* @param targetType the target method type for filtering
|
||||
* @param sourceType the source method type for filtering
|
||||
* @return a type adapted filter
|
||||
*/
|
||||
private static MethodHandle asFilterType(final MethodHandle filter, int pos, MethodType targetType, MethodType sourceType) {
|
||||
return filter.asType(MethodType.methodType(targetType.parameterType(pos), sourceType.parameterType(pos)));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static Object addPrefixToMethodName(final Object name) {
|
||||
return SUPER_PREFIX.concat(String.valueOf(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to transform the return value of getMethod; transform a {@code DynamicMethod} into a
|
||||
* {@code BoundDynamicMethod} while also accounting for the possibility of a non-existent method.
|
||||
* @param dynamicMethod the dynamic method to bind
|
||||
* @param boundThis the adapter underlying a super adapter, to which the dynamic method is bound.
|
||||
* @return a dynamic method bound to the adapter instance.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private static Object bindDynamicMethod(final Object dynamicMethod, final Object boundThis) {
|
||||
return dynamicMethod == null ? ScriptRuntime.UNDEFINED : Bootstrap.bindDynamicMethod(dynamicMethod, boundThis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used as the guard of linkages, as the receiver is not guaranteed to be a JavaSuperAdapter.
|
||||
* @param clazz the class the receiver's adapter is tested against.
|
||||
* @param obj receiver
|
||||
* @return true if the receiver is a super adapter, and its underlying adapter is of the specified class
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private static boolean isAdapterOfClass(Class<?> clazz, Object obj) {
|
||||
return obj instanceof JavaSuperAdapter && clazz == (((JavaSuperAdapter)obj).getAdapter()).getClass();
|
||||
}
|
||||
}
|
@ -60,7 +60,7 @@ public abstract class RegExp {
|
||||
* @param flags the flags string
|
||||
*/
|
||||
protected RegExp(final String source, final String flags) {
|
||||
this.source = source;
|
||||
this.source = source.length() == 0 ? "(?:)" : source;
|
||||
for (int i = 0; i < flags.length(); i++) {
|
||||
final char ch = flags.charAt(i);
|
||||
switch (ch) {
|
||||
|
@ -39,7 +39,6 @@ import jdk.nashorn.internal.runtime.regexp.joni.constants.NodeType;
|
||||
import jdk.nashorn.internal.runtime.regexp.joni.constants.OPCode;
|
||||
import jdk.nashorn.internal.runtime.regexp.joni.constants.OPSize;
|
||||
import jdk.nashorn.internal.runtime.regexp.joni.constants.TargetInfo;
|
||||
import jdk.nashorn.internal.runtime.regexp.joni.encoding.CharacterType;
|
||||
|
||||
final class ArrayCompiler extends Compiler {
|
||||
private int[] code;
|
||||
@ -345,6 +344,7 @@ final class ArrayCompiler extends Compiler {
|
||||
|
||||
private static final int QUANTIFIER_EXPAND_LIMIT_SIZE = 50; // was 50
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static boolean cknOn(int ckn) {
|
||||
return ckn > 0;
|
||||
}
|
||||
@ -879,6 +879,7 @@ final class ArrayCompiler extends Compiler {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void addStateCheckNum(int num) {
|
||||
addInt(num);
|
||||
}
|
||||
@ -887,6 +888,7 @@ final class ArrayCompiler extends Compiler {
|
||||
addInt(addr);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void addAbsAddr(int addr) {
|
||||
addInt(addr);
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ public final class BitSet {
|
||||
final int[] bits = new int[BITSET_SIZE];
|
||||
|
||||
private static final int BITS_TO_STRING_WRAP = 4;
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.append("BitSet");
|
||||
|
@ -26,7 +26,6 @@ import static jdk.nashorn.internal.runtime.regexp.joni.Option.isFindNotEmpty;
|
||||
import static jdk.nashorn.internal.runtime.regexp.joni.Option.isNotBol;
|
||||
import static jdk.nashorn.internal.runtime.regexp.joni.Option.isNotEol;
|
||||
import static jdk.nashorn.internal.runtime.regexp.joni.Option.isPosixRegion;
|
||||
import static jdk.nashorn.internal.runtime.regexp.joni.EncodingHelper.isCrnl;
|
||||
import static jdk.nashorn.internal.runtime.regexp.joni.EncodingHelper.isNewLine;
|
||||
|
||||
import jdk.nashorn.internal.runtime.regexp.joni.ast.CClassNode;
|
||||
@ -96,6 +95,7 @@ class ByteCodeMachine extends StackMachine {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final int matchAt(int range, int sstart, int sprev) {
|
||||
this.range = range;
|
||||
this.sstart = sstart;
|
||||
@ -499,7 +499,7 @@ class ByteCodeMachine extends StackMachine {
|
||||
|
||||
private void opAnyChar() {
|
||||
if (s >= range) {opFail(); return;}
|
||||
if (chars[s] == EncodingHelper.NEW_LINE) {opFail(); return;}
|
||||
if (isNewLine(chars[s])) {opFail(); return;}
|
||||
s++;
|
||||
sprev = sbegin; // break;
|
||||
}
|
||||
@ -537,7 +537,7 @@ class ByteCodeMachine extends StackMachine {
|
||||
while (s < range) {
|
||||
char b = chars[s];
|
||||
if (c == b) pushAlt(ip + 1, s, sprev);
|
||||
if (b == EncodingHelper.NEW_LINE) {opFail(); return;}
|
||||
if (isNewLine(b)) {opFail(); return;}
|
||||
sprev = s;
|
||||
s++;
|
||||
}
|
||||
@ -616,7 +616,7 @@ class ByteCodeMachine extends StackMachine {
|
||||
if (s == str) {
|
||||
if (isNotBol(msaOptions)) opFail();
|
||||
return;
|
||||
} else if (EncodingHelper.isNewLine(chars, sprev, end) && s != end) {
|
||||
} else if (isNewLine(chars, sprev, end) && s != end) {
|
||||
return;
|
||||
}
|
||||
opFail();
|
||||
@ -625,7 +625,7 @@ class ByteCodeMachine extends StackMachine {
|
||||
private void opEndLine() {
|
||||
if (s == end) {
|
||||
if (Config.USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE) {
|
||||
if (str == end || !EncodingHelper.isNewLine(chars, sprev, end)) {
|
||||
if (str == end || !isNewLine(chars, sprev, end)) {
|
||||
if (isNotEol(msaOptions)) opFail();
|
||||
}
|
||||
return;
|
||||
@ -633,7 +633,7 @@ class ByteCodeMachine extends StackMachine {
|
||||
if (isNotEol(msaOptions)) opFail();
|
||||
return;
|
||||
}
|
||||
} else if (isNewLine(chars, s, end) || (Config.USE_CRNL_AS_LINE_TERMINATOR && isCrnl(chars, s, end))) {
|
||||
} else if (isNewLine(chars, s, end)) {
|
||||
return;
|
||||
}
|
||||
opFail();
|
||||
@ -652,9 +652,6 @@ class ByteCodeMachine extends StackMachine {
|
||||
}
|
||||
} else if (isNewLine(chars, s, end) && s + 1 == end) {
|
||||
return;
|
||||
} else if (Config.USE_CRNL_AS_LINE_TERMINATOR && isCrnl(chars, s, end)) {
|
||||
int ss = s + 2;
|
||||
if (ss == end) return;
|
||||
}
|
||||
opFail();
|
||||
}
|
||||
@ -731,8 +728,6 @@ class ByteCodeMachine extends StackMachine {
|
||||
// STRING_CMP
|
||||
while(n-- > 0) if (chars[pstart++] != chars[s++]) {opFail(); return;}
|
||||
|
||||
int len;
|
||||
|
||||
// beyond string check
|
||||
if (sprev < range) {
|
||||
while (sprev + 1 < s) sprev++;
|
||||
@ -768,7 +763,6 @@ class ByteCodeMachine extends StackMachine {
|
||||
if (!stringCmpIC(regex.caseFoldFlag, pstart, this, n, end)) {opFail(); return;}
|
||||
s = value;
|
||||
|
||||
int len;
|
||||
// if (sprev < chars.length)
|
||||
while (sprev + 1 < s) sprev++;
|
||||
}
|
||||
@ -796,8 +790,6 @@ class ByteCodeMachine extends StackMachine {
|
||||
|
||||
s = swork;
|
||||
|
||||
int len;
|
||||
|
||||
// beyond string check
|
||||
if (sprev < range) {
|
||||
while (sprev + 1 < s) sprev++;
|
||||
@ -829,7 +821,6 @@ class ByteCodeMachine extends StackMachine {
|
||||
if (!stringCmpIC(regex.caseFoldFlag, pstart, this, n, end)) continue loop; // STRING_CMP_VALUE_IC
|
||||
s = value;
|
||||
|
||||
int len;
|
||||
// if (sprev < chars.length)
|
||||
while (sprev + 1 < s) sprev++;
|
||||
|
||||
@ -902,7 +893,6 @@ class ByteCodeMachine extends StackMachine {
|
||||
|
||||
sprev = s;
|
||||
if (backrefMatchAtNestedLevel(ic != 0, regex.caseFoldFlag, level, tlen, ip)) { // (s) and (end) implicit
|
||||
int len;
|
||||
while (sprev + 1 < s) sprev++;
|
||||
ip += tlen; // * SIZE_MEMNUM
|
||||
} else {
|
||||
|
@ -58,6 +58,7 @@ public final class CodeRangeBuffer implements Cloneable {
|
||||
used = orig.used;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append("CodeRange");
|
||||
|
@ -29,7 +29,6 @@ public interface Config {
|
||||
final int INTERNAL_ENC_CASE_FOLD_MULTI_CHAR = (1<<30);
|
||||
final int ENC_CASE_FOLD_MIN = INTERNAL_ENC_CASE_FOLD_MULTI_CHAR;
|
||||
final int ENC_CASE_FOLD_DEFAULT = ENC_CASE_FOLD_MIN;
|
||||
final boolean USE_CRNL_AS_LINE_TERMINATOR = false;
|
||||
|
||||
final boolean USE_MONOMANIAC_CHECK_CAPTURES_IN_ENDLESS_REPEAT = true; /* /(?:()|())*\2/ */
|
||||
final boolean USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE = true; /* /\n$/ =~ "\n" */
|
||||
|
@ -24,10 +24,12 @@ import jdk.nashorn.internal.runtime.regexp.joni.encoding.IntHolder;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class EncodingHelper {
|
||||
public final class EncodingHelper {
|
||||
|
||||
public final static char NEW_LINE = 0xa;
|
||||
public final static char RETURN = 0xd;
|
||||
final static int NEW_LINE = 0x000a;
|
||||
final static int RETURN = 0x000d;
|
||||
final static int LINE_SEPARATOR = 0x2028;
|
||||
final static int PARAGRAPH_SEPARATOR = 0x2029;
|
||||
|
||||
final static char[] EMPTYCHARS = new char[0];
|
||||
final static int[][] codeRanges = new int[15][];
|
||||
@ -64,15 +66,11 @@ public class EncodingHelper {
|
||||
}
|
||||
|
||||
public static boolean isNewLine(int code) {
|
||||
return code == NEW_LINE;
|
||||
return code == NEW_LINE || code == RETURN || code == LINE_SEPARATOR || code == PARAGRAPH_SEPARATOR;
|
||||
}
|
||||
|
||||
public static boolean isNewLine(char[] chars, int p, int end) {
|
||||
return p < end && chars[p] == NEW_LINE;
|
||||
}
|
||||
|
||||
public static boolean isCrnl(char[] chars, int p, int end) {
|
||||
return p + 1 < end && chars[p] == RETURN && chars[p + 1] == NEW_LINE;
|
||||
return p < end && isNewLine(chars[p]);
|
||||
}
|
||||
|
||||
// Encoding.prevCharHead
|
||||
@ -194,7 +192,7 @@ public class EncodingHelper {
|
||||
int type;
|
||||
switch (ctype) {
|
||||
case CharacterType.NEWLINE:
|
||||
return code == EncodingHelper.NEW_LINE;
|
||||
return isNewLine(code);
|
||||
case CharacterType.ALPHA:
|
||||
return (1 << Character.getType(code) & CharacterType.ALPHA_MASK) != 0;
|
||||
case CharacterType.BLANK:
|
||||
|
@ -139,6 +139,7 @@ class Lexer extends ScannerSupport {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("fallthrough")
|
||||
/* \M-, \C-, \c, or \... */
|
||||
private int fetchEscapedValue() {
|
||||
if (!left()) {
|
||||
@ -731,7 +732,7 @@ class Lexer extends ScannerSupport {
|
||||
if (syntax.opLineAnchor()) fetchTokenFor_anchor(isSingleline(env.option) ? AnchorType.BEGIN_BUF : AnchorType.BEGIN_LINE);
|
||||
break;
|
||||
case '$':
|
||||
if (syntax.opLineAnchor()) fetchTokenFor_anchor(isSingleline(env.option) ? AnchorType.SEMI_END_BUF : AnchorType.END_LINE);
|
||||
if (syntax.opLineAnchor()) fetchTokenFor_anchor(isSingleline(env.option) ? AnchorType.END_BUF : AnchorType.END_LINE);
|
||||
break;
|
||||
case '[':
|
||||
if (syntax.opBracketCC()) token.type = TokenType.CC_CC_OPEN;
|
||||
|
@ -141,7 +141,7 @@ public abstract class Matcher extends IntHolder {
|
||||
continue retry;
|
||||
}
|
||||
}
|
||||
} else if (!EncodingHelper.isNewLine(chars, p, end) && (!Config.USE_CRNL_AS_LINE_TERMINATOR || !EncodingHelper.isCrnl(chars, p, end))) {
|
||||
} else if (!EncodingHelper.isNewLine(chars, p, end)) {
|
||||
//if () break;
|
||||
// goto retry_gate;
|
||||
pprev = p;
|
||||
@ -226,7 +226,7 @@ public abstract class Matcher extends IntHolder {
|
||||
continue retry;
|
||||
}
|
||||
}
|
||||
} else if (!EncodingHelper.isNewLine(chars, p, end) && (!Config.USE_CRNL_AS_LINE_TERMINATOR || !EncodingHelper.isCrnl(chars, p, end))) {
|
||||
} else if (!EncodingHelper.isNewLine(chars, p, end)) {
|
||||
p = EncodingHelper.prevCharHead(adjrange, p);
|
||||
if (p == -1) return false;
|
||||
continue retry;
|
||||
@ -330,12 +330,6 @@ public abstract class Matcher extends IntHolder {
|
||||
maxSemiEnd = end;
|
||||
if (EncodingHelper.isNewLine(chars, preEnd, end)) {
|
||||
minSemiEnd = preEnd;
|
||||
if (Config.USE_CRNL_AS_LINE_TERMINATOR) {
|
||||
preEnd = EncodingHelper.stepBack(str, preEnd, 1);
|
||||
if (preEnd != -1 && EncodingHelper.isCrnl(chars, preEnd, end)) {
|
||||
minSemiEnd = preEnd;
|
||||
}
|
||||
}
|
||||
if (minSemiEnd > str && start <= minSemiEnd) {
|
||||
// !goto end_buf;!
|
||||
if (endBuf(start, range, minSemiEnd, maxSemiEnd)) return -1; // mismatch_no_msa;
|
||||
|
@ -297,8 +297,6 @@ class Parser extends Lexer {
|
||||
throw new SyntaxException(ERR_END_PATTERN_IN_GROUP);
|
||||
}
|
||||
|
||||
boolean listCapture = false;
|
||||
|
||||
fetch();
|
||||
switch(c) {
|
||||
case ':': /* (?:...) grouping only */
|
||||
|
@ -32,6 +32,7 @@ public final class Region {
|
||||
this.end = new int[num];
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Region: \n");
|
||||
|
@ -21,9 +21,6 @@ package jdk.nashorn.internal.runtime.regexp.joni;
|
||||
|
||||
import jdk.nashorn.internal.runtime.regexp.joni.encoding.IntHolder;
|
||||
import jdk.nashorn.internal.runtime.regexp.joni.exception.ErrorMessages;
|
||||
import jdk.nashorn.internal.runtime.regexp.joni.exception.InternalException;
|
||||
import jdk.nashorn.internal.runtime.regexp.joni.exception.SyntaxException;
|
||||
import jdk.nashorn.internal.runtime.regexp.joni.exception.ValueException;
|
||||
|
||||
abstract class ScannerSupport extends IntHolder implements ErrorMessages {
|
||||
|
||||
|
@ -28,14 +28,17 @@ public abstract class SearchAlgorithm {
|
||||
|
||||
public static final SearchAlgorithm NONE = new SearchAlgorithm() {
|
||||
|
||||
@Override
|
||||
public final String getName() {
|
||||
return "NONE";
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int search(Regex regex, char[] text, int textP, int textEnd, int textRange) {
|
||||
return textP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int searchBackward(Regex regex, char[] text, int textP, int adjustText, int textEnd, int textStart, int s_, int range_) {
|
||||
return textP;
|
||||
}
|
||||
@ -44,10 +47,12 @@ public abstract class SearchAlgorithm {
|
||||
|
||||
public static final SearchAlgorithm SLOW = new SearchAlgorithm() {
|
||||
|
||||
@Override
|
||||
public final String getName() {
|
||||
return "EXACT";
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int search(Regex regex, char[] text, int textP, int textEnd, int textRange) {
|
||||
char[] target = regex.exact;
|
||||
int targetP = regex.exactP;
|
||||
@ -78,6 +83,7 @@ public abstract class SearchAlgorithm {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int searchBackward(Regex regex, char[] text, int textP, int adjustText, int textEnd, int textStart, int s_, int range_) {
|
||||
char[] target = regex.exact;
|
||||
int targetP = regex.exactP;
|
||||
@ -114,10 +120,12 @@ public abstract class SearchAlgorithm {
|
||||
this.caseFoldFlag = regex.caseFoldFlag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getName() {
|
||||
return "EXACT_IC";
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int search(Regex regex, char[] text, int textP, int textEnd, int textRange) {
|
||||
char[] target = regex.exact;
|
||||
int targetP = regex.exactP;
|
||||
@ -136,6 +144,7 @@ public abstract class SearchAlgorithm {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int searchBackward(Regex regex, char[] text, int textP, int adjustText, int textEnd, int textStart, int s_, int range_) {
|
||||
char[] target = regex.exact;
|
||||
int targetP = regex.exactP;
|
||||
@ -163,14 +172,16 @@ public abstract class SearchAlgorithm {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static final SearchAlgorithm BM = new SearchAlgorithm() {
|
||||
|
||||
@Override
|
||||
public final String getName() {
|
||||
return "EXACT_BM";
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int search(Regex regex, char[] text, int textP, int textEnd, int textRange) {
|
||||
char[] target = regex.exact;
|
||||
int targetP = regex.exactP;
|
||||
@ -212,6 +223,7 @@ public abstract class SearchAlgorithm {
|
||||
|
||||
private static final int BM_BACKWARD_SEARCH_LENGTH_THRESHOLD = 100;
|
||||
|
||||
@Override
|
||||
public final int searchBackward(Regex regex, char[] text, int textP, int adjustText, int textEnd, int textStart, int s_, int range_) {
|
||||
char[] target = regex.exact;
|
||||
int targetP = regex.exactP;
|
||||
@ -263,10 +275,12 @@ public abstract class SearchAlgorithm {
|
||||
|
||||
public static final SearchAlgorithm MAP = new SearchAlgorithm() {
|
||||
|
||||
@Override
|
||||
public final String getName() {
|
||||
return "MAP";
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int search(Regex regex, char[] text, int textP, int textEnd, int textRange) {
|
||||
byte[] map = regex.map;
|
||||
int s = textP;
|
||||
@ -278,6 +292,7 @@ public abstract class SearchAlgorithm {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int searchBackward(Regex regex, char[] text, int textP, int adjustText, int textEnd, int textStart, int s_, int range_) {
|
||||
byte[] map = regex.map;
|
||||
int s = textStart;
|
||||
|
@ -458,7 +458,7 @@ abstract class StackMachine extends Matcher implements StackType {
|
||||
isNull = 0;
|
||||
break;
|
||||
} else if (endp != s) {
|
||||
isNull = -1;; /* empty, but position changed */
|
||||
isNull = -1; /* empty, but position changed */
|
||||
}
|
||||
}
|
||||
k++;
|
||||
|
@ -24,6 +24,7 @@ package jdk.nashorn.internal.runtime.regexp.joni;
|
||||
*/
|
||||
public interface WarnCallback {
|
||||
WarnCallback DEFAULT = new WarnCallback() {
|
||||
@Override
|
||||
public void warn(String message) {
|
||||
System.err.println(message);
|
||||
}
|
||||
|
@ -19,7 +19,6 @@
|
||||
*/
|
||||
package jdk.nashorn.internal.runtime.regexp.joni.ast;
|
||||
|
||||
import jdk.nashorn.internal.runtime.regexp.joni.Config;
|
||||
import jdk.nashorn.internal.runtime.regexp.joni.Option;
|
||||
import jdk.nashorn.internal.runtime.regexp.joni.constants.EncloseType;
|
||||
|
||||
|
@ -35,7 +35,7 @@ public abstract class Node implements NodeType {
|
||||
}
|
||||
|
||||
protected void setChild(Node tgt){} // default definition
|
||||
protected Node getChild(){return null;}; // default definition
|
||||
protected Node getChild(){return null;} // default definition
|
||||
|
||||
public void swap(Node with) {
|
||||
Node tmp;
|
||||
@ -74,6 +74,7 @@ public abstract class Node implements NodeType {
|
||||
return getName() + ":0x" + Integer.toHexString(System.identityHashCode(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
StringBuilder s = new StringBuilder();
|
||||
s.append("<" + getAddressName() + " (" + (parent == null ? "NULL" : parent.getAddressName()) + ")>");
|
||||
|
@ -223,6 +223,7 @@ public final class QuantifierNode extends StateNode {
|
||||
other.target = null; // remove target from reduced quantifier
|
||||
}
|
||||
|
||||
@SuppressWarnings("fallthrough")
|
||||
public int setQuantifier(Node tgt, boolean group, ScanEnvironment env, char[] chars, int p, int end) {
|
||||
if (lower == 1 && upper == 1) return 1;
|
||||
|
||||
|
@ -19,8 +19,6 @@
|
||||
*/
|
||||
package jdk.nashorn.internal.runtime.regexp.joni.exception;
|
||||
|
||||
import jdk.nashorn.internal.runtime.regexp.joni.Config;
|
||||
|
||||
public interface ErrorMessages {
|
||||
|
||||
/* from jcodings */
|
||||
|
@ -94,6 +94,8 @@ type.error.cant.delete.property=Cannot delete property "{0}" of {1}
|
||||
type.error.cant.redefine.property=Cannot redefine property "{0}" of {1}
|
||||
type.error.property.not.writable="{0}" is not a writable property of {1}
|
||||
type.error.object.non.extensible=Cannot add new property "{0}" to non-extensible {1}
|
||||
type.error.__proto__.set.non.extensible=Cannot set __proto__ of non-extensible {0}
|
||||
type.error.circular.__proto__.set=Cannot create__proto__ cycle for {0}
|
||||
|
||||
# miscellaneous
|
||||
type.error.regex.cant.supply.flags=Cannot supply flags when constructing one RegExp from another
|
||||
|
@ -157,6 +157,14 @@ nashorn.option.fx = { \
|
||||
default=false \
|
||||
}
|
||||
|
||||
nashorn.option.global.per.engine = { \
|
||||
name="--global-per-engine", \
|
||||
desc="Use single Global instance per script engine instance.", \
|
||||
is_undocumented=true, \
|
||||
type=Boolean, \
|
||||
default=false \
|
||||
}
|
||||
|
||||
nashorn.option.log = { \
|
||||
name="--log", \
|
||||
is_undocumented=true, \
|
||||
@ -216,15 +224,6 @@ nashorn.option.no.typed.arrays = { \
|
||||
default=false \
|
||||
}
|
||||
|
||||
nashorn.option.package = { \
|
||||
name="--package", \
|
||||
is_undocumented=true, \
|
||||
desc="Package to which generated .class files are added.", \
|
||||
params="<package>", \
|
||||
type=String, \
|
||||
default="" \
|
||||
}
|
||||
|
||||
nashorn.option.parse.only = { \
|
||||
name="--parse-only", \
|
||||
is_undocumented=true, \
|
||||
@ -289,7 +288,7 @@ nashorn.option.print.symbols = { \
|
||||
nashorn.option.range.analysis = { \
|
||||
name="--range-analysis", \
|
||||
is_undocumented=true, \
|
||||
desc="Do range analysis using known compile time types, and try to narrow number types" \
|
||||
desc="EXPERIMENTAL: Do range analysis using known compile time types, and try to narrow number types" \
|
||||
}
|
||||
|
||||
nashorn.option.D = { \
|
||||
@ -308,12 +307,12 @@ nashorn.option.scripting = { \
|
||||
desc="Enable scripting features." \
|
||||
}
|
||||
|
||||
nashorn.option.specialize.calls = { \
|
||||
name="--specialize-calls", \
|
||||
is_undocumented=true, \
|
||||
type=String, \
|
||||
params="[=function_1,...,function_n]", \
|
||||
desc="Specialize all or a set of method according to callsite parameter types" \
|
||||
nashorn.option.specialize.calls = { \
|
||||
name="--specialize-calls", \
|
||||
is_undocumented=true, \
|
||||
type=String, \
|
||||
params="[=function_1,...,function_n]", \
|
||||
desc="EXPERIMENTAL: Specialize all or a set of method according to callsite parameter types" \
|
||||
}
|
||||
|
||||
nashorn.option.stdout = { \
|
||||
|
@ -144,7 +144,7 @@ Object.defineProperty(Object.prototype, "__proto__", {
|
||||
return Object.getPrototypeOf(this);
|
||||
},
|
||||
set: function(x) {
|
||||
throw new TypeError("__proto__ set not supported");
|
||||
Object.setPrototypeOf(this, x);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -445,7 +445,7 @@ public class Shell {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (res != null && res != ScriptRuntime.UNDEFINED) {
|
||||
if (res != ScriptRuntime.UNDEFINED) {
|
||||
err.println(JSType.toString(res));
|
||||
}
|
||||
}
|
||||
|
171
nashorn/test/script/basic/JDK-8019987.js
Normal file
171
nashorn/test/script/basic/JDK-8019987.js
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8019987: String trimRight and trimLeft could be defined.
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
var TESTSTRING = "abcde";
|
||||
|
||||
var SPACES = " ";
|
||||
var TESTSTRING_LEFT_SPACES = SPACES + TESTSTRING;
|
||||
var TESTSTRING_RIGHT_SPACES = TESTSTRING + SPACES;
|
||||
var TESTSTRING_BOTH_SPACES = SPACES + TESTSTRING + SPACES;
|
||||
var TESTSTRING_MIDDLE_SPACES = TESTSTRING + SPACES + TESTSTRING;
|
||||
|
||||
var WHITESPACE =
|
||||
" \t" + // space and tab
|
||||
"\n\r" + // newline and return
|
||||
"\u2028" + // line separator
|
||||
"\u2029" + // paragraph separator
|
||||
"\u000b" + // tabulation line
|
||||
"\u000c" + // ff (ctrl-l)
|
||||
"\u00a0" + // Latin-1 space
|
||||
"\u1680" + // Ogham space mark
|
||||
"\u180e" + // separator, Mongolian vowel
|
||||
"\u2000" + // en quad
|
||||
"\u2001" + // em quad
|
||||
"\u2002" + // en space
|
||||
"\u2003" + // em space
|
||||
"\u2004" + // three-per-em space
|
||||
"\u2005" + // four-per-em space
|
||||
"\u2006" + // six-per-em space
|
||||
"\u2007" + // figure space
|
||||
"\u2008" + // punctuation space
|
||||
"\u2009" + // thin space
|
||||
"\u200a" + // hair space
|
||||
"\u202f" + // narrow no-break space
|
||||
"\u205f" + // medium mathematical space
|
||||
"\u3000" + // ideographic space
|
||||
"\ufeff"; // byte order mark
|
||||
var TESTSTRING_LEFT_WHITESPACE = WHITESPACE + TESTSTRING;
|
||||
var TESTSTRING_RIGHT_WHITESPACE = TESTSTRING + WHITESPACE;
|
||||
var TESTSTRING_BOTH_WHITESPACE = WHITESPACE + TESTSTRING + WHITESPACE;
|
||||
var TESTSTRING_MIDDLE_WHITESPACE = TESTSTRING + WHITESPACE + TESTSTRING;
|
||||
|
||||
function escape(string) {
|
||||
var sb = new java.lang.StringBuilder();
|
||||
sb.append("\"");
|
||||
|
||||
for (var i = 0; i < string.length; i++) {
|
||||
var ch = string.charAt(i);
|
||||
|
||||
switch (ch) {
|
||||
case '\\':
|
||||
sb.append("\\\\");
|
||||
break;
|
||||
case '"':
|
||||
sb.append("\\\"");
|
||||
break;
|
||||
case '\'':
|
||||
sb.append("\\\'");
|
||||
break;
|
||||
case '\b':
|
||||
sb.append("\\b");
|
||||
break;
|
||||
case '\f':
|
||||
sb.append("\\f");
|
||||
break;
|
||||
case '\n':
|
||||
sb.append("\\n");
|
||||
break;
|
||||
case '\r':
|
||||
sb.append("\\r");
|
||||
break;
|
||||
case '\t':
|
||||
sb.append("\\t");
|
||||
break;
|
||||
default:
|
||||
var code = string.charCodeAt(i);
|
||||
|
||||
if (code < 0x20 || code >= 0xFF) {
|
||||
sb.append("\\u");
|
||||
|
||||
var hex = java.lang.Integer.toHexString(code);
|
||||
for (var i = hex.length; i < 4; i++) {
|
||||
sb.append('0');
|
||||
}
|
||||
sb.append(hex);
|
||||
} else {
|
||||
sb.append(ch);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sb.append("\"");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
var count = 0;
|
||||
function test(expected, trimmed) {
|
||||
count++;
|
||||
if (trimmed != expected) {
|
||||
print(count + ": Expected: " + escape(expected) + ", found: " + escape(trimmed));
|
||||
}
|
||||
}
|
||||
|
||||
test("", SPACES.trim());
|
||||
test("", SPACES.trimLeft());
|
||||
test("", SPACES.trimRight());
|
||||
|
||||
test(TESTSTRING, TESTSTRING_LEFT_SPACES.trim());
|
||||
test(TESTSTRING, TESTSTRING_LEFT_SPACES.trimLeft());
|
||||
test(TESTSTRING_LEFT_SPACES, TESTSTRING_LEFT_SPACES.trimRight());
|
||||
|
||||
test(TESTSTRING, TESTSTRING_RIGHT_SPACES.trim());
|
||||
test(TESTSTRING_RIGHT_SPACES, TESTSTRING_RIGHT_SPACES.trimLeft());
|
||||
test(TESTSTRING, TESTSTRING_RIGHT_SPACES.trimRight());
|
||||
|
||||
test(TESTSTRING, TESTSTRING_BOTH_SPACES.trim());
|
||||
test(TESTSTRING_RIGHT_SPACES, TESTSTRING_BOTH_SPACES.trimLeft());
|
||||
test(TESTSTRING_LEFT_SPACES, TESTSTRING_BOTH_SPACES.trimRight());
|
||||
|
||||
test(TESTSTRING_MIDDLE_SPACES, TESTSTRING_MIDDLE_SPACES.trim());
|
||||
test(TESTSTRING_MIDDLE_SPACES, TESTSTRING_MIDDLE_SPACES.trimLeft());
|
||||
test(TESTSTRING_MIDDLE_SPACES, TESTSTRING_MIDDLE_SPACES.trimRight());
|
||||
|
||||
test("", WHITESPACE.trim());
|
||||
test("", WHITESPACE.trimLeft());
|
||||
test("", WHITESPACE.trimRight());
|
||||
|
||||
test(TESTSTRING, TESTSTRING_LEFT_WHITESPACE.trim());
|
||||
test(TESTSTRING, TESTSTRING_LEFT_WHITESPACE.trimLeft());
|
||||
test(TESTSTRING_LEFT_WHITESPACE, TESTSTRING_LEFT_WHITESPACE.trimRight());
|
||||
|
||||
test(TESTSTRING, TESTSTRING_RIGHT_WHITESPACE.trim());
|
||||
test(TESTSTRING_RIGHT_WHITESPACE, TESTSTRING_RIGHT_WHITESPACE.trimLeft());
|
||||
test(TESTSTRING, TESTSTRING_RIGHT_WHITESPACE.trimRight());
|
||||
|
||||
test(TESTSTRING, TESTSTRING_BOTH_WHITESPACE.trim());
|
||||
test(TESTSTRING_RIGHT_WHITESPACE, TESTSTRING_BOTH_WHITESPACE.trimLeft());
|
||||
test(TESTSTRING_LEFT_WHITESPACE, TESTSTRING_BOTH_WHITESPACE.trimRight());
|
||||
|
||||
test(TESTSTRING_MIDDLE_WHITESPACE, TESTSTRING_MIDDLE_WHITESPACE.trim());
|
||||
test(TESTSTRING_MIDDLE_WHITESPACE, TESTSTRING_MIDDLE_WHITESPACE.trimLeft());
|
||||
test(TESTSTRING_MIDDLE_WHITESPACE, TESTSTRING_MIDDLE_WHITESPACE.trimRight());
|
55
nashorn/test/script/basic/JDK-8022903.js
Normal file
55
nashorn/test/script/basic/JDK-8022903.js
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8022903: Enhance for-in and for-each for Lists and Maps
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
var colors = new java.util.ArrayList()
|
||||
colors.add("red")
|
||||
colors.add("purple")
|
||||
colors.add("pink")
|
||||
|
||||
for(var index in colors) {
|
||||
print("colors[" + index + "]=" + colors[index])
|
||||
}
|
||||
|
||||
for each(var color in colors) {
|
||||
print(color)
|
||||
}
|
||||
|
||||
var capitals = new java.util.LinkedHashMap()
|
||||
capitals.Sweden = "Stockholm"
|
||||
capitals.Hungary = "Budapet"
|
||||
capitals.Croatia = "Zagreb"
|
||||
|
||||
for(var key in capitals) {
|
||||
print("capital of " + key + " is " + capitals[key])
|
||||
}
|
||||
|
||||
for each(var capital in capitals) {
|
||||
print(capital)
|
||||
}
|
12
nashorn/test/script/basic/JDK-8022903.js.EXPECTED
Normal file
12
nashorn/test/script/basic/JDK-8022903.js.EXPECTED
Normal file
@ -0,0 +1,12 @@
|
||||
colors[0]=red
|
||||
colors[1]=purple
|
||||
colors[2]=pink
|
||||
red
|
||||
purple
|
||||
pink
|
||||
capital of Sweden is Stockholm
|
||||
capital of Hungary is Budapet
|
||||
capital of Croatia is Zagreb
|
||||
Stockholm
|
||||
Budapet
|
||||
Zagreb
|
73
nashorn/test/script/basic/JDK-8023368.js
Normal file
73
nashorn/test/script/basic/JDK-8023368.js
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8023368: Instance __proto__ property should exist and be writable.
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
load("nashorn:mozilla_compat.js");
|
||||
|
||||
// function to force same callsites
|
||||
function check(obj) {
|
||||
print(obj.func());
|
||||
print(obj.x);
|
||||
print(obj.toString());
|
||||
}
|
||||
|
||||
function Func() {
|
||||
}
|
||||
|
||||
Func.prototype.func = function() {
|
||||
return "Func.prototype.func";
|
||||
}
|
||||
|
||||
Func.prototype.x = "hello";
|
||||
|
||||
var obj = new Func();
|
||||
var obj2 = Object.create(obj);
|
||||
|
||||
// check direct and indirect __proto__ change
|
||||
check(obj);
|
||||
check(obj2);
|
||||
obj.__proto__ = {
|
||||
func: function() {
|
||||
return "obj.__proto__.func @ " + __LINE__;
|
||||
},
|
||||
x: 344
|
||||
};
|
||||
|
||||
check(obj);
|
||||
check(obj2);
|
||||
|
||||
// check indirect (1 and 2 levels) __proto__ function change
|
||||
obj.__proto__.__proto__ = {
|
||||
toString: function() {
|
||||
return "new object.toString";
|
||||
}
|
||||
};
|
||||
|
||||
check(obj);
|
||||
check(obj2);
|
18
nashorn/test/script/basic/JDK-8023368.js.EXPECTED
Normal file
18
nashorn/test/script/basic/JDK-8023368.js.EXPECTED
Normal file
@ -0,0 +1,18 @@
|
||||
Func.prototype.func
|
||||
hello
|
||||
[object Object]
|
||||
Func.prototype.func
|
||||
hello
|
||||
[object Object]
|
||||
obj.__proto__.func @ 57
|
||||
344
|
||||
[object Object]
|
||||
obj.__proto__.func @ 57
|
||||
344
|
||||
[object Object]
|
||||
obj.__proto__.func @ 57
|
||||
344
|
||||
new object.toString
|
||||
obj.__proto__.func @ 57
|
||||
344
|
||||
new object.toString
|
73
nashorn/test/script/basic/JDK-8023368_2.js
Normal file
73
nashorn/test/script/basic/JDK-8023368_2.js
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8023368: Instance __proto__ property should exist and be writable.
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
// check Object.setPrototypeOf extension rather than using __proto__
|
||||
|
||||
// function to force same callsites
|
||||
function check(obj) {
|
||||
print(obj.func());
|
||||
print(obj.x);
|
||||
print(obj.toString());
|
||||
}
|
||||
|
||||
function Func() {
|
||||
}
|
||||
|
||||
Func.prototype.func = function() {
|
||||
return "Func.prototype.func";
|
||||
}
|
||||
|
||||
Func.prototype.x = "hello";
|
||||
|
||||
var obj = new Func();
|
||||
var obj2 = Object.create(obj);
|
||||
|
||||
// check direct and indirect __proto__ change
|
||||
check(obj);
|
||||
check(obj2);
|
||||
Object.setPrototypeOf(obj, {
|
||||
func: function() {
|
||||
return "obj.__proto__.func @ " + __LINE__;
|
||||
},
|
||||
x: 344
|
||||
});
|
||||
|
||||
check(obj);
|
||||
check(obj2);
|
||||
|
||||
// check indirect (1 and 2 levels) __proto__ function change
|
||||
Object.setPrototypeOf(Object.getPrototypeOf(obj), {
|
||||
toString: function() {
|
||||
return "new object.toString";
|
||||
}
|
||||
});
|
||||
|
||||
check(obj);
|
||||
check(obj2);
|
18
nashorn/test/script/basic/JDK-8023368_2.js.EXPECTED
Normal file
18
nashorn/test/script/basic/JDK-8023368_2.js.EXPECTED
Normal file
@ -0,0 +1,18 @@
|
||||
Func.prototype.func
|
||||
hello
|
||||
[object Object]
|
||||
Func.prototype.func
|
||||
hello
|
||||
[object Object]
|
||||
obj.__proto__.func @ 57
|
||||
344
|
||||
[object Object]
|
||||
obj.__proto__.func @ 57
|
||||
344
|
||||
[object Object]
|
||||
obj.__proto__.func @ 57
|
||||
344
|
||||
new object.toString
|
||||
obj.__proto__.func @ 57
|
||||
344
|
||||
new object.toString
|
84
nashorn/test/script/basic/JDK-8023373.js
Normal file
84
nashorn/test/script/basic/JDK-8023373.js
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8023373: allow super invocation for adapters
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
var CharArray = Java.type("char[]")
|
||||
var jString = Java.type("java.lang.String")
|
||||
var Character = Java.type("java.lang.Character")
|
||||
|
||||
function capitalize(s) {
|
||||
if(s instanceof CharArray) {
|
||||
return new jString(s).toUpperCase()
|
||||
}
|
||||
if(s instanceof jString) {
|
||||
return s.toUpperCase()
|
||||
}
|
||||
return Character.toUpperCase(s) // must be int
|
||||
}
|
||||
|
||||
var sw = new (Java.type("java.io.StringWriter"))
|
||||
|
||||
var FilterWriterAdapter = Java.extend(Java.type("java.io.FilterWriter"))
|
||||
|
||||
var cw = new FilterWriterAdapter(sw) {
|
||||
write: function(s, off, len) {
|
||||
s = capitalize(s)
|
||||
// Must handle overloads by arity
|
||||
if(off === undefined) {
|
||||
cw.super$write(s, 0, s.length())
|
||||
} else if (typeof s === "string") {
|
||||
cw.super$write(s, off, len)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cw.write("abcd")
|
||||
cw.write("e".charAt(0))
|
||||
cw.write("fgh".toCharArray())
|
||||
cw.write("**ijk**", 2, 3)
|
||||
cw.write("***lmno**".toCharArray(), 3, 4)
|
||||
cw.flush()
|
||||
print(sw)
|
||||
|
||||
// Can invoke super for Object methods
|
||||
print("cw has super hashCode(): " + (typeof cw.super$hashCode === "function"))
|
||||
print("cw has super equals(): " + (typeof cw.super$equals === "function"))
|
||||
// Can't invoke super for final methods
|
||||
print("cw has no super getClass(): " + (typeof cw.super$getClass === "undefined"))
|
||||
print("cw has no super wait(): " + (typeof cw.super$wait === "undefined"))
|
||||
|
||||
var r = new (Java.type("java.lang.Runnable"))(function() {})
|
||||
// Can't invoke super for abstract methods
|
||||
print("r has no super run(): " + (typeof r.super$run === "undefined"))
|
||||
// Interfaces can also invoke super Object methods
|
||||
print("r has super hashCode(): " + (typeof r.super$hashCode === "function"))
|
||||
print("r has super equals(): " + (typeof r.super$equals === "function"))
|
||||
// But still can't invoke final methods
|
||||
print("r has no super getClass(): " + (typeof r.super$getClass === "undefined"))
|
||||
print("r has no super wait(): " + (typeof r.super$wait === "undefined"))
|
10
nashorn/test/script/basic/JDK-8023373.js.EXPECTED
Normal file
10
nashorn/test/script/basic/JDK-8023373.js.EXPECTED
Normal file
@ -0,0 +1,10 @@
|
||||
ABCDEFGHIJKLMNO
|
||||
cw has super hashCode(): true
|
||||
cw has super equals(): true
|
||||
cw has no super getClass(): true
|
||||
cw has no super wait(): true
|
||||
r has no super run(): true
|
||||
r has super hashCode(): true
|
||||
r has super equals(): true
|
||||
r has no super getClass(): true
|
||||
r has no super wait(): true
|
106
nashorn/test/script/basic/JDK-8023531.js
Normal file
106
nashorn/test/script/basic/JDK-8023531.js
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8023531: new RegExp('').toString() should return '/(?:)/'
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
if (new RegExp("").toString() !== "/(?:)/") {
|
||||
throw new Error();
|
||||
} else if (!(new RegExp("").test(""))) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
if (new RegExp("", "g").toString() !== "/(?:)/g") {
|
||||
throw new Error();
|
||||
} else if (!(new RegExp("", "g").test(""))) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
if (new RegExp("", "i").toString() !== "/(?:)/i") {
|
||||
throw new Error();
|
||||
} else if (!(new RegExp("", "i").test(""))) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
if (new RegExp("", "m").toString() !== "/(?:)/m") {
|
||||
throw new Error();
|
||||
} else if (!(new RegExp("", "m").test(""))) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
if (RegExp("").toString() !== "/(?:)/") {
|
||||
throw new Error();
|
||||
} else if (!RegExp("").test("")) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
if (RegExp("", "g").toString() !== "/(?:)/g") {
|
||||
throw new Error();
|
||||
} else if (!RegExp("", "g").test("")) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
if (RegExp("", "i").toString() !== "/(?:)/i") {
|
||||
throw new Error();
|
||||
} else if (!RegExp("", "i").test("")) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
if (RegExp("", "m").toString() !== "/(?:)/m") {
|
||||
throw new Error();
|
||||
} else if (!RegExp("", "m").test("")) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
var re = /abc/;
|
||||
re.compile("");
|
||||
if (re.toString() !== "/(?:)/") {
|
||||
throw new Error();
|
||||
} else if (!re.test("")) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
re.compile("", "g");
|
||||
if (re.toString() !== "/(?:)/g") {
|
||||
throw new Error();
|
||||
} else if (!re.test("")) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
re.compile("", "i");
|
||||
if (re.toString() !== "/(?:)/i") {
|
||||
throw new Error();
|
||||
} else if (!re.test("")) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
re.compile("", "m");
|
||||
if (re.toString() !== "/(?:)/m") {
|
||||
throw new Error();
|
||||
} else if (!re.test("")) {
|
||||
throw new Error();
|
||||
}
|
42
nashorn/test/script/basic/JDK-8023551.js
Normal file
42
nashorn/test/script/basic/JDK-8023551.js
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8023551: Mirror functions can not be invoked using invokeMethod, invokeFunction
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
var m = new javax.script.ScriptEngineManager();
|
||||
var e = m.getEngineByName("nashorn");
|
||||
|
||||
function func(x) {
|
||||
print("func: " + x);
|
||||
}
|
||||
|
||||
e.put("func", func);
|
||||
e.invokeFunction("func", "hello");
|
||||
|
||||
var obj = e.eval("({ foo: func })");
|
||||
e.invokeMethod(obj, "foo", "world");
|
2
nashorn/test/script/basic/JDK-8023551.js.EXPECTED
Normal file
2
nashorn/test/script/basic/JDK-8023551.js.EXPECTED
Normal file
@ -0,0 +1,2 @@
|
||||
func: hello
|
||||
func: world
|
94
nashorn/test/script/basic/JDK-8023630.js
Normal file
94
nashorn/test/script/basic/JDK-8023630.js
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8023630: Implement Java.super() as the preferred way to call super methods
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
var CharArray = Java.type("char[]")
|
||||
var jString = Java.type("java.lang.String")
|
||||
var Character = Java.type("java.lang.Character")
|
||||
|
||||
function capitalize(s) {
|
||||
if(s instanceof CharArray) {
|
||||
return new jString(s).toUpperCase()
|
||||
}
|
||||
if(s instanceof jString) {
|
||||
return s.toUpperCase()
|
||||
}
|
||||
return Character.toUpperCase(s) // must be int
|
||||
}
|
||||
|
||||
var sw = new (Java.type("java.io.StringWriter"))
|
||||
|
||||
var FilterWriterAdapter = Java.extend(Java.type("java.io.FilterWriter"))
|
||||
|
||||
var cw = new FilterWriterAdapter(sw) {
|
||||
write: function(s, off, len) {
|
||||
s = capitalize(s)
|
||||
// Must handle overloads by arity
|
||||
if(off === undefined) {
|
||||
cw_super.write(s, 0, s.length())
|
||||
} else if (typeof s === "string") {
|
||||
cw_super.write(s, off, len)
|
||||
}
|
||||
}
|
||||
}
|
||||
var cw_super = Java.super(cw)
|
||||
|
||||
cw.write("abcd")
|
||||
cw.write("e".charAt(0))
|
||||
cw.write("fgh".toCharArray())
|
||||
cw.write("**ijk**", 2, 3)
|
||||
cw.write("***lmno**".toCharArray(), 3, 4)
|
||||
cw.flush()
|
||||
print(sw)
|
||||
|
||||
// Can invoke super for Object methods
|
||||
print("cw_super has hashCode(): " + (typeof cw_super.hashCode === "function"))
|
||||
print("cw_super has super equals(): " + (typeof cw_super.equals === "function"))
|
||||
// Can't invoke super for final methods
|
||||
print("cw_super has no getClass(): " + (typeof cw_super.getClass === "undefined"))
|
||||
print("cw_super has no wait(): " + (typeof cw_super.wait === "undefined"))
|
||||
|
||||
var r = new (Java.type("java.lang.Runnable"))(function() {})
|
||||
var r_super = Java.super(r)
|
||||
|
||||
// Can't invoke super for abstract methods
|
||||
print("r_super has no run(): " + (typeof r_super.run === "undefined"))
|
||||
// Interfaces can also invoke super Object methods
|
||||
print("r_super has hashCode(): " + (typeof r_super.hashCode === "function"))
|
||||
print("r_super has equals(): " + (typeof r_super.equals === "function"))
|
||||
// But still can't invoke final methods
|
||||
print("r_super has no getClass(): " + (typeof r_super.getClass === "undefined"))
|
||||
print("r_super has no wait(): " + (typeof r_super.wait === "undefined"))
|
||||
|
||||
var name = "write"
|
||||
print("cw_super can access write through [] getter: " + (typeof cw_super[name] === "function"))
|
||||
var name = "hashCode"
|
||||
print("cw_super can access hashCode through [] getter: " + (typeof cw_super[name] === "function"))
|
||||
var name = "getClass"
|
||||
print("cw_super can not access getClass through [] getter: " + (typeof cw_super[name] === "undefined"))
|
13
nashorn/test/script/basic/JDK-8023630.js.EXPECTED
Normal file
13
nashorn/test/script/basic/JDK-8023630.js.EXPECTED
Normal file
@ -0,0 +1,13 @@
|
||||
ABCDEFGHIJKLMNO
|
||||
cw_super has hashCode(): true
|
||||
cw_super has super equals(): true
|
||||
cw_super has no getClass(): true
|
||||
cw_super has no wait(): true
|
||||
r_super has no run(): true
|
||||
r_super has hashCode(): true
|
||||
r_super has equals(): true
|
||||
r_super has no getClass(): true
|
||||
r_super has no wait(): true
|
||||
cw_super can access write through [] getter: true
|
||||
cw_super can access hashCode through [] getter: true
|
||||
cw_super can not access getClass through [] getter: true
|
109
nashorn/test/script/basic/JDK-8023650.js
Normal file
109
nashorn/test/script/basic/JDK-8023650.js
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8023650: Regexp m flag does not recognize CRNL or CR
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
if (!/^Connection: close$/m.test('\r\n\r\nConnection: close\r\n\r\n')) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
if (!/^Connection: close$/m.test('\n\nConnection: close\n\n')) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
if (!/^Connection: close$/m.test('\r\rConnection: close\r\r')) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
if (!/^Connection: close$/m.test('\u2028\u2028Connection: close\u2028\u2028')) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
if (!/^Connection: close$/m.test('\u2029\u2029Connection: close\u2029\u2029')) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
var result = /a(.*)/.exec("a\r");
|
||||
if (!result || result[0] != 'a' || result[1] != '') {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
result = /a(.*)/m.exec("a\r");
|
||||
if (!result || result[0] != 'a' || result[1] != '') {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
result = /a(.*)/.exec("a\n");
|
||||
if (!result || result[0] != 'a' || result[1] != '') {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
result = /a(.*)/m.exec("a\n");
|
||||
if (!result || result[0] != 'a' || result[1] != '') {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
result = /a(.*)/.exec("a\r\n");
|
||||
if (!result || result[0] != 'a' || result[1] != '') {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
result = /a(.*)/m.exec("a\r\n");
|
||||
if (!result || result[0] != 'a' || result[1] != '') {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
result = /a(.*)/.exec("a\u2028");
|
||||
if (!result || result[0] != 'a' || result[1] != '') {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
result = /a(.*)/m.exec("a\u2029");
|
||||
if (!result || result[0] != 'a' || result[1] != '') {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
if (/a$/.test("a\n")) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
if (/a$/.test("a\r")) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
if (/a$/.test("a\r\n")) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
if (/a$/.test("a\u2028")) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
if (/a$/.test("a\u2029")) {
|
||||
throw new Error();
|
||||
}
|
38
nashorn/test/script/basic/JDK-8023780.js
Normal file
38
nashorn/test/script/basic/JDK-8023780.js
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8023780: Gracefully handle @CS methods while binding bean properties
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
var obj = {}
|
||||
Object.bindProperties(obj, java.lang.Thread.currentThread());
|
||||
|
||||
print(typeof obj.getName === "function")
|
||||
print(typeof obj.getCurrentContext === "undefined")
|
||||
|
||||
print(Object.hasOwnProperty("name"))
|
||||
print(!Object.hasOwnProperty("currentContext"))
|
4
nashorn/test/script/basic/JDK-8023780.js.EXPECTED
Normal file
4
nashorn/test/script/basic/JDK-8023780.js.EXPECTED
Normal file
@ -0,0 +1,4 @@
|
||||
true
|
||||
true
|
||||
true
|
||||
true
|
66
nashorn/test/script/basic/JDK-8023784.js
Normal file
66
nashorn/test/script/basic/JDK-8023784.js
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8023784: Object.prototype.toString should contain the class name for all instances
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
// two parts to this bug -- typed array don't have proper [[Class]] property
|
||||
|
||||
print(Object.prototype.toString.call(new ArrayBuffer(1)));
|
||||
print(Object.prototype.toString.call(new Int8Array(1)));
|
||||
print(Object.prototype.toString.call(new Int16Array(1)));
|
||||
print(Object.prototype.toString.call(new Int32Array(1)));
|
||||
print(Object.prototype.toString.call(new Uint8Array(1)));
|
||||
print(Object.prototype.toString.call(new Uint8ClampedArray(1)));
|
||||
print(Object.prototype.toString.call(new Uint16Array(1)));
|
||||
print(Object.prototype.toString.call(new Uint32Array(1)));
|
||||
print(Object.prototype.toString.call(new Float32Array(1)));
|
||||
print(Object.prototype.toString.call(new Float64Array(1)));
|
||||
|
||||
// second part is that Object.prototype.toString does not handle mirror
|
||||
// in the manner expected.
|
||||
|
||||
var global = loadWithNewGlobal({
|
||||
name: "test",
|
||||
script: "this"
|
||||
});
|
||||
|
||||
print(Object.prototype.toString.call(new global.Object()));
|
||||
print(Object.prototype.toString.call(new global.Array()));
|
||||
print(Object.prototype.toString.call(new global.RegExp()));
|
||||
print(Object.prototype.toString.call(new global.Error("error!")));
|
||||
print(Object.prototype.toString.call(global.Object));
|
||||
print(Object.prototype.toString.call(new global.ArrayBuffer(1)));
|
||||
print(Object.prototype.toString.call(new global.Int8Array(1)));
|
||||
print(Object.prototype.toString.call(new global.Int16Array(1)));
|
||||
print(Object.prototype.toString.call(new global.Int32Array(1)));
|
||||
print(Object.prototype.toString.call(new global.Uint8Array(1)));
|
||||
print(Object.prototype.toString.call(new global.Uint8ClampedArray(1)));
|
||||
print(Object.prototype.toString.call(new global.Uint16Array(1)));
|
||||
print(Object.prototype.toString.call(new global.Uint32Array(1)));
|
||||
print(Object.prototype.toString.call(new global.Float32Array(1)));
|
||||
print(Object.prototype.toString.call(new global.Float64Array(1)));
|
25
nashorn/test/script/basic/JDK-8023784.js.EXPECTED
Normal file
25
nashorn/test/script/basic/JDK-8023784.js.EXPECTED
Normal file
@ -0,0 +1,25 @@
|
||||
[object ArrayBuffer]
|
||||
[object Int8Array]
|
||||
[object Int16Array]
|
||||
[object Int32Array]
|
||||
[object Uint8Array]
|
||||
[object Uint8ClampedArray]
|
||||
[object Uint16Array]
|
||||
[object Uint32Array]
|
||||
[object Float32Array]
|
||||
[object Float64Array]
|
||||
[object Object]
|
||||
[object Array]
|
||||
[object RegExp]
|
||||
[object Error]
|
||||
[object Function]
|
||||
[object ArrayBuffer]
|
||||
[object Int8Array]
|
||||
[object Int16Array]
|
||||
[object Int32Array]
|
||||
[object Uint8Array]
|
||||
[object Uint8ClampedArray]
|
||||
[object Uint16Array]
|
||||
[object Uint32Array]
|
||||
[object Float32Array]
|
||||
[object Float64Array]
|
@ -1,5 +1,5 @@
|
||||
8 8 true undefined
|
||||
[object Object] [object Object] [object Object]
|
||||
[object ArrayBuffer] [object ArrayBuffer] [object Int8Array]
|
||||
0 8 8 1
|
||||
0 8 8 1
|
||||
0 8 8 1
|
||||
|
@ -35,7 +35,10 @@ if (typeof (5).x !== 'number') {
|
||||
fail("typeof(5).x is not 'number'");
|
||||
}
|
||||
|
||||
if (typeof (java.lang.System.out) != 'object') {
|
||||
// It is function because PrintStream implements Closeable, which is
|
||||
// marked with @FunctionalInterface. Yes, this means calling a stream
|
||||
// like "stream()" closes it.
|
||||
if (typeof (java.lang.System.out) != 'function') {
|
||||
fail("typeof java.lang.System.out is not 'object'");
|
||||
}
|
||||
|
||||
|
46
nashorn/test/script/basic/circular_proto.js
Normal file
46
nashorn/test/script/basic/circular_proto.js
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8023368: Instance __proto__ property should exist and be writable.
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
// check that we cannot create __proto__ cycle
|
||||
load("nashorn:mozilla_compat.js");
|
||||
|
||||
var obj = {};
|
||||
var obj2 = Object.create(obj);
|
||||
|
||||
// attempt to create __proto__ cycle
|
||||
try {
|
||||
obj.__proto__ = obj2;
|
||||
fail("Should have thrown TypeError");
|
||||
} catch (e) {
|
||||
if (! (e instanceof TypeError)) {
|
||||
fail("Expected TypeError, got " + e);
|
||||
}
|
||||
print(e);
|
||||
}
|
1
nashorn/test/script/basic/circular_proto.js.EXPECTED
Normal file
1
nashorn/test/script/basic/circular_proto.js.EXPECTED
Normal file
@ -0,0 +1 @@
|
||||
TypeError: Cannot create__proto__ cycle for [object Object]
|
52
nashorn/test/script/basic/mirror_proto_assign.js
Normal file
52
nashorn/test/script/basic/mirror_proto_assign.js
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8023368: Instance __proto__ property should exist and be writable.
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
// check that Object.setPrototypeOf works for mirror objects as well.
|
||||
|
||||
var global = loadWithNewGlobal({
|
||||
name: "test",
|
||||
script: "var obj = {}; this"
|
||||
});
|
||||
|
||||
var proto = global.eval("({ foo: 323 })");
|
||||
|
||||
Object.setPrototypeOf(global.obj, proto);
|
||||
|
||||
function func(obj) {
|
||||
// check proto inherited value
|
||||
print("obj.foo = " + obj.foo);
|
||||
}
|
||||
|
||||
func(global.obj);
|
||||
|
||||
var newProto = global.eval("({ foo: 'hello' })");
|
||||
Object.setPrototypeOf(global.obj, newProto);
|
||||
|
||||
func(global.obj);
|
@ -0,0 +1,2 @@
|
||||
obj.foo = 323
|
||||
obj.foo = hello
|
44
nashorn/test/script/basic/nonextensible_proto_assign.js
Normal file
44
nashorn/test/script/basic/nonextensible_proto_assign.js
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8023368: Instance __proto__ property should exist and be writable.
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
load("nashorn:mozilla_compat.js")
|
||||
|
||||
// check that we cannot assign to __proto__ of a non-extensible object
|
||||
try {
|
||||
var obj = {}
|
||||
Object.preventExtensions(obj);
|
||||
obj.__proto__ = { };
|
||||
fail("Should have thrown TypeError");
|
||||
} catch (e) {
|
||||
if (! (e instanceof TypeError)) {
|
||||
fail("Expected TypeError, got " + e);
|
||||
}
|
||||
print(e);
|
||||
}
|
@ -0,0 +1 @@
|
||||
TypeError: Cannot set __proto__ of non-extensible [object Object]
|
525
nashorn/test/src/jdk/nashorn/api/scripting/InvocableTest.java
Normal file
525
nashorn/test/src/jdk/nashorn/api/scripting/InvocableTest.java
Normal file
@ -0,0 +1,525 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.nashorn.api.scripting;
|
||||
|
||||
import java.util.Objects;
|
||||
import javax.script.Invocable;
|
||||
import javax.script.ScriptContext;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
import javax.script.SimpleScriptContext;
|
||||
import org.testng.Assert;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.fail;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Tests for javax.script.Invocable implementation of nashorn.
|
||||
*/
|
||||
public class InvocableTest {
|
||||
|
||||
private void log(String msg) {
|
||||
org.testng.Reporter.log(msg, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invokeMethodTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
|
||||
try {
|
||||
e.eval("var Example = function() { this.hello = function() { return 'Hello World!'; };}; myExample = new Example();");
|
||||
final Object obj = e.get("myExample");
|
||||
final Object res = ((Invocable) e).invokeMethod(obj, "hello");
|
||||
assertEquals(res, "Hello World!");
|
||||
} catch (final Exception exp) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Check that we can call invokeMethod on an object that we got by
|
||||
* evaluating script with different Context set.
|
||||
*/
|
||||
public void invokeMethodDifferentContextTest() {
|
||||
ScriptEngineManager m = new ScriptEngineManager();
|
||||
ScriptEngine e = m.getEngineByName("nashorn");
|
||||
|
||||
try {
|
||||
// define an object with method on it
|
||||
Object obj = e.eval("({ hello: function() { return 'Hello World!'; } })");
|
||||
|
||||
final ScriptContext ctxt = new SimpleScriptContext();
|
||||
ctxt.setBindings(e.createBindings(), ScriptContext.ENGINE_SCOPE);
|
||||
e.setContext(ctxt);
|
||||
|
||||
// invoke 'func' on obj - but with current script context changed
|
||||
final Object res = ((Invocable) e).invokeMethod(obj, "hello");
|
||||
assertEquals(res, "Hello World!");
|
||||
} catch (final Exception exp) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Check that invokeMethod throws NPE on null method name.
|
||||
*/
|
||||
public void invokeMethodNullNameTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
|
||||
try {
|
||||
final Object obj = e.eval("({})");
|
||||
final Object res = ((Invocable) e).invokeMethod(obj, null);
|
||||
fail("should have thrown NPE");
|
||||
} catch (final Exception exp) {
|
||||
if (!(exp instanceof NullPointerException)) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Check that invokeMethod throws NoSuchMethodException on missing method.
|
||||
*/
|
||||
public void invokeMethodMissingTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
|
||||
try {
|
||||
final Object obj = e.eval("({})");
|
||||
final Object res = ((Invocable) e).invokeMethod(obj, "nonExistentMethod");
|
||||
fail("should have thrown NoSuchMethodException");
|
||||
} catch (final Exception exp) {
|
||||
if (!(exp instanceof NoSuchMethodException)) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Check that calling method on non-script object 'thiz' results in
|
||||
* IllegalArgumentException.
|
||||
*/
|
||||
public void invokeMethodNonScriptObjectThizTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
|
||||
try {
|
||||
((Invocable) e).invokeMethod(new Object(), "toString");
|
||||
fail("should have thrown IllegalArgumentException");
|
||||
} catch (final Exception exp) {
|
||||
if (!(exp instanceof IllegalArgumentException)) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Check that calling method on null 'thiz' results in
|
||||
* IllegalArgumentException.
|
||||
*/
|
||||
public void invokeMethodNullThizTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
|
||||
try {
|
||||
((Invocable) e).invokeMethod(null, "toString");
|
||||
fail("should have thrown IllegalArgumentException");
|
||||
} catch (final Exception exp) {
|
||||
if (!(exp instanceof IllegalArgumentException)) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Check that calling method on mirror created by another engine results in
|
||||
* IllegalArgumentException.
|
||||
*/
|
||||
public void invokeMethodMixEnginesTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine engine1 = m.getEngineByName("nashorn");
|
||||
final ScriptEngine engine2 = m.getEngineByName("nashorn");
|
||||
|
||||
try {
|
||||
Object obj = engine1.eval("({ run: function() {} })");
|
||||
// pass object from engine1 to engine2 as 'thiz' for invokeMethod
|
||||
((Invocable) engine2).invokeMethod(obj, "run");
|
||||
fail("should have thrown IllegalArgumentException");
|
||||
} catch (final Exception exp) {
|
||||
if (!(exp instanceof IllegalArgumentException)) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getInterfaceTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
final Invocable inv = (Invocable) e;
|
||||
|
||||
// try to get interface from global functions
|
||||
try {
|
||||
e.eval("function run() { print('run'); };");
|
||||
final Runnable runnable = inv.getInterface(Runnable.class);
|
||||
runnable.run();
|
||||
} catch (final Exception exp) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
|
||||
// try interface on specific script object
|
||||
try {
|
||||
e.eval("var obj = { run: function() { print('run from obj'); } };");
|
||||
Object obj = e.get("obj");
|
||||
final Runnable runnable = inv.getInterface(obj, Runnable.class);
|
||||
runnable.run();
|
||||
} catch (final Exception exp) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public interface Foo {
|
||||
|
||||
public void bar();
|
||||
}
|
||||
|
||||
public interface Foo2 extends Foo {
|
||||
|
||||
public void bar2();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getInterfaceMissingTest() {
|
||||
final ScriptEngineManager manager = new ScriptEngineManager();
|
||||
final ScriptEngine engine = manager.getEngineByName("nashorn");
|
||||
|
||||
// don't define any function.
|
||||
try {
|
||||
engine.eval("");
|
||||
} catch (final Exception exp) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
|
||||
Runnable runnable = ((Invocable) engine).getInterface(Runnable.class);
|
||||
if (runnable != null) {
|
||||
fail("runnable is not null!");
|
||||
}
|
||||
|
||||
// now define "run"
|
||||
try {
|
||||
engine.eval("function run() { print('this is run function'); }");
|
||||
} catch (final Exception exp) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
runnable = ((Invocable) engine).getInterface(Runnable.class);
|
||||
// should not return null now!
|
||||
runnable.run();
|
||||
|
||||
// define only one method of "Foo2"
|
||||
try {
|
||||
engine.eval("function bar() { print('bar function'); }");
|
||||
} catch (final Exception exp) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
|
||||
Foo2 foo2 = ((Invocable) engine).getInterface(Foo2.class);
|
||||
if (foo2 != null) {
|
||||
throw new RuntimeException("foo2 is not null!");
|
||||
}
|
||||
|
||||
// now define other method of "Foo2"
|
||||
try {
|
||||
engine.eval("function bar2() { print('bar2 function'); }");
|
||||
} catch (final Exception exp) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
foo2 = ((Invocable) engine).getInterface(Foo2.class);
|
||||
foo2.bar();
|
||||
foo2.bar2();
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Try passing non-interface Class object for interface implementation.
|
||||
*/
|
||||
public void getNonInterfaceGetInterfaceTest() {
|
||||
final ScriptEngineManager manager = new ScriptEngineManager();
|
||||
final ScriptEngine engine = manager.getEngineByName("nashorn");
|
||||
try {
|
||||
log(Objects.toString(((Invocable) engine).getInterface(Object.class)));
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (final Exception exp) {
|
||||
if (!(exp instanceof IllegalArgumentException)) {
|
||||
fail("IllegalArgumentException expected, got " + exp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Check that we can get interface out of a script object even after
|
||||
* switching to use different ScriptContext.
|
||||
*/
|
||||
public void getInterfaceDifferentContext() {
|
||||
ScriptEngineManager m = new ScriptEngineManager();
|
||||
ScriptEngine e = m.getEngineByName("nashorn");
|
||||
try {
|
||||
Object obj = e.eval("({ run: function() { } })");
|
||||
|
||||
// change script context
|
||||
ScriptContext ctxt = new SimpleScriptContext();
|
||||
ctxt.setBindings(e.createBindings(), ScriptContext.ENGINE_SCOPE);
|
||||
e.setContext(ctxt);
|
||||
|
||||
Runnable r = ((Invocable) e).getInterface(obj, Runnable.class);
|
||||
r.run();
|
||||
} catch (final Exception exp) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Check that getInterface on non-script object 'thiz' results in
|
||||
* IllegalArgumentException.
|
||||
*/
|
||||
public void getInterfaceNonScriptObjectThizTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
|
||||
try {
|
||||
((Invocable) e).getInterface(new Object(), Runnable.class);
|
||||
fail("should have thrown IllegalArgumentException");
|
||||
} catch (final Exception exp) {
|
||||
if (!(exp instanceof IllegalArgumentException)) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Check that getInterface on null 'thiz' results in
|
||||
* IllegalArgumentException.
|
||||
*/
|
||||
public void getInterfaceNullThizTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
|
||||
try {
|
||||
((Invocable) e).getInterface(null, Runnable.class);
|
||||
fail("should have thrown IllegalArgumentException");
|
||||
} catch (final Exception exp) {
|
||||
if (!(exp instanceof IllegalArgumentException)) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Check that calling getInterface on mirror created by another engine
|
||||
* results in IllegalArgumentException.
|
||||
*/
|
||||
public void getInterfaceMixEnginesTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine engine1 = m.getEngineByName("nashorn");
|
||||
final ScriptEngine engine2 = m.getEngineByName("nashorn");
|
||||
|
||||
try {
|
||||
Object obj = engine1.eval("({ run: function() {} })");
|
||||
// pass object from engine1 to engine2 as 'thiz' for getInterface
|
||||
((Invocable) engine2).getInterface(obj, Runnable.class);
|
||||
fail("should have thrown IllegalArgumentException");
|
||||
} catch (final Exception exp) {
|
||||
if (!(exp instanceof IllegalArgumentException)) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* check that null function name results in NPE.
|
||||
*/
|
||||
public void invokeFunctionNullNameTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
|
||||
try {
|
||||
final Object res = ((Invocable) e).invokeFunction(null);
|
||||
fail("should have thrown NPE");
|
||||
} catch (final Exception exp) {
|
||||
if (!(exp instanceof NullPointerException)) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Check that attempt to call missing function results in
|
||||
* NoSuchMethodException.
|
||||
*/
|
||||
public void invokeFunctionMissingTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
|
||||
try {
|
||||
final Object res = ((Invocable) e).invokeFunction("NonExistentFunc");
|
||||
fail("should have thrown NoSuchMethodException");
|
||||
} catch (final Exception exp) {
|
||||
if (!(exp instanceof NoSuchMethodException)) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Check that invokeFunction calls functions only from current context's
|
||||
* Bindings.
|
||||
*/
|
||||
public void invokeFunctionDifferentContextTest() {
|
||||
ScriptEngineManager m = new ScriptEngineManager();
|
||||
ScriptEngine e = m.getEngineByName("nashorn");
|
||||
|
||||
try {
|
||||
// define an object with method on it
|
||||
Object obj = e.eval("function hello() { return 'Hello World!'; }");
|
||||
final ScriptContext ctxt = new SimpleScriptContext();
|
||||
ctxt.setBindings(e.createBindings(), ScriptContext.ENGINE_SCOPE);
|
||||
// change engine's current context
|
||||
e.setContext(ctxt);
|
||||
|
||||
((Invocable) e).invokeFunction("hello"); // no 'hello' in new context!
|
||||
fail("should have thrown NoSuchMethodException");
|
||||
} catch (final Exception exp) {
|
||||
if (!(exp instanceof NoSuchMethodException)) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invokeFunctionExceptionTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
try {
|
||||
e.eval("function func() { throw new TypeError(); }");
|
||||
} catch (final Throwable t) {
|
||||
t.printStackTrace();
|
||||
fail(t.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
((Invocable) e).invokeFunction("func");
|
||||
fail("should have thrown exception");
|
||||
} catch (final ScriptException se) {
|
||||
// ECMA TypeError property wrapped as a ScriptException
|
||||
log("got " + se + " as expected");
|
||||
} catch (final Throwable t) {
|
||||
t.printStackTrace();
|
||||
fail(t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invokeMethodExceptionTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
try {
|
||||
e.eval("var sobj = {}; sobj.foo = function func() { throw new TypeError(); }");
|
||||
} catch (final Throwable t) {
|
||||
t.printStackTrace();
|
||||
fail(t.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
final Object sobj = e.get("sobj");
|
||||
((Invocable) e).invokeMethod(sobj, "foo");
|
||||
fail("should have thrown exception");
|
||||
} catch (final ScriptException se) {
|
||||
// ECMA TypeError property wrapped as a ScriptException
|
||||
log("got " + se + " as expected");
|
||||
} catch (final Throwable t) {
|
||||
t.printStackTrace();
|
||||
fail(t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Tests whether invocation of a JavaScript method through a variable arity
|
||||
* Java method will pass the vararg array. Both non-vararg and vararg
|
||||
* JavaScript methods are tested.
|
||||
*
|
||||
* @throws ScriptException
|
||||
*/
|
||||
public void variableArityInterfaceTest() throws ScriptException {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
e.eval(
|
||||
"function test1(i, strings) {"
|
||||
+ " return 'i == ' + i + ', strings instanceof java.lang.String[] == ' + (strings instanceof Java.type('java.lang.String[]')) + ', strings == ' + java.util.Arrays.toString(strings)"
|
||||
+ "}"
|
||||
+ "function test2() {"
|
||||
+ " return 'arguments[0] == ' + arguments[0] + ', arguments[1] instanceof java.lang.String[] == ' + (arguments[1] instanceof Java.type('java.lang.String[]')) + ', arguments[1] == ' + java.util.Arrays.toString(arguments[1])"
|
||||
+ "}");
|
||||
final VariableArityTestInterface itf = ((Invocable) e).getInterface(VariableArityTestInterface.class);
|
||||
Assert.assertEquals(itf.test1(42, "a", "b"), "i == 42, strings instanceof java.lang.String[] == true, strings == [a, b]");
|
||||
Assert.assertEquals(itf.test2(44, "c", "d", "e"), "arguments[0] == 44, arguments[1] instanceof java.lang.String[] == true, arguments[1] == [c, d, e]");
|
||||
}
|
||||
}
|
248
nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java
Normal file
248
nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java
Normal file
@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.nashorn.api.scripting;
|
||||
|
||||
import javax.script.Bindings;
|
||||
import javax.script.ScriptContext;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
import javax.script.SimpleBindings;
|
||||
import javax.script.SimpleScriptContext;
|
||||
import org.testng.Assert;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
import static org.testng.Assert.fail;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Tests for jsr223 Bindings "scope" (engine, global scopes)
|
||||
*/
|
||||
public class ScopeTest {
|
||||
|
||||
@Test
|
||||
public void createBindingsTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
Bindings b = e.createBindings();
|
||||
b.put("foo", 42.0);
|
||||
Object res = null;
|
||||
try {
|
||||
res = e.eval("foo == 42.0", b);
|
||||
} catch (final ScriptException | NullPointerException se) {
|
||||
se.printStackTrace();
|
||||
fail(se.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(res, Boolean.TRUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void engineScopeTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
Bindings engineScope = e.getBindings(ScriptContext.ENGINE_SCOPE);
|
||||
|
||||
// check few ECMA standard built-in global properties
|
||||
assertNotNull(engineScope.get("Object"));
|
||||
assertNotNull(engineScope.get("TypeError"));
|
||||
assertNotNull(engineScope.get("eval"));
|
||||
|
||||
// can access via ScriptEngine.get as well
|
||||
assertNotNull(e.get("Object"));
|
||||
assertNotNull(e.get("TypeError"));
|
||||
assertNotNull(e.get("eval"));
|
||||
|
||||
// Access by either way should return same object
|
||||
assertEquals(engineScope.get("Array"), e.get("Array"));
|
||||
assertEquals(engineScope.get("EvalError"), e.get("EvalError"));
|
||||
assertEquals(engineScope.get("undefined"), e.get("undefined"));
|
||||
|
||||
// try exposing a new variable from scope
|
||||
engineScope.put("myVar", "foo");
|
||||
try {
|
||||
assertEquals(e.eval("myVar"), "foo");
|
||||
} catch (final ScriptException se) {
|
||||
se.printStackTrace();
|
||||
fail(se.getMessage());
|
||||
}
|
||||
|
||||
// update "myVar" in script an check the value from scope
|
||||
try {
|
||||
e.eval("myVar = 'nashorn';");
|
||||
} catch (final ScriptException se) {
|
||||
se.printStackTrace();
|
||||
fail(se.getMessage());
|
||||
}
|
||||
|
||||
// now check modified value from scope and engine
|
||||
assertEquals(engineScope.get("myVar"), "nashorn");
|
||||
assertEquals(e.get("myVar"), "nashorn");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiGlobalTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
final Bindings b = e.createBindings();
|
||||
final ScriptContext newCtxt = new SimpleScriptContext();
|
||||
newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
|
||||
|
||||
try {
|
||||
Object obj1 = e.eval("Object");
|
||||
Object obj2 = e.eval("Object", newCtxt);
|
||||
Assert.assertNotEquals(obj1, obj2);
|
||||
Assert.assertNotNull(obj1);
|
||||
Assert.assertNotNull(obj2);
|
||||
Assert.assertEquals(obj1.toString(), obj2.toString());
|
||||
|
||||
e.eval("x = 'hello'");
|
||||
e.eval("x = 'world'", newCtxt);
|
||||
Object x1 = e.getContext().getAttribute("x");
|
||||
Object x2 = newCtxt.getAttribute("x");
|
||||
Assert.assertNotEquals(x1, x2);
|
||||
Assert.assertEquals(x1, "hello");
|
||||
Assert.assertEquals(x2, "world");
|
||||
|
||||
x1 = e.eval("x");
|
||||
x2 = e.eval("x", newCtxt);
|
||||
Assert.assertNotEquals(x1, x2);
|
||||
Assert.assertEquals(x1, "hello");
|
||||
Assert.assertEquals(x2, "world");
|
||||
|
||||
final ScriptContext origCtxt = e.getContext();
|
||||
e.setContext(newCtxt);
|
||||
e.eval("y = new Object()");
|
||||
e.eval("y = new Object()", origCtxt);
|
||||
|
||||
Object y1 = origCtxt.getAttribute("y");
|
||||
Object y2 = newCtxt.getAttribute("y");
|
||||
Assert.assertNotEquals(y1, y2);
|
||||
Assert.assertNotEquals(e.eval("y"), e.eval("y", origCtxt));
|
||||
Assert.assertEquals("[object Object]", y1.toString());
|
||||
Assert.assertEquals("[object Object]", y2.toString());
|
||||
} catch (final ScriptException se) {
|
||||
se.printStackTrace();
|
||||
fail(se.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void userEngineScopeBindingsTest() throws ScriptException {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
e.eval("function func() {}");
|
||||
|
||||
final ScriptContext newContext = new SimpleScriptContext();
|
||||
newContext.setBindings(new SimpleBindings(), ScriptContext.ENGINE_SCOPE);
|
||||
// we are using a new bindings - so it should have 'func' defined
|
||||
Object value = e.eval("typeof func", newContext);
|
||||
assertTrue(value.equals("undefined"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void userEngineScopeBindingsNoLeakTest() throws ScriptException {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
final ScriptContext newContext = new SimpleScriptContext();
|
||||
newContext.setBindings(new SimpleBindings(), ScriptContext.ENGINE_SCOPE);
|
||||
e.eval("function foo() {}", newContext);
|
||||
|
||||
// in the default context's ENGINE_SCOPE, 'foo' shouldn't exist
|
||||
assertTrue(e.eval("typeof foo").equals("undefined"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void userEngineScopeBindingsRetentionTest() throws ScriptException {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
final ScriptContext newContext = new SimpleScriptContext();
|
||||
newContext.setBindings(new SimpleBindings(), ScriptContext.ENGINE_SCOPE);
|
||||
e.eval("function foo() {}", newContext);
|
||||
|
||||
// definition retained with user's ENGINE_SCOPE Binding
|
||||
assertTrue(e.eval("typeof foo", newContext).equals("function"));
|
||||
|
||||
final Bindings oldBindings = newContext.getBindings(ScriptContext.ENGINE_SCOPE);
|
||||
// but not in another ENGINE_SCOPE binding
|
||||
newContext.setBindings(new SimpleBindings(), ScriptContext.ENGINE_SCOPE);
|
||||
assertTrue(e.eval("typeof foo", newContext).equals("undefined"));
|
||||
|
||||
// restore ENGINE_SCOPE and check again
|
||||
newContext.setBindings(oldBindings, ScriptContext.ENGINE_SCOPE);
|
||||
assertTrue(e.eval("typeof foo", newContext).equals("function"));
|
||||
}
|
||||
|
||||
@Test
|
||||
// check that engine.js definitions are visible in all new global instances
|
||||
public void checkBuiltinsInNewBindingsTest() throws ScriptException {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
|
||||
// check default global instance has engine.js definitions
|
||||
final Bindings g = (Bindings) e.eval("this");
|
||||
Object value = g.get("__noSuchProperty__");
|
||||
assertTrue(value instanceof ScriptObjectMirror && ((ScriptObjectMirror)value).isFunction());
|
||||
value = g.get("print");
|
||||
assertTrue(value instanceof ScriptObjectMirror && ((ScriptObjectMirror)value).isFunction());
|
||||
|
||||
// check new global instance created has engine.js definitions
|
||||
Bindings b = e.createBindings();
|
||||
value = b.get("__noSuchProperty__");
|
||||
assertTrue(value instanceof ScriptObjectMirror && ((ScriptObjectMirror)value).isFunction());
|
||||
value = b.get("print");
|
||||
assertTrue(value instanceof ScriptObjectMirror && ((ScriptObjectMirror)value).isFunction());
|
||||
|
||||
// put a mapping into GLOBAL_SCOPE
|
||||
final Bindings globalScope = e.getContext().getBindings(ScriptContext.GLOBAL_SCOPE);
|
||||
globalScope.put("x", "hello");
|
||||
|
||||
// GLOBAL_SCOPE mapping should be visible from default ScriptContext eval
|
||||
assertTrue(e.eval("x").equals("hello"));
|
||||
|
||||
final ScriptContext ctx = new SimpleScriptContext();
|
||||
ctx.setBindings(globalScope, ScriptContext.GLOBAL_SCOPE);
|
||||
ctx.setBindings(b, ScriptContext.ENGINE_SCOPE);
|
||||
|
||||
// GLOBAL_SCOPE mapping should be visible from non-default ScriptContext eval
|
||||
assertTrue(e.eval("x", ctx).equals("hello"));
|
||||
|
||||
// try some arbitray Bindings for ENGINE_SCOPE
|
||||
Bindings sb = new SimpleBindings();
|
||||
ctx.setBindings(sb, ScriptContext.ENGINE_SCOPE);
|
||||
|
||||
// GLOBAL_SCOPE mapping should be visible from non-default ScriptContext eval
|
||||
assertTrue(e.eval("x", ctx).equals("hello"));
|
||||
|
||||
// engine.js builtins are still defined even with arbitrary Bindings
|
||||
assertTrue(e.eval("typeof print", ctx).equals("function"));
|
||||
assertTrue(e.eval("typeof __noSuchProperty__", ctx).equals("function"));
|
||||
|
||||
// ENGINE_SCOPE definition should 'hide' GLOBAL_SCOPE definition
|
||||
sb.put("x", "newX");
|
||||
assertTrue(e.eval("x", ctx).equals("newX"));
|
||||
}
|
||||
}
|
@ -26,29 +26,21 @@
|
||||
package jdk.nashorn.api.scripting;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
import static org.testng.Assert.fail;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.Callable;
|
||||
import javax.script.Bindings;
|
||||
import javax.script.Compilable;
|
||||
import javax.script.CompiledScript;
|
||||
import javax.script.Invocable;
|
||||
import javax.script.ScriptContext;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineFactory;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
import javax.script.SimpleScriptContext;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
@ -238,214 +230,6 @@ public class ScriptEngineTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createBindingsTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
Bindings b = e.createBindings();
|
||||
b.put("foo", 42.0);
|
||||
Object res = null;
|
||||
try {
|
||||
res = e.eval("foo == 42.0", b);
|
||||
} catch (final ScriptException | NullPointerException se) {
|
||||
se.printStackTrace();
|
||||
fail(se.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(res, Boolean.TRUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getInterfaceTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
final Invocable inv = (Invocable)e;
|
||||
|
||||
// try to get interface from global functions
|
||||
try {
|
||||
e.eval("function run() { print('run'); };");
|
||||
final Runnable runnable = inv.getInterface(Runnable.class);
|
||||
runnable.run();
|
||||
} catch (final Exception exp) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
|
||||
// try interface on specific script object
|
||||
try {
|
||||
e.eval("var obj = { run: function() { print('run from obj'); } };");
|
||||
Object obj = e.get("obj");
|
||||
final Runnable runnable = inv.getInterface(obj, Runnable.class);
|
||||
runnable.run();
|
||||
} catch (final Exception exp) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public interface Foo {
|
||||
public void bar();
|
||||
}
|
||||
|
||||
public interface Foo2 extends Foo {
|
||||
public void bar2();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getInterfaceMissingTest() {
|
||||
final ScriptEngineManager manager = new ScriptEngineManager();
|
||||
final ScriptEngine engine = manager.getEngineByName("nashorn");
|
||||
|
||||
// don't define any function.
|
||||
try {
|
||||
engine.eval("");
|
||||
} catch (final Exception exp) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
|
||||
Runnable runnable = ((Invocable)engine).getInterface(Runnable.class);
|
||||
if (runnable != null) {
|
||||
fail("runnable is not null!");
|
||||
}
|
||||
|
||||
// now define "run"
|
||||
try {
|
||||
engine.eval("function run() { print('this is run function'); }");
|
||||
} catch (final Exception exp) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
runnable = ((Invocable)engine).getInterface(Runnable.class);
|
||||
// should not return null now!
|
||||
runnable.run();
|
||||
|
||||
// define only one method of "Foo2"
|
||||
try {
|
||||
engine.eval("function bar() { print('bar function'); }");
|
||||
} catch (final Exception exp) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
|
||||
Foo2 foo2 = ((Invocable)engine).getInterface(Foo2.class);
|
||||
if (foo2 != null) {
|
||||
throw new RuntimeException("foo2 is not null!");
|
||||
}
|
||||
|
||||
// now define other method of "Foo2"
|
||||
try {
|
||||
engine.eval("function bar2() { print('bar2 function'); }");
|
||||
} catch (final Exception exp) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
foo2 = ((Invocable)engine).getInterface(Foo2.class);
|
||||
foo2.bar();
|
||||
foo2.bar2();
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Try passing non-interface Class object for interface implementation.
|
||||
*/
|
||||
public void getNonInterfaceGetInterfaceTest() {
|
||||
final ScriptEngineManager manager = new ScriptEngineManager();
|
||||
final ScriptEngine engine = manager.getEngineByName("nashorn");
|
||||
try {
|
||||
log(Objects.toString(((Invocable)engine).getInterface(Object.class)));
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (final Exception exp) {
|
||||
if (! (exp instanceof IllegalArgumentException)) {
|
||||
fail("IllegalArgumentException expected, got " + exp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Check that we can get interface out of a script object even after
|
||||
* switching to use different ScriptContext.
|
||||
*/
|
||||
public void getInterfaceDifferentContext() {
|
||||
ScriptEngineManager m = new ScriptEngineManager();
|
||||
ScriptEngine e = m.getEngineByName("nashorn");
|
||||
try {
|
||||
Object obj = e.eval("({ run: function() { } })");
|
||||
|
||||
// change script context
|
||||
ScriptContext ctxt = new SimpleScriptContext();
|
||||
ctxt.setBindings(e.createBindings(), ScriptContext.ENGINE_SCOPE);
|
||||
e.setContext(ctxt);
|
||||
|
||||
Runnable r = ((Invocable)e).getInterface(obj, Runnable.class);
|
||||
r.run();
|
||||
}catch (final Exception exp) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Check that getInterface on non-script object 'thiz' results in IllegalArgumentException.
|
||||
*/
|
||||
public void getInterfaceNonScriptObjectThizTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
|
||||
try {
|
||||
((Invocable)e).getInterface(new Object(), Runnable.class);
|
||||
fail("should have thrown IllegalArgumentException");
|
||||
} catch (final Exception exp) {
|
||||
if (! (exp instanceof IllegalArgumentException)) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Check that getInterface on null 'thiz' results in IllegalArgumentException.
|
||||
*/
|
||||
public void getInterfaceNullThizTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
|
||||
try {
|
||||
((Invocable)e).getInterface(null, Runnable.class);
|
||||
fail("should have thrown IllegalArgumentException");
|
||||
} catch (final Exception exp) {
|
||||
if (! (exp instanceof IllegalArgumentException)) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Check that calling getInterface on mirror created by another engine results in IllegalArgumentException.
|
||||
*/
|
||||
public void getInterfaceMixEnginesTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine engine1 = m.getEngineByName("nashorn");
|
||||
final ScriptEngine engine2 = m.getEngineByName("nashorn");
|
||||
|
||||
try {
|
||||
Object obj = engine1.eval("({ run: function() {} })");
|
||||
// pass object from engine1 to engine2 as 'thiz' for getInterface
|
||||
((Invocable)engine2).getInterface(obj, Runnable.class);
|
||||
fail("should have thrown IllegalArgumentException");
|
||||
} catch (final Exception exp) {
|
||||
if (! (exp instanceof IllegalArgumentException)) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessGlobalTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
@ -617,90 +401,7 @@ public class ScriptEngineTest {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
// dos2unix - fix line endings if running on windows
|
||||
assertEquals(sw.toString().replaceAll("\r", ""), "hello world\n");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void reflectionTest() throws ScriptException {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
|
||||
e.eval("var obj = { x: 344, y: 'nashorn' }");
|
||||
|
||||
int count = 0;
|
||||
Map<Object, Object> map = (Map<Object, Object>)e.get("obj");
|
||||
assertFalse(map.isEmpty());
|
||||
assertTrue(map.keySet().contains("x"));
|
||||
assertTrue(map.containsKey("x"));
|
||||
assertTrue(map.values().contains("nashorn"));
|
||||
assertTrue(map.containsValue("nashorn"));
|
||||
for (final Map.Entry<?, ?> ex : map.entrySet()) {
|
||||
final Object key = ex.getKey();
|
||||
if (key.equals("x")) {
|
||||
assertTrue(344 == ((Number)ex.getValue()).doubleValue());
|
||||
count++;
|
||||
} else if (key.equals("y")) {
|
||||
assertEquals(ex.getValue(), "nashorn");
|
||||
count++;
|
||||
}
|
||||
}
|
||||
assertEquals(2, count);
|
||||
assertEquals(2, map.size());
|
||||
|
||||
// add property
|
||||
map.put("z", "hello");
|
||||
assertEquals(e.eval("obj.z"), "hello");
|
||||
assertEquals(map.get("z"), "hello");
|
||||
assertTrue(map.keySet().contains("z"));
|
||||
assertTrue(map.containsKey("z"));
|
||||
assertTrue(map.values().contains("hello"));
|
||||
assertTrue(map.containsValue("hello"));
|
||||
assertEquals(map.size(), 3);
|
||||
|
||||
final Map<Object, Object> newMap = new HashMap<>();
|
||||
newMap.put("foo", 23.0);
|
||||
newMap.put("bar", true);
|
||||
map.putAll(newMap);
|
||||
|
||||
assertEquals(e.eval("obj.foo"), 23.0);
|
||||
assertEquals(e.eval("obj.bar"), true);
|
||||
|
||||
// remove using map method
|
||||
map.remove("foo");
|
||||
assertEquals(e.eval("typeof obj.foo"), "undefined");
|
||||
|
||||
count = 0;
|
||||
e.eval("var arr = [ true, 'hello' ]");
|
||||
map = (Map<Object, Object>)e.get("arr");
|
||||
assertFalse(map.isEmpty());
|
||||
assertTrue(map.containsKey("length"));
|
||||
assertTrue(map.containsValue("hello"));
|
||||
for (final Map.Entry<?, ?> ex : map.entrySet()) {
|
||||
final Object key = ex.getKey();
|
||||
if (key.equals("0")) {
|
||||
assertEquals(ex.getValue(), Boolean.TRUE);
|
||||
count++;
|
||||
} else if (key.equals("1")) {
|
||||
assertEquals(ex.getValue(), "hello");
|
||||
count++;
|
||||
}
|
||||
}
|
||||
assertEquals(count, 2);
|
||||
assertEquals(map.size(), 2);
|
||||
|
||||
// add element
|
||||
map.put("2", "world");
|
||||
assertEquals(map.get("2"), "world");
|
||||
assertEquals(map.size(), 3);
|
||||
|
||||
// remove all
|
||||
map.clear();
|
||||
assertTrue(map.isEmpty());
|
||||
assertEquals(e.eval("typeof arr[0]"), "undefined");
|
||||
assertEquals(e.eval("typeof arr[1]"), "undefined");
|
||||
assertEquals(e.eval("typeof arr[2]"), "undefined");
|
||||
assertEquals(sw.toString(), println("hello world"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -715,150 +416,6 @@ public class ScriptEngineTest {
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invokeMethodTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
|
||||
try {
|
||||
e.eval("var Example = function() { this.hello = function() { return 'Hello World!'; };}; myExample = new Example();");
|
||||
final Object obj = e.get("myExample");
|
||||
final Object res = ((Invocable)e).invokeMethod(obj, "hello");
|
||||
assertEquals(res, "Hello World!");
|
||||
} catch (final Exception exp) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Check that we can call invokeMethod on an object that we got by evaluating
|
||||
* script with different Context set.
|
||||
*/
|
||||
public void invokeMethodDifferentContextTest() {
|
||||
ScriptEngineManager m = new ScriptEngineManager();
|
||||
ScriptEngine e = m.getEngineByName("nashorn");
|
||||
|
||||
try {
|
||||
// define an object with method on it
|
||||
Object obj = e.eval("({ hello: function() { return 'Hello World!'; } })");
|
||||
|
||||
final ScriptContext ctxt = new SimpleScriptContext();
|
||||
ctxt.setBindings(e.createBindings(), ScriptContext.ENGINE_SCOPE);
|
||||
e.setContext(ctxt);
|
||||
|
||||
// invoke 'func' on obj - but with current script context changed
|
||||
final Object res = ((Invocable)e).invokeMethod(obj, "hello");
|
||||
assertEquals(res, "Hello World!");
|
||||
} catch (final Exception exp) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Check that invokeMethod throws NPE on null method name.
|
||||
*/
|
||||
public void invokeMethodNullNameTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
|
||||
try {
|
||||
final Object obj = e.eval("({})");
|
||||
final Object res = ((Invocable)e).invokeMethod(obj, null);
|
||||
fail("should have thrown NPE");
|
||||
} catch (final Exception exp) {
|
||||
if (! (exp instanceof NullPointerException)) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Check that invokeMethod throws NoSuchMethodException on missing method.
|
||||
*/
|
||||
public void invokeMethodMissingTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
|
||||
try {
|
||||
final Object obj = e.eval("({})");
|
||||
final Object res = ((Invocable)e).invokeMethod(obj, "nonExistentMethod");
|
||||
fail("should have thrown NoSuchMethodException");
|
||||
} catch (final Exception exp) {
|
||||
if (! (exp instanceof NoSuchMethodException)) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Check that calling method on non-script object 'thiz' results in IllegalArgumentException.
|
||||
*/
|
||||
public void invokeMethodNonScriptObjectThizTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
|
||||
try {
|
||||
((Invocable)e).invokeMethod(new Object(), "toString");
|
||||
fail("should have thrown IllegalArgumentException");
|
||||
} catch (final Exception exp) {
|
||||
if (! (exp instanceof IllegalArgumentException)) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Check that calling method on null 'thiz' results in IllegalArgumentException.
|
||||
*/
|
||||
public void invokeMethodNullThizTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
|
||||
try {
|
||||
((Invocable)e).invokeMethod(null, "toString");
|
||||
fail("should have thrown IllegalArgumentException");
|
||||
} catch (final Exception exp) {
|
||||
if (! (exp instanceof IllegalArgumentException)) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Check that calling method on mirror created by another engine results in IllegalArgumentException.
|
||||
*/
|
||||
public void invokeMethodMixEnginesTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine engine1 = m.getEngineByName("nashorn");
|
||||
final ScriptEngine engine2 = m.getEngineByName("nashorn");
|
||||
|
||||
try {
|
||||
Object obj = engine1.eval("({ run: function() {} })");
|
||||
// pass object from engine1 to engine2 as 'thiz' for invokeMethod
|
||||
((Invocable)engine2).invokeMethod(obj, "run");
|
||||
fail("should have thrown IllegalArgumentException");
|
||||
} catch (final Exception exp) {
|
||||
if (! (exp instanceof IllegalArgumentException)) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noEnumerablePropertiesTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
@ -919,308 +476,6 @@ public class ScriptEngineTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jsobjectTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
try {
|
||||
e.eval("var obj = { '1': 'world', func: function() { return this.bar; }, bar: 'hello' }");
|
||||
JSObject obj = (JSObject) e.get("obj");
|
||||
|
||||
// try basic get on existing properties
|
||||
if (! obj.getMember("bar").equals("hello")) {
|
||||
fail("obj.bar != 'hello'");
|
||||
}
|
||||
|
||||
if (! obj.getSlot(1).equals("world")) {
|
||||
fail("obj[1] != 'world'");
|
||||
}
|
||||
|
||||
if (! obj.call("func", new Object[0]).equals("hello")) {
|
||||
fail("obj.call('func') != 'hello'");
|
||||
}
|
||||
|
||||
// try setting properties
|
||||
obj.setMember("bar", "new-bar");
|
||||
obj.setSlot(1, "new-element-1");
|
||||
if (! obj.getMember("bar").equals("new-bar")) {
|
||||
fail("obj.bar != 'new-bar'");
|
||||
}
|
||||
|
||||
if (! obj.getSlot(1).equals("new-element-1")) {
|
||||
fail("obj[1] != 'new-element-1'");
|
||||
}
|
||||
|
||||
// try adding properties
|
||||
obj.setMember("prop", "prop-value");
|
||||
obj.setSlot(12, "element-12");
|
||||
if (! obj.getMember("prop").equals("prop-value")) {
|
||||
fail("obj.prop != 'prop-value'");
|
||||
}
|
||||
|
||||
if (! obj.getSlot(12).equals("element-12")) {
|
||||
fail("obj[12] != 'element-12'");
|
||||
}
|
||||
|
||||
// delete properties
|
||||
obj.removeMember("prop");
|
||||
if ("prop-value".equals(obj.getMember("prop"))) {
|
||||
fail("obj.prop is not deleted!");
|
||||
}
|
||||
|
||||
// Simple eval tests
|
||||
assertEquals(obj.eval("typeof Object"), "function");
|
||||
assertEquals(obj.eval("'nashorn'.substring(3)"), "horn");
|
||||
} catch (final Exception exp) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* check that null function name results in NPE.
|
||||
*/
|
||||
public void invokeFunctionNullNameTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
|
||||
try {
|
||||
final Object res = ((Invocable)e).invokeFunction(null);
|
||||
fail("should have thrown NPE");
|
||||
} catch (final Exception exp) {
|
||||
if (! (exp instanceof NullPointerException)) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Check that attempt to call missing function results in NoSuchMethodException.
|
||||
*/
|
||||
public void invokeFunctionMissingTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
|
||||
try {
|
||||
final Object res = ((Invocable)e).invokeFunction("NonExistentFunc");
|
||||
fail("should have thrown NoSuchMethodException");
|
||||
} catch (final Exception exp) {
|
||||
if (! (exp instanceof NoSuchMethodException)) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Check that invokeFunction calls functions only from current context's Bindings.
|
||||
*/
|
||||
public void invokeFunctionDifferentContextTest() {
|
||||
ScriptEngineManager m = new ScriptEngineManager();
|
||||
ScriptEngine e = m.getEngineByName("nashorn");
|
||||
|
||||
try {
|
||||
// define an object with method on it
|
||||
Object obj = e.eval("function hello() { return 'Hello World!'; }");
|
||||
final ScriptContext ctxt = new SimpleScriptContext();
|
||||
ctxt.setBindings(e.createBindings(), ScriptContext.ENGINE_SCOPE);
|
||||
// change engine's current context
|
||||
e.setContext(ctxt);
|
||||
|
||||
((Invocable)e).invokeFunction("hello"); // no 'hello' in new context!
|
||||
fail("should have thrown NoSuchMethodException");
|
||||
} catch (final Exception exp) {
|
||||
if (! (exp instanceof NoSuchMethodException)) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invokeFunctionExceptionTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
try {
|
||||
e.eval("function func() { throw new TypeError(); }");
|
||||
} catch (final Throwable t) {
|
||||
t.printStackTrace();
|
||||
fail(t.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
((Invocable)e).invokeFunction("func");
|
||||
fail("should have thrown exception");
|
||||
} catch (final ScriptException se) {
|
||||
// ECMA TypeError property wrapped as a ScriptException
|
||||
log("got " + se + " as expected");
|
||||
} catch (final Throwable t) {
|
||||
t.printStackTrace();
|
||||
fail(t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invokeMethodExceptionTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
try {
|
||||
e.eval("var sobj = {}; sobj.foo = function func() { throw new TypeError(); }");
|
||||
} catch (final Throwable t) {
|
||||
t.printStackTrace();
|
||||
fail(t.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
final Object sobj = e.get("sobj");
|
||||
((Invocable)e).invokeMethod(sobj, "foo");
|
||||
fail("should have thrown exception");
|
||||
} catch (final ScriptException se) {
|
||||
// ECMA TypeError property wrapped as a ScriptException
|
||||
log("got " + se + " as expected");
|
||||
} catch (final Throwable t) {
|
||||
t.printStackTrace();
|
||||
fail(t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void scriptObjectMirrorToStringTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
try {
|
||||
Object obj = e.eval("new TypeError('wrong type')");
|
||||
assertEquals(obj.toString(), "TypeError: wrong type", "toString returns wrong value");
|
||||
} catch (final Throwable t) {
|
||||
t.printStackTrace();
|
||||
fail(t.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
Object obj = e.eval("function func() { print('hello'); }");
|
||||
assertEquals(obj.toString(), "function func() { print('hello'); }", "toString returns wrong value");
|
||||
} catch (final Throwable t) {
|
||||
t.printStackTrace();
|
||||
fail(t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void engineScopeTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
Bindings engineScope = e.getBindings(ScriptContext.ENGINE_SCOPE);
|
||||
|
||||
// check few ECMA standard built-in global properties
|
||||
assertNotNull(engineScope.get("Object"));
|
||||
assertNotNull(engineScope.get("TypeError"));
|
||||
assertNotNull(engineScope.get("eval"));
|
||||
|
||||
// can access via ScriptEngine.get as well
|
||||
assertNotNull(e.get("Object"));
|
||||
assertNotNull(e.get("TypeError"));
|
||||
assertNotNull(e.get("eval"));
|
||||
|
||||
// Access by either way should return same object
|
||||
assertEquals(engineScope.get("Array"), e.get("Array"));
|
||||
assertEquals(engineScope.get("EvalError"), e.get("EvalError"));
|
||||
assertEquals(engineScope.get("undefined"), e.get("undefined"));
|
||||
|
||||
// try exposing a new variable from scope
|
||||
engineScope.put("myVar", "foo");
|
||||
try {
|
||||
assertEquals(e.eval("myVar"), "foo");
|
||||
} catch (final ScriptException se) {
|
||||
se.printStackTrace();
|
||||
fail(se.getMessage());
|
||||
}
|
||||
|
||||
// update "myVar" in script an check the value from scope
|
||||
try {
|
||||
e.eval("myVar = 'nashorn';");
|
||||
} catch (final ScriptException se) {
|
||||
se.printStackTrace();
|
||||
fail(se.getMessage());
|
||||
}
|
||||
|
||||
// now check modified value from scope and engine
|
||||
assertEquals(engineScope.get("myVar"), "nashorn");
|
||||
assertEquals(e.get("myVar"), "nashorn");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiGlobalTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
final Bindings b = e.createBindings();
|
||||
final ScriptContext newCtxt = new SimpleScriptContext();
|
||||
newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
|
||||
|
||||
try {
|
||||
Object obj1 = e.eval("Object");
|
||||
Object obj2 = e.eval("Object", newCtxt);
|
||||
Assert.assertNotEquals(obj1, obj2);
|
||||
Assert.assertNotNull(obj1);
|
||||
Assert.assertNotNull(obj2);
|
||||
Assert.assertEquals(obj1.toString(), obj2.toString());
|
||||
|
||||
e.eval("x = 'hello'");
|
||||
e.eval("x = 'world'", newCtxt);
|
||||
Object x1 = e.getContext().getAttribute("x");
|
||||
Object x2 = newCtxt.getAttribute("x");
|
||||
Assert.assertNotEquals(x1, x2);
|
||||
Assert.assertEquals(x1, "hello");
|
||||
Assert.assertEquals(x2, "world");
|
||||
|
||||
x1 = e.eval("x");
|
||||
x2 = e.eval("x", newCtxt);
|
||||
Assert.assertNotEquals(x1, x2);
|
||||
Assert.assertEquals(x1, "hello");
|
||||
Assert.assertEquals(x2, "world");
|
||||
|
||||
final ScriptContext origCtxt = e.getContext();
|
||||
e.setContext(newCtxt);
|
||||
e.eval("y = new Object()");
|
||||
e.eval("y = new Object()", origCtxt);
|
||||
|
||||
Object y1 = origCtxt.getAttribute("y");
|
||||
Object y2 = newCtxt.getAttribute("y");
|
||||
Assert.assertNotEquals(y1, y2);
|
||||
Assert.assertNotEquals(e.eval("y"), e.eval("y", origCtxt));
|
||||
Assert.assertEquals("[object Object]", y1.toString());
|
||||
Assert.assertEquals("[object Object]", y2.toString());
|
||||
} catch (final ScriptException se) {
|
||||
se.printStackTrace();
|
||||
fail(se.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Tests whether invocation of a JavaScript method through a variable arity Java method will pass the vararg array.
|
||||
* Both non-vararg and vararg JavaScript methods are tested.
|
||||
* @throws ScriptException
|
||||
*/
|
||||
public void variableArityInterfaceTest() throws ScriptException {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
e.eval(
|
||||
"function test1(i, strings) {" +
|
||||
" return 'i == ' + i + ', strings instanceof java.lang.String[] == ' + (strings instanceof Java.type('java.lang.String[]')) + ', strings == ' + java.util.Arrays.toString(strings)" +
|
||||
"}" +
|
||||
"function test2() {" +
|
||||
" return 'arguments[0] == ' + arguments[0] + ', arguments[1] instanceof java.lang.String[] == ' + (arguments[1] instanceof Java.type('java.lang.String[]')) + ', arguments[1] == ' + java.util.Arrays.toString(arguments[1])" +
|
||||
"}"
|
||||
);
|
||||
final VariableArityTestInterface itf = ((Invocable)e).getInterface(VariableArityTestInterface.class);
|
||||
Assert.assertEquals(itf.test1(42, "a", "b"), "i == 42, strings instanceof java.lang.String[] == true, strings == [a, b]");
|
||||
Assert.assertEquals(itf.test2(44, "c", "d", "e"), "arguments[0] == 44, arguments[1] instanceof java.lang.String[] == true, arguments[1] == [c, d, e]");
|
||||
}
|
||||
|
||||
@Test
|
||||
// check that print function prints arg followed by newline char
|
||||
public void printTest() {
|
||||
@ -1235,8 +490,7 @@ public class ScriptEngineTest {
|
||||
fail(t.getMessage());
|
||||
}
|
||||
|
||||
// dos2unix - fix line endings if running on windows
|
||||
assertEquals(sw.toString().replaceAll("\r", ""), "hello\n");
|
||||
assertEquals(sw.toString(), println("hello"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -1253,7 +507,14 @@ public class ScriptEngineTest {
|
||||
fail(t.getMessage());
|
||||
}
|
||||
|
||||
// dos2unix - fix line endings if running on windows
|
||||
assertEquals(sw.toString().replaceAll("\r", ""), "34 true hello\n");
|
||||
assertEquals(sw.toString(), println("34 true hello"));
|
||||
}
|
||||
|
||||
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
|
||||
|
||||
// Returns String that would be the result of calling PrintWriter.println
|
||||
// of the given String. (This is to handle platform specific newline).
|
||||
private static String println(final String str) {
|
||||
return str + LINE_SEPARATOR;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.nashorn.api.scripting;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
import static org.testng.Assert.fail;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Tests to check jdk.nashorn.api.scripting.ScriptObjectMirror API.
|
||||
*/
|
||||
public class ScriptObjectMirrorTest {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void reflectionTest() throws ScriptException {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
|
||||
e.eval("var obj = { x: 344, y: 'nashorn' }");
|
||||
|
||||
int count = 0;
|
||||
Map<Object, Object> map = (Map<Object, Object>) e.get("obj");
|
||||
assertFalse(map.isEmpty());
|
||||
assertTrue(map.keySet().contains("x"));
|
||||
assertTrue(map.containsKey("x"));
|
||||
assertTrue(map.values().contains("nashorn"));
|
||||
assertTrue(map.containsValue("nashorn"));
|
||||
for (final Map.Entry<?, ?> ex : map.entrySet()) {
|
||||
final Object key = ex.getKey();
|
||||
if (key.equals("x")) {
|
||||
assertTrue(344 == ((Number) ex.getValue()).doubleValue());
|
||||
count++;
|
||||
} else if (key.equals("y")) {
|
||||
assertEquals(ex.getValue(), "nashorn");
|
||||
count++;
|
||||
}
|
||||
}
|
||||
assertEquals(2, count);
|
||||
assertEquals(2, map.size());
|
||||
|
||||
// add property
|
||||
map.put("z", "hello");
|
||||
assertEquals(e.eval("obj.z"), "hello");
|
||||
assertEquals(map.get("z"), "hello");
|
||||
assertTrue(map.keySet().contains("z"));
|
||||
assertTrue(map.containsKey("z"));
|
||||
assertTrue(map.values().contains("hello"));
|
||||
assertTrue(map.containsValue("hello"));
|
||||
assertEquals(map.size(), 3);
|
||||
|
||||
final Map<Object, Object> newMap = new HashMap<>();
|
||||
newMap.put("foo", 23.0);
|
||||
newMap.put("bar", true);
|
||||
map.putAll(newMap);
|
||||
|
||||
assertEquals(e.eval("obj.foo"), 23.0);
|
||||
assertEquals(e.eval("obj.bar"), true);
|
||||
|
||||
// remove using map method
|
||||
map.remove("foo");
|
||||
assertEquals(e.eval("typeof obj.foo"), "undefined");
|
||||
|
||||
count = 0;
|
||||
e.eval("var arr = [ true, 'hello' ]");
|
||||
map = (Map<Object, Object>) e.get("arr");
|
||||
assertFalse(map.isEmpty());
|
||||
assertTrue(map.containsKey("length"));
|
||||
assertTrue(map.containsValue("hello"));
|
||||
for (final Map.Entry<?, ?> ex : map.entrySet()) {
|
||||
final Object key = ex.getKey();
|
||||
if (key.equals("0")) {
|
||||
assertEquals(ex.getValue(), Boolean.TRUE);
|
||||
count++;
|
||||
} else if (key.equals("1")) {
|
||||
assertEquals(ex.getValue(), "hello");
|
||||
count++;
|
||||
}
|
||||
}
|
||||
assertEquals(count, 2);
|
||||
assertEquals(map.size(), 2);
|
||||
|
||||
// add element
|
||||
map.put("2", "world");
|
||||
assertEquals(map.get("2"), "world");
|
||||
assertEquals(map.size(), 3);
|
||||
|
||||
// remove all
|
||||
map.clear();
|
||||
assertTrue(map.isEmpty());
|
||||
assertEquals(e.eval("typeof arr[0]"), "undefined");
|
||||
assertEquals(e.eval("typeof arr[1]"), "undefined");
|
||||
assertEquals(e.eval("typeof arr[2]"), "undefined");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jsobjectTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
try {
|
||||
e.eval("var obj = { '1': 'world', func: function() { return this.bar; }, bar: 'hello' }");
|
||||
JSObject obj = (JSObject) e.get("obj");
|
||||
|
||||
// try basic get on existing properties
|
||||
if (!obj.getMember("bar").equals("hello")) {
|
||||
fail("obj.bar != 'hello'");
|
||||
}
|
||||
|
||||
if (!obj.getSlot(1).equals("world")) {
|
||||
fail("obj[1] != 'world'");
|
||||
}
|
||||
|
||||
if (!obj.call("func", new Object[0]).equals("hello")) {
|
||||
fail("obj.call('func') != 'hello'");
|
||||
}
|
||||
|
||||
// try setting properties
|
||||
obj.setMember("bar", "new-bar");
|
||||
obj.setSlot(1, "new-element-1");
|
||||
if (!obj.getMember("bar").equals("new-bar")) {
|
||||
fail("obj.bar != 'new-bar'");
|
||||
}
|
||||
|
||||
if (!obj.getSlot(1).equals("new-element-1")) {
|
||||
fail("obj[1] != 'new-element-1'");
|
||||
}
|
||||
|
||||
// try adding properties
|
||||
obj.setMember("prop", "prop-value");
|
||||
obj.setSlot(12, "element-12");
|
||||
if (!obj.getMember("prop").equals("prop-value")) {
|
||||
fail("obj.prop != 'prop-value'");
|
||||
}
|
||||
|
||||
if (!obj.getSlot(12).equals("element-12")) {
|
||||
fail("obj[12] != 'element-12'");
|
||||
}
|
||||
|
||||
// delete properties
|
||||
obj.removeMember("prop");
|
||||
if ("prop-value".equals(obj.getMember("prop"))) {
|
||||
fail("obj.prop is not deleted!");
|
||||
}
|
||||
|
||||
// Simple eval tests
|
||||
assertEquals(obj.eval("typeof Object"), "function");
|
||||
assertEquals(obj.eval("'nashorn'.substring(3)"), "horn");
|
||||
} catch (final Exception exp) {
|
||||
exp.printStackTrace();
|
||||
fail(exp.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void scriptObjectMirrorToStringTest() {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
try {
|
||||
Object obj = e.eval("new TypeError('wrong type')");
|
||||
assertEquals(obj.toString(), "TypeError: wrong type", "toString returns wrong value");
|
||||
} catch (final Throwable t) {
|
||||
t.printStackTrace();
|
||||
fail(t.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
Object obj = e.eval("function func() { print('hello'); }");
|
||||
assertEquals(obj.toString(), "function func() { print('hello'); }", "toString returns wrong value");
|
||||
} catch (final Throwable t) {
|
||||
t.printStackTrace();
|
||||
fail(t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mirrorNewObjectGlobalFunctionTest() throws ScriptException {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
final ScriptEngine e2 = m.getEngineByName("nashorn");
|
||||
|
||||
e.eval("function func() {}");
|
||||
e2.put("foo", e.get("func"));
|
||||
final Object e2global = e2.eval("this");
|
||||
final Object newObj = ((ScriptObjectMirror) e2global).newObject("foo");
|
||||
assertTrue(newObj instanceof ScriptObjectMirror);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mirrorNewObjectInstanceFunctionTest() throws ScriptException {
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
final ScriptEngine e2 = m.getEngineByName("nashorn");
|
||||
|
||||
e.eval("function func() {}");
|
||||
e2.put("func", e.get("func"));
|
||||
final Object e2obj = e2.eval("({ foo: func })");
|
||||
final Object newObj = ((ScriptObjectMirror) e2obj).newObject("foo");
|
||||
assertTrue(newObj instanceof ScriptObjectMirror);
|
||||
}
|
||||
}
|
@ -32,7 +32,10 @@ import static org.testng.Assert.fail;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineFactory;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptContext;
|
||||
import javax.script.ScriptException;
|
||||
import javax.script.SimpleBindings;
|
||||
import javax.script.SimpleScriptContext;
|
||||
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
@ -196,4 +199,25 @@ public class TrustedScriptEngineTest {
|
||||
}
|
||||
fail("Cannot find nashorn factory!");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void globalPerEngineTest() throws ScriptException {
|
||||
final NashornScriptEngineFactory fac = new NashornScriptEngineFactory();
|
||||
final String[] options = new String[] { "--global-per-engine" };
|
||||
final ScriptEngine e = fac.getScriptEngine(options);
|
||||
|
||||
e.eval("function foo() {}");
|
||||
|
||||
final ScriptContext newCtx = new SimpleScriptContext();
|
||||
newCtx.setBindings(e.createBindings(), ScriptContext.ENGINE_SCOPE);
|
||||
|
||||
// all global definitions shared and so 'foo' should be
|
||||
// visible in new Bindings as well.
|
||||
assertTrue(e.eval("typeof foo", newCtx).equals("function"));
|
||||
|
||||
e.eval("function bar() {}", newCtx);
|
||||
|
||||
// bar should be visible in default context
|
||||
assertTrue(e.eval("typeof bar").equals("function"));
|
||||
}
|
||||
}
|
||||
|
@ -32,13 +32,9 @@ import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javafx.application.Application;
|
||||
import javafx.stage.Stage;
|
||||
import javax.script.Invocable;
|
||||
import javax.script.ScriptContext;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineFactory;
|
||||
import javax.script.ScriptEngineManager;
|
||||
@ -180,6 +176,7 @@ public class FXShell extends Application {
|
||||
*
|
||||
* @return Last evaluation result (discarded.)
|
||||
*/
|
||||
@SuppressWarnings("resource")
|
||||
private Object load(String path) {
|
||||
try {
|
||||
FileInputStream file = new FileInputStream(path);
|
||||
|
Loading…
x
Reference in New Issue
Block a user