aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--buildtools/nasgen/build.xml3
-rw-r--r--buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java89
-rw-r--r--buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java18
-rw-r--r--buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java5
-rw-r--r--buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java19
-rw-r--r--buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java14
-rw-r--r--buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java96
-rw-r--r--docs/JavaScriptingProgrammersGuide.html9
-rw-r--r--make/build-nasgen.xml7
-rw-r--r--make/build.xml72
-rw-r--r--make/code_coverage.xml8
-rw-r--r--make/project.properties3
-rw-r--r--makefiles/BuildNashorn.gmk6
-rw-r--r--src/jdk/internal/dynalink/DynamicLinker.java47
-rw-r--r--src/jdk/internal/dynalink/beans/AbstractJavaLinker.java248
-rw-r--r--src/jdk/internal/dynalink/beans/ApplicableOverloadedMethods.java27
-rw-r--r--src/jdk/internal/dynalink/beans/BeansLinker.java68
-rw-r--r--src/jdk/internal/dynalink/beans/CallerSensitiveDetector.java148
-rw-r--r--src/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java158
-rw-r--r--src/jdk/internal/dynalink/beans/ClassString.java4
-rw-r--r--src/jdk/internal/dynalink/beans/DynamicMethod.java38
-rw-r--r--src/jdk/internal/dynalink/beans/DynamicMethodLinker.java13
-rw-r--r--src/jdk/internal/dynalink/beans/FacetIntrospector.java4
-rw-r--r--src/jdk/internal/dynalink/beans/MaximallySpecific.java68
-rw-r--r--src/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java92
-rw-r--r--src/jdk/internal/dynalink/beans/OverloadedMethod.java4
-rw-r--r--src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java136
-rw-r--r--src/jdk/internal/dynalink/beans/SingleDynamicMethod.java255
-rw-r--r--src/jdk/internal/dynalink/beans/StaticClassIntrospector.java10
-rw-r--r--src/jdk/internal/dynalink/beans/StaticClassLinker.java42
-rw-r--r--src/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java3
-rw-r--r--src/jdk/internal/dynalink/support/Lookup.java25
-rw-r--r--src/jdk/nashorn/api/scripting/NashornException.java4
-rw-r--r--src/jdk/nashorn/api/scripting/NashornScriptEngine.java15
-rw-r--r--src/jdk/nashorn/api/scripting/ScriptObjectMirror.java101
-rw-r--r--src/jdk/nashorn/internal/codegen/Attr.java173
-rw-r--r--src/jdk/nashorn/internal/codegen/BranchOptimizer.java14
-rw-r--r--src/jdk/nashorn/internal/codegen/CodeGenerator.java489
-rw-r--r--src/jdk/nashorn/internal/codegen/CompilationPhase.java34
-rw-r--r--src/jdk/nashorn/internal/codegen/Compiler.java7
-rw-r--r--src/jdk/nashorn/internal/codegen/CompilerConstants.java4
-rw-r--r--src/jdk/nashorn/internal/codegen/FieldObjectCreator.java69
-rw-r--r--src/jdk/nashorn/internal/codegen/FinalizeTypes.java98
-rw-r--r--src/jdk/nashorn/internal/codegen/FoldConstants.java8
-rw-r--r--src/jdk/nashorn/internal/codegen/FunctionSignature.java8
-rw-r--r--src/jdk/nashorn/internal/codegen/Lower.java93
-rw-r--r--src/jdk/nashorn/internal/codegen/MapCreator.java38
-rw-r--r--src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java19
-rw-r--r--src/jdk/nashorn/internal/codegen/ObjectCreator.java74
-rw-r--r--src/jdk/nashorn/internal/codegen/RangeAnalyzer.java11
-rw-r--r--src/jdk/nashorn/internal/codegen/SpillObjectCreator.java133
-rw-r--r--src/jdk/nashorn/internal/codegen/Splitter.java6
-rw-r--r--src/jdk/nashorn/internal/codegen/WeighNodes.java7
-rw-r--r--src/jdk/nashorn/internal/codegen/types/Type.java66
-rw-r--r--src/jdk/nashorn/internal/ir/AccessNode.java8
-rw-r--r--src/jdk/nashorn/internal/ir/Assignment.java4
-rw-r--r--src/jdk/nashorn/internal/ir/BaseNode.java11
-rw-r--r--src/jdk/nashorn/internal/ir/BinaryNode.java26
-rw-r--r--src/jdk/nashorn/internal/ir/Block.java36
-rw-r--r--src/jdk/nashorn/internal/ir/BlockLexicalContext.java19
-rw-r--r--src/jdk/nashorn/internal/ir/BlockStatement.java115
-rw-r--r--src/jdk/nashorn/internal/ir/BreakableNode.java47
-rw-r--r--src/jdk/nashorn/internal/ir/BreakableStatement.java91
-rw-r--r--src/jdk/nashorn/internal/ir/CallNode.java59
-rw-r--r--src/jdk/nashorn/internal/ir/CaseNode.java12
-rw-r--r--src/jdk/nashorn/internal/ir/CatchNode.java12
-rw-r--r--src/jdk/nashorn/internal/ir/Expression.java99
-rw-r--r--src/jdk/nashorn/internal/ir/ExpressionStatement.java (renamed from src/jdk/nashorn/internal/ir/ExecuteNode.java)20
-rw-r--r--src/jdk/nashorn/internal/ir/ForNode.java28
-rw-r--r--src/jdk/nashorn/internal/ir/FunctionNode.java55
-rw-r--r--src/jdk/nashorn/internal/ir/IdentNode.java3
-rw-r--r--src/jdk/nashorn/internal/ir/IfNode.java12
-rw-r--r--src/jdk/nashorn/internal/ir/IndexNode.java16
-rw-r--r--src/jdk/nashorn/internal/ir/LabelNode.java2
-rw-r--r--src/jdk/nashorn/internal/ir/LexicalContext.java37
-rw-r--r--src/jdk/nashorn/internal/ir/LexicalContextExpression.java59
-rw-r--r--src/jdk/nashorn/internal/ir/LexicalContextNode.java53
-rw-r--r--src/jdk/nashorn/internal/ir/LexicalContextStatement.java55
-rw-r--r--src/jdk/nashorn/internal/ir/LiteralNode.java78
-rw-r--r--src/jdk/nashorn/internal/ir/LoopNode.java13
-rw-r--r--src/jdk/nashorn/internal/ir/Node.java55
-rw-r--r--src/jdk/nashorn/internal/ir/ObjectNode.java2
-rw-r--r--src/jdk/nashorn/internal/ir/PropertyNode.java16
-rw-r--r--src/jdk/nashorn/internal/ir/ReturnNode.java13
-rw-r--r--src/jdk/nashorn/internal/ir/RuntimeNode.java27
-rw-r--r--src/jdk/nashorn/internal/ir/SplitNode.java7
-rw-r--r--src/jdk/nashorn/internal/ir/SwitchNode.java15
-rw-r--r--src/jdk/nashorn/internal/ir/Symbol.java3
-rw-r--r--src/jdk/nashorn/internal/ir/TemporarySymbols.java2
-rw-r--r--src/jdk/nashorn/internal/ir/TernaryNode.java120
-rw-r--r--src/jdk/nashorn/internal/ir/ThrowNode.java12
-rw-r--r--src/jdk/nashorn/internal/ir/UnaryNode.java41
-rw-r--r--src/jdk/nashorn/internal/ir/VarNode.java22
-rw-r--r--src/jdk/nashorn/internal/ir/WhileNode.java12
-rw-r--r--src/jdk/nashorn/internal/ir/WithNode.java12
-rw-r--r--src/jdk/nashorn/internal/ir/debug/ASTWriter.java22
-rw-r--r--src/jdk/nashorn/internal/ir/debug/JSONWriter.java31
-rw-r--r--src/jdk/nashorn/internal/ir/debug/PrintVisitor.java28
-rw-r--r--src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java2
-rw-r--r--src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java39
-rw-r--r--src/jdk/nashorn/internal/lookup/Lookup.java40
-rw-r--r--src/jdk/nashorn/internal/objects/AccessorPropertyDescriptor.java8
-rw-r--r--src/jdk/nashorn/internal/objects/ArrayBufferView.java24
-rw-r--r--src/jdk/nashorn/internal/objects/BoundScriptFunctionImpl.java2
-rw-r--r--src/jdk/nashorn/internal/objects/DataPropertyDescriptor.java9
-rw-r--r--src/jdk/nashorn/internal/objects/GenericPropertyDescriptor.java8
-rw-r--r--src/jdk/nashorn/internal/objects/Global.java270
-rw-r--r--src/jdk/nashorn/internal/objects/NativeArguments.java36
-rw-r--r--src/jdk/nashorn/internal/objects/NativeArray.java59
-rw-r--r--src/jdk/nashorn/internal/objects/NativeArrayBuffer.java12
-rw-r--r--src/jdk/nashorn/internal/objects/NativeBoolean.java29
-rw-r--r--src/jdk/nashorn/internal/objects/NativeDate.java26
-rw-r--r--src/jdk/nashorn/internal/objects/NativeDebug.java22
-rw-r--r--src/jdk/nashorn/internal/objects/NativeError.java28
-rw-r--r--src/jdk/nashorn/internal/objects/NativeEvalError.java17
-rw-r--r--src/jdk/nashorn/internal/objects/NativeFloat32Array.java5
-rw-r--r--src/jdk/nashorn/internal/objects/NativeFloat64Array.java5
-rw-r--r--src/jdk/nashorn/internal/objects/NativeFunction.java3
-rw-r--r--src/jdk/nashorn/internal/objects/NativeInt16Array.java5
-rw-r--r--src/jdk/nashorn/internal/objects/NativeInt32Array.java5
-rw-r--r--src/jdk/nashorn/internal/objects/NativeInt8Array.java5
-rw-r--r--src/jdk/nashorn/internal/objects/NativeJSAdapter.java59
-rw-r--r--src/jdk/nashorn/internal/objects/NativeJSON.java6
-rw-r--r--src/jdk/nashorn/internal/objects/NativeJava.java49
-rw-r--r--src/jdk/nashorn/internal/objects/NativeJavaImporter.java16
-rw-r--r--src/jdk/nashorn/internal/objects/NativeMath.java6
-rw-r--r--src/jdk/nashorn/internal/objects/NativeNumber.java35
-rw-r--r--src/jdk/nashorn/internal/objects/NativeObject.java212
-rw-r--r--src/jdk/nashorn/internal/objects/NativeRangeError.java16
-rw-r--r--src/jdk/nashorn/internal/objects/NativeReferenceError.java16
-rw-r--r--src/jdk/nashorn/internal/objects/NativeRegExp.java34
-rw-r--r--src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java8
-rw-r--r--src/jdk/nashorn/internal/objects/NativeStrictArguments.java25
-rw-r--r--src/jdk/nashorn/internal/objects/NativeString.java33
-rw-r--r--src/jdk/nashorn/internal/objects/NativeSyntaxError.java12
-rw-r--r--src/jdk/nashorn/internal/objects/NativeTypeError.java12
-rw-r--r--src/jdk/nashorn/internal/objects/NativeURIError.java12
-rw-r--r--src/jdk/nashorn/internal/objects/NativeUint16Array.java5
-rw-r--r--src/jdk/nashorn/internal/objects/NativeUint32Array.java5
-rw-r--r--src/jdk/nashorn/internal/objects/NativeUint8Array.java5
-rw-r--r--src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java5
-rw-r--r--src/jdk/nashorn/internal/objects/PrototypeObject.java32
-rw-r--r--src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java103
-rw-r--r--src/jdk/nashorn/internal/parser/JSONParser.java13
-rw-r--r--src/jdk/nashorn/internal/parser/Lexer.java30
-rw-r--r--src/jdk/nashorn/internal/parser/Parser.java261
-rw-r--r--src/jdk/nashorn/internal/parser/TokenType.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/AccessorProperty.java102
-rw-r--r--src/jdk/nashorn/internal/runtime/CodeInstaller.java6
-rw-r--r--src/jdk/nashorn/internal/runtime/Context.java93
-rw-r--r--src/jdk/nashorn/internal/runtime/FunctionScope.java4
-rw-r--r--src/jdk/nashorn/internal/runtime/GlobalFunctions.java3
-rw-r--r--src/jdk/nashorn/internal/runtime/GlobalObject.java9
-rw-r--r--src/jdk/nashorn/internal/runtime/JSType.java10
-rw-r--r--src/jdk/nashorn/internal/runtime/ListAdapter.java25
-rw-r--r--src/jdk/nashorn/internal/runtime/PropertyListenerManager.java10
-rw-r--r--src/jdk/nashorn/internal/runtime/PropertyMap.java148
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptEnvironment.java8
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptFunction.java28
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptObject.java63
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptRuntime.java19
-rw-r--r--src/jdk/nashorn/internal/runtime/StructureLoader.java49
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/ArrayData.java9
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java47
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java32
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java21
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/Bootstrap.java39
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java51
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java90
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/InvokeByName.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java19
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java17
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java53
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java42
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java4
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java58
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/Analyser.java64
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/ArrayCompiler.java67
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodeMachine.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodePrinter.java212
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/CodeRangeBuffer.java34
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/EncodingHelper.java19
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/Lexer.java255
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/Parser.java129
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/Regex.java53
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/ScanEnvironment.java15
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/ScannerSupport.java20
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/Token.java74
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/ast/BackRefNode.java59
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/ast/CClassNode.java40
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/ast/StateNode.java9
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/ast/StringNode.java7
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/constants/OPCode.java30
-rw-r--r--src/jdk/nashorn/internal/runtime/resources/Messages.properties1
-rw-r--r--src/jdk/nashorn/internal/runtime/resources/Options.properties16
-rw-r--r--src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js7
-rw-r--r--src/jdk/nashorn/internal/scripts/JO.java18
-rw-r--r--src/jdk/nashorn/tools/Shell.java7
-rw-r--r--test/script/basic/JDK-8010946-2.js38
-rw-r--r--test/script/basic/JDK-8010946-2.js.EXPECTED3
-rw-r--r--test/script/basic/JDK-8010946-privileged.js47
-rw-r--r--test/script/basic/JDK-8010946.js51
-rw-r--r--test/script/basic/JDK-8010946.js.EXPECTED5
-rw-r--r--test/script/basic/JDK-8012191.js53
-rw-r--r--test/script/basic/JDK-8012191.js.EXPECTED6
-rw-r--r--test/script/basic/JDK-8014785.js62
-rw-r--r--test/script/basic/JDK-8014785.js.EXPECTED8
-rw-r--r--test/script/basic/JDK-8015356.js44
-rw-r--r--test/script/basic/JDK-8015356.js.EXPECTED13
-rw-r--r--test/script/basic/JDK-8016667.js20
-rw-r--r--test/script/basic/JDK-8016681.js42
-rw-r--r--test/script/basic/JDK-8016681.js.EXPECTED15
-rw-r--r--test/script/basic/JDK-8017084.js17625
-rw-r--r--test/script/basic/JDK-8017084.js.EXPECTED13
-rw-r--r--test/script/basic/JDK-8017768.js35
-rw-r--r--test/script/basic/JDK-8017768.js.EXPECTED4
-rw-r--r--test/script/basic/JDK-8019585.js34
-rw-r--r--test/script/basic/JDK-8019629.js42
-rw-r--r--test/script/basic/JDK-8019783.js55
-rw-r--r--test/script/basic/JDK-8019783.js.EXPECTED9
-rw-r--r--test/script/basic/JDK-8019791.js50
-rw-r--r--test/script/basic/JDK-8019791.js.EXPECTED6
-rw-r--r--test/script/basic/JDK-8019805.js36
-rw-r--r--test/script/basic/JDK-8019805.js.EXPECTED3
-rw-r--r--test/script/basic/JDK-8019808.js39
-rw-r--r--test/script/basic/JDK-8019809.js37
-rw-r--r--test/script/basic/JDK-8019810.js36
-rw-r--r--test/script/basic/JDK-8019810.js.EXPECTED1
-rw-r--r--test/script/basic/JDK-8019811.js47
-rw-r--r--test/script/basic/JDK-8019814.js73
-rw-r--r--test/script/basic/JDK-8019814.js.EXPECTED6
-rw-r--r--test/script/basic/JDK-8019817.js37
-rw-r--r--test/script/basic/JDK-8019819.js46
-rw-r--r--test/script/basic/JDK-8019821.js37
-rw-r--r--test/script/basic/JDK-8019822.js29
-rw-r--r--test/script/basic/JDK-8019947.js68
-rw-r--r--test/script/basic/JDK-8019947.js.EXPECTED3
-rw-r--r--test/script/basic/JDK-8019963.js66
-rw-r--r--test/script/basic/JDK-8019963.js.EXPECTED29
-rw-r--r--test/script/basic/JDK-8019983.js42
-rw-r--r--test/script/basic/JDK-8019983.js.EXPECTED1
-rw-r--r--test/script/basic/JDK-8020124.js32
-rw-r--r--test/script/basic/JDK-8020223.js71
-rw-r--r--test/script/basic/JDK-8020324.js139
-rw-r--r--test/script/basic/JDK-8020324.js.EXPECTED90
-rw-r--r--test/script/basic/JDK-8020325.js38
-rw-r--r--test/script/basic/JDK-8020325.js.EXPECTED4
-rw-r--r--test/script/basic/JDK-8020354.js43
-rw-r--r--test/script/basic/JDK-8020354.js.EXPECTED9
-rw-r--r--test/script/basic/JDK-8020357.js52
-rw-r--r--test/script/basic/JDK-8020357.js.EXPECTED1
-rw-r--r--test/script/basic/JDK-8020358.js43
-rw-r--r--test/script/basic/JDK-8020358.js.EXPECTED7
-rw-r--r--test/script/basic/JDK-8020380.js36
-rw-r--r--test/script/basic/JDK-8020437.js49
-rw-r--r--test/script/basic/JDK-8020437.js.EXPECTED5
-rw-r--r--test/script/basic/JDK-8020463.js54
-rw-r--r--test/script/basic/JDK-8020508.js37
-rw-r--r--test/script/basic/JDK-8020508.js.EXPECTED1
-rw-r--r--test/script/basic/NASHORN-759.js.EXPECTED2
-rw-r--r--test/script/basic/forin.js5
-rw-r--r--test/script/basic/forin.js.EXPECTED10
-rw-r--r--test/script/error/JDK-8020437-2.js36
-rw-r--r--test/script/error/JDK-8020437-2.js.EXPECTED3
-rw-r--r--test/script/error/JDK-8020437.js36
-rw-r--r--test/script/error/JDK-8020437.js.EXPECTED3
-rw-r--r--test/script/trusted/JDK-8006529.js (renamed from test/script/currently-failing/JDK-8006529.js)131
-rw-r--r--test/src/jdk/nashorn/api/scripting/ScriptEngineSecurityTest.java44
-rw-r--r--test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java18
-rw-r--r--test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java51
-rw-r--r--test/src/jdk/nashorn/test/models/OuterClass.java4
-rw-r--r--test/src/jdk/nashorn/test/models/PropertyBind.java82
273 files changed, 25201 insertions, 3343 deletions
diff --git a/buildtools/nasgen/build.xml b/buildtools/nasgen/build.xml
index bf56c111..6243bb2f 100644
--- a/buildtools/nasgen/build.xml
+++ b/buildtools/nasgen/build.xml
@@ -42,7 +42,8 @@
destdir="${build.classes.dir}"
classpath="${javac.classpath}"
debug="${javac.debug}"
- includeantruntime="false">
+ includeantruntime="false" fork="true">
+ <compilerarg value="-J-Djava.ext.dirs="/>
<compilerarg value="-Xlint:unchecked"/>
<compilerarg value="-Xlint:deprecation"/>
<compilerarg value="-XDignore.symbol.file"/>
diff --git a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java
index bc6bb4b2..3425e9fd 100644
--- a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java
@@ -25,6 +25,7 @@
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_PRIVATE;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC;
@@ -36,14 +37,24 @@ import static jdk.nashorn.internal.tools.nasgen.StringConstants.GETTER_PREFIX;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.GET_CLASS_NAME;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.GET_CLASS_NAME_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.LOOKUP_NEWPROPERTY;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.LOOKUP_NEWPROPERTY_DESC;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.LOOKUP_TYPE;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DESC;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_FIELD_NAME;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_NEWMAP;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_NEWMAP_DESC;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_TYPE;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.ACCESSORPROPERTY_CREATE;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.ACCESSORPROPERTY_CREATE_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.ACCESSORPROPERTY_TYPE;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.LIST_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.ARRAYLIST_TYPE;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.ARRAYLIST_INIT_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.COLLECTION_TYPE;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.COLLECTION_ADD;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.COLLECTION_ADD_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.COLLECTIONS_TYPE;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.COLLECTIONS_EMPTY_LIST;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_FIELD_NAME;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_SETISSHARED;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_SETISSHARED_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_NEWMAP;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_NEWMAP_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_TYPE;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_MAKEFUNCTION;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_MAKEFUNCTION_DESC;
@@ -160,18 +171,30 @@ public class ClassGenerator {
return new MethodGenerator(mv, access, name, desc);
}
- static void emitStaticInitPrefix(final MethodGenerator mi, final String className) {
+ static void emitStaticInitPrefix(final MethodGenerator mi, final String className, final int memberCount) {
mi.visitCode();
- mi.pushNull();
- mi.putStatic(className, MAP_FIELD_NAME, MAP_DESC);
- mi.loadClass(className);
- mi.invokeStatic(MAP_TYPE, MAP_NEWMAP, MAP_NEWMAP_DESC);
- // stack: PropertyMap
+ if (memberCount > 0) {
+ // new ArrayList(int)
+ mi.newObject(ARRAYLIST_TYPE);
+ mi.dup();
+ mi.push(memberCount);
+ mi.invokeSpecial(ARRAYLIST_TYPE, INIT, ARRAYLIST_INIT_DESC);
+ // stack: ArrayList
+ } else {
+ // java.util.Collections.EMPTY_LIST
+ mi.getStatic(COLLECTIONS_TYPE, COLLECTIONS_EMPTY_LIST, LIST_DESC);
+ // stack List
+ }
}
static void emitStaticInitSuffix(final MethodGenerator mi, final String className) {
- // stack: PropertyMap
- mi.putStatic(className, MAP_FIELD_NAME, MAP_DESC);
+ // stack: Collection
+ // pmap = PropertyMap.newMap(Collection<Property>);
+ mi.invokeStatic(PROPERTYMAP_TYPE, PROPERTYMAP_NEWMAP, PROPERTYMAP_NEWMAP_DESC);
+ // pmap.setIsShared();
+ mi.invokeVirtual(PROPERTYMAP_TYPE, PROPERTYMAP_SETISSHARED, PROPERTYMAP_SETISSHARED_DESC);
+ // $nasgenmap$ = pmap;
+ mi.putStatic(className, PROPERTYMAP_FIELD_NAME, PROPERTYMAP_DESC);
mi.returnVoid();
mi.computeMaxs();
mi.visitEnd();
@@ -235,9 +258,9 @@ public class ClassGenerator {
}
static void addMapField(final ClassVisitor cv) {
- // add a MAP static field
- final FieldVisitor fv = cv.visitField(ACC_PRIVATE | ACC_STATIC,
- MAP_FIELD_NAME, MAP_DESC, null, null);
+ // add a PropertyMap static field
+ final FieldVisitor fv = cv.visitField(ACC_PRIVATE | ACC_STATIC | ACC_FINAL,
+ PROPERTYMAP_FIELD_NAME, PROPERTYMAP_DESC, null, null);
if (fv != null) {
fv.visitEnd();
}
@@ -278,7 +301,11 @@ public class ClassGenerator {
static void linkerAddGetterSetter(final MethodGenerator mi, final String className, final MemberInfo memInfo) {
final String propertyName = memInfo.getName();
- // stack: PropertyMap
+ // stack: Collection
+ // dup of Collection instance
+ mi.dup();
+
+ // property = AccessorProperty.create(key, flags, getter, setter);
mi.loadLiteral(propertyName);
// setup flags
mi.push(memInfo.getAttributes());
@@ -292,13 +319,21 @@ public class ClassGenerator {
javaName = SETTER_PREFIX + memInfo.getJavaName();
mi.visitLdcInsn(new Handle(H_INVOKEVIRTUAL, className, javaName, setterDesc(memInfo)));
}
- mi.invokeStatic(LOOKUP_TYPE, LOOKUP_NEWPROPERTY, LOOKUP_NEWPROPERTY_DESC);
- // stack: PropertyMap
+ mi.invokeStatic(ACCESSORPROPERTY_TYPE, ACCESSORPROPERTY_CREATE, ACCESSORPROPERTY_CREATE_DESC);
+ // boolean Collection.add(property)
+ mi.invokeInterface(COLLECTION_TYPE, COLLECTION_ADD, COLLECTION_ADD_DESC);
+ // pop return value of Collection.add
+ mi.pop();
+ // stack: Collection
}
static void linkerAddGetterSetter(final MethodGenerator mi, final String className, final MemberInfo getter, final MemberInfo setter) {
final String propertyName = getter.getName();
- // stack: PropertyMap
+ // stack: Collection
+ // dup of Collection instance
+ mi.dup();
+
+ // property = AccessorProperty.create(key, flags, getter, setter);
mi.loadLiteral(propertyName);
// setup flags
mi.push(getter.getAttributes());
@@ -312,8 +347,12 @@ public class ClassGenerator {
mi.visitLdcInsn(new Handle(H_INVOKESTATIC, className,
setter.getJavaName(), setter.getJavaDesc()));
}
- mi.invokeStatic(LOOKUP_TYPE, LOOKUP_NEWPROPERTY, LOOKUP_NEWPROPERTY_DESC);
- // stack: PropertyMap
+ mi.invokeStatic(ACCESSORPROPERTY_TYPE, ACCESSORPROPERTY_CREATE, ACCESSORPROPERTY_CREATE_DESC);
+ // boolean Collection.add(property)
+ mi.invokeInterface(COLLECTION_TYPE, COLLECTION_ADD, COLLECTION_ADD_DESC);
+ // pop return value of Collection.add
+ mi.pop();
+ // stack: Collection
}
static ScriptClassInfo getScriptClassInfo(final String fileName) throws IOException {
diff --git a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java
index 7c59f8c3..e90b53ec 100644
--- a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java
@@ -32,11 +32,11 @@ import static jdk.internal.org.objectweb.asm.Opcodes.V1_7;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.CONSTRUCTOR_SUFFIX;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.DEFAULT_INIT_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DESC;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DUPLICATE;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DUPLICATE_DESC;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_FIELD_NAME;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_TYPE;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_DUPLICATE;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_DUPLICATE_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_FIELD_NAME;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_TYPE;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_SETCONSTRUCTOR;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC;
@@ -129,7 +129,7 @@ public class ConstructorGenerator extends ClassGenerator {
private void emitStaticInitializer() {
final MethodGenerator mi = makeStaticInitializer();
- emitStaticInitPrefix(mi, className);
+ emitStaticInitPrefix(mi, className, memberCount);
for (final MemberInfo memInfo : scriptClassInfo.getMembers()) {
if (memInfo.isConstructorFunction() || memInfo.isConstructorProperty()) {
@@ -170,10 +170,10 @@ public class ConstructorGenerator extends ClassGenerator {
private void loadMap(final MethodGenerator mi) {
if (memberCount > 0) {
- mi.getStatic(className, MAP_FIELD_NAME, MAP_DESC);
+ mi.getStatic(className, PROPERTYMAP_FIELD_NAME, PROPERTYMAP_DESC);
// make sure we use duplicated PropertyMap so that original map
- // stays intact and so can be used for many globals in same context
- mi.invokeVirtual(MAP_TYPE, MAP_DUPLICATE, MAP_DUPLICATE_DESC);
+ // stays intact and so can be used for many globals.
+ mi.invokeVirtual(PROPERTYMAP_TYPE, PROPERTYMAP_DUPLICATE, PROPERTYMAP_DUPLICATE_DESC);
}
}
diff --git a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java
index c3dfd878..475d7328 100644
--- a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java
@@ -57,6 +57,7 @@ import static jdk.internal.org.objectweb.asm.Opcodes.IALOAD;
import static jdk.internal.org.objectweb.asm.Opcodes.IASTORE;
import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_0;
import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD;
+import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEINTERFACE;
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.INVOKEVIRTUAL;
@@ -347,6 +348,10 @@ public class MethodGenerator extends MethodVisitor {
}
// invokes, field get/sets
+ void invokeInterface(final String owner, final String method, final String desc) {
+ super.visitMethodInsn(INVOKEINTERFACE, owner, method, desc);
+ }
+
void invokeVirtual(final String owner, final String method, final String desc) {
super.visitMethodInsn(INVOKEVIRTUAL, owner, method, desc);
}
diff --git a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java
index 17750cd1..98048a29 100644
--- a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java
@@ -30,11 +30,11 @@ import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER;
import static jdk.internal.org.objectweb.asm.Opcodes.V1_7;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.DEFAULT_INIT_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DESC;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DUPLICATE;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DUPLICATE_DESC;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_FIELD_NAME;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_TYPE;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_DUPLICATE;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_DUPLICATE_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_FIELD_NAME;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_TYPE;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_TYPE;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPE_SUFFIX;
@@ -67,6 +67,7 @@ public class PrototypeGenerator extends ClassGenerator {
// add <clinit>
emitStaticInitializer();
}
+
// add <init>
emitConstructor();
@@ -106,7 +107,7 @@ public class PrototypeGenerator extends ClassGenerator {
private void emitStaticInitializer() {
final MethodGenerator mi = makeStaticInitializer();
- emitStaticInitPrefix(mi, className);
+ emitStaticInitPrefix(mi, className, memberCount);
for (final MemberInfo memInfo : scriptClassInfo.getMembers()) {
if (memInfo.isPrototypeFunction() || memInfo.isPrototypeProperty()) {
linkerAddGetterSetter(mi, className, memInfo);
@@ -124,10 +125,10 @@ public class PrototypeGenerator extends ClassGenerator {
mi.loadThis();
if (memberCount > 0) {
// call "super(map$)"
- mi.getStatic(className, MAP_FIELD_NAME, MAP_DESC);
+ mi.getStatic(className, PROPERTYMAP_FIELD_NAME, PROPERTYMAP_DESC);
// make sure we use duplicated PropertyMap so that original map
- // stays intact and so can be used for many globals in same context
- mi.invokeVirtual(MAP_TYPE, MAP_DUPLICATE, MAP_DUPLICATE_DESC);
+ // stays intact and so can be used for many global.
+ mi.invokeVirtual(PROPERTYMAP_TYPE, PROPERTYMAP_DUPLICATE, PROPERTYMAP_DUPLICATE_DESC);
mi.invokeSpecial(PROTOTYPEOBJECT_TYPE, INIT, SCRIPTOBJECT_INIT_DESC);
// initialize Function type fields
initFunctionFields(mi);
diff --git a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java
index ffeb90be..1622e02b 100644
--- a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java
@@ -37,10 +37,7 @@ import static jdk.nashorn.internal.tools.nasgen.StringConstants.$CLINIT$;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.CLINIT;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.DEFAULT_INIT_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DESC;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_FIELD_NAME;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_INIT_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_TYPE;
import java.io.BufferedInputStream;
@@ -159,14 +156,7 @@ public class ScriptClassInstrumentor extends ClassVisitor {
public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) {
if (isConstructor && opcode == INVOKESPECIAL &&
INIT.equals(name) && SCRIPTOBJECT_TYPE.equals(owner)) {
-
- // replace call to empty super-constructor with one passing PropertyMap argument
- if (DEFAULT_INIT_DESC.equals(desc)) {
- super.visitFieldInsn(GETSTATIC, scriptClassInfo.getJavaName(), MAP_FIELD_NAME, MAP_DESC);
- super.visitMethodInsn(INVOKESPECIAL, SCRIPTOBJECT_TYPE, INIT, SCRIPTOBJECT_INIT_DESC);
- } else {
- super.visitMethodInsn(opcode, owner, name, desc);
- }
+ super.visitMethodInsn(opcode, owner, name, desc);
if (memberCount > 0) {
// initialize @Property fields if needed
@@ -256,7 +246,7 @@ public class ScriptClassInstrumentor extends ClassVisitor {
}
// Now generate $clinit$
final MethodGenerator mi = ClassGenerator.makeStaticInitializer(this, $CLINIT$);
- ClassGenerator.emitStaticInitPrefix(mi, className);
+ ClassGenerator.emitStaticInitPrefix(mi, className, memberCount);
if (memberCount > 0) {
for (final MemberInfo memInfo : scriptClassInfo.getMembers()) {
if (memInfo.isInstanceProperty() || memInfo.isInstanceFunction()) {
diff --git a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java
index 5a5032f9..c4c1ab8d 100644
--- a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java
@@ -27,10 +27,14 @@ package jdk.nashorn.internal.tools.nasgen;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import jdk.internal.org.objectweb.asm.Type;
-import jdk.nashorn.internal.lookup.Lookup;
import jdk.nashorn.internal.objects.PrototypeObject;
import jdk.nashorn.internal.objects.ScriptFunctionImpl;
+import jdk.nashorn.internal.runtime.AccessorProperty;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
@@ -40,15 +44,41 @@ import jdk.nashorn.internal.runtime.ScriptObject;
*/
@SuppressWarnings("javadoc")
public interface StringConstants {
+ // standard jdk types, methods
static final Type TYPE_METHOD = Type.getType(Method.class);
static final Type TYPE_METHODHANDLE = Type.getType(MethodHandle.class);
static final Type TYPE_METHODHANDLE_ARRAY = Type.getType(MethodHandle[].class);
static final Type TYPE_OBJECT = Type.getType(Object.class);
static final Type TYPE_CLASS = Type.getType(Class.class);
static final Type TYPE_STRING = Type.getType(String.class);
+ static final Type TYPE_COLLECTION = Type.getType(Collection.class);
+ static final Type TYPE_COLLECTIONS = Type.getType(Collections.class);
+ static final Type TYPE_ARRAYLIST = Type.getType(ArrayList.class);
+ static final Type TYPE_LIST = Type.getType(List.class);
- // Nashorn types
- static final Type TYPE_LOOKUP = Type.getType(Lookup.class);
+ static final String CLINIT = "<clinit>";
+ static final String INIT = "<init>";
+ static final String DEFAULT_INIT_DESC = Type.getMethodDescriptor(Type.VOID_TYPE);
+
+ static final String METHODHANDLE_TYPE = TYPE_METHODHANDLE.getInternalName();
+ static final String OBJECT_TYPE = TYPE_OBJECT.getInternalName();
+ static final String OBJECT_DESC = TYPE_OBJECT.getDescriptor();
+ static final String OBJECT_ARRAY_DESC = Type.getDescriptor(Object[].class);
+ static final String ARRAYLIST_TYPE = TYPE_ARRAYLIST.getInternalName();
+ static final String COLLECTION_TYPE = TYPE_COLLECTION.getInternalName();
+ static final String COLLECTIONS_TYPE = TYPE_COLLECTIONS.getInternalName();
+
+ // java.util.Collection.add(Object)
+ static final String COLLECTION_ADD = "add";
+ static final String COLLECTION_ADD_DESC = Type.getMethodDescriptor(Type.BOOLEAN_TYPE, TYPE_OBJECT);
+ // java.util.ArrayList.<init>(int)
+ static final String ARRAYLIST_INIT_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE);
+ // java.util.Collections.EMPTY_LIST
+ static final String COLLECTIONS_EMPTY_LIST = "EMPTY_LIST";
+ static final String LIST_DESC = TYPE_LIST.getDescriptor();
+
+ // Nashorn types, methods
+ static final Type TYPE_ACCESSORPROPERTY = Type.getType(AccessorProperty.class);
static final Type TYPE_PROPERTYMAP = Type.getType(PropertyMap.class);
static final Type TYPE_PROTOTYPEOBJECT = Type.getType(PrototypeObject.class);
static final Type TYPE_SCRIPTFUNCTION = Type.getType(ScriptFunction.class);
@@ -57,54 +87,56 @@ public interface StringConstants {
static final String PROTOTYPE_SUFFIX = "$Prototype";
static final String CONSTRUCTOR_SUFFIX = "$Constructor";
+
// This field name is known to Nashorn runtime (Context).
// Synchronize the name change, if needed at all.
- static final String MAP_FIELD_NAME = "$nasgenmap$";
+ static final String PROPERTYMAP_FIELD_NAME = "$nasgenmap$";
static final String $CLINIT$ = "$clinit$";
- static final String CLINIT = "<clinit>";
- static final String INIT = "<init>";
- static final String DEFAULT_INIT_DESC = Type.getMethodDescriptor(Type.VOID_TYPE);
- static final String SCRIPTOBJECT_INIT_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_PROPERTYMAP);
+ // AccessorProperty
+ static final String ACCESSORPROPERTY_TYPE = TYPE_ACCESSORPROPERTY.getInternalName();
+ static final String ACCESSORPROPERTY_CREATE = "create";
+ static final String ACCESSORPROPERTY_CREATE_DESC =
+ Type.getMethodDescriptor(TYPE_ACCESSORPROPERTY, TYPE_STRING, Type.INT_TYPE, TYPE_METHODHANDLE, TYPE_METHODHANDLE);
- static final String METHODHANDLE_TYPE = TYPE_METHODHANDLE.getInternalName();
+ // PropertyMap
+ static final String PROPERTYMAP_TYPE = TYPE_PROPERTYMAP.getInternalName();
+ static final String PROPERTYMAP_DESC = TYPE_PROPERTYMAP.getDescriptor();
+ static final String PROPERTYMAP_NEWMAP = "newMap";
+ static final String PROPERTYMAP_NEWMAP_DESC = Type.getMethodDescriptor(TYPE_PROPERTYMAP, TYPE_COLLECTION);
+ static final String PROPERTYMAP_DUPLICATE = "duplicate";
+ static final String PROPERTYMAP_DUPLICATE_DESC = Type.getMethodDescriptor(TYPE_PROPERTYMAP);
+ static final String PROPERTYMAP_SETISSHARED = "setIsShared";
+ static final String PROPERTYMAP_SETISSHARED_DESC = Type.getMethodDescriptor(TYPE_PROPERTYMAP);
- static final String OBJECT_TYPE = TYPE_OBJECT.getInternalName();
- static final String OBJECT_DESC = TYPE_OBJECT.getDescriptor();
- static final String OBJECT_ARRAY_DESC = Type.getDescriptor(Object[].class);
+ // PrototypeObject
+ static final String PROTOTYPEOBJECT_TYPE = TYPE_PROTOTYPEOBJECT.getInternalName();
+ static final String PROTOTYPEOBJECT_SETCONSTRUCTOR = "setConstructor";
+ static final String PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT, TYPE_OBJECT);
+ // ScriptFunction
static final String SCRIPTFUNCTION_TYPE = TYPE_SCRIPTFUNCTION.getInternalName();
+ static final String SCRIPTFUNCTION_SETARITY = "setArity";
+ static final String SCRIPTFUNCTION_SETARITY_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE);
+ static final String SCRIPTFUNCTION_SETPROTOTYPE = "setPrototype";
+ static final String SCRIPTFUNCTION_SETPROTOTYPE_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT);
+
+ // ScriptFunctionImpl
static final String SCRIPTFUNCTIONIMPL_TYPE = TYPE_SCRIPTFUNCTIONIMPL.getInternalName();
static final String SCRIPTFUNCTIONIMPL_MAKEFUNCTION = "makeFunction";
static final String SCRIPTFUNCTIONIMPL_MAKEFUNCTION_DESC =
Type.getMethodDescriptor(TYPE_SCRIPTFUNCTION, TYPE_STRING, TYPE_METHODHANDLE);
static final String SCRIPTFUNCTIONIMPL_MAKEFUNCTION_SPECS_DESC =
Type.getMethodDescriptor(TYPE_SCRIPTFUNCTION, TYPE_STRING, TYPE_METHODHANDLE, TYPE_METHODHANDLE_ARRAY);
-
static final String SCRIPTFUNCTIONIMPL_INIT_DESC3 =
Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_METHODHANDLE_ARRAY);
static final String SCRIPTFUNCTIONIMPL_INIT_DESC4 =
Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_PROPERTYMAP, TYPE_METHODHANDLE_ARRAY);
- static final String SCRIPTFUNCTION_SETARITY = "setArity";
- static final String SCRIPTFUNCTION_SETARITY_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE);
- static final String SCRIPTFUNCTION_SETPROTOTYPE = "setPrototype";
- static final String SCRIPTFUNCTION_SETPROTOTYPE_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT);
- static final String PROTOTYPEOBJECT_TYPE = TYPE_PROTOTYPEOBJECT.getInternalName();
- static final String PROTOTYPEOBJECT_SETCONSTRUCTOR = "setConstructor";
- static final String PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT, TYPE_OBJECT);
+
+ // ScriptObject
static final String SCRIPTOBJECT_TYPE = TYPE_SCRIPTOBJECT.getInternalName();
- static final String MAP_TYPE = TYPE_PROPERTYMAP.getInternalName();
- static final String MAP_DESC = TYPE_PROPERTYMAP.getDescriptor();
- static final String MAP_NEWMAP = "newMap";
- static final String MAP_NEWMAP_DESC = Type.getMethodDescriptor(TYPE_PROPERTYMAP, TYPE_CLASS);
- static final String MAP_DUPLICATE = "duplicate";
- static final String MAP_DUPLICATE_DESC = Type.getMethodDescriptor(TYPE_PROPERTYMAP);
- static final String MAP_SETFLAGS = "setFlags";
- static final String LOOKUP_TYPE = TYPE_LOOKUP.getInternalName();
- static final String LOOKUP_GETMETHOD = "getMethod";
- static final String LOOKUP_NEWPROPERTY = "newProperty";
- static final String LOOKUP_NEWPROPERTY_DESC =
- Type.getMethodDescriptor(TYPE_PROPERTYMAP, TYPE_PROPERTYMAP, TYPE_STRING, Type.INT_TYPE, TYPE_METHODHANDLE, TYPE_METHODHANDLE);
+ static final String SCRIPTOBJECT_INIT_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_PROPERTYMAP);
+
static final String GETTER_PREFIX = "G$";
static final String SETTER_PREFIX = "S$";
diff --git a/docs/JavaScriptingProgrammersGuide.html b/docs/JavaScriptingProgrammersGuide.html
index 18ae823d..dd74d749 100644
--- a/docs/JavaScriptingProgrammersGuide.html
+++ b/docs/JavaScriptingProgrammersGuide.html
@@ -501,14 +501,19 @@ or
var anArrayListWithSize = new ArrayList(16)
</code></pre>
-In the special case of inner classes, you need to use the JVM fully qualified name, meaning using $ sign in the class name:
+In the special case of inner classes, you can either use the JVM fully qualified name, meaning using the dollar sign in the class name, or you can use the dot:
<pre><code>
var ftype = Java.type("java.awt.geom.Arc2D$Float")
</code></pre>
+and
+
+<pre><code>
+ var ftype = Java.type("java.awt.geom.Arc2D.Float")
+</code></pre>
-However, once you retrieved the outer class, you can access the inner class as a property on it:
+both work. Note however that using the dollar sign is faster, as Java.type first tries to resolve the class name as it is originally specified, and the internal JVM names for inner classes use the dollar sign. If you use the dot, Java.type will internally get a ClassNotFoundException and subsequently retry by changing the last dot to dollar sign. As a matter of fact, it'll keep replacing dots with dollar signs until it either successfully loads the class or runs out of all dots in the name. This way it can correctly resolve and load even multiply nested inner classes with the dot notation. Again, this will be slower than using the dollar signs in the name. An alternative way to access the inner class is as a property of the outer class:
<pre><code>
var arctype = Java.type("java.awt.geom.Arc2D")
diff --git a/make/build-nasgen.xml b/make/build-nasgen.xml
index a50d41e0..9dca5505 100644
--- a/make/build-nasgen.xml
+++ b/make/build-nasgen.xml
@@ -42,11 +42,6 @@
<arg value="jdk.nashorn.internal.objects"/>
<arg value="${basedir}/build/classes"/>
</java>
-
- <move todir="${basedir}/build/classes/jdk/nashorn/internal/objects">
- <fileset dir="${basedir}/build/classes/jdk/nashorn/internal/objects"/>
- <mapper type="glob" from="*.class" to="*.clazz"/>
- </move>
</target>
<target name="run-nasgen-eclipse">
@@ -66,7 +61,6 @@
<fileset dir="${basedir}/build/eclipse/.nasgentmp/jdk/nashorn/internal/objects">
<include name="*.class"/>
</fileset>
- <mapper type="glob" from="*.class" to="*.clazz"/>
</move>
<delete includeemptydirs="true"><fileset dir="${basedir}/build/eclipse/.nasgentmp" includes="**"/></delete>
@@ -75,7 +69,6 @@
<fileset dir="${basedir}/build/eclipse/jdk/nashorn/internal/objects">
<include name="**/*.class"/>
</fileset>
- <mapper type="glob" from="*.class" to="*.clazz"/>
</copy>
</target>
diff --git a/make/build.xml b/make/build.xml
index 7e2d999d..2bda503f 100644
--- a/make/build.xml
+++ b/make/build.xml
@@ -100,7 +100,8 @@
target="${javac.target}"
debug="${javac.debug}"
encoding="${javac.encoding}"
- includeantruntime="false">
+ includeantruntime="false" fork="true">
+ <compilerarg value="-J-Djava.ext.dirs="/>
<compilerarg value="-Xlint:unchecked"/>
<compilerarg value="-Xlint:deprecation"/>
<compilerarg value="-XDignore.symbol.file"/>
@@ -218,8 +219,10 @@
target="${javac.target}"
debug="${javac.debug}"
encoding="${javac.encoding}"
- includeantruntime="false">
- <compilerarg line="-extdirs &quot;&quot;"/>
+ includeantruntime="false" fork="true">
+ <compilerarg value="-J-Djava.ext.dirs="/>
+ <compilerarg value="-Xlint:unchecked"/>
+ <compilerarg value="-Xlint:deprecation"/>
</javac>
<!-- tests that check nashorn internals and internal API -->
@@ -235,44 +238,31 @@
</target>
<target name="generate-policy-file" depends="prepare">
- <!-- Generating nashorn.policy file -->
-
- <!-- nashorn internal tests jar requires AllPermission -->
- <echo message="grant codeBase &quot;file:/${basedir}/${nashorn.internal.tests.jar}&quot; {" file="${build.dir}/nashorn.policy"/>
- <echo message="" file="${build.dir}/nashorn.policy" append="true"/>
- <echo message=" permission java.security.AllPermission;" file="${build.dir}/nashorn.policy" append="true"/>
- <echo message="" file="${build.dir}/nashorn.policy" append="true"/>
- <echo message="};" file="${build.dir}/nashorn.policy" append="true"/>
- <echo message="" file="${build.dir}/nashorn.policy" append="true"/>
-
- <!-- TestNG framework jar needs AllPermission -->
- <echo message="grant codeBase &quot;file:/${basedir}/${file.reference.testng.jar}&quot; {" file="${build.dir}/nashorn.policy" append="true"/>
- <echo message="" file="${build.dir}/nashorn.policy" append="true"/>
- <echo message=" permission java.security.AllPermission;" file="${build.dir}/nashorn.policy" append="true"/>
- <echo message="" file="${build.dir}/nashorn.policy" append="true"/>
- <echo message="};" file="${build.dir}/nashorn.policy" append="true"/>
- <echo message="" file="${build.dir}/nashorn.policy" append="true"/>
-
- <!-- AllPermission to test/script/trusted tests -->
- <echo message="grant codeBase &quot;file:/${basedir}/test/script/trusted/*&quot; {" file="${build.dir}/nashorn.policy" append="true"/>
- <echo message="" file="${build.dir}/nashorn.policy" append="true"/>
- <echo message=" permission java.security.AllPermission;" file="${build.dir}/nashorn.policy" append="true"/>
- <echo message="" file="${build.dir}/nashorn.policy" append="true"/>
- <echo message="};" file="${build.dir}/nashorn.policy" append="true"/>
- <echo message="" file="${build.dir}/nashorn.policy" append="true"/>
-
- <echo message="grant codeBase &quot;file:/${basedir}/test/script/basic/*&quot; {" file="${build.dir}/nashorn.policy" append="true"/>
- <echo message="" file="${build.dir}/nashorn.policy" append="true"/>
- <!-- test/script/basic .js scripts load other script tests -->
- <echo message=" permission java.io.FilePermission &quot;${basedir}/test/script/-&quot;, &quot;read&quot;;" file="${build.dir}/nashorn.policy" append="true"/>
- <echo message=" permission java.io.FilePermission &quot;user.dir&quot;, &quot;read&quot;;" file="${build.dir}/nashorn.policy" append="true"/>
- <echo message=" permission java.util.PropertyPermission &quot;user.dir&quot;, &quot;read&quot;;" file="${build.dir}/nashorn.policy" append="true"/>
- <echo message="" file="${build.dir}/nashorn.policy" append="true"/>
- <!-- test/script/basic .js scripts can read nashorn.test.* properties -->
- <echo message=" permission java.util.PropertyPermission &quot;nashorn.test.*&quot;, &quot;read&quot;;" file="${build.dir}/nashorn.policy" append="true"/>
- <echo message="" file="${build.dir}/nashorn.policy" append="true"/>
- <echo message="};" file="${build.dir}/nashorn.policy" append="true"/>
- <echo message="" file="${build.dir}/nashorn.policy" append="true"/>
+ <echo file="${build.dir}/nashorn.policy">
+
+grant codeBase "file:/${basedir}/${nashorn.internal.tests.jar}" {
+ permission java.security.AllPermission;
+};
+
+grant codeBase "file:/${basedir}/${file.reference.testng.jar}" {
+ permission java.security.AllPermission;
+};
+
+grant codeBase "file:/${basedir}/test/script/trusted/*" {
+ permission java.security.AllPermission;
+};
+
+grant codeBase "file:/${basedir}/test/script/basic/*" {
+ permission java.io.FilePermission "${basedir}/test/script/-", "read";
+ permission java.io.FilePermission "$${user.dir}", "read";
+ permission java.util.PropertyPermission "user.dir", "read";
+ permission java.util.PropertyPermission "nashorn.test.*", "read";
+};
+
+grant codeBase "file:/${basedir}/test/script/basic/JDK-8010946-privileged.js" {
+ permission java.util.PropertyPermission "java.security.policy", "read";
+};
+ </echo>
<replace file="${build.dir}/nashorn.policy"><replacetoken>\</replacetoken><replacevalue>/</replacevalue></replace> <!--hack for Windows - to make URLs with normal path separators -->
<replace file="${build.dir}/nashorn.policy"><replacetoken>//</replacetoken><replacevalue>/</replacevalue></replace> <!--hack for Unix - to avoid leading // in URLs -->
diff --git a/make/code_coverage.xml b/make/code_coverage.xml
index 3e2860f8..dea03099 100644
--- a/make/code_coverage.xml
+++ b/make/code_coverage.xml
@@ -60,16 +60,8 @@
<copy todir="${build.dir}/to_be_instrumented">
<fileset dir="${build.classes.dir}">
<include name="**/*.class"/>
- <include name="**/*.clazz"/>
</fileset>
</copy>
-
- <move todir="${build.dir}/to_be_instrumented/jdk/nashorn/internal/objects">
- <fileset dir="${build.dir}/to_be_instrumented/jdk/nashorn/internal/objects">
- <include name="**/*.clazz"/>
- </fileset>
- <mapper type="glob" from="*.clazz" to="*.class"/>
- </move>
</target>
<target name="generate-cc-template" depends="prepare-to-be-instrumented" description="Generates code coverage template for dynamic CC" if="cc.generate.template">
diff --git a/make/project.properties b/make/project.properties
index 66bbdbeb..dbd9efce 100644
--- a/make/project.properties
+++ b/make/project.properties
@@ -200,6 +200,9 @@ test262-test-sys-prop.test.failed.list.file=${build.dir}/test/failedTests
# test262 test frameworks
test262-test-sys-prop.test.js.framework=\
+ --class-cache-size=0 \
+ --no-java \
+ --no-typed-arrays \
-timezone=PST \
${test.script.dir}/test262.js \
${test262.dir}/test/harness/framework.js \
diff --git a/makefiles/BuildNashorn.gmk b/makefiles/BuildNashorn.gmk
index d08f7e8f..96bedf44 100644
--- a/makefiles/BuildNashorn.gmk
+++ b/makefiles/BuildNashorn.gmk
@@ -71,7 +71,6 @@ $(eval $(call SetupJavaCompilation,BUILD_NASGEN,\
$(BUILD_NASGEN): $(BUILD_NASHORN)
# Copy classes to final classes dir and run nasgen to modify classes in jdk.nashorn.internal.objects package
-# Finally rename classes in jdk.nashorn.internal.objects package
$(NASHORN_OUTPUTDIR)/classes/_the.nasgen.run: $(BUILD_NASGEN)
$(ECHO) Running nasgen
$(MKDIR) -p $(@D)
@@ -80,9 +79,6 @@ $(NASHORN_OUTPUTDIR)/classes/_the.nasgen.run: $(BUILD_NASGEN)
$(FIXPATH) $(JAVA) \
-cp "$(NASHORN_OUTPUTDIR)/nasgen_classes$(PATH_SEP)$(NASHORN_OUTPUTDIR)/nashorn_classes" \
jdk.nashorn.internal.tools.nasgen.Main $(@D) jdk.nashorn.internal.objects $(@D)
- for f in `$(FIND) $(@D)/jdk/nashorn/internal/objects/ -name "*.class"`; do \
- mv "$$f" `$(ECHO) "$$f" | $(SED) "s/\.class$$/\.clazz/"`; \
- done
$(TOUCH) $@
# Version file needs to be processed with version numbers
@@ -104,7 +100,7 @@ $(eval $(call SetupArchive,BUILD_NASHORN_JAR,\
$(NASHORN_OUTPUTDIR)/classes/_the.nasgen.run \
$(VERSION_FILE),\
SRCS:=$(NASHORN_OUTPUTDIR)/classes,\
- SUFFIXES:=.class .clazz .js .properties Factory,\
+ SUFFIXES:=.class .js .properties Factory,\
MANIFEST:=$(NASHORN_TOPDIR)/src/META-INF/MANIFEST.MF,\
EXTRA_MANIFEST_ATTR:=$(MANIFEST_ATTRIBUTES),\
SKIP_METAINF:=true,\
diff --git a/src/jdk/internal/dynalink/DynamicLinker.java b/src/jdk/internal/dynalink/DynamicLinker.java
index c0930dae..155ff309 100644
--- a/src/jdk/internal/dynalink/DynamicLinker.java
+++ b/src/jdk/internal/dynalink/DynamicLinker.java
@@ -144,6 +144,9 @@ public class DynamicLinker {
private static final String CLASS_NAME = DynamicLinker.class.getName();
private static final String RELINK_METHOD_NAME = "relink";
+ private static final String INITIAL_LINK_CLASS_NAME = "java.lang.invoke.MethodHandleNatives";
+ private static final String INITIAL_LINK_METHOD_NAME = "linkCallSite";
+
private final LinkerServices linkerServices;
private final int runtimeContextArgCount;
private final boolean syncOnRelink;
@@ -262,20 +265,54 @@ public class DynamicLinker {
}
/**
- * Returns a stack trace element describing the location of the call site currently being relinked on the current
+ * Returns a stack trace element describing the location of the call site currently being linked on the current
* thread. The operation internally creates a Throwable object and inspects its stack trace, so it's potentially
* expensive. The recommended usage for it is in writing diagnostics code.
- * @return a stack trace element describing the location of the call site currently being relinked, or null if it is
- * not invoked while a call site is being relinked.
+ * @return a stack trace element describing the location of the call site currently being linked, or null if it is
+ * not invoked while a call site is being linked.
*/
- public static StackTraceElement getRelinkedCallSiteLocation() {
+ public static StackTraceElement getLinkedCallSiteLocation() {
final StackTraceElement[] trace = new Throwable().getStackTrace();
for(int i = 0; i < trace.length - 1; ++i) {
final StackTraceElement frame = trace[i];
- if(RELINK_METHOD_NAME.equals(frame.getMethodName()) && CLASS_NAME.equals(frame.getClassName())) {
+ if(isRelinkFrame(frame) || isInitialLinkFrame(frame)) {
return trace[i + 1];
}
}
return null;
}
+
+ /**
+ * Deprecated because of not precise name.
+ * @deprecated Use {@link #getLinkedCallSiteLocation()} instead.
+ * @return see non-deprecated method
+ */
+ @Deprecated
+ public static StackTraceElement getRelinkedCallSiteLocation() {
+ return getLinkedCallSiteLocation();
+ }
+
+ /**
+ * Returns true if the frame represents {@code MethodHandleNatives.linkCallSite()}, the frame immediately on top of
+ * the call site frame when the call site is being linked for the first time.
+ * @param frame the frame
+ * @return true if this frame represents {@code MethodHandleNatives.linkCallSite()}
+ */
+ private static boolean isInitialLinkFrame(final StackTraceElement frame) {
+ return testFrame(frame, INITIAL_LINK_METHOD_NAME, INITIAL_LINK_CLASS_NAME);
+ }
+
+ /**
+ * Returns true if the frame represents {@code DynamicLinker.relink()}, the frame immediately on top of the call
+ * site frame when the call site is being relinked (linked for second and subsequent times).
+ * @param frame the frame
+ * @return true if this frame represents {@code DynamicLinker.relink()}
+ */
+ private static boolean isRelinkFrame(final StackTraceElement frame) {
+ return testFrame(frame, RELINK_METHOD_NAME, CLASS_NAME);
+ }
+
+ private static boolean testFrame(final StackTraceElement frame, final String methodName, final String className) {
+ return methodName.equals(frame.getMethodName()) && className.equals(frame.getClassName());
+ }
}
diff --git a/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java b/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java
index 702c1509..0c8d3efd 100644
--- a/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java
+++ b/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java
@@ -86,9 +86,14 @@ package jdk.internal.dynalink.beans;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
+import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -109,10 +114,11 @@ import jdk.internal.dynalink.support.Lookup;
* @author Attila Szegedi
*/
abstract class AbstractJavaLinker implements GuardingDynamicLinker {
+
final Class<?> clazz;
private final MethodHandle classGuard;
private final MethodHandle assignableGuard;
- private final Map<String, AnnotatedMethodHandle> propertyGetters = new HashMap<>();
+ private final Map<String, AnnotatedDynamicMethod> propertyGetters = new HashMap<>();
private final Map<String, DynamicMethod> propertySetters = new HashMap<>();
private final Map<String, DynamicMethod> methods = new HashMap<>();
@@ -129,22 +135,19 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
// Add methods and properties
for(Method method: introspector.getMethods()) {
final String name = method.getName();
- final MethodHandle methodHandle = introspector.unreflect(method);
// Add method
- addMember(name, methodHandle, methods);
+ addMember(name, method, methods);
// Add the method as a property getter and/or setter
if(name.startsWith("get") && name.length() > 3 && method.getParameterTypes().length == 0) {
// Property getter
- setPropertyGetter(decapitalize(name.substring(3)), introspector.unreflect(
- getMostGenericGetter(method)), ValidationType.INSTANCE_OF);
+ setPropertyGetter(method, 3);
} else if(name.startsWith("is") && name.length() > 2 && method.getParameterTypes().length == 0 &&
method.getReturnType() == boolean.class) {
// Boolean property getter
- setPropertyGetter(decapitalize(name.substring(2)), introspector.unreflect(
- getMostGenericGetter(method)), ValidationType.INSTANCE_OF);
+ setPropertyGetter(method, 2);
} else if(name.startsWith("set") && name.length() > 3 && method.getParameterTypes().length == 1) {
// Property setter
- addMember(decapitalize(name.substring(3)), methodHandle, propertySetters);
+ addMember(decapitalize(name.substring(3)), method, propertySetters);
}
}
@@ -156,7 +159,8 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
setPropertyGetter(name, introspector.unreflectGetter(field), ValidationType.EXACT_CLASS);
}
if(!(Modifier.isFinal(field.getModifiers()) || propertySetters.containsKey(name))) {
- addMember(name, introspector.unreflectSetter(field), propertySetters);
+ addMember(name, new SimpleDynamicMethod(introspector.unreflectSetter(field), clazz, name),
+ propertySetters);
}
}
@@ -192,38 +196,135 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
abstract FacetIntrospector createFacetIntrospector();
+ Collection<String> getReadablePropertyNames() {
+ return getUnmodifiableKeys(propertyGetters);
+ }
+
+ Collection<String> getWritablePropertyNames() {
+ return getUnmodifiableKeys(propertySetters);
+ }
+
+ Collection<String> getMethodNames() {
+ return getUnmodifiableKeys(methods);
+ }
+
+ private static Collection<String> getUnmodifiableKeys(Map<String, ?> m) {
+ return Collections.unmodifiableCollection(m.keySet());
+ }
+
+ /**
+ * Sets the specified dynamic method to be the property getter for the specified property. Note that you can only
+ * use this when you're certain that the method handle does not belong to a caller-sensitive method. For properties
+ * that are caller-sensitive, you must use {@link #setPropertyGetter(String, SingleDynamicMethod, ValidationType)}
+ * instead.
+ * @param name name of the property
+ * @param handle the method handle that implements the property getter
+ * @param validationType the validation type for the property
+ */
+ private void setPropertyGetter(String name, SingleDynamicMethod handle, ValidationType validationType) {
+ propertyGetters.put(name, new AnnotatedDynamicMethod(handle, validationType));
+ }
+
+ /**
+ * Sets the specified reflective method to be the property getter for the specified property.
+ * @param getter the getter method
+ * @param prefixLen the getter prefix in the method name; should be 3 for getter names starting with "get" and 2 for
+ * names starting with "is".
+ */
+ private void setPropertyGetter(Method getter, int prefixLen) {
+ setPropertyGetter(decapitalize(getter.getName().substring(prefixLen)), createDynamicMethod(
+ getMostGenericGetter(getter)), ValidationType.INSTANCE_OF);
+ }
+
+ /**
+ * Sets the specified method handle to be the property getter for the specified property. Note that you can only
+ * use this when you're certain that the method handle does not belong to a caller-sensitive method. For properties
+ * that are caller-sensitive, you must use {@link #setPropertyGetter(String, SingleDynamicMethod, ValidationType)}
+ * instead.
+ * @param name name of the property
+ * @param handle the method handle that implements the property getter
+ * @param validationType the validation type for the property
+ */
void setPropertyGetter(String name, MethodHandle handle, ValidationType validationType) {
- propertyGetters.put(name, new AnnotatedMethodHandle(handle, validationType));
+ setPropertyGetter(name, new SimpleDynamicMethod(handle, clazz, name), validationType);
}
- private void addMember(String name, MethodHandle mh, Map<String, DynamicMethod> methodMap) {
+ private void addMember(String name, AccessibleObject ao, Map<String, DynamicMethod> methodMap) {
+ addMember(name, createDynamicMethod(ao), methodMap);
+ }
+
+ private void addMember(String name, SingleDynamicMethod method, Map<String, DynamicMethod> methodMap) {
final DynamicMethod existingMethod = methodMap.get(name);
- final DynamicMethod newMethod = addMember(mh, existingMethod, clazz, name);
+ final DynamicMethod newMethod = mergeMethods(method, existingMethod, clazz, name);
if(newMethod != existingMethod) {
methodMap.put(name, newMethod);
}
}
- static DynamicMethod createDynamicMethod(Iterable<MethodHandle> methodHandles, Class<?> clazz, String name) {
+ /**
+ * Given one or more reflective methods or constructors, creates a dynamic method that represents them all. The
+ * methods should represent all overloads of the same name (or all constructors of the class).
+ * @param members the reflective members
+ * @param clazz the class declaring the reflective members
+ * @param name the common name of the reflective members.
+ * @return a dynamic method representing all the specified reflective members.
+ */
+ static DynamicMethod createDynamicMethod(Iterable<? extends AccessibleObject> members, Class<?> clazz, String name) {
DynamicMethod dynMethod = null;
- for(MethodHandle methodHandle: methodHandles) {
- dynMethod = addMember(methodHandle, dynMethod, clazz, name);
+ for(AccessibleObject method: members) {
+ dynMethod = mergeMethods(createDynamicMethod(method), dynMethod, clazz, name);
}
return dynMethod;
}
- private static DynamicMethod addMember(MethodHandle mh, DynamicMethod existing, Class<?> clazz, String name) {
+ /**
+ * Given a reflective method or a constructor, creates a dynamic method that represents it. This method will
+ * distinguish between caller sensitive and ordinary methods/constructors, and create appropriate caller sensitive
+ * dynamic method when needed.
+ * @param m the reflective member
+ * @return the single dynamic method representing the reflective member
+ */
+ private static SingleDynamicMethod createDynamicMethod(AccessibleObject m) {
+ if(CallerSensitiveDetector.isCallerSensitive(m)) {
+ return new CallerSensitiveDynamicMethod(m);
+ }
+ final Member member = (Member)m;
+ return new SimpleDynamicMethod(unreflectSafely(m), member.getDeclaringClass(), member.getName());
+ }
+
+ /**
+ * Unreflects a method handle from a Method or a Constructor using safe (zero-privilege) unreflection. Should be
+ * only used for methods and constructors that are not caller sensitive. If a caller sensitive method were
+ * unreflected through this mechanism, it would not be a security issue, but would be bound to the zero-privilege
+ * unreflector as its caller, and thus completely useless.
+ * @param m the method or constructor
+ * @return the method handle
+ */
+ private static MethodHandle unreflectSafely(AccessibleObject m) {
+ if(m instanceof Method) {
+ final Method reflMethod = (Method)m;
+ final MethodHandle handle = SafeUnreflector.unreflect(reflMethod);
+ if(Modifier.isStatic(reflMethod.getModifiers())) {
+ return StaticClassIntrospector.editStaticMethodHandle(handle);
+ }
+ return handle;
+ }
+ return StaticClassIntrospector.editConstructorMethodHandle(SafeUnreflector.unreflectConstructor(
+ (Constructor<?>)m));
+ }
+
+ private static DynamicMethod mergeMethods(SingleDynamicMethod method, DynamicMethod existing, Class<?> clazz, String name) {
if(existing == null) {
- return new SimpleDynamicMethod(mh, clazz, name);
- } else if(existing.contains(mh)) {
+ return method;
+ } else if(existing.contains(method)) {
return existing;
- } else if(existing instanceof SimpleDynamicMethod) {
+ } else if(existing instanceof SingleDynamicMethod) {
final OverloadedDynamicMethod odm = new OverloadedDynamicMethod(clazz, name);
- odm.addMethod(((SimpleDynamicMethod)existing));
- odm.addMethod(mh);
+ odm.addMethod(((SingleDynamicMethod)existing));
+ odm.addMethod(method);
return odm;
} else if(existing instanceof OverloadedDynamicMethod) {
- ((OverloadedDynamicMethod)existing).addMethod(mh);
+ ((OverloadedDynamicMethod)existing).addMethod(method);
return existing;
}
throw new AssertionError();
@@ -296,7 +397,7 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
private GuardedInvocation getCallPropWithThis(CallSiteDescriptor callSiteDescriptor, LinkerServices linkerServices) {
switch(callSiteDescriptor.getNameTokenCount()) {
case 3: {
- return createGuardedDynamicMethodInvocation(callSiteDescriptor.getMethodType(), linkerServices,
+ return createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), methods);
}
default: {
@@ -305,16 +406,16 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
}
}
- private GuardedInvocation createGuardedDynamicMethodInvocation(MethodType callSiteType,
+ private GuardedInvocation createGuardedDynamicMethodInvocation(CallSiteDescriptor callSiteDescriptor,
LinkerServices linkerServices, String methodName, Map<String, DynamicMethod> methodMap){
- final MethodHandle inv = getDynamicMethodInvocation(callSiteType, linkerServices, methodName, methodMap);
- return inv == null ? null : new GuardedInvocation(inv, getClassGuard(callSiteType));
+ final MethodHandle inv = getDynamicMethodInvocation(callSiteDescriptor, linkerServices, methodName, methodMap);
+ return inv == null ? null : new GuardedInvocation(inv, getClassGuard(callSiteDescriptor.getMethodType()));
}
- private static MethodHandle getDynamicMethodInvocation(MethodType callSiteType, LinkerServices linkerServices,
- String methodName, Map<String, DynamicMethod> methodMap) {
+ private static MethodHandle getDynamicMethodInvocation(CallSiteDescriptor callSiteDescriptor,
+ LinkerServices linkerServices, String methodName, Map<String, DynamicMethod> methodMap) {
final DynamicMethod dynaMethod = getDynamicMethod(methodName, methodMap);
- return dynaMethod != null ? dynaMethod.getInvocation(callSiteType, linkerServices) : null;
+ return dynaMethod != null ? dynaMethod.getInvocation(callSiteDescriptor, linkerServices) : null;
}
private static DynamicMethod getDynamicMethod(String methodName, Map<String, DynamicMethod> methodMap) {
@@ -322,13 +423,13 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
return dynaMethod != null ? dynaMethod : getExplicitSignatureDynamicMethod(methodName, methodMap);
}
- private static SimpleDynamicMethod getExplicitSignatureDynamicMethod(String methodName,
+ private static SingleDynamicMethod getExplicitSignatureDynamicMethod(String methodName,
Map<String, DynamicMethod> methodsMap) {
// What's below is meant to support the "name(type, type, ...)" syntax that programmers can use in a method name
// to manually pin down an exact overloaded variant. This is not usually required, as the overloaded method
// resolution works correctly in almost every situation. However, in presence of many language-specific
// conversions with a radically dynamic language, most overloaded methods will end up being constantly selected
- // at invocation time, so a programmer knowledgable of the situation might choose to pin down an exact overload
+ // at invocation time, so a programmer knowledgeable of the situation might choose to pin down an exact overload
// for performance reasons.
// Is the method name lexically of the form "name(types)"?
@@ -377,8 +478,8 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
final MethodType setterType = type.dropParameterTypes(1, 2);
// Bind property setter handle to the expected setter type and linker services. Type is
// MethodHandle(Object, String, Object)
- final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0, setterType,
- linkerServices);
+ final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0,
+ CallSiteDescriptorFactory.dropParameterTypes(callSiteDescriptor, 1, 2), linkerServices);
// Cast getter to MethodHandle(O, N, V)
final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType(
@@ -415,9 +516,8 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
case 3: {
// Must have two arguments: target object and property value
assertParameterCount(callSiteDescriptor, 2);
- final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor.getMethodType(),
- linkerServices, callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND),
- propertySetters);
+ final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
+ callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), propertySetters);
// If we have a property setter with this name, this composite operation will always stop here
if(gi != null) {
return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS);
@@ -435,14 +535,13 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
private static final Lookup privateLookup = new Lookup(MethodHandles.lookup());
- private static final MethodHandle IS_ANNOTATED_HANDLE_NOT_NULL = Guards.isNotNull().asType(MethodType.methodType(
- boolean.class, AnnotatedMethodHandle.class));
- private static final MethodHandle CONSTANT_NULL_DROP_ANNOTATED_HANDLE = MethodHandles.dropArguments(
- MethodHandles.constant(Object.class, null), 0, AnnotatedMethodHandle.class);
- private static final MethodHandle GET_ANNOTATED_HANDLE = privateLookup.findGetter(AnnotatedMethodHandle.class,
- "handle", MethodHandle.class);
- private static final MethodHandle GENERIC_PROPERTY_GETTER_HANDLER_INVOKER = MethodHandles.filterArguments(
- MethodHandles.invoker(MethodType.methodType(Object.class, Object.class)), 0, GET_ANNOTATED_HANDLE);
+ private static final MethodHandle IS_ANNOTATED_METHOD_NOT_NULL = Guards.isNotNull().asType(MethodType.methodType(
+ boolean.class, AnnotatedDynamicMethod.class));
+ private static final MethodHandle CONSTANT_NULL_DROP_ANNOTATED_METHOD = MethodHandles.dropArguments(
+ MethodHandles.constant(Object.class, null), 0, AnnotatedDynamicMethod.class);
+ private static final MethodHandle GET_ANNOTATED_METHOD = privateLookup.findVirtual(AnnotatedDynamicMethod.class,
+ "getTarget", MethodType.methodType(MethodHandle.class, MethodHandles.Lookup.class));
+ private static final MethodHandle GETTER_INVOKER = MethodHandles.invoker(MethodType.methodType(Object.class, Object.class));
private GuardedInvocationComponent getPropertyGetter(CallSiteDescriptor callSiteDescriptor,
LinkerServices linkerServices, List<String> ops) throws Exception {
@@ -455,16 +554,20 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
// What's below is basically:
// foldArguments(guardWithTest(isNotNull, invoke(get_handle), null|nextComponent.invocation), get_getter_handle)
// only with a bunch of method signature adjustments. Basically, retrieve method getter
- // AnnotatedMethodHandle; if it is non-null, invoke its "handle" field, otherwise either return null,
+ // AnnotatedDynamicMethod; if it is non-null, invoke its "handle" field, otherwise either return null,
// or delegate to next component's invocation.
final MethodHandle typedGetter = linkerServices.asType(getPropertyGetterHandle, type.changeReturnType(
- AnnotatedMethodHandle.class));
- // Object(AnnotatedMethodHandle, Object)->R(AnnotatedMethodHandle, T0)
- final MethodHandle invokeHandleTyped = linkerServices.asType(GENERIC_PROPERTY_GETTER_HANDLER_INVOKER,
- MethodType.methodType(type.returnType(), AnnotatedMethodHandle.class, type.parameterType(0)));
+ AnnotatedDynamicMethod.class));
+ final MethodHandle callSiteBoundMethodGetter = MethodHandles.insertArguments(
+ GET_ANNOTATED_METHOD, 1, callSiteDescriptor.getLookup());
+ final MethodHandle callSiteBoundInvoker = MethodHandles.filterArguments(GETTER_INVOKER, 0,
+ callSiteBoundMethodGetter);
+ // Object(AnnotatedDynamicMethod, Object)->R(AnnotatedDynamicMethod, T0)
+ final MethodHandle invokeHandleTyped = linkerServices.asType(callSiteBoundInvoker,
+ MethodType.methodType(type.returnType(), AnnotatedDynamicMethod.class, type.parameterType(0)));
// Since it's in the target of a fold, drop the unnecessary second argument
- // R(AnnotatedMethodHandle, T0)->R(AnnotatedMethodHandle, T0, T1)
+ // R(AnnotatedDynamicMethod, T0)->R(AnnotatedDynamicMethod, T0, T1)
final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandleTyped, 2,
type.parameterType(1));
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
@@ -472,19 +575,19 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
final MethodHandle fallbackFolded;
if(nextComponent == null) {
- // Object(AnnotatedMethodHandle)->R(AnnotatedMethodHandle, T0, T1); returns constant null
- fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_ANNOTATED_HANDLE, 1,
- type.parameterList()).asType(type.insertParameterTypes(0, AnnotatedMethodHandle.class));
+ // Object(AnnotatedDynamicMethod)->R(AnnotatedDynamicMethod, T0, T1); returns constant null
+ fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_ANNOTATED_METHOD, 1,
+ type.parameterList()).asType(type.insertParameterTypes(0, AnnotatedDynamicMethod.class));
} else {
- // R(T0, T1)->R(AnnotatedMethodHAndle, T0, T1); adapts the next component's invocation to drop the
+ // R(T0, T1)->R(AnnotatedDynamicMethod, T0, T1); adapts the next component's invocation to drop the
// extra argument resulting from fold
fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(),
- 0, AnnotatedMethodHandle.class);
+ 0, AnnotatedDynamicMethod.class);
}
- // fold(R(AnnotatedMethodHandle, T0, T1), AnnotatedMethodHandle(T0, T1))
+ // fold(R(AnnotatedDynamicMethod, T0, T1), AnnotatedDynamicMethod(T0, T1))
final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
- IS_ANNOTATED_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
+ IS_ANNOTATED_METHOD_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
if(nextComponent == null) {
return getClassGuardedInvocationComponent(compositeGetter, type);
}
@@ -494,13 +597,13 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
// Must have exactly one argument: receiver
assertParameterCount(callSiteDescriptor, 1);
// Fixed name
- final AnnotatedMethodHandle annGetter = propertyGetters.get(callSiteDescriptor.getNameToken(
+ final AnnotatedDynamicMethod annGetter = propertyGetters.get(callSiteDescriptor.getNameToken(
CallSiteDescriptor.NAME_OPERAND));
if(annGetter == null) {
// We have no such property, always delegate to the next component operation
return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops);
}
- final MethodHandle getter = annGetter.handle;
+ final MethodHandle getter = annGetter.getInvocation(callSiteDescriptor, linkerServices);
// NOTE: since property getters (not field getters!) are no-arg, we don't have to worry about them being
// overloaded in a subclass. Therefore, we can discover the most abstract superclass that has the
// method, and use that as the guard with Guards.isInstance() for a more stably linked call site. If
@@ -508,6 +611,7 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
// NOTE: No delegation to the next component operation if we have a property with this name, even if its
// value is null.
final ValidationType validationType = annGetter.validationType;
+ // TODO: we aren't using the type that declares the most generic getter here!
return new GuardedInvocationComponent(linkerServices.asType(getter, type), getGuard(validationType,
type), clazz, validationType);
}
@@ -623,14 +727,15 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
// args are dropped; this makes handles with first three args conform to "Object, String, Object" though, which is
// a typical property setter with variable name signature (target, name, value).
private static final MethodHandle GET_PROPERTY_SETTER_HANDLE = MethodHandles.dropArguments(MethodHandles.dropArguments(
- privateLookup.findOwnSpecial("getPropertySetterHandle", MethodHandle.class, MethodType.class,
+ privateLookup.findOwnSpecial("getPropertySetterHandle", MethodHandle.class, CallSiteDescriptor.class,
LinkerServices.class, Object.class), 3, Object.class), 5, Object.class);
// Type is MethodHandle(MethodType, LinkerServices, Object, String, Object)
private final MethodHandle getPropertySetterHandle = GET_PROPERTY_SETTER_HANDLE.bindTo(this);
@SuppressWarnings("unused")
- private MethodHandle getPropertySetterHandle(MethodType setterType, LinkerServices linkerServices, Object id) {
- return getDynamicMethodInvocation(setterType, linkerServices, String.valueOf(id), propertySetters);
+ private MethodHandle getPropertySetterHandle(CallSiteDescriptor setterDescriptor, LinkerServices linkerServices,
+ Object id) {
+ return getDynamicMethodInvocation(setterDescriptor, linkerServices, String.valueOf(id), propertySetters);
}
private static MethodHandle GET_DYNAMIC_METHOD = MethodHandles.dropArguments(privateLookup.findOwnSpecial(
@@ -689,13 +794,24 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
return null;
}
- private static final class AnnotatedMethodHandle {
- final MethodHandle handle;
+ private static final class AnnotatedDynamicMethod {
+ private final SingleDynamicMethod method;
/*private*/ final ValidationType validationType;
- AnnotatedMethodHandle(MethodHandle handle, ValidationType validationType) {
- this.handle = handle;
+ AnnotatedDynamicMethod(SingleDynamicMethod method, ValidationType validationType) {
+ this.method = method;
this.validationType = validationType;
}
+
+ MethodHandle getInvocation(CallSiteDescriptor callSiteDescriptor, LinkerServices linkerServices) {
+ return method.getInvocation(callSiteDescriptor, linkerServices);
+ }
+
+ @SuppressWarnings("unused")
+ MethodHandle getTarget(MethodHandles.Lookup lookup) {
+ MethodHandle inv = method.getTarget(lookup);
+ assert inv != null;
+ return inv;
+ }
}
}
diff --git a/src/jdk/internal/dynalink/beans/ApplicableOverloadedMethods.java b/src/jdk/internal/dynalink/beans/ApplicableOverloadedMethods.java
index a232caf1..39a03a8e 100644
--- a/src/jdk/internal/dynalink/beans/ApplicableOverloadedMethods.java
+++ b/src/jdk/internal/dynalink/beans/ApplicableOverloadedMethods.java
@@ -83,7 +83,6 @@
package jdk.internal.dynalink.beans;
-import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.util.LinkedList;
import java.util.List;
@@ -95,7 +94,7 @@ import jdk.internal.dynalink.support.TypeUtilities;
* @author Attila Szegedi
*/
class ApplicableOverloadedMethods {
- private final List<MethodHandle> methods;
+ private final List<SingleDynamicMethod> methods;
private final boolean varArgs;
/**
@@ -106,10 +105,10 @@ class ApplicableOverloadedMethods {
* @param test applicability test. One of {@link #APPLICABLE_BY_SUBTYPING},
* {@link #APPLICABLE_BY_METHOD_INVOCATION_CONVERSION}, or {@link #APPLICABLE_BY_VARIABLE_ARITY}.
*/
- ApplicableOverloadedMethods(final List<MethodHandle> methods, final MethodType callSiteType,
+ ApplicableOverloadedMethods(final List<SingleDynamicMethod> methods, final MethodType callSiteType,
final ApplicabilityTest test) {
this.methods = new LinkedList<>();
- for(MethodHandle m: methods) {
+ for(SingleDynamicMethod m: methods) {
if(test.isApplicable(callSiteType, m)) {
this.methods.add(m);
}
@@ -122,7 +121,7 @@ class ApplicableOverloadedMethods {
*
* @return list of all methods.
*/
- List<MethodHandle> getMethods() {
+ List<SingleDynamicMethod> getMethods() {
return methods;
}
@@ -131,12 +130,12 @@ class ApplicableOverloadedMethods {
*
* @return a list of maximally specific methods.
*/
- List<MethodHandle> findMaximallySpecificMethods() {
+ List<SingleDynamicMethod> findMaximallySpecificMethods() {
return MaximallySpecific.getMaximallySpecificMethods(methods, varArgs);
}
abstract static class ApplicabilityTest {
- abstract boolean isApplicable(MethodType callSiteType, MethodHandle method);
+ abstract boolean isApplicable(MethodType callSiteType, SingleDynamicMethod method);
}
/**
@@ -144,8 +143,8 @@ class ApplicableOverloadedMethods {
*/
static final ApplicabilityTest APPLICABLE_BY_SUBTYPING = new ApplicabilityTest() {
@Override
- boolean isApplicable(MethodType callSiteType, MethodHandle method) {
- final MethodType methodType = method.type();
+ boolean isApplicable(MethodType callSiteType, SingleDynamicMethod method) {
+ final MethodType methodType = method.getMethodType();
final int methodArity = methodType.parameterCount();
if(methodArity != callSiteType.parameterCount()) {
return false;
@@ -166,8 +165,8 @@ class ApplicableOverloadedMethods {
*/
static final ApplicabilityTest APPLICABLE_BY_METHOD_INVOCATION_CONVERSION = new ApplicabilityTest() {
@Override
- boolean isApplicable(MethodType callSiteType, MethodHandle method) {
- final MethodType methodType = method.type();
+ boolean isApplicable(MethodType callSiteType, SingleDynamicMethod method) {
+ final MethodType methodType = method.getMethodType();
final int methodArity = methodType.parameterCount();
if(methodArity != callSiteType.parameterCount()) {
return false;
@@ -189,11 +188,11 @@ class ApplicableOverloadedMethods {
*/
static final ApplicabilityTest APPLICABLE_BY_VARIABLE_ARITY = new ApplicabilityTest() {
@Override
- boolean isApplicable(MethodType callSiteType, MethodHandle method) {
- if(!method.isVarargsCollector()) {
+ boolean isApplicable(MethodType callSiteType, SingleDynamicMethod method) {
+ if(!method.isVarArgs()) {
return false;
}
- final MethodType methodType = method.type();
+ final MethodType methodType = method.getMethodType();
final int methodArity = methodType.parameterCount();
final int fixArity = methodArity - 1;
final int callSiteArity = callSiteType.parameterCount();
diff --git a/src/jdk/internal/dynalink/beans/BeansLinker.java b/src/jdk/internal/dynalink/beans/BeansLinker.java
index 85811235..e0c14b0d 100644
--- a/src/jdk/internal/dynalink/beans/BeansLinker.java
+++ b/src/jdk/internal/dynalink/beans/BeansLinker.java
@@ -84,6 +84,8 @@
package jdk.internal.dynalink.beans;
import java.lang.invoke.MethodHandles;
+import java.util.Collection;
+import java.util.Collections;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.DynamicLinkerFactory;
import jdk.internal.dynalink.linker.GuardedInvocation;
@@ -166,6 +168,72 @@ public class BeansLinker implements GuardingDynamicLinker {
return obj instanceof DynamicMethod;
}
+ /**
+ * Returns a collection of names of all readable instance properties of a class.
+ * @param clazz the class
+ * @return a collection of names of all readable instance properties of a class.
+ */
+ public static Collection<String> getReadableInstancePropertyNames(Class<?> clazz) {
+ TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz);
+ if(linker instanceof BeanLinker) {
+ return ((BeanLinker)linker).getReadablePropertyNames();
+ }
+ return Collections.emptySet();
+ }
+
+ /**
+ * Returns a collection of names of all writable instance properties of a class.
+ * @param clazz the class
+ * @return a collection of names of all writable instance properties of a class.
+ */
+ public static Collection<String> getWritableInstancePropertyNames(Class<?> clazz) {
+ TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz);
+ if(linker instanceof BeanLinker) {
+ return ((BeanLinker)linker).getWritablePropertyNames();
+ }
+ return Collections.emptySet();
+ }
+
+ /**
+ * Returns a collection of names of all instance methods of a class.
+ * @param clazz the class
+ * @return a collection of names of all instance methods of a class.
+ */
+ public static Collection<String> getInstanceMethodNames(Class<?> clazz) {
+ TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz);
+ if(linker instanceof BeanLinker) {
+ return ((BeanLinker)linker).getMethodNames();
+ }
+ return Collections.emptySet();
+ }
+
+ /**
+ * Returns a collection of names of all readable static properties of a class.
+ * @param clazz the class
+ * @return a collection of names of all readable static properties of a class.
+ */
+ public static Collection<String> getReadableStaticPropertyNames(Class<?> clazz) {
+ return StaticClassLinker.getReadableStaticPropertyNames(clazz);
+ }
+
+ /**
+ * Returns a collection of names of all writable static properties of a class.
+ * @param clazz the class
+ * @return a collection of names of all writable static properties of a class.
+ */
+ public static Collection<String> getWritableStaticPropertyNames(Class<?> clazz) {
+ return StaticClassLinker.getWritableStaticPropertyNames(clazz);
+ }
+
+ /**
+ * Returns a collection of names of all static methods of a class.
+ * @param clazz the class
+ * @return a collection of names of all static methods of a class.
+ */
+ public static Collection<String> getStaticMethodNames(Class<?> clazz) {
+ return StaticClassLinker.getStaticMethodNames(clazz);
+ }
+
@Override
public GuardedInvocation getGuardedInvocation(LinkRequest request, final LinkerServices linkerServices)
throws Exception {
diff --git a/src/jdk/internal/dynalink/beans/CallerSensitiveDetector.java b/src/jdk/internal/dynalink/beans/CallerSensitiveDetector.java
new file mode 100644
index 00000000..466bafe6
--- /dev/null
+++ b/src/jdk/internal/dynalink/beans/CallerSensitiveDetector.java
@@ -0,0 +1,148 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file, and Oracle licenses the original version of this file under the BSD
+ * license:
+ */
+/*
+ Copyright 2009-2013 Attila Szegedi
+
+ Licensed under both the Apache License, Version 2.0 (the "Apache License")
+ and the BSD License (the "BSD License"), with licensee being free to
+ choose either of the two at their discretion.
+
+ You may not use this file except in compliance with either the Apache
+ License or the BSD License.
+
+ If you choose to use this file in compliance with the Apache License, the
+ following notice applies to you:
+
+ You may obtain a copy of the Apache License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ permissions and limitations under the License.
+
+ If you choose to use this file in compliance with the BSD License, the
+ following notice applies to you:
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the copyright holder nor the names of
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package jdk.internal.dynalink.beans;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AccessibleObject;
+import sun.reflect.CallerSensitive;
+
+/**
+ * Utility class that determines if a method or constructor is caller sensitive. It actually encapsulates two different
+ * strategies for determining caller sensitivity; a more robust one that works if Dynalink runs as code with access
+ * to {@code sun.reflect} package, and an unprivileged one that is used when Dynalink doesn't have access to that
+ * package. Note that even the unprivileged strategy is ordinarily robust, but it relies on the {@code toString} method
+ * of the annotation. If an attacker were to use a different annotation to spoof the string representation of the
+ * {@code CallerSensitive} annotation, they could designate their own methods as caller sensitive. This however does not
+ * escalate privileges, only causes Dynalink to never cache method handles for such methods, so all it would do would
+ * decrease the performance in linking such methods. In the opposite case when an attacker could trick Dynalink into not
+ * recognizing genuine {@code CallerSensitive} annotations, Dynalink would treat caller sensitive methods as ordinary
+ * methods, and would cache them bound to a zero-privilege delegate as the caller (just what Dynalink did before it
+ * could handle caller-sensitive methods). That would practically render caller-sensitive methods exposed through
+ * Dynalink unusable, but again, can not lead to any privilege escalations. Therefore, even the less robust unprivileged
+ * strategy is safe; the worst thing a successful attack against it can achieve is slight reduction in Dynalink-exposed
+ * functionality or performance.
+ */
+public class CallerSensitiveDetector {
+
+ private static final DetectionStrategy DETECTION_STRATEGY = getDetectionStrategy();
+
+ static boolean isCallerSensitive(AccessibleObject ao) {
+ return DETECTION_STRATEGY.isCallerSensitive(ao);
+ }
+
+ private static DetectionStrategy getDetectionStrategy() {
+ try {
+ return new PrivilegedDetectionStrategy();
+ } catch(Throwable t) {
+ return new UnprivilegedDetectionStrategy();
+ }
+ }
+
+ private abstract static class DetectionStrategy {
+ abstract boolean isCallerSensitive(AccessibleObject ao);
+ }
+
+ private static class PrivilegedDetectionStrategy extends DetectionStrategy {
+ private static final Class<? extends Annotation> CALLER_SENSITIVE_ANNOTATION_CLASS = CallerSensitive.class;
+
+ @Override
+ boolean isCallerSensitive(AccessibleObject ao) {
+ return ao.getAnnotation(CALLER_SENSITIVE_ANNOTATION_CLASS) != null;
+ }
+ }
+
+ private static class UnprivilegedDetectionStrategy extends DetectionStrategy {
+ private static final String CALLER_SENSITIVE_ANNOTATION_STRING = "@sun.reflect.CallerSensitive()";
+
+ @Override
+ boolean isCallerSensitive(AccessibleObject o) {
+ for(Annotation a: o.getAnnotations()) {
+ if(String.valueOf(a).equals(CALLER_SENSITIVE_ANNOTATION_STRING)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+}
diff --git a/src/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java b/src/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java
new file mode 100644
index 00000000..1e274d51
--- /dev/null
+++ b/src/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java
@@ -0,0 +1,158 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file, and Oracle licenses the original version of this file under the BSD
+ * license:
+ */
+/*
+ Copyright 2009-2013 Attila Szegedi
+
+ Licensed under both the Apache License, Version 2.0 (the "Apache License")
+ and the BSD License (the "BSD License"), with licensee being free to
+ choose either of the two at their discretion.
+
+ You may not use this file except in compliance with either the Apache
+ License or the BSD License.
+
+ If you choose to use this file in compliance with the Apache License, the
+ following notice applies to you:
+
+ You may obtain a copy of the Apache License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ permissions and limitations under the License.
+
+ If you choose to use this file in compliance with the BSD License, the
+ following notice applies to you:
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the copyright holder nor the names of
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package jdk.internal.dynalink.beans;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import jdk.internal.dynalink.support.Lookup;
+
+/**
+ * A dynamic method bound to exactly one Java method or constructor that is caller sensitive. Since the target method is
+ * caller sensitive, it doesn't cache a method handle but rather uses the passed lookup object in
+ * {@link #getTarget(java.lang.invoke.MethodHandles.Lookup)} to unreflect a method handle from the reflective member on
+ * every request.
+ *
+ * @author Attila Szegedi
+ */
+class CallerSensitiveDynamicMethod extends SingleDynamicMethod {
+ // Typed as "AccessibleObject" as it can be either a method or a constructor.
+ // If we were Java8-only, we could use java.lang.reflect.Executable
+ private final AccessibleObject target;
+ private final MethodType type;
+
+ public CallerSensitiveDynamicMethod(AccessibleObject target) {
+ super(getName(target));
+ this.target = target;
+ this.type = getMethodType(target);
+ }
+
+ private static String getName(AccessibleObject target) {
+ final Member m = (Member)target;
+ return getMethodNameWithSignature(getMethodType(target), getClassAndMethodName(m.getDeclaringClass(),
+ m.getName()));
+ }
+
+ @Override
+ MethodType getMethodType() {
+ return type;
+ }
+
+ private static MethodType getMethodType(AccessibleObject ao) {
+ final boolean isMethod = ao instanceof Method;
+ final Class<?> rtype = isMethod ? ((Method)ao).getReturnType() : ((Constructor<?>)ao).getDeclaringClass();
+ final Class<?>[] ptypes = isMethod ? ((Method)ao).getParameterTypes() : ((Constructor<?>)ao).getParameterTypes();
+ final MethodType type = MethodType.methodType(rtype, ptypes);
+ final Member m = (Member)ao;
+ return type.insertParameterTypes(0,
+ isMethod ?
+ Modifier.isStatic(m.getModifiers()) ?
+ Object.class :
+ m.getDeclaringClass() :
+ StaticClass.class);
+ }
+
+ @Override
+ boolean isVarArgs() {
+ return target instanceof Method ? ((Method)target).isVarArgs() : ((Constructor<?>)target).isVarArgs();
+ }
+
+ @Override
+ MethodHandle getTarget(MethodHandles.Lookup lookup) {
+ if(target instanceof Method) {
+ final MethodHandle mh = Lookup.unreflect(lookup, (Method)target);
+ if(Modifier.isStatic(((Member)target).getModifiers())) {
+ return StaticClassIntrospector.editStaticMethodHandle(mh);
+ }
+ return mh;
+ }
+ return StaticClassIntrospector.editConstructorMethodHandle(Lookup.unreflectConstructor(lookup,
+ (Constructor<?>)target));
+ }
+}
diff --git a/src/jdk/internal/dynalink/beans/ClassString.java b/src/jdk/internal/dynalink/beans/ClassString.java
index dfcb3786..8ab45727 100644
--- a/src/jdk/internal/dynalink/beans/ClassString.java
+++ b/src/jdk/internal/dynalink/beans/ClassString.java
@@ -155,8 +155,8 @@ final class ClassString {
}
List<MethodHandle> getMaximallySpecifics(List<MethodHandle> methods, LinkerServices linkerServices, boolean varArg) {
- return MaximallySpecific.getMaximallySpecificMethods(getApplicables(methods, linkerServices, varArg), varArg,
- classes, linkerServices);
+ return MaximallySpecific.getMaximallySpecificMethodHandles(getApplicables(methods, linkerServices, varArg),
+ varArg, classes, linkerServices);
}
/**
diff --git a/src/jdk/internal/dynalink/beans/DynamicMethod.java b/src/jdk/internal/dynalink/beans/DynamicMethod.java
index aee69ff7..6beb92b1 100644
--- a/src/jdk/internal/dynalink/beans/DynamicMethod.java
+++ b/src/jdk/internal/dynalink/beans/DynamicMethod.java
@@ -84,8 +84,7 @@
package jdk.internal.dynalink.beans;
import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodType;
-import java.util.StringTokenizer;
+import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.LinkerServices;
/**
@@ -116,45 +115,28 @@ abstract class DynamicMethod {
* is a variable arguments (vararg) method, it will pack the extra arguments in an array before the invocation of
* the underlying method if it is not already done.
*
- * @param callSiteType the method type at a call site
+ * @param callSiteDescriptor the descriptor of the call site
* @param linkerServices linker services. Used for language-specific type conversions.
* @return an invocation suitable for calling the method from the specified call site.
*/
- abstract MethodHandle getInvocation(MethodType callSiteType, LinkerServices linkerServices);
+ abstract MethodHandle getInvocation(CallSiteDescriptor callSiteDescriptor, LinkerServices linkerServices);
/**
- * Returns a simple dynamic method representing a single underlying Java method (possibly selected among several
+ * Returns a single dynamic method representing a single underlying Java method (possibly selected among several
* overloads) with formal parameter types exactly matching the passed signature.
* @param paramTypes the comma-separated list of requested parameter type names. The names will match both
* qualified and unqualified type names.
- * @return a simple dynamic method representing a single underlying Java method, or null if none of the Java methods
+ * @return a single dynamic method representing a single underlying Java method, or null if none of the Java methods
* behind this dynamic method exactly match the requested parameter types.
*/
- abstract SimpleDynamicMethod getMethodForExactParamTypes(String paramTypes);
+ abstract SingleDynamicMethod getMethodForExactParamTypes(String paramTypes);
/**
- * True if this dynamic method already contains a method handle with an identical signature as the passed in method
- * handle.
- * @param mh the method handle to check
- * @return true if it already contains an equivalent method handle.
+ * True if this dynamic method already contains a method with an identical signature as the passed in method.
+ * @param method the method to check
+ * @return true if it already contains an equivalent method.
*/
- abstract boolean contains(MethodHandle mh);
-
- static boolean typeMatchesDescription(String paramTypes, MethodType type) {
- final StringTokenizer tok = new StringTokenizer(paramTypes, ", ");
- for(int i = 1; i < type.parameterCount(); ++i) { // i = 1 as we ignore the receiver
- if(!(tok.hasMoreTokens() && typeNameMatches(tok.nextToken(), type.parameterType(i)))) {
- return false;
- }
- }
- return !tok.hasMoreTokens();
- }
-
- private static boolean typeNameMatches(String typeName, Class<?> type) {
- final int lastDot = typeName.lastIndexOf('.');
- final String fullTypeName = type.getCanonicalName();
- return lastDot != -1 && fullTypeName.endsWith(typeName.substring(lastDot)) || typeName.equals(fullTypeName);
- }
+ abstract boolean contains(SingleDynamicMethod method);
static String getClassAndMethodName(Class<?> clazz, String name) {
final String clazzName = clazz.getCanonicalName();
diff --git a/src/jdk/internal/dynalink/beans/DynamicMethodLinker.java b/src/jdk/internal/dynalink/beans/DynamicMethodLinker.java
index d8ceeea0..32942b9a 100644
--- a/src/jdk/internal/dynalink/beans/DynamicMethodLinker.java
+++ b/src/jdk/internal/dynalink/beans/DynamicMethodLinker.java
@@ -85,12 +85,12 @@ package jdk.internal.dynalink.beans;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
import jdk.internal.dynalink.CallSiteDescriptor;
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.Guards;
/**
@@ -110,19 +110,18 @@ class DynamicMethodLinker implements TypeBasedGuardingDynamicLinker {
return null;
}
final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor();
- if(desc.getNameTokenCount() != 2 && desc.getNameToken(CallSiteDescriptor.SCHEME) != "dyn") {
+ if(desc.getNameTokenCount() != 2 && desc.getNameToken(CallSiteDescriptor.SCHEME) != "dyn") {
return null;
}
final String operator = desc.getNameToken(CallSiteDescriptor.OPERATOR);
if(operator == "call") {
- final MethodType type = desc.getMethodType();
- final MethodHandle invocation = ((DynamicMethod)receiver).getInvocation(type.dropParameterTypes(0, 1),
- linkerServices);
+ final MethodHandle invocation = ((DynamicMethod)receiver).getInvocation(
+ CallSiteDescriptorFactory.dropParameterTypes(desc, 0, 1), linkerServices);
if(invocation == null) {
return null;
}
- return new GuardedInvocation(MethodHandles.dropArguments(invocation, 0, type.parameterType(0)),
- Guards.getIdentityGuard(receiver));
+ return new GuardedInvocation(MethodHandles.dropArguments(invocation, 0,
+ desc.getMethodType().parameterType(0)), Guards.getIdentityGuard(receiver));
}
return null;
}
diff --git a/src/jdk/internal/dynalink/beans/FacetIntrospector.java b/src/jdk/internal/dynalink/beans/FacetIntrospector.java
index f4fbd824..97e431ca 100644
--- a/src/jdk/internal/dynalink/beans/FacetIntrospector.java
+++ b/src/jdk/internal/dynalink/beans/FacetIntrospector.java
@@ -167,10 +167,6 @@ abstract class FacetIntrospector {
return editMethodHandle(SafeUnreflector.unreflectSetter(field));
}
- MethodHandle unreflect(Method method) {
- return editMethodHandle(SafeUnreflector.unreflect(method));
- }
-
/**
* Returns an edited method handle. A facet might need to edit an unreflected method handle before it is usable with
* the facet. By default, returns the passed method handle unchanged. The class' static facet will introduce a
diff --git a/src/jdk/internal/dynalink/beans/MaximallySpecific.java b/src/jdk/internal/dynalink/beans/MaximallySpecific.java
index 182fd016..3ee8e41a 100644
--- a/src/jdk/internal/dynalink/beans/MaximallySpecific.java
+++ b/src/jdk/internal/dynalink/beans/MaximallySpecific.java
@@ -105,10 +105,58 @@ class MaximallySpecific {
* @param varArgs whether to assume the methods are varargs
* @return the list of maximally specific methods.
*/
- static List<MethodHandle> getMaximallySpecificMethods(List<MethodHandle> methods, boolean varArgs) {
- return getMaximallySpecificMethods(methods, varArgs, null, null);
+ static List<SingleDynamicMethod> getMaximallySpecificMethods(List<SingleDynamicMethod> methods, boolean varArgs) {
+ return getMaximallySpecificSingleDynamicMethods(methods, varArgs, null, null);
}
+ private abstract static class MethodTypeGetter<T> {
+ abstract MethodType getMethodType(T t);
+ }
+
+ private static final MethodTypeGetter<MethodHandle> METHOD_HANDLE_TYPE_GETTER =
+ new MethodTypeGetter<MethodHandle>() {
+ @Override
+ MethodType getMethodType(MethodHandle t) {
+ return t.type();
+ }
+ };
+
+ private static final MethodTypeGetter<SingleDynamicMethod> DYNAMIC_METHOD_TYPE_GETTER =
+ new MethodTypeGetter<SingleDynamicMethod>() {
+ @Override
+ MethodType getMethodType(SingleDynamicMethod t) {
+ return t.getMethodType();
+ }
+ };
+
+ /**
+ * Given a list of methods handles, returns a list of maximally specific methods, applying language-runtime
+ * specific conversion preferences.
+ *
+ * @param methods the list of method handles
+ * @param varArgs whether to assume the method handles are varargs
+ * @param argTypes concrete argument types for the invocation
+ * @return the list of maximally specific method handles.
+ */
+ static List<MethodHandle> getMaximallySpecificMethodHandles(List<MethodHandle> methods, boolean varArgs,
+ Class<?>[] argTypes, LinkerServices ls) {
+ return getMaximallySpecificMethods(methods, varArgs, argTypes, ls, METHOD_HANDLE_TYPE_GETTER);
+ }
+
+ /**
+ * Given a list of methods, returns a list of maximally specific methods, applying language-runtime specific
+ * conversion preferences.
+ *
+ * @param methods the list of methods
+ * @param varArgs whether to assume the methods are varargs
+ * @param argTypes concrete argument types for the invocation
+ * @return the list of maximally specific methods.
+ */
+ static List<SingleDynamicMethod> getMaximallySpecificSingleDynamicMethods(List<SingleDynamicMethod> methods,
+ boolean varArgs, Class<?>[] argTypes, LinkerServices ls) {
+ return getMaximallySpecificMethods(methods, varArgs, argTypes, ls, DYNAMIC_METHOD_TYPE_GETTER);
+ }
+
/**
* Given a list of methods, returns a list of maximally specific methods, applying language-runtime specific
* conversion preferences.
@@ -118,18 +166,18 @@ class MaximallySpecific {
* @param argTypes concrete argument types for the invocation
* @return the list of maximally specific methods.
*/
- static List<MethodHandle> getMaximallySpecificMethods(List<MethodHandle> methods, boolean varArgs,
- Class<?>[] argTypes, LinkerServices ls) {
+ private static <T> List<T> getMaximallySpecificMethods(List<T> methods, boolean varArgs,
+ Class<?>[] argTypes, LinkerServices ls, MethodTypeGetter<T> methodTypeGetter) {
if(methods.size() < 2) {
return methods;
}
- final LinkedList<MethodHandle> maximals = new LinkedList<>();
- for(MethodHandle m: methods) {
- final MethodType methodType = m.type();
+ final LinkedList<T> maximals = new LinkedList<>();
+ for(T m: methods) {
+ final MethodType methodType = methodTypeGetter.getMethodType(m);
boolean lessSpecific = false;
- for(Iterator<MethodHandle> maximal = maximals.iterator(); maximal.hasNext();) {
- final MethodHandle max = maximal.next();
- switch(isMoreSpecific(methodType, max.type(), varArgs, argTypes, ls)) {
+ for(Iterator<T> maximal = maximals.iterator(); maximal.hasNext();) {
+ final T max = maximal.next();
+ switch(isMoreSpecific(methodType, methodTypeGetter.getMethodType(max), varArgs, argTypes, ls)) {
case TYPE_1_BETTER: {
maximal.remove();
break;
diff --git a/src/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java b/src/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java
index 7873cf15..407d2b83 100644
--- a/src/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java
+++ b/src/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java
@@ -84,16 +84,21 @@
package jdk.internal.dynalink.beans;
import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
+import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.beans.ApplicableOverloadedMethods.ApplicabilityTest;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.support.TypeUtilities;
/**
- * Represents an overloaded method.
+ * Represents a group of {@link SingleDynamicMethod} objects that represents all overloads of a particular name (or all
+ * constructors) for a particular class. Correctly handles overload resolution, variable arity methods, and caller
+ * sensitive methods within the overloads.
*
* @author Attila Szegedi
*/
@@ -101,7 +106,7 @@ class OverloadedDynamicMethod extends DynamicMethod {
/**
* Holds a list of all methods.
*/
- private final LinkedList<MethodHandle> methods;
+ private final LinkedList<SingleDynamicMethod> methods;
private final ClassLoader classLoader;
/**
@@ -111,21 +116,22 @@ class OverloadedDynamicMethod extends DynamicMethod {
* @param name the name of the method
*/
OverloadedDynamicMethod(Class<?> clazz, String name) {
- this(new LinkedList<MethodHandle>(), clazz.getClassLoader(), getClassAndMethodName(clazz, name));
+ this(new LinkedList<SingleDynamicMethod>(), clazz.getClassLoader(), getClassAndMethodName(clazz, name));
}
- private OverloadedDynamicMethod(LinkedList<MethodHandle> methods, ClassLoader classLoader, String name) {
+ private OverloadedDynamicMethod(LinkedList<SingleDynamicMethod> methods, ClassLoader classLoader, String name) {
super(name);
this.methods = methods;
this.classLoader = classLoader;
}
@Override
- SimpleDynamicMethod getMethodForExactParamTypes(String paramTypes) {
- final LinkedList<MethodHandle> matchingMethods = new LinkedList<>();
- for(MethodHandle method: methods) {
- if(typeMatchesDescription(paramTypes, method.type())) {
- matchingMethods.add(method);
+ SingleDynamicMethod getMethodForExactParamTypes(String paramTypes) {
+ final LinkedList<SingleDynamicMethod> matchingMethods = new LinkedList<>();
+ for(SingleDynamicMethod method: methods) {
+ final SingleDynamicMethod matchingMethod = method.getMethodForExactParamTypes(paramTypes);
+ if(matchingMethod != null) {
+ matchingMethods.add(matchingMethod);
}
}
switch(matchingMethods.size()) {
@@ -133,8 +139,7 @@ class OverloadedDynamicMethod extends DynamicMethod {
return null;
}
case 1: {
- final MethodHandle target = matchingMethods.get(0);
- return new SimpleDynamicMethod(target, SimpleDynamicMethod.getMethodNameWithSignature(target, getName()));
+ return matchingMethods.getFirst();
}
default: {
throw new BootstrapMethodError("Can't choose among " + matchingMethods + " for argument types "
@@ -144,7 +149,8 @@ class OverloadedDynamicMethod extends DynamicMethod {
}
@Override
- public MethodHandle getInvocation(final MethodType callSiteType, final LinkerServices linkerServices) {
+ public MethodHandle getInvocation(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) {
+ final MethodType callSiteType = callSiteDescriptor.getMethodType();
// First, find all methods applicable to the call site by subtyping (JLS 15.12.2.2)
final ApplicableOverloadedMethods subtypingApplicables = getApplicables(callSiteType,
ApplicableOverloadedMethods.APPLICABLE_BY_SUBTYPING);
@@ -156,7 +162,7 @@ class OverloadedDynamicMethod extends DynamicMethod {
ApplicableOverloadedMethods.APPLICABLE_BY_VARIABLE_ARITY);
// Find the methods that are maximally specific based on the call site signature
- List<MethodHandle> maximallySpecifics = subtypingApplicables.findMaximallySpecificMethods();
+ List<SingleDynamicMethod> maximallySpecifics = subtypingApplicables.findMaximallySpecificMethods();
if(maximallySpecifics.isEmpty()) {
maximallySpecifics = methodInvocationApplicables.findMaximallySpecificMethods();
if(maximallySpecifics.isEmpty()) {
@@ -171,12 +177,12 @@ class OverloadedDynamicMethod extends DynamicMethod {
// (Object, Object), and we have a method whose parameter types are (String, int). None of the JLS applicability
// rules will trigger, but we must consider the method, as it can be the right match for a concrete invocation.
@SuppressWarnings({ "unchecked", "rawtypes" })
- final List<MethodHandle> invokables = (List)methods.clone();
+ final List<SingleDynamicMethod> invokables = (List)methods.clone();
invokables.removeAll(subtypingApplicables.getMethods());
invokables.removeAll(methodInvocationApplicables.getMethods());
invokables.removeAll(variableArityApplicables.getMethods());
- for(final Iterator<MethodHandle> it = invokables.iterator(); it.hasNext();) {
- final MethodHandle m = it.next();
+ for(final Iterator<SingleDynamicMethod> it = invokables.iterator(); it.hasNext();) {
+ final SingleDynamicMethod m = it.next();
if(!isApplicableDynamically(linkerServices, callSiteType, m)) {
it.remove();
}
@@ -199,54 +205,45 @@ class OverloadedDynamicMethod extends DynamicMethod {
}
case 1: {
// Very lucky, we ended up with a single candidate method handle based on the call site signature; we
- // can link it very simply by delegating to a SimpleDynamicMethod.
- final MethodHandle mh = invokables.iterator().next();
- return new SimpleDynamicMethod(mh).getInvocation(callSiteType, linkerServices);
+ // can link it very simply by delegating to the SingleDynamicMethod.
+ invokables.iterator().next().getInvocation(callSiteDescriptor, linkerServices);
}
default: {
// We have more than one candidate. We have no choice but to link to a method that resolves overloads on
// every invocation (alternatively, we could opportunistically link the one method that resolves for the
// current arguments, but we'd need to install a fairly complex guard for that and when it'd fail, we'd
- // go back all the way to candidate selection.
- // TODO: cache per call site type
- return new OverloadedMethod(invokables, this, callSiteType, linkerServices).getInvoker();
+ // go back all the way to candidate selection. Note that we're resolving any potential caller sensitive
+ // methods here to their handles, as the OverloadedMethod instance is specific to a call site, so it
+ // has an already determined Lookup.
+ final List<MethodHandle> methodHandles = new ArrayList<>(invokables.size());
+ final MethodHandles.Lookup lookup = callSiteDescriptor.getLookup();
+ for(SingleDynamicMethod method: invokables) {
+ methodHandles.add(method.getTarget(lookup));
+ }
+ return new OverloadedMethod(methodHandles, this, callSiteType, linkerServices).getInvoker();
}
}
}
@Override
- public boolean contains(MethodHandle mh) {
- final MethodType type = mh.type();
- for(MethodHandle method: methods) {
- if(typesEqualNoReceiver(type, method.type())) {
+ public boolean contains(SingleDynamicMethod m) {
+ for(SingleDynamicMethod method: methods) {
+ if(method.contains(m)) {
return true;
}
}
return false;
}
- private static boolean typesEqualNoReceiver(MethodType type1, MethodType type2) {
- final int pc = type1.parameterCount();
- if(pc != type2.parameterCount()) {
- return false;
- }
- for(int i = 1; i < pc; ++i) { // i = 1: ignore receiver
- if(type1.parameterType(i) != type2.parameterType(i)) {
- return false;
- }
- }
- return true;
- }
-
ClassLoader getClassLoader() {
return classLoader;
}
private static boolean isApplicableDynamically(LinkerServices linkerServices, MethodType callSiteType,
- MethodHandle m) {
- final MethodType methodType = m.type();
- final boolean varArgs = m.isVarargsCollector();
+ SingleDynamicMethod m) {
+ final MethodType methodType = m.getMethodType();
+ final boolean varArgs = m.isVarArgs();
final int fixedArgLen = methodType.parameterCount() - (varArgs ? 1 : 0);
final int callSiteArgLen = callSiteType.parameterCount();
@@ -301,20 +298,11 @@ class OverloadedDynamicMethod extends DynamicMethod {
}
/**
- * Add a method identified by a {@link SimpleDynamicMethod} to this overloaded method's set.
- *
- * @param method the method to add.
- */
- void addMethod(SimpleDynamicMethod method) {
- addMethod(method.getTarget());
- }
-
- /**
* Add a method to this overloaded method's set.
*
* @param method a method to add
*/
- public void addMethod(MethodHandle method) {
+ public void addMethod(SingleDynamicMethod method) {
methods.add(method);
}
}
diff --git a/src/jdk/internal/dynalink/beans/OverloadedMethod.java b/src/jdk/internal/dynalink/beans/OverloadedMethod.java
index 7093e757..f711489b 100644
--- a/src/jdk/internal/dynalink/beans/OverloadedMethod.java
+++ b/src/jdk/internal/dynalink/beans/OverloadedMethod.java
@@ -135,7 +135,7 @@ class OverloadedMethod {
varArgMethods.trimToSize();
final MethodHandle bound = SELECT_METHOD.bindTo(this);
- final MethodHandle collecting = SimpleDynamicMethod.collectArguments(bound, argNum).asType(
+ final MethodHandle collecting = SingleDynamicMethod.collectArguments(bound, argNum).asType(
callSiteType.changeReturnType(MethodHandle.class));
invoker = MethodHandles.foldArguments(MethodHandles.exactInvoker(callSiteType), collecting);
}
@@ -167,7 +167,7 @@ class OverloadedMethod {
break;
}
case 1: {
- method = new SimpleDynamicMethod(methods.get(0)).getInvocation(callSiteType, linkerServices);
+ method = SingleDynamicMethod.getInvocation(methods.get(0), callSiteType, linkerServices);
break;
}
default: {
diff --git a/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java b/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java
index 1fbf7dbb..9d4d6961 100644
--- a/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java
+++ b/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java
@@ -84,29 +84,22 @@
package jdk.internal.dynalink.beans;
import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
-import java.lang.reflect.Array;
-import jdk.internal.dynalink.linker.LinkerServices;
-import jdk.internal.dynalink.support.Guards;
/**
- * A dynamic method bound to exactly one, non-overloaded Java method. Handles varargs.
+ * A dynamic method bound to exactly one Java method or constructor that is not caller sensitive. Since its target is
+ * not caller sensitive, this class pre-caches its method handle and always returns it from the call to
+ * {@link #getTarget(Lookup)}. Can be used in general to represents dynamic methods bound to a single method handle,
+ * even if that handle is not mapped to a Java method, i.e. as a wrapper around field getters/setters, array element
+ * getters/setters, etc.
*
* @author Attila Szegedi
*/
-class SimpleDynamicMethod extends DynamicMethod {
+class SimpleDynamicMethod extends SingleDynamicMethod {
private final MethodHandle target;
/**
- * Creates a simple dynamic method with no name.
- * @param target the target method handle
- */
- SimpleDynamicMethod(MethodHandle target) {
- this(target, null);
- }
-
- /**
* Creates a new simple dynamic method, with a name constructed from the class name, method name, and handle
* signature.
*
@@ -115,125 +108,26 @@ class SimpleDynamicMethod extends DynamicMethod {
* @param name the simple name of the method
*/
SimpleDynamicMethod(MethodHandle target, Class<?> clazz, String name) {
- this(target, getName(target, clazz, name));
- }
-
- SimpleDynamicMethod(MethodHandle target, String name) {
- super(name);
+ super(getName(target, clazz, name));
this.target = target;
}
private static String getName(MethodHandle target, Class<?> clazz, String name) {
- return getMethodNameWithSignature(target, getClassAndMethodName(clazz, name));
- }
-
- static String getMethodNameWithSignature(MethodHandle target, String methodName) {
- final String typeStr = target.type().toString();
- final int retTypeIndex = typeStr.lastIndexOf(')') + 1;
- int secondParamIndex = typeStr.indexOf(',') + 1;
- if(secondParamIndex == 0) {
- secondParamIndex = retTypeIndex - 1;
- }
- return typeStr.substring(retTypeIndex) + " " + methodName + "(" + typeStr.substring(secondParamIndex, retTypeIndex);
- }
-
- /**
- * Returns the target of this dynamic method
- *
- * @return the target of this dynamic method
- */
- MethodHandle getTarget() {
- return target;
+ return getMethodNameWithSignature(target.type(), getClassAndMethodName(clazz, name));
}
@Override
- SimpleDynamicMethod getMethodForExactParamTypes(String paramTypes) {
- return typeMatchesDescription(paramTypes, target.type()) ? this : null;
+ boolean isVarArgs() {
+ return target.isVarargsCollector();
}
@Override
- MethodHandle getInvocation(MethodType callSiteType, LinkerServices linkerServices) {
- final MethodType methodType = target.type();
- final int paramsLen = methodType.parameterCount();
- final boolean varArgs = target.isVarargsCollector();
- final MethodHandle fixTarget = varArgs ? target.asFixedArity() : target;
- final int fixParamsLen = varArgs ? paramsLen - 1 : paramsLen;
- final int argsLen = callSiteType.parameterCount();
- if(argsLen < fixParamsLen) {
- // Less actual arguments than number of fixed declared arguments; can't invoke.
- return null;
- }
- // Method handle has the same number of fixed arguments as the call site type
- if(argsLen == fixParamsLen) {
- // Method handle that matches the number of actual arguments as the number of fixed arguments
- final MethodHandle matchedMethod;
- if(varArgs) {
- // If vararg, add a zero-length array of the expected type as the last argument to signify no variable
- // arguments.
- matchedMethod = MethodHandles.insertArguments(fixTarget, fixParamsLen, Array.newInstance(
- methodType.parameterType(fixParamsLen).getComponentType(), 0));
- } else {
- // Otherwise, just use the method
- matchedMethod = fixTarget;
- }
- return createConvertingInvocation(matchedMethod, linkerServices, callSiteType);
- }
-
- // What's below only works for varargs
- if(!varArgs) {
- return null;
- }
-
- final Class<?> varArgType = methodType.parameterType(fixParamsLen);
- // Handle a somewhat sinister corner case: caller passes exactly one argument in the vararg position, and we
- // must handle both a prepacked vararg array as well as a genuine 1-long vararg sequence.
- if(argsLen == paramsLen) {
- final Class<?> callSiteLastArgType = callSiteType.parameterType(fixParamsLen);
- if(varArgType.isAssignableFrom(callSiteLastArgType)) {
- // Call site signature guarantees we'll always be passed a single compatible array; just link directly
- // to the method.
- return createConvertingInvocation(fixTarget, linkerServices, callSiteType);
- }
- if(!linkerServices.canConvert(callSiteLastArgType, varArgType)) {
- // Call site signature guarantees the argument can definitely not be an array (i.e. it is primitive);
- // link immediately to a vararg-packing method handle.
- return createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType);
- }
- // Call site signature makes no guarantees that the single argument in the vararg position will be
- // compatible across all invocations. Need to insert an appropriate guard and fall back to generic vararg
- // method when it is not.
- return MethodHandles.guardWithTest(Guards.isInstance(varArgType, fixParamsLen, callSiteType),
- createConvertingInvocation(fixTarget, linkerServices, callSiteType),
- createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType));
- }
-
- // Remaining case: more than one vararg.
- return createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType);
+ MethodType getMethodType() {
+ return target.type();
}
@Override
- public boolean contains(MethodHandle mh) {
- return target.type().parameterList().equals(mh.type().parameterList());
- }
-
- /**
- * Creates a method handle out of the original target that will collect the varargs for the exact component type of
- * the varArg array. Note that this will nicely trigger language-specific type converters for exactly those varargs
- * for which it is necessary when later passed to linkerServices.convertArguments().
- *
- * @param target the original method handle
- * @param parameterCount the total number of arguments in the new method handle
- * @return a collecting method handle
- */
- static MethodHandle collectArguments(MethodHandle target, final int parameterCount) {
- final MethodType methodType = target.type();
- final int fixParamsLen = methodType.parameterCount() - 1;
- final Class<?> arrayType = methodType.parameterType(fixParamsLen);
- return target.asCollector(arrayType, parameterCount - fixParamsLen);
- }
-
- private static MethodHandle createConvertingInvocation(final MethodHandle sizedMethod,
- final LinkerServices linkerServices, final MethodType callSiteType) {
- return linkerServices.asType(sizedMethod, callSiteType);
+ MethodHandle getTarget(Lookup lookup) {
+ return target;
}
}
diff --git a/src/jdk/internal/dynalink/beans/SingleDynamicMethod.java b/src/jdk/internal/dynalink/beans/SingleDynamicMethod.java
new file mode 100644
index 00000000..d15fab99
--- /dev/null
+++ b/src/jdk/internal/dynalink/beans/SingleDynamicMethod.java
@@ -0,0 +1,255 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file, and Oracle licenses the original version of this file under the BSD
+ * license:
+ */
+/*
+ Copyright 2009-2013 Attila Szegedi
+
+ Licensed under both the Apache License, Version 2.0 (the "Apache License")
+ and the BSD License (the "BSD License"), with licensee being free to
+ choose either of the two at their discretion.
+
+ You may not use this file except in compliance with either the Apache
+ License or the BSD License.
+
+ If you choose to use this file in compliance with the Apache License, the
+ following notice applies to you:
+
+ You may obtain a copy of the Apache License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ permissions and limitations under the License.
+
+ If you choose to use this file in compliance with the BSD License, the
+ following notice applies to you:
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the copyright holder nor the names of
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package jdk.internal.dynalink.beans;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.Array;
+import java.util.StringTokenizer;
+import jdk.internal.dynalink.CallSiteDescriptor;
+import jdk.internal.dynalink.linker.LinkerServices;
+import jdk.internal.dynalink.support.Guards;
+
+/**
+ * Base class for dynamic methods that dispatch to a single target Java method or constructor. Handles adaptation of the
+ * target method to a call site type (including mapping variable arity methods to a call site signature with different
+ * arity).
+ * @author Attila Szegedi
+ * @version $Id: $
+ */
+abstract class SingleDynamicMethod extends DynamicMethod {
+ SingleDynamicMethod(String name) {
+ super(name);
+ }
+
+ /**
+ * Returns true if this method is variable arity.
+ * @return true if this method is variable arity.
+ */
+ abstract boolean isVarArgs();
+
+ /**
+ * Returns this method's native type.
+ * @return this method's native type.
+ */
+ abstract MethodType getMethodType();
+
+ /**
+ * Given a specified lookup, returns a method handle to this method's target.
+ * @param lookup the lookup to use.
+ * @return the handle to this method's target method.
+ */
+ abstract MethodHandle getTarget(MethodHandles.Lookup lookup);
+
+ @Override
+ MethodHandle getInvocation(CallSiteDescriptor callSiteDescriptor, LinkerServices linkerServices) {
+ return getInvocation(getTarget(callSiteDescriptor.getLookup()), callSiteDescriptor.getMethodType(),
+ linkerServices);
+ }
+
+ @Override
+ SingleDynamicMethod getMethodForExactParamTypes(String paramTypes) {
+ return typeMatchesDescription(paramTypes, getMethodType()) ? this : null;
+ }
+
+ @Override
+ boolean contains(SingleDynamicMethod method) {
+ return getMethodType().parameterList().equals(method.getMethodType().parameterList());
+ }
+
+ static String getMethodNameWithSignature(MethodType type, String methodName) {
+ final String typeStr = type.toString();
+ final int retTypeIndex = typeStr.lastIndexOf(')') + 1;
+ int secondParamIndex = typeStr.indexOf(',') + 1;
+ if(secondParamIndex == 0) {
+ secondParamIndex = retTypeIndex - 1;
+ }
+ return typeStr.substring(retTypeIndex) + " " + methodName + "(" + typeStr.substring(secondParamIndex, retTypeIndex);
+ }
+
+ /**
+ * Given a method handle and a call site type, adapts the method handle to the call site type. Performs type
+ * conversions as needed using the specified linker services, and in case that the method handle is a vararg
+ * collector, matches it to the arity of the call site.
+ * @param target the method handle to adapt
+ * @param callSiteType the type of the call site
+ * @param linkerServices the linker services used for type conversions
+ * @return the adapted method handle.
+ */
+ static MethodHandle getInvocation(MethodHandle target, MethodType callSiteType, LinkerServices linkerServices) {
+ final MethodType methodType = target.type();
+ final int paramsLen = methodType.parameterCount();
+ final boolean varArgs = target.isVarargsCollector();
+ final MethodHandle fixTarget = varArgs ? target.asFixedArity() : target;
+ final int fixParamsLen = varArgs ? paramsLen - 1 : paramsLen;
+ final int argsLen = callSiteType.parameterCount();
+ if(argsLen < fixParamsLen) {
+ // Less actual arguments than number of fixed declared arguments; can't invoke.
+ return null;
+ }
+ // Method handle has the same number of fixed arguments as the call site type
+ if(argsLen == fixParamsLen) {
+ // Method handle that matches the number of actual arguments as the number of fixed arguments
+ final MethodHandle matchedMethod;
+ if(varArgs) {
+ // If vararg, add a zero-length array of the expected type as the last argument to signify no variable
+ // arguments.
+ matchedMethod = MethodHandles.insertArguments(fixTarget, fixParamsLen, Array.newInstance(
+ methodType.parameterType(fixParamsLen).getComponentType(), 0));
+ } else {
+ // Otherwise, just use the method
+ matchedMethod = fixTarget;
+ }
+ return createConvertingInvocation(matchedMethod, linkerServices, callSiteType);
+ }
+
+ // What's below only works for varargs
+ if(!varArgs) {
+ return null;
+ }
+
+ final Class<?> varArgType = methodType.parameterType(fixParamsLen);
+ // Handle a somewhat sinister corner case: caller passes exactly one argument in the vararg position, and we
+ // must handle both a prepacked vararg array as well as a genuine 1-long vararg sequence.
+ if(argsLen == paramsLen) {
+ final Class<?> callSiteLastArgType = callSiteType.parameterType(fixParamsLen);
+ if(varArgType.isAssignableFrom(callSiteLastArgType)) {
+ // Call site signature guarantees we'll always be passed a single compatible array; just link directly
+ // to the method, introducing necessary conversions. Also, preserve it being a variable arity method.
+ return createConvertingInvocation(target, linkerServices, callSiteType).asVarargsCollector(
+ callSiteLastArgType);
+ }
+ if(!linkerServices.canConvert(callSiteLastArgType, varArgType)) {
+ // Call site signature guarantees the argument can definitely not be an array (i.e. it is primitive);
+ // link immediately to a vararg-packing method handle.
+ return createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType);
+ }
+ // Call site signature makes no guarantees that the single argument in the vararg position will be
+ // compatible across all invocations. Need to insert an appropriate guard and fall back to generic vararg
+ // method when it is not.
+ return MethodHandles.guardWithTest(Guards.isInstance(varArgType, fixParamsLen, callSiteType),
+ createConvertingInvocation(fixTarget, linkerServices, callSiteType),
+ createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType));
+ }
+
+ // Remaining case: more than one vararg.
+ return createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType);
+ }
+
+ /**
+ * Creates a method handle out of the original target that will collect the varargs for the exact component type of
+ * the varArg array. Note that this will nicely trigger language-specific type converters for exactly those varargs
+ * for which it is necessary when later passed to linkerServices.convertArguments().
+ *
+ * @param target the original method handle
+ * @param parameterCount the total number of arguments in the new method handle
+ * @return a collecting method handle
+ */
+ static MethodHandle collectArguments(MethodHandle target, final int parameterCount) {
+ final MethodType methodType = target.type();
+ final int fixParamsLen = methodType.parameterCount() - 1;
+ final Class<?> arrayType = methodType.parameterType(fixParamsLen);
+ return target.asCollector(arrayType, parameterCount - fixParamsLen);
+ }
+
+ private static MethodHandle createConvertingInvocation(final MethodHandle sizedMethod,
+ final LinkerServices linkerServices, final MethodType callSiteType) {
+ return linkerServices.asType(sizedMethod, callSiteType);
+ }
+
+ private static boolean typeMatchesDescription(String paramTypes, MethodType type) {
+ final StringTokenizer tok = new StringTokenizer(paramTypes, ", ");
+ for(int i = 1; i < type.parameterCount(); ++i) { // i = 1 as we ignore the receiver
+ if(!(tok.hasMoreTokens() && typeNameMatches(tok.nextToken(), type.parameterType(i)))) {
+ return false;
+ }
+ }
+ return !tok.hasMoreTokens();
+ }
+
+ private static boolean typeNameMatches(String typeName, Class<?> type) {
+ return typeName.equals(typeName.indexOf('.') == -1 ? type.getSimpleName() : type.getCanonicalName());
+ }
+}
diff --git a/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java b/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java
index 214152a4..62ce41a9 100644
--- a/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java
+++ b/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java
@@ -106,10 +106,18 @@ class StaticClassIntrospector extends FacetIntrospector {
@Override
MethodHandle editMethodHandle(MethodHandle mh) {
+ return editStaticMethodHandle(mh);
+ }
+
+ static MethodHandle editStaticMethodHandle(MethodHandle mh) {
return dropReceiver(mh, Object.class);
}
- static MethodHandle dropReceiver(final MethodHandle mh, final Class<?> receiverClass) {
+ static MethodHandle editConstructorMethodHandle(MethodHandle cmh) {
+ return dropReceiver(cmh, StaticClass.class);
+ }
+
+ private static MethodHandle dropReceiver(final MethodHandle mh, final Class<?> receiverClass) {
MethodHandle newHandle = MethodHandles.dropArguments(mh, 0, receiverClass);
// NOTE: this is a workaround for the fact that dropArguments doesn't preserve vararg collector state.
if(mh.isVarargsCollector() && !newHandle.isVarargsCollector()) {
diff --git a/src/jdk/internal/dynalink/beans/StaticClassLinker.java b/src/jdk/internal/dynalink/beans/StaticClassLinker.java
index d6096fe5..2abdbbe9 100644
--- a/src/jdk/internal/dynalink/beans/StaticClassLinker.java
+++ b/src/jdk/internal/dynalink/beans/StaticClassLinker.java
@@ -87,13 +87,11 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Array;
-import java.lang.reflect.Constructor;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Arrays;
+import java.util.Collection;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType;
import jdk.internal.dynalink.linker.GuardedInvocation;
-import jdk.internal.dynalink.linker.GuardingDynamicLinker;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
@@ -104,9 +102,9 @@ import jdk.internal.dynalink.support.Lookup;
* @author Attila Szegedi
*/
class StaticClassLinker implements TypeBasedGuardingDynamicLinker {
- private final ClassValue<GuardingDynamicLinker> linkers = new ClassValue<GuardingDynamicLinker>() {
+ private static final ClassValue<SingleClassStaticsLinker> linkers = new ClassValue<SingleClassStaticsLinker>() {
@Override
- protected GuardingDynamicLinker computeValue(Class<?> clazz) {
+ protected SingleClassStaticsLinker computeValue(Class<?> clazz) {
return new SingleClassStaticsLinker(clazz);
}
};
@@ -131,20 +129,11 @@ class StaticClassLinker implements TypeBasedGuardingDynamicLinker {
private static DynamicMethod createConstructorMethod(Class<?> clazz) {
if(clazz.isArray()) {
final MethodHandle boundArrayCtor = ARRAY_CTOR.bindTo(clazz.getComponentType());
- return new SimpleDynamicMethod(drop(boundArrayCtor.asType(boundArrayCtor.type().changeReturnType(
- clazz))), clazz, "<init>");
+ return new SimpleDynamicMethod(StaticClassIntrospector.editConstructorMethodHandle(
+ boundArrayCtor.asType(boundArrayCtor.type().changeReturnType(clazz))), clazz, "<init>");
}
- final Constructor<?>[] ctrs = clazz.getConstructors();
- final List<MethodHandle> mhs = new ArrayList<>(ctrs.length);
- for(int i = 0; i < ctrs.length; ++i) {
- mhs.add(drop(SafeUnreflector.unreflectConstructor(ctrs[i])));
- }
- return createDynamicMethod(mhs, clazz, "<init>");
- }
-
- private static MethodHandle drop(MethodHandle mh) {
- return StaticClassIntrospector.dropReceiver(mh, StaticClass.class);
+ return createDynamicMethod(Arrays.asList(clazz.getConstructors()), clazz, "<init>");
}
@Override
@@ -161,17 +150,28 @@ class StaticClassLinker implements TypeBasedGuardingDynamicLinker {
}
final CallSiteDescriptor desc = request.getCallSiteDescriptor();
final String op = desc.getNameToken(CallSiteDescriptor.OPERATOR);
- final MethodType methodType = desc.getMethodType();
if("new" == op && constructor != null) {
- final MethodHandle ctorInvocation = constructor.getInvocation(methodType, linkerServices);
+ final MethodHandle ctorInvocation = constructor.getInvocation(desc, linkerServices);
if(ctorInvocation != null) {
- return new GuardedInvocation(ctorInvocation, getClassGuard(methodType));
+ return new GuardedInvocation(ctorInvocation, getClassGuard(desc.getMethodType()));
}
}
return null;
}
}
+ static Collection<String> getReadableStaticPropertyNames(Class<?> clazz) {
+ return linkers.get(clazz).getReadablePropertyNames();
+ }
+
+ static Collection<String> getWritableStaticPropertyNames(Class<?> clazz) {
+ return linkers.get(clazz).getWritablePropertyNames();
+ }
+
+ static Collection<String> getStaticMethodNames(Class<?> clazz) {
+ return linkers.get(clazz).getMethodNames();
+ }
+
@Override
public GuardedInvocation getGuardedInvocation(LinkRequest request, LinkerServices linkerServices) throws Exception {
final Object receiver = request.getReceiver();
diff --git a/src/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java b/src/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java
index e51f6fe2..3161cf50 100644
--- a/src/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java
+++ b/src/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java
@@ -139,8 +139,9 @@ public abstract class AbstractCallSiteDescriptor implements CallSiteDescriptor {
@Override
public int hashCode() {
+ final MethodHandles.Lookup lookup = getLookup();
+ int h = lookup.lookupClass().hashCode() + 31 * lookup.lookupModes();
final int c = getNameTokenCount();
- int h = 0;
for(int i = 0; i < c; ++i) {
h = h * 31 + getNameToken(i).hashCode();
}
diff --git a/src/jdk/internal/dynalink/support/Lookup.java b/src/jdk/internal/dynalink/support/Lookup.java
index 52a61024..4b21e1c4 100644
--- a/src/jdk/internal/dynalink/support/Lookup.java
+++ b/src/jdk/internal/dynalink/support/Lookup.java
@@ -122,6 +122,18 @@ public class Lookup {
* @return the unreflected method handle.
*/
public MethodHandle unreflect(Method m) {
+ return unreflect(lookup, m);
+ }
+
+ /**
+ * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflect(Method)}, converting any encountered
+ * {@link IllegalAccessException} into an {@link IllegalAccessError}.
+ *
+ * @param lookup the lookup used to unreflect
+ * @param m the method to unreflect
+ * @return the unreflected method handle.
+ */
+ public static MethodHandle unreflect(MethodHandles.Lookup lookup, Method m) {
try {
return lookup.unreflect(m);
} catch(IllegalAccessException e) {
@@ -131,7 +143,6 @@ public class Lookup {
}
}
-
/**
* Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectGetter(Field)}, converting any encountered
* {@link IllegalAccessException} into an {@link IllegalAccessError}.
@@ -202,6 +213,18 @@ public class Lookup {
* @return the unreflected constructor handle.
*/
public MethodHandle unreflectConstructor(Constructor<?> c) {
+ return unreflectConstructor(lookup, c);
+ }
+
+ /**
+ * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectConstructor(Constructor)}, converting any
+ * encountered {@link IllegalAccessException} into an {@link IllegalAccessError}.
+ *
+ * @param lookup the lookup used to unreflect
+ * @param c the constructor to unreflect
+ * @return the unreflected constructor handle.
+ */
+ public static MethodHandle unreflectConstructor(MethodHandles.Lookup lookup, Constructor<?> c) {
try {
return lookup.unreflectConstructor(c);
} catch(IllegalAccessException e) {
diff --git a/src/jdk/nashorn/api/scripting/NashornException.java b/src/jdk/nashorn/api/scripting/NashornException.java
index 3cd687cc..d5ec5bb4 100644
--- a/src/jdk/nashorn/api/scripting/NashornException.java
+++ b/src/jdk/nashorn/api/scripting/NashornException.java
@@ -146,7 +146,7 @@ public abstract class NashornException extends RuntimeException {
* @return array of javascript stack frames
*/
public static StackTraceElement[] getScriptFrames(final Throwable exception) {
- final StackTraceElement[] frames = ((Throwable)exception).getStackTrace();
+ final StackTraceElement[] frames = exception.getStackTrace();
final List<StackTraceElement> filtered = new ArrayList<>();
for (final StackTraceElement st : frames) {
if (ECMAErrors.isScriptFrame(st)) {
@@ -170,7 +170,7 @@ public abstract class NashornException extends RuntimeException {
*/
public static String getScriptStackString(final Throwable exception) {
final StringBuilder buf = new StringBuilder();
- final StackTraceElement[] frames = getScriptFrames((Throwable)exception);
+ final StackTraceElement[] frames = getScriptFrames(exception);
for (final StackTraceElement st : frames) {
buf.append("\tat ");
buf.append(st.getMethodName());
diff --git a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
index d38e63c8..682975a8 100644
--- a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
+++ b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
@@ -33,6 +33,7 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
import java.net.URL;
import java.nio.charset.Charset;
import java.security.AccessController;
@@ -184,6 +185,19 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
}
private <T> T getInterfaceInner(final Object self, final Class<T> clazz) {
+ if (clazz == null || !clazz.isInterface()) {
+ throw new IllegalArgumentException("interface Class expected");
+ }
+
+ // perform security access check as early as possible
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ if (! Modifier.isPublic(clazz.getModifiers())) {
+ throw new SecurityException("attempt to implement non-public interfce: " + clazz);
+ }
+ Context.checkPackageAccess(clazz.getName());
+ }
+
final ScriptObject realSelf;
final ScriptObject ctxtGlobal = getNashornGlobalFrom(context);
if(self == null) {
@@ -193,6 +207,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
} else {
realSelf = (ScriptObject)self;
}
+
try {
final ScriptObject oldGlobal = getNashornGlobal();
try {
diff --git a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java
index c7dbab5a..c7c384e7 100644
--- a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java
+++ b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java
@@ -52,11 +52,6 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
private final ScriptObject sobj;
private final ScriptObject global;
- ScriptObjectMirror(final ScriptObject sobj, final ScriptObject global) {
- this.sobj = sobj;
- this.global = global;
- }
-
@Override
public boolean equals(final Object other) {
if (other instanceof ScriptObjectMirror) {
@@ -81,25 +76,6 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
});
}
- private <V> V inGlobal(final Callable<V> callable) {
- final ScriptObject oldGlobal = NashornScriptEngine.getNashornGlobal();
- final boolean globalChanged = (oldGlobal != global);
- if (globalChanged) {
- NashornScriptEngine.setNashornGlobal(global);
- }
- try {
- return callable.call();
- } catch (final RuntimeException e) {
- throw e;
- } catch (final Exception e) {
- throw new AssertionError("Cannot happen", e);
- } finally {
- if (globalChanged) {
- NashornScriptEngine.setNashornGlobal(oldGlobal);
- }
- }
- }
-
// JSObject methods
@Override
public Object call(final String functionName, final Object... args) {
@@ -212,6 +188,8 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
});
}
+ // javax.script.Bindings methods
+
@Override
public void clear() {
inGlobal(new Callable<Object>() {
@@ -308,9 +286,9 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
public void putAll(final Map<? extends String, ? extends Object> map) {
final ScriptObject oldGlobal = NashornScriptEngine.getNashornGlobal();
final boolean globalChanged = (oldGlobal != global);
- final boolean strict = sobj.isStrictContext();
inGlobal(new Callable<Object>() {
@Override public Object call() {
+ final boolean strict = global.isStrictContext();
for (final Map.Entry<? extends String, ? extends Object> entry : map.entrySet()) {
final Object value = entry.getValue();
final Object modValue = globalChanged? wrap(value, oldGlobal) : value;
@@ -379,7 +357,7 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
public Object getProto() {
return inGlobal(new Callable<Object>() {
@Override public Object call() {
- return wrap(getScriptObject().getProto(), global);
+ return wrap(sobj.getProto(), global);
}
});
}
@@ -395,7 +373,7 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
public Object getOwnPropertyDescriptor(final String key) {
return inGlobal(new Callable<Object>() {
@Override public Object call() {
- return wrap(getScriptObject().getOwnPropertyDescriptor(key), global);
+ return wrap(sobj.getOwnPropertyDescriptor(key), global);
}
});
}
@@ -409,7 +387,7 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
public String[] getOwnKeys(final boolean all) {
return inGlobal(new Callable<String[]>() {
@Override public String[] call() {
- return getScriptObject().getOwnKeys(all);
+ return sobj.getOwnKeys(all);
}
});
}
@@ -422,7 +400,7 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
public ScriptObjectMirror preventExtensions() {
return inGlobal(new Callable<ScriptObjectMirror>() {
@Override public ScriptObjectMirror call() {
- getScriptObject().preventExtensions();
+ sobj.preventExtensions();
return ScriptObjectMirror.this;
}
});
@@ -435,7 +413,7 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
public boolean isExtensible() {
return inGlobal(new Callable<Boolean>() {
@Override public Boolean call() {
- return getScriptObject().isExtensible();
+ return sobj.isExtensible();
}
});
}
@@ -447,7 +425,7 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
public ScriptObjectMirror seal() {
return inGlobal(new Callable<ScriptObjectMirror>() {
@Override public ScriptObjectMirror call() {
- getScriptObject().seal();
+ sobj.seal();
return ScriptObjectMirror.this;
}
});
@@ -460,7 +438,7 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
public boolean isSealed() {
return inGlobal(new Callable<Boolean>() {
@Override public Boolean call() {
- return getScriptObject().isSealed();
+ return sobj.isSealed();
}
});
}
@@ -472,7 +450,7 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
public ScriptObjectMirror freeze() {
return inGlobal(new Callable<ScriptObjectMirror>() {
@Override public ScriptObjectMirror call() {
- getScriptObject().freeze();
+ sobj.freeze();
return ScriptObjectMirror.this;
}
});
@@ -485,7 +463,7 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
public boolean isFrozen() {
return inGlobal(new Callable<Boolean>() {
@Override public Boolean call() {
- return getScriptObject().isFrozen();
+ return sobj.isFrozen();
}
});
}
@@ -507,28 +485,18 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
return inGlobal(new Callable<Boolean>() {
@Override public Boolean call() {
- return getScriptObject().isInstance(instance.getScriptObject());
+ return sobj.isInstance(instance.sobj);
}
});
}
/**
- * Utility to check if given object is ECMAScript undefined value
- *
- * @param obj object to check
- * @return true if 'obj' is ECMAScript undefined value
- */
- public static boolean isUndefined(final Object obj) {
- return obj == ScriptRuntime.UNDEFINED;
- }
-
- /**
* is this a function object?
*
* @return if this mirror wraps a ECMAScript function instance
*/
public boolean isFunction() {
- return getScriptObject() instanceof ScriptFunction;
+ return sobj instanceof ScriptFunction;
}
/**
@@ -537,7 +505,7 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
* @return true if this mirror represents a ECMAScript 'use strict' function
*/
public boolean isStrictFunction() {
- return isFunction() && ((ScriptFunction)getScriptObject()).isStrict();
+ return isFunction() && ((ScriptFunction)sobj).isStrict();
}
/**
@@ -546,10 +514,18 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
* @return if this mirror wraps a ECMAScript array object
*/
public boolean isArray() {
- return getScriptObject().isArray();
+ return sobj.isArray();
}
- // These are public only so that Context can access these.
+ /**
+ * Utility to check if given object is ECMAScript undefined value
+ *
+ * @param obj object to check
+ * @return true if 'obj' is ECMAScript undefined value
+ */
+ public static boolean isUndefined(final Object obj) {
+ return obj == ScriptRuntime.UNDEFINED;
+ }
/**
* Make a script object mirror on given object if needed.
@@ -621,6 +597,12 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
}
// package-privates below this.
+
+ ScriptObjectMirror(final ScriptObject sobj, final ScriptObject global) {
+ this.sobj = sobj;
+ this.global = global;
+ }
+
ScriptObject getScriptObject() {
return sobj;
}
@@ -628,4 +610,25 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
static Object translateUndefined(Object obj) {
return (obj == ScriptRuntime.UNDEFINED)? null : obj;
}
+
+ // internals only below this.
+ private <V> V inGlobal(final Callable<V> callable) {
+ final ScriptObject oldGlobal = NashornScriptEngine.getNashornGlobal();
+ final boolean globalChanged = (oldGlobal != global);
+ if (globalChanged) {
+ NashornScriptEngine.setNashornGlobal(global);
+ }
+ try {
+ return callable.call();
+ } catch (final RuntimeException e) {
+ throw e;
+ } catch (final Exception e) {
+ throw new AssertionError("Cannot happen", e);
+ } finally {
+ if (globalChanged) {
+ NashornScriptEngine.setNashornGlobal(oldGlobal);
+ }
+ }
+ }
+
}
diff --git a/src/jdk/nashorn/internal/codegen/Attr.java b/src/jdk/nashorn/internal/codegen/Attr.java
index 3a442a7d..f56a881d 100644
--- a/src/jdk/nashorn/internal/codegen/Attr.java
+++ b/src/jdk/nashorn/internal/codegen/Attr.java
@@ -61,6 +61,7 @@ import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.CallNode;
import jdk.nashorn.internal.ir.CaseNode;
import jdk.nashorn.internal.ir.CatchNode;
+import jdk.nashorn.internal.ir.Expression;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
@@ -72,7 +73,6 @@ import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ObjectNode;
-import jdk.nashorn.internal.ir.PropertyNode;
import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.RuntimeNode.Request;
@@ -94,7 +94,6 @@ import jdk.nashorn.internal.runtime.DebugLogger;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.Property;
import jdk.nashorn.internal.runtime.PropertyMap;
-import jdk.nashorn.internal.runtime.ScriptObject;
/**
* This is the attribution pass of the code generator. Attr takes Lowered IR,
@@ -166,19 +165,19 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
}
private void initFunctionWideVariables(final FunctionNode functionNode, final Block body) {
- initCompileConstant(CALLEE, body, IS_PARAM | IS_INTERNAL, FunctionNode.FUNCTION_TYPE);
+ initCompileConstant(CALLEE, body, IS_PARAM | IS_INTERNAL);
initCompileConstant(THIS, body, IS_PARAM | IS_THIS, Type.OBJECT);
if (functionNode.isVarArg()) {
- initCompileConstant(VARARGS, body, IS_PARAM | IS_INTERNAL, Type.OBJECT_ARRAY);
+ initCompileConstant(VARARGS, body, IS_PARAM | IS_INTERNAL);
if (functionNode.needsArguments()) {
- initCompileConstant(ARGUMENTS, body, IS_VAR | IS_INTERNAL | IS_ALWAYS_DEFINED, Type.typeFor(ScriptObject.class));
+ initCompileConstant(ARGUMENTS, body, IS_VAR | IS_INTERNAL | IS_ALWAYS_DEFINED);
addLocalDef(ARGUMENTS.symbolName());
}
}
initParameters(functionNode, body);
- initCompileConstant(SCOPE, body, IS_VAR | IS_INTERNAL | IS_ALWAYS_DEFINED, Type.typeFor(ScriptObject.class));
+ initCompileConstant(SCOPE, body, IS_VAR | IS_INTERNAL | IS_ALWAYS_DEFINED);
initCompileConstant(RETURN, body, IS_VAR | IS_INTERNAL | IS_ALWAYS_DEFINED, Type.OBJECT);
}
@@ -234,10 +233,25 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
@Override
public boolean enterVarNode(final VarNode varNode) {
final String name = varNode.getName().getName();
- //if this is used the var node symbol needs to be tagged as can be undefined
+ //if this is used before the var node, the var node symbol needs to be tagged as can be undefined
if (uses.contains(name)) {
canBeUndefined.add(name);
}
+
+ // all uses of the declared varnode inside the var node are potentially undefined
+ // however this is a bit conservative as e.g. var x = 17; var x = 1 + x; does work
+ if (!varNode.isFunctionDeclaration() && varNode.getInit() != null) {
+ varNode.getInit().accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ @Override
+ public boolean enterIdentNode(final IdentNode identNode) {
+ if (name.equals(identNode.getName())) {
+ canBeUndefined.add(name);
+ }
+ return false;
+ }
+ });
+ }
+
return true;
}
@@ -257,6 +271,7 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
}
return varNode.setName((IdentNode)ident.setSymbol(lc, symbol));
}
+
return varNode;
}
});
@@ -326,10 +341,11 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
catchNestingLevel++;
// define block-local exception variable
- final Symbol def = defineSymbol(block, exception.getName(), IS_VAR | IS_LET | IS_ALWAYS_DEFINED);
+ final String exname = exception.getName();
+ final Symbol def = defineSymbol(block, exname, IS_VAR | IS_LET | IS_ALWAYS_DEFINED);
newType(def, Type.OBJECT); //we can catch anything, not just ecma exceptions
- addLocalDef(exception.getName());
+ addLocalDef(exname);
return true;
}
@@ -496,7 +512,6 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
assert nameSymbol != null;
selfInit = selfInit.setName((IdentNode)name.setSymbol(lc, nameSymbol));
- selfInit = (VarNode)selfInit.setSymbol(lc, nameSymbol);
newStatements.add(selfInit);
newStatements.addAll(body.getStatements());
@@ -661,7 +676,7 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
if (scopeBlock != null) {
assert lc.contains(scopeBlock);
- lc.setFlag(scopeBlock, Block.NEEDS_SCOPE);
+ lc.setBlockNeedsScope(scopeBlock);
}
}
}
@@ -724,14 +739,9 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
}
@Override
- public Node leavePropertyNode(final PropertyNode propertyNode) {
- // assign a pseudo symbol to property name, see NASHORN-710
- return propertyNode.setSymbol(lc, new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT));
- }
-
- @Override
public Node leaveReturnNode(final ReturnNode returnNode) {
- final Node expr = returnNode.getExpression();
+ final Expression expr = returnNode.getExpression();
+ final Type returnType;
if (expr != null) {
//we can't do parameter specialization if we return something that hasn't been typed yet
@@ -740,10 +750,12 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
symbol.setType(Type.OBJECT);
}
- final Type returnType = Type.widest(returnTypes.pop(), symbol.getSymbolType());
- returnTypes.push(returnType);
- LOG.info("Returntype is now ", returnType);
+ returnType = Type.widest(returnTypes.pop(), symbol.getSymbolType());
+ } else {
+ returnType = Type.OBJECT; //undefined
}
+ LOG.info("Returntype is now ", returnType);
+ returnTypes.push(returnType);
end(returnNode);
@@ -765,7 +777,7 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
final LiteralNode<?> lit = (LiteralNode<?>)test;
if (lit.isNumeric() && !(lit.getValue() instanceof Integer)) {
if (JSType.isRepresentableAsInt(lit.getNumber())) {
- newCaseNode = caseNode.setTest(LiteralNode.newInstance(lit, lit.getInt32()).accept(this));
+ newCaseNode = caseNode.setTest((Expression)LiteralNode.newInstance(lit, lit.getInt32()).accept(this));
}
}
} else {
@@ -774,6 +786,9 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
}
type = Type.widest(type, newCaseNode.getTest().getType());
+ if (type.isBoolean()) {
+ type = Type.OBJECT; //booleans and integers aren't assignment compatible
+ }
}
newCases.add(newCaseNode);
@@ -825,19 +840,18 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
@Override
public Node leaveVarNode(final VarNode varNode) {
- VarNode newVarNode = varNode;
-
- final Node init = newVarNode.getInit();
- final IdentNode ident = newVarNode.getName();
- final String name = ident.getName();
+ final Expression init = varNode.getInit();
+ final IdentNode ident = varNode.getName();
+ final String name = ident.getName();
- final Symbol symbol = findSymbol(lc.getCurrentBlock(), ident.getName());
+ final Symbol symbol = findSymbol(lc.getCurrentBlock(), name);
+ assert ident.getSymbol() == symbol;
if (init == null) {
// var x; with no init will be treated like a use of x by
// leaveIdentNode unless we remove the name from the localdef list.
removeLocalDef(name);
- return end(newVarNode.setSymbol(lc, symbol));
+ return end(varNode);
}
addLocalDef(name);
@@ -846,8 +860,7 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
final IdentNode newIdent = (IdentNode)ident.setSymbol(lc, symbol);
- newVarNode = newVarNode.setName(newIdent);
- newVarNode = (VarNode)newVarNode.setSymbol(lc, symbol);
+ final VarNode newVarNode = varNode.setName(newIdent);
final boolean isScript = lc.getDefiningFunction(symbol).isProgram(); //see NASHORN-56
if ((init.getType().isNumeric() || init.getType().isBoolean()) && !isScript) {
@@ -857,7 +870,7 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
newType(symbol, Type.OBJECT);
}
- assert newVarNode.hasType() : newVarNode + " has no type";
+ assert newVarNode.getName().hasType() : newVarNode + " has no type";
return end(newVarNode);
}
@@ -885,11 +898,11 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
public Node leaveDELETE(final UnaryNode unaryNode) {
final FunctionNode currentFunctionNode = lc.getCurrentFunction();
final boolean strictMode = currentFunctionNode.isStrict();
- final Node rhs = unaryNode.rhs();
- final Node strictFlagNode = LiteralNode.newInstance(unaryNode, strictMode).accept(this);
+ final Expression rhs = unaryNode.rhs();
+ final Expression strictFlagNode = (Expression)LiteralNode.newInstance(unaryNode, strictMode).accept(this);
Request request = Request.DELETE;
- final List<Node> args = new ArrayList<>();
+ final List<Expression> args = new ArrayList<>();
if (rhs instanceof IdentNode) {
// If this is a declared variable or a function parameter, delete always fails (except for globals).
@@ -900,7 +913,7 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
if (failDelete && rhs.getSymbol().isThis()) {
return LiteralNode.newInstance(unaryNode, true).accept(this);
}
- final Node literalNode = LiteralNode.newInstance(unaryNode, name).accept(this);
+ final Expression literalNode = (Expression)LiteralNode.newInstance(unaryNode, name).accept(this);
if (!failDelete) {
args.add(compilerConstant(SCOPE));
@@ -912,16 +925,17 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
request = Request.FAIL_DELETE;
}
} else if (rhs instanceof AccessNode) {
- final Node base = ((AccessNode)rhs).getBase();
- final IdentNode property = ((AccessNode)rhs).getProperty();
+ final Expression base = ((AccessNode)rhs).getBase();
+ final IdentNode property = ((AccessNode)rhs).getProperty();
args.add(base);
- args.add(LiteralNode.newInstance(unaryNode, property.getName()).accept(this));
+ args.add((Expression)LiteralNode.newInstance(unaryNode, property.getName()).accept(this));
args.add(strictFlagNode);
} else if (rhs instanceof IndexNode) {
- final Node base = ((IndexNode)rhs).getBase();
- final Node index = ((IndexNode)rhs).getIndex();
+ final IndexNode indexNode = (IndexNode)rhs;
+ final Expression base = indexNode.getBase();
+ final Expression index = indexNode.getIndex();
args.add(base);
args.add(index);
@@ -976,15 +990,15 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
@Override
public Node leaveTYPEOF(final UnaryNode unaryNode) {
- final Node rhs = unaryNode.rhs();
+ final Expression rhs = unaryNode.rhs();
- List<Node> args = new ArrayList<>();
+ List<Expression> args = new ArrayList<>();
if (rhs instanceof IdentNode && !rhs.getSymbol().isParam() && !rhs.getSymbol().isVar()) {
args.add(compilerConstant(SCOPE));
- args.add(LiteralNode.newInstance(rhs, ((IdentNode)rhs).getName()).accept(this)); //null
+ args.add((Expression)LiteralNode.newInstance(rhs, ((IdentNode)rhs).getName()).accept(this)); //null
} else {
args.add(rhs);
- args.add(LiteralNode.newInstance(unaryNode).accept(this)); //null, do not reuse token of identifier rhs, it can be e.g. 'this'
+ args.add((Expression)LiteralNode.newInstance(unaryNode).accept(this)); //null, do not reuse token of identifier rhs, it can be e.g. 'this'
}
RuntimeNode runtimeNode = new RuntimeNode(unaryNode, Request.TYPEOF, args);
@@ -1009,10 +1023,7 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
@Override
public Node leaveVOID(final UnaryNode unaryNode) {
- final RuntimeNode runtimeNode = (RuntimeNode)new RuntimeNode(unaryNode, Request.VOID).accept(this);
- assert runtimeNode.getSymbol().getSymbolType().isObject();
- end(unaryNode);
- return runtimeNode;
+ return end(ensureSymbol(Type.OBJECT, unaryNode));
}
/**
@@ -1021,8 +1032,8 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
*/
@Override
public Node leaveADD(final BinaryNode binaryNode) {
- final Node lhs = binaryNode.lhs();
- final Node rhs = binaryNode.rhs();
+ final Expression lhs = binaryNode.lhs();
+ final Expression rhs = binaryNode.rhs();
ensureTypeNotUnknown(lhs);
ensureTypeNotUnknown(rhs);
@@ -1077,8 +1088,8 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
private Node leaveAssignmentNode(final BinaryNode binaryNode) {
BinaryNode newBinaryNode = binaryNode;
- final Node lhs = binaryNode.lhs();
- final Node rhs = binaryNode.rhs();
+ final Expression lhs = binaryNode.lhs();
+ final Expression rhs = binaryNode.rhs();
final Type type;
if (rhs.getType().isNumeric()) {
@@ -1114,8 +1125,8 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
@Override
public Node leaveASSIGN_ADD(final BinaryNode binaryNode) {
- final Node lhs = binaryNode.lhs();
- final Node rhs = binaryNode.rhs();
+ final Expression lhs = binaryNode.lhs();
+ final Expression rhs = binaryNode.rhs();
final Type widest = Type.widest(lhs.getType(), rhs.getType());
//Type.NUMBER if we can't prove that the add doesn't overflow. todo
@@ -1394,19 +1405,26 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
@Override
public Node leaveTernaryNode(final TernaryNode ternaryNode) {
- final Node lhs = ternaryNode.rhs();
- final Node rhs = ternaryNode.third();
+ final Expression trueExpr = ternaryNode.getTrueExpression();
+ final Expression falseExpr = ternaryNode.getFalseExpression();
- ensureTypeNotUnknown(lhs);
- ensureTypeNotUnknown(rhs);
+ ensureTypeNotUnknown(trueExpr);
+ ensureTypeNotUnknown(falseExpr);
- final Type type = Type.widest(lhs.getType(), rhs.getType());
+ final Type type = Type.widest(trueExpr.getType(), falseExpr.getType());
return end(ensureSymbol(type, ternaryNode));
}
+ private void initCompileConstant(final CompilerConstants cc, final Block block, final int flags) {
+ final Class<?> type = cc.type();
+ // Must not call this method for constants with no explicit types; use the one with (..., Type) signature instead.
+ assert type != null;
+ initCompileConstant(cc, block, flags, Type.typeFor(type));
+ }
+
private void initCompileConstant(final CompilerConstants cc, final Block block, final int flags, final Type type) {
final Symbol symbol = defineSymbol(block, cc.symbolName(), flags);
- newType(symbol, type);
+ symbol.setTypeOverride(type);
symbol.setNeedsSlot(true);
}
@@ -1511,7 +1529,7 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
}
}
- private static void ensureTypeNotUnknown(final Node node) {
+ private static void ensureTypeNotUnknown(final Expression node) {
final Symbol symbol = node.getSymbol();
@@ -1568,13 +1586,13 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
*
* @param assignmentDest the destination node of the assignment, e.g. lhs for binary nodes
*/
- private Node ensureAssignmentSlots(final Node assignmentDest) {
+ private Expression ensureAssignmentSlots(final Expression assignmentDest) {
final LexicalContext attrLexicalContext = lc;
- return assignmentDest.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ return (Expression)assignmentDest.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
public Node leaveIndexNode(final IndexNode indexNode) {
assert indexNode.getSymbol().isTemp();
- final Node index = indexNode.getIndex();
+ final Expression index = indexNode.getIndex();
//only temps can be set as needing slots. the others will self resolve
//it is illegal to take a scope var and force it to be a slot, that breaks
Symbol indexSymbol = index.getSymbol();
@@ -1616,7 +1634,7 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
changed.clear();
final FunctionNode newFunctionNode = (FunctionNode)currentFunctionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
- private Node widen(final Node node, final Type to) {
+ private Expression widen(final Expression node, final Type to) {
if (node instanceof LiteralNode) {
return node;
}
@@ -1628,7 +1646,7 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
symbol = temporarySymbols.getTypedTemporarySymbol(to);
}
newType(symbol, to);
- final Node newNode = node.setSymbol(lc, symbol);
+ final Expression newNode = node.setSymbol(lc, symbol);
changed.add(newNode);
return newNode;
}
@@ -1683,7 +1701,7 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
private Node leaveSelfModifyingAssignmentNode(final BinaryNode binaryNode, final Type destType) {
//e.g. for -=, Number, no wider, destType (binaryNode.getWidestOperationType()) is the coerce type
- final Node lhs = binaryNode.lhs();
+ final Expression lhs = binaryNode.lhs();
newType(lhs.getSymbol(), destType); //may not narrow if dest is already wider than destType
// ensureSymbol(destType, binaryNode); //for OP= nodes, the node can carry a narrower types than its lhs rhs. This is perfectly fine
@@ -1691,9 +1709,9 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
return end(ensureSymbol(destType, ensureAssignmentSlots(binaryNode)));
}
- private Node ensureSymbol(final Type type, final Node node) {
+ private Expression ensureSymbol(final Type type, final Expression expr) {
LOG.info("New TEMPORARY added to ", lc.getCurrentFunction().getName(), " type=", type);
- return temporarySymbols.ensureSymbol(lc, type, node);
+ return temporarySymbols.ensureSymbol(lc, type, expr);
}
private Symbol newInternal(final String name, final Type type) {
@@ -1815,11 +1833,11 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
return true;
}
- private Node end(final Node node) {
+ private <T extends Node> T end(final T node) {
return end(node, true);
}
- private Node end(final Node node, final boolean printNode) {
+ private <T extends Node> T end(final T node, final boolean printNode) {
if(node instanceof Statement) {
// If we're done with a statement, all temporaries can be reused.
temporarySymbols.reuse();
@@ -1834,10 +1852,13 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
append(" in '").
append(lc.getCurrentFunction().getName());
- if (node.getSymbol() == null) {
- sb.append(" <NO SYMBOL>");
- } else {
- sb.append(" <symbol=").append(node.getSymbol()).append('>');
+ if(node instanceof Expression) {
+ final Symbol symbol = ((Expression)node).getSymbol();
+ if (symbol == null) {
+ sb.append(" <NO SYMBOL>");
+ } else {
+ sb.append(" <symbol=").append(symbol).append('>');
+ }
}
LOG.unindent();
diff --git a/src/jdk/nashorn/internal/codegen/BranchOptimizer.java b/src/jdk/nashorn/internal/codegen/BranchOptimizer.java
index ee922115..02ea95f1 100644
--- a/src/jdk/nashorn/internal/codegen/BranchOptimizer.java
+++ b/src/jdk/nashorn/internal/codegen/BranchOptimizer.java
@@ -34,7 +34,7 @@ import static jdk.nashorn.internal.codegen.Condition.NE;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.BinaryNode;
-import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.Expression;
import jdk.nashorn.internal.ir.TernaryNode;
import jdk.nashorn.internal.ir.UnaryNode;
@@ -52,16 +52,16 @@ final class BranchOptimizer {
this.method = method;
}
- void execute(final Node node, final Label label, final boolean state) {
+ void execute(final Expression node, final Label label, final boolean state) {
branchOptimizer(node, label, state);
}
- private void load(final Node node) {
+ private void load(final Expression node) {
codegen.load(node);
}
private void branchOptimizer(final UnaryNode unaryNode, final Label label, final boolean state) {
- final Node rhs = unaryNode.rhs();
+ final Expression rhs = unaryNode.rhs();
switch (unaryNode.tokenType()) {
case NOT:
@@ -88,8 +88,8 @@ final class BranchOptimizer {
}
private void branchOptimizer(final BinaryNode binaryNode, final Label label, final boolean state) {
- final Node lhs = binaryNode.lhs();
- final Node rhs = binaryNode.rhs();
+ final Expression lhs = binaryNode.lhs();
+ final Expression rhs = binaryNode.rhs();
switch (binaryNode.tokenType()) {
case AND:
@@ -173,7 +173,7 @@ final class BranchOptimizer {
}
}
- private void branchOptimizer(final Node node, final Label label, final boolean state) {
+ private void branchOptimizer(final Expression node, final Label label, final boolean state) {
if (!(node instanceof TernaryNode)) {
if (node instanceof BinaryNode) {
diff --git a/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk/nashorn/internal/codegen/CodeGenerator.java
index 414d1bb8..9503e95a 100644
--- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java
+++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java
@@ -55,10 +55,12 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
+import java.util.Set;
import java.util.TreeMap;
import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
@@ -69,6 +71,7 @@ import jdk.nashorn.internal.ir.AccessNode;
import jdk.nashorn.internal.ir.BaseNode;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
+import jdk.nashorn.internal.ir.BlockStatement;
import jdk.nashorn.internal.ir.BreakNode;
import jdk.nashorn.internal.ir.BreakableNode;
import jdk.nashorn.internal.ir.CallNode;
@@ -76,7 +79,8 @@ import jdk.nashorn.internal.ir.CaseNode;
import jdk.nashorn.internal.ir.CatchNode;
import jdk.nashorn.internal.ir.ContinueNode;
import jdk.nashorn.internal.ir.EmptyNode;
-import jdk.nashorn.internal.ir.ExecuteNode;
+import jdk.nashorn.internal.ir.Expression;
+import jdk.nashorn.internal.ir.ExpressionStatement;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
@@ -109,6 +113,8 @@ import jdk.nashorn.internal.ir.WithNode;
import jdk.nashorn.internal.ir.debug.ASTWriter;
import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.objects.Global;
+import jdk.nashorn.internal.objects.ScriptFunctionImpl;
import jdk.nashorn.internal.parser.Lexer.RegexToken;
import jdk.nashorn.internal.parser.TokenType;
import jdk.nashorn.internal.runtime.Context;
@@ -148,11 +154,9 @@ import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
*/
final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContext> {
- /** Name of the Global object, cannot be referred to as .class, @see CodeGenerator */
- private static final String GLOBAL_OBJECT = Compiler.OBJECTS_PACKAGE + '/' + "Global";
+ private static final String GLOBAL_OBJECT = Type.getInternalName(Global.class);
- /** Name of the ScriptFunctionImpl, cannot be referred to as .class @see FunctionObjectCreator */
- private static final String SCRIPTFUNCTION_IMPL_OBJECT = Compiler.OBJECTS_PACKAGE + '/' + "ScriptFunctionImpl";
+ private static final String SCRIPTFUNCTION_IMPL_OBJECT = Type.getInternalName(ScriptFunctionImpl.class);
/** Constant data & installation. The only reason the compiler keeps this is because it is assigned
* by reflection in class installation */
@@ -179,6 +183,10 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
private static final DebugLogger LOG = new DebugLogger("codegen", "nashorn.codegen.debug");
+ /** From what size should we use spill instead of fields for JavaScript objects? */
+ private static final int OBJECT_SPILL_THRESHOLD = 300;
+
+ private final Set<String> emittedMethods = new HashSet<>();
/**
* Constructor.
@@ -348,11 +356,11 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
*
* @return the method emitter used
*/
- MethodEmitter load(final Node node) {
+ MethodEmitter load(final Expression node) {
return load(node, false);
}
- private MethodEmitter load(final Node node, final boolean baseAlreadyOnStack) {
+ private MethodEmitter load(final Expression node, final boolean baseAlreadyOnStack) {
final Symbol symbol = node.getSymbol();
// If we lack symbols, we just generate what we see.
@@ -486,6 +494,9 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterBlock(final Block block) {
+ if(lc.isFunctionBody() && emittedMethods.contains(lc.getCurrentFunction().getName())) {
+ return false;
+ }
method.label(block.getEntryLabel());
initLocals(block);
@@ -537,11 +548,11 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return false;
}
- private int loadArgs(final List<Node> args) {
+ private int loadArgs(final List<Expression> args) {
return loadArgs(args, null, false, args.size());
}
- private int loadArgs(final List<Node> args, final String signature, final boolean isVarArg, final int argCount) {
+ private int loadArgs(final List<Expression> args, final String signature, final boolean isVarArg, final int argCount) {
// arg have already been converted to objects here.
if (isVarArg || argCount > LinkerCallSite.ARGLIMIT) {
loadArgsArray(args);
@@ -551,7 +562,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
// pad with undefined if size is too short. argCount is the real number of args
int n = 0;
final Type[] params = signature == null ? null : Type.getMethodArguments(signature);
- for (final Node arg : args) {
+ for (final Expression arg : args) {
assert arg != null;
load(arg);
if (n >= argCount) {
@@ -572,12 +583,13 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterCallNode(final CallNode callNode) {
- lineNumber(callNode);
+ lineNumber(callNode.getLineNumber());
- final List<Node> args = callNode.getArgs();
- final Node function = callNode.getFunction();
- final Block currentBlock = lc.getCurrentBlock();
+ final List<Expression> args = callNode.getArgs();
+ final Expression function = callNode.getFunction();
+ final Block currentBlock = lc.getCurrentBlock();
final CodeGeneratorLexicalContext codegenLexicalContext = lc;
+ final Type callNodeType = callNode.getType();
function.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@@ -593,7 +605,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
}
loadArgs(args);
final Type[] paramTypes = method.getTypesFromStack(args.size());
- final SharedScopeCall scopeCall = codegenLexicalContext.getScopeCall(unit, symbol, identNode.getType(), callNode.getType(), paramTypes, scopeCallFlags);
+ final SharedScopeCall scopeCall = codegenLexicalContext.getScopeCall(unit, symbol, identNode.getType(), callNodeType, paramTypes, scopeCallFlags);
return scopeCall.generateInvoke(method);
}
@@ -602,7 +614,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
method.convert(Type.OBJECT); // foo() makes no sense if foo == 3
// ScriptFunction will see CALLSITE_SCOPE and will bind scope accordingly.
method.loadNull(); //the 'this'
- method.dynamicCall(callNode.getType(), 2 + loadArgs(args), flags);
+ method.dynamicCall(callNodeType, 2 + loadArgs(args), flags);
}
private void evalCall(final IdentNode node, final int flags) {
@@ -634,14 +646,14 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
// direct call to Global.directEval
globalDirectEval();
- method.convert(callNode.getType());
+ method.convert(callNodeType);
method._goto(eval_done);
method.label(not_eval);
// This is some scope 'eval' or global eval replaced by user
// but not the built-in ECMAScript 'eval' function call
method.loadNull();
- method.dynamicCall(callNode.getType(), 2 + loadArgs(args), flags);
+ method.dynamicCall(callNodeType, 2 + loadArgs(args), flags);
method.label(eval_done);
}
@@ -666,7 +678,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
} else {
sharedScopeCall(node, flags);
}
- assert method.peekType().equals(callNode.getType()) : method.peekType() + "!=" + callNode.getType();
+ assert method.peekType().equals(callNodeType) : method.peekType() + "!=" + callNode.getType();
} else {
enterDefault(node);
}
@@ -681,8 +693,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
method.dup();
method.dynamicGet(node.getType(), node.getProperty().getName(), getCallSiteFlags(), true);
method.swap();
- method.dynamicCall(callNode.getType(), 2 + loadArgs(args), getCallSiteFlags());
- assert method.peekType().equals(callNode.getType());
+ method.dynamicCall(callNodeType, 2 + loadArgs(args), getCallSiteFlags());
+ assert method.peekType().equals(callNodeType);
return false;
}
@@ -707,6 +719,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
assert callee.getCompileUnit() != null : "no compile unit for " + callee.getName() + " " + Debug.id(callee) + " " + callNode;
method.invokestatic(callee.getCompileUnit().getUnitClassName(), callee.getName(), signature);
assert method.peekType().equals(callee.getReturnType()) : method.peekType() + " != " + callee.getReturnType();
+ method.convert(callNodeType);
return false;
}
@@ -722,7 +735,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
}
method.dynamicGetIndex(node.getType(), getCallSiteFlags(), true);
method.swap();
- method.dynamicCall(callNode.getType(), 2 + loadArgs(args), getCallSiteFlags());
+ method.dynamicCall(callNodeType, 2 + loadArgs(args), getCallSiteFlags());
assert method.peekType().equals(callNode.getType());
return false;
@@ -734,7 +747,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
load(function);
method.convert(Type.OBJECT); //TODO, e.g. booleans can be used as functions
method.loadNull(); // ScriptFunction will figure out the correct this when it sees CALLSITE_SCOPE
- method.dynamicCall(callNode.getType(), 2 + loadArgs(args), getCallSiteFlags() | CALLSITE_SCOPE);
+ method.dynamicCall(callNodeType, 2 + loadArgs(args), getCallSiteFlags() | CALLSITE_SCOPE);
assert method.peekType().equals(callNode.getType());
return false;
@@ -767,11 +780,19 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
}
@Override
- public boolean enterExecuteNode(final ExecuteNode executeNode) {
- lineNumber(executeNode);
+ public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) {
+ lineNumber(expressionStatement);
- final Node expression = executeNode.getExpression();
- expression.accept(this);
+ expressionStatement.getExpression().accept(this);
+
+ return false;
+ }
+
+ @Override
+ public boolean enterBlockStatement(final BlockStatement blockStatement) {
+ lineNumber(blockStatement);
+
+ blockStatement.getBlock().accept(this);
return false;
}
@@ -790,10 +811,10 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
}
private void enterFor(final ForNode forNode) {
- final Node init = forNode.getInit();
- final Node test = forNode.getTest();
- final Block body = forNode.getBody();
- final Node modify = forNode.getModify();
+ final Expression init = forNode.getInit();
+ final Expression test = forNode.getTest();
+ final Block body = forNode.getBody();
+ final Expression modify = forNode.getModify();
if (init != null) {
init.accept(this);
@@ -823,19 +844,13 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
private void enterForIn(final ForNode forNode) {
final Block body = forNode.getBody();
- final Node modify = forNode.getModify();
+ final Expression modify = forNode.getModify();
final Symbol iter = forNode.getIterator();
final Label loopLabel = new Label("loop");
- Node init = forNode.getInit();
-
- // We have to evaluate the optional initializer expression
- // of the iterator variable of the for-in statement.
- if (init instanceof VarNode) {
- init.accept(this);
- init = ((VarNode)init).getName();
- }
+ final Expression init = forNode.getInit();
+ assert init instanceof IdentNode;
load(modify);
assert modify.getType().isObject();
@@ -844,7 +859,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
method._goto(forNode.getContinueLabel());
method.label(loopLabel);
- new Store<Node>(init) {
+ new Store<Expression>(init) {
@Override
protected void storeNonDiscard() {
return;
@@ -877,9 +892,15 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
final FunctionNode function = lc.getCurrentFunction();
if (isFunctionBody) {
- /* Fix the predefined slots so they have numbers >= 0, like varargs. */
- if (function.needsParentScope()) {
- initParentScope();
+ if(method.hasScope()) {
+ if (function.needsParentScope()) {
+ method.loadCompilerConstant(CALLEE);
+ method.invoke(ScriptFunction.GET_SCOPE);
+ } else {
+ assert function.hasScopeBlock();
+ method.loadNull();
+ }
+ method.storeCompilerConstant(SCOPE);
}
if (function.needsArguments()) {
initArguments(function);
@@ -940,22 +961,12 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
* Create a new object based on the symbols and values, generate
* bootstrap code for object
*/
- final FieldObjectCreator<Symbol> foc = new FieldObjectCreator<Symbol>(this, nameList, newSymbols, values, true, hasArguments) {
+ new FieldObjectCreator<Symbol>(this, nameList, newSymbols, values, true, hasArguments) {
@Override
protected void loadValue(final Symbol value) {
method.load(value);
}
-
- @Override
- protected void loadScope(MethodEmitter m) {
- if (function.needsParentScope()) {
- m.loadCompilerConstant(SCOPE);
- } else {
- m.loadNull();
- }
- }
- };
- foc.makeObject(method);
+ }.makeObject(method);
// runScript(): merge scope into global
if (isFunctionBody && function.isProgram()) {
@@ -995,12 +1006,6 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
method.storeCompilerConstant(ARGUMENTS);
}
- private void initParentScope() {
- method.loadCompilerConstant(CALLEE);
- method.invoke(ScriptFunction.GET_SCOPE);
- method.storeCompilerConstant(SCOPE);
- }
-
@Override
public boolean enterFunctionNode(final FunctionNode functionNode) {
if (functionNode.isLazy()) {
@@ -1009,17 +1014,28 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return false;
}
- LOG.info("=== BEGIN ", functionNode.getName());
+ final String fnName = functionNode.getName();
+ // NOTE: we only emit the method for a function with the given name once. We can have multiple functions with
+ // the same name as a result of inlining finally blocks. However, in the future -- with type specialization,
+ // notably -- we might need to check for both name *and* signature. Of course, even that might not be
+ // sufficient; the function might have a code dependency on the type of the variables in its enclosing scopes,
+ // and the type of such a variable can be different in catch and finally blocks. So, in the future we will have
+ // to decide to either generate a unique method for each inlined copy of the function, maybe figure out its
+ // exact type closure and deduplicate based on that, or just decide that functions in finally blocks aren't
+ // worth it, and generate one method with most generic type closure.
+ if(!emittedMethods.contains(fnName)) {
+ LOG.info("=== BEGIN ", fnName);
- assert functionNode.getCompileUnit() != null : "no compile unit for " + functionNode.getName() + " " + Debug.id(functionNode);
- unit = lc.pushCompileUnit(functionNode.getCompileUnit());
- assert lc.hasCompileUnits();
+ assert functionNode.getCompileUnit() != null : "no compile unit for " + fnName + " " + Debug.id(functionNode);
+ unit = lc.pushCompileUnit(functionNode.getCompileUnit());
+ assert lc.hasCompileUnits();
- method = lc.pushMethodEmitter(unit.getClassEmitter().method(functionNode));
- // new method - reset last line number
- lastLineNumber = -1;
- // Mark end for variable tables.
- method.begin();
+ method = lc.pushMethodEmitter(unit.getClassEmitter().method(functionNode));
+ // new method - reset last line number
+ lastLineNumber = -1;
+ // Mark end for variable tables.
+ method.begin();
+ }
return true;
}
@@ -1027,13 +1043,14 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public Node leaveFunctionNode(final FunctionNode functionNode) {
try {
- method.end(); // wrap up this method
- unit = lc.popCompileUnit(functionNode.getCompileUnit());
- method = lc.popMethodEmitter(method);
- LOG.info("=== END ", functionNode.getName());
+ if(emittedMethods.add(functionNode.getName())) {
+ method.end(); // wrap up this method
+ unit = lc.popCompileUnit(functionNode.getCompileUnit());
+ method = lc.popMethodEmitter(method);
+ LOG.info("=== END ", functionNode.getName());
+ }
final FunctionNode newFunctionNode = functionNode.setState(lc, CompilationState.EMITTED);
-
newFunctionObject(newFunctionNode, functionNode);
return newFunctionNode;
} catch (final Throwable t) {
@@ -1053,7 +1070,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
public boolean enterIfNode(final IfNode ifNode) {
lineNumber(ifNode);
- final Node test = ifNode.getTest();
+ final Expression test = ifNode.getTest();
final Block pass = ifNode.getPass();
final Block fail = ifNode.getFail();
@@ -1093,7 +1110,10 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
}
private void lineNumber(final Statement statement) {
- final int lineNumber = statement.getLineNumber();
+ lineNumber(statement.getLineNumber());
+ }
+
+ private void lineNumber(int lineNumber) {
if (lineNumber != lastLineNumber) {
method.lineNumber(lineNumber);
}
@@ -1112,7 +1132,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
private MethodEmitter loadArray(final ArrayLiteralNode arrayLiteralNode, final ArrayType arrayType) {
assert arrayType == Type.INT_ARRAY || arrayType == Type.LONG_ARRAY || arrayType == Type.NUMBER_ARRAY || arrayType == Type.OBJECT_ARRAY;
- final Node[] nodes = arrayLiteralNode.getValue();
+ final Expression[] nodes = arrayLiteralNode.getValue();
final Object presets = arrayLiteralNode.getPresets();
final int[] postsets = arrayLiteralNode.getPostsets();
final Class<?> type = arrayType.getTypeClass();
@@ -1172,11 +1192,11 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return method;
}
- private void storeElement(final Node[] nodes, final Type elementType, final int index) {
+ private void storeElement(final Expression[] nodes, final Type elementType, final int index) {
method.dup();
method.load(index);
- final Node element = nodes[index];
+ final Expression element = nodes[index];
if (element == null) {
method.loadEmpty(elementType);
@@ -1188,7 +1208,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
method.arraystore();
}
- private MethodEmitter loadArgsArray(final List<Node> args) {
+ private MethodEmitter loadArgsArray(final List<Expression> args) {
final Object[] array = new Object[args.size()];
loadConstant(array);
@@ -1318,9 +1338,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return method;
}
- @SuppressWarnings("rawtypes")
@Override
- public boolean enterLiteralNode(final LiteralNode literalNode) {
+ public boolean enterLiteralNode(final LiteralNode<?> literalNode) {
assert literalNode.getSymbol() != null : literalNode + " has no symbol";
load(literalNode).store(literalNode.getSymbol());
return false;
@@ -1330,16 +1349,16 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
public boolean enterObjectNode(final ObjectNode objectNode) {
final List<PropertyNode> elements = objectNode.getElements();
- final List<String> keys = new ArrayList<>();
- final List<Symbol> symbols = new ArrayList<>();
- final List<Node> values = new ArrayList<>();
+ final List<String> keys = new ArrayList<>();
+ final List<Symbol> symbols = new ArrayList<>();
+ final List<Expression> values = new ArrayList<>();
boolean hasGettersSetters = false;
for (PropertyNode propertyNode: elements) {
- final Node value = propertyNode.getValue();
+ final Expression value = propertyNode.getValue();
final String key = propertyNode.getKeyName();
- final Symbol symbol = value == null ? null : propertyNode.getSymbol();
+ final Symbol symbol = value == null ? null : propertyNode.getKey().getSymbol();
if (value == null) {
hasGettersSetters = true;
@@ -1350,73 +1369,71 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
values.add(value);
}
- new FieldObjectCreator<Node>(this, keys, symbols, values) {
- @Override
- protected void loadValue(final Node node) {
- load(node);
- }
+ if (elements.size() > OBJECT_SPILL_THRESHOLD) {
+ new SpillObjectCreator(this, keys, symbols, values).makeObject(method);
+ } else {
+ new FieldObjectCreator<Expression>(this, keys, symbols, values) {
+ @Override
+ protected void loadValue(final Expression node) {
+ load(node);
+ }
- /**
- * Ensure that the properties start out as object types so that
- * we can do putfield initializations instead of dynamicSetIndex
- * which would be the case to determine initial property type
- * otherwise.
- *
- * Use case, it's very expensive to do a million var x = {a:obj, b:obj}
- * just to have to invalidate them immediately on initialization
- *
- * see NASHORN-594
- */
- @Override
- protected MapCreator newMapCreator(final Class<?> fieldObjectClass) {
- return new MapCreator(fieldObjectClass, keys, symbols) {
- @Override
- protected int getPropertyFlags(final Symbol symbol, final boolean isVarArg) {
- return super.getPropertyFlags(symbol, isVarArg) | Property.IS_ALWAYS_OBJECT;
- }
- };
- }
+ /**
+ * Ensure that the properties start out as object types so that
+ * we can do putfield initializations instead of dynamicSetIndex
+ * which would be the case to determine initial property type
+ * otherwise.
+ *
+ * Use case, it's very expensive to do a million var x = {a:obj, b:obj}
+ * just to have to invalidate them immediately on initialization
+ *
+ * see NASHORN-594
+ */
+ @Override
+ protected MapCreator newMapCreator(final Class<?> fieldObjectClass) {
+ return new MapCreator(fieldObjectClass, keys, symbols) {
+ @Override
+ protected int getPropertyFlags(final Symbol symbol, final boolean hasArguments) {
+ return super.getPropertyFlags(symbol, hasArguments) | Property.IS_ALWAYS_OBJECT;
+ }
+ };
+ }
- }.makeObject(method);
+ }.makeObject(method);
+ }
method.dup();
globalObjectPrototype();
method.invoke(ScriptObject.SET_PROTO);
- if (!hasGettersSetters) {
- method.store(objectNode.getSymbol());
- return false;
- }
+ if (hasGettersSetters) {
+ for (final PropertyNode propertyNode : elements) {
+ final FunctionNode getter = propertyNode.getGetter();
+ final FunctionNode setter = propertyNode.getSetter();
- for (final Node element : elements) {
- final PropertyNode propertyNode = (PropertyNode)element;
- final Object key = propertyNode.getKey();
- final FunctionNode getter = propertyNode.getGetter();
- final FunctionNode setter = propertyNode.getSetter();
+ if (getter == null && setter == null) {
+ continue;
+ }
- if (getter == null && setter == null) {
- continue;
- }
+ method.dup().loadKey(propertyNode.getKey());
- method.dup().loadKey(key);
+ if (getter == null) {
+ method.loadNull();
+ } else {
+ getter.accept(this);
+ }
- if (getter == null) {
- method.loadNull();
- } else {
- getter.accept(this);
- }
+ if (setter == null) {
+ method.loadNull();
+ } else {
+ setter.accept(this);
+ }
- if (setter == null) {
- method.loadNull();
- } else {
- setter.accept(this);
+ method.invoke(ScriptObject.SET_USER_ACCESSORS);
}
-
- method.invoke(ScriptObject.SET_USER_ACCESSORS);
}
method.store(objectNode.getSymbol());
-
return false;
}
@@ -1428,7 +1445,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
final Type returnType = lc.getCurrentFunction().getReturnType();
- final Node expression = returnNode.getExpression();
+ final Expression expression = returnNode.getExpression();
if (expression != null) {
load(expression);
} else {
@@ -1444,7 +1461,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return node instanceof LiteralNode<?> && ((LiteralNode<?>) node).isNull();
}
- private boolean nullCheck(final RuntimeNode runtimeNode, final List<Node> args, final String signature) {
+ private boolean nullCheck(final RuntimeNode runtimeNode, final List<Expression> args, final String signature) {
final Request request = runtimeNode.getRequest();
if (!Request.isEQ(request) && !Request.isNE(request)) {
@@ -1453,11 +1470,11 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
assert args.size() == 2 : "EQ or NE or TYPEOF need two args";
- Node lhs = args.get(0);
- Node rhs = args.get(1);
+ Expression lhs = args.get(0);
+ Expression rhs = args.get(1);
if (isNullLiteral(lhs)) {
- final Node tmp = lhs;
+ final Expression tmp = lhs;
lhs = rhs;
rhs = tmp;
}
@@ -1511,7 +1528,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return false;
}
- private boolean specializationCheck(final RuntimeNode.Request request, final Node node, final List<Node> args) {
+ private boolean specializationCheck(final RuntimeNode.Request request, final Expression node, final List<Expression> args) {
if (!request.canSpecialize()) {
return false;
}
@@ -1564,10 +1581,11 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
*
* TODO - remove this - Access Specializer will always know after Attr/Lower
*/
+ final List<Expression> args = runtimeNode.getArgs();
if (runtimeNode.isPrimitive() && !runtimeNode.isFinal() && isReducible(runtimeNode.getRequest())) {
- final Node lhs = runtimeNode.getArgs().get(0);
- assert runtimeNode.getArgs().size() > 1 : runtimeNode + " must have two args";
- final Node rhs = runtimeNode.getArgs().get(1);
+ final Expression lhs = args.get(0);
+ assert args.size() > 1 : runtimeNode + " must have two args";
+ final Expression rhs = args.get(1);
final Type type = runtimeNode.getType();
final Symbol symbol = runtimeNode.getSymbol();
@@ -1604,9 +1622,6 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
}
}
- // Get the request arguments.
- final List<Node> args = runtimeNode.getArgs();
-
if (nullCheck(runtimeNode, args, new FunctionSignature(false, false, runtimeNode.getType(), args).toString())) {
return false;
}
@@ -1615,7 +1630,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return false;
}
- for (final Node arg : runtimeNode.getArgs()) {
+ for (final Expression arg : args) {
load(arg).convert(Type.OBJECT); //TODO this should not be necessary below Lower
}
@@ -1626,7 +1641,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
false,
false,
runtimeNode.getType(),
- runtimeNode.getArgs().size()).toString());
+ args.size()).toString());
method.convert(runtimeNode.getType());
method.store(runtimeNode.getSymbol());
@@ -1635,8 +1650,6 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterSplitNode(final SplitNode splitNode) {
- lineNumber(splitNode);
-
final CompileUnit splitCompileUnit = splitNode.getCompileUnit();
final FunctionNode fn = lc.getCurrentFunction();
@@ -1781,7 +1794,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
public boolean enterSwitchNode(final SwitchNode switchNode) {
lineNumber(switchNode);
- final Node expression = switchNode.getExpression();
+ final Expression expression = switchNode.getExpression();
final Symbol tag = switchNode.getTag();
final boolean allInteger = tag.getSymbolType().isInteger();
final List<CaseNode> cases = switchNode.getCases();
@@ -1847,7 +1860,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
// If expression not int see if we can convert, if not use deflt to trigger default.
if (!type.isInteger()) {
method.load(deflt);
- final Class exprClass = type.getTypeClass();
+ final Class<?> exprClass = type.getTypeClass();
method.invoke(staticCallNoLookup(ScriptRuntime.class, "switchTagAsInt", int.class, exprClass.isPrimitive()? exprClass : Object.class, int.class));
}
@@ -1878,11 +1891,13 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
method.store(tag);
method.conditionalJump(Condition.NE, true, defaultLabel);
} else {
+ assert tag.getSymbolType().isObject();
+ method.convert(Type.OBJECT); //e.g. 1 literal pushed and tag is object
method.store(tag);
}
for (final CaseNode caseNode : cases) {
- final Node test = caseNode.getTest();
+ final Expression test = caseNode.getTest();
if (test != null) {
method.load(tag);
@@ -1922,10 +1937,10 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
final Source source = lc.getCurrentFunction().getSource();
- final Node expression = throwNode.getExpression();
- final int position = throwNode.position();
- final int line = source.getLine(position);
- final int column = source.getColumn(position);
+ final Expression expression = throwNode.getExpression();
+ final int position = throwNode.position();
+ final int line = source.getLine(position);
+ final int column = source.getColumn(position);
load(expression);
assert expression.getType().isObject();
@@ -1974,10 +1989,10 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
lc.push(catchBlock);
enterBlock(catchBlock);
- final CatchNode catchNode = (CatchNode)catchBlocks.get(i).getStatements().get(0);
- final IdentNode exception = catchNode.getException();
- final Node exceptionCondition = catchNode.getExceptionCondition();
- final Block catchBody = catchNode.getBody();
+ final CatchNode catchNode = (CatchNode)catchBlocks.get(i).getStatements().get(0);
+ final IdentNode exception = catchNode.getException();
+ final Expression exceptionCondition = catchNode.getExceptionCondition();
+ final Block catchBody = catchNode.getBody();
new Store<IdentNode>(exception) {
@Override
@@ -2045,7 +2060,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterVarNode(final VarNode varNode) {
- final Node init = varNode.getInit();
+ final Expression init = varNode.getInit();
if (init == null) {
return false;
@@ -2053,8 +2068,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
lineNumber(varNode);
- final Symbol varSymbol = varNode.getSymbol();
- assert varSymbol != null : "variable node " + varNode + " requires a symbol";
+ final Symbol varSymbol = varNode.getName().getSymbol();
+ assert varSymbol != null : "variable node " + varNode + " requires a name with a symbol";
assert method != null;
@@ -2074,9 +2089,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
method.dynamicSet(type, identNode.getName(), flags);
}
} else {
- assert varNode.getType() == varNode.getName().getType() : "varNode type=" + varNode.getType() + " nametype=" + varNode.getName().getType() + " inittype=" + init.getType();
-
- method.convert(varNode.getType()); // aw: convert moved here
+ method.convert(varNode.getName().getType()); // aw: convert moved here
method.store(varSymbol);
}
@@ -2087,11 +2100,11 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
public boolean enterWhileNode(final WhileNode whileNode) {
lineNumber(whileNode);
- final Node test = whileNode.getTest();
- final Block body = whileNode.getBody();
- final Label breakLabel = whileNode.getBreakLabel();
- final Label continueLabel = whileNode.getContinueLabel();
- final Label loopLabel = new Label("loop");
+ final Expression test = whileNode.getTest();
+ final Block body = whileNode.getBody();
+ final Label breakLabel = whileNode.getBreakLabel();
+ final Label continueLabel = whileNode.getContinueLabel();
+ final Label loopLabel = new Label("loop");
if (!whileNode.isDoWhile()) {
method._goto(continueLabel);
@@ -2118,8 +2131,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterWithNode(final WithNode withNode) {
- final Node expression = withNode.getExpression();
- final Node body = withNode.getBody();
+ final Expression expression = withNode.getExpression();
+ final Node body = withNode.getBody();
// It is possible to have a "pathological" case where the with block does not reference *any* identifiers. It's
// pointless, but legal. In that case, if nothing else in the method forced the assignment of a slot to the
@@ -2194,7 +2207,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
// do this better with convert calls to method. TODO
@Override
public boolean enterCONVERT(final UnaryNode unaryNode) {
- final Node rhs = unaryNode.rhs();
+ final Expression rhs = unaryNode.rhs();
final Type to = unaryNode.getType();
if (to.isObject() && rhs instanceof LiteralNode) {
@@ -2231,11 +2244,11 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterDECINC(final UnaryNode unaryNode) {
- final Node rhs = unaryNode.rhs();
- final Type type = unaryNode.getType();
- final TokenType tokenType = unaryNode.tokenType();
- final boolean isPostfix = tokenType == TokenType.DECPOSTFIX || tokenType == TokenType.INCPOSTFIX;
- final boolean isIncrement = tokenType == TokenType.INCPREFIX || tokenType == TokenType.INCPOSTFIX;
+ final Expression rhs = unaryNode.rhs();
+ final Type type = unaryNode.getType();
+ final TokenType tokenType = unaryNode.tokenType();
+ final boolean isPostfix = tokenType == TokenType.DECPOSTFIX || tokenType == TokenType.INCPOSTFIX;
+ final boolean isIncrement = tokenType == TokenType.INCPREFIX || tokenType == TokenType.INCPOSTFIX;
assert !type.isObject();
@@ -2279,7 +2292,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterDISCARD(final UnaryNode unaryNode) {
- final Node rhs = unaryNode.rhs();
+ final Expression rhs = unaryNode.rhs();
lc.pushDiscard(rhs);
load(rhs);
@@ -2296,7 +2309,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterNEW(final UnaryNode unaryNode) {
final CallNode callNode = (CallNode)unaryNode.rhs();
- final List<Node> args = callNode.getArgs();
+ final List<Expression> args = callNode.getArgs();
// Load function reference.
load(callNode.getFunction()).convert(Type.OBJECT); // must detect type error
@@ -2309,7 +2322,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterNOT(final UnaryNode unaryNode) {
- final Node rhs = unaryNode.rhs();
+ final Expression rhs = unaryNode.rhs();
load(rhs);
@@ -2335,19 +2348,26 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return false;
}
- private Node enterNumericAdd(final Node lhs, final Node rhs, final Type type, final Symbol symbol) {
+ @Override
+ public boolean enterVOID(final UnaryNode unaryNode) {
+ load(unaryNode.rhs()).pop();
+ method.loadUndefined(Type.OBJECT);
+
+ return false;
+ }
+
+ private void enterNumericAdd(final Expression lhs, final Expression rhs, final Type type, final Symbol symbol) {
assert lhs.getType().equals(rhs.getType()) && lhs.getType().equals(type) : lhs.getType() + " != " + rhs.getType() + " != " + type + " " + new ASTWriter(lhs) + " " + new ASTWriter(rhs);
load(lhs);
load(rhs);
method.add(); //if the symbol is optimistic, it always needs to be written, not on the stack?
method.store(symbol);
- return null;
}
@Override
public boolean enterADD(final BinaryNode binaryNode) {
- final Node lhs = binaryNode.lhs();
- final Node rhs = binaryNode.rhs();
+ final Expression lhs = binaryNode.lhs();
+ final Expression rhs = binaryNode.rhs();
final Type type = binaryNode.getType();
if (type.isNumeric()) {
@@ -2363,8 +2383,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
}
private boolean enterAND_OR(final BinaryNode binaryNode) {
- final Node lhs = binaryNode.lhs();
- final Node rhs = binaryNode.rhs();
+ final Expression lhs = binaryNode.lhs();
+ final Expression rhs = binaryNode.rhs();
final Label skip = new Label("skip");
@@ -2391,8 +2411,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterASSIGN(final BinaryNode binaryNode) {
- final Node lhs = binaryNode.lhs();
- final Node rhs = binaryNode.rhs();
+ final Expression lhs = binaryNode.lhs();
+ final Expression rhs = binaryNode.rhs();
final Type lhsType = lhs.getType();
final Type rhsType = rhs.getType();
@@ -2660,8 +2680,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
}
private boolean enterComma(final BinaryNode binaryNode) {
- final Node lhs = binaryNode.lhs();
- final Node rhs = binaryNode.rhs();
+ final Expression lhs = binaryNode.lhs();
+ final Expression rhs = binaryNode.rhs();
load(lhs);
load(rhs);
@@ -2692,7 +2712,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return false;
}
- private boolean enterCmp(final Node lhs, final Node rhs, final Condition cond, final Type type, final Symbol symbol) {
+ private boolean enterCmp(final Expression lhs, final Expression rhs, final Condition cond, final Type type, final Symbol symbol) {
final Type lhsType = lhs.getType();
final Type rhsType = rhs.getType();
@@ -2845,21 +2865,21 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterTernaryNode(final TernaryNode ternaryNode) {
- final Node lhs = ternaryNode.lhs();
- final Node rhs = ternaryNode.rhs();
- final Node third = ternaryNode.third();
+ final Expression test = ternaryNode.getTest();
+ final Expression trueExpr = ternaryNode.getTrueExpression();
+ final Expression falseExpr = ternaryNode.getFalseExpression();
final Symbol symbol = ternaryNode.getSymbol();
final Label falseLabel = new Label("ternary_false");
final Label exitLabel = new Label("ternary_exit");
- Type widest = Type.widest(rhs.getType(), third.getType());
- if (rhs.getType().isArray() || third.getType().isArray()) { //loadArray creates a Java array type on the stack, calls global allocate, which creates a native array type
+ Type widest = Type.widest(trueExpr.getType(), falseExpr.getType());
+ if (trueExpr.getType().isArray() || falseExpr.getType().isArray()) { //loadArray creates a Java array type on the stack, calls global allocate, which creates a native array type
widest = Type.OBJECT;
}
- load(lhs);
- assert lhs.getType().isBoolean() : "lhs in ternary must be boolean";
+ load(test);
+ assert test.getType().isBoolean() : "lhs in ternary must be boolean";
// we still keep the conversion here as the AccessSpecializer can have separated the types, e.g. var y = x ? x=55 : 17
// will left as (Object)x=55 : (Object)17 by Lower. Then the first term can be {I}x=55 of type int, which breaks the
@@ -2867,11 +2887,11 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
// to early, or Apply the AccessSpecializer too late. We are mostly probably looking for a separate type pass to
// do this property. Then we never need any conversions in CodeGenerator
method.ifeq(falseLabel);
- load(rhs);
+ load(trueExpr);
method.convert(widest);
method._goto(exitLabel);
method.label(falseLabel);
- load(third);
+ load(falseExpr);
method.convert(widest);
method.label(exitLabel);
method.store(symbol);
@@ -2924,8 +2944,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
*
* @param <T>
*/
- private abstract class SelfModifyingStore<T extends Node> extends Store<T> {
- protected SelfModifyingStore(final T assignNode, final Node target) {
+ private abstract class SelfModifyingStore<T extends Expression> extends Store<T> {
+ protected SelfModifyingStore(final T assignNode, final Expression target) {
super(assignNode, target);
}
@@ -2938,13 +2958,13 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
/**
* Helper class to generate stores
*/
- private abstract class Store<T extends Node> {
+ private abstract class Store<T extends Expression> {
/** An assignment node, e.g. x += y */
protected final T assignNode;
/** The target node to store to, e.g. x */
- private final Node target;
+ private final Expression target;
/** How deep on the stack do the arguments go if this generates an indy call */
private int depth;
@@ -2958,7 +2978,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
* @param assignNode the node representing the whole assignment
* @param target the target node of the assignment (destination)
*/
- protected Store(final T assignNode, final Node target) {
+ protected Store(final T assignNode, final Expression target) {
this.assignNode = assignNode;
this.target = target;
}
@@ -3001,8 +3021,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
private void enterBaseNode() {
assert target instanceof BaseNode : "error - base node " + target + " must be instanceof BaseNode";
- final BaseNode baseNode = (BaseNode)target;
- final Node base = baseNode.getBase();
+ final BaseNode baseNode = (BaseNode)target;
+ final Expression base = baseNode.getBase();
load(base);
method.convert(Type.OBJECT);
@@ -3023,7 +3043,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
public boolean enterIndexNode(final IndexNode node) {
enterBaseNode();
- final Node index = node.getIndex();
+ final Expression index = node.getIndex();
// could be boolean here as well
load(index);
if (!index.getType().isNumeric()) {
@@ -3173,31 +3193,24 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return;
}
- final boolean isLazy = functionNode.isLazy();
+ // Generate the object class and property map in case this function is ever used as constructor
+ final String className = SCRIPTFUNCTION_IMPL_OBJECT;
+ final int fieldCount = ObjectClassGenerator.getPaddedFieldCount(functionNode.countThisProperties());
+ final String allocatorClassName = Compiler.binaryName(ObjectClassGenerator.getClassName(fieldCount));
+ final PropertyMap allocatorMap = PropertyMap.newMap(null, 0, fieldCount, 0);
- new ObjectCreator(this, new ArrayList<String>(), new ArrayList<Symbol>(), false, false) {
- @Override
- protected void makeObject(final MethodEmitter m) {
- final String className = SCRIPTFUNCTION_IMPL_OBJECT;
-
- m._new(className).dup();
- loadConstant(new RecompilableScriptFunctionData(functionNode, compiler.getCodeInstaller(), Compiler.binaryName(getClassName()), makeMap()));
+ method._new(className).dup();
+ loadConstant(new RecompilableScriptFunctionData(functionNode, compiler.getCodeInstaller(), allocatorClassName, allocatorMap));
- if (isLazy || functionNode.needsParentScope()) {
- m.loadCompilerConstant(SCOPE);
- } else {
- m.loadNull();
- }
- m.invoke(constructorNoLookup(className, RecompilableScriptFunctionData.class, ScriptObject.class));
- }
- }.makeObject(method);
+ if (functionNode.isLazy() || functionNode.needsParentScope()) {
+ method.loadCompilerConstant(SCOPE);
+ } else {
+ method.loadNull();
+ }
+ method.invoke(constructorNoLookup(className, RecompilableScriptFunctionData.class, ScriptObject.class));
}
- /*
- * Globals are special. We cannot refer to any Global (or NativeObject) class by .class, as they are different
- * for different contexts. As far as I can tell, the only NativeObject that we need to deal with like this
- * is from the code pipeline is Global
- */
+ // calls on Global class.
private MethodEmitter globalInstance() {
return method.invokestatic(GLOBAL_OBJECT, "instance", "()L" + GLOBAL_OBJECT + ';');
}
diff --git a/src/jdk/nashorn/internal/codegen/CompilationPhase.java b/src/jdk/nashorn/internal/codegen/CompilationPhase.java
index 9f263067..5d48fb73 100644
--- a/src/jdk/nashorn/internal/codegen/CompilationPhase.java
+++ b/src/jdk/nashorn/internal/codegen/CompilationPhase.java
@@ -18,17 +18,16 @@ import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
-
import jdk.nashorn.internal.codegen.types.Range;
import jdk.nashorn.internal.codegen.types.Type;
-import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.CallNode;
+import jdk.nashorn.internal.ir.Expression;
import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.LexicalContext;
+import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.Symbol;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
-import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.TemporarySymbols;
import jdk.nashorn.internal.ir.debug.ASTWriter;
import jdk.nashorn.internal.ir.debug.PrintVisitor;
@@ -117,7 +116,7 @@ enum CompilationPhase {
final FunctionNode parent = lc.getParentFunction(functionNode);
assert parent != null;
lc.setFlag(parent, FunctionNode.HAS_LAZY_CHILDREN);
- lc.setFlag(parent.getBody(), Block.NEEDS_SCOPE);
+ lc.setBlockNeedsScope(parent.getBody());
lc.setFlag(functionNode, FunctionNode.IS_LAZY);
return functionNode;
}
@@ -258,17 +257,20 @@ enum CompilationPhase {
@Override
public Node leaveDefault(final Node node) {
- final Symbol symbol = node.getSymbol();
- if (symbol != null) {
- final Range range = symbol.getRange();
- final Type symbolType = symbol.getSymbolType();
- if (!symbolType.isNumeric()) {
- return node;
- }
- final Type rangeType = range.getType();
- if (!Type.areEquivalent(symbolType, rangeType) && Type.widest(symbolType, rangeType) == symbolType) { //we can narrow range
- RangeAnalyzer.LOG.info("[", lc.getCurrentFunction().getName(), "] ", symbol, " can be ", range.getType(), " ", symbol.getRange());
- return node.setSymbol(lc, symbol.setTypeOverrideShared(range.getType(), compiler.getTemporarySymbols()));
+ if(node instanceof Expression) {
+ final Expression expr = (Expression)node;
+ final Symbol symbol = expr.getSymbol();
+ if (symbol != null) {
+ final Range range = symbol.getRange();
+ final Type symbolType = symbol.getSymbolType();
+ if (!symbolType.isNumeric()) {
+ return expr;
+ }
+ final Type rangeType = range.getType();
+ if (!Type.areEquivalent(symbolType, rangeType) && Type.widest(symbolType, rangeType) == symbolType) { //we can narrow range
+ RangeAnalyzer.LOG.info("[", lc.getCurrentFunction().getName(), "] ", symbol, " can be ", range.getType(), " ", symbol.getRange());
+ return expr.setSymbol(lc, symbol.setTypeOverrideShared(range.getType(), compiler.getTemporarySymbols()));
+ }
}
}
return node;
diff --git a/src/jdk/nashorn/internal/codegen/Compiler.java b/src/jdk/nashorn/internal/codegen/Compiler.java
index 72fcf178..a31358f6 100644
--- a/src/jdk/nashorn/internal/codegen/Compiler.java
+++ b/src/jdk/nashorn/internal/codegen/Compiler.java
@@ -528,8 +528,8 @@ public final class Compiler {
return this.env;
}
- private static String safeSourceName(final Source source) {
- String baseName = new File(source.getName()).getName();
+ private String safeSourceName(final Source src) {
+ String baseName = new File(src.getName()).getName();
final int index = baseName.lastIndexOf(".js");
if (index != -1) {
@@ -537,6 +537,9 @@ public final class Compiler {
}
baseName = baseName.replace('.', '_').replace('-', '_');
+ if (! env._loader_per_compile) {
+ baseName = baseName + installer.getUniqueScriptId();
+ }
final String mangled = NameCodec.encode(baseName);
return mangled != null ? mangled : baseName;
diff --git a/src/jdk/nashorn/internal/codegen/CompilerConstants.java b/src/jdk/nashorn/internal/codegen/CompilerConstants.java
index 3deff98c..c8ccc1ce 100644
--- a/src/jdk/nashorn/internal/codegen/CompilerConstants.java
+++ b/src/jdk/nashorn/internal/codegen/CompilerConstants.java
@@ -100,10 +100,10 @@ public enum CompilerConstants {
CALLEE(":callee", ScriptFunction.class),
/** the varargs variable when necessary */
- VARARGS(":varargs"),
+ VARARGS(":varargs", Object[].class),
/** the arguments vector when necessary and the slot */
- ARGUMENTS("arguments", Object.class, 2),
+ ARGUMENTS("arguments", ScriptObject.class, 2),
/** prefix for iterators for for (x in ...) */
ITERATOR_PREFIX(":i", Iterator.class),
diff --git a/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java b/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java
index 974b5ba8..9e15b497 100644
--- a/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java
+++ b/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java
@@ -26,15 +26,16 @@
package jdk.nashorn.internal.codegen;
import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS;
-import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor;
+import static jdk.nashorn.internal.codegen.ObjectClassGenerator.getPaddedFieldCount;
import static jdk.nashorn.internal.codegen.types.Type.OBJECT;
import java.util.Iterator;
import java.util.List;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.Symbol;
+import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
@@ -48,6 +49,13 @@ import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
* @see jdk.nashorn.internal.ir.Node
*/
public abstract class FieldObjectCreator<T> extends ObjectCreator {
+
+ private String fieldObjectClassName;
+ private Class<?> fieldObjectClass;
+ private int fieldCount;
+ private int paddedFieldCount;
+ private int paramCount;
+
/** array of corresponding values to symbols (null for no values) */
private final List<T> values;
@@ -80,14 +88,9 @@ public abstract class FieldObjectCreator<T> extends ObjectCreator {
super(codegen, keys, symbols, isScope, hasArguments);
this.values = values;
this.callSiteFlags = codegen.getCallSiteFlags();
- }
- /**
- * Loads the scope on the stack through the passed method emitter.
- * @param method the method emitter to use
- */
- protected void loadScope(final MethodEmitter method) {
- method.loadCompilerConstant(SCOPE);
+ countFields();
+ findClass();
}
/**
@@ -137,6 +140,13 @@ public abstract class FieldObjectCreator<T> extends ObjectCreator {
}
}
+ @Override
+ protected PropertyMap makeMap() {
+ assert propertyMap == null : "property map already initialized";
+ propertyMap = newMapCreator(fieldObjectClass).makeFieldMap(hasArguments(), fieldCount, paddedFieldCount);
+ return propertyMap;
+ }
+
/**
* Technique for loading an initial value. Defined by anonymous subclasses in code gen.
*
@@ -173,4 +183,47 @@ public abstract class FieldObjectCreator<T> extends ObjectCreator {
loadValue(value);
method.dynamicSetIndex(callSiteFlags);
}
+
+ /**
+ * Locate (or indirectly create) the object container class.
+ */
+ private void findClass() {
+ fieldObjectClassName = isScope() ?
+ ObjectClassGenerator.getClassName(fieldCount, paramCount) :
+ ObjectClassGenerator.getClassName(paddedFieldCount);
+
+ try {
+ this.fieldObjectClass = Context.forStructureClass(Compiler.binaryName(fieldObjectClassName));
+ } catch (final ClassNotFoundException e) {
+ throw new AssertionError("Nashorn has encountered an internal error. Structure can not be created.");
+ }
+ }
+
+ /**
+ * Get the class name for the object class,
+ * e.g. {@code com.nashorn.oracle.scripts.JO2P0}
+ *
+ * @return script class name
+ */
+ String getClassName() {
+ return fieldObjectClassName;
+ }
+
+ /**
+ * Tally the number of fields and parameters.
+ */
+ private void countFields() {
+ for (final Symbol symbol : this.symbols) {
+ if (symbol != null) {
+ if (hasArguments() && symbol.isParam()) {
+ symbol.setFieldIndex(paramCount++);
+ } else {
+ symbol.setFieldIndex(fieldCount++);
+ }
+ }
+ }
+
+ paddedFieldCount = getPaddedFieldCount(fieldCount);
+ }
+
}
diff --git a/src/jdk/nashorn/internal/codegen/FinalizeTypes.java b/src/jdk/nashorn/internal/codegen/FinalizeTypes.java
index f9d64322..476ac745 100644
--- a/src/jdk/nashorn/internal/codegen/FinalizeTypes.java
+++ b/src/jdk/nashorn/internal/codegen/FinalizeTypes.java
@@ -31,7 +31,6 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
-
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.AccessNode;
import jdk.nashorn.internal.ir.Assignment;
@@ -40,7 +39,8 @@ import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.CallNode;
import jdk.nashorn.internal.ir.CaseNode;
import jdk.nashorn.internal.ir.CatchNode;
-import jdk.nashorn.internal.ir.ExecuteNode;
+import jdk.nashorn.internal.ir.Expression;
+import jdk.nashorn.internal.ir.ExpressionStatement;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
@@ -147,9 +147,9 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
* strings etc as well.
*/
@Override
- public Node leaveADD(final BinaryNode binaryNode) {
- final Node lhs = binaryNode.lhs();
- final Node rhs = binaryNode.rhs();
+ public Expression leaveADD(final BinaryNode binaryNode) {
+ final Expression lhs = binaryNode.lhs();
+ final Expression rhs = binaryNode.rhs();
final Type type = binaryNode.getType();
@@ -175,6 +175,14 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
if (destType == null) {
destType = specBinaryNode.getType();
}
+ // Register assignments to this object in case this is used as constructor
+ if (binaryNode.lhs() instanceof AccessNode) {
+ AccessNode accessNode = (AccessNode) binaryNode.lhs();
+
+ if (accessNode.getBase().getSymbol().isThis()) {
+ lc.getCurrentFunction().addThisProperty(accessNode.getProperty().getName());
+ }
+ }
return specBinaryNode.setRHS(convert(specBinaryNode.rhs(), destType));
}
@@ -233,7 +241,7 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
return leaveASSIGN(binaryNode);
}
- private boolean symbolIsInteger(Node node) {
+ private boolean symbolIsInteger(final Expression node) {
final Symbol symbol = node.getSymbol();
assert symbol != null && symbol.getSymbolType().isInteger() : "int coercion expected: " + Debug.id(symbol) + " " + symbol + " " + lc.getCurrentFunction().getSource();
return true;
@@ -365,7 +373,7 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
@Override
public Node leaveCatchNode(final CatchNode catchNode) {
- final Node exceptionCondition = catchNode.getExceptionCondition();
+ final Expression exceptionCondition = catchNode.getExceptionCondition();
if (exceptionCondition != null) {
return catchNode.setExceptionCondition(convert(exceptionCondition, Type.BOOLEAN));
}
@@ -373,16 +381,16 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
}
@Override
- public Node leaveExecuteNode(final ExecuteNode executeNode) {
+ public Node leaveExpressionStatement(final ExpressionStatement expressionStatement) {
temporarySymbols.reuse();
- return executeNode.setExpression(discard(executeNode.getExpression()));
+ return expressionStatement.setExpression(discard(expressionStatement.getExpression()));
}
@Override
public Node leaveForNode(final ForNode forNode) {
- final Node init = forNode.getInit();
- final Node test = forNode.getTest();
- final Node modify = forNode.getModify();
+ final Expression init = forNode.getInit();
+ final Expression test = forNode.getTest();
+ final Expression modify = forNode.getModify();
if (forNode.isForIn()) {
return forNode.setModify(lc, convert(forNode.getModify(), Type.OBJECT)); // NASHORN-400
@@ -407,10 +415,10 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
if (!functionNode.needsCallee()) {
functionNode.compilerConstant(CALLEE).setNeedsSlot(false);
}
- // Similar reasoning applies to __scope__ symbol: if the function doesn't need either parent scope or its
- // own scope, we ensure it doesn't get a slot, but we can't determine whether it needs a scope earlier than
- // this phase.
- if (!(functionNode.getBody().needsScope() || functionNode.needsParentScope())) {
+ // Similar reasoning applies to __scope__ symbol: if the function doesn't need either parent scope and none of
+ // its blocks create a scope, we ensure it doesn't get a slot, but we can't determine whether it needs a scope
+ // earlier than this phase.
+ if (!(functionNode.hasScopeBlock() || functionNode.needsParentScope())) {
functionNode.compilerConstant(SCOPE).setNeedsSlot(false);
}
@@ -432,13 +440,13 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
public boolean enterLiteralNode(final LiteralNode literalNode) {
if (literalNode instanceof ArrayLiteralNode) {
final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode;
- final Node[] array = arrayLiteralNode.getValue();
+ final Expression[] array = arrayLiteralNode.getValue();
final Type elementType = arrayLiteralNode.getElementType();
for (int i = 0; i < array.length; i++) {
final Node element = array[i];
if (element != null) {
- array[i] = convert(element.accept(this), elementType);
+ array[i] = convert((Expression)element.accept(this), elementType);
}
}
}
@@ -448,7 +456,7 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
@Override
public Node leaveReturnNode(final ReturnNode returnNode) {
- final Node expr = returnNode.getExpression();
+ final Expression expr = returnNode.getExpression();
if (expr != null) {
return returnNode.setExpression(convert(expr, lc.getCurrentFunction().getReturnType()));
}
@@ -457,8 +465,8 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
@Override
public Node leaveRuntimeNode(final RuntimeNode runtimeNode) {
- final List<Node> args = runtimeNode.getArgs();
- for (final Node arg : args) {
+ final List<Expression> args = runtimeNode.getArgs();
+ for (final Expression arg : args) {
assert !arg.getType().isUnknown();
}
return runtimeNode;
@@ -472,12 +480,12 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
return switchNode;
}
- final Node expression = switchNode.getExpression();
+ final Expression expression = switchNode.getExpression();
final List<CaseNode> cases = switchNode.getCases();
final List<CaseNode> newCases = new ArrayList<>();
for (final CaseNode caseNode : cases) {
- final Node test = caseNode.getTest();
+ final Expression test = caseNode.getTest();
newCases.add(test != null ? caseNode.setTest(convert(test, Type.OBJECT)) : caseNode);
}
@@ -488,7 +496,7 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
@Override
public Node leaveTernaryNode(final TernaryNode ternaryNode) {
- return ternaryNode.setLHS(convert(ternaryNode.lhs(), Type.BOOLEAN));
+ return ternaryNode.setTest(convert(ternaryNode.getTest(), Type.BOOLEAN));
}
@Override
@@ -498,16 +506,16 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
@Override
public Node leaveVarNode(final VarNode varNode) {
- final Node init = varNode.getInit();
+ final Expression init = varNode.getInit();
if (init != null) {
final SpecializedNode specialized = specialize(varNode);
final VarNode specVarNode = (VarNode)specialized.node;
Type destType = specialized.type;
if (destType == null) {
- destType = specVarNode.getType();
+ destType = specVarNode.getName().getType();
}
- assert specVarNode.hasType() : specVarNode + " doesn't have a type";
- final Node convertedInit = convert(init, destType);
+ assert specVarNode.getName().hasType() : specVarNode + " doesn't have a type";
+ final Expression convertedInit = convert(init, destType);
temporarySymbols.reuse();
return specVarNode.setInit(convertedInit);
}
@@ -517,7 +525,7 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
@Override
public Node leaveWhileNode(final WhileNode whileNode) {
- final Node test = whileNode.getTest();
+ final Expression test = whileNode.getTest();
if (test != null) {
return whileNode.setTest(lc, convert(test, Type.BOOLEAN));
}
@@ -592,8 +600,8 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
*/
@SuppressWarnings("fallthrough")
private Node leaveCmp(final BinaryNode binaryNode, final RuntimeNode.Request request) {
- final Node lhs = binaryNode.lhs();
- final Node rhs = binaryNode.rhs();
+ final Expression lhs = binaryNode.lhs();
+ final Expression rhs = binaryNode.rhs();
Type widest = Type.widest(lhs.getType(), rhs.getType());
@@ -689,10 +697,10 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
}
}
- <T extends Node> SpecializedNode specialize(final Assignment<T> assignment) {
+ <T extends Expression> SpecializedNode specialize(final Assignment<T> assignment) {
final Node node = ((Node)assignment);
final T lhs = assignment.getAssignmentDest();
- final Node rhs = assignment.getAssignmentSource();
+ final Expression rhs = assignment.getAssignmentSource();
if (!canHaveCallSiteType(lhs)) {
return new SpecializedNode(node, null);
@@ -711,8 +719,16 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
}
final Node newNode = assignment.setAssignmentDest(setTypeOverride(lhs, to));
- final Node typePropagatedNode = propagateType(newNode, to);
-
+ final Node typePropagatedNode;
+ if(newNode instanceof Expression) {
+ typePropagatedNode = propagateType((Expression)newNode, to);
+ } else if(newNode instanceof VarNode) {
+ // VarNode, being a statement, doesn't have its own symbol; it uses the symbol of its name instead.
+ final VarNode varNode = (VarNode)newNode;
+ typePropagatedNode = varNode.setName((IdentNode)propagateType(varNode.getName(), to));
+ } else {
+ throw new AssertionError();
+ }
return new SpecializedNode(typePropagatedNode, to);
}
@@ -752,7 +768,7 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
* @param to new type
*/
@SuppressWarnings("unchecked")
- <T extends Node> T setTypeOverride(final T node, final Type to) {
+ <T extends Expression> T setTypeOverride(final T node, final Type to) {
final Type from = node.getType();
if (!node.getType().equals(to)) {
LOG.info("Changing call override type for '", node, "' from ", node.getType(), " to ", to);
@@ -781,7 +797,7 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
* @param to destination type
* @return conversion node
*/
- private Node convert(final Node node, final Type to) {
+ private Expression convert(final Expression node, final Type to) {
assert !to.isUnknown() : "unknown type for " + node + " class=" + node.getClass();
assert node != null : "node is null";
assert node.getSymbol() != null : "node " + node + " " + node.getClass() + " has no symbol! " + lc.getCurrentFunction();
@@ -797,7 +813,7 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
return node;
}
- Node resultNode = node;
+ Expression resultNode = node;
if (node instanceof LiteralNode && !(node instanceof ArrayLiteralNode) && !to.isObject()) {
final LiteralNode<?> newNode = new LiteralNodeConstantEvaluator((LiteralNode<?>)node, to).eval();
@@ -821,9 +837,9 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
return temporarySymbols.ensureSymbol(lc, to, resultNode);
}
- private static Node discard(final Node node) {
+ private static Expression discard(final Expression node) {
if (node.getSymbol() != null) {
- final Node discard = new UnaryNode(Token.recast(node.getToken(), TokenType.DISCARD), node);
+ final UnaryNode discard = new UnaryNode(Token.recast(node.getToken(), TokenType.DISCARD), node);
//discard never has a symbol in the discard node - then it would be a nop
assert !node.isTerminal();
return discard;
@@ -846,7 +862,7 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
* @param node
* @param to
*/
- private Node propagateType(final Node node, final Type to) {
+ private Expression propagateType(final Expression node, final Type to) {
Symbol symbol = node.getSymbol();
if (symbol.isTemp() && symbol.getSymbolType() != to) {
symbol = symbol.setTypeOverrideShared(to, temporarySymbols);
diff --git a/src/jdk/nashorn/internal/codegen/FoldConstants.java b/src/jdk/nashorn/internal/codegen/FoldConstants.java
index 2331cf75..49dfbb32 100644
--- a/src/jdk/nashorn/internal/codegen/FoldConstants.java
+++ b/src/jdk/nashorn/internal/codegen/FoldConstants.java
@@ -28,8 +28,8 @@ package jdk.nashorn.internal.codegen;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
+import jdk.nashorn.internal.ir.BlockStatement;
import jdk.nashorn.internal.ir.EmptyNode;
-import jdk.nashorn.internal.ir.ExecuteNode;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.IfNode;
@@ -91,7 +91,7 @@ final class FoldConstants extends NodeVisitor<LexicalContext> {
if (test instanceof LiteralNode) {
final Block shortCut = ((LiteralNode<?>)test).isTrue() ? ifNode.getPass() : ifNode.getFail();
if (shortCut != null) {
- return new ExecuteNode(shortCut.getLineNumber(), shortCut.getToken(), shortCut.getFinish(), shortCut);
+ return new BlockStatement(ifNode.getLineNumber(), shortCut);
}
return new EmptyNode(ifNode);
}
@@ -100,9 +100,9 @@ final class FoldConstants extends NodeVisitor<LexicalContext> {
@Override
public Node leaveTernaryNode(final TernaryNode ternaryNode) {
- final Node test = ternaryNode.lhs();
+ final Node test = ternaryNode.getTest();
if (test instanceof LiteralNode) {
- return ((LiteralNode<?>)test).isTrue() ? ternaryNode.rhs() : ternaryNode.third();
+ return ((LiteralNode<?>)test).isTrue() ? ternaryNode.getTrueExpression() : ternaryNode.getFalseExpression();
}
return ternaryNode;
}
diff --git a/src/jdk/nashorn/internal/codegen/FunctionSignature.java b/src/jdk/nashorn/internal/codegen/FunctionSignature.java
index 057d2d4e..1c1b5f74 100644
--- a/src/jdk/nashorn/internal/codegen/FunctionSignature.java
+++ b/src/jdk/nashorn/internal/codegen/FunctionSignature.java
@@ -31,8 +31,8 @@ import java.lang.invoke.MethodType;
import java.util.ArrayList;
import java.util.List;
import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.ir.Expression;
import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
@@ -63,7 +63,7 @@ public final class FunctionSignature {
* @param retType what is the return type
* @param args argument list of AST Nodes
*/
- public FunctionSignature(final boolean hasSelf, final boolean hasCallee, final Type retType, final List<? extends Node> args) {
+ public FunctionSignature(final boolean hasSelf, final boolean hasCallee, final Type retType, final List<? extends Expression> args) {
this(hasSelf, hasCallee, retType, FunctionSignature.typeArray(args));
}
@@ -167,7 +167,7 @@ public final class FunctionSignature {
*
* @return the array of types
*/
- private static Type[] typeArray(final List<? extends Node> args) {
+ private static Type[] typeArray(final List<? extends Expression> args) {
if (args == null) {
return null;
}
@@ -175,7 +175,7 @@ public final class FunctionSignature {
final Type[] typeArray = new Type[args.size()];
int pos = 0;
- for (final Node arg : args) {
+ for (final Expression arg : args) {
typeArray[pos++] = arg.getType();
}
diff --git a/src/jdk/nashorn/internal/codegen/Lower.java b/src/jdk/nashorn/internal/codegen/Lower.java
index 013564c2..cc109695 100644
--- a/src/jdk/nashorn/internal/codegen/Lower.java
+++ b/src/jdk/nashorn/internal/codegen/Lower.java
@@ -32,16 +32,19 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.ListIterator;
import jdk.nashorn.internal.ir.BaseNode;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.BlockLexicalContext;
+import jdk.nashorn.internal.ir.BlockStatement;
import jdk.nashorn.internal.ir.BreakNode;
import jdk.nashorn.internal.ir.CallNode;
import jdk.nashorn.internal.ir.CatchNode;
import jdk.nashorn.internal.ir.ContinueNode;
import jdk.nashorn.internal.ir.EmptyNode;
-import jdk.nashorn.internal.ir.ExecuteNode;
+import jdk.nashorn.internal.ir.Expression;
+import jdk.nashorn.internal.ir.ExpressionStatement;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
@@ -115,6 +118,21 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
}
return newStatements;
}
+
+ @Override
+ protected Block afterSetStatements(final Block block) {
+ final List<Statement> stmts = block.getStatements();
+ for(final ListIterator<Statement> li = stmts.listIterator(stmts.size()); li.hasPrevious();) {
+ final Statement stmt = li.previous();
+ // popStatements() guarantees that the only thing after a terminal statement are uninitialized
+ // VarNodes. We skip past those, and set the terminal state of the block to the value of the
+ // terminal state of the first statement that is not an uninitialized VarNode.
+ if(!(stmt instanceof VarNode && ((VarNode)stmt).getInit() == null)) {
+ return block.setIsTerminal(this, stmt.isTerminal());
+ }
+ }
+ return block.setIsTerminal(this, false);
+ }
});
}
@@ -122,7 +140,7 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
public boolean enterBlock(final Block block) {
final FunctionNode function = lc.getCurrentFunction();
if (lc.isFunctionBody() && function.isProgram() && !function.hasDeclaredFunctions()) {
- new ExecuteNode(block.getLineNumber(), block.getToken(), block.getFinish(), LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)).accept(this);
+ new ExpressionStatement(function.getLineNumber(), block.getToken(), block.getFinish(), LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)).accept(this);
}
return true;
}
@@ -132,24 +150,20 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
//now we have committed the entire statement list to the block, but we need to truncate
//whatever is after the last terminal. block append won't append past it
- Statement last = lc.getLastStatement();
if (lc.isFunctionBody()) {
final FunctionNode currentFunction = lc.getCurrentFunction();
final boolean isProgram = currentFunction.isProgram();
+ final Statement last = lc.getLastStatement();
final ReturnNode returnNode = new ReturnNode(
- last == null ? block.getLineNumber() : last.getLineNumber(), //TODO?
+ last == null ? currentFunction.getLineNumber() : last.getLineNumber(), //TODO?
currentFunction.getToken(),
currentFunction.getFinish(),
isProgram ?
compilerConstant(RETURN) :
LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED));
- last = (Statement)returnNode.accept(this);
- }
-
- if (last != null && last.isTerminal()) {
- return block.setIsTerminal(lc, true);
+ returnNode.accept(this);
}
return block;
@@ -183,23 +197,21 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
}
@Override
- public Node leaveExecuteNode(final ExecuteNode executeNode) {
- final Node expr = executeNode.getExpression();
- ExecuteNode node = executeNode;
+ public Node leaveExpressionStatement(final ExpressionStatement expressionStatement) {
+ final Expression expr = expressionStatement.getExpression();
+ ExpressionStatement node = expressionStatement;
final FunctionNode currentFunction = lc.getCurrentFunction();
if (currentFunction.isProgram()) {
- if (!(expr instanceof Block) || expr instanceof FunctionNode) { // it's not a block, but can be a function
- if (!isInternalExpression(expr) && !isEvalResultAssignment(expr)) {
- node = executeNode.setExpression(
- new BinaryNode(
- Token.recast(
- executeNode.getToken(),
- TokenType.ASSIGN),
- compilerConstant(RETURN),
- expr));
- }
+ if (!isInternalExpression(expr) && !isEvalResultAssignment(expr)) {
+ node = expressionStatement.setExpression(
+ new BinaryNode(
+ Token.recast(
+ expressionStatement.getToken(),
+ TokenType.ASSIGN),
+ compilerConstant(RETURN),
+ expr));
}
}
@@ -207,6 +219,11 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
}
@Override
+ public Node leaveBlockStatement(BlockStatement blockStatement) {
+ return addStatement(blockStatement);
+ }
+
+ @Override
public Node leaveForNode(final ForNode forNode) {
ForNode newForNode = forNode;
@@ -290,11 +307,11 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
final IdentNode exception = new IdentNode(token, finish, lc.getCurrentFunction().uniqueName("catch_all"));
- final Block catchBody = new Block(lineNumber, token, finish, new ThrowNode(lineNumber, token, finish, new IdentNode(exception), ThrowNode.IS_SYNTHETIC_RETHROW)).
+ final Block catchBody = new Block(token, finish, new ThrowNode(lineNumber, token, finish, new IdentNode(exception), ThrowNode.IS_SYNTHETIC_RETHROW)).
setIsTerminal(lc, true); //ends with throw, so terminal
final CatchNode catchAllNode = new CatchNode(lineNumber, token, finish, new IdentNode(exception), null, catchBody, CatchNode.IS_SYNTHETIC_RETHROW);
- final Block catchAllBlock = new Block(lineNumber, token, finish, catchAllNode);
+ final Block catchAllBlock = new Block(token, finish, catchAllNode);
//catchallblock -> catchallnode (catchnode) -> exception -> throw
@@ -343,14 +360,14 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
if (!isTerminal(newStatements)) {
newStatements.add(throwNode);
}
- return new Block(throwNode.getLineNumber(), throwNode.getToken(), throwNode.getFinish(), newStatements);
+ return BlockStatement.createReplacement(throwNode, newStatements);
}
return throwNode;
}
@Override
public Node leaveBreakNode(final BreakNode breakNode) {
- return copy(breakNode, Lower.this.lc.getBreakable(breakNode.getLabel()));
+ return copy(breakNode, (Node)Lower.this.lc.getBreakable(breakNode.getLabel()));
}
@Override
@@ -360,15 +377,15 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
@Override
public Node leaveReturnNode(final ReturnNode returnNode) {
- final Node expr = returnNode.getExpression();
+ final Expression expr = returnNode.getExpression();
final List<Statement> newStatements = new ArrayList<>();
- final Node resultNode;
+ final Expression resultNode;
if (expr != null) {
//we need to evaluate the result of the return in case it is complex while
//still in the try block, store it in a result value and return it afterwards
resultNode = new IdentNode(Lower.this.compilerConstant(RETURN));
- newStatements.add(new ExecuteNode(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new BinaryNode(Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr)));
+ newStatements.add(new ExpressionStatement(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new BinaryNode(Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr)));
} else {
resultNode = null;
}
@@ -378,7 +395,7 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
newStatements.add(expr == null ? returnNode : returnNode.setExpression(resultNode));
}
- return new ExecuteNode(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new Block(returnNode.getLineNumber(), returnNode.getToken(), lc.getCurrentBlock().getFinish(), newStatements));
+ return BlockStatement.createReplacement(returnNode, lc.getCurrentBlock().getFinish(), newStatements);
}
private Node copy(final Statement endpoint, final Node targetNode) {
@@ -387,7 +404,7 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
if (!isTerminal(newStatements)) {
newStatements.add(endpoint);
}
- return new ExecuteNode(endpoint.getLineNumber(), endpoint.getToken(), endpoint.getFinish(), new Block(endpoint.getLineNumber(), endpoint.getToken(), finish, newStatements));
+ return BlockStatement.createReplacement(endpoint, finish, newStatements);
}
return endpoint;
}
@@ -449,7 +466,7 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
if (tryNode.getCatchBlocks().isEmpty()) {
newTryNode = tryNode.setFinallyBody(null);
} else {
- Block outerBody = new Block(tryNode.getLineNumber(), tryNode.getToken(), tryNode.getFinish(), new ArrayList<Statement>(Arrays.asList(tryNode.setFinallyBody(null))));
+ Block outerBody = new Block(tryNode.getToken(), tryNode.getFinish(), new ArrayList<Statement>(Arrays.asList(tryNode.setFinallyBody(null))));
newTryNode = tryNode.setBody(outerBody).setCatchBlocks(null);
}
@@ -466,7 +483,7 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
public Node leaveVarNode(final VarNode varNode) {
addStatement(varNode);
if (varNode.getFlag(VarNode.IS_LAST_FUNCTION_DECLARATION) && lc.getCurrentFunction().isProgram()) {
- new ExecuteNode(varNode.getLineNumber(), varNode.getToken(), varNode.getFinish(), new IdentNode(varNode.getName())).accept(this);
+ new ExpressionStatement(varNode.getLineNumber(), varNode.getToken(), varNode.getFinish(), new IdentNode(varNode.getName())).accept(this);
}
return varNode;
}
@@ -499,7 +516,7 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
* @param function function called by a CallNode
* @return transformed node to marker function or identity if not ident/access/indexnode
*/
- private static Node markerFunction(final Node function) {
+ private static Expression markerFunction(final Expression function) {
if (function instanceof IdentNode) {
return ((IdentNode)function).setIsFunction();
} else if (function instanceof BaseNode) {
@@ -541,15 +558,15 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
private CallNode checkEval(final CallNode callNode) {
if (callNode.getFunction() instanceof IdentNode) {
- final List<Node> args = callNode.getArgs();
- final IdentNode callee = (IdentNode)callNode.getFunction();
+ final List<Expression> args = callNode.getArgs();
+ final IdentNode callee = (IdentNode)callNode.getFunction();
// 'eval' call with at least one argument
if (args.size() >= 1 && EVAL.symbolName().equals(callee.getName())) {
final FunctionNode currentFunction = lc.getCurrentFunction();
return callNode.setEvalArgs(
new CallNode.EvalArgs(
- ensureUniqueNamesIn(args.get(0)).accept(this),
+ (Expression)ensureUniqueNamesIn(args.get(0)).accept(this),
compilerConstant(THIS),
evalLocation(callee),
currentFunction.isStrict()));
@@ -618,7 +635,7 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
* @param expression expression to check for internal symbol
* @return true if internal, false otherwise
*/
- private static boolean isInternalExpression(final Node expression) {
+ private static boolean isInternalExpression(final Expression expression) {
final Symbol symbol = expression.getSymbol();
return symbol != null && symbol.isInternal();
}
diff --git a/src/jdk/nashorn/internal/codegen/MapCreator.java b/src/jdk/nashorn/internal/codegen/MapCreator.java
index 609fac9b..6ad03c73 100644
--- a/src/jdk/nashorn/internal/codegen/MapCreator.java
+++ b/src/jdk/nashorn/internal/codegen/MapCreator.java
@@ -41,10 +41,10 @@ public class MapCreator {
private final Class<?> structure;
/** key set for object map */
- private final String[] keys;
+ final List<String> keys;
/** corresponding symbol set for object map */
- private final Symbol[] symbols;
+ final List<Symbol> symbols;
/**
* Constructor
@@ -54,11 +54,9 @@ public class MapCreator {
* @param symbols list of symbols for map
*/
MapCreator(final Class<?> structure, final List<String> keys, final List<Symbol> symbols) {
- final int size = keys.size();
-
this.structure = structure;
- this.keys = keys.toArray(new String[size]);
- this.symbols = symbols.toArray(new Symbol[size]);
+ this.keys = keys;
+ this.symbols = symbols;
}
/**
@@ -70,21 +68,37 @@ public class MapCreator {
*
* @return New map populated with accessor properties.
*/
- PropertyMap makeMap(final boolean hasArguments, final int fieldCount, final int fieldMaximum) {
+ PropertyMap makeFieldMap(final boolean hasArguments, final int fieldCount, final int fieldMaximum) {
final List<Property> properties = new ArrayList<>();
-
assert keys != null;
- for (int i = 0; i < keys.length; i++) {
- final String key = keys[i];
- final Symbol symbol = symbols[i];
+ for (int i = 0, length = keys.size(); i < length; i++) {
+ final String key = keys.get(i);
+ final Symbol symbol = symbols.get(i);
if (symbol != null && !ArrayIndex.isIntArrayIndex(key)) {
properties.add(new AccessorProperty(key, getPropertyFlags(symbol, hasArguments), structure, symbol.getFieldIndex()));
}
}
- return PropertyMap.newMap(structure, properties, fieldCount, fieldMaximum);
+ return PropertyMap.newMap(properties, fieldCount, fieldMaximum, 0);
+ }
+
+ PropertyMap makeSpillMap(final boolean hasArguments) {
+ final List<Property> properties = new ArrayList<>();
+ int spillIndex = 0;
+ assert keys != null;
+
+ for (int i = 0, length = keys.size(); i < length; i++) {
+ final String key = keys.get(i);
+ final Symbol symbol = symbols.get(i);
+
+ if (symbol != null && !ArrayIndex.isIntArrayIndex(key)) {
+ properties.add(new AccessorProperty(key, getPropertyFlags(symbol, hasArguments), spillIndex++));
+ }
+ }
+
+ return PropertyMap.newMap(properties, 0, 0, spillIndex);
}
/**
diff --git a/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java b/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java
index 934df7a6..fa3d19e5 100644
--- a/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java
+++ b/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java
@@ -74,11 +74,6 @@ public final class ObjectClassGenerator {
static final int FIELD_PADDING = 4;
/**
- * Rounding when calculating the number of fields.
- */
- static final int FIELD_ROUNDING = 4;
-
- /**
* Debug field logger
* Should we print debugging information for fields when they are generated and getters/setters are called?
*/
@@ -325,7 +320,6 @@ public final class ObjectClassGenerator {
final List<String> initFields = addFields(classEmitter, fieldCount);
final MethodEmitter init = newInitMethod(classEmitter);
- initializeToUndefined(init, className, initFields);
init.returnVoid();
init.end();
@@ -441,13 +435,13 @@ public final class ObjectClassGenerator {
* @return Open method emitter.
*/
private static MethodEmitter newInitScopeWithArgumentsMethod(final ClassEmitter classEmitter) {
- final MethodEmitter init = classEmitter.init(PropertyMap.class, ScriptObject.class, Object.class);
+ final MethodEmitter init = classEmitter.init(PropertyMap.class, ScriptObject.class, ScriptObject.class);
init.begin();
init.load(Type.OBJECT, JAVA_THIS.slot());
init.load(Type.OBJECT, INIT_MAP.slot());
init.load(Type.OBJECT, INIT_SCOPE.slot());
init.load(Type.OBJECT, INIT_ARGUMENTS.slot());
- init.invoke(constructorNoLookup(FunctionScope.class, PropertyMap.class, ScriptObject.class, Object.class));
+ init.invoke(constructorNoLookup(FunctionScope.class, PropertyMap.class, ScriptObject.class, ScriptObject.class));
return init;
}
@@ -709,6 +703,15 @@ public final class ObjectClassGenerator {
}
}
+ /**
+ * Add padding to field count to avoid creating too many classes and have some spare fields
+ * @param count the field count
+ * @return the padded field count
+ */
+ static int getPaddedFieldCount(final int count) {
+ return count / FIELD_PADDING * FIELD_PADDING + FIELD_PADDING;
+ }
+
//
// Provide generic getters and setters for undefined types. If a type is undefined, all
// and marshals the set to the correct setter depending on the type of the value being set.
diff --git a/src/jdk/nashorn/internal/codegen/ObjectCreator.java b/src/jdk/nashorn/internal/codegen/ObjectCreator.java
index b0e5a773..2a8ebba7 100644
--- a/src/jdk/nashorn/internal/codegen/ObjectCreator.java
+++ b/src/jdk/nashorn/internal/codegen/ObjectCreator.java
@@ -25,10 +25,10 @@
package jdk.nashorn.internal.codegen;
+import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
+
import java.util.List;
-import static jdk.nashorn.internal.codegen.ObjectClassGenerator.FIELD_PADDING;
import jdk.nashorn.internal.ir.Symbol;
-import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.PropertyMap;
/**
@@ -36,9 +36,6 @@ import jdk.nashorn.internal.runtime.PropertyMap;
*/
public abstract class ObjectCreator {
- /** Compile unit for this ObjectCreator, see CompileUnit */
- //protected final CompileUnit compileUnit;
-
/** List of keys to initiate in this ObjectCreator */
protected final List<String> keys;
@@ -50,12 +47,7 @@ public abstract class ObjectCreator {
private final boolean isScope;
private final boolean hasArguments;
- private int fieldCount;
- private int paddedFieldCount;
- private int paramCount;
- private String fieldObjectClassName;
- private Class<?> fieldObjectClass;
- private PropertyMap propertyMap;
+ protected PropertyMap propertyMap;
/**
* Constructor
@@ -72,41 +64,6 @@ public abstract class ObjectCreator {
this.symbols = symbols;
this.isScope = isScope;
this.hasArguments = hasArguments;
-
- countFields();
- findClass();
- }
-
- /**
- * Tally the number of fields and parameters.
- */
- private void countFields() {
- for (final Symbol symbol : this.symbols) {
- if (symbol != null) {
- if (hasArguments() && symbol.isParam()) {
- symbol.setFieldIndex(paramCount++);
- } else {
- symbol.setFieldIndex(fieldCount++);
- }
- }
- }
-
- paddedFieldCount = fieldCount + FIELD_PADDING;
- }
-
- /**
- * Locate (or indirectly create) the object container class.
- */
- private void findClass() {
- fieldObjectClassName = isScope() ?
- ObjectClassGenerator.getClassName(fieldCount, paramCount) :
- ObjectClassGenerator.getClassName(paddedFieldCount);
-
- try {
- this.fieldObjectClass = Context.forStructureClass(Compiler.binaryName(fieldObjectClassName));
- } catch (final ClassNotFoundException e) {
- throw new AssertionError("Nashorn has encountered an internal error. Structure can not be created.");
- }
}
/**
@@ -116,6 +73,12 @@ public abstract class ObjectCreator {
protected abstract void makeObject(final MethodEmitter method);
/**
+ * Construct the property map appropriate for the object.
+ * @return the newly created property map
+ */
+ protected abstract PropertyMap makeMap();
+
+ /**
* Create a new MapCreator
* @param clazz type of MapCreator
* @return map creator instantiated by type
@@ -125,12 +88,11 @@ public abstract class ObjectCreator {
}
/**
- * Construct the property map appropriate for the object.
- * @return the newly created property map
+ * Loads the scope on the stack through the passed method emitter.
+ * @param method the method emitter to use
*/
- protected PropertyMap makeMap() {
- propertyMap = newMapCreator(fieldObjectClass).makeMap(hasArguments(), fieldCount, paddedFieldCount);
- return propertyMap;
+ protected void loadScope(final MethodEmitter method) {
+ method.loadCompilerConstant(SCOPE);
}
/**
@@ -144,16 +106,6 @@ public abstract class ObjectCreator {
}
/**
- * Get the class name for the object class,
- * e.g. {@code com.nashorn.oracle.scripts.JO2P0}
- *
- * @return script class name
- */
- String getClassName() {
- return fieldObjectClassName;
- }
-
- /**
* Is this a scope object
* @return true if scope
*/
diff --git a/src/jdk/nashorn/internal/codegen/RangeAnalyzer.java b/src/jdk/nashorn/internal/codegen/RangeAnalyzer.java
index ab61d374..4056ec0c 100644
--- a/src/jdk/nashorn/internal/codegen/RangeAnalyzer.java
+++ b/src/jdk/nashorn/internal/codegen/RangeAnalyzer.java
@@ -28,11 +28,11 @@ package jdk.nashorn.internal.codegen;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
-
import jdk.nashorn.internal.codegen.types.Range;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.Assignment;
import jdk.nashorn.internal.ir.BinaryNode;
+import jdk.nashorn.internal.ir.Expression;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.LexicalContext;
@@ -87,7 +87,7 @@ final class RangeAnalyzer extends NodeOperatorVisitor<LexicalContext> {
}
//destination visited
- private Symbol setRange(final Node dest, final Range range) {
+ private Symbol setRange(final Expression dest, final Range range) {
if (range.isUnknown()) {
return null;
}
@@ -352,7 +352,6 @@ final class RangeAnalyzer extends NodeOperatorVisitor<LexicalContext> {
range = range.isUnknown() ? Range.createGenericRange() : range;
setRange(node.getName(), range);
- setRange(node, range);
}
return node;
@@ -438,12 +437,12 @@ final class RangeAnalyzer extends NodeOperatorVisitor<LexicalContext> {
* @return
*/
private static Symbol findLoopCounter(final LoopNode node) {
- final Node test = node.getTest();
+ final Expression test = node.getTest();
if (test != null && test.isComparison()) {
final BinaryNode binaryNode = (BinaryNode)test;
- final Node lhs = binaryNode.lhs();
- final Node rhs = binaryNode.rhs();
+ final Expression lhs = binaryNode.lhs();
+ final Expression rhs = binaryNode.rhs();
//detect ident cmp int_literal
if (lhs instanceof IdentNode && rhs instanceof LiteralNode && ((LiteralNode<?>)rhs).getType().isInteger()) {
diff --git a/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java b/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java
new file mode 100644
index 00000000..08dfedf1
--- /dev/null
+++ b/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java
@@ -0,0 +1,133 @@
+/*
+ * 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.codegen;
+
+import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
+import static jdk.nashorn.internal.codegen.types.Type.OBJECT;
+
+import java.util.List;
+import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.ir.Expression;
+import jdk.nashorn.internal.ir.LiteralNode;
+import jdk.nashorn.internal.ir.Symbol;
+import jdk.nashorn.internal.runtime.Property;
+import jdk.nashorn.internal.runtime.PropertyMap;
+import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.scripts.JO;
+
+/**
+ * An object creator that uses spill properties.
+ */
+public class SpillObjectCreator extends ObjectCreator {
+
+ private final List<Expression> values;
+
+ /**
+ * Constructor
+ *
+ * @param codegen code generator
+ * @param keys keys for fields in object
+ * @param symbols symbols for fields in object
+ * @param values list of values corresponding to keys
+ */
+ protected SpillObjectCreator(final CodeGenerator codegen, final List<String> keys, final List<Symbol> symbols, final List<Expression> values) {
+ super(codegen, keys, symbols, false, false);
+ this.values = values;
+ makeMap();
+ }
+
+ @Override
+ protected void makeObject(final MethodEmitter method) {
+ assert !isScope() : "spill scope objects are not currently supported";
+
+ final int length = keys.size();
+ final Object[] presetValues = new Object[propertyMap.size()];
+ final Class clazz = JO.class;
+
+ // Compute constant values
+ for (int i = 0; i < length; i++) {
+ final String key = keys.get(i);
+ final Property property = propertyMap.findProperty(key);
+
+ if (property != null) {
+ presetValues[property.getSlot()] = LiteralNode.objectAsConstant(values.get(i));
+ }
+ }
+
+ method._new(clazz).dup();
+ codegen.loadConstant(propertyMap);
+
+ method.invoke(constructorNoLookup(JO.class, PropertyMap.class));
+
+ method.dup();
+ codegen.loadConstant(presetValues);
+
+ // Create properties with non-constant values
+ for (int i = 0; i < length; i++) {
+ final String key = keys.get(i);
+ final Property property = propertyMap.findProperty(key);
+
+ if (property != null && presetValues[property.getSlot()] == LiteralNode.POSTSET_MARKER) {
+ method.dup();
+ method.load(property.getSlot());
+ codegen.load(values.get(i)).convert(OBJECT);
+ method.arraystore();
+ presetValues[property.getSlot()] = null;
+ }
+ }
+
+ method.putField(Type.typeFor(ScriptObject.class).getInternalName(), "spill", Type.OBJECT_ARRAY.getDescriptor());
+ final int callSiteFlags = codegen.getCallSiteFlags();
+
+ // Assign properties with valid array index keys
+ for (int i = 0; i < length; i++) {
+ final String key = keys.get(i);
+ final Property property = propertyMap.findProperty(key);
+ final Expression value = values.get(i);
+
+ if (property == null && value != null) {
+ method.dup();
+ method.load(keys.get(i));
+ codegen.load(value);
+ method.dynamicSetIndex(callSiteFlags);
+ }
+ }
+ }
+
+ @Override
+ protected PropertyMap makeMap() {
+ assert propertyMap == null : "property map already initialized";
+
+ propertyMap = new MapCreator(JO.class, keys, symbols) {
+ @Override
+ protected int getPropertyFlags(Symbol symbol, boolean hasArguments) {
+ return super.getPropertyFlags(symbol, hasArguments) | Property.IS_SPILL | Property.IS_ALWAYS_OBJECT;
+ }
+ }.makeSpillMap(false);
+
+ return propertyMap;
+ }
+}
diff --git a/src/jdk/nashorn/internal/codegen/Splitter.java b/src/jdk/nashorn/internal/codegen/Splitter.java
index e724ce26..a35c6dfd 100644
--- a/src/jdk/nashorn/internal/codegen/Splitter.java
+++ b/src/jdk/nashorn/internal/codegen/Splitter.java
@@ -31,7 +31,6 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-
import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
@@ -221,14 +220,13 @@ final class Splitter extends NodeVisitor<LexicalContext> {
* @return New split node.
*/
private SplitNode createBlockSplitNode(final Block parent, final FunctionNode function, final List<Statement> statements, final long weight) {
- final int lineNumber = parent.getLineNumber();
final long token = parent.getToken();
final int finish = parent.getFinish();
final String name = function.uniqueName(SPLIT_PREFIX.symbolName());
- final Block newBlock = new Block(lineNumber, token, finish, statements);
+ final Block newBlock = new Block(token, finish, statements);
- return new SplitNode(lineNumber, name, newBlock, compiler.findUnit(weight + WeighNodes.FUNCTION_WEIGHT));
+ return new SplitNode(name, newBlock, compiler.findUnit(weight + WeighNodes.FUNCTION_WEIGHT));
}
@Override
diff --git a/src/jdk/nashorn/internal/codegen/WeighNodes.java b/src/jdk/nashorn/internal/codegen/WeighNodes.java
index 1adef12b..57b3bafa 100644
--- a/src/jdk/nashorn/internal/codegen/WeighNodes.java
+++ b/src/jdk/nashorn/internal/codegen/WeighNodes.java
@@ -27,7 +27,6 @@ package jdk.nashorn.internal.codegen;
import java.util.List;
import java.util.Map;
-
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.AccessNode;
import jdk.nashorn.internal.ir.BinaryNode;
@@ -36,7 +35,7 @@ import jdk.nashorn.internal.ir.BreakNode;
import jdk.nashorn.internal.ir.CallNode;
import jdk.nashorn.internal.ir.CatchNode;
import jdk.nashorn.internal.ir.ContinueNode;
-import jdk.nashorn.internal.ir.ExecuteNode;
+import jdk.nashorn.internal.ir.ExpressionStatement;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.IdentNode;
@@ -158,8 +157,8 @@ final class WeighNodes extends NodeOperatorVisitor<LexicalContext> {
}
@Override
- public Node leaveExecuteNode(final ExecuteNode executeNode) {
- return executeNode;
+ public Node leaveExpressionStatement(final ExpressionStatement expressionStatement) {
+ return expressionStatement;
}
@Override
diff --git a/src/jdk/nashorn/internal/codegen/types/Type.java b/src/jdk/nashorn/internal/codegen/types/Type.java
index ab32a779..c1e8bfbb 100644
--- a/src/jdk/nashorn/internal/codegen/types/Type.java
+++ b/src/jdk/nashorn/internal/codegen/types/Type.java
@@ -47,9 +47,8 @@ import static jdk.internal.org.objectweb.asm.Opcodes.T_INT;
import static jdk.internal.org.objectweb.asm.Opcodes.T_LONG;
import java.lang.invoke.MethodHandle;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
@@ -548,19 +547,19 @@ public abstract class Type implements Comparable<Type>, BytecodeOps {
* @return the Type representing this class
*/
public static Type typeFor(final Class<?> clazz) {
- Type type = cache.get(clazz);
-
- if (type == null) {
- assert !clazz.isPrimitive() || clazz == void.class;
- if (clazz.isArray()) {
- type = new ArrayType(clazz);
- } else {
- type = new ObjectType(clazz);
- }
- cache.put(clazz, type);
+ final Type type = cache.get(clazz);
+ if(type != null) {
+ return type;
+ }
+ assert !clazz.isPrimitive() || clazz == void.class;
+ final Type newType;
+ if (clazz.isArray()) {
+ newType = new ArrayType(clazz);
+ } else {
+ newType = new ObjectType(clazz);
}
-
- return type;
+ final Type existingType = cache.putIfAbsent(clazz, newType);
+ return existingType == null ? newType : existingType;
}
@Override
@@ -663,35 +662,38 @@ public abstract class Type implements Comparable<Type>, BytecodeOps {
}
}
+ /** Mappings between java classes and their Type singletons */
+ private static final ConcurrentMap<Class<?>, Type> cache = new ConcurrentHashMap<>();
+
/**
* This is the boolean singleton, used for all boolean types
*/
- public static final Type BOOLEAN = new BooleanType();
+ public static final Type BOOLEAN = putInCache(new BooleanType());
/**
* This is an integer type, i.e INT, INT32.
*/
- public static final Type INT = new IntType();
+ public static final Type INT = putInCache(new IntType());
/**
* This is the number singleton, used for all number types
*/
- public static final Type NUMBER = new NumberType();
+ public static final Type NUMBER = putInCache(new NumberType());
/**
* This is the long singleton, used for all long types
*/
- public static final Type LONG = new LongType();
+ public static final Type LONG = putInCache(new LongType());
/**
* A string singleton
*/
- public static final Type STRING = new ObjectType(String.class);
+ public static final Type STRING = putInCache(new ObjectType(String.class));
/**
* This is the object singleton, used for all object types
*/
- public static final Type OBJECT = new ObjectType();
+ public static final Type OBJECT = putInCache(new ObjectType());
/**
* This is the singleton for integer arrays
@@ -775,13 +777,13 @@ public abstract class Type implements Comparable<Type>, BytecodeOps {
};
/** Singleton for method handle arrays used for properties etc. */
- public static final ArrayType METHODHANDLE_ARRAY = new ArrayType(MethodHandle[].class);
+ public static final ArrayType METHODHANDLE_ARRAY = putInCache(new ArrayType(MethodHandle[].class));
/** This is the singleton for string arrays */
- public static final ArrayType STRING_ARRAY = new ArrayType(String[].class);
+ public static final ArrayType STRING_ARRAY = putInCache(new ArrayType(String[].class));
/** This is the singleton for object arrays */
- public static final ArrayType OBJECT_ARRAY = new ArrayType(Object[].class);
+ public static final ArrayType OBJECT_ARRAY = putInCache(new ArrayType(Object[].class));
/** This type, always an object type, just a toString override */
public static final Type THIS = new ObjectType() {
@@ -855,18 +857,8 @@ public abstract class Type implements Comparable<Type>, BytecodeOps {
}
};
- /** Mappings between java classes and their Type singletons */
- private static final Map<Class<?>, Type> cache = Collections.synchronizedMap(new HashMap<Class<?>, Type>());
-
- //TODO may need to be cleared, as all types are retained throughout code generation
- static {
- cache.put(BOOLEAN.getTypeClass(), BOOLEAN);
- cache.put(INT.getTypeClass(), INT);
- cache.put(LONG.getTypeClass(), LONG);
- cache.put(NUMBER.getTypeClass(), NUMBER);
- cache.put(STRING.getTypeClass(), STRING);
- cache.put(OBJECT.getTypeClass(), OBJECT);
- cache.put(OBJECT_ARRAY.getTypeClass(), OBJECT_ARRAY);
+ private static <T extends Type> T putInCache(T type) {
+ cache.put(type.getTypeClass(), type);
+ return type;
}
-
}
diff --git a/src/jdk/nashorn/internal/ir/AccessNode.java b/src/jdk/nashorn/internal/ir/AccessNode.java
index eecc5713..55b0aa3f 100644
--- a/src/jdk/nashorn/internal/ir/AccessNode.java
+++ b/src/jdk/nashorn/internal/ir/AccessNode.java
@@ -45,12 +45,12 @@ public final class AccessNode extends BaseNode {
* @param base base node
* @param property property
*/
- public AccessNode(final long token, final int finish, final Node base, final IdentNode property) {
+ public AccessNode(final long token, final int finish, final Expression base, final IdentNode property) {
super(token, finish, base, false, false);
this.property = property.setIsPropertyName();
}
- private AccessNode(final AccessNode accessNode, final Node base, final IdentNode property, final boolean isFunction, final boolean hasCallSiteType) {
+ private AccessNode(final AccessNode accessNode, final Expression base, final IdentNode property, final boolean isFunction, final boolean hasCallSiteType) {
super(accessNode, base, isFunction, hasCallSiteType);
this.property = property;
}
@@ -63,7 +63,7 @@ public final class AccessNode extends BaseNode {
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterAccessNode(this)) {
return visitor.leaveAccessNode(
- setBase(base.accept(visitor)).
+ setBase((Expression)base.accept(visitor)).
setProperty((IdentNode)property.accept(visitor)));
}
return this;
@@ -103,7 +103,7 @@ public final class AccessNode extends BaseNode {
return property;
}
- private AccessNode setBase(final Node base) {
+ private AccessNode setBase(final Expression base) {
if (this.base == base) {
return this;
}
diff --git a/src/jdk/nashorn/internal/ir/Assignment.java b/src/jdk/nashorn/internal/ir/Assignment.java
index 0c531bc2..093b0d80 100644
--- a/src/jdk/nashorn/internal/ir/Assignment.java
+++ b/src/jdk/nashorn/internal/ir/Assignment.java
@@ -31,7 +31,7 @@ package jdk.nashorn.internal.ir;
*
* @param <D> the destination type
*/
-public interface Assignment<D extends Node> {
+public interface Assignment<D extends Expression> {
/**
* Get assignment destination
@@ -45,7 +45,7 @@ public interface Assignment<D extends Node> {
*
* @return get the assignment source node
*/
- public Node getAssignmentSource();
+ public Expression getAssignmentSource();
/**
* Set assignment destination node.
diff --git a/src/jdk/nashorn/internal/ir/BaseNode.java b/src/jdk/nashorn/internal/ir/BaseNode.java
index a1b7c0ee..f945ef35 100644
--- a/src/jdk/nashorn/internal/ir/BaseNode.java
+++ b/src/jdk/nashorn/internal/ir/BaseNode.java
@@ -26,6 +26,7 @@
package jdk.nashorn.internal.ir;
import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS;
+
import jdk.nashorn.internal.codegen.ObjectClassGenerator;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
@@ -37,10 +38,10 @@ import jdk.nashorn.internal.ir.annotations.Immutable;
* @see IndexNode
*/
@Immutable
-public abstract class BaseNode extends Node implements FunctionCall, TypeOverride<BaseNode> {
+public abstract class BaseNode extends Expression implements FunctionCall, TypeOverride<BaseNode> {
/** Base Node. */
- protected final Node base;
+ protected final Expression base;
private final boolean isFunction;
@@ -55,7 +56,7 @@ public abstract class BaseNode extends Node implements FunctionCall, TypeOverrid
* @param isFunction is this a function
* @param hasCallSiteType does this access have a callsite type
*/
- public BaseNode(final long token, final int finish, final Node base, final boolean isFunction, final boolean hasCallSiteType) {
+ public BaseNode(final long token, final int finish, final Expression base, final boolean isFunction, final boolean hasCallSiteType) {
super(token, base.getStart(), finish);
this.base = base;
this.isFunction = isFunction;
@@ -69,7 +70,7 @@ public abstract class BaseNode extends Node implements FunctionCall, TypeOverrid
* @param isFunction is this a function
* @param hasCallSiteType does this access have a callsite type
*/
- protected BaseNode(final BaseNode baseNode, final Node base, final boolean isFunction, final boolean hasCallSiteType) {
+ protected BaseNode(final BaseNode baseNode, final Expression base, final boolean isFunction, final boolean hasCallSiteType) {
super(baseNode);
this.base = base;
this.isFunction = isFunction;
@@ -80,7 +81,7 @@ public abstract class BaseNode extends Node implements FunctionCall, TypeOverrid
* Get the base node for this access
* @return the base node
*/
- public Node getBase() {
+ public Expression getBase() {
return base;
}
diff --git a/src/jdk/nashorn/internal/ir/BinaryNode.java b/src/jdk/nashorn/internal/ir/BinaryNode.java
index 4afa1945..1576fb93 100644
--- a/src/jdk/nashorn/internal/ir/BinaryNode.java
+++ b/src/jdk/nashorn/internal/ir/BinaryNode.java
@@ -34,11 +34,11 @@ import jdk.nashorn.internal.parser.TokenType;
* BinaryNode nodes represent two operand operations.
*/
@Immutable
-public final class BinaryNode extends Node implements Assignment<Node> {
+public final class BinaryNode extends Expression implements Assignment<Expression> {
/** Left hand side argument. */
- private final Node lhs;
+ private final Expression lhs;
- private final Node rhs;
+ private final Expression rhs;
/**
* Constructor
@@ -47,13 +47,13 @@ public final class BinaryNode extends Node implements Assignment<Node> {
* @param lhs left hand side
* @param rhs right hand side
*/
- public BinaryNode(final long token, final Node lhs, final Node rhs) {
+ public BinaryNode(final long token, final Expression lhs, final Expression rhs) {
super(token, lhs.getStart(), rhs.getFinish());
this.lhs = lhs;
this.rhs = rhs;
}
- private BinaryNode(final BinaryNode binaryNode, final Node lhs, final Node rhs) {
+ private BinaryNode(final BinaryNode binaryNode, final Expression lhs, final Expression rhs) {
super(binaryNode);
this.lhs = lhs;
this.rhs = rhs;
@@ -141,17 +141,17 @@ public final class BinaryNode extends Node implements Assignment<Node> {
}
@Override
- public Node getAssignmentDest() {
+ public Expression getAssignmentDest() {
return isAssignment() ? lhs() : null;
}
@Override
- public Node setAssignmentDest(Node n) {
+ public BinaryNode setAssignmentDest(Expression n) {
return setLHS(n);
}
@Override
- public Node getAssignmentSource() {
+ public Expression getAssignmentSource() {
return rhs();
}
@@ -162,7 +162,7 @@ public final class BinaryNode extends Node implements Assignment<Node> {
@Override
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterBinaryNode(this)) {
- return visitor.leaveBinaryNode(setLHS(lhs.accept(visitor)).setRHS(rhs.accept(visitor)));
+ return visitor.leaveBinaryNode(setLHS((Expression)lhs.accept(visitor)).setRHS((Expression)rhs.accept(visitor)));
}
return this;
@@ -218,7 +218,7 @@ public final class BinaryNode extends Node implements Assignment<Node> {
* Get the left hand side expression for this node
* @return the left hand side expression
*/
- public Node lhs() {
+ public Expression lhs() {
return lhs;
}
@@ -226,7 +226,7 @@ public final class BinaryNode extends Node implements Assignment<Node> {
* Get the right hand side expression for this node
* @return the left hand side expression
*/
- public Node rhs() {
+ public Expression rhs() {
return rhs;
}
@@ -235,7 +235,7 @@ public final class BinaryNode extends Node implements Assignment<Node> {
* @param lhs new left hand side expression
* @return a node equivalent to this one except for the requested change.
*/
- public BinaryNode setLHS(final Node lhs) {
+ public BinaryNode setLHS(final Expression lhs) {
if (this.lhs == lhs) {
return this;
}
@@ -247,7 +247,7 @@ public final class BinaryNode extends Node implements Assignment<Node> {
* @param rhs new left hand side expression
* @return a node equivalent to this one except for the requested change.
*/
- public BinaryNode setRHS(final Node rhs) {
+ public BinaryNode setRHS(final Expression rhs) {
if (this.rhs == rhs) {
return this;
}
diff --git a/src/jdk/nashorn/internal/ir/Block.java b/src/jdk/nashorn/internal/ir/Block.java
index 71692144..c411401e 100644
--- a/src/jdk/nashorn/internal/ir/Block.java
+++ b/src/jdk/nashorn/internal/ir/Block.java
@@ -38,11 +38,10 @@ import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
/**
- * IR representation for a list of statements and functions. All provides the
- * basis for script body.
+ * IR representation for a list of statements.
*/
@Immutable
-public class Block extends BreakableNode implements Flags<Block> {
+public class Block extends Node implements BreakableNode, Flags<Block> {
/** List of statements */
protected final List<Statement> statements;
@@ -52,6 +51,9 @@ public class Block extends BreakableNode implements Flags<Block> {
/** Entry label. */
protected final Label entryLabel;
+ /** Break label. */
+ private final Label breakLabel;
+
/** Does the block/function need a new scope? */
protected final int flags;
@@ -76,17 +78,17 @@ public class Block extends BreakableNode implements Flags<Block> {
/**
* Constructor
*
- * @param lineNumber line number
* @param token token
* @param finish finish
* @param statements statements
*/
- public Block(final int lineNumber, final long token, final int finish, final Statement... statements) {
- super(lineNumber, token, finish, new Label("block_break"));
+ public Block(final long token, final int finish, final Statement... statements) {
+ super(token, finish);
this.statements = Arrays.asList(statements);
this.symbols = new LinkedHashMap<>();
this.entryLabel = new Label("block_entry");
+ this.breakLabel = new Label("block_break");
this.flags = 0;
}
@@ -98,8 +100,8 @@ public class Block extends BreakableNode implements Flags<Block> {
* @param finish finish
* @param statements statements
*/
- public Block(final int lineNumber, final long token, final int finish, final List<Statement> statements) {
- this(lineNumber, token, finish, statements.toArray(new Statement[statements.size()]));
+ public Block(final long token, final int finish, final List<Statement> statements) {
+ this(token, finish, statements.toArray(new Statement[statements.size()]));
}
private Block(final Block block, final int finish, final List<Statement> statements, final int flags, final Map<String, Symbol> symbols) {
@@ -108,6 +110,7 @@ public class Block extends BreakableNode implements Flags<Block> {
this.flags = flags;
this.symbols = new LinkedHashMap<>(symbols); //todo - symbols have no dependencies on any IR node and can as far as we understand it be shallow copied now
this.entryLabel = new Label(block.entryLabel);
+ this.breakLabel = new Label(block.breakLabel);
this.finish = finish;
}
@@ -223,6 +226,11 @@ public class Block extends BreakableNode implements Flags<Block> {
return entryLabel;
}
+ @Override
+ public Label getBreakLabel() {
+ return breakLabel;
+ }
+
/**
* Get the list of statements in this block
*
@@ -322,7 +330,17 @@ public class Block extends BreakableNode implements Flags<Block> {
}
@Override
- protected boolean isBreakableWithoutLabel() {
+ public boolean isBreakableWithoutLabel() {
return false;
}
+
+ @Override
+ public List<Label> getLabels() {
+ return Collections.singletonList(breakLabel);
+ }
+
+ @Override
+ public Node accept(NodeVisitor<? extends LexicalContext> visitor) {
+ return Acceptor.accept(this, visitor);
+ }
}
diff --git a/src/jdk/nashorn/internal/ir/BlockLexicalContext.java b/src/jdk/nashorn/internal/ir/BlockLexicalContext.java
index 71c80a6b..8fecddd0 100644
--- a/src/jdk/nashorn/internal/ir/BlockLexicalContext.java
+++ b/src/jdk/nashorn/internal/ir/BlockLexicalContext.java
@@ -29,7 +29,6 @@ import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
-import java.util.ListIterator;
/**
* This is a subclass of lexical context used for filling
@@ -63,6 +62,16 @@ public class BlockLexicalContext extends LexicalContext {
return sstack.pop();
}
+ /**
+ * Override this method to perform some additional processing on the block after its statements have been set. By
+ * default does nothing and returns the original block.
+ * @param block the block to operate on
+ * @return a modified block.
+ */
+ protected Block afterSetStatements(Block block) {
+ return block;
+ }
+
@SuppressWarnings("unchecked")
@Override
public <T extends LexicalContextNode> T pop(final T node) {
@@ -70,6 +79,7 @@ public class BlockLexicalContext extends LexicalContext {
if (node instanceof Block) {
final List<Statement> newStatements = popStatements();
expected = (T)((Block)node).setStatements(this, newStatements);
+ expected = (T)afterSetStatements((Block)expected);
if (!sstack.isEmpty()) {
lastStatement = lastStatement(sstack.peek());
}
@@ -107,10 +117,7 @@ public class BlockLexicalContext extends LexicalContext {
}
private static Statement lastStatement(final List<Statement> statements) {
- for (final ListIterator<Statement> iter = statements.listIterator(statements.size()); iter.hasPrevious(); ) {
- final Statement node = iter.previous();
- return node;
- }
- return null;
+ final int s = statements.size();
+ return s == 0 ? null : statements.get(s - 1);
}
}
diff --git a/src/jdk/nashorn/internal/ir/BlockStatement.java b/src/jdk/nashorn/internal/ir/BlockStatement.java
new file mode 100644
index 00000000..e790cf49
--- /dev/null
+++ b/src/jdk/nashorn/internal/ir/BlockStatement.java
@@ -0,0 +1,115 @@
+/*
+ * 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.ir;
+
+import java.util.List;
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+
+/**
+ * Represents a block used as a statement.
+ */
+public class BlockStatement extends Statement {
+ /** Block to execute. */
+ private final Block block;
+
+ /**
+ * Constructor
+ *
+ * @param lineNumber line number
+ * @param block the block to execute
+ */
+ public BlockStatement(final int lineNumber, final Block block) {
+ super(lineNumber, block.getToken(), block.getFinish());
+ this.block = block;
+ }
+
+ private BlockStatement(final BlockStatement blockStatement, final Block block) {
+ super(blockStatement);
+ this.block = block;
+ }
+
+ /**
+ * Use this method to create a block statement meant to replace a single statement.
+ * @param stmt the statement to replace
+ * @param newStmts the statements for the new block statement
+ * @return a block statement with the new statements. It will have the line number, token, and finish of the
+ * original statement.
+ */
+ public static Statement createReplacement(final Statement stmt, final List<Statement> newStmts) {
+ return createReplacement(stmt, stmt.getFinish(), newStmts);
+ }
+
+ /**
+ * Use this method to create a block statement meant to replace a single statement.
+ * @param stmt the statement to replace
+ * @param finish the new finish for the block
+ * @param newStmts the statements for the new block statement
+ * @return a block statement with the new statements. It will have the line number, and token of the
+ * original statement.
+ */
+ public static Statement createReplacement(final Statement stmt, int finish, final List<Statement> newStmts) {
+ return new BlockStatement(stmt.getLineNumber(), new Block(stmt.getToken(), finish, newStmts));
+ }
+
+ @Override
+ public boolean isTerminal() {
+ return block.isTerminal();
+ }
+
+ @Override
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
+ if (visitor.enterBlockStatement(this)) {
+ return visitor.leaveBlockStatement(setBlock((Block)block.accept(visitor)));
+ }
+
+ return this;
+ }
+
+ @Override
+ public void toString(final StringBuilder sb) {
+ block.toString(sb);
+ }
+
+ /**
+ * Return the block to be executed
+ * @return the block
+ */
+ public Block getBlock() {
+ return block;
+ }
+
+ /**
+ * Reset the block to be executed
+ * @param block the block
+ * @return new or same execute node
+ */
+ public BlockStatement setBlock(final Block block) {
+ if (this.block == block) {
+ return this;
+ }
+ return new BlockStatement(this, block);
+ }
+}
diff --git a/src/jdk/nashorn/internal/ir/BreakableNode.java b/src/jdk/nashorn/internal/ir/BreakableNode.java
index 171df8e3..61528de2 100644
--- a/src/jdk/nashorn/internal/ir/BreakableNode.java
+++ b/src/jdk/nashorn/internal/ir/BreakableNode.java
@@ -25,46 +25,14 @@
package jdk.nashorn.internal.ir;
-import java.util.Arrays;
import java.util.List;
-
import jdk.nashorn.internal.codegen.Label;
-import jdk.nashorn.internal.ir.annotations.Immutable;
/**
* This class represents a node from which control flow can execute
* a {@code break} statement
*/
-@Immutable
-public abstract class BreakableNode extends LexicalContextNode {
-
- /** break label. */
- protected final Label breakLabel;
-
- /**
- * Constructor
- *
- * @param lineNumber line number
- * @param token token
- * @param finish finish
- * @param breakLabel break label
- */
- protected BreakableNode(final int lineNumber, final long token, final int finish, final Label breakLabel) {
- super(lineNumber, token, finish);
- this.breakLabel = breakLabel;
- }
-
- /**
- * Copy constructor
- *
- * @param breakableNode source node
- */
- protected BreakableNode(final BreakableNode breakableNode) {
- super(breakableNode);
- this.breakLabel = new Label(breakableNode.getBreakLabel());
- }
-
- @Override
+public interface BreakableNode extends LexicalContextNode {
public abstract Node ensureUniqueLabels(final LexicalContext lc);
/**
@@ -72,17 +40,13 @@ public abstract class BreakableNode extends LexicalContextNode {
* e.g. everything but Blocks, basically
* @return true if breakable without label
*/
- protected boolean isBreakableWithoutLabel() {
- return true;
- }
+ public boolean isBreakableWithoutLabel();
/**
* Return the break label, i.e. the location to go to on break.
* @return the break label
*/
- public Label getBreakLabel() {
- return breakLabel;
- }
+ public Label getBreakLabel();
/**
* Return the labels associated with this node. Breakable nodes that
@@ -90,8 +54,5 @@ public abstract class BreakableNode extends LexicalContextNode {
* afterwards the node in code
* @return list of labels representing locations around this node
*/
- public List<Label> getLabels() {
- return Arrays.asList(breakLabel);
- }
-
+ public List<Label> getLabels();
}
diff --git a/src/jdk/nashorn/internal/ir/BreakableStatement.java b/src/jdk/nashorn/internal/ir/BreakableStatement.java
new file mode 100644
index 00000000..fa74454e
--- /dev/null
+++ b/src/jdk/nashorn/internal/ir/BreakableStatement.java
@@ -0,0 +1,91 @@
+/*
+ * 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.ir;
+
+import java.util.Collections;
+import java.util.List;
+import jdk.nashorn.internal.codegen.Label;
+import jdk.nashorn.internal.ir.annotations.Immutable;
+
+@Immutable
+abstract class BreakableStatement extends LexicalContextStatement implements BreakableNode {
+
+ /** break label. */
+ protected final Label breakLabel;
+
+ /**
+ * Constructor
+ *
+ * @param lineNumber line number
+ * @param token token
+ * @param finish finish
+ * @param breakLabel break label
+ */
+ protected BreakableStatement(final int lineNumber, final long token, final int finish, final Label breakLabel) {
+ super(lineNumber, token, finish);
+ this.breakLabel = breakLabel;
+ }
+
+ /**
+ * Copy constructor
+ *
+ * @param breakableNode source node
+ */
+ protected BreakableStatement(final BreakableStatement breakableNode) {
+ super(breakableNode);
+ this.breakLabel = new Label(breakableNode.getBreakLabel());
+ }
+
+ /**
+ * Check whether this can be broken out from without using a label,
+ * e.g. everything but Blocks, basically
+ * @return true if breakable without label
+ */
+ @Override
+ public boolean isBreakableWithoutLabel() {
+ return true;
+ }
+
+ /**
+ * Return the break label, i.e. the location to go to on break.
+ * @return the break label
+ */
+ @Override
+ public Label getBreakLabel() {
+ return breakLabel;
+ }
+
+ /**
+ * Return the labels associated with this node. Breakable nodes that
+ * aren't LoopNodes only have a break label - the location immediately
+ * afterwards the node in code
+ * @return list of labels representing locations around this node
+ */
+ @Override
+ public List<Label> getLabels() {
+ return Collections.singletonList(breakLabel);
+ }
+}
diff --git a/src/jdk/nashorn/internal/ir/CallNode.java b/src/jdk/nashorn/internal/ir/CallNode.java
index 7180d9ce..ffaae078 100644
--- a/src/jdk/nashorn/internal/ir/CallNode.java
+++ b/src/jdk/nashorn/internal/ir/CallNode.java
@@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir;
import java.util.Collections;
import java.util.List;
-
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Ignore;
import jdk.nashorn.internal.ir.annotations.Immutable;
@@ -37,27 +36,29 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
* IR representation for a function call.
*/
@Immutable
-public final class CallNode extends LexicalContextNode implements TypeOverride<CallNode> {
+public final class CallNode extends LexicalContextExpression implements TypeOverride<CallNode> {
private final Type type;
/** Function identifier or function body. */
- private final Node function;
+ private final Expression function;
/** Call arguments. */
- private final List<Node> args;
+ private final List<Expression> args;
/** Is this a "new" operation */
public static final int IS_NEW = 0x1;
private final int flags;
+ private final int lineNumber;
+
/**
* Arguments to be passed to builtin {@code eval} function
*/
public static class EvalArgs {
/** evaluated code */
- private final Node code;
+ private final Expression code;
/** 'this' passed to evaluated code */
private final IdentNode evalThis;
@@ -76,7 +77,7 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
* @param location location for the eval call
* @param strictMode is this a call from a strict context?
*/
- public EvalArgs(final Node code, final IdentNode evalThis, final String location, final boolean strictMode) {
+ public EvalArgs(final Expression code, final IdentNode evalThis, final String location, final boolean strictMode) {
this.code = code;
this.evalThis = evalThis;
this.location = location;
@@ -87,11 +88,11 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
* Return the code that is to be eval:ed by this eval function
* @return code as an AST node
*/
- public Node getCode() {
+ public Expression getCode() {
return code;
}
- private EvalArgs setCode(final Node code) {
+ private EvalArgs setCode(final Expression code) {
if (this.code == code) {
return this;
}
@@ -143,18 +144,20 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
* @param function the function to call
* @param args args to the call
*/
- public CallNode(final int lineNumber, final long token, final int finish, final Node function, final List<Node> args) {
- super(lineNumber, token, finish);
-
- this.function = function;
- this.args = args;
- this.flags = 0;
- this.type = null;
- this.evalArgs = null;
+ public CallNode(final int lineNumber, final long token, final int finish, final Expression function, final List<Expression> args) {
+ super(token, finish);
+
+ this.function = function;
+ this.args = args;
+ this.flags = 0;
+ this.type = null;
+ this.evalArgs = null;
+ this.lineNumber = lineNumber;
}
- private CallNode(final CallNode callNode, final Node function, final List<Node> args, final int flags, final Type type, final EvalArgs evalArgs) {
+ private CallNode(final CallNode callNode, final Expression function, final List<Expression> args, final int flags, final Type type, final EvalArgs evalArgs) {
super(callNode);
+ this.lineNumber = callNode.lineNumber;
this.function = function;
this.args = args;
this.flags = flags;
@@ -162,6 +165,14 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
this.evalArgs = evalArgs;
}
+ /**
+ * Returns the line number.
+ * @return the line number.
+ */
+ public int getLineNumber() {
+ return lineNumber;
+ }
+
@Override
public Type getType() {
if (hasCallSiteType()) {
@@ -198,13 +209,13 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterCallNode(this)) {
final CallNode newCallNode = (CallNode)visitor.leaveCallNode(
- setFunction(function.accept(visitor)).
- setArgs(Node.accept(visitor, Node.class, args)).
+ setFunction((Expression)function.accept(visitor)).
+ setArgs(Node.accept(visitor, Expression.class, args)).
setFlags(flags).
setType(null, lc, type).
setEvalArgs(evalArgs == null ?
null :
- evalArgs.setCode(evalArgs.getCode().accept(visitor)).
+ evalArgs.setCode((Expression)evalArgs.getCode().accept(visitor)).
setThis((IdentNode)evalArgs.getThis().accept(visitor))));
// Theoretically, we'd need to instead pass lc to every setter and do a replacement on each. In practice,
// setType from TypeOverride can't accept a lc, and we don't necessarily want to go there now.
@@ -248,7 +259,7 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
* Get the arguments for the call
* @return a list of arguments
*/
- public List<Node> getArgs() {
+ public List<Expression> getArgs() {
return Collections.unmodifiableList(args);
}
@@ -256,7 +267,7 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
* Reset the arguments for the call
* @param args new arguments list
*/
- private CallNode setArgs(final List<Node> args) {
+ private CallNode setArgs(final List<Expression> args) {
if (this.args == args) {
return this;
}
@@ -297,7 +308,7 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
* Return the function expression that this call invokes
* @return the function
*/
- public Node getFunction() {
+ public Expression getFunction() {
return function;
}
@@ -306,7 +317,7 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
* @param function the function
* @return same node or new one on state change
*/
- public CallNode setFunction(final Node function) {
+ public CallNode setFunction(final Expression function) {
if (this.function == function) {
return this;
}
diff --git a/src/jdk/nashorn/internal/ir/CaseNode.java b/src/jdk/nashorn/internal/ir/CaseNode.java
index aae370f3..c809058a 100644
--- a/src/jdk/nashorn/internal/ir/CaseNode.java
+++ b/src/jdk/nashorn/internal/ir/CaseNode.java
@@ -36,7 +36,7 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@Immutable
public final class CaseNode extends Node {
/** Test expression. */
- private final Node test;
+ private final Expression test;
/** Statements. */
private final Block body;
@@ -52,7 +52,7 @@ public final class CaseNode extends Node {
* @param test case test node, can be any node in JavaScript
* @param body case body
*/
- public CaseNode(final long token, final int finish, final Node test, final Block body) {
+ public CaseNode(final long token, final int finish, final Expression test, final Block body) {
super(token, finish);
this.test = test;
@@ -60,7 +60,7 @@ public final class CaseNode extends Node {
this.entry = new Label("entry");
}
- CaseNode(final CaseNode caseNode, final Node test, final Block body) {
+ CaseNode(final CaseNode caseNode, final Expression test, final Block body) {
super(caseNode);
this.test = test;
@@ -80,7 +80,7 @@ public final class CaseNode extends Node {
@Override
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterCaseNode(this)) {
- final Node newTest = test == null ? null : test.accept(visitor);
+ final Expression newTest = test == null ? null : (Expression)test.accept(visitor);
final Block newBody = body == null ? null : (Block)body.accept(visitor);
return visitor.leaveCaseNode(setTest(newTest).setBody(newBody));
@@ -120,7 +120,7 @@ public final class CaseNode extends Node {
* Get the test expression for this case node
* @return the test
*/
- public Node getTest() {
+ public Expression getTest() {
return test;
}
@@ -129,7 +129,7 @@ public final class CaseNode extends Node {
* @param test new test expression
* @return new or same CaseNode
*/
- public CaseNode setTest(final Node test) {
+ public CaseNode setTest(final Expression test) {
if (this.test == test) {
return this;
}
diff --git a/src/jdk/nashorn/internal/ir/CatchNode.java b/src/jdk/nashorn/internal/ir/CatchNode.java
index f3818148..ba640a52 100644
--- a/src/jdk/nashorn/internal/ir/CatchNode.java
+++ b/src/jdk/nashorn/internal/ir/CatchNode.java
@@ -37,7 +37,7 @@ public final class CatchNode extends Statement {
private final IdentNode exception;
/** Exception condition. */
- private final Node exceptionCondition;
+ private final Expression exceptionCondition;
/** Catch body. */
private final Block body;
@@ -58,7 +58,7 @@ public final class CatchNode extends Statement {
* @param body catch body
* @param flags flags
*/
- public CatchNode(final int lineNumber, final long token, final int finish, final IdentNode exception, final Node exceptionCondition, final Block body, final int flags) {
+ public CatchNode(final int lineNumber, final long token, final int finish, final IdentNode exception, final Expression exceptionCondition, final Block body, final int flags) {
super(lineNumber, token, finish);
this.exception = exception;
this.exceptionCondition = exceptionCondition;
@@ -66,7 +66,7 @@ public final class CatchNode extends Statement {
this.flags = flags;
}
- private CatchNode(final CatchNode catchNode, final IdentNode exception, final Node exceptionCondition, final Block body, final int flags) {
+ private CatchNode(final CatchNode catchNode, final IdentNode exception, final Expression exceptionCondition, final Block body, final int flags) {
super(catchNode);
this.exception = exception;
this.exceptionCondition = exceptionCondition;
@@ -83,7 +83,7 @@ public final class CatchNode extends Statement {
if (visitor.enterCatchNode(this)) {
return visitor.leaveCatchNode(
setException((IdentNode)exception.accept(visitor)).
- setExceptionCondition(exceptionCondition == null ? null : exceptionCondition.accept(visitor)).
+ setExceptionCondition(exceptionCondition == null ? null : (Expression)exceptionCondition.accept(visitor)).
setBody((Block)body.accept(visitor)));
}
@@ -119,7 +119,7 @@ public final class CatchNode extends Statement {
* Get the exception condition for this catch block
* @return the exception condition
*/
- public Node getExceptionCondition() {
+ public Expression getExceptionCondition() {
return exceptionCondition;
}
@@ -128,7 +128,7 @@ public final class CatchNode extends Statement {
* @param exceptionCondition the new exception condition
* @return new or same CatchNode
*/
- public CatchNode setExceptionCondition(final Node exceptionCondition) {
+ public CatchNode setExceptionCondition(final Expression exceptionCondition) {
if (this.exceptionCondition == exceptionCondition) {
return this;
}
diff --git a/src/jdk/nashorn/internal/ir/Expression.java b/src/jdk/nashorn/internal/ir/Expression.java
new file mode 100644
index 00000000..9006fa8d
--- /dev/null
+++ b/src/jdk/nashorn/internal/ir/Expression.java
@@ -0,0 +1,99 @@
+/*
+ * 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.ir;
+
+import jdk.nashorn.internal.codegen.types.Type;
+
+/**
+ * Common superclass for all expression nodes. Expression nodes can have
+ * an associated symbol as well as a type.
+ *
+ */
+public abstract class Expression extends Node {
+ private Symbol symbol;
+
+ Expression(long token, int start, int finish) {
+ super(token, start, finish);
+ }
+
+ Expression(long token, int finish) {
+ super(token, finish);
+ }
+
+ Expression(Expression expr) {
+ super(expr);
+ this.symbol = expr.symbol;
+ }
+
+ /**
+ * Return the Symbol the compiler has assigned to this Node. The symbol
+ * is the place where it's expression value is stored after evaluation
+ *
+ * @return the symbol
+ */
+ public Symbol getSymbol() {
+ return symbol;
+ }
+
+ /**
+ * Assign a symbol to this node. See {@link Expression#getSymbol()} for explanation
+ * of what a symbol is
+ *
+ * @param lc lexical context
+ * @param symbol the symbol
+ * @return new node
+ */
+ public Expression setSymbol(final LexicalContext lc, final Symbol symbol) {
+ if (this.symbol == symbol) {
+ return this;
+ }
+ final Expression newExpr = (Expression)clone();
+ newExpr.symbol = symbol;
+ return newExpr;
+ }
+
+ /**
+ * Check if the expression has a type. The default behavior is to go into the symbol
+ * and check the symbol type, but there may be overrides, for example in
+ * getters that require a different type than the internal representation
+ *
+ * @return true if a type exists
+ */
+ public boolean hasType() {
+ return getSymbol() != null;
+ }
+
+ /**
+ * Returns the type of the expression. Typically this is the symbol type. No types
+ * are stored in the expression itself, unless it implements TypeOverride.
+ *
+ * @return the type of the node.
+ */
+ public Type getType() {
+ assert hasType() : this + " has no type";
+ return symbol.getSymbolType();
+ }
+}
diff --git a/src/jdk/nashorn/internal/ir/ExecuteNode.java b/src/jdk/nashorn/internal/ir/ExpressionStatement.java
index c696202b..8b118a2b 100644
--- a/src/jdk/nashorn/internal/ir/ExecuteNode.java
+++ b/src/jdk/nashorn/internal/ir/ExpressionStatement.java
@@ -34,9 +34,9 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
* statements being added to the IR
*/
@Immutable
-public final class ExecuteNode extends Statement {
+public final class ExpressionStatement extends Statement {
/** Expression to execute. */
- private final Node expression;
+ private final Expression expression;
/**
* Constructor
@@ -46,13 +46,13 @@ public final class ExecuteNode extends Statement {
* @param finish finish
* @param expression the expression to execute
*/
- public ExecuteNode(final int lineNumber, final long token, final int finish, final Node expression) {
+ public ExpressionStatement(final int lineNumber, final long token, final int finish, final Expression expression) {
super(lineNumber, token, finish);
this.expression = expression;
}
- private ExecuteNode(final ExecuteNode executeNode, final Node expression) {
- super(executeNode);
+ private ExpressionStatement(final ExpressionStatement expressionStatement, final Expression expression) {
+ super(expressionStatement);
this.expression = expression;
}
@@ -63,8 +63,8 @@ public final class ExecuteNode extends Statement {
@Override
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
- if (visitor.enterExecuteNode(this)) {
- return visitor.leaveExecuteNode(setExpression(expression.accept(visitor)));
+ if (visitor.enterExpressionStatement(this)) {
+ return visitor.leaveExpressionStatement(setExpression((Expression)expression.accept(visitor)));
}
return this;
@@ -79,7 +79,7 @@ public final class ExecuteNode extends Statement {
* Return the expression to be executed
* @return the expression
*/
- public Node getExpression() {
+ public Expression getExpression() {
return expression;
}
@@ -88,10 +88,10 @@ public final class ExecuteNode extends Statement {
* @param expression the expression
* @return new or same execute node
*/
- public ExecuteNode setExpression(final Node expression) {
+ public ExpressionStatement setExpression(final Expression expression) {
if (this.expression == expression) {
return this;
}
- return new ExecuteNode(this, expression);
+ return new ExpressionStatement(this, expression);
}
}
diff --git a/src/jdk/nashorn/internal/ir/ForNode.java b/src/jdk/nashorn/internal/ir/ForNode.java
index bad38c6a..8130e23b 100644
--- a/src/jdk/nashorn/internal/ir/ForNode.java
+++ b/src/jdk/nashorn/internal/ir/ForNode.java
@@ -34,10 +34,10 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@Immutable
public final class ForNode extends LoopNode {
/** Initialize expression. */
- private final Node init;
+ private final Expression init;
/** Test expression. */
- private final Node modify;
+ private final Expression modify;
/** Iterator symbol. */
private Symbol iterator;
@@ -65,14 +65,14 @@ public final class ForNode extends LoopNode {
* @param modify modify
* @param flags flags
*/
- public ForNode(final int lineNumber, final long token, final int finish, final Node init, final Node test, final Block body, final Node modify, final int flags) {
+ public ForNode(final int lineNumber, final long token, final int finish, final Expression init, final Expression test, final Block body, final Expression modify, final int flags) {
super(lineNumber, token, finish, test, body, false);
this.init = init;
this.modify = modify;
this.flags = flags;
}
- private ForNode(final ForNode forNode, final Node init, final Node test, final Block body, final Node modify, final int flags, final boolean controlFlowEscapes) {
+ private ForNode(final ForNode forNode, final Expression init, final Expression test, final Block body, final Expression modify, final int flags, final boolean controlFlowEscapes) {
super(forNode, test, body, controlFlowEscapes);
this.init = init;
this.modify = modify;
@@ -86,12 +86,12 @@ public final class ForNode extends LoopNode {
}
@Override
- protected Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
+ public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterForNode(this)) {
return visitor.leaveForNode(
- setInit(lc, init == null ? null : init.accept(visitor)).
- setTest(lc, test == null ? null : test.accept(visitor)).
- setModify(lc, modify == null ? null : modify.accept(visitor)).
+ setInit(lc, init == null ? null : (Expression)init.accept(visitor)).
+ setTest(lc, test == null ? null : (Expression)test.accept(visitor)).
+ setModify(lc, modify == null ? null : (Expression)modify.accept(visitor)).
setBody(lc, (Block)body.accept(visitor)));
}
@@ -140,7 +140,7 @@ public final class ForNode extends LoopNode {
* Get the initialization expression for this for loop
* @return the initialization expression
*/
- public Node getInit() {
+ public Expression getInit() {
return init;
}
@@ -150,7 +150,7 @@ public final class ForNode extends LoopNode {
* @param init new initialization expression
* @return new for node if changed or existing if not
*/
- public ForNode setInit(final LexicalContext lc, final Node init) {
+ public ForNode setInit(final LexicalContext lc, final Expression init) {
if (this.init == init) {
return this;
}
@@ -212,7 +212,7 @@ public final class ForNode extends LoopNode {
* Get the modification expression for this ForNode
* @return the modification expression
*/
- public Node getModify() {
+ public Expression getModify() {
return modify;
}
@@ -222,7 +222,7 @@ public final class ForNode extends LoopNode {
* @param modify new modification expression
* @return new for node if changed or existing if not
*/
- public ForNode setModify(final LexicalContext lc, final Node modify) {
+ public ForNode setModify(final LexicalContext lc, final Expression modify) {
if (this.modify == modify) {
return this;
}
@@ -230,12 +230,12 @@ public final class ForNode extends LoopNode {
}
@Override
- public Node getTest() {
+ public Expression getTest() {
return test;
}
@Override
- public ForNode setTest(final LexicalContext lc, final Node test) {
+ public ForNode setTest(final LexicalContext lc, final Expression test) {
if (this.test == test) {
return this;
}
diff --git a/src/jdk/nashorn/internal/ir/FunctionNode.java b/src/jdk/nashorn/internal/ir/FunctionNode.java
index 3640db30..311a7f91 100644
--- a/src/jdk/nashorn/internal/ir/FunctionNode.java
+++ b/src/jdk/nashorn/internal/ir/FunctionNode.java
@@ -47,7 +47,7 @@ import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
* IR representation for function (or script.)
*/
@Immutable
-public final class FunctionNode extends LexicalContextNode implements Flags<FunctionNode> {
+public final class FunctionNode extends LexicalContextExpression implements Flags<FunctionNode> {
/** Type used for all FunctionNodes */
public static final Type FUNCTION_TYPE = Type.typeFor(ScriptFunction.class);
@@ -131,9 +131,15 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
@Ignore
private final Compiler.Hints hints;
+ /** Properties of this object assigned in this function */
+ @Ignore
+ private HashSet<String> thisProperties;
+
/** Function flags. */
private final int flags;
+ private final int lineNumber;
+
/** Is anonymous function flag. */
public static final int IS_ANONYMOUS = 1 << 0;
@@ -156,6 +162,10 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
/** Does a nested function contain eval? If it does, then all variables in this function might be get/set by it. */
public static final int HAS_NESTED_EVAL = 1 << 6;
+ /** Does this function have any blocks that create a scope? This is used to determine if the function needs to
+ * have a local variable slot for the scope symbol. */
+ public static final int HAS_SCOPE_BLOCK = 1 << 7;
+
/**
* Flag this function as one that defines the identifier "arguments" as a function parameter or nested function
* name. This precludes it from needing to have an Arguments object defined as "arguments" local variable. Note that
@@ -226,9 +236,10 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
final List<IdentNode> parameters,
final FunctionNode.Kind kind,
final int flags) {
- super(lineNumber, token, finish);
+ super(token, finish);
this.source = source;
+ this.lineNumber = lineNumber;
this.ident = ident;
this.name = name;
this.kind = kind;
@@ -258,7 +269,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
final FunctionNode snapshot,
final Compiler.Hints hints) {
super(functionNode);
-
+ this.lineNumber = functionNode.lineNumber;
this.flags = flags;
this.name = name;
this.returnType = returnType;
@@ -277,6 +288,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
this.declaredSymbols = functionNode.declaredSymbols;
this.kind = functionNode.kind;
this.firstToken = functionNode.firstToken;
+ this.thisProperties = functionNode.thisProperties;
}
@Override
@@ -296,6 +308,14 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
}
/**
+ * Returns the line number.
+ * @return the line number.
+ */
+ public int getLineNumber() {
+ return lineNumber;
+ }
+
+ /**
* Get the version of this function node's code as it looked upon construction
* i.e typically parsed and nothing else
* @return initial version of function node
@@ -572,7 +592,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
if(this.body == body) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
+ return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags | (body.needsScope() ? FunctionNode.HAS_SCOPE_BLOCK : 0), name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
}
/**
@@ -614,6 +634,33 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
}
/**
+ * Register a property assigned to the this object in this function.
+ * @param key the property name
+ */
+ public void addThisProperty(final String key) {
+ if (thisProperties == null) {
+ thisProperties = new HashSet<>();
+ }
+ thisProperties.add(key);
+ }
+
+ /**
+ * Get the number of properties assigned to the this object in this function.
+ * @return number of properties
+ */
+ public int countThisProperties() {
+ return thisProperties == null ? 0 : thisProperties.size();
+ }
+
+ /**
+ * Returns true if any of the blocks in this function create their own scope.
+ * @return true if any of the blocks in this function create their own scope.
+ */
+ public boolean hasScopeBlock() {
+ return getFlag(HAS_SCOPE_BLOCK);
+ }
+
+ /**
* Return the kind of this function
* @see FunctionNode.Kind
* @return the kind
diff --git a/src/jdk/nashorn/internal/ir/IdentNode.java b/src/jdk/nashorn/internal/ir/IdentNode.java
index de197c3c..14d1304d 100644
--- a/src/jdk/nashorn/internal/ir/IdentNode.java
+++ b/src/jdk/nashorn/internal/ir/IdentNode.java
@@ -29,6 +29,7 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.__DIR__;
import static jdk.nashorn.internal.codegen.CompilerConstants.__FILE__;
import static jdk.nashorn.internal.codegen.CompilerConstants.__LINE__;
import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS;
+
import jdk.nashorn.internal.codegen.ObjectClassGenerator;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
@@ -38,7 +39,7 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
* IR representation for an identifier.
*/
@Immutable
-public final class IdentNode extends Node implements PropertyKey, TypeOverride<IdentNode>, FunctionCall {
+public final class IdentNode extends Expression implements PropertyKey, TypeOverride<IdentNode>, FunctionCall {
private static final int PROPERTY_NAME = 1 << 0;
private static final int INITIALIZED_HERE = 1 << 1;
private static final int FUNCTION = 1 << 2;
diff --git a/src/jdk/nashorn/internal/ir/IfNode.java b/src/jdk/nashorn/internal/ir/IfNode.java
index 1b606cb0..64e70d87 100644
--- a/src/jdk/nashorn/internal/ir/IfNode.java
+++ b/src/jdk/nashorn/internal/ir/IfNode.java
@@ -34,7 +34,7 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@Immutable
public final class IfNode extends Statement {
/** Test expression. */
- private final Node test;
+ private final Expression test;
/** Pass statements. */
private final Block pass;
@@ -52,14 +52,14 @@ public final class IfNode extends Statement {
* @param pass block to execute when test passes
* @param fail block to execute when test fails or null
*/
- public IfNode(final int lineNumber, final long token, final int finish, final Node test, final Block pass, final Block fail) {
+ public IfNode(final int lineNumber, final long token, final int finish, final Expression test, final Block pass, final Block fail) {
super(lineNumber, token, finish);
this.test = test;
this.pass = pass;
this.fail = fail;
}
- private IfNode(final IfNode ifNode, final Node test, final Block pass, final Block fail) {
+ private IfNode(final IfNode ifNode, final Expression test, final Block pass, final Block fail) {
super(ifNode);
this.test = test;
this.pass = pass;
@@ -75,7 +75,7 @@ public final class IfNode extends Statement {
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterIfNode(this)) {
return visitor.leaveIfNode(
- setTest(test.accept(visitor)).
+ setTest((Expression)test.accept(visitor)).
setPass((Block)pass.accept(visitor)).
setFail(fail == null ? null : (Block)fail.accept(visitor)));
}
@@ -124,7 +124,7 @@ public final class IfNode extends Statement {
* Get the test expression for this IfNode
* @return the test expression
*/
- public Node getTest() {
+ public Expression getTest() {
return test;
}
@@ -133,7 +133,7 @@ public final class IfNode extends Statement {
* @param test a new test expression
* @return new or same IfNode
*/
- public IfNode setTest(final Node test) {
+ public IfNode setTest(final Expression test) {
if (this.test == test) {
return this;
}
diff --git a/src/jdk/nashorn/internal/ir/IndexNode.java b/src/jdk/nashorn/internal/ir/IndexNode.java
index 0a9b7db2..2799e9be 100644
--- a/src/jdk/nashorn/internal/ir/IndexNode.java
+++ b/src/jdk/nashorn/internal/ir/IndexNode.java
@@ -35,7 +35,7 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@Immutable
public final class IndexNode extends BaseNode {
/** Property index. */
- private final Node index;
+ private final Expression index;
/**
* Constructors
@@ -45,12 +45,12 @@ public final class IndexNode extends BaseNode {
* @param base base node for access
* @param index index for access
*/
- public IndexNode(final long token, final int finish, final Node base, final Node index) {
+ public IndexNode(final long token, final int finish, final Expression base, final Expression index) {
super(token, finish, base, false, false);
this.index = index;
}
- private IndexNode(final IndexNode indexNode, final Node base, final Node index, final boolean isFunction, final boolean hasCallSiteType) {
+ private IndexNode(final IndexNode indexNode, final Expression base, final Expression index, final boolean isFunction, final boolean hasCallSiteType) {
super(indexNode, base, isFunction, hasCallSiteType);
this.index = index;
}
@@ -59,8 +59,8 @@ public final class IndexNode extends BaseNode {
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterIndexNode(this)) {
return visitor.leaveIndexNode(
- setBase(base.accept(visitor)).
- setIndex(index.accept(visitor)));
+ setBase((Expression)base.accept(visitor)).
+ setIndex((Expression)index.accept(visitor)));
}
return this;
}
@@ -95,11 +95,11 @@ public final class IndexNode extends BaseNode {
* Get the index expression for this IndexNode
* @return the index
*/
- public Node getIndex() {
+ public Expression getIndex() {
return index;
}
- private IndexNode setBase(final Node base) {
+ private IndexNode setBase(final Expression base) {
if (this.base == base) {
return this;
}
@@ -111,7 +111,7 @@ public final class IndexNode extends BaseNode {
* @param index new index expression
* @return a node equivalent to this one except for the requested change.
*/
- public IndexNode setIndex(Node index) {
+ public IndexNode setIndex(Expression index) {
if(this.index == index) {
return this;
}
diff --git a/src/jdk/nashorn/internal/ir/LabelNode.java b/src/jdk/nashorn/internal/ir/LabelNode.java
index ad9979ef..9903c2b0 100644
--- a/src/jdk/nashorn/internal/ir/LabelNode.java
+++ b/src/jdk/nashorn/internal/ir/LabelNode.java
@@ -32,7 +32,7 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
* IR representation for a labeled statement.
*/
@Immutable
-public final class LabelNode extends LexicalContextNode {
+public final class LabelNode extends LexicalContextStatement {
/** Label ident. */
private final IdentNode label;
diff --git a/src/jdk/nashorn/internal/ir/LexicalContext.java b/src/jdk/nashorn/internal/ir/LexicalContext.java
index 2ca5ec39..ed0ca62f 100644
--- a/src/jdk/nashorn/internal/ir/LexicalContext.java
+++ b/src/jdk/nashorn/internal/ir/LexicalContext.java
@@ -54,13 +54,16 @@ public class LexicalContext {
/**
* Set the flags for a lexical context node on the stack. Does not
- * replace the flags, but rather adds to them
+ * replace the flags, but rather adds to them.
*
* @param node node
* @param flag new flag to set
*/
public void setFlag(final LexicalContextNode node, final int flag) {
if (flag != 0) {
+ // Use setBlockNeedsScope() instead
+ assert !(flag == Block.NEEDS_SCOPE && node instanceof Block);
+
for (int i = sp - 1; i >= 0; i--) {
if (stack[i] == node) {
flags[i] |= flag;
@@ -72,6 +75,29 @@ public class LexicalContext {
}
/**
+ * Marks the block as one that creates a scope. Note that this method must
+ * be used instead of {@link #setFlag(LexicalContextNode, int)} with
+ * {@link Block#NEEDS_SCOPE} because it atomically also sets the
+ * {@link FunctionNode#HAS_SCOPE_BLOCK} flag on the block's containing
+ * function.
+ * @param block the block that needs to be marked as creating a scope.
+ */
+ public void setBlockNeedsScope(final Block block) {
+ for (int i = sp - 1; i >= 0; i--) {
+ if (stack[i] == block) {
+ flags[i] |= Block.NEEDS_SCOPE;
+ for(int j = i - 1; j >=0; j --) {
+ if(stack[j] instanceof FunctionNode) {
+ flags[j] |= FunctionNode.HAS_SCOPE_BLOCK;
+ return;
+ }
+ }
+ }
+ }
+ assert false;
+ }
+
+ /**
* Get the flags for a lexical context node on the stack
* @param node node
* @return the flags for the node
@@ -550,19 +576,20 @@ public class LexicalContext {
final StringBuffer sb = new StringBuffer();
sb.append("[ ");
for (int i = 0; i < sp; i++) {
- final Node node = stack[i];
+ final Object node = stack[i];
sb.append(node.getClass().getSimpleName());
sb.append('@');
sb.append(Debug.id(node));
sb.append(':');
if (node instanceof FunctionNode) {
- final Source source = ((FunctionNode)node).getSource();
+ final FunctionNode fn = (FunctionNode)node;
+ final Source source = fn.getSource();
String src = source.toString();
if (src.indexOf(File.pathSeparator) != -1) {
src = src.substring(src.lastIndexOf(File.pathSeparator));
}
src += ' ';
- src += source.getLine(node.getStart());
+ src += source.getLine(fn.getStart());
sb.append(src);
}
sb.append(' ');
@@ -605,7 +632,7 @@ public class LexicalContext {
private T findNext() {
for (int i = index; i >= 0; i--) {
- final Node node = stack[i];
+ final Object node = stack[i];
if (node == until) {
return null;
}
diff --git a/src/jdk/nashorn/internal/ir/LexicalContextExpression.java b/src/jdk/nashorn/internal/ir/LexicalContextExpression.java
new file mode 100644
index 00000000..d3c77777
--- /dev/null
+++ b/src/jdk/nashorn/internal/ir/LexicalContextExpression.java
@@ -0,0 +1,59 @@
+/*
+ * 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.ir;
+
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+
+abstract class LexicalContextExpression extends Expression implements LexicalContextNode {
+
+ LexicalContextExpression(LexicalContextExpression expr) {
+ super(expr);
+ }
+
+ LexicalContextExpression(long token, int start, int finish) {
+ super(token, start, finish);
+ }
+
+ LexicalContextExpression(long token, int finish) {
+ super(token, finish);
+ }
+
+ @Override
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
+ return Acceptor.accept(this, visitor);
+ }
+
+ /**
+ * Set the symbol and replace in lexical context if applicable
+ * @param lc lexical context
+ * @param symbol symbol
+ * @return new node if symbol changed
+ */
+ @Override
+ public Expression setSymbol(final LexicalContext lc, final Symbol symbol) {
+ return Node.replaceInLexicalContext(lc, this, (LexicalContextExpression)super.setSymbol(null, symbol));
+ }
+}
diff --git a/src/jdk/nashorn/internal/ir/LexicalContextNode.java b/src/jdk/nashorn/internal/ir/LexicalContextNode.java
index 020faf8e..bb6a681d 100644
--- a/src/jdk/nashorn/internal/ir/LexicalContextNode.java
+++ b/src/jdk/nashorn/internal/ir/LexicalContextNode.java
@@ -26,31 +26,12 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+
/**
- * Superclass for nodes that can be part of the lexical context
+ * Interface for nodes that can be part of the lexical context.
* @see LexicalContext
*/
-public abstract class LexicalContextNode extends Statement {
- /**
- * Constructor
- *
- * @param lineNumber line number
- * @param token token
- * @param finish finish
- */
- protected LexicalContextNode(final int lineNumber, final long token, final int finish) {
- super(lineNumber, token, finish);
- }
-
- /**
- * Copy constructor
- *
- * @param node source node
- */
- protected LexicalContextNode(final LexicalContextNode node) {
- super(node);
- }
-
+public interface LexicalContextNode {
/**
* Accept function for the node given a lexical context. It must be prepared
* to replace itself if present in the lexical context
@@ -60,25 +41,15 @@ public abstract class LexicalContextNode extends Statement {
*
* @return new node or same node depending on state change
*/
- protected abstract Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor);
-
- @Override
- public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
- final LexicalContext lc = visitor.getLexicalContext();
- lc.push(this);
- final LexicalContextNode newNode = (LexicalContextNode)accept(lc, visitor);
- return lc.pop(newNode);
- }
+ Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor);
- /**
- * Set the symbol and replace in lexical context if applicable
- * @param lc lexical context
- * @param symbol symbol
- * @return new node if symbol changed
- */
- @Override
- public Node setSymbol(final LexicalContext lc, final Symbol symbol) {
- return Node.replaceInLexicalContext(lc, this, (LexicalContextNode)super.setSymbol(null, symbol));
+ // Would be a default method on Java 8
+ static class Acceptor {
+ static Node accept(LexicalContextNode node, final NodeVisitor<? extends LexicalContext> visitor) {
+ final LexicalContext lc = visitor.getLexicalContext();
+ lc.push(node);
+ final LexicalContextNode newNode = (LexicalContextNode)node.accept(lc, visitor);
+ return (Node)lc.pop(newNode);
+ }
}
-
}
diff --git a/src/jdk/nashorn/internal/ir/LexicalContextStatement.java b/src/jdk/nashorn/internal/ir/LexicalContextStatement.java
new file mode 100644
index 00000000..c7bbfb2f
--- /dev/null
+++ b/src/jdk/nashorn/internal/ir/LexicalContextStatement.java
@@ -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. 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.ir;
+
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+
+abstract class LexicalContextStatement extends Statement implements LexicalContextNode {
+ /**
+ * Constructor
+ *
+ * @param lineNumber line number
+ * @param token token
+ * @param finish finish
+ */
+ protected LexicalContextStatement(final int lineNumber, final long token, final int finish) {
+ super(lineNumber, token, finish);
+ }
+
+ /**
+ * Copy constructor
+ *
+ * @param node source node
+ */
+ protected LexicalContextStatement(final LexicalContextStatement node) {
+ super(node);
+ }
+
+ @Override
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
+ return Acceptor.accept(this, visitor);
+ }
+}
diff --git a/src/jdk/nashorn/internal/ir/LiteralNode.java b/src/jdk/nashorn/internal/ir/LiteralNode.java
index a7cea66a..b2d9e9fa 100644
--- a/src/jdk/nashorn/internal/ir/LiteralNode.java
+++ b/src/jdk/nashorn/internal/ir/LiteralNode.java
@@ -45,10 +45,13 @@ import jdk.nashorn.internal.runtime.Undefined;
* @param <T> the literal type
*/
@Immutable
-public abstract class LiteralNode<T> extends Node implements PropertyKey {
+public abstract class LiteralNode<T> extends Expression implements PropertyKey {
/** Literal value */
protected final T value;
+ /** Marker for values that must be computed at runtime */
+ public static final Object POSTSET_MARKER = new Object();
+
/**
* Constructor
*
@@ -495,6 +498,30 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
return new LexerTokenLiteralNode(parent.getToken(), parent.getFinish(), value);
}
+ /**
+ * Get the constant value for an object, or {@link #POSTSET_MARKER} if the value can't be statically computed.
+ *
+ * @param object a node or value object
+ * @return the constant value or {@code POSTSET_MARKER}
+ */
+ public static Object objectAsConstant(final Object object) {
+ if (object == null) {
+ return null;
+ } else if (object instanceof Number || object instanceof String || object instanceof Boolean) {
+ return object;
+ } else if (object instanceof LiteralNode) {
+ return objectAsConstant(((LiteralNode<?>)object).getValue());
+ } else if (object instanceof UnaryNode) {
+ final UnaryNode unaryNode = (UnaryNode)object;
+
+ if (unaryNode.isTokenType(TokenType.CONVERT) && unaryNode.getType().isObject()) {
+ return objectAsConstant(unaryNode.rhs());
+ }
+ }
+
+ return POSTSET_MARKER;
+ }
+
private static final class NullLiteralNode extends LiteralNode<Object> {
private NullLiteralNode(final long token, final int finish) {
@@ -524,12 +551,7 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
/**
* Array literal node class.
*/
- public static final class ArrayLiteralNode extends LiteralNode<Node[]> {
- private static class PostsetMarker {
- //empty
- }
-
- private static PostsetMarker POSTSET_MARKER = new PostsetMarker();
+ public static final class ArrayLiteralNode extends LiteralNode<Expression[]> {
/** Array element type. */
private Type elementType;
@@ -597,7 +619,7 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
* @param finish finish
* @param value array literal value, a Node array
*/
- protected ArrayLiteralNode(final long token, final int finish, final Node[] value) {
+ protected ArrayLiteralNode(final long token, final int finish, final Expression[] value) {
super(Token.recast(token, TokenType.ARRAY), finish, value);
this.elementType = Type.UNKNOWN;
}
@@ -606,7 +628,7 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
* Copy constructor
* @param node source array literal node
*/
- private ArrayLiteralNode(final ArrayLiteralNode node, final Node[] value) {
+ private ArrayLiteralNode(final ArrayLiteralNode node, final Expression[] value) {
super(node, value);
this.elementType = node.elementType;
this.presets = node.presets;
@@ -715,7 +737,7 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
}
private void analyzeElements() {
- for (final Node node : value) {
+ for (final Expression node : value) {
if (node == null) {
elementType = elementType.widest(Type.OBJECT); //no way to represent undefined as number
break;
@@ -740,24 +762,6 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
}
}
- private Object objectAsConstant(final Object object) {
- if (object == null) {
- return null;
- } else if (object instanceof Number || object instanceof String || object instanceof Boolean) {
- return object;
- } else if (object instanceof LiteralNode) {
- return objectAsConstant(((LiteralNode<?>)object).getValue());
- } else if (object instanceof UnaryNode) {
- final UnaryNode unaryNode = (UnaryNode)object;
-
- if (unaryNode.isTokenType(TokenType.CONVERT) && unaryNode.getType().isObject()) {
- return objectAsConstant(unaryNode.rhs());
- }
- }
-
- return POSTSET_MARKER;
- }
-
@Override
public Node[] getArray() {
return value;
@@ -822,15 +826,15 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
@Override
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterLiteralNode(this)) {
- final List<Node> oldValue = Arrays.asList(value);
- final List<Node> newValue = Node.accept(visitor, Node.class, oldValue);
+ final List<Expression> oldValue = Arrays.asList(value);
+ final List<Expression> newValue = Node.accept(visitor, Expression.class, oldValue);
return visitor.leaveLiteralNode(oldValue != newValue ? setValue(newValue) : this);
}
return this;
}
- private ArrayLiteralNode setValue(final List<Node> value) {
- return new ArrayLiteralNode(this, value.toArray(new Node[value.size()]));
+ private ArrayLiteralNode setValue(final List<Expression> value) {
+ return new ArrayLiteralNode(this, value.toArray(new Expression[value.size()]));
}
@Override
@@ -862,8 +866,8 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
*
* @return the new literal node
*/
- public static LiteralNode<Node[]> newInstance(final long token, final int finish, final List<Node> value) {
- return new ArrayLiteralNode(token, finish, value.toArray(new Node[value.size()]));
+ public static LiteralNode<Expression[]> newInstance(final long token, final int finish, final List<Expression> value) {
+ return new ArrayLiteralNode(token, finish, value.toArray(new Expression[value.size()]));
}
@@ -875,8 +879,8 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
*
* @return the new literal node
*/
- public static LiteralNode<?> newInstance(final Node parent, final List<Node> value) {
- return new ArrayLiteralNode(parent.getToken(), parent.getFinish(), value.toArray(new Node[value.size()]));
+ public static LiteralNode<?> newInstance(final Node parent, final List<Expression> value) {
+ return new ArrayLiteralNode(parent.getToken(), parent.getFinish(), value.toArray(new Expression[value.size()]));
}
/**
@@ -888,7 +892,7 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
*
* @return the new literal node
*/
- public static LiteralNode<Node[]> newInstance(final long token, final int finish, final Node[] value) {
+ public static LiteralNode<Expression[]> newInstance(final long token, final int finish, final Expression[] value) {
return new ArrayLiteralNode(token, finish, value);
}
}
diff --git a/src/jdk/nashorn/internal/ir/LoopNode.java b/src/jdk/nashorn/internal/ir/LoopNode.java
index 4a4fd3be..107030a2 100644
--- a/src/jdk/nashorn/internal/ir/LoopNode.java
+++ b/src/jdk/nashorn/internal/ir/LoopNode.java
@@ -27,18 +27,17 @@ package jdk.nashorn.internal.ir;
import java.util.Arrays;
import java.util.List;
-
import jdk.nashorn.internal.codegen.Label;
/**
* A loop node, for example a while node, do while node or for node
*/
-public abstract class LoopNode extends BreakableNode {
+public abstract class LoopNode extends BreakableStatement {
/** loop continue label. */
protected final Label continueLabel;
/** Loop test node, null if infinite */
- protected final Node test;
+ protected final Expression test;
/** Loop body */
protected final Block body;
@@ -56,7 +55,7 @@ public abstract class LoopNode extends BreakableNode {
* @param body loop body
* @param controlFlowEscapes controlFlowEscapes
*/
- protected LoopNode(final int lineNumber, final long token, final int finish, final Node test, final Block body, final boolean controlFlowEscapes) {
+ protected LoopNode(final int lineNumber, final long token, final int finish, final Expression test, final Block body, final boolean controlFlowEscapes) {
super(lineNumber, token, finish, new Label("while_break"));
this.continueLabel = new Label("while_continue");
this.test = test;
@@ -72,7 +71,7 @@ public abstract class LoopNode extends BreakableNode {
* @param body new body
* @param controlFlowEscapes controlFlowEscapes
*/
- protected LoopNode(final LoopNode loopNode, final Node test, final Block body, final boolean controlFlowEscapes) {
+ protected LoopNode(final LoopNode loopNode, final Expression test, final Block body, final boolean controlFlowEscapes) {
super(loopNode);
this.continueLabel = new Label(loopNode.continueLabel);
this.test = test;
@@ -151,7 +150,7 @@ public abstract class LoopNode extends BreakableNode {
* Get the test for this for node
* @return the test
*/
- public abstract Node getTest();
+ public abstract Expression getTest();
/**
* Set the test for this for node
@@ -160,7 +159,7 @@ public abstract class LoopNode extends BreakableNode {
* @param test new test
* @return same or new node depending on if test was changed
*/
- public abstract LoopNode setTest(final LexicalContext lc, final Node test);
+ public abstract LoopNode setTest(final LexicalContext lc, final Expression test);
/**
* Set the control flow escapes flag for this node.
diff --git a/src/jdk/nashorn/internal/ir/Node.java b/src/jdk/nashorn/internal/ir/Node.java
index 4342c2be..c59c235b 100644
--- a/src/jdk/nashorn/internal/ir/Node.java
+++ b/src/jdk/nashorn/internal/ir/Node.java
@@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir;
import java.util.ArrayList;
import java.util.List;
-
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.parser.Token;
@@ -37,9 +36,6 @@ import jdk.nashorn.internal.parser.TokenType;
* Nodes are used to compose Abstract Syntax Trees.
*/
public abstract class Node implements Cloneable {
- /** Node symbol. */
- private Symbol symbol;
-
/** Start of source range. */
protected final int start;
@@ -81,34 +77,11 @@ public abstract class Node implements Cloneable {
*/
protected Node(final Node node) {
this.token = node.token;
- this.symbol = node.symbol;
this.start = node.start;
this.finish = node.finish;
}
/**
- * Check if the node has a type. The default behavior is to go into the symbol
- * and check the symbol type, but there may be overrides, for example in
- * getters that require a different type than the internal representation
- *
- * @return true if a type exists
- */
- public boolean hasType() {
- return getSymbol() != null;
- }
-
- /**
- * Returns the type of the node. Typically this is the symbol type. No types
- * are stored in the node itself, unless it implements TypeOverride
- *
- * @return the type of the node.
- */
- public Type getType() {
- assert hasType() : this + " has no type";
- return symbol.getSymbolType();
- }
-
- /**
* Is this an atom node - for example a literal or an identity
*
* @return true if atom
@@ -235,16 +208,6 @@ public abstract class Node implements Cloneable {
return start;
}
- /**
- * Return the Symbol the compiler has assigned to this Node. The symbol
- * is the place where it's expression value is stored after evaluation
- *
- * @return the symbol
- */
- public Symbol getSymbol() {
- return symbol;
- }
-
@Override
protected Object clone() {
try {
@@ -254,24 +217,6 @@ public abstract class Node implements Cloneable {
}
}
- /**
- * Assign a symbol to this node. See {@link Node#getSymbol()} for explanation
- * of what a symbol is
- *
- * @param lc lexical context
- * @param symbol the symbol
- * @return new node
- */
- public Node setSymbol(final LexicalContext lc, final Symbol symbol) {
- if (this.symbol == symbol) {
- return this;
- }
- final Node newNode = (Node)clone();
- newNode.symbol = symbol;
- return newNode;
- }
-
-
@Override
public final boolean equals(final Object other) {
return super.equals(other);
diff --git a/src/jdk/nashorn/internal/ir/ObjectNode.java b/src/jdk/nashorn/internal/ir/ObjectNode.java
index 31c07812..b46e9b31 100644
--- a/src/jdk/nashorn/internal/ir/ObjectNode.java
+++ b/src/jdk/nashorn/internal/ir/ObjectNode.java
@@ -34,7 +34,7 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
* IR representation of an object literal.
*/
@Immutable
-public final class ObjectNode extends Node {
+public final class ObjectNode extends Expression {
/** Literal elements. */
private final List<PropertyNode> elements;
diff --git a/src/jdk/nashorn/internal/ir/PropertyNode.java b/src/jdk/nashorn/internal/ir/PropertyNode.java
index 8bf6b80f..9cb82091 100644
--- a/src/jdk/nashorn/internal/ir/PropertyNode.java
+++ b/src/jdk/nashorn/internal/ir/PropertyNode.java
@@ -38,7 +38,7 @@ public final class PropertyNode extends Node {
private final PropertyKey key;
/** Property value. */
- private final Node value;
+ private final Expression value;
/** Property getter. */
private final FunctionNode getter;
@@ -56,7 +56,7 @@ public final class PropertyNode extends Node {
* @param getter getter function body
* @param setter setter function body
*/
- public PropertyNode(final long token, final int finish, final PropertyKey key, final Node value, final FunctionNode getter, final FunctionNode setter) {
+ public PropertyNode(final long token, final int finish, final PropertyKey key, final Expression value, final FunctionNode getter, final FunctionNode setter) {
super(token, finish);
this.key = key;
this.value = value;
@@ -64,7 +64,7 @@ public final class PropertyNode extends Node {
this.setter = setter;
}
- private PropertyNode(final PropertyNode propertyNode, final PropertyKey key, final Node value, final FunctionNode getter, final FunctionNode setter) {
+ private PropertyNode(final PropertyNode propertyNode, final PropertyKey key, final Expression value, final FunctionNode getter, final FunctionNode setter) {
super(propertyNode);
this.key = key;
this.value = value;
@@ -85,7 +85,7 @@ public final class PropertyNode extends Node {
if (visitor.enterPropertyNode(this)) {
return visitor.leavePropertyNode(
setKey((PropertyKey)((Node)key).accept(visitor)).
- setValue(value == null ? null : value.accept(visitor)).
+ setValue(value == null ? null : (Expression)value.accept(visitor)).
setGetter(getter == null ? null : (FunctionNode)getter.accept(visitor)).
setSetter(setter == null ? null : (FunctionNode)setter.accept(visitor)));
}
@@ -140,8 +140,8 @@ public final class PropertyNode extends Node {
* Return the key for this property node
* @return the key
*/
- public Node getKey() {
- return (Node)key;
+ public Expression getKey() {
+ return (Expression)key;
}
private PropertyNode setKey(final PropertyKey key) {
@@ -175,7 +175,7 @@ public final class PropertyNode extends Node {
* Get the value of this property
* @return property value
*/
- public Node getValue() {
+ public Expression getValue() {
return value;
}
@@ -184,7 +184,7 @@ public final class PropertyNode extends Node {
* @param value new value
* @return same node or new node if state changed
*/
- public PropertyNode setValue(final Node value) {
+ public PropertyNode setValue(final Expression value) {
if (this.value == value) {
return this;
}
diff --git a/src/jdk/nashorn/internal/ir/ReturnNode.java b/src/jdk/nashorn/internal/ir/ReturnNode.java
index 563d0519..209e47b1 100644
--- a/src/jdk/nashorn/internal/ir/ReturnNode.java
+++ b/src/jdk/nashorn/internal/ir/ReturnNode.java
@@ -27,6 +27,7 @@ package jdk.nashorn.internal.ir;
import static jdk.nashorn.internal.parser.TokenType.RETURN;
import static jdk.nashorn.internal.parser.TokenType.YIELD;
+
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -36,7 +37,7 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@Immutable
public class ReturnNode extends Statement {
/** Optional expression. */
- private final Node expression;
+ private final Expression expression;
/**
* Constructor
@@ -46,12 +47,12 @@ public class ReturnNode extends Statement {
* @param finish finish
* @param expression expression to return
*/
- public ReturnNode(final int lineNumber, final long token, final int finish, final Node expression) {
+ public ReturnNode(final int lineNumber, final long token, final int finish, final Expression expression) {
super(lineNumber, token, finish);
this.expression = expression;
}
- private ReturnNode(final ReturnNode returnNode, final Node expression) {
+ private ReturnNode(final ReturnNode returnNode, final Expression expression) {
super(returnNode);
this.expression = expression;
}
@@ -89,7 +90,7 @@ public class ReturnNode extends Statement {
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterReturnNode(this)) {
if (expression != null) {
- return visitor.leaveReturnNode(setExpression(expression.accept(visitor)));
+ return visitor.leaveReturnNode(setExpression((Expression)expression.accept(visitor)));
}
return visitor.leaveReturnNode(this);
}
@@ -111,7 +112,7 @@ public class ReturnNode extends Statement {
* Get the expression this node returns
* @return return expression, or null if void return
*/
- public Node getExpression() {
+ public Expression getExpression() {
return expression;
}
@@ -120,7 +121,7 @@ public class ReturnNode extends Statement {
* @param expression new expression, or null if void return
* @return new or same return node
*/
- public ReturnNode setExpression(final Node expression) {
+ public ReturnNode setExpression(final Expression expression) {
if (this.expression == expression) {
return this;
}
diff --git a/src/jdk/nashorn/internal/ir/RuntimeNode.java b/src/jdk/nashorn/internal/ir/RuntimeNode.java
index 540b2eaf..d100b408 100644
--- a/src/jdk/nashorn/internal/ir/RuntimeNode.java
+++ b/src/jdk/nashorn/internal/ir/RuntimeNode.java
@@ -29,7 +29,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -39,7 +38,7 @@ import jdk.nashorn.internal.parser.TokenType;
* IR representation for a runtime call.
*/
@Immutable
-public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
+public class RuntimeNode extends Expression implements TypeOverride<RuntimeNode> {
/**
* Request enum used for meta-information about the runtime request
@@ -53,8 +52,6 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
NEW,
/** Typeof operator */
TYPEOF,
- /** void type */
- VOID,
/** Reference error type */
REFERENCE_ERROR,
/** Delete operator */
@@ -269,7 +266,7 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
private final Request request;
/** Call arguments. */
- private final List<Node> args;
+ private final List<Expression> args;
/** Call site override - e.g. we know that a ScriptRuntime.ADD will return an int */
private final Type callSiteType;
@@ -285,7 +282,7 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
* @param request the request
* @param args arguments to request
*/
- public RuntimeNode(final long token, final int finish, final Request request, final List<Node> args) {
+ public RuntimeNode(final long token, final int finish, final Request request, final List<Expression> args) {
super(token, finish);
this.request = request;
@@ -294,7 +291,7 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
this.isFinal = false;
}
- private RuntimeNode(final RuntimeNode runtimeNode, final Request request, final Type callSiteType, final boolean isFinal, final List<Node> args) {
+ private RuntimeNode(final RuntimeNode runtimeNode, final Request request, final Type callSiteType, final boolean isFinal, final List<Expression> args) {
super(runtimeNode);
this.request = request;
@@ -311,7 +308,7 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
* @param request the request
* @param args arguments to request
*/
- public RuntimeNode(final long token, final int finish, final Request request, final Node... args) {
+ public RuntimeNode(final long token, final int finish, final Request request, final Expression... args) {
this(token, finish, request, Arrays.asList(args));
}
@@ -322,7 +319,7 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
* @param request the request
* @param args arguments to request
*/
- public RuntimeNode(final Node parent, final Request request, final Node... args) {
+ public RuntimeNode(final Expression parent, final Request request, final Expression... args) {
this(parent, request, Arrays.asList(args));
}
@@ -333,7 +330,7 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
* @param request the request
* @param args arguments to request
*/
- public RuntimeNode(final Node parent, final Request request, final List<Node> args) {
+ public RuntimeNode(final Expression parent, final Request request, final List<Expression> args) {
super(parent);
this.request = request;
@@ -410,9 +407,9 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
@Override
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterRuntimeNode(this)) {
- final List<Node> newArgs = new ArrayList<>();
+ final List<Expression> newArgs = new ArrayList<>();
for (final Node arg : args) {
- newArgs.add(arg.accept(visitor));
+ newArgs.add((Expression)arg.accept(visitor));
}
return visitor.leaveRuntimeNode(setArgs(newArgs));
}
@@ -445,11 +442,11 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
* Get the arguments for this runtime node
* @return argument list
*/
- public List<Node> getArgs() {
+ public List<Expression> getArgs() {
return Collections.unmodifiableList(args);
}
- private RuntimeNode setArgs(final List<Node> args) {
+ private RuntimeNode setArgs(final List<Expression> args) {
if (this.args == args) {
return this;
}
@@ -472,7 +469,7 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
* @return true if all arguments now are primitive
*/
public boolean isPrimitive() {
- for (final Node arg : args) {
+ for (final Expression arg : args) {
if (arg.getType().isObject()) {
return false;
}
diff --git a/src/jdk/nashorn/internal/ir/SplitNode.java b/src/jdk/nashorn/internal/ir/SplitNode.java
index e71cd6bd..d6c619b7 100644
--- a/src/jdk/nashorn/internal/ir/SplitNode.java
+++ b/src/jdk/nashorn/internal/ir/SplitNode.java
@@ -33,7 +33,7 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
* Node indicating code is split across classes.
*/
@Immutable
-public class SplitNode extends LexicalContextNode {
+public class SplitNode extends LexicalContextStatement {
/** Split node method name. */
private final String name;
@@ -46,13 +46,12 @@ public class SplitNode extends LexicalContextNode {
/**
* Constructor
*
- * @param lineNumber lineNumber
* @param name name of split node
* @param body body of split code
* @param compileUnit compile unit to use for the body
*/
- public SplitNode(final int lineNumber, final String name, final Node body, final CompileUnit compileUnit) {
- super(lineNumber, body.getToken(), body.getFinish());
+ public SplitNode(final String name, final Node body, final CompileUnit compileUnit) {
+ super(-1, body.getToken(), body.getFinish());
this.name = name;
this.body = body;
this.compileUnit = compileUnit;
diff --git a/src/jdk/nashorn/internal/ir/SwitchNode.java b/src/jdk/nashorn/internal/ir/SwitchNode.java
index 3790ad51..d31bec52 100644
--- a/src/jdk/nashorn/internal/ir/SwitchNode.java
+++ b/src/jdk/nashorn/internal/ir/SwitchNode.java
@@ -28,7 +28,6 @@ package jdk.nashorn.internal.ir;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-
import jdk.nashorn.internal.codegen.Label;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -37,9 +36,9 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
* IR representation of a SWITCH statement.
*/
@Immutable
-public final class SwitchNode extends BreakableNode {
+public final class SwitchNode extends BreakableStatement {
/** Switch expression. */
- private final Node expression;
+ private final Expression expression;
/** Switch cases. */
private final List<CaseNode> cases;
@@ -60,14 +59,14 @@ public final class SwitchNode extends BreakableNode {
* @param cases cases
* @param defaultCase the default case node - null if none, otherwise has to be present in cases list
*/
- public SwitchNode(final int lineNumber, final long token, final int finish, final Node expression, final List<CaseNode> cases, final CaseNode defaultCase) {
+ public SwitchNode(final int lineNumber, final long token, final int finish, final Expression expression, final List<CaseNode> cases, final CaseNode defaultCase) {
super(lineNumber, token, finish, new Label("switch_break"));
this.expression = expression;
this.cases = cases;
this.defaultCaseIndex = defaultCase == null ? -1 : cases.indexOf(defaultCase);
}
- private SwitchNode(final SwitchNode switchNode, final Node expression, final List<CaseNode> cases, final int defaultCase) {
+ private SwitchNode(final SwitchNode switchNode, final Expression expression, final List<CaseNode> cases, final int defaultCase) {
super(switchNode);
this.expression = expression;
this.cases = cases;
@@ -103,7 +102,7 @@ public final class SwitchNode extends BreakableNode {
public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterSwitchNode(this)) {
return visitor.leaveSwitchNode(
- setExpression(lc, expression.accept(visitor)).
+ setExpression(lc, (Expression)expression.accept(visitor)).
setCases(lc, Node.accept(visitor, CaseNode.class, cases), defaultCaseIndex));
}
@@ -167,7 +166,7 @@ public final class SwitchNode extends BreakableNode {
* Return the expression to switch on
* @return switch expression
*/
- public Node getExpression() {
+ public Expression getExpression() {
return expression;
}
@@ -177,7 +176,7 @@ public final class SwitchNode extends BreakableNode {
* @param expression switch expression
* @return new switch node or same if no state was changed
*/
- public SwitchNode setExpression(final LexicalContext lc, final Node expression) {
+ public SwitchNode setExpression(final LexicalContext lc, final Expression expression) {
if (this.expression == expression) {
return this;
}
diff --git a/src/jdk/nashorn/internal/ir/Symbol.java b/src/jdk/nashorn/internal/ir/Symbol.java
index 7c183902..5061ab90 100644
--- a/src/jdk/nashorn/internal/ir/Symbol.java
+++ b/src/jdk/nashorn/internal/ir/Symbol.java
@@ -29,7 +29,6 @@ import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
-
import jdk.nashorn.internal.codegen.types.Range;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.runtime.Context;
@@ -705,7 +704,7 @@ public final class Symbol implements Comparable<Symbol> {
public static void setSymbolIsScope(final LexicalContext lc, final Symbol symbol) {
symbol.setIsScope();
if (!symbol.isGlobal()) {
- lc.setFlag(lc.getDefiningBlock(symbol), Block.NEEDS_SCOPE);
+ lc.setBlockNeedsScope(lc.getDefiningBlock(symbol));
}
}
diff --git a/src/jdk/nashorn/internal/ir/TemporarySymbols.java b/src/jdk/nashorn/internal/ir/TemporarySymbols.java
index ee8069e1..4a438ddd 100644
--- a/src/jdk/nashorn/internal/ir/TemporarySymbols.java
+++ b/src/jdk/nashorn/internal/ir/TemporarySymbols.java
@@ -49,7 +49,7 @@ public class TemporarySymbols {
* @param node the node
* @return the node that is guaranteed to have a symbol.
*/
- public Node ensureSymbol(final LexicalContext lc, final Type type, final Node node) {
+ public Expression ensureSymbol(final LexicalContext lc, final Type type, final Expression node) {
final Symbol symbol = node.getSymbol();
if (symbol != null) {
return node;
diff --git a/src/jdk/nashorn/internal/ir/TernaryNode.java b/src/jdk/nashorn/internal/ir/TernaryNode.java
index c05e6245..70e1c726 100644
--- a/src/jdk/nashorn/internal/ir/TernaryNode.java
+++ b/src/jdk/nashorn/internal/ir/TernaryNode.java
@@ -32,43 +32,43 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
* TernaryNode nodes represent three operand operations (?:).
*/
@Immutable
-public final class TernaryNode extends Node {
- private final Node lhs;
+public final class TernaryNode extends Expression {
+ private final Expression test;
- private final Node rhs;
+ private final Expression trueExpr;
/** Third argument. */
- private final Node third;
+ private final Expression falseExpr;
/**
* Constructor
*
- * @param token token
- * @param lhs left hand side node
- * @param rhs right hand side node
- * @param third third node
+ * @param token token
+ * @param test test expression
+ * @param trueExpr expression evaluated when test evaluates to true
+ * @param falseExpr expression evaluated when test evaluates to true
*/
- public TernaryNode(final long token, final Node lhs, final Node rhs, final Node third) {
- super(token, third.getFinish());
- this.lhs = lhs;
- this.rhs = rhs;
- this.third = third;
+ public TernaryNode(final long token, final Expression test, final Expression trueExpr, final Expression falseExpr) {
+ super(token, falseExpr.getFinish());
+ this.test = test;
+ this.trueExpr = trueExpr;
+ this.falseExpr = falseExpr;
}
- private TernaryNode(final TernaryNode ternaryNode, final Node lhs, final Node rhs, final Node third) {
+ private TernaryNode(final TernaryNode ternaryNode, final Expression test, final Expression trueExpr, final Expression falseExpr) {
super(ternaryNode);
- this.lhs = lhs;
- this.rhs = rhs;
- this.third = third;
+ this.test = test;
+ this.trueExpr = trueExpr;
+ this.falseExpr = falseExpr;
}
@Override
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterTernaryNode(this)) {
- final Node newLhs = lhs().accept(visitor);
- final Node newRhs = rhs().accept(visitor);
- final Node newThird = third.accept(visitor);
- return visitor.leaveTernaryNode(setThird(newThird).setLHS(newLhs).setRHS(newRhs));
+ final Expression newTest = (Expression)getTest().accept(visitor);
+ final Expression newTrueExpr = (Expression)getTrueExpression().accept(visitor);
+ final Expression newFalseExpr = (Expression)falseExpr.accept(visitor);
+ return visitor.leaveTernaryNode(setTest(newTest).setTrueExpression(newTrueExpr).setFalseExpression1(newFalseExpr));
}
return this;
@@ -76,96 +76,96 @@ public final class TernaryNode extends Node {
@Override
public void toString(final StringBuilder sb) {
- final boolean lhsParen = tokenType().needsParens(lhs().tokenType(), true);
- final boolean rhsParen = tokenType().needsParens(rhs().tokenType(), false);
- final boolean thirdParen = tokenType().needsParens(third().tokenType(), false);
+ final boolean testParen = tokenType().needsParens(getTest().tokenType(), true);
+ final boolean trueParen = tokenType().needsParens(getTrueExpression().tokenType(), false);
+ final boolean falseParen = tokenType().needsParens(getFalseExpression().tokenType(), false);
- if (lhsParen) {
+ if (testParen) {
sb.append('(');
}
- lhs().toString(sb);
- if (lhsParen) {
+ getTest().toString(sb);
+ if (testParen) {
sb.append(')');
}
sb.append(" ? ");
- if (rhsParen) {
+ if (trueParen) {
sb.append('(');
}
- rhs().toString(sb);
- if (rhsParen) {
+ getTrueExpression().toString(sb);
+ if (trueParen) {
sb.append(')');
}
sb.append(" : ");
- if (thirdParen) {
+ if (falseParen) {
sb.append('(');
}
- third().toString(sb);
- if (thirdParen) {
+ getFalseExpression().toString(sb);
+ if (falseParen) {
sb.append(')');
}
}
/**
- * Get the lhs node for this ternary expression, i.e. "x" in x ? y : z
- * @return a node
+ * Get the test expression for this ternary expression, i.e. "x" in x ? y : z
+ * @return the test expression
*/
- public Node lhs() {
- return lhs;
+ public Expression getTest() {
+ return test;
}
/**
- * Get the rhs node for this ternary expression, i.e. "y" in x ? y : z
- * @return a node
+ * Get the true expression for this ternary expression, i.e. "y" in x ? y : z
+ * @return the true expression
*/
- public Node rhs() {
- return rhs;
+ public Expression getTrueExpression() {
+ return trueExpr;
}
/**
- * Get the "third" node for this ternary expression, i.e. "z" in x ? y : z
- * @return a node
+ * Get the false expression for this ternary expression, i.e. "z" in x ? y : z
+ * @return the false expression
*/
- public Node third() {
- return third;
+ public Expression getFalseExpression() {
+ return falseExpr;
}
/**
- * Set the left hand side expression for this node
- * @param lhs new left hand side expression
+ * Set the test expression for this node
+ * @param test new test expression
* @return a node equivalent to this one except for the requested change.
*/
- public TernaryNode setLHS(final Node lhs) {
- if (this.lhs == lhs) {
+ public TernaryNode setTest(final Expression test) {
+ if (this.test == test) {
return this;
}
- return new TernaryNode(this, lhs, rhs, third);
+ return new TernaryNode(this, test, trueExpr, falseExpr);
}
/**
- * Set the right hand side expression for this node
- * @param rhs new left hand side expression
+ * Set the true expression for this node
+ * @param trueExpr new true expression
* @return a node equivalent to this one except for the requested change.
*/
- public TernaryNode setRHS(final Node rhs) {
- if (this.rhs == rhs) {
+ public TernaryNode setTrueExpression(final Expression trueExpr) {
+ if (this.trueExpr == trueExpr) {
return this;
}
- return new TernaryNode(this, lhs, rhs, third);
+ return new TernaryNode(this, test, trueExpr, falseExpr);
}
/**
- * Reset the "third" node for this ternary expression, i.e. "z" in x ? y : z
- * @param third a node
+ * Set the false expression for this node
+ * @param falseExpr new false expression
* @return a node equivalent to this one except for the requested change.
*/
- public TernaryNode setThird(final Node third) {
- if (this.third == third) {
+ public TernaryNode setFalseExpression1(final Expression falseExpr) {
+ if (this.falseExpr == falseExpr) {
return this;
}
- return new TernaryNode(this, lhs, rhs, third);
+ return new TernaryNode(this, test, trueExpr, falseExpr);
}
}
diff --git a/src/jdk/nashorn/internal/ir/ThrowNode.java b/src/jdk/nashorn/internal/ir/ThrowNode.java
index 3d33fc77..70efa532 100644
--- a/src/jdk/nashorn/internal/ir/ThrowNode.java
+++ b/src/jdk/nashorn/internal/ir/ThrowNode.java
@@ -34,7 +34,7 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@Immutable
public final class ThrowNode extends Statement {
/** Exception expression. */
- private final Node expression;
+ private final Expression expression;
private final int flags;
@@ -50,13 +50,13 @@ public final class ThrowNode extends Statement {
* @param expression expression to throw
* @param flags flags
*/
- public ThrowNode(final int lineNumber, final long token, final int finish, final Node expression, final int flags) {
+ public ThrowNode(final int lineNumber, final long token, final int finish, final Expression expression, final int flags) {
super(lineNumber, token, finish);
this.expression = expression;
this.flags = flags;
}
- private ThrowNode(final ThrowNode node, final Node expression, final int flags) {
+ private ThrowNode(final ThrowNode node, final Expression expression, final int flags) {
super(node);
this.expression = expression;
this.flags = flags;
@@ -74,7 +74,7 @@ public final class ThrowNode extends Statement {
@Override
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterThrowNode(this)) {
- return visitor.leaveThrowNode(setExpression(expression.accept(visitor)));
+ return visitor.leaveThrowNode(setExpression((Expression)expression.accept(visitor)));
}
return this;
@@ -93,7 +93,7 @@ public final class ThrowNode extends Statement {
* Get the expression that is being thrown by this node
* @return expression
*/
- public Node getExpression() {
+ public Expression getExpression() {
return expression;
}
@@ -102,7 +102,7 @@ public final class ThrowNode extends Statement {
* @param expression new expression
* @return new or same thrownode
*/
- public ThrowNode setExpression(final Node expression) {
+ public ThrowNode setExpression(final Expression expression) {
if (this.expression == expression) {
return this;
}
diff --git a/src/jdk/nashorn/internal/ir/UnaryNode.java b/src/jdk/nashorn/internal/ir/UnaryNode.java
index f9c971ed..2de2ca5d 100644
--- a/src/jdk/nashorn/internal/ir/UnaryNode.java
+++ b/src/jdk/nashorn/internal/ir/UnaryNode.java
@@ -29,6 +29,7 @@ import static jdk.nashorn.internal.parser.TokenType.BIT_NOT;
import static jdk.nashorn.internal.parser.TokenType.CONVERT;
import static jdk.nashorn.internal.parser.TokenType.DECPOSTFIX;
import static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX;
+
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -39,9 +40,9 @@ import jdk.nashorn.internal.parser.TokenType;
* UnaryNode nodes represent single operand operations.
*/
@Immutable
-public final class UnaryNode extends Node implements Assignment<Node> {
+public final class UnaryNode extends Expression implements Assignment<Expression> {
/** Right hand side argument. */
- private final Node rhs;
+ private final Expression rhs;
/**
* Constructor
@@ -49,7 +50,7 @@ public final class UnaryNode extends Node implements Assignment<Node> {
* @param token token
* @param rhs expression
*/
- public UnaryNode(final long token, final Node rhs) {
+ public UnaryNode(final long token, final Expression rhs) {
this(token, Math.min(rhs.getStart(), Token.descPosition(token)), Math.max(Token.descPosition(token) + Token.descLength(token), rhs.getFinish()), rhs);
}
@@ -61,13 +62,13 @@ public final class UnaryNode extends Node implements Assignment<Node> {
* @param finish finish
* @param rhs expression
*/
- public UnaryNode(final long token, final int start, final int finish, final Node rhs) {
+ public UnaryNode(final long token, final int start, final int finish, final Expression rhs) {
super(token, start, finish);
this.rhs = rhs;
}
- private UnaryNode(final UnaryNode unaryNode, final Node rhs) {
+ private UnaryNode(final UnaryNode unaryNode, final Expression rhs) {
super(unaryNode);
this.rhs = rhs;
}
@@ -101,17 +102,17 @@ public final class UnaryNode extends Node implements Assignment<Node> {
}
@Override
- public Node getAssignmentDest() {
+ public Expression getAssignmentDest() {
return isAssignment() ? rhs() : null;
}
@Override
- public Node setAssignmentDest(Node n) {
+ public UnaryNode setAssignmentDest(Expression n) {
return setRHS(n);
}
@Override
- public Node getAssignmentSource() {
+ public Expression getAssignmentSource() {
return getAssignmentDest();
}
@@ -122,7 +123,7 @@ public final class UnaryNode extends Node implements Assignment<Node> {
@Override
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterUnaryNode(this)) {
- return visitor.leaveUnaryNode(setRHS(rhs.accept(visitor)));
+ return visitor.leaveUnaryNode(setRHS((Expression)rhs.accept(visitor)));
}
return this;
@@ -130,6 +131,22 @@ public final class UnaryNode extends Node implements Assignment<Node> {
@Override
public void toString(final StringBuilder sb) {
+ toString(sb, new Runnable() {
+ @Override
+ public void run() {
+ sb.append(rhs().toString());
+ }
+ });
+ }
+
+ /**
+ * Creates the string representation of this unary node, delegating the creation of the string representation of its
+ * operand to a specified runnable.
+ * @param sb the string builder to use
+ * @param rhsStringBuilder the runnable that appends the string representation of the operand to the string builder
+ * when invoked.
+ */
+ public void toString(final StringBuilder sb, final Runnable rhsStringBuilder) {
final TokenType type = tokenType();
final String name = type.getName();
final boolean isPostfix = type == DECPOSTFIX || type == INCPOSTFIX;
@@ -161,7 +178,7 @@ public final class UnaryNode extends Node implements Assignment<Node> {
if (rhsParen) {
sb.append('(');
}
- rhs().toString(sb);
+ rhsStringBuilder.run();
if (rhsParen) {
sb.append(')');
}
@@ -189,7 +206,7 @@ public final class UnaryNode extends Node implements Assignment<Node> {
*
* @return right hand side or expression node
*/
- public Node rhs() {
+ public Expression rhs() {
return rhs;
}
@@ -202,7 +219,7 @@ public final class UnaryNode extends Node implements Assignment<Node> {
* @param rhs right hand side or expression node
* @return a node equivalent to this one except for the requested change.
*/
- public UnaryNode setRHS(final Node rhs) {
+ public UnaryNode setRHS(final Expression rhs) {
if (this.rhs == rhs) {
return this;
}
diff --git a/src/jdk/nashorn/internal/ir/VarNode.java b/src/jdk/nashorn/internal/ir/VarNode.java
index d4f41d6d..67648a00 100644
--- a/src/jdk/nashorn/internal/ir/VarNode.java
+++ b/src/jdk/nashorn/internal/ir/VarNode.java
@@ -37,7 +37,7 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
private final IdentNode name;
/** Initialization expression. */
- private final Node init;
+ private final Expression init;
/** Is this a var statement (as opposed to a "var" in a for loop statement) */
private final int flags;
@@ -59,11 +59,11 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
* @param name name of variable
* @param init init node or null if just a declaration
*/
- public VarNode(final int lineNumber, final long token, final int finish, final IdentNode name, final Node init) {
+ public VarNode(final int lineNumber, final long token, final int finish, final IdentNode name, final Expression init) {
this(lineNumber, token, finish, name, init, IS_STATEMENT);
}
- private VarNode(final VarNode varNode, final IdentNode name, final Node init, final int flags) {
+ private VarNode(final VarNode varNode, final IdentNode name, final Expression init, final int flags) {
super(varNode);
this.name = init == null ? name : name.setIsInitializedHere();
this.init = init;
@@ -80,7 +80,7 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
* @param init init node or null if just a declaration
* @param flags flags
*/
- public VarNode(final int lineNumber, final long token, final int finish, final IdentNode name, final Node init, final int flags) {
+ public VarNode(final int lineNumber, final long token, final int finish, final IdentNode name, final Expression init, final int flags) {
super(lineNumber, token, finish);
this.name = init == null ? name : name.setIsInitializedHere();
@@ -99,12 +99,12 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
}
@Override
- public Node setAssignmentDest(IdentNode n) {
+ public VarNode setAssignmentDest(IdentNode n) {
return setName(n);
}
@Override
- public Node getAssignmentSource() {
+ public Expression getAssignmentSource() {
return isAssignment() ? getInit() : null;
}
@@ -123,9 +123,9 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
@Override
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterVarNode(this)) {
- final IdentNode newName = (IdentNode)name.accept(visitor);
- final Node newInit = init == null ? null : init.accept(visitor);
- final VarNode newThis;
+ final IdentNode newName = (IdentNode)name.accept(visitor);
+ final Expression newInit = init == null ? null : (Expression)init.accept(visitor);
+ final VarNode newThis;
if (name != newName || init != newInit) {
newThis = new VarNode(this, newName, newInit, flags);
} else {
@@ -151,7 +151,7 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
* If this is an assignment of the form {@code var x = init;}, get the init part.
* @return the expression to initialize the variable to, null if just a declaration
*/
- public Node getInit() {
+ public Expression getInit() {
return init;
}
@@ -160,7 +160,7 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
* @param init new initialization expression
* @return a node equivalent to this one except for the requested change.
*/
- public VarNode setInit(final Node init) {
+ public VarNode setInit(final Expression init) {
if (this.init == init) {
return this;
}
diff --git a/src/jdk/nashorn/internal/ir/WhileNode.java b/src/jdk/nashorn/internal/ir/WhileNode.java
index c2d05b3d..3c0046c0 100644
--- a/src/jdk/nashorn/internal/ir/WhileNode.java
+++ b/src/jdk/nashorn/internal/ir/WhileNode.java
@@ -59,7 +59,7 @@ public final class WhileNode extends LoopNode {
* @param body body
* @param controlFlowEscapes control flow escapes?
*/
- protected WhileNode(final WhileNode whileNode, final Node test, final Block body, final boolean controlFlowEscapes) {
+ protected WhileNode(final WhileNode whileNode, final Expression test, final Block body, final boolean controlFlowEscapes) {
super(whileNode, test, body, controlFlowEscapes);
this.isDoWhile = whileNode.isDoWhile;
}
@@ -75,28 +75,28 @@ public final class WhileNode extends LoopNode {
}
@Override
- protected Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
+ public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterWhileNode(this)) {
if (isDoWhile()) {
return visitor.leaveWhileNode(
- setTest(lc, test.accept(visitor)).
+ setTest(lc, (Expression)test.accept(visitor)).
setBody(lc, (Block)body.accept(visitor)));
}
return visitor.leaveWhileNode(
setBody(lc, (Block)body.accept(visitor)).
- setTest(lc, test.accept(visitor)));
+ setTest(lc, (Expression)test.accept(visitor)));
}
return this;
}
@Override
- public Node getTest() {
+ public Expression getTest() {
return test;
}
@Override
- public WhileNode setTest(final LexicalContext lc, final Node test) {
+ public WhileNode setTest(final LexicalContext lc, final Expression test) {
if (this.test == test) {
return this;
}
diff --git a/src/jdk/nashorn/internal/ir/WithNode.java b/src/jdk/nashorn/internal/ir/WithNode.java
index 387659b2..69bd22d6 100644
--- a/src/jdk/nashorn/internal/ir/WithNode.java
+++ b/src/jdk/nashorn/internal/ir/WithNode.java
@@ -32,9 +32,9 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
* IR representation for {@code with} statements.
*/
@Immutable
-public final class WithNode extends LexicalContextNode {
+public final class WithNode extends LexicalContextStatement {
/** This expression. */
- private final Node expression;
+ private final Expression expression;
/** Statements. */
private final Block body;
@@ -52,7 +52,7 @@ public final class WithNode extends LexicalContextNode {
this.body = null;
}
- private WithNode(final WithNode node, final Node expression, final Block body) {
+ private WithNode(final WithNode node, final Expression expression, final Block body) {
super(node);
this.expression = expression;
this.body = body;
@@ -67,7 +67,7 @@ public final class WithNode extends LexicalContextNode {
public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterWithNode(this)) {
return visitor.leaveWithNode(
- setExpression(lc, expression.accept(visitor)).
+ setExpression(lc, (Expression)expression.accept(visitor)).
setBody(lc, (Block)body.accept(visitor)));
}
return this;
@@ -110,7 +110,7 @@ public final class WithNode extends LexicalContextNode {
* Get the expression of this WithNode
* @return the expression
*/
- public Node getExpression() {
+ public Expression getExpression() {
return expression;
}
@@ -120,7 +120,7 @@ public final class WithNode extends LexicalContextNode {
* @param expression new expression
* @return new or same withnode
*/
- public WithNode setExpression(final LexicalContext lc, final Node expression) {
+ public WithNode setExpression(final LexicalContext lc, final Expression expression) {
if (this.expression == expression) {
return this;
}
diff --git a/src/jdk/nashorn/internal/ir/debug/ASTWriter.java b/src/jdk/nashorn/internal/ir/debug/ASTWriter.java
index 5d9b5dfb..2f75e09b 100644
--- a/src/jdk/nashorn/internal/ir/debug/ASTWriter.java
+++ b/src/jdk/nashorn/internal/ir/debug/ASTWriter.java
@@ -33,10 +33,11 @@ import java.util.Deque;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
-
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
+import jdk.nashorn.internal.ir.Expression;
import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.Symbol;
import jdk.nashorn.internal.ir.TernaryNode;
import jdk.nashorn.internal.ir.annotations.Ignore;
import jdk.nashorn.internal.ir.annotations.Reference;
@@ -111,8 +112,15 @@ public final class ASTWriter {
type = "ref: " + type;
}
type += "@" + Debug.id(node);
- if (node.getSymbol() != null) {
- type += "#" + node.getSymbol();
+ final Symbol symbol;
+ if(node instanceof Expression) {
+ symbol = ((Expression)node).getSymbol();
+ } else {
+ symbol = null;
+ }
+
+ if (symbol != null) {
+ type += "#" + symbol;
}
if (node instanceof Block && ((Block)node).needsScope()) {
@@ -135,8 +143,8 @@ public final class ASTWriter {
status += " Goto ";
}
- if (node.getSymbol() != null) {
- status += node.getSymbol();
+ if (symbol != null) {
+ status += symbol;
}
status = status.trim();
@@ -144,8 +152,8 @@ public final class ASTWriter {
status = " [" + status + "]";
}
- if (node.getSymbol() != null) {
- String tname = node.getType().toString();
+ if (symbol != null) {
+ String tname = ((Expression)node).getType().toString();
if (tname.indexOf('.') != -1) {
tname = tname.substring(tname.lastIndexOf('.') + 1, tname.length());
}
diff --git a/src/jdk/nashorn/internal/ir/debug/JSONWriter.java b/src/jdk/nashorn/internal/ir/debug/JSONWriter.java
index 4415ebd7..be4d49b4 100644
--- a/src/jdk/nashorn/internal/ir/debug/JSONWriter.java
+++ b/src/jdk/nashorn/internal/ir/debug/JSONWriter.java
@@ -27,18 +27,18 @@ package jdk.nashorn.internal.ir.debug;
import java.util.Arrays;
import java.util.List;
-
import jdk.nashorn.internal.codegen.CompilerConstants;
import jdk.nashorn.internal.ir.AccessNode;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
+import jdk.nashorn.internal.ir.BlockStatement;
import jdk.nashorn.internal.ir.BreakNode;
import jdk.nashorn.internal.ir.CallNode;
import jdk.nashorn.internal.ir.CaseNode;
import jdk.nashorn.internal.ir.CatchNode;
import jdk.nashorn.internal.ir.ContinueNode;
import jdk.nashorn.internal.ir.EmptyNode;
-import jdk.nashorn.internal.ir.ExecuteNode;
+import jdk.nashorn.internal.ir.ExpressionStatement;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.IdentNode;
@@ -298,14 +298,27 @@ public final class JSONWriter extends NodeVisitor<LexicalContext> {
}
@Override
- public boolean enterExecuteNode(final ExecuteNode executeNode) {
- enterDefault(executeNode);
+ public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) {
+ enterDefault(expressionStatement);
type("ExpressionStatement");
comma();
property("expression");
- executeNode.getExpression().accept(this);
+ expressionStatement.getExpression().accept(this);
+
+ return leave();
+ }
+
+ @Override
+ public boolean enterBlockStatement(BlockStatement blockStatement) {
+ enterDefault(blockStatement);
+
+ type("BlockStatement");
+ comma();
+
+ property("block");
+ blockStatement.getBlock().accept(this);
return leave();
}
@@ -514,7 +527,7 @@ public final class JSONWriter extends NodeVisitor<LexicalContext> {
type("ArrayExpression");
comma();
- final Node[] value = (Node[])literalNode.getValue();
+ final Node[] value = literalNode.getArray();
array("elements", Arrays.asList(value));
} else {
type("Literal");
@@ -680,15 +693,15 @@ public final class JSONWriter extends NodeVisitor<LexicalContext> {
comma();
property("test");
- ternaryNode.lhs().accept(this);
+ ternaryNode.getTest().accept(this);
comma();
property("consequent");
- ternaryNode.rhs().accept(this);
+ ternaryNode.getTrueExpression().accept(this);
comma();
property("alternate");
- ternaryNode.third().accept(this);
+ ternaryNode.getFalseExpression().accept(this);
return leave();
}
diff --git a/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java b/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java
index 2e2368b1..f939dc67 100644
--- a/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java
+++ b/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java
@@ -26,12 +26,11 @@
package jdk.nashorn.internal.ir.debug;
import java.util.List;
-
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.CaseNode;
import jdk.nashorn.internal.ir.CatchNode;
-import jdk.nashorn.internal.ir.ExecuteNode;
+import jdk.nashorn.internal.ir.ExpressionStatement;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.IfNode;
@@ -41,8 +40,8 @@ import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.SplitNode;
import jdk.nashorn.internal.ir.Statement;
import jdk.nashorn.internal.ir.SwitchNode;
-import jdk.nashorn.internal.ir.Symbol;
import jdk.nashorn.internal.ir.TryNode;
+import jdk.nashorn.internal.ir.UnaryNode;
import jdk.nashorn.internal.ir.VarNode;
import jdk.nashorn.internal.ir.WhileNode;
import jdk.nashorn.internal.ir.WithNode;
@@ -167,14 +166,6 @@ public final class PrintVisitor extends NodeVisitor<LexicalContext> {
continue;
}
- final Symbol symbol = statement.getSymbol();
-
- if (symbol != null) {
- sb.append(" [");
- sb.append(symbol.toString());
- sb.append(']');
- }
-
int lastIndex = sb.length() - 1;
char lastChar = sb.charAt(lastIndex);
while (Character.isWhitespace(lastChar) && lastIndex >= 0) {
@@ -215,8 +206,19 @@ public final class PrintVisitor extends NodeVisitor<LexicalContext> {
}
@Override
- public boolean enterExecuteNode(final ExecuteNode executeNode) {
- executeNode.getExpression().accept(this);
+ public boolean enterUnaryNode(final UnaryNode unaryNode) {
+ unaryNode.toString(sb, new Runnable() {
+ @Override
+ public void run() {
+ unaryNode.rhs().accept(PrintVisitor.this);
+ }
+ });
+ return false;
+ }
+
+ @Override
+ public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) {
+ expressionStatement.getExpression().accept(this);
return false;
}
diff --git a/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java b/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java
index 1791f92b..71600395 100644
--- a/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java
+++ b/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java
@@ -1263,6 +1263,4 @@ public class NodeOperatorVisitor<T extends LexicalContext> extends NodeVisitor<T
public Node leaveSUB(final BinaryNode binaryNode) {
return leaveDefault(binaryNode);
}
-
-
}
diff --git a/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java b/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java
index d8a21a64..4dc55b33 100644
--- a/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java
+++ b/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java
@@ -28,13 +28,14 @@ package jdk.nashorn.internal.ir.visitor;
import jdk.nashorn.internal.ir.AccessNode;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
+import jdk.nashorn.internal.ir.BlockStatement;
import jdk.nashorn.internal.ir.BreakNode;
import jdk.nashorn.internal.ir.CallNode;
import jdk.nashorn.internal.ir.CaseNode;
import jdk.nashorn.internal.ir.CatchNode;
import jdk.nashorn.internal.ir.ContinueNode;
import jdk.nashorn.internal.ir.EmptyNode;
-import jdk.nashorn.internal.ir.ExecuteNode;
+import jdk.nashorn.internal.ir.ExpressionStatement;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.IdentNode;
@@ -308,23 +309,43 @@ public abstract class NodeVisitor<T extends LexicalContext> {
}
/**
- * Callback for entering an ExecuteNode
+ * Callback for entering an ExpressionStatement
*
- * @param executeNode the node
+ * @param expressionStatement the node
* @return true if traversal should continue and node children be traversed, false otherwise
*/
- public boolean enterExecuteNode(final ExecuteNode executeNode) {
- return enterDefault(executeNode);
+ public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) {
+ return enterDefault(expressionStatement);
}
/**
- * Callback for leaving an ExecuteNode
+ * Callback for leaving an ExpressionStatement
*
- * @param executeNode the node
+ * @param expressionStatement the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leaveExecuteNode(final ExecuteNode executeNode) {
- return leaveDefault(executeNode);
+ public Node leaveExpressionStatement(final ExpressionStatement expressionStatement) {
+ return leaveDefault(expressionStatement);
+ }
+
+ /**
+ * Callback for entering a BlockStatement
+ *
+ * @param blockStatement the node
+ * @return true if traversal should continue and node children be traversed, false otherwise
+ */
+ public boolean enterBlockStatement(final BlockStatement blockStatement) {
+ return enterDefault(blockStatement);
+ }
+
+ /**
+ * Callback for leaving a BlockStatement
+ *
+ * @param blockStatement the node
+ * @return processed node, which will replace the original one, or the original node
+ */
+ public Node leaveBlockStatement(final BlockStatement blockStatement) {
+ return leaveDefault(blockStatement);
}
/**
diff --git a/src/jdk/nashorn/internal/lookup/Lookup.java b/src/jdk/nashorn/internal/lookup/Lookup.java
index a454527a..0dd2741e 100644
--- a/src/jdk/nashorn/internal/lookup/Lookup.java
+++ b/src/jdk/nashorn/internal/lookup/Lookup.java
@@ -32,8 +32,6 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import jdk.nashorn.internal.runtime.JSType;
-import jdk.nashorn.internal.runtime.Property;
-import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptRuntime;
/**
@@ -125,44 +123,6 @@ public final class Lookup {
}
/**
- * Create a new {@link Property}
- *
- * @param map property map
- * @param key property key
- * @param flags property flags
- * @param propertyGetter getter for property if available, null otherwise
- * @param propertySetter setter for property if available, null otherwise
- *
- * @return new property map, representing {@code PropertyMap} with the new property added to it
- */
- @SuppressWarnings("fallthrough")
- public static PropertyMap newProperty(final PropertyMap map, final String key, final int flags, final MethodHandle propertyGetter, final MethodHandle propertySetter) {
- MethodHandle getter = propertyGetter;
- MethodHandle setter = propertySetter;
-
- // TODO: this is temporary code. This code exists to support reflective
- // field reader/writer handles generated by "unreflect" lookup.
-
- switch (getter.type().parameterCount()) {
- case 0:
- // A static field reader, so drop the 'self' argument.
- getter = MH.dropArguments(getter, 0, Object.class);
- if (setter != null) {
- setter = MH.dropArguments(setter, 0, Object.class);
- }
- // fall through
- case 1:
- // standard getter that accepts 'self'.
- break;
- default:
- // Huh!! something wrong..
- throw new IllegalArgumentException("getter/setter has wrong arguments");
- }
-
- return map.newProperty(key, flags, -1, getter, setter);
- }
-
- /**
* This method filters primitive return types using JavaScript semantics. For example,
* an (int) cast of a double in Java land is not the same thing as invoking toInt32 on it.
* If you are returning values to JavaScript that have to be of a specific type, this is
diff --git a/src/jdk/nashorn/internal/objects/AccessorPropertyDescriptor.java b/src/jdk/nashorn/internal/objects/AccessorPropertyDescriptor.java
index d2d80b2f..b3731620 100644
--- a/src/jdk/nashorn/internal/objects/AccessorPropertyDescriptor.java
+++ b/src/jdk/nashorn/internal/objects/AccessorPropertyDescriptor.java
@@ -67,12 +67,12 @@ public final class AccessorPropertyDescriptor extends ScriptObject implements Pr
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- AccessorPropertyDescriptor() {
- this(false, false, UNDEFINED, UNDEFINED);
+ static PropertyMap getInitialMap() {
+ return $nasgenmap$;
}
- AccessorPropertyDescriptor(final boolean configurable, final boolean enumerable, final Object get, final Object set) {
- super(Global.objectPrototype(), $nasgenmap$);
+ AccessorPropertyDescriptor(final boolean configurable, final boolean enumerable, final Object get, final Object set, final Global global) {
+ super(global.getObjectPrototype(), global.getAccessorPropertyDescriptorMap());
this.configurable = configurable;
this.enumerable = enumerable;
this.get = get;
diff --git a/src/jdk/nashorn/internal/objects/ArrayBufferView.java b/src/jdk/nashorn/internal/objects/ArrayBufferView.java
index 312d521c..40b1a95c 100644
--- a/src/jdk/nashorn/internal/objects/ArrayBufferView.java
+++ b/src/jdk/nashorn/internal/objects/ArrayBufferView.java
@@ -25,6 +25,8 @@
package jdk.nashorn.internal.objects;
+import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError;
+
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Getter;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
@@ -34,20 +36,27 @@ import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
-import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError;
-
@ScriptClass("ArrayBufferView")
abstract class ArrayBufferView extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- ArrayBufferView(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
+ static PropertyMap getInitialMap() {
+ return $nasgenmap$;
+ }
+
+ private ArrayBufferView(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength, final Global global) {
+ super(global.getArrayBufferViewMap());
checkConstructorArgs(buffer, byteOffset, elementLength);
- this.setProto(getPrototype());
+ this.setProto(getPrototype(global));
this.setArray(factory().createArrayData(buffer, byteOffset, elementLength));
}
+ ArrayBufferView(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
+ this(buffer, byteOffset, elementLength, Global.instance());
+ }
+
private void checkConstructorArgs(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
if (byteOffset < 0 || elementLength < 0) {
throw new RuntimeException("byteOffset or length must not be negative");
@@ -266,12 +275,17 @@ abstract class ArrayBufferView extends ScriptObject {
protected static abstract class Factory {
final int bytesPerElement;
+ final int maxElementLength;
public Factory(final int bytesPerElement) {
this.bytesPerElement = bytesPerElement;
+ this.maxElementLength = Integer.MAX_VALUE / bytesPerElement;
}
public final ArrayBufferView construct(final int elementLength) {
+ if(elementLength > maxElementLength) {
+ throw rangeError("inappropriate.array.buffer.length", JSType.toString(elementLength));
+ }
return construct(new NativeArrayBuffer(elementLength * bytesPerElement), 0, elementLength);
}
@@ -282,7 +296,7 @@ abstract class ArrayBufferView extends ScriptObject {
protected abstract Factory factory();
- protected abstract ScriptObject getPrototype();
+ protected abstract ScriptObject getPrototype(final Global global);
protected boolean isFloatArray() {
return false;
diff --git a/src/jdk/nashorn/internal/objects/BoundScriptFunctionImpl.java b/src/jdk/nashorn/internal/objects/BoundScriptFunctionImpl.java
index be155f50..a8f311eb 100644
--- a/src/jdk/nashorn/internal/objects/BoundScriptFunctionImpl.java
+++ b/src/jdk/nashorn/internal/objects/BoundScriptFunctionImpl.java
@@ -39,7 +39,7 @@ class BoundScriptFunctionImpl extends ScriptFunctionImpl {
private final ScriptFunction targetFunction;
BoundScriptFunctionImpl(ScriptFunctionData data, ScriptFunction targetFunction) {
- super(data);
+ super(data, Global.instance());
setPrototype(ScriptRuntime.UNDEFINED);
this.targetFunction = targetFunction;
}
diff --git a/src/jdk/nashorn/internal/objects/DataPropertyDescriptor.java b/src/jdk/nashorn/internal/objects/DataPropertyDescriptor.java
index 8ac43977..ef3f0a30 100644
--- a/src/jdk/nashorn/internal/objects/DataPropertyDescriptor.java
+++ b/src/jdk/nashorn/internal/objects/DataPropertyDescriptor.java
@@ -25,7 +25,6 @@
package jdk.nashorn.internal.objects;
-import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import static jdk.nashorn.internal.runtime.ScriptRuntime.sameValue;
import java.util.Objects;
@@ -65,12 +64,12 @@ public final class DataPropertyDescriptor extends ScriptObject implements Proper
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- DataPropertyDescriptor() {
- this(false, false, false, UNDEFINED);
+ static PropertyMap getInitialMap() {
+ return $nasgenmap$;
}
- DataPropertyDescriptor(final boolean configurable, final boolean enumerable, final boolean writable, final Object value) {
- super(Global.objectPrototype(), $nasgenmap$);
+ DataPropertyDescriptor(final boolean configurable, final boolean enumerable, final boolean writable, final Object value, final Global global) {
+ super(global.getObjectPrototype(), global.getDataPropertyDescriptorMap());
this.configurable = configurable;
this.enumerable = enumerable;
this.writable = writable;
diff --git a/src/jdk/nashorn/internal/objects/GenericPropertyDescriptor.java b/src/jdk/nashorn/internal/objects/GenericPropertyDescriptor.java
index d6e9cf60..f5662efa 100644
--- a/src/jdk/nashorn/internal/objects/GenericPropertyDescriptor.java
+++ b/src/jdk/nashorn/internal/objects/GenericPropertyDescriptor.java
@@ -55,12 +55,12 @@ public final class GenericPropertyDescriptor extends ScriptObject implements Pro
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- GenericPropertyDescriptor() {
- this(false, false);
+ static PropertyMap getInitialMap() {
+ return $nasgenmap$;
}
- GenericPropertyDescriptor(final boolean configurable, final boolean enumerable) {
- super(Global.objectPrototype(), $nasgenmap$);
+ GenericPropertyDescriptor(final boolean configurable, final boolean enumerable, final Global global) {
+ super(global.getObjectPrototype(), global.getGenericPropertyDescriptorMap());
this.configurable = configurable;
this.enumerable = enumerable;
}
diff --git a/src/jdk/nashorn/internal/objects/Global.java b/src/jdk/nashorn/internal/objects/Global.java
index 5644c510..e54fbb45 100644
--- a/src/jdk/nashorn/internal/objects/Global.java
+++ b/src/jdk/nashorn/internal/objects/Global.java
@@ -43,7 +43,6 @@ import java.util.List;
import java.util.Map;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
-import jdk.nashorn.internal.lookup.MethodHandleFactory;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
@@ -363,6 +362,36 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
private ScriptObject builtinFloat32Array;
private ScriptObject builtinFloat64Array;
+ private PropertyMap accessorPropertyDescriptorMap;
+ private PropertyMap arrayBufferViewMap;
+ private PropertyMap dataPropertyDescriptorMap;
+ private PropertyMap genericPropertyDescriptorMap;
+ private PropertyMap nativeArgumentsMap;
+ private PropertyMap nativeArrayMap;
+ private PropertyMap nativeArrayBufferMap;
+ private PropertyMap nativeBooleanMap;
+ private PropertyMap nativeDateMap;
+ private PropertyMap nativeErrorMap;
+ private PropertyMap nativeEvalErrorMap;
+ private PropertyMap nativeJSAdapterMap;
+ private PropertyMap nativeJavaImporterMap;
+ private PropertyMap nativeNumberMap;
+ private PropertyMap nativeRangeErrorMap;
+ private PropertyMap nativeReferenceErrorMap;
+ private PropertyMap nativeRegExpMap;
+ private PropertyMap nativeRegExpExecResultMap;
+ private PropertyMap nativeStrictArgumentsMap;
+ private PropertyMap nativeStringMap;
+ private PropertyMap nativeSyntaxErrorMap;
+ private PropertyMap nativeTypeErrorMap;
+ private PropertyMap nativeURIErrorMap;
+ private PropertyMap prototypeObjectMap;
+ private PropertyMap objectMap;
+ private PropertyMap functionMap;
+ private PropertyMap anonymousFunctionMap;
+ private PropertyMap strictFunctionMap;
+ private PropertyMap boundFunctionMap;
+
// Flag to indicate that a split method issued a return statement
private int splitState = -1;
@@ -379,8 +408,6 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
private static final MethodHandle LOADWITHNEWGLOBAL = findOwnMH("loadWithNewGlobal", Object.class, Object.class, Object[].class);
private static final MethodHandle EXIT = findOwnMH("exit", Object.class, Object.class, Object.class);
- private final Context context;
-
// initialized by nasgen
private static PropertyMap $nasgenmap$;
@@ -390,14 +417,14 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
* @param context the context
*/
public Global(final Context context) {
- this.context = context;
- this.setIsScope();
/*
* Duplicate global's map and use it. This way the initial Map filled
* by nasgen (referenced from static field in this class) is retained
- * 'as is'. This allows multiple globals to be used within a context.
+ * 'as is' (as that one is process wide singleton.
*/
- this.setMap(getMap().duplicate());
+ super($nasgenmap$.duplicate());
+ this.setContext(context);
+ this.setIsScope();
final int cacheSize = context.getEnv()._class_cache_size;
if (cacheSize > 0) {
@@ -424,7 +451,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
* @return the script environment
*/
static ScriptEnvironment getEnv() {
- return instance().context.getEnv();
+ return instance().getContext().getEnv();
}
/**
@@ -433,7 +460,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
* @return the context
*/
static Context getThisContext() {
- return instance().context;
+ return instance().getContext();
}
// GlobalObject interface implementation
@@ -456,11 +483,11 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
@Override
public Object wrapAsObject(final Object obj) {
if (obj instanceof Boolean) {
- return new NativeBoolean((Boolean)obj);
+ return new NativeBoolean((Boolean)obj, this);
} else if (obj instanceof Number) {
- return new NativeNumber(((Number)obj).doubleValue());
+ return new NativeNumber(((Number)obj).doubleValue(), this);
} else if (obj instanceof String || obj instanceof ConsString) {
- return new NativeString((CharSequence)obj);
+ return new NativeString((CharSequence)obj, this);
} else if (obj instanceof Object[]) { // extension
return new NativeArray((Object[])obj);
} else if (obj instanceof double[]) { // extension
@@ -489,7 +516,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
@Override
public ScriptObject newObject() {
- return new JO(getObjectPrototype());
+ return new JO(getObjectPrototype(), getObjectMap());
}
@Override
@@ -566,52 +593,52 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
@Override
public ScriptObject newError(final String msg) {
- return new NativeError(msg);
+ return new NativeError(msg, this);
}
@Override
public ScriptObject newEvalError(final String msg) {
- return new NativeEvalError(msg);
+ return new NativeEvalError(msg, this);
}
@Override
public ScriptObject newRangeError(final String msg) {
- return new NativeRangeError(msg);
+ return new NativeRangeError(msg, this);
}
@Override
public ScriptObject newReferenceError(final String msg) {
- return new NativeReferenceError(msg);
+ return new NativeReferenceError(msg, this);
}
@Override
public ScriptObject newSyntaxError(final String msg) {
- return new NativeSyntaxError(msg);
+ return new NativeSyntaxError(msg, this);
}
@Override
public ScriptObject newTypeError(final String msg) {
- return new NativeTypeError(msg);
+ return new NativeTypeError(msg, this);
}
@Override
public ScriptObject newURIError(final String msg) {
- return new NativeURIError(msg);
+ return new NativeURIError(msg, this);
}
@Override
public PropertyDescriptor newGenericDescriptor(final boolean configurable, final boolean enumerable) {
- return new GenericPropertyDescriptor(configurable, enumerable);
+ return new GenericPropertyDescriptor(configurable, enumerable, this);
}
@Override
public PropertyDescriptor newDataDescriptor(final Object value, final boolean configurable, final boolean enumerable, final boolean writable) {
- return new DataPropertyDescriptor(configurable, enumerable, writable, value);
+ return new DataPropertyDescriptor(configurable, enumerable, writable, value, this);
}
@Override
public PropertyDescriptor newAccessorDescriptor(final Object get, final Object set, final boolean configurable, final boolean enumerable) {
- final AccessorPropertyDescriptor desc = new AccessorPropertyDescriptor(configurable, enumerable, get == null ? UNDEFINED : get, set == null ? UNDEFINED : set);
+ final AccessorPropertyDescriptor desc = new AccessorPropertyDescriptor(configurable, enumerable, get == null ? UNDEFINED : get, set == null ? UNDEFINED : set, this);
if (get == null) {
desc.delete(PropertyDescriptor.GET, false);
@@ -700,7 +727,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
final Global global = Global.instance();
final ScriptObject scope = (self instanceof ScriptObject) ? (ScriptObject)self : global;
- return global.context.eval(scope, str.toString(), callThis, location, Boolean.TRUE.equals(strict));
+ return global.getContext().eval(scope, str.toString(), callThis, location, Boolean.TRUE.equals(strict));
}
/**
@@ -740,7 +767,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
public static Object load(final Object self, final Object source) throws IOException {
final Global global = Global.instance();
final ScriptObject scope = (self instanceof ScriptObject) ? (ScriptObject)self : global;
- return global.context.load(scope, source);
+ return global.getContext().load(scope, source);
}
/**
@@ -760,7 +787,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
final Object from = hasArgs ? args[0] : UNDEFINED;
final Object[] arguments = hasArgs ? Arrays.copyOfRange(args, 1, length) : args;
- return global.context.loadWithNewGlobal(from, arguments);
+ return global.getContext().loadWithNewGlobal(from, arguments);
}
/**
@@ -776,6 +803,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
return UNDEFINED;
}
+ // builtin prototype accessors
ScriptObject getFunctionPrototype() {
return ScriptFunction.getPrototype(builtinFunction);
}
@@ -884,11 +912,127 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
return ScriptFunction.getPrototype(builtinFloat64Array);
}
+ // Builtin PropertyMap accessors
+ PropertyMap getAccessorPropertyDescriptorMap() {
+ return accessorPropertyDescriptorMap;
+ }
+
+ PropertyMap getArrayBufferViewMap() {
+ return arrayBufferViewMap;
+ }
+
+ PropertyMap getDataPropertyDescriptorMap() {
+ return dataPropertyDescriptorMap;
+ }
+
+ PropertyMap getGenericPropertyDescriptorMap() {
+ return genericPropertyDescriptorMap;
+ }
+
+ PropertyMap getArgumentsMap() {
+ return nativeArgumentsMap;
+ }
+
+ PropertyMap getArrayMap() {
+ return nativeArrayMap;
+ }
+
+ PropertyMap getArrayBufferMap() {
+ return nativeArrayBufferMap;
+ }
+
+ PropertyMap getBooleanMap() {
+ return nativeBooleanMap;
+ }
+
+ PropertyMap getDateMap() {
+ return nativeDateMap;
+ }
+
+ PropertyMap getErrorMap() {
+ return nativeErrorMap;
+ }
+
+ PropertyMap getEvalErrorMap() {
+ return nativeEvalErrorMap;
+ }
+
+ PropertyMap getJSAdapterMap() {
+ return nativeJSAdapterMap;
+ }
+
+ PropertyMap getJavaImporterMap() {
+ return nativeJavaImporterMap;
+ }
+
+ PropertyMap getNumberMap() {
+ return nativeNumberMap;
+ }
+
+ PropertyMap getRangeErrorMap() {
+ return nativeRangeErrorMap;
+ }
+
+ PropertyMap getReferenceErrorMap() {
+ return nativeReferenceErrorMap;
+ }
+
+ PropertyMap getRegExpMap() {
+ return nativeRegExpMap;
+ }
+
+ PropertyMap getRegExpExecResultMap() {
+ return nativeRegExpExecResultMap;
+ }
+
+ PropertyMap getStrictArgumentsMap() {
+ return nativeStrictArgumentsMap;
+ }
+
+ PropertyMap getStringMap() {
+ return nativeStringMap;
+ }
+
+ PropertyMap getSyntaxErrorMap() {
+ return nativeSyntaxErrorMap;
+ }
+
+ PropertyMap getTypeErrorMap() {
+ return nativeTypeErrorMap;
+ }
+
+ PropertyMap getURIErrorMap() {
+ return nativeURIErrorMap;
+ }
+
+ PropertyMap getPrototypeObjectMap() {
+ return prototypeObjectMap;
+ }
+
+ PropertyMap getObjectMap() {
+ return objectMap;
+ }
+
+ PropertyMap getFunctionMap() {
+ return functionMap;
+ }
+
+ PropertyMap getAnonymousFunctionMap() {
+ return anonymousFunctionMap;
+ }
+
+ PropertyMap getStrictFunctionMap() {
+ return strictFunctionMap;
+ }
+
+ PropertyMap getBoundFunctionMap() {
+ return boundFunctionMap;
+ }
+
private ScriptFunction getBuiltinArray() {
return builtinArray;
}
-
/**
* Called from compiled script code to test if builtin has been overridden
*
@@ -1394,7 +1538,11 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
private void init() {
assert Context.getGlobal() == this : "this global is not set as current";
- final ScriptEnvironment env = context.getEnv();
+ final ScriptEnvironment env = getContext().getEnv();
+
+ // duplicate PropertyMaps of Native* classes
+ copyInitialMaps(env);
+
// initialize Function and Object constructor
initFunctionAndObject();
@@ -1440,10 +1588,10 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
final ScriptObject arrayPrototype = getArrayPrototype();
arrayPrototype.addOwnProperty("length", Attribute.NOT_ENUMERABLE|Attribute.NOT_CONFIGURABLE, 0.0);
- this.DEFAULT_DATE = new NativeDate(Double.NaN);
+ this.DEFAULT_DATE = new NativeDate(Double.NaN, this);
// initialize default regexp object
- this.DEFAULT_REGEXP = new NativeRegExp("(?:)");
+ this.DEFAULT_REGEXP = new NativeRegExp("(?:)", this);
// RegExp.prototype should behave like a RegExp object. So copy the
// properties.
@@ -1454,12 +1602,16 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
initErrorObjects();
// java access
- initJavaAccess();
+ if (! env._no_java) {
+ initJavaAccess();
+ }
- initTypedArray();
+ if (! env._no_typed_arrays) {
+ initTypedArray();
+ }
if (env._scripting) {
- initScripting();
+ initScripting(env);
}
if (Context.DEBUG && System.getSecurityManager() == null) {
@@ -1540,7 +1692,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
this.builtinJavaApi = initConstructor("Java");
}
- private void initScripting() {
+ private void initScripting(final ScriptEnvironment scriptEnv) {
Object value;
value = ScriptFunctionImpl.makeFunction("readLine", ScriptingFunctions.READLINE);
addOwnProperty("readLine", Attribute.NOT_ENUMERABLE, value);
@@ -1559,7 +1711,6 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
// Nashorn extension: global.$OPTIONS (scripting-mode-only)
final ScriptObject options = newObject();
- final ScriptEnvironment scriptEnv = context.getEnv();
copyOptions(options, scriptEnv);
addOwnProperty("$OPTIONS", Attribute.NOT_ENUMERABLE, options);
@@ -1712,6 +1863,46 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
}
}
+ private void copyInitialMaps(final ScriptEnvironment env) {
+ this.accessorPropertyDescriptorMap = AccessorPropertyDescriptor.getInitialMap().duplicate();
+ this.dataPropertyDescriptorMap = DataPropertyDescriptor.getInitialMap().duplicate();
+ this.genericPropertyDescriptorMap = GenericPropertyDescriptor.getInitialMap().duplicate();
+ this.nativeArgumentsMap = NativeArguments.getInitialMap().duplicate();
+ this.nativeArrayMap = NativeArray.getInitialMap().duplicate();
+ this.nativeBooleanMap = NativeBoolean.getInitialMap().duplicate();
+ this.nativeDateMap = NativeDate.getInitialMap().duplicate();
+ this.nativeErrorMap = NativeError.getInitialMap().duplicate();
+ this.nativeEvalErrorMap = NativeEvalError.getInitialMap().duplicate();
+ this.nativeJSAdapterMap = NativeJSAdapter.getInitialMap().duplicate();
+ this.nativeNumberMap = NativeNumber.getInitialMap().duplicate();
+ this.nativeRangeErrorMap = NativeRangeError.getInitialMap().duplicate();
+ this.nativeReferenceErrorMap = NativeReferenceError.getInitialMap().duplicate();
+ this.nativeRegExpMap = NativeRegExp.getInitialMap().duplicate();
+ this.nativeRegExpExecResultMap = NativeRegExpExecResult.getInitialMap().duplicate();
+ this.nativeStrictArgumentsMap = NativeStrictArguments.getInitialMap().duplicate();
+ this.nativeStringMap = NativeString.getInitialMap().duplicate();
+ this.nativeSyntaxErrorMap = NativeSyntaxError.getInitialMap().duplicate();
+ this.nativeTypeErrorMap = NativeTypeError.getInitialMap().duplicate();
+ this.nativeURIErrorMap = NativeURIError.getInitialMap().duplicate();
+ this.prototypeObjectMap = PrototypeObject.getInitialMap().duplicate();
+ this.objectMap = JO.getInitialMap().duplicate();
+ this.functionMap = ScriptFunctionImpl.getInitialMap().duplicate();
+ this.anonymousFunctionMap = ScriptFunctionImpl.getInitialAnonymousMap().duplicate();
+ this.strictFunctionMap = ScriptFunctionImpl.getInitialStrictMap().duplicate();
+ this.boundFunctionMap = ScriptFunctionImpl.getInitialBoundMap().duplicate();
+
+ // java
+ if (! env._no_java) {
+ this.nativeJavaImporterMap = NativeJavaImporter.getInitialMap().duplicate();
+ }
+
+ // typed arrays
+ if (! env._no_typed_arrays) {
+ this.arrayBufferViewMap = ArrayBufferView.getInitialMap().duplicate();
+ this.nativeArrayBufferMap = NativeArrayBuffer.getInitialMap().duplicate();
+ }
+ }
+
// Function and Object constructors are inter-dependent. Also,
// Function.prototype
// functions are not properly initialized. We fix the references here.
@@ -1723,7 +1914,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
this.builtinFunction = (ScriptFunction)initConstructor("Function");
// create global anonymous function
- final ScriptFunction anon = ScriptFunctionImpl.newAnonymousFunction();
+ final ScriptFunction anon = ScriptFunctionImpl.newAnonymousFunction(this);
// need to copy over members of Function.prototype to anon function
anon.addBoundProperties(getFunctionPrototype());
@@ -1792,13 +1983,8 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
}
}
-
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
- try {
- return MethodHandles.lookup().findStatic(Global.class, name, MH.type(rtype, types));
- } catch (final NoSuchMethodException | IllegalAccessException e) {
- throw new MethodHandleFactory.LookupException(e);
- }
+ return MH.findStatic(MethodHandles.lookup(), Global.class, name, MH.type(rtype, types));
}
RegExpResult getLastRegExpResult() {
diff --git a/src/jdk/nashorn/internal/objects/NativeArguments.java b/src/jdk/nashorn/internal/objects/NativeArguments.java
index 456284d8..3bd74d52 100644
--- a/src/jdk/nashorn/internal/objects/NativeArguments.java
+++ b/src/jdk/nashorn/internal/objects/NativeArguments.java
@@ -31,8 +31,10 @@ import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
+import jdk.nashorn.internal.runtime.AccessorProperty;
import jdk.nashorn.internal.runtime.Property;
import jdk.nashorn.internal.runtime.PropertyDescriptor;
import jdk.nashorn.internal.runtime.PropertyMap;
@@ -41,8 +43,6 @@ import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
-import jdk.nashorn.internal.lookup.Lookup;
-import jdk.nashorn.internal.lookup.MethodHandleFactory;
/**
* ECMA 10.6 Arguments Object.
@@ -64,10 +64,14 @@ public final class NativeArguments extends ScriptObject {
private static final PropertyMap map$;
static {
- PropertyMap map = PropertyMap.newMap(NativeArguments.class);
- map = Lookup.newProperty(map, "length", Property.NOT_ENUMERABLE, G$LENGTH, S$LENGTH);
- map = Lookup.newProperty(map, "callee", Property.NOT_ENUMERABLE, G$CALLEE, S$CALLEE);
- map$ = map;
+ final ArrayList<Property> properties = new ArrayList<>(2);
+ properties.add(AccessorProperty.create("length", Property.NOT_ENUMERABLE, G$LENGTH, S$LENGTH));
+ properties.add(AccessorProperty.create("callee", Property.NOT_ENUMERABLE, G$CALLEE, S$CALLEE));
+ map$ = PropertyMap.newMap(properties).setIsShared();
+ }
+
+ static PropertyMap getInitialMap() {
+ return map$;
}
private Object length;
@@ -76,8 +80,8 @@ public final class NativeArguments extends ScriptObject {
// This is lazily initialized - only when delete is invoked at all
private BitSet deleted;
- NativeArguments(final ScriptObject proto, final Object[] arguments, final Object callee, final int numParams) {
- super(proto, map$);
+ NativeArguments(final Object[] arguments, final Object callee, final int numParams, final ScriptObject proto, final PropertyMap map) {
+ super(proto, map);
setIsArguments();
setArray(ArrayData.allocate(arguments));
@@ -550,8 +554,13 @@ public final class NativeArguments extends ScriptObject {
public static ScriptObject allocate(final Object[] arguments, final ScriptFunction callee, final int numParams) {
// Strict functions won't always have a callee for arguments, and will pass null instead.
final boolean isStrict = callee == null || callee.isStrict();
- final ScriptObject proto = Global.objectPrototype();
- return isStrict ? new NativeStrictArguments(proto, arguments, numParams) : new NativeArguments(proto, arguments, callee, numParams);
+ final Global global = Global.instance();
+ final ScriptObject proto = global.getObjectPrototype();
+ if (isStrict) {
+ return new NativeStrictArguments(arguments, numParams, proto, global.getStrictArgumentsMap());
+ } else {
+ return new NativeArguments(arguments, callee, numParams, proto, global.getArgumentsMap());
+ }
}
/**
@@ -623,11 +632,6 @@ public final class NativeArguments extends ScriptObject {
}
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
- try {
- return MethodHandles.lookup().findStatic(NativeArguments.class, name, MH.type(rtype, types));
- } catch (final NoSuchMethodException | IllegalAccessException e) {
- throw new MethodHandleFactory.LookupException(e);
- }
+ return MH.findStatic(MethodHandles.lookup(), NativeArguments.class, name, MH.type(rtype, types));
}
-
}
diff --git a/src/jdk/nashorn/internal/objects/NativeArray.java b/src/jdk/nashorn/internal/objects/NativeArray.java
index 1af79785..c1b64c78 100644
--- a/src/jdk/nashorn/internal/objects/NativeArray.java
+++ b/src/jdk/nashorn/internal/objects/NativeArray.java
@@ -86,6 +86,10 @@ public final class NativeArray extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
+ static PropertyMap getInitialMap() {
+ return $nasgenmap$;
+ }
+
/*
* Constructors.
*/
@@ -130,7 +134,11 @@ public final class NativeArray extends ScriptObject {
}
NativeArray(final ArrayData arrayData) {
- super(Global.instance().getArrayPrototype(), $nasgenmap$);
+ this(arrayData, Global.instance());
+ }
+
+ NativeArray(final ArrayData arrayData, final Global global) {
+ super(global.getArrayPrototype(), global.getArrayMap());
this.setArray(arrayData);
this.setIsArray();
}
@@ -544,35 +552,40 @@ public final class NativeArray extends ScriptObject {
@Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
public static Object concat(final Object self, final Object... args) {
final ArrayList<Object> list = new ArrayList<>();
- final Object selfToObject = Global.toObject(self);
+ concatToList(list, Global.toObject(self));
- if (isArray(selfToObject)) {
- final Iterator<Object> iter = arrayLikeIterator(selfToObject, true);
- while (iter.hasNext()) {
- list.add(iter.next());
- }
- } else {
- // single element, add it
- list.add(selfToObject);
+ for (final Object obj : args) {
+ concatToList(list, obj);
}
- for (final Object obj : args) {
- if (isArray(obj) || obj instanceof Iterable || (obj != null && obj.getClass().isArray())) {
- final Iterator<Object> iter = arrayLikeIterator(obj, true);
- if (iter.hasNext()) {
- while (iter.hasNext()) {
- list.add(iter.next());
+ return new NativeArray(list.toArray());
+ }
+
+ private static void concatToList(final ArrayList<Object> list, final Object obj) {
+ final boolean isScriptArray = isArray(obj);
+ final boolean isScriptObject = isScriptArray || obj instanceof ScriptObject;
+ if (isScriptArray || obj instanceof Iterable || (obj != null && obj.getClass().isArray())) {
+ final Iterator<Object> iter = arrayLikeIterator(obj, true);
+ if (iter.hasNext()) {
+ for(int i = 0; iter.hasNext(); ++i) {
+ final Object value = iter.next();
+ if(value == ScriptRuntime.UNDEFINED && isScriptObject && !((ScriptObject)obj).has(i)) {
+ // TODO: eventually rewrite arrayLikeIterator to use a three-state enum for handling
+ // UNDEFINED instead of an "includeUndefined" boolean with states SKIP, INCLUDE,
+ // RETURN_EMPTY. Until then, this is how we'll make sure that empty elements don't make it
+ // into the concatenated array.
+ list.add(ScriptRuntime.EMPTY);
+ } else {
+ list.add(value);
}
- } else if (!isArray(obj)) {
- list.add(obj); // add empty object, but not an empty array
}
- } else {
- // single element, add it
- list.add(obj);
+ } else if (!isScriptArray) {
+ list.add(obj); // add empty object, but not an empty array
}
+ } else {
+ // single element, add it
+ list.add(obj);
}
-
- return new NativeArray(list.toArray());
}
/**
diff --git a/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java b/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java
index f122bfca..356e7b6c 100644
--- a/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java
+++ b/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java
@@ -43,6 +43,10 @@ final class NativeArrayBuffer extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
+ static PropertyMap getInitialMap() {
+ return $nasgenmap$;
+ }
+
@Constructor(arity = 1)
public static Object constructor(final boolean newObj, final Object self, final Object... args) {
if (args.length == 0) {
@@ -52,11 +56,15 @@ final class NativeArrayBuffer extends ScriptObject {
return new NativeArrayBuffer(JSType.toInt32(args[0]));
}
- protected NativeArrayBuffer(final byte[] byteArray) {
- super(Global.instance().getArrayBufferPrototype(), $nasgenmap$);
+ protected NativeArrayBuffer(final byte[] byteArray, final Global global) {
+ super(global.getArrayBufferPrototype(), global.getArrayBufferMap());
this.buffer = byteArray;
}
+ protected NativeArrayBuffer(final byte[] byteArray) {
+ this(byteArray, Global.instance());
+ }
+
protected NativeArrayBuffer(final int byteLength) {
this(new byte[byteLength]);
}
diff --git a/src/jdk/nashorn/internal/objects/NativeBoolean.java b/src/jdk/nashorn/internal/objects/NativeBoolean.java
index bfbbb3d7..bb57cc71 100644
--- a/src/jdk/nashorn/internal/objects/NativeBoolean.java
+++ b/src/jdk/nashorn/internal/objects/NativeBoolean.java
@@ -40,7 +40,6 @@ import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
-import jdk.nashorn.internal.lookup.MethodHandleFactory;
import jdk.nashorn.internal.runtime.linker.PrimitiveLookup;
/**
@@ -56,15 +55,23 @@ public final class NativeBoolean extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- NativeBoolean(final boolean value) {
- this(value, Global.instance().getBooleanPrototype());
+ static PropertyMap getInitialMap() {
+ return $nasgenmap$;
}
- private NativeBoolean(final boolean value, final ScriptObject proto) {
- super(proto, $nasgenmap$);
+ private NativeBoolean(final boolean value, final ScriptObject proto, final PropertyMap map) {
+ super(proto, map);
this.value = value;
}
+ NativeBoolean(final boolean flag, final Global global) {
+ this(flag, global.getBooleanPrototype(), global.getBooleanMap());
+ }
+
+ NativeBoolean(final boolean flag) {
+ this(flag, Global.instance());
+ }
+
@Override
public String safeToString() {
return "[Boolean " + toString() + "]";
@@ -131,11 +138,7 @@ public final class NativeBoolean extends ScriptObject {
final boolean flag = JSType.toBoolean(value);
if (newObj) {
- final ScriptObject proto = (self instanceof ScriptObject) ?
- ((ScriptObject)self).getProto() :
- Global.instance().getBooleanPrototype();
-
- return new NativeBoolean(flag, proto);
+ return new NativeBoolean(flag);
}
return flag;
@@ -176,10 +179,6 @@ public final class NativeBoolean extends ScriptObject {
}
private static MethodHandle findWrapFilter() {
- try {
- return MethodHandles.lookup().findStatic(NativeBoolean.class, "wrapFilter", MH.type(NativeBoolean.class, Object.class));
- } catch (NoSuchMethodException | IllegalAccessException e) {
- throw new MethodHandleFactory.LookupException(e);
- }
+ return MH.findStatic(MethodHandles.lookup(), NativeBoolean.class, "wrapFilter", MH.type(NativeBoolean.class, Object.class));
}
}
diff --git a/src/jdk/nashorn/internal/objects/NativeDate.java b/src/jdk/nashorn/internal/objects/NativeDate.java
index 3a7d0ef3..11ab886e 100644
--- a/src/jdk/nashorn/internal/objects/NativeDate.java
+++ b/src/jdk/nashorn/internal/objects/NativeDate.java
@@ -104,18 +104,30 @@ public final class NativeDate extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- NativeDate() {
- this(System.currentTimeMillis());
+ static PropertyMap getInitialMap() {
+ return $nasgenmap$;
}
- NativeDate(final double time) {
- super(Global.instance().getDatePrototype(), $nasgenmap$);
+ private NativeDate(final double time, final ScriptObject proto, final PropertyMap map) {
+ super(proto, map);
final ScriptEnvironment env = Global.getEnv();
this.time = time;
this.timezone = env._timezone;
}
+ NativeDate(final double time, final Global global) {
+ this(time, global.getDatePrototype(), global.getDateMap());
+ }
+
+ private NativeDate (final double time) {
+ this(time, Global.instance());
+ }
+
+ private NativeDate() {
+ this(System.currentTimeMillis());
+ }
+
@Override
public String getClassName() {
return "Date";
@@ -153,6 +165,10 @@ public final class NativeDate extends ScriptObject {
*/
@Constructor(arity = 7)
public static Object construct(final boolean isNew, final Object self, final Object... args) {
+ if (! isNew) {
+ return toStringImpl(new NativeDate(), FORMAT_DATE_TIME);
+ }
+
NativeDate result;
switch (args.length) {
case 0:
@@ -182,7 +198,7 @@ public final class NativeDate extends ScriptObject {
break;
}
- return isNew ? result : toStringImpl(new NativeDate(), FORMAT_DATE_TIME);
+ return result;
}
@Override
diff --git a/src/jdk/nashorn/internal/objects/NativeDebug.java b/src/jdk/nashorn/internal/objects/NativeDebug.java
index afcf7b2b..82757cba 100644
--- a/src/jdk/nashorn/internal/objects/NativeDebug.java
+++ b/src/jdk/nashorn/internal/objects/NativeDebug.java
@@ -49,10 +49,12 @@ import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
public final class NativeDebug extends ScriptObject {
// initialized by nasgen
+ @SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
- NativeDebug() {
- super(Global.objectPrototype(), $nasgenmap$);
+ private NativeDebug() {
+ // don't create me!
+ throw new UnsupportedOperationException();
}
@Override
@@ -143,7 +145,7 @@ public final class NativeDebug extends ScriptObject {
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
public static Object equals(final Object self, final Object obj1, final Object obj2) {
- return (obj1 != null) ? obj1.equals(obj2) : false;
+ return Objects.equals(obj1, obj2);
}
/**
@@ -176,6 +178,18 @@ public final class NativeDebug extends ScriptObject {
}
/**
+ * Returns the property listener count for a script object
+ *
+ * @param self self reference
+ * @param obj script object whose listener count is returned
+ * @return listener count
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+ public static Object getListenerCount(final Object self, final Object obj) {
+ return (obj instanceof ScriptObject)? ((ScriptObject)obj).getListenerCount() : 0;
+ }
+
+ /**
* Dump all Nashorn debug mode counters. Calling this may be better if
* you want to print all counters. This way you can avoid too many callsites
* due to counter access itself!!
@@ -196,6 +210,8 @@ public final class NativeDebug extends ScriptObject {
out.println("ScriptFunction allocations " + ScriptFunction.getAllocations());
out.println("PropertyMap count " + PropertyMap.getCount());
out.println("PropertyMap cloned " + PropertyMap.getClonedCount());
+ out.println("PropertyMap shared " + PropertyMap.getSharedCount());
+ out.println("PropertyMap duplicated " + PropertyMap.getDuplicatedCount());
out.println("PropertyMap history hit " + PropertyMap.getHistoryHit());
out.println("PropertyMap proto invalidations " + PropertyMap.getProtoInvalidations());
out.println("PropertyMap proto history hit " + PropertyMap.getProtoHistoryHit());
diff --git a/src/jdk/nashorn/internal/objects/NativeError.java b/src/jdk/nashorn/internal/objects/NativeError.java
index 07f5d65a..dc6aef90 100644
--- a/src/jdk/nashorn/internal/objects/NativeError.java
+++ b/src/jdk/nashorn/internal/objects/NativeError.java
@@ -31,7 +31,6 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import jdk.nashorn.api.scripting.NashornException;
-import jdk.nashorn.internal.lookup.MethodHandleFactory;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
@@ -87,8 +86,12 @@ public final class NativeError extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- NativeError(final Object msg) {
- super(Global.instance().getErrorPrototype(), $nasgenmap$);
+ static PropertyMap getInitialMap() {
+ return $nasgenmap$;
+ }
+
+ private NativeError(final Object msg, final ScriptObject proto, final PropertyMap map) {
+ super(proto, map);
if (msg != UNDEFINED) {
this.instMessage = JSType.toString(msg);
} else {
@@ -96,6 +99,14 @@ public final class NativeError extends ScriptObject {
}
}
+ NativeError(final Object msg, final Global global) {
+ this(msg, global.getErrorPrototype(), global.getErrorMap());
+ }
+
+ private NativeError(final Object msg) {
+ this(msg, Global.instance());
+ }
+
@Override
public String getClassName() {
return "Error";
@@ -119,6 +130,7 @@ public final class NativeError extends ScriptObject {
* Nashorn extension: Error.captureStackTrace. Capture stack trace at the point of call into the Error object provided.
*
* @param self self reference
+ * @param errorObj the error object
* @return undefined
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
@@ -286,9 +298,9 @@ public final class NativeError extends ScriptObject {
final Object exception = ECMAException.getException(sobj);
if (exception instanceof Throwable) {
return getScriptStackString(sobj, (Throwable)exception);
- } else {
- return "";
}
+
+ return "";
}
/**
@@ -353,11 +365,7 @@ public final class NativeError extends ScriptObject {
}
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
- try {
- return MethodHandles.lookup().findStatic(NativeError.class, name, MH.type(rtype, types));
- } catch (final NoSuchMethodException | IllegalAccessException e) {
- throw new MethodHandleFactory.LookupException(e);
- }
+ return MH.findStatic(MethodHandles.lookup(), NativeError.class, name, MH.type(rtype, types));
}
private static String getScriptStackString(final ScriptObject sobj, final Throwable exp) {
diff --git a/src/jdk/nashorn/internal/objects/NativeEvalError.java b/src/jdk/nashorn/internal/objects/NativeEvalError.java
index 2b88f7dc..89e9485f 100644
--- a/src/jdk/nashorn/internal/objects/NativeEvalError.java
+++ b/src/jdk/nashorn/internal/objects/NativeEvalError.java
@@ -58,8 +58,12 @@ public final class NativeEvalError extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- NativeEvalError(final Object msg) {
- super(Global.instance().getEvalErrorPrototype(), $nasgenmap$);
+ static PropertyMap getInitialMap() {
+ return $nasgenmap$;
+ }
+
+ private NativeEvalError(final Object msg, final ScriptObject proto, final PropertyMap map) {
+ super(proto, map);
if (msg != UNDEFINED) {
this.instMessage = JSType.toString(msg);
} else {
@@ -67,12 +71,19 @@ public final class NativeEvalError extends ScriptObject {
}
}
+ NativeEvalError(final Object msg, final Global global) {
+ this(msg, global.getEvalErrorPrototype(), global.getEvalErrorMap());
+ }
+
+ private NativeEvalError(final Object msg) {
+ this(msg, Global.instance());
+ }
+
@Override
public String getClassName() {
return "Error";
}
-
/**
* ECMA 15.11.6.1 EvalError
*
diff --git a/src/jdk/nashorn/internal/objects/NativeFloat32Array.java b/src/jdk/nashorn/internal/objects/NativeFloat32Array.java
index beb7d50e..614fd6f5 100644
--- a/src/jdk/nashorn/internal/objects/NativeFloat32Array.java
+++ b/src/jdk/nashorn/internal/objects/NativeFloat32Array.java
@@ -48,6 +48,7 @@ public final class NativeFloat32Array extends ArrayBufferView {
public static final int BYTES_PER_ELEMENT = 4;
// initialized by nasgen
+ @SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {
@@ -191,7 +192,7 @@ public final class NativeFloat32Array extends ArrayBufferView {
}
@Override
- protected ScriptObject getPrototype() {
- return Global.instance().getFloat32ArrayPrototype();
+ protected ScriptObject getPrototype(final Global global) {
+ return global.getFloat32ArrayPrototype();
}
}
diff --git a/src/jdk/nashorn/internal/objects/NativeFloat64Array.java b/src/jdk/nashorn/internal/objects/NativeFloat64Array.java
index 3451e315..22467bcc 100644
--- a/src/jdk/nashorn/internal/objects/NativeFloat64Array.java
+++ b/src/jdk/nashorn/internal/objects/NativeFloat64Array.java
@@ -48,6 +48,7 @@ public final class NativeFloat64Array extends ArrayBufferView {
public static final int BYTES_PER_ELEMENT = 8;
// initialized by nasgen
+ @SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {
@@ -201,7 +202,7 @@ public final class NativeFloat64Array extends ArrayBufferView {
}
@Override
- protected ScriptObject getPrototype() {
- return Global.instance().getFloat64ArrayPrototype();
+ protected ScriptObject getPrototype(final Global global) {
+ return global.getFloat64ArrayPrototype();
}
}
diff --git a/src/jdk/nashorn/internal/objects/NativeFunction.java b/src/jdk/nashorn/internal/objects/NativeFunction.java
index 7df1b521..c208a35c 100644
--- a/src/jdk/nashorn/internal/objects/NativeFunction.java
+++ b/src/jdk/nashorn/internal/objects/NativeFunction.java
@@ -29,6 +29,7 @@ import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.util.List;
+
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
@@ -55,10 +56,12 @@ import jdk.nashorn.internal.runtime.Source;
public final class NativeFunction {
// initialized by nasgen
+ @SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
// do *not* create me!
private NativeFunction() {
+ throw new UnsupportedOperationException();
}
/**
diff --git a/src/jdk/nashorn/internal/objects/NativeInt16Array.java b/src/jdk/nashorn/internal/objects/NativeInt16Array.java
index d05c69d7..904dbce0 100644
--- a/src/jdk/nashorn/internal/objects/NativeInt16Array.java
+++ b/src/jdk/nashorn/internal/objects/NativeInt16Array.java
@@ -42,6 +42,7 @@ import jdk.nashorn.internal.runtime.arrays.ArrayData;
public final class NativeInt16Array extends ArrayBufferView {
// initialized by nasgen
+ @SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
/**
@@ -150,7 +151,7 @@ public final class NativeInt16Array extends ArrayBufferView {
}
@Override
- protected ScriptObject getPrototype() {
- return Global.instance().getInt16ArrayPrototype();
+ protected ScriptObject getPrototype(final Global global) {
+ return global.getInt16ArrayPrototype();
}
}
diff --git a/src/jdk/nashorn/internal/objects/NativeInt32Array.java b/src/jdk/nashorn/internal/objects/NativeInt32Array.java
index 596b935c..78aed11f 100644
--- a/src/jdk/nashorn/internal/objects/NativeInt32Array.java
+++ b/src/jdk/nashorn/internal/objects/NativeInt32Array.java
@@ -47,6 +47,7 @@ public final class NativeInt32Array extends ArrayBufferView {
public static final int BYTES_PER_ELEMENT = 4;
// initialized by nasgen
+ @SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {
@@ -153,7 +154,7 @@ public final class NativeInt32Array extends ArrayBufferView {
}
@Override
- protected ScriptObject getPrototype() {
- return Global.instance().getInt32ArrayPrototype();
+ protected ScriptObject getPrototype(final Global global) {
+ return global.getInt32ArrayPrototype();
}
}
diff --git a/src/jdk/nashorn/internal/objects/NativeInt8Array.java b/src/jdk/nashorn/internal/objects/NativeInt8Array.java
index f1a9b7f7..3ed5688a 100644
--- a/src/jdk/nashorn/internal/objects/NativeInt8Array.java
+++ b/src/jdk/nashorn/internal/objects/NativeInt8Array.java
@@ -47,6 +47,7 @@ public final class NativeInt8Array extends ArrayBufferView {
public static final int BYTES_PER_ELEMENT = 1;
// initialized by nasgen
+ @SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {
@@ -143,7 +144,7 @@ public final class NativeInt8Array extends ArrayBufferView {
}
@Override
- protected ScriptObject getPrototype() {
- return Global.instance().getInt8ArrayPrototype();
+ protected ScriptObject getPrototype(final Global global) {
+ return global.getInt8ArrayPrototype();
}
}
diff --git a/src/jdk/nashorn/internal/objects/NativeJSAdapter.java b/src/jdk/nashorn/internal/objects/NativeJSAdapter.java
index 5db4a1fd..5b89e2ca 100644
--- a/src/jdk/nashorn/internal/objects/NativeJSAdapter.java
+++ b/src/jdk/nashorn/internal/objects/NativeJSAdapter.java
@@ -48,7 +48,7 @@ import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
import jdk.nashorn.internal.lookup.Lookup;
-import jdk.nashorn.internal.lookup.MethodHandleFactory;
+import jdk.nashorn.internal.scripts.JO;
/**
* This class is the implementation of the Nashorn-specific global object named {@code JSAdapter}. It can be
@@ -146,8 +146,12 @@ public final class NativeJSAdapter extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- NativeJSAdapter(final ScriptObject proto, final Object overrides, final ScriptObject adaptee) {
- super(proto, $nasgenmap$);
+ static PropertyMap getInitialMap() {
+ return $nasgenmap$;
+ }
+
+ NativeJSAdapter(final Object overrides, final ScriptObject adaptee, final ScriptObject proto, final PropertyMap map) {
+ super(proto, map);
this.adaptee = wrapAdaptee(adaptee);
if (overrides instanceof ScriptObject) {
this.overrides = true;
@@ -159,9 +163,7 @@ public final class NativeJSAdapter extends ScriptObject {
}
private static ScriptObject wrapAdaptee(final ScriptObject adaptee) {
- final ScriptObject sobj = new jdk.nashorn.internal.scripts.JO();
- sobj.setProto(adaptee);
- return sobj;
+ return new JO(adaptee, Global.instance().getObjectMap());
}
@Override
@@ -570,11 +572,12 @@ public final class NativeJSAdapter extends ScriptObject {
throw typeError("not.an.object", ScriptRuntime.safeToString(adaptee));
}
+ final Global global = Global.instance();
if (proto != null && !(proto instanceof ScriptObject)) {
- proto = Global.instance().getJSAdapterPrototype();
+ proto = global.getJSAdapterPrototype();
}
- return new NativeJSAdapter((ScriptObject)proto, overrides, (ScriptObject)adaptee);
+ return new NativeJSAdapter(overrides, (ScriptObject)adaptee, (ScriptObject)proto, global.getJSAdapterMap());
}
@Override
@@ -619,12 +622,15 @@ public final class NativeJSAdapter extends ScriptObject {
case "getMethod":
final FindProperty find = adaptee.findProperty(__call__, true);
if (find != null) {
- final ScriptFunctionImpl func = (ScriptFunctionImpl)getObjectValue(find);
- // TODO: It's a shame we need to produce a function bound to this and name, when we'd only need it bound
- // to name. Probably not a big deal, but if we can ever make it leaner, it'd be nice.
- return new GuardedInvocation(MH.dropArguments(MH.constant(Object.class,
- func.makeBoundFunction(this, new Object[] { name })), 0, Object.class),
- adaptee.getMap().getProtoGetSwitchPoint(adaptee.getProto(), __call__), testJSAdaptor(adaptee, null, null, null));
+ final Object value = getObjectValue(find);
+ if (value instanceof ScriptFunction) {
+ final ScriptFunctionImpl func = (ScriptFunctionImpl)value;
+ // TODO: It's a shame we need to produce a function bound to this and name, when we'd only need it bound
+ // to name. Probably not a big deal, but if we can ever make it leaner, it'd be nice.
+ return new GuardedInvocation(MH.dropArguments(MH.constant(Object.class,
+ func.makeBoundFunction(this, new Object[] { name })), 0, Object.class),
+ adaptee.getMap().getProtoGetSwitchPoint(adaptee.getProto(), __call__), testJSAdaptor(adaptee, null, null, null));
+ }
}
throw typeError("no.such.function", desc.getNameToken(2), ScriptRuntime.safeToString(this));
default:
@@ -684,16 +690,19 @@ public final class NativeJSAdapter extends ScriptObject {
final MethodType type = desc.getMethodType();
if (findData != null) {
final String name = desc.getNameTokenCount() > 2 ? desc.getNameToken(2) : null;
- final ScriptFunction func = (ScriptFunction)getObjectValue(findData);
+ final Object value = getObjectValue(findData);
+ if (value instanceof ScriptFunction) {
+ final ScriptFunction func = (ScriptFunction)value;
- final MethodHandle methodHandle = getCallMethodHandle(findData, type,
+ final MethodHandle methodHandle = getCallMethodHandle(findData, type,
useName ? name : null);
- if (methodHandle != null) {
- return new GuardedInvocation(
- methodHandle,
- adaptee.getMap().getProtoGetSwitchPoint(adaptee.getProto(), hook),
- testJSAdaptor(adaptee, findData.getGetter(Object.class), findData.getOwner(), func));
- }
+ if (methodHandle != null) {
+ return new GuardedInvocation(
+ methodHandle,
+ adaptee.getMap().getProtoGetSwitchPoint(adaptee.getProto(), hook),
+ testJSAdaptor(adaptee, findData.getGetter(Object.class), findData.getOwner(), func));
+ }
+ }
}
switch (hook) {
@@ -736,10 +745,6 @@ public final class NativeJSAdapter extends ScriptObject {
}
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
- try {
- return MethodHandles.lookup().findStatic(NativeJSAdapter.class, name, MH.type(rtype, types));
- } catch (final NoSuchMethodException | IllegalAccessException e) {
- throw new MethodHandleFactory.LookupException(e);
- }
+ return MH.findStatic(MethodHandles.lookup(), NativeJSAdapter.class, name, MH.type(rtype, types));
}
}
diff --git a/src/jdk/nashorn/internal/objects/NativeJSON.java b/src/jdk/nashorn/internal/objects/NativeJSON.java
index 3270bc84..863d531b 100644
--- a/src/jdk/nashorn/internal/objects/NativeJSON.java
+++ b/src/jdk/nashorn/internal/objects/NativeJSON.java
@@ -60,10 +60,12 @@ public final class NativeJSON extends ScriptObject {
ScriptFunction.class, ScriptObject.class, Object.class, Object.class);
// initialized by nasgen
+ @SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
- NativeJSON() {
- super(Global.objectPrototype(), $nasgenmap$);
+ private NativeJSON() {
+ // don't create me!!
+ throw new UnsupportedOperationException();
}
/**
diff --git a/src/jdk/nashorn/internal/objects/NativeJava.java b/src/jdk/nashorn/internal/objects/NativeJava.java
index 7a9ec38f..be63e531 100644
--- a/src/jdk/nashorn/internal/objects/NativeJava.java
+++ b/src/jdk/nashorn/internal/objects/NativeJava.java
@@ -32,12 +32,14 @@ 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;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.Where;
+import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ListAdapter;
import jdk.nashorn.internal.runtime.PropertyMap;
@@ -54,9 +56,12 @@ import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory;
public final class NativeJava {
// initialized by nasgen
+ @SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
private NativeJava() {
+ // don't create me
+ throw new UnsupportedOperationException();
}
/**
@@ -103,12 +108,22 @@ public final class NativeJava {
* var anArrayList = new ArrayList
* var anArrayListWithSize = new ArrayList(16)
* </pre>
- * In the special case of inner classes, you need to use the JVM fully qualified name, meaning using {@code $} sign
- * in the class name:
+ * In the special case of inner classes, you can either use the JVM fully qualified name, meaning using {@code $}
+ * sign in the class name, or you can use the dot:
* <pre>
* var ftype = Java.type("java.awt.geom.Arc2D$Float")
* </pre>
- * However, once you retrieved the outer class, you can access the inner class as a property on it:
+ * and
+ * <pre>
+ * var ftype = Java.type("java.awt.geom.Arc2D.Float")
+ * </pre>
+ * both work. Note however that using the dollar sign is faster, as Java.type first tries to resolve the class name
+ * as it is originally specified, and the internal JVM names for inner classes use the dollar sign. If you use the
+ * dot, Java.type will internally get a ClassNotFoundException and subsequently retry by changing the last dot to
+ * dollar sign. As a matter of fact, it'll keep replacing dots with dollar signs until it either successfully loads
+ * the class or runs out of all dots in the name. This way it can correctly resolve and load even multiply nested
+ * inner classes with the dot notation. Again, this will be slower than using the dollar signs in the name. An
+ * alternative way to access the inner class is as a property of the outer class:
* <pre>
* var arctype = Java.type("java.awt.geom.Arc2D")
* var ftype = arctype.Float
@@ -388,7 +403,33 @@ public final class NativeJava {
private static Class<?> simpleType(final String typeName) throws ClassNotFoundException {
final Class<?> primClass = TypeUtilities.getPrimitiveTypeByName(typeName);
- return primClass != null ? primClass : Global.getThisContext().findClass(typeName);
+ if(primClass != null) {
+ return primClass;
+ }
+ final Context ctx = Global.getThisContext();
+ try {
+ return ctx.findClass(typeName);
+ } catch(ClassNotFoundException e) {
+ // The logic below compensates for a frequent user error - when people use dot notation to separate inner
+ // class names, i.e. "java.lang.Character.UnicodeBlock" vs."java.lang.Character$UnicodeBlock". The logic
+ // below will try alternative class names, replacing dots at the end of the name with dollar signs.
+ final StringBuilder nextName = new StringBuilder(typeName);
+ int lastDot = nextName.length();
+ for(;;) {
+ lastDot = nextName.lastIndexOf(".", lastDot - 1);
+ if(lastDot == -1) {
+ // Exhausted the search space, class not found - rethrow the original exception.
+ throw e;
+ }
+ nextName.setCharAt(lastDot, '$');
+ try {
+ return ctx.findClass(nextName.toString());
+ } catch(ClassNotFoundException cnfe) {
+ // Intentionally ignored, so the loop retries with the next name
+ }
+ }
+ }
+
}
private static Class<?> arrayType(final String typeName) throws ClassNotFoundException {
diff --git a/src/jdk/nashorn/internal/objects/NativeJavaImporter.java b/src/jdk/nashorn/internal/objects/NativeJavaImporter.java
index 9d4c15ac..c2d2bd10 100644
--- a/src/jdk/nashorn/internal/objects/NativeJavaImporter.java
+++ b/src/jdk/nashorn/internal/objects/NativeJavaImporter.java
@@ -59,11 +59,23 @@ public final class NativeJavaImporter extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- NativeJavaImporter(final Object[] args) {
- super(Global.instance().getJavaImporterPrototype(), $nasgenmap$);
+ static PropertyMap getInitialMap() {
+ return $nasgenmap$;
+ }
+
+ private NativeJavaImporter(final Object[] args, final ScriptObject proto, final PropertyMap map) {
+ super(proto, map);
this.args = args;
}
+ private NativeJavaImporter(final Object[] args, final Global global) {
+ this(args, global.getJavaImporterPrototype(), global.getJavaImporterMap());
+ }
+
+ private NativeJavaImporter(final Object[] args) {
+ this(args, Global.instance());
+ }
+
@Override
public String getClassName() {
return "JavaImporter";
diff --git a/src/jdk/nashorn/internal/objects/NativeMath.java b/src/jdk/nashorn/internal/objects/NativeMath.java
index 2b093548..cc50fbb4 100644
--- a/src/jdk/nashorn/internal/objects/NativeMath.java
+++ b/src/jdk/nashorn/internal/objects/NativeMath.java
@@ -43,10 +43,12 @@ import jdk.nashorn.internal.runtime.ScriptObject;
public final class NativeMath extends ScriptObject {
// initialized by nasgen
+ @SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
- NativeMath() {
- super(Global.objectPrototype(), $nasgenmap$);
+ private NativeMath() {
+ // don't create me!
+ throw new UnsupportedOperationException();
}
/** ECMA 15.8.1.1 - E, always a double constant. Not writable or configurable */
diff --git a/src/jdk/nashorn/internal/objects/NativeNumber.java b/src/jdk/nashorn/internal/objects/NativeNumber.java
index 94a7cca1..d9d568b7 100644
--- a/src/jdk/nashorn/internal/objects/NativeNumber.java
+++ b/src/jdk/nashorn/internal/objects/NativeNumber.java
@@ -48,7 +48,6 @@ import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
-import jdk.nashorn.internal.lookup.MethodHandleFactory;
import jdk.nashorn.internal.runtime.linker.PrimitiveLookup;
/**
@@ -87,17 +86,26 @@ public final class NativeNumber extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- NativeNumber(final double value) {
- this(value, Global.instance().getNumberPrototype());
+ static PropertyMap getInitialMap() {
+ return $nasgenmap$;
}
- private NativeNumber(final double value, final ScriptObject proto) {
- super(proto, $nasgenmap$);
+ private NativeNumber(final double value, final ScriptObject proto, final PropertyMap map) {
+ super(proto, map);
this.value = value;
this.isInt = isRepresentableAsInt(value);
this.isLong = isRepresentableAsLong(value);
}
+ NativeNumber(final double value, final Global global) {
+ this(value, global.getNumberPrototype(), global.getNumberMap());
+ }
+
+ private NativeNumber(final double value) {
+ this(value, Global.instance());
+ }
+
+
@Override
public String safeToString() {
return "[Number " + toString() + "]";
@@ -165,16 +173,7 @@ public final class NativeNumber extends ScriptObject {
public static Object constructor(final boolean newObj, final Object self, final Object... args) {
final double num = (args.length > 0) ? JSType.toNumber(args[0]) : 0.0;
- if (newObj) {
- final ScriptObject proto =
- (self instanceof ScriptObject) ?
- ((ScriptObject)self).getProto() :
- Global.instance().getNumberPrototype();
-
- return new NativeNumber(num, proto);
- }
-
- return num;
+ return newObj? new NativeNumber(num) : num;
}
/**
@@ -380,10 +379,6 @@ public final class NativeNumber extends ScriptObject {
}
private static MethodHandle findWrapFilter() {
- try {
- return MethodHandles.lookup().findStatic(NativeNumber.class, "wrapFilter", MH.type(NativeNumber.class, Object.class));
- } catch (final NoSuchMethodException | IllegalAccessException e) {
- throw new MethodHandleFactory.LookupException(e);
- }
+ return MH.findStatic(MethodHandles.lookup(), NativeNumber.class, "wrapFilter", MH.type(NativeNumber.class, Object.class));
}
}
diff --git a/src/jdk/nashorn/internal/objects/NativeObject.java b/src/jdk/nashorn/internal/objects/NativeObject.java
index 10340345..b392c662 100644
--- a/src/jdk/nashorn/internal/objects/NativeObject.java
+++ b/src/jdk/nashorn/internal/objects/NativeObject.java
@@ -28,18 +28,37 @@ package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import jdk.internal.dynalink.beans.BeansLinker;
+import jdk.internal.dynalink.beans.StaticClass;
+import jdk.internal.dynalink.linker.GuardedInvocation;
+import jdk.internal.dynalink.linker.GuardingDynamicLinker;
+import jdk.internal.dynalink.linker.LinkRequest;
+import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
+import jdk.internal.dynalink.support.LinkRequestImpl;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
+import jdk.nashorn.internal.lookup.Lookup;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.Where;
+import jdk.nashorn.internal.runtime.AccessorProperty;
import jdk.nashorn.internal.runtime.ECMAException;
import jdk.nashorn.internal.runtime.JSType;
+import jdk.nashorn.internal.runtime.Property;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
+import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.InvokeByName;
/**
@@ -53,11 +72,16 @@ import jdk.nashorn.internal.runtime.linker.InvokeByName;
@ScriptClass("Object")
public final class NativeObject {
private static final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class);
+ private static final MethodType MIRROR_GETTER_TYPE = MethodType.methodType(Object.class, ScriptObjectMirror.class);
+ private static final MethodType MIRROR_SETTER_TYPE = MethodType.methodType(Object.class, ScriptObjectMirror.class, Object.class);
// initialized by nasgen
+ @SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
private NativeObject() {
+ // don't create me!
+ throw new UnsupportedOperationException();
}
private static ECMAException notAnObject(final Object obj) {
@@ -469,4 +493,192 @@ public final class NativeObject {
return false;
}
+
+ /**
+ * Nashorn extension: Object.bindProperties
+ *
+ * Binds the source object's properties to the target object. Binding
+ * properties allows two-way read/write for the properties of the source object.
+ *
+ * Example:
+ * <pre>
+ * var obj = { x: 34, y: 100 };
+ * var foo = {}
+ *
+ * // bind properties of "obj" to "foo" object
+ * Object.bindProperties(foo, obj);
+ *
+ * // now, we can access/write on 'foo' properties
+ * print(foo.x); // prints obj.x which is 34
+ *
+ * // update obj.x via foo.x
+ * foo.x = "hello";
+ * print(obj.x); // prints "hello" now
+ *
+ * obj.x = 42; // foo.x also becomes 42
+ * print(foo.x); // prints 42
+ * </pre>
+ * <p>
+ * The source object bound can be a ScriptObject or a ScriptOjectMirror.
+ * null or undefined source object results in TypeError being thrown.
+ * </p>
+ * Example:
+ * <pre>
+ * var obj = loadWithNewGlobal({
+ * name: "test",
+ * script: "obj = { x: 33, y: 'hello' }"
+ * });
+ *
+ * // bind 'obj's properties to global scope 'this'
+ * Object.bindProperties(this, obj);
+ * print(x); // prints 33
+ * print(y); // prints "hello"
+ * x = Math.PI; // changes obj.x to Math.PI
+ * print(obj.x); // prints Math.PI
+ * </pre>
+ *
+ * Limitations of property binding:
+ * <ul>
+ * <li> Only enumerable, immediate (not proto inherited) properties of the source object are bound.
+ * <li> If the target object already contains a property called "foo", the source's "foo" is skipped (not bound).
+ * <li> Properties added to the source object after binding to the target are not bound.
+ * <li> Property configuration changes on the source object (or on the target) is not propagated.
+ * <li> Delete of property on the target (or the source) is not propagated -
+ * only the property value is set to 'undefined' if the property happens to be a data property.
+ * </ul>
+ * <p>
+ * It is recommended that the bound properties be treated as non-configurable
+ * properties to avoid surprises.
+ * </p>
+ *
+ * @param self self reference
+ * @param target the target object to which the source object's properties are bound
+ * @param source the source object whose properties are bound to the target
+ * @return the target object after property binding
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+ public static Object bindProperties(final Object self, final Object target, final Object source) {
+ // target object has to be a ScriptObject
+ Global.checkObject(target);
+ // check null or undefined source object
+ Global.checkObjectCoercible(source);
+
+ final ScriptObject targetObj = (ScriptObject)target;
+
+ if (source instanceof ScriptObject) {
+ final ScriptObject sourceObj = (ScriptObject)source;
+ final Property[] properties = sourceObj.getMap().getProperties();
+
+ // filter non-enumerable properties
+ final ArrayList<Property> propList = new ArrayList<>();
+ for (Property prop : properties) {
+ if (prop.isEnumerable()) {
+ propList.add(prop);
+ }
+ }
+
+ if (! propList.isEmpty()) {
+ targetObj.addBoundProperties(sourceObj, propList.toArray(new Property[propList.size()]));
+ }
+ } else if (source instanceof ScriptObjectMirror) {
+ // get enumerable, immediate properties of mirror
+ final ScriptObjectMirror mirror = (ScriptObjectMirror)source;
+ final String[] keys = mirror.getOwnKeys(false);
+ if (keys.length == 0) {
+ // nothing to bind
+ return target;
+ }
+
+ // make accessor properties using dynamic invoker getters and setters
+ final AccessorProperty[] props = new AccessorProperty[keys.length];
+ for (int idx = 0; idx < keys.length; idx++) {
+ final String name = keys[idx];
+ final MethodHandle getter = Bootstrap.createDynamicInvoker("dyn:getMethod|getProp|getElem:" + name, MIRROR_GETTER_TYPE);
+ final MethodHandle setter = Bootstrap.createDynamicInvoker("dyn:setProp|setElem:" + name, MIRROR_SETTER_TYPE);
+ props[idx] = (AccessorProperty.create(name, 0, getter, setter));
+ }
+
+ targetObj.addBoundProperties(source, props);
+ } else if (source instanceof StaticClass) {
+ final Class<?> clazz = ((StaticClass)source).getRepresentedClass();
+ bindBeanProperties(targetObj, source, BeansLinker.getReadableStaticPropertyNames(clazz),
+ BeansLinker.getWritableStaticPropertyNames(clazz), BeansLinker.getStaticMethodNames(clazz));
+ } else {
+ final Class<?> clazz = source.getClass();
+ bindBeanProperties(targetObj, source, BeansLinker.getReadableInstancePropertyNames(clazz),
+ BeansLinker.getWritableInstancePropertyNames(clazz), BeansLinker.getInstanceMethodNames(clazz));
+ }
+
+ return target;
+ }
+
+ private static void bindBeanProperties(final ScriptObject targetObj, final Object source,
+ final Collection<String> readablePropertyNames, final Collection<String> writablePropertyNames,
+ final Collection<String> methodNames) {
+ final Set<String> propertyNames = new HashSet<>(readablePropertyNames);
+ propertyNames.addAll(writablePropertyNames);
+
+ final Class<?> clazz = source.getClass();
+ Bootstrap.checkReflectionAccess(clazz);
+
+ final MethodType getterType = MethodType.methodType(Object.class, clazz);
+ final MethodType setterType = MethodType.methodType(Object.class, clazz, Object.class);
+
+ final GuardingDynamicLinker linker = BeansLinker.getLinkerForClass(clazz);
+
+ 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));
+ }
+ for(final String propertyName: propertyNames) {
+ 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));
+ }
+
+ targetObj.addBoundProperties(source, properties.toArray(new AccessorProperty[properties.size()]));
+ }
+
+ private static MethodHandle getBoundBeanMethodGetter(Object source, MethodHandle methodGetter) {
+ try {
+ // NOTE: we're relying on the fact that "dyn:getMethod:..." return value is constant for any given method
+ // name and object linked with BeansLinker. (Actually, an even stronger assumption is true: return value is
+ // constant for any given method name and object's class.)
+ return MethodHandles.dropArguments(MethodHandles.constant(Object.class,
+ Bootstrap.bindDynamicMethod(methodGetter.invoke(source), source)), 0, Object.class);
+ } catch(RuntimeException|Error e) {
+ throw e;
+ } catch(Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+
+ private static MethodHandle getBeanOperation(final GuardingDynamicLinker linker, final String operation,
+ final MethodType methodType, final Object source) {
+ final GuardedInvocation inv;
+ try {
+ inv = linker.getGuardedInvocation(createLinkRequest(operation, methodType, source),
+ Bootstrap.getLinkerServices());
+ assert passesGuard(source, inv.getGuard());
+ } catch(RuntimeException|Error e) {
+ throw e;
+ } catch(Throwable t) {
+ throw new RuntimeException(t);
+ }
+ assert inv.getSwitchPoint() == null; // Linkers in Dynalink's beans package don't use switchpoints.
+ // We discard the guard, as all method handles will be bound to a specific object.
+ return inv.getInvocation();
+ }
+
+ private static boolean passesGuard(final Object obj, final MethodHandle guard) throws Throwable {
+ return guard == null || (boolean)guard.invoke(obj);
+ }
+
+ private static LinkRequest createLinkRequest(String operation, MethodType methodType, Object source) {
+ return new LinkRequestImpl(CallSiteDescriptorFactory.create(MethodHandles.publicLookup(), operation,
+ methodType), false, source);
+ }
}
diff --git a/src/jdk/nashorn/internal/objects/NativeRangeError.java b/src/jdk/nashorn/internal/objects/NativeRangeError.java
index faf68f87..d51a0c09 100644
--- a/src/jdk/nashorn/internal/objects/NativeRangeError.java
+++ b/src/jdk/nashorn/internal/objects/NativeRangeError.java
@@ -58,8 +58,12 @@ public final class NativeRangeError extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- NativeRangeError(final Object msg) {
- super(Global.instance().getRangeErrorPrototype(), $nasgenmap$);
+ static PropertyMap getInitialMap() {
+ return $nasgenmap$;
+ }
+
+ private NativeRangeError(final Object msg, final ScriptObject proto, final PropertyMap map) {
+ super(proto, map);
if (msg != UNDEFINED) {
this.instMessage = JSType.toString(msg);
} else {
@@ -67,6 +71,14 @@ public final class NativeRangeError extends ScriptObject {
}
}
+ NativeRangeError(final Object msg, final Global global) {
+ this(msg, global.getRangeErrorPrototype(), global.getRangeErrorMap());
+ }
+
+ private NativeRangeError(final Object msg) {
+ this(msg, Global.instance());
+ }
+
@Override
public String getClassName() {
return "Error";
diff --git a/src/jdk/nashorn/internal/objects/NativeReferenceError.java b/src/jdk/nashorn/internal/objects/NativeReferenceError.java
index 954eed64..a269b515 100644
--- a/src/jdk/nashorn/internal/objects/NativeReferenceError.java
+++ b/src/jdk/nashorn/internal/objects/NativeReferenceError.java
@@ -58,8 +58,12 @@ public final class NativeReferenceError extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- NativeReferenceError(final Object msg) {
- super(Global.instance().getReferenceErrorPrototype(), $nasgenmap$);
+ static PropertyMap getInitialMap() {
+ return $nasgenmap$;
+ }
+
+ private NativeReferenceError(final Object msg, final ScriptObject proto, final PropertyMap map) {
+ super(proto, map);
if (msg != UNDEFINED) {
this.instMessage = JSType.toString(msg);
} else {
@@ -67,6 +71,14 @@ public final class NativeReferenceError extends ScriptObject {
}
}
+ NativeReferenceError(final Object msg, final Global global) {
+ this(msg, global.getReferenceErrorPrototype(), global.getReferenceErrorMap());
+ }
+
+ private NativeReferenceError(final Object msg) {
+ this(msg, Global.instance());
+ }
+
@Override
public String getClassName() {
return "Error";
diff --git a/src/jdk/nashorn/internal/objects/NativeRegExp.java b/src/jdk/nashorn/internal/objects/NativeRegExp.java
index bec8b37d..e6aa4be4 100644
--- a/src/jdk/nashorn/internal/objects/NativeRegExp.java
+++ b/src/jdk/nashorn/internal/objects/NativeRegExp.java
@@ -68,9 +68,20 @@ public final class NativeRegExp extends ScriptObject {
private Global globalObject;
// initialized by nasgen
+ @SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
- NativeRegExp(final String input, final String flagString) {
+ static PropertyMap getInitialMap() {
+ return $nasgenmap$;
+ }
+
+ private NativeRegExp(final Global global) {
+ super(global.getRegExpPrototype(), global.getRegExpMap());
+ this.globalObject = global;
+ }
+
+ NativeRegExp(final String input, final String flagString, final Global global) {
+ this(global);
try {
this.regexp = RegExpFactory.create(input, flagString);
} catch (final ParserException e) {
@@ -80,17 +91,24 @@ public final class NativeRegExp extends ScriptObject {
}
this.setLastIndex(0);
- init();
+ }
+
+ NativeRegExp(final String input, final String flagString) {
+ this(input, flagString, Global.instance());
+ }
+
+ NativeRegExp(final String string, final Global global) {
+ this(string, "", global);
}
NativeRegExp(final String string) {
- this(string, "");
+ this(string, Global.instance());
}
NativeRegExp(final NativeRegExp regExp) {
+ this(Global.instance());
this.lastIndex = regExp.getLastIndexObject();
this.regexp = regExp.getRegExp();
- init();
}
@Override
@@ -614,7 +632,7 @@ public final class NativeRegExp extends ScriptObject {
return null;
}
- return new NativeRegExpExecResult(match);
+ return new NativeRegExpExecResult(match, globalObject);
}
/**
@@ -885,12 +903,6 @@ public final class NativeRegExp extends ScriptObject {
this.lastIndex = JSType.toObject(lastIndex);
}
- private void init() {
- // Keep reference to global object to support "static" properties of RegExp
- this.globalObject = Global.instance();
- this.setProto(globalObject.getRegExpPrototype());
- }
-
private static NativeRegExp checkRegExp(final Object self) {
Global.checkObjectCoercible(self);
if (self instanceof NativeRegExp) {
diff --git a/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java b/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java
index 66720552..3508e5f6 100644
--- a/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java
+++ b/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java
@@ -53,8 +53,12 @@ public final class NativeRegExpExecResult extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- NativeRegExpExecResult(final RegExpResult result) {
- super(Global.instance().getArrayPrototype(), $nasgenmap$);
+ static PropertyMap getInitialMap() {
+ return $nasgenmap$;
+ }
+
+ NativeRegExpExecResult(final RegExpResult result, final Global global) {
+ super(global.getArrayPrototype(), global.getRegExpExecResultMap());
setIsArray();
this.setArray(ArrayData.allocate(result.getGroups().clone()));
this.index = result.getIndex();
diff --git a/src/jdk/nashorn/internal/objects/NativeStrictArguments.java b/src/jdk/nashorn/internal/objects/NativeStrictArguments.java
index cf434f9f..de6e4b51 100644
--- a/src/jdk/nashorn/internal/objects/NativeStrictArguments.java
+++ b/src/jdk/nashorn/internal/objects/NativeStrictArguments.java
@@ -30,14 +30,14 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
+import java.util.ArrayList;
import java.util.Arrays;
+import jdk.nashorn.internal.runtime.AccessorProperty;
import jdk.nashorn.internal.runtime.Property;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
-import jdk.nashorn.internal.lookup.Lookup;
-import jdk.nashorn.internal.lookup.MethodHandleFactory;
/**
* ECMA 10.6 Arguments Object.
@@ -54,21 +54,26 @@ public final class NativeStrictArguments extends ScriptObject {
private static final PropertyMap map$;
static {
- PropertyMap map = PropertyMap.newMap(NativeStrictArguments.class);
- map = Lookup.newProperty(map, "length", Property.NOT_ENUMERABLE, G$LENGTH, S$LENGTH);
+ final ArrayList<Property> properties = new ArrayList<>(1);
+ properties.add(AccessorProperty.create("length", Property.NOT_ENUMERABLE, G$LENGTH, S$LENGTH));
+ PropertyMap map = PropertyMap.newMap(properties);
// In strict mode, the caller and callee properties should throw TypeError
// Need to add properties directly to map since slots are assigned speculatively by newUserAccessors.
final int flags = Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE;
map = map.addProperty(map.newUserAccessors("caller", flags));
map = map.addProperty(map.newUserAccessors("callee", flags));
- map$ = map;
+ map$ = map.setIsShared();
+ }
+
+ static PropertyMap getInitialMap() {
+ return map$;
}
private Object length;
private final Object[] namedArgs;
- NativeStrictArguments(final ScriptObject proto, final Object[] values, final int numParams) {
- super(proto, map$);
+ NativeStrictArguments(final Object[] values, final int numParams,final ScriptObject proto, final PropertyMap map) {
+ super(proto, map);
setIsArguments();
final ScriptFunction func = ScriptFunctionImpl.getTypeErrorThrower();
@@ -143,10 +148,6 @@ public final class NativeStrictArguments extends ScriptObject {
}
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
- try {
- return MethodHandles.lookup().findStatic(NativeStrictArguments.class, name, MH.type(rtype, types));
- } catch (final NoSuchMethodException | IllegalAccessException e) {
- throw new MethodHandleFactory.LookupException(e);
- }
+ return MH.findStatic(MethodHandles.lookup(), NativeStrictArguments.class, name, MH.type(rtype, types));
}
}
diff --git a/src/jdk/nashorn/internal/objects/NativeString.java b/src/jdk/nashorn/internal/objects/NativeString.java
index a5b9ea83..aa2eec63 100644
--- a/src/jdk/nashorn/internal/objects/NativeString.java
+++ b/src/jdk/nashorn/internal/objects/NativeString.java
@@ -41,7 +41,7 @@ import java.util.Locale;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
-import jdk.nashorn.internal.lookup.MethodHandleFactory;
+import jdk.nashorn.internal.lookup.MethodHandleFactory.LookupException;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
@@ -74,12 +74,20 @@ public final class NativeString extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- NativeString(final CharSequence value) {
- this(value, Global.instance().getStringPrototype());
+ static PropertyMap getInitialMap() {
+ return $nasgenmap$;
}
- private NativeString(final CharSequence value, final ScriptObject proto) {
- super(proto, $nasgenmap$);
+ private NativeString(final CharSequence value) {
+ this(value, Global.instance());
+ }
+
+ NativeString(final CharSequence value, final Global global) {
+ this(value, global.getStringPrototype(), global.getStringMap());
+ }
+
+ private NativeString(final CharSequence value, final ScriptObject proto, final PropertyMap map) {
+ super(proto, map);
assert value instanceof String || value instanceof ConsString;
this.value = value;
}
@@ -147,9 +155,9 @@ public final class NativeString extends ScriptObject {
if (returnType == Object.class && (self instanceof String || self instanceof ConsString)) {
try {
- MethodHandle mh = MethodHandles.lookup().findStatic(NativeString.class, "get", desc.getMethodType());
+ MethodHandle mh = MH.findStatic(MethodHandles.lookup(), NativeString.class, "get", desc.getMethodType());
return new GuardedInvocation(mh, NashornGuards.getInstanceOf2Guard(String.class, ConsString.class));
- } catch (final NoSuchMethodException | IllegalAccessException e) {
+ } catch (final LookupException e) {
// Shouldn't happen. Fall back to super
}
}
@@ -1065,10 +1073,7 @@ public final class NativeString extends ScriptObject {
}
private static Object newObj(final Object self, final CharSequence str) {
- if (self instanceof ScriptObject) {
- return new NativeString(str, ((ScriptObject)self).getProto());
- }
- return new NativeString(str, Global.instance().getStringPrototype());
+ return new NativeString(str);
}
/**
@@ -1202,10 +1207,6 @@ public final class NativeString extends ScriptObject {
}
private static MethodHandle findWrapFilter() {
- try {
- return MethodHandles.lookup().findStatic(NativeString.class, "wrapFilter", MH.type(NativeString.class, Object.class));
- } catch (final NoSuchMethodException | IllegalAccessException e) {
- throw new MethodHandleFactory.LookupException(e);
- }
+ return MH.findStatic(MethodHandles.lookup(), NativeString.class, "wrapFilter", MH.type(NativeString.class, Object.class));
}
}
diff --git a/src/jdk/nashorn/internal/objects/NativeSyntaxError.java b/src/jdk/nashorn/internal/objects/NativeSyntaxError.java
index d7d04bba..45920ba7 100644
--- a/src/jdk/nashorn/internal/objects/NativeSyntaxError.java
+++ b/src/jdk/nashorn/internal/objects/NativeSyntaxError.java
@@ -58,8 +58,12 @@ public final class NativeSyntaxError extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- NativeSyntaxError(final Object msg) {
- super(Global.instance().getSyntaxErrorPrototype(), $nasgenmap$);
+ static PropertyMap getInitialMap() {
+ return $nasgenmap$;
+ }
+
+ NativeSyntaxError(final Object msg, final Global global) {
+ super(global.getSyntaxErrorPrototype(), global.getSyntaxErrorMap());
if (msg != UNDEFINED) {
this.instMessage = JSType.toString(msg);
} else {
@@ -67,6 +71,10 @@ public final class NativeSyntaxError extends ScriptObject {
}
}
+ private NativeSyntaxError(final Object msg) {
+ this(msg, Global.instance());
+ }
+
@Override
public String getClassName() {
return "Error";
diff --git a/src/jdk/nashorn/internal/objects/NativeTypeError.java b/src/jdk/nashorn/internal/objects/NativeTypeError.java
index c811a530..2b2308b1 100644
--- a/src/jdk/nashorn/internal/objects/NativeTypeError.java
+++ b/src/jdk/nashorn/internal/objects/NativeTypeError.java
@@ -58,8 +58,12 @@ public final class NativeTypeError extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- NativeTypeError(final Object msg) {
- super(Global.instance().getTypeErrorPrototype(), $nasgenmap$);
+ static PropertyMap getInitialMap() {
+ return $nasgenmap$;
+ }
+
+ NativeTypeError(final Object msg, final Global global) {
+ super(global.getTypeErrorPrototype(), global.getTypeErrorMap());
if (msg != UNDEFINED) {
this.instMessage = JSType.toString(msg);
} else {
@@ -67,6 +71,10 @@ public final class NativeTypeError extends ScriptObject {
}
}
+ private NativeTypeError(final Object msg) {
+ this(msg, Global.instance());
+ }
+
@Override
public String getClassName() {
return "Error";
diff --git a/src/jdk/nashorn/internal/objects/NativeURIError.java b/src/jdk/nashorn/internal/objects/NativeURIError.java
index 80df6c28..2caf1369 100644
--- a/src/jdk/nashorn/internal/objects/NativeURIError.java
+++ b/src/jdk/nashorn/internal/objects/NativeURIError.java
@@ -57,8 +57,12 @@ public final class NativeURIError extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- NativeURIError(final Object msg) {
- super(Global.instance().getURIErrorPrototype(), $nasgenmap$);
+ static PropertyMap getInitialMap() {
+ return $nasgenmap$;
+ }
+
+ NativeURIError(final Object msg, final Global global) {
+ super(global.getURIErrorPrototype(), global.getURIErrorMap());
if (msg != UNDEFINED) {
this.instMessage = JSType.toString(msg);
} else {
@@ -66,6 +70,10 @@ public final class NativeURIError extends ScriptObject {
}
}
+ private NativeURIError(final Object msg) {
+ this(msg, Global.instance());
+ }
+
@Override
public String getClassName() {
return "Error";
diff --git a/src/jdk/nashorn/internal/objects/NativeUint16Array.java b/src/jdk/nashorn/internal/objects/NativeUint16Array.java
index 39c19131..7c37bac9 100644
--- a/src/jdk/nashorn/internal/objects/NativeUint16Array.java
+++ b/src/jdk/nashorn/internal/objects/NativeUint16Array.java
@@ -47,6 +47,7 @@ public final class NativeUint16Array extends ArrayBufferView {
public static final int BYTES_PER_ELEMENT = 2;
// initialized by nasgen
+ @SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {
@@ -149,7 +150,7 @@ public final class NativeUint16Array extends ArrayBufferView {
}
@Override
- protected ScriptObject getPrototype() {
- return Global.instance().getUint16ArrayPrototype();
+ protected ScriptObject getPrototype(final Global global) {
+ return global.getUint16ArrayPrototype();
}
}
diff --git a/src/jdk/nashorn/internal/objects/NativeUint32Array.java b/src/jdk/nashorn/internal/objects/NativeUint32Array.java
index 37102bae..9b51db48 100644
--- a/src/jdk/nashorn/internal/objects/NativeUint32Array.java
+++ b/src/jdk/nashorn/internal/objects/NativeUint32Array.java
@@ -48,6 +48,7 @@ public final class NativeUint32Array extends ArrayBufferView {
public static final int BYTES_PER_ELEMENT = 4;
// initialized by nasgen
+ @SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {
@@ -168,7 +169,7 @@ public final class NativeUint32Array extends ArrayBufferView {
}
@Override
- protected ScriptObject getPrototype() {
- return Global.instance().getUint32ArrayPrototype();
+ protected ScriptObject getPrototype(final Global global) {
+ return global.getUint32ArrayPrototype();
}
}
diff --git a/src/jdk/nashorn/internal/objects/NativeUint8Array.java b/src/jdk/nashorn/internal/objects/NativeUint8Array.java
index aa6f89be..be4e59d3 100644
--- a/src/jdk/nashorn/internal/objects/NativeUint8Array.java
+++ b/src/jdk/nashorn/internal/objects/NativeUint8Array.java
@@ -47,6 +47,7 @@ public final class NativeUint8Array extends ArrayBufferView {
public static final int BYTES_PER_ELEMENT = 1;
// initialized by nasgen
+ @SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {
@@ -142,7 +143,7 @@ public final class NativeUint8Array extends ArrayBufferView {
}
@Override
- protected ScriptObject getPrototype() {
- return Global.instance().getUint8ArrayPrototype();
+ protected ScriptObject getPrototype(final Global global) {
+ return global.getUint8ArrayPrototype();
}
}
diff --git a/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java b/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java
index 4467c856..43b777ba 100644
--- a/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java
+++ b/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java
@@ -48,6 +48,7 @@ public final class NativeUint8ClampedArray extends ArrayBufferView {
public static final int BYTES_PER_ELEMENT = 1;
// initialized by nasgen
+ @SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {
@@ -159,7 +160,7 @@ public final class NativeUint8ClampedArray extends ArrayBufferView {
}
@Override
- protected ScriptObject getPrototype() {
- return Global.instance().getUint8ClampedArrayPrototype();
+ protected ScriptObject getPrototype(final Global global) {
+ return global.getUint8ClampedArrayPrototype();
}
}
diff --git a/src/jdk/nashorn/internal/objects/PrototypeObject.java b/src/jdk/nashorn/internal/objects/PrototypeObject.java
index 3a7205f9..837fee8b 100644
--- a/src/jdk/nashorn/internal/objects/PrototypeObject.java
+++ b/src/jdk/nashorn/internal/objects/PrototypeObject.java
@@ -30,12 +30,12 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
+import java.util.ArrayList;
+import jdk.nashorn.internal.runtime.AccessorProperty;
import jdk.nashorn.internal.runtime.Property;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
-import jdk.nashorn.internal.lookup.Lookup;
-import jdk.nashorn.internal.lookup.MethodHandleFactory;
/**
* Instances of this class serve as "prototype" object for script functions.
@@ -52,13 +52,22 @@ public class PrototypeObject extends ScriptObject {
private static final MethodHandle SET_CONSTRUCTOR = findOwnMH("setConstructor", void.class, Object.class, Object.class);
static {
- PropertyMap map = PropertyMap.newMap(PrototypeObject.class);
- map = Lookup.newProperty(map, "constructor", Property.NOT_ENUMERABLE, GET_CONSTRUCTOR, SET_CONSTRUCTOR);
- map$ = map;
+ final ArrayList<Property> properties = new ArrayList<>(1);
+ properties.add(AccessorProperty.create("constructor", Property.NOT_ENUMERABLE, GET_CONSTRUCTOR, SET_CONSTRUCTOR));
+ map$ = PropertyMap.newMap(properties).setIsShared();
+ }
+
+ static PropertyMap getInitialMap() {
+ return map$;
+ }
+
+ private PrototypeObject(final Global global, final PropertyMap map) {
+ super(map != map$? map.addAll(global.getPrototypeObjectMap()) : global.getPrototypeObjectMap());
+ setProto(global.getObjectPrototype());
}
PrototypeObject() {
- this(map$);
+ this(Global.instance(), map$);
}
/**
@@ -67,12 +76,11 @@ public class PrototypeObject extends ScriptObject {
* @param map property map
*/
public PrototypeObject(final PropertyMap map) {
- super(map != map$ ? map.addAll(map$) : map$);
- setProto(Global.objectPrototype());
+ this(Global.instance(), map);
}
PrototypeObject(final ScriptFunction func) {
- this(map$);
+ this(Global.instance(), map$);
this.constructor = func;
}
@@ -107,10 +115,6 @@ public class PrototypeObject extends ScriptObject {
}
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
- try {
- return MethodHandles.lookup().findStatic(PrototypeObject.class, name, MH.type(rtype, types));
- } catch (final NoSuchMethodException | IllegalAccessException e) {
- throw new MethodHandleFactory.LookupException(e);
- }
+ return MH.findStatic(MethodHandles.lookup(), PrototypeObject.class, name, MH.type(rtype, types));
}
}
diff --git a/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java b/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java
index 6834ef4b..88421a70 100644
--- a/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java
+++ b/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java
@@ -28,6 +28,7 @@ package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.lang.invoke.MethodHandle;
+import java.util.ArrayList;
import jdk.nashorn.internal.runtime.GlobalFunctions;
import jdk.nashorn.internal.runtime.Property;
import jdk.nashorn.internal.runtime.PropertyMap;
@@ -36,6 +37,7 @@ import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptFunctionData;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.lookup.Lookup;
+import jdk.nashorn.internal.runtime.AccessorProperty;
/**
* Concrete implementation of ScriptFunction. This sets correct map for the
@@ -53,9 +55,30 @@ public class ScriptFunctionImpl extends ScriptFunction {
// property map for non-strict, non-bound functions.
private static final PropertyMap map$;
+ static PropertyMap getInitialMap() {
+ return map$;
+ }
+
+ static PropertyMap getInitialAnonymousMap() {
+ return AnonymousFunction.getInitialMap();
+ }
+
+ static PropertyMap getInitialStrictMap() {
+ return strictmodemap$;
+ }
+
+ static PropertyMap getInitialBoundMap() {
+ return boundfunctionmap$;
+ }
+
// Marker object for lazily initialized prototype object
private static final Object LAZY_PROTOTYPE = new Object();
+ private ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final MethodHandle[] specs, final Global global) {
+ super(name, invokeHandle, global.getFunctionMap(), null, specs, false, true, true);
+ init(global);
+ }
+
/**
* Constructor called by Nasgen generated code, no membercount, use the default map.
* Creates builtin functions only.
@@ -65,8 +88,12 @@ public class ScriptFunctionImpl extends ScriptFunction {
* @param specs specialized versions of this method, if available, null otherwise
*/
ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final MethodHandle[] specs) {
- super(name, invokeHandle, map$, null, specs, false, true, true);
- init();
+ this(name, invokeHandle, specs, Global.instance());
+ }
+
+ private ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final PropertyMap map, final MethodHandle[] specs, final Global global) {
+ super(name, invokeHandle, map.addAll(global.getFunctionMap()), null, specs, false, true, true);
+ init(global);
}
/**
@@ -79,8 +106,12 @@ public class ScriptFunctionImpl extends ScriptFunction {
* @param specs specialized versions of this method, if available, null otherwise
*/
ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final PropertyMap map, final MethodHandle[] specs) {
- super(name, invokeHandle, map.addAll(map$), null, specs, false, true, true);
- init();
+ this(name, invokeHandle, map, specs, Global.instance());
+ }
+
+ private ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor, final Global global) {
+ super(name, methodHandle, getMap(global, isStrict), scope, specs, isStrict, isBuiltin, isConstructor);
+ init(global);
}
/**
@@ -95,8 +126,12 @@ public class ScriptFunctionImpl extends ScriptFunction {
* @param isConstructor can the function be used as a constructor (most can; some built-ins are restricted).
*/
ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) {
- super(name, methodHandle, getMap(isStrict), scope, specs, isStrict, isBuiltin, isConstructor);
- init();
+ this(name, methodHandle, scope, specs, isStrict, isBuiltin, isConstructor, Global.instance());
+ }
+
+ private ScriptFunctionImpl(final RecompilableScriptFunctionData data, final ScriptObject scope, final Global global) {
+ super(data, getMap(global, data.isStrict()), scope);
+ init(global);
}
/**
@@ -106,27 +141,32 @@ public class ScriptFunctionImpl extends ScriptFunction {
* @param scope scope object
*/
public ScriptFunctionImpl(final RecompilableScriptFunctionData data, final ScriptObject scope) {
- super(data, getMap(data.isStrict()), scope);
- init();
+ this(data, scope, Global.instance());
}
/**
* Only invoked internally from {@link BoundScriptFunctionImpl} constructor.
* @param data the script function data for the bound function.
+ * @param global the global object
*/
- ScriptFunctionImpl(final ScriptFunctionData data) {
- super(data, boundfunctionmap$, null);
- init();
+ ScriptFunctionImpl(final ScriptFunctionData data, final Global global) {
+ super(data, global.getBoundFunctionMap(), null);
+ init(global);
}
static {
- PropertyMap map = PropertyMap.newMap(ScriptFunctionImpl.class);
- map = Lookup.newProperty(map, "prototype", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE, G$PROTOTYPE, S$PROTOTYPE);
- map = Lookup.newProperty(map, "length", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE | Property.NOT_WRITABLE, G$LENGTH, null);
- map = Lookup.newProperty(map, "name", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE | Property.NOT_WRITABLE, G$NAME, null);
- map$ = map;
+ final ArrayList<Property> properties = new ArrayList<>(3);
+ properties.add(AccessorProperty.create("prototype", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE, G$PROTOTYPE, S$PROTOTYPE));
+ properties.add(AccessorProperty.create("length", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE | Property.NOT_WRITABLE, G$LENGTH, null));
+ properties.add(AccessorProperty.create("name", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE | Property.NOT_WRITABLE, G$NAME, null));
+ map$ = PropertyMap.newMap(properties);
strictmodemap$ = createStrictModeMap(map$);
boundfunctionmap$ = createBoundFunctionMap(strictmodemap$);
+ // There are order dependencies between normal map, struct map and bound map
+ // We can make these 'shared' only after initialization of all three.
+ map$.setIsShared();
+ strictmodemap$.setIsShared();
+ boundfunctionmap$.setIsShared();
}
// function object representing TypeErrorThrower
@@ -149,17 +189,18 @@ public class ScriptFunctionImpl extends ScriptFunction {
return typeErrorThrower;
}
- private static PropertyMap createStrictModeMap(PropertyMap map) {
+ private static PropertyMap createStrictModeMap(final PropertyMap map) {
final int flags = Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE;
+ PropertyMap newMap = map;
// Need to add properties directly to map since slots are assigned speculatively by newUserAccessors.
- map = map.addProperty(map.newUserAccessors("arguments", flags));
- map = map.addProperty(map.newUserAccessors("caller", flags));
- return map;
+ newMap = newMap.addProperty(map.newUserAccessors("arguments", flags));
+ newMap = newMap.addProperty(map.newUserAccessors("caller", flags));
+ return newMap;
}
// Choose the map based on strict mode!
- private static PropertyMap getMap(final boolean strict) {
- return strict ? strictmodemap$ : map$;
+ private static PropertyMap getMap(final Global global, final boolean strict) {
+ return strict ? global.getStrictFunctionMap() : global.getFunctionMap();
}
private static PropertyMap createBoundFunctionMap(final PropertyMap strictModeMap) {
@@ -171,15 +212,19 @@ public class ScriptFunctionImpl extends ScriptFunction {
// Instance of this class is used as global anonymous function which
// serves as Function.prototype object.
private static class AnonymousFunction extends ScriptFunctionImpl {
- private static final PropertyMap nasgenmap$$ = PropertyMap.newMap(AnonymousFunction.class);
+ private static final PropertyMap anonmap$ = PropertyMap.newMap().setIsShared();
+
+ static PropertyMap getInitialMap() {
+ return anonmap$;
+ }
- AnonymousFunction() {
- super("", GlobalFunctions.ANONYMOUS, nasgenmap$$, null);
+ AnonymousFunction(final Global global) {
+ super("", GlobalFunctions.ANONYMOUS, global.getAnonymousFunctionMap(), null);
}
}
- static ScriptFunctionImpl newAnonymousFunction() {
- return new AnonymousFunction();
+ static ScriptFunctionImpl newAnonymousFunction(final Global global) {
+ return new AnonymousFunction(global);
}
/**
@@ -254,8 +299,8 @@ public class ScriptFunctionImpl extends ScriptFunction {
}
// Internals below..
- private void init() {
- this.setProto(Global.instance().getFunctionPrototype());
+ private void init(final Global global) {
+ this.setProto(global.getFunctionPrototype());
this.prototype = LAZY_PROTOTYPE;
// We have to fill user accessor functions late as these are stored
diff --git a/src/jdk/nashorn/internal/parser/JSONParser.java b/src/jdk/nashorn/internal/parser/JSONParser.java
index f1e68f66..cb14fcdf 100644
--- a/src/jdk/nashorn/internal/parser/JSONParser.java
+++ b/src/jdk/nashorn/internal/parser/JSONParser.java
@@ -35,6 +35,7 @@ import static jdk.nashorn.internal.parser.TokenType.STRING;
import java.util.ArrayList;
import java.util.List;
+import jdk.nashorn.internal.ir.Expression;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ObjectNode;
@@ -274,7 +275,7 @@ public class JSONParser extends AbstractParser {
* Parse a JSON literal from the token stream
* @return the JSON literal as a Node
*/
- private Node jsonLiteral() {
+ private Expression jsonLiteral() {
final long literalToken = token;
switch (type) {
@@ -326,7 +327,7 @@ public class JSONParser extends AbstractParser {
* Parse an array literal from the token stream
* @return the array literal as a Node
*/
- private Node arrayLiteral() {
+ private LiteralNode<Expression[]> arrayLiteral() {
// Unlike JavaScript array literals, elison is not permitted in JSON.
// Capture LBRACKET token.
@@ -334,9 +335,9 @@ public class JSONParser extends AbstractParser {
// LBRACKET tested in caller.
next();
- Node result = null;
+ LiteralNode<Expression[]> result = null;
// Prepare to accummulating elements.
- final List<Node> elements = new ArrayList<>();
+ final List<Expression> elements = new ArrayList<>();
loop:
while (true) {
@@ -368,7 +369,7 @@ loop:
* Parse an object literal from the token stream
* @return the object literal as a Node
*/
- private Node objectLiteral() {
+ private ObjectNode objectLiteral() {
// Capture LBRACE token.
final long objectToken = token;
// LBRACE tested in caller.
@@ -423,7 +424,7 @@ loop:
if (name != null) {
expect(COLON);
- final Node value = jsonLiteral();
+ final Expression value = jsonLiteral();
return new PropertyNode(propertyToken, value.getFinish(), name, value, null, null);
}
diff --git a/src/jdk/nashorn/internal/parser/Lexer.java b/src/jdk/nashorn/internal/parser/Lexer.java
index ecf67962..adb1445c 100644
--- a/src/jdk/nashorn/internal/parser/Lexer.java
+++ b/src/jdk/nashorn/internal/parser/Lexer.java
@@ -546,14 +546,27 @@ public class Lexer extends Scanner {
}
/**
+ * interface to receive line information for multi-line literals.
+ */
+ protected interface LineInfoReceiver {
+ /**
+ * Receives line information
+ * @param line last line number
+ * @param linePosition position of last line
+ */
+ public void lineInfo(int line, int linePosition);
+ }
+
+ /**
* Check whether the given token represents the beginning of a literal. If so scan
* the literal and return <tt>true</tt>, otherwise return false.
*
* @param token the token.
* @param startTokenType the token type.
+ * @parasm lir LineInfoReceiver that receives line info for multi-line string literals.
* @return True if a literal beginning with startToken was found and scanned.
*/
- protected boolean scanLiteral(final long token, final TokenType startTokenType) {
+ protected boolean scanLiteral(final long token, final TokenType startTokenType, final LineInfoReceiver lir) {
// Check if it can be a literal.
if (!canStartLiteral(startTokenType)) {
return false;
@@ -569,7 +582,7 @@ public class Lexer extends Scanner {
return scanRegEx();
} else if (ch0 == '<') {
if (ch1 == '<') {
- return scanHereString();
+ return scanHereString(lir);
} else if (Character.isJavaIdentifierStart(ch1)) {
return scanXMLLiteral();
}
@@ -1417,7 +1430,7 @@ public class Lexer extends Scanner {
*
* @return TRUE if is a here string.
*/
- private boolean scanHereString() {
+ private boolean scanHereString(final LineInfoReceiver lir) {
assert ch0 == '<' && ch1 == '<';
if (scripting) {
// Record beginning of here string.
@@ -1446,7 +1459,13 @@ public class Lexer extends Scanner {
// Record rest of line.
final State restState = saveState();
+ // keep line number updated
+ int lastLine = line;
+ int lastLinePosition = linePosition;
+
skipLine(false);
+ lastLine++;
+ lastLinePosition = position;
restState.setLimit(position);
// Record beginning of string.
@@ -1463,9 +1482,14 @@ public class Lexer extends Scanner {
}
skipLine(false);
+ lastLine++;
+ lastLinePosition = position;
stringEnd = position;
}
+ // notify last line information
+ lir.lineInfo(lastLine, lastLinePosition);
+
// Record end of string.
stringState.setLimit(stringEnd);
diff --git a/src/jdk/nashorn/internal/parser/Parser.java b/src/jdk/nashorn/internal/parser/Parser.java
index 181dcf83..fd97adde 100644
--- a/src/jdk/nashorn/internal/parser/Parser.java
+++ b/src/jdk/nashorn/internal/parser/Parser.java
@@ -54,9 +54,10 @@ import static jdk.nashorn.internal.parser.TokenType.TERNARY;
import static jdk.nashorn.internal.parser.TokenType.WHILE;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
-import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import jdk.nashorn.internal.codegen.CompilerConstants;
@@ -66,6 +67,7 @@ import jdk.nashorn.internal.ir.BaseNode;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.BlockLexicalContext;
+import jdk.nashorn.internal.ir.BlockStatement;
import jdk.nashorn.internal.ir.BreakNode;
import jdk.nashorn.internal.ir.BreakableNode;
import jdk.nashorn.internal.ir.CallNode;
@@ -73,7 +75,8 @@ import jdk.nashorn.internal.ir.CaseNode;
import jdk.nashorn.internal.ir.CatchNode;
import jdk.nashorn.internal.ir.ContinueNode;
import jdk.nashorn.internal.ir.EmptyNode;
-import jdk.nashorn.internal.ir.ExecuteNode;
+import jdk.nashorn.internal.ir.Expression;
+import jdk.nashorn.internal.ir.ExpressionStatement;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
@@ -127,6 +130,9 @@ public class Parser extends AbstractParser {
private static final DebugLogger LOG = new DebugLogger("parser");
+ /** to receive line information from Lexer when scanning multine literals. */
+ protected final Lexer.LineInfoReceiver lineInfoReceiver;
+
/**
* Constructor
*
@@ -151,6 +157,19 @@ public class Parser extends AbstractParser {
this.env = env;
this.namespace = new Namespace(env.getNamespace());
this.scripting = env._scripting;
+ if (this.scripting) {
+ this.lineInfoReceiver = new Lexer.LineInfoReceiver() {
+ @Override
+ public void lineInfo(final int line, final int linePosition) {
+ // update the parser maintained line information
+ Parser.this.line = line;
+ Parser.this.linePosition = linePosition;
+ }
+ };
+ } else {
+ // non-scripting mode script can't have multi-line literals
+ this.lineInfoReceiver = null;
+ }
}
/**
@@ -350,7 +369,7 @@ loop:
* @return New block.
*/
private Block newBlock() {
- return lc.push(new Block(line, token, Token.descPosition(token)));
+ return lc.push(new Block(token, Token.descPosition(token)));
}
/**
@@ -516,7 +535,7 @@ loop:
* @param rhs Right hand side expression.
* @return Verified expression.
*/
- private Node verifyAssignment(final long op, final Node lhs, final Node rhs) {
+ private Expression verifyAssignment(final long op, final Expression lhs, final Expression rhs) {
final TokenType opType = Token.descType(op);
switch (opType) {
@@ -562,7 +581,7 @@ loop:
* @param isPostfix Prefix or postfix.
* @return Reduced expression.
*/
- private static Node incDecExpression(final long firstToken, final TokenType tokenType, final Node expression, final boolean isPostfix) {
+ private static UnaryNode incDecExpression(final long firstToken, final TokenType tokenType, final Expression expression, final boolean isPostfix) {
if (isPostfix) {
return new UnaryNode(Token.recast(firstToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX), expression.getStart(), Token.descPosition(firstToken) + Token.descLength(firstToken), expression);
}
@@ -622,8 +641,8 @@ loop:
* @return Directive value if the given statement is a directive
*/
private String getDirective(final Node stmt) {
- if (stmt instanceof ExecuteNode) {
- final Node expr = ((ExecuteNode)stmt).getExpression();
+ if (stmt instanceof ExpressionStatement) {
+ final Node expr = ((ExpressionStatement)stmt).getExpression();
if (expr instanceof LiteralNode) {
final LiteralNode<?> lit = (LiteralNode<?>)expr;
final long litToken = lit.getToken();
@@ -836,9 +855,7 @@ loop:
* Parse a statement block.
*/
private void block() {
- final Block newBlock = getBlock(true);
- // Force block execution.
- appendStatement(new ExecuteNode(newBlock.getLineNumber(), newBlock.getToken(), finish, newBlock));
+ appendStatement(new BlockStatement(line, getBlock(true)));
}
/**
@@ -921,7 +938,7 @@ loop:
verifyStrictIdent(name, "variable name");
// Assume no init.
- Node init = null;
+ Expression init = null;
// Look for initializer assignment.
if (type == ASSIGN) {
@@ -985,20 +1002,20 @@ loop:
final long expressionToken = token;
// Get expression and add as statement.
- final Node expression = expression();
+ final Expression expression = expression();
- ExecuteNode executeNode = null;
+ ExpressionStatement expressionStatement = null;
if (expression != null) {
- executeNode = new ExecuteNode(expressionLine, expressionToken, finish, expression);
- appendStatement(executeNode);
+ expressionStatement = new ExpressionStatement(expressionLine, expressionToken, finish, expression);
+ appendStatement(expressionStatement);
} else {
expect(null);
}
endOfLine();
- if (executeNode != null) {
- executeNode.setFinish(finish);
+ if (expressionStatement != null) {
+ expressionStatement.setFinish(finish);
lc.getCurrentBlock().setFinish(finish);
}
}
@@ -1020,7 +1037,7 @@ loop:
next();
expect(LPAREN);
- final Node test = expression();
+ final Expression test = expression();
expect(RPAREN);
final Block pass = getStatement();
@@ -1049,8 +1066,6 @@ loop:
// Create FOR node, capturing FOR token.
ForNode forNode = new ForNode(line, token, Token.descPosition(token), null, null, null, null, ForNode.IS_FOR);
- // Set up new block for scope of vars. Captures first token.
- Block outer = newBlock();
lc.push(forNode);
try {
@@ -1076,7 +1091,7 @@ loop:
case SEMICOLON:
break;
default:
- final Node expression = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true);
+ final Expression expression = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true);
forNode = forNode.setInit(lc, expression);
break;
}
@@ -1084,6 +1099,12 @@ loop:
switch (type) {
case SEMICOLON:
// for (init; test; modify)
+
+ // for each (init; test; modify) is invalid
+ if (forNode.isForEach()) {
+ throw error(AbstractParser.message("for.each.without.in"), token);
+ }
+
expect(SEMICOLON);
if (type != SEMICOLON) {
forNode = forNode.setTest(lc, expression());
@@ -1142,15 +1163,11 @@ loop:
final Block body = getStatement();
forNode = forNode.setBody(lc, body);
forNode.setFinish(body.getFinish());
- outer.setFinish(body.getFinish());
appendStatement(forNode);
} finally {
lc.pop(forNode);
- outer = restoreBlock(outer);
}
-
- appendStatement(new ExecuteNode(outer.getLineNumber(), outer.getToken(), outer.getFinish(), outer));
}
/**
@@ -1358,7 +1375,7 @@ loop:
// RETURN tested in caller.
nextOrEOL();
- Node expression = null;
+ Expression expression = null;
// SEMICOLON or expression.
switch (type) {
@@ -1394,7 +1411,7 @@ loop:
// YIELD tested in caller.
nextOrEOL();
- Node expression = null;
+ Expression expression = null;
// SEMICOLON or expression.
switch (type) {
@@ -1496,7 +1513,7 @@ loop:
while (type != RBRACE) {
// Prepare for next case.
- Node caseExpression = null;
+ Expression caseExpression = null;
final long caseToken = token;
switch (type) {
@@ -1589,7 +1606,7 @@ loop:
// THROW tested in caller.
nextOrEOL();
- Node expression = null;
+ Expression expression = null;
// SEMICOLON or expression.
switch (type) {
@@ -1637,6 +1654,7 @@ loop:
next();
// Container block needed to act as target for labeled break statements
+ final int startLine = line;
Block outer = newBlock();
// Create try.
@@ -1656,11 +1674,13 @@ loop:
verifyStrictIdent(exception, "catch argument");
// Check for conditional catch.
- Node ifExpression = null;
+ final Expression ifExpression;
if (type == IF) {
next();
// Get the exception condition.
ifExpression = expression();
+ } else {
+ ifExpression = null;
}
expect(RPAREN);
@@ -1707,7 +1727,7 @@ loop:
outer = restoreBlock(outer);
}
- appendStatement(new ExecuteNode(outer.getLineNumber(), outer.getToken(), outer.getFinish(), outer));
+ appendStatement(new BlockStatement(startLine, outer));
}
/**
@@ -1725,7 +1745,7 @@ loop:
// DEBUGGER tested in caller.
next();
endOfLine();
- appendStatement(new ExecuteNode(debuggerLine, debuggerToken, finish, new RuntimeNode(debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Node>())));
+ appendStatement(new ExpressionStatement(debuggerLine, debuggerToken, finish, new RuntimeNode(debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Expression>())));
}
/**
@@ -1743,7 +1763,7 @@ loop:
* @return Expression node.
*/
@SuppressWarnings("fallthrough")
- private Node primaryExpression() {
+ private Expression primaryExpression() {
// Capture first token.
final int primaryLine = line;
final long primaryToken = token;
@@ -1790,7 +1810,7 @@ loop:
case LPAREN:
next();
- final Node expression = expression();
+ final Expression expression = expression();
expect(RPAREN);
@@ -1798,7 +1818,7 @@ loop:
default:
// In this context some operator tokens mark the start of a literal.
- if (lexer.scanLiteral(primaryToken, type)) {
+ if (lexer.scanLiteral(primaryToken, type, lineInfoReceiver)) {
next();
return getLiteral();
}
@@ -1817,17 +1837,16 @@ loop:
* @param primaryToken Original string token.
* @return callNode to $EXEC.
*/
- Node execString(final int primaryLine, final long primaryToken) {
+ CallNode execString(final int primaryLine, final long primaryToken) {
// Synthesize an ident to call $EXEC.
final IdentNode execIdent = new IdentNode(primaryToken, finish, ScriptingFunctions.EXEC_NAME);
// Skip over EXECSTRING.
next();
// Set up argument list for call.
- final List<Node> arguments = new ArrayList<>();
// Skip beginning of edit string expression.
expect(LBRACE);
// Add the following expression to arguments.
- arguments.add(expression());
+ final List<Expression> arguments = Collections.singletonList(expression());
// Skip ending of edit string expression.
expect(RBRACE);
@@ -1854,14 +1873,14 @@ loop:
* Parse array literal.
* @return Expression node.
*/
- private Node arrayLiteral() {
+ private LiteralNode<Expression[]> arrayLiteral() {
// Capture LBRACKET token.
final long arrayToken = token;
// LBRACKET tested in caller.
next();
// Prepare to accummulating elements.
- final List<Node> elements = new ArrayList<>();
+ final List<Expression> elements = new ArrayList<>();
// Track elisions.
boolean elision = true;
loop:
@@ -1889,7 +1908,7 @@ loop:
throw error(AbstractParser.message("expected.comma", type.getNameOrType()));
}
// Add expression element.
- final Node expression = assignmentExpression(false);
+ final Expression expression = assignmentExpression(false);
if (expression != null) {
elements.add(expression);
@@ -1919,7 +1938,7 @@ loop:
* Parse an object literal.
* @return Expression node.
*/
- private Node objectLiteral() {
+ private ObjectNode objectLiteral() {
// Capture LBRACE token.
final long objectToken = token;
// LBRACE tested in caller.
@@ -1927,14 +1946,14 @@ loop:
// Object context.
// Prepare to accumulate elements.
- // final List<Node> elements = new ArrayList<>();
- final Map<String, PropertyNode> map = new LinkedHashMap<>();
+ final List<PropertyNode> elements = new ArrayList<>();
+ final Map<String, Integer> map = new HashMap<>();
// Create a block for the object literal.
- boolean commaSeen = true;
+ boolean commaSeen = true;
loop:
- while (true) {
- switch (type) {
+ while (true) {
+ switch (type) {
case RBRACE:
next();
break loop;
@@ -1956,30 +1975,29 @@ loop:
// Get and add the next property.
final PropertyNode property = propertyAssignment();
final String key = property.getKeyName();
- final PropertyNode existingProperty = map.get(key);
+ final Integer existing = map.get(key);
- if (existingProperty == null) {
- map.put(key, property);
- // elements.add(property);
+ if (existing == null) {
+ map.put(key, elements.size());
+ elements.add(property);
break;
}
+ final PropertyNode existingProperty = elements.get(existing);
+
// ECMA section 11.1.5 Object Initialiser
// point # 4 on property assignment production
- final Node value = property.getValue();
+ final Expression value = property.getValue();
final FunctionNode getter = property.getGetter();
final FunctionNode setter = property.getSetter();
- final Node prevValue = existingProperty.getValue();
+ final Expression prevValue = existingProperty.getValue();
final FunctionNode prevGetter = existingProperty.getGetter();
final FunctionNode prevSetter = existingProperty.getSetter();
- boolean redefinitionOk = true;
// ECMA 11.1.5 strict mode restrictions
- if (isStrictMode) {
- if (value != null && prevValue != null) {
- redefinitionOk = false;
- }
+ if (isStrictMode && value != null && prevValue != null) {
+ throw error(AbstractParser.message("property.redefinition", key), property.getToken());
}
final boolean isPrevAccessor = prevGetter != null || prevSetter != null;
@@ -1987,49 +2005,33 @@ loop:
// data property redefined as accessor property
if (prevValue != null && isAccessor) {
- redefinitionOk = false;
+ throw error(AbstractParser.message("property.redefinition", key), property.getToken());
}
// accessor property redefined as data
if (isPrevAccessor && value != null) {
- redefinitionOk = false;
+ throw error(AbstractParser.message("property.redefinition", key), property.getToken());
}
if (isAccessor && isPrevAccessor) {
if (getter != null && prevGetter != null ||
- setter != null && prevSetter != null) {
- redefinitionOk = false;
+ setter != null && prevSetter != null) {
+ throw error(AbstractParser.message("property.redefinition", key), property.getToken());
}
}
- if (!redefinitionOk) {
- throw error(AbstractParser.message("property.redefinition", key.toString()), property.getToken());
- }
-
- PropertyNode newProperty = existingProperty;
if (value != null) {
- if (prevValue == null) {
- map.put(key, newProperty = newProperty.setValue(value));
- } else {
- final long propertyToken = Token.recast(newProperty.getToken(), COMMARIGHT);
- map.put(key, newProperty = newProperty.setValue(new BinaryNode(propertyToken, prevValue, value)));
- }
-
- map.put(key, newProperty = newProperty.setGetter(null).setSetter(null));
- }
-
- if (getter != null) {
- map.put(key, newProperty = newProperty.setGetter(getter));
- }
-
- if (setter != null) {
- map.put(key, newProperty = newProperty.setSetter(setter));
+ elements.add(property);
+ } else if (getter != null) {
+ elements.set(existing, existingProperty.setGetter(getter));
+ } else if (setter != null) {
+ elements.set(existing, existingProperty.setSetter(setter));
}
break;
}
}
- return new ObjectNode(objectToken, finish, new ArrayList<>(map.values()));
+ return new ObjectNode(objectToken, finish, elements);
}
/**
@@ -2046,7 +2048,7 @@ loop:
private PropertyKey propertyName() {
switch (type) {
case IDENT:
- return getIdent();
+ return getIdent().setIsPropertyName();
case OCTAL:
if (isStrictMode) {
throw error(AbstractParser.message("strict.no.octal"), token);
@@ -2123,7 +2125,7 @@ loop:
}
}
- propertyName = new IdentNode(propertyToken, finish, ident);
+ propertyName = new IdentNode(propertyToken, finish, ident).setIsPropertyName();
} else {
propertyName = propertyName();
}
@@ -2149,14 +2151,14 @@ loop:
* Parse left hand side expression.
* @return Expression node.
*/
- private Node leftHandSideExpression() {
+ private Expression leftHandSideExpression() {
int callLine = line;
long callToken = token;
- Node lhs = memberExpression();
+ Expression lhs = memberExpression();
if (type == LPAREN) {
- final List<Node> arguments = argumentList();
+ final List<Expression> arguments = optimizeList(argumentList());
// Catch special functions.
if (lhs instanceof IdentNode) {
@@ -2175,7 +2177,7 @@ loop:
switch (type) {
case LPAREN:
// Get NEW or FUNCTION arguments.
- final List<Node> arguments = argumentList();
+ final List<Expression> arguments = optimizeList(argumentList());
// Create call node.
lhs = new CallNode(callLine, callToken, finish, lhs, arguments);
@@ -2186,7 +2188,7 @@ loop:
next();
// Get array index.
- final Node rhs = expression();
+ final Expression rhs = expression();
expect(RBRACKET);
@@ -2223,19 +2225,19 @@ loop:
* Parse new expression.
* @return Expression node.
*/
- private Node newExpression() {
+ private Expression newExpression() {
final long newToken = token;
// NEW is tested in caller.
next();
// Get function base.
final int callLine = line;
- final Node constructor = memberExpression();
+ final Expression constructor = memberExpression();
if (constructor == null) {
return null;
}
// Get arguments.
- List<Node> arguments;
+ ArrayList<Expression> arguments;
// Allow for missing arguments.
if (type == LPAREN) {
@@ -2253,12 +2255,11 @@ loop:
//
// The object literal following the "new Constructor()" expresssion
// is passed as an additional (last) argument to the constructor.
-
if (!env._no_syntax_extensions && type == LBRACE) {
arguments.add(objectLiteral());
}
- final CallNode callNode = new CallNode(callLine, constructor.getToken(), finish, constructor, arguments);
+ final CallNode callNode = new CallNode(callLine, constructor.getToken(), finish, constructor, optimizeList(arguments));
return new UnaryNode(newToken, callNode);
}
@@ -2276,9 +2277,9 @@ loop:
* Parse member expression.
* @return Expression node.
*/
- private Node memberExpression() {
+ private Expression memberExpression() {
// Prepare to build operation.
- Node lhs;
+ Expression lhs;
switch (type) {
case NEW:
@@ -2307,7 +2308,7 @@ loop:
next();
// Get array index.
- final Node index = expression();
+ final Expression index = expression();
expect(RBRACKET);
@@ -2352,9 +2353,9 @@ loop:
* Parse function call arguments.
* @return Argument list.
*/
- private List<Node> argumentList() {
+ private ArrayList<Expression> argumentList() {
// Prepare to accumulate list of arguments.
- final List<Node> nodeList = new ArrayList<>();
+ final ArrayList<Expression> nodeList = new ArrayList<>();
// LPAREN tested in caller.
next();
@@ -2374,9 +2375,23 @@ loop:
}
expect(RPAREN);
-
return nodeList;
- }
+ }
+
+ private static <T> List<T> optimizeList(ArrayList<T> list) {
+ switch(list.size()) {
+ case 0: {
+ return Collections.emptyList();
+ }
+ case 1: {
+ return Collections.singletonList(list.get(0));
+ }
+ default: {
+ list.trimToSize();
+ return list;
+ }
+ }
+ }
/**
* FunctionDeclaration :
@@ -2392,7 +2407,7 @@ loop:
*
* @return Expression node.
*/
- private Node functionExpression(final boolean isStatement, final boolean topLevel) {
+ private Expression functionExpression(final boolean isStatement, final boolean topLevel) {
final long functionToken = token;
final int functionLine = line;
// FUNCTION is tested in caller.
@@ -2568,10 +2583,8 @@ loop:
*/
// just expression as function body
- final Node expr = assignmentExpression(true);
+ final Expression expr = assignmentExpression(true);
assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode);
- // create a return statement - this creates code in itself and does not need to be
- // wrapped into an ExecuteNode
final ReturnNode returnNode = new ReturnNode(functionNode.getLineNumber(), expr.getToken(), finish, expr);
appendStatement(returnNode);
lastToken = token;
@@ -2614,11 +2627,11 @@ loop:
}
}
- private RuntimeNode referenceError(final Node lhs, final Node rhs, final boolean earlyError) {
+ private RuntimeNode referenceError(final Expression lhs, final Expression rhs, final boolean earlyError) {
if (earlyError) {
throw error(JSErrorType.REFERENCE_ERROR, AbstractParser.message("invalid.lvalue"), lhs.getToken());
}
- final ArrayList<Node> args = new ArrayList<>();
+ final ArrayList<Expression> args = new ArrayList<>();
args.add(lhs);
if (rhs == null) {
args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish()));
@@ -2663,18 +2676,18 @@ loop:
* Parse unary expression.
* @return Expression node.
*/
- private Node unaryExpression() {
+ private Expression unaryExpression() {
final int unaryLine = line;
final long unaryToken = token;
switch (type) {
case DELETE: {
next();
- final Node expr = unaryExpression();
+ final Expression expr = unaryExpression();
if (expr instanceof BaseNode || expr instanceof IdentNode) {
return new UnaryNode(unaryToken, expr);
}
- appendStatement(new ExecuteNode(unaryLine, unaryToken, finish, expr));
+ appendStatement(new ExpressionStatement(unaryLine, unaryToken, finish, expr));
return LiteralNode.newInstance(unaryToken, finish, true);
}
case VOID:
@@ -2684,7 +2697,7 @@ loop:
case BIT_NOT:
case NOT:
next();
- final Node expr = unaryExpression();
+ final Expression expr = unaryExpression();
return new UnaryNode(unaryToken, expr);
case INCPREFIX:
@@ -2692,7 +2705,7 @@ loop:
final TokenType opType = type;
next();
- final Node lhs = leftHandSideExpression();
+ final Expression lhs = leftHandSideExpression();
// ++, -- without operand..
if (lhs == null) {
throw error(AbstractParser.message("expected.lvalue", type.getNameOrType()));
@@ -2717,14 +2730,14 @@ loop:
break;
}
- Node expression = leftHandSideExpression();
+ Expression expression = leftHandSideExpression();
if (last != EOL) {
switch (type) {
case INCPREFIX:
case DECPREFIX:
final TokenType opType = type;
- final Node lhs = expression;
+ final Expression lhs = expression;
// ++, -- without operand..
if (lhs == null) {
throw error(AbstractParser.message("expected.lvalue", type.getNameOrType()));
@@ -2849,16 +2862,16 @@ loop:
* Parse expression.
* @return Expression node.
*/
- private Node expression() {
+ private Expression expression() {
// TODO - Destructuring array.
// Include commas in expression parsing.
return expression(unaryExpression(), COMMARIGHT.getPrecedence()