This commit is contained in:
Lana Steuck 2013-08-29 16:34:31 -07:00
commit acaf7ca35c
100 changed files with 4061 additions and 1112 deletions
nashorn
buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen
docs
src/jdk
test
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>() {

@ -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));
}
}

@ -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());

@ -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)
}

@ -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

@ -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);

@ -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

@ -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);

@ -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

@ -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"))

@ -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

@ -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();
}

@ -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");

@ -0,0 +1,2 @@
func: hello
func: world

@ -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"))

@ -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

@ -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();
}

@ -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"))

@ -0,0 +1,4 @@
true
true
true
true

@ -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)));

@ -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'");
}

@ -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);
}

@ -0,0 +1 @@
TypeError: Cannot create__proto__ cycle for [object Object]

@ -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

@ -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]

@ -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]");
}
}

@ -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);