aboutsummaryrefslogtreecommitdiff
path: root/buildtools/nasgen
diff options
context:
space:
mode:
authorjlaskey <none@none>2012-12-21 16:36:24 -0400
committerjlaskey <none@none>2012-12-21 16:36:24 -0400
commitb5b4ea8613543cf553f0b7c0668872769057a081 (patch)
tree7383cfecccd985a21e16d2e5f9756f27c725bbe3 /buildtools/nasgen
parent97e525f8f856419b8922a89308d6ab60f680e846 (diff)
downloadnashorn-b5b4ea8613543cf553f0b7c0668872769057a081.tar.gz
8005403: Open-source Nashorn
Reviewed-by: attila, hannesw, lagergren, sundar Contributed-by: james.laskey@oracle.com, akhil.arora@oracle.com, andreas.woess@jku.at, attila.szegedi@oracle.com, hannes.wallnoefer@oracle.com, henry.jen@oracle.com, marcus.lagergren@oracle.com, pavel.semenov@oracle.com, pavel.stepanov@oracle.com, petr.hejl@oracle.com, petr.pisl@oracle.com, sundararajan.athijegannathan@oracle.com
Diffstat (limited to 'buildtools/nasgen')
-rw-r--r--buildtools/nasgen/README34
-rw-r--r--buildtools/nasgen/build.xml60
-rw-r--r--buildtools/nasgen/nasgen.iml39
-rw-r--r--buildtools/nasgen/project.properties52
-rw-r--r--buildtools/nasgen/src/META-INF/MANIFEST.MF4
-rw-r--r--buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java334
-rw-r--r--buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java276
-rw-r--r--buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/Main.java181
-rw-r--r--buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java377
-rw-r--r--buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java426
-rw-r--r--buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/NullVisitor.java88
-rw-r--r--buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java184
-rw-r--r--buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfo.java237
-rw-r--r--buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java331
-rw-r--r--buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java309
-rw-r--r--buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java113
16 files changed, 3045 insertions, 0 deletions
diff --git a/buildtools/nasgen/README b/buildtools/nasgen/README
new file mode 100644
index 00000000..d4509459
--- /dev/null
+++ b/buildtools/nasgen/README
@@ -0,0 +1,34 @@
+Nasgen is a tool for processing Java classes that implement native
+JavaScript objects. It does so by looking for the
+com.oracle.nashorn.objects.annotations.ScriptClass annotation and other
+annotations in that package.
+
+For each class "C", nasgen instruments the original class and generates
+two additional classes: a "C$Prototype" class for the JavaScript
+prototype object, and a "C$Constructor" class for the JavaScript
+constructor function.
+
+Each class instrumented or generated by nasgen contains a private static
+"$nasgenmap$" field of type com.oracle.nashorn.runtime.PropertyMap and
+static initializer block to initialize the field to the object's
+JavaScript properties.
+
+Members annotated with @Function, @Property, @Getter, and @Setter are
+mapped to the $Constructor, $Prototype, or main class, depending on the
+value of the annotation's 'where' field. By default, @Property, @Getter,
+and @Setter belong to the main class while @Function methods without
+explicit 'where' field belong to the $Prototype class. The @Constructor
+annotation marks a method to be invoked as JavaScript constructor.
+
+Nasgen enforces all @Function/@Getter/@Setter/@Constructor annotated
+methods to be declared as static. Static final @Property fields remain
+in the main class while other @Property fields are moved to respective
+classes depending on the annotation's 'where' value. For functions
+mapped to the $Prototype or $Constructor class, nasgen also generates
+getters and setters prefixed by G$ and S$, respectively.
+
+Nasgen-generated classes are hidden from normal ClassLoaders by giving
+them a ".clazz" file name extension instead of the standard ".class"
+extension. This allows script classes to be loaded independently by each
+Nashorn context through the com.oracle.nashorn.runtime.StructureLoader
+class loader.
diff --git a/buildtools/nasgen/build.xml b/buildtools/nasgen/build.xml
new file mode 100644
index 00000000..e20793b7
--- /dev/null
+++ b/buildtools/nasgen/build.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ This code is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License version 2 only, as
+ published by the Free Software Foundation.
+
+ This code is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ version 2 for more details (a copy is included in the LICENSE file that
+ accompanied this code).
+
+ You should have received a copy of the GNU General Public License version
+ 2 along with this work; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ or visit www.oracle.com if you need additional information or have any
+ questions.
+-->
+<project name="nasgen" default="all" basedir=".">
+ <target name="init">
+ <loadproperties srcFile="project.properties"/>
+ </target>
+
+ <target name="prepare" depends="init">
+ <mkdir dir="${build.classes.dir}"/>
+ <mkdir dir="${dist.dir}"/>
+ <mkdir dir="${dist.dir}/lib"/>
+ </target>
+
+ <target name="clean" depends="init">
+ <delete dir="${build.dir}"/>
+ <delete dir="${dist.dir}"/>
+ </target>
+
+ <target name="compile" depends="prepare" description="Compiles the nasgen sources">
+ <javac srcdir="${src.dir}"
+ destdir="${build.classes.dir}"
+ classpath="${javac.classpath}"
+ debug="${javac.debug}"
+ includeantruntime="false">
+ <compilerarg value="-Xlint:unchecked"/>
+ <compilerarg value="-Xlint:deprecation"/>
+ <compilerarg value="-XDignore.symbol.file"/>
+ </javac>
+ </target>
+
+ <target name="jar" depends="compile" description="Creates nasgen.jar">
+ <jar jarfile="${dist.jar}" basedir="${build.classes.dir}" manifest="${meta.inf.dir}/MANIFEST.MF"/>
+ </target>
+
+ <target name="dist" depends="jar"/>
+
+ <target name="all" depends="dist"
+ description="Builds sources and generates nasgen.jar"/>
+</project>
diff --git a/buildtools/nasgen/nasgen.iml b/buildtools/nasgen/nasgen.iml
new file mode 100644
index 00000000..b67d39e9
--- /dev/null
+++ b/buildtools/nasgen/nasgen.iml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ This code is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License version 2 only, as
+ published by the Free Software Foundation.
+
+ This code is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ version 2 for more details (a copy is included in the LICENSE file that
+ accompanied this code).
+
+ You should have received a copy of the GNU General Public License version
+ 2 along with this work; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ or visit www.oracle.com if you need additional information or have any
+ questions.
+-->
+<module type="JAVA_MODULE" version="4">
+ <component name="NewModuleRootManager" inherit-compiler-output="false">
+ <output url="file://$MODULE_DIR$/build/classes" />
+ <output-test url="file://$MODULE_DIR$/build/test/classes" />
+ <exclude-output />
+ <content url="file://$MODULE_DIR$">
+ <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+ <excludeFolder url="file://$MODULE_DIR$/build" />
+ <excludeFolder url="file://$MODULE_DIR$/dist" />
+ </content>
+ <orderEntry type="inheritedJdk" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ <orderEntry type="module" module-name="asm" />
+ </component>
+</module>
+
diff --git a/buildtools/nasgen/project.properties b/buildtools/nasgen/project.properties
new file mode 100644
index 00000000..65047d95
--- /dev/null
+++ b/buildtools/nasgen/project.properties
@@ -0,0 +1,52 @@
+#
+# Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+application.title=nasgen
+
+# source and target levels
+build.compiler=modern
+javac.source=1.7
+javac.target=1.7
+
+build.classes.dir=${build.dir}/classes
+
+# This directory is removed when the project is cleaned:
+build.dir=build
+
+# This directory is removed when the project is cleaned:
+dist.dir=dist
+dist.jar=${dist.dir}/nasgen.jar
+dist.javadoc.dir=${dist.dir}/javadoc
+
+nashorn.dir=../../
+
+javac.debug=true
+
+javac.classpath=\
+ ${nashorn.dir}/build/classes
+
+meta.inf.dir=${src.dir}/META-INF
+run.classpath=\
+ ${javac.classpath}:\
+ ${build.classes.dir}
+run.jvmargs=
+src.dir=src
diff --git a/buildtools/nasgen/src/META-INF/MANIFEST.MF b/buildtools/nasgen/src/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..b7098636
--- /dev/null
+++ b/buildtools/nasgen/src/META-INF/MANIFEST.MF
@@ -0,0 +1,4 @@
+Manifest-Version: 1.0
+Class-Path: lib/ant-1.7.1.jar
+Main-Class: jdk.nashorn.internal.tools.nasgen.Main
+
diff --git a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java
new file mode 100644
index 00000000..3a78da41
--- /dev/null
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2010, 2012, 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.tools.nasgen;
+
+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;
+import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC;
+import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKEVIRTUAL;
+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.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.OBJECT_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_MAKEFUNCTION;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_MAKEFUNCTION_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_MAKEFUNCTION_SPECS_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_TYPE;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_TYPE;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SETTER_PREFIX;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_OBJECT;
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.List;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassVisitor;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.FieldVisitor;
+import jdk.internal.org.objectweb.asm.Handle;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Type;
+import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind;
+
+/**
+ * Base class for class generator classes.
+ *
+ */
+public class ClassGenerator {
+ /** ASM class writer used to output bytecode for this class */
+ protected final ClassWriter cw;
+
+ /**
+ * Constructor
+ */
+ protected ClassGenerator() {
+ this.cw = makeClassWriter();
+ }
+
+ MethodGenerator makeStaticInitializer() {
+ return makeStaticInitializer(cw);
+ }
+
+ MethodGenerator makeConstructor() {
+ return makeConstructor(cw);
+ }
+
+ MethodGenerator makeMethod(final int access, final String name, final String desc) {
+ return makeMethod(cw, access, name, desc);
+ }
+
+ void addMapField() {
+ addMapField(cw);
+ }
+
+ void addField(final String name, final String desc) {
+ addField(cw, name, desc);
+ }
+
+ void addFunctionField(final String name) {
+ addFunctionField(cw, name);
+ }
+
+ void addGetter(final String owner, final MemberInfo memInfo) {
+ addGetter(cw, owner, memInfo);
+ }
+
+ void addSetter(final String owner, final MemberInfo memInfo) {
+ addSetter(cw, owner, memInfo);
+ }
+
+ void emitGetClassName(final String name) {
+ final MethodGenerator mi = makeMethod(ACC_PUBLIC, GET_CLASS_NAME, GET_CLASS_NAME_DESC);
+ mi.loadLiteral(name);
+ mi.returnValue();
+ mi.computeMaxs();
+ mi.visitEnd();
+ }
+
+ static ClassWriter makeClassWriter() {
+ return new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) {
+ @Override
+ protected String getCommonSuperClass(final String type1, final String type2) {
+ try {
+ return super.getCommonSuperClass(type1, type2);
+ } catch (final RuntimeException | LinkageError e) {
+ return StringConstants.OBJECT_TYPE;
+ }
+ }
+ };
+ }
+
+ static MethodGenerator makeStaticInitializer(final ClassVisitor cv) {
+ return makeStaticInitializer(cv, CLINIT);
+ }
+
+ static MethodGenerator makeStaticInitializer(final ClassVisitor cv, final String name) {
+ final int access = ACC_PUBLIC | ACC_STATIC;
+ final String desc = DEFAULT_INIT_DESC;
+ final MethodVisitor mv = cv.visitMethod(access, name, desc, null, null);
+ return new MethodGenerator(mv, access, name, desc);
+ }
+
+ static MethodGenerator makeConstructor(final ClassVisitor cv) {
+ final int access = ACC_PUBLIC;
+ final String name = INIT;
+ final String desc = DEFAULT_INIT_DESC;
+ final MethodVisitor mv = cv.visitMethod(access, name, desc, null, null);
+ return new MethodGenerator(mv, access, name, desc);
+ }
+
+ static MethodGenerator makeMethod(final ClassVisitor cv, final int access, final String name, final String desc) {
+ final MethodVisitor mv = cv.visitMethod(access, name, desc, null, null);
+ return new MethodGenerator(mv, access, name, desc);
+ }
+
+ static void emitStaticInitPrefix(final MethodGenerator mi, final String className) {
+ mi.visitCode();
+ mi.pushNull();
+ mi.putStatic(className, MAP_FIELD_NAME, MAP_DESC);
+ mi.loadClass(className);
+ mi.invokeStatic(MAP_TYPE, MAP_NEWMAP, MAP_NEWMAP_DESC);
+ mi.storeLocal(0);
+ }
+
+ static void emitStaticInitSuffix(final MethodGenerator mi, final String className) {
+ mi.loadLocal(0);
+ mi.putStatic(className, MAP_FIELD_NAME, MAP_DESC);
+ mi.returnVoid();
+ mi.computeMaxs();
+ mi.visitEnd();
+ }
+
+ @SuppressWarnings("fallthrough")
+ private static Type memInfoType(final MemberInfo memInfo) {
+ switch (memInfo.getJavaDesc().charAt(0)) {
+ case 'I': return Type.INT_TYPE;
+ case 'J': return Type.LONG_TYPE;
+ case 'D': return Type.DOUBLE_TYPE;
+ default: assert false : memInfo.getJavaDesc();
+ case 'L': return TYPE_OBJECT;
+ }
+ }
+
+ private static String getterDesc(final MemberInfo memInfo) {
+ return Type.getMethodDescriptor(memInfoType(memInfo));
+ }
+
+ private static String setterDesc(final MemberInfo memInfo) {
+ return Type.getMethodDescriptor(Type.VOID_TYPE, memInfoType(memInfo));
+ }
+
+ static void addGetter(final ClassVisitor cv, final String owner, final MemberInfo memInfo) {
+ final int access = ACC_PUBLIC;
+ final String name = GETTER_PREFIX + memInfo.getJavaName();
+ final String desc = getterDesc(memInfo);
+ final MethodVisitor mv = cv.visitMethod(access, name, desc, null, null);
+ final MethodGenerator mi = new MethodGenerator(mv, access, name, desc);
+ mi.visitCode();
+ if (memInfo.isStatic() && memInfo.getKind() == Kind.PROPERTY) {
+ mi.getStatic(owner, memInfo.getJavaName(), memInfo.getJavaDesc());
+ } else {
+ mi.loadLocal(0);
+ mi.getField(owner, memInfo.getJavaName(), memInfo.getJavaDesc());
+ }
+ mi.returnValue();
+ mi.computeMaxs();
+ mi.visitEnd();
+ }
+
+ static void addSetter(final ClassVisitor cv, final String owner, final MemberInfo memInfo) {
+ final int access = ACC_PUBLIC;
+ final String name = SETTER_PREFIX + memInfo.getJavaName();
+ final String desc = setterDesc(memInfo);
+ final MethodVisitor mv = cv.visitMethod(access, name, desc, null, null);
+ final MethodGenerator mi = new MethodGenerator(mv, access, name, desc);
+ mi.visitCode();
+ if (memInfo.isStatic() && memInfo.getKind() == Kind.PROPERTY) {
+ mi.loadLocal(1);
+ mi.putStatic(owner, memInfo.getJavaName(), memInfo.getJavaDesc());
+ } else {
+ mi.loadLocal(0);
+ mi.loadLocal(1);
+ mi.putField(owner, memInfo.getJavaName(), memInfo.getJavaDesc());
+ }
+ mi.returnVoid();
+ mi.computeMaxs();
+ mi.visitEnd();
+ }
+
+ 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);
+ if (fv != null) {
+ fv.visitEnd();
+ }
+ }
+
+ static void addField(final ClassVisitor cv, final String name, final String desc) {
+ final FieldVisitor fv = cv.visitField(ACC_PRIVATE, name, desc, null, null);
+ if (fv != null) {
+ fv.visitEnd();
+ }
+ }
+
+ static void addFunctionField(final ClassVisitor cv, final String name) {
+ addField(cv, name, OBJECT_DESC);
+ }
+
+ static void newFunction(final MethodGenerator mi, final String className, final MemberInfo memInfo, final List<MemberInfo> specs) {
+ final boolean arityFound = (memInfo.getArity() != MemberInfo.DEFAULT_ARITY);
+
+ mi.loadLiteral(memInfo.getName());
+ mi.visitLdcInsn(new Handle(H_INVOKESTATIC, className, memInfo.getJavaName(), memInfo.getJavaDesc()));
+
+ assert specs != null;
+ if (!specs.isEmpty()) {
+ mi.memberInfoArray(className, specs);
+ mi.invokeStatic(SCRIPTFUNCTIONIMPL_TYPE, SCRIPTFUNCTIONIMPL_MAKEFUNCTION, SCRIPTFUNCTIONIMPL_MAKEFUNCTION_SPECS_DESC);
+ } else {
+ mi.invokeStatic(SCRIPTFUNCTIONIMPL_TYPE, SCRIPTFUNCTIONIMPL_MAKEFUNCTION, SCRIPTFUNCTIONIMPL_MAKEFUNCTION_DESC);
+ }
+
+ if (arityFound) {
+ mi.dup();
+ mi.push(memInfo.getArity());
+ mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETARITY, SCRIPTFUNCTION_SETARITY_DESC);
+ }
+
+ }
+
+ static void linkerAddGetterSetter(final MethodGenerator mi, final String className, final MemberInfo memInfo) {
+ final String propertyName = memInfo.getName();
+ mi.loadLocal(0);
+ mi.loadLiteral(propertyName);
+ // setup flags
+ mi.push(memInfo.getAttributes());
+ // setup getter method handle
+ String javaName = GETTER_PREFIX + memInfo.getJavaName();
+ mi.visitLdcInsn(new Handle(H_INVOKEVIRTUAL, className, javaName, getterDesc(memInfo)));
+ // setup setter method handle
+ if (memInfo.isFinal()) {
+ mi.pushNull();
+ } else {
+ javaName = SETTER_PREFIX + memInfo.getJavaName();
+ mi.visitLdcInsn(new Handle(H_INVOKEVIRTUAL, className, javaName, setterDesc(memInfo)));
+ }
+ mi.invokeStatic(LOOKUP_TYPE, LOOKUP_NEWPROPERTY, LOOKUP_NEWPROPERTY_DESC);
+ mi.storeLocal(0);
+ }
+
+ static void linkerAddGetterSetter(final MethodGenerator mi, final String className, final MemberInfo getter, final MemberInfo setter) {
+ final String propertyName = getter.getName();
+ mi.loadLocal(0);
+ mi.loadLiteral(propertyName);
+ // setup flags
+ mi.push(getter.getAttributes());
+ // setup getter method handle
+ mi.visitLdcInsn(new Handle(H_INVOKESTATIC, className,
+ getter.getJavaName(), getter.getJavaDesc()));
+ // setup setter method handle
+ if (setter == null) {
+ mi.pushNull();
+ } else {
+ mi.visitLdcInsn(new Handle(H_INVOKESTATIC, className,
+ setter.getJavaName(), setter.getJavaDesc()));
+ }
+ mi.invokeStatic(LOOKUP_TYPE, LOOKUP_NEWPROPERTY, LOOKUP_NEWPROPERTY_DESC);
+ mi.storeLocal(0);
+ }
+
+ static ScriptClassInfo getScriptClassInfo(final String fileName) throws IOException {
+ try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fileName))) {
+ return getScriptClassInfo(new ClassReader(bis));
+ }
+ }
+
+ static ScriptClassInfo getScriptClassInfo(final byte[] classBuf) {
+ return getScriptClassInfo(new ClassReader(classBuf));
+ }
+
+ private static ScriptClassInfo getScriptClassInfo(final ClassReader reader) {
+ final ScriptClassInfoCollector scic = new ScriptClassInfoCollector();
+ reader.accept(scic, 0);
+ return scic.getScriptClassInfo();
+ }
+}
diff --git a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java
new file mode 100644
index 00000000..2491e630
--- /dev/null
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2010, 2012, 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.tools.nasgen;
+
+import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
+import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER;
+import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC;
+import static jdk.internal.org.objectweb.asm.Opcodes.V1_7;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.CONSTRUCTOR_SUFFIX;
+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.OBJECT_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPE;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_SETCONSTRUCTOR;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_TYPE;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_INIT_DESC3;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_INIT_DESC4;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_TYPE;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_TYPE;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_INIT_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_TYPE;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.List;
+import jdk.internal.org.objectweb.asm.Handle;
+
+/**
+ * This class generates constructor class for a @ClassInfo annotated class.
+ *
+ */
+public class ConstructorGenerator extends ClassGenerator {
+ private final ScriptClassInfo scriptClassInfo;
+ private final String className;
+ private final MemberInfo constructor;
+ private final int memberCount;
+ private final List<MemberInfo> specs;
+
+ ConstructorGenerator(final ScriptClassInfo sci) {
+ this.scriptClassInfo = sci;
+
+ this.className = scriptClassInfo.getConstructorClassName();
+ this.constructor = scriptClassInfo.getConstructor();
+ this.memberCount = scriptClassInfo.getConstructorMemberCount();
+ this.specs = scriptClassInfo.getSpecializedConstructors();
+ }
+
+ byte[] getClassBytes() {
+ // new class extensing from ScriptObject
+ final String superClass = (constructor != null)? SCRIPTFUNCTIONIMPL_TYPE : SCRIPTOBJECT_TYPE;
+ cw.visit(V1_7, ACC_PUBLIC | ACC_SUPER, className, null, superClass, null);
+ if (memberCount > 0) {
+ // add fields
+ emitFields();
+ // add <clinit>
+ emitStaticInitializer();
+ }
+ // add <init>
+ emitConstructor();
+
+ if (constructor == null) {
+ emitGetClassName(scriptClassInfo.getName());
+ }
+
+ cw.visitEnd();
+ return cw.toByteArray();
+ }
+
+ // --Internals only below this point
+ private void emitFields() {
+ // Introduce "Function" type instance fields for each
+ // constructor @Function in script class and introduce instance
+ // fields for each constructor @Property in the script class.
+ for (MemberInfo memInfo : scriptClassInfo.getMembers()) {
+ if (memInfo.isConstructorFunction()) {
+ addFunctionField(memInfo.getJavaName());
+ memInfo = (MemberInfo)memInfo.clone();
+ memInfo.setJavaDesc(OBJECT_DESC);
+ memInfo.setJavaAccess(ACC_PUBLIC);
+ addGetter(className, memInfo);
+ addSetter(className, memInfo);
+ } else if (memInfo.isConstructorProperty()) {
+ if (memInfo.isStaticFinal()) {
+ addGetter(scriptClassInfo.getJavaName(), memInfo);
+ } else {
+ addField(memInfo.getJavaName(), memInfo.getJavaDesc());
+ memInfo = (MemberInfo)memInfo.clone();
+ memInfo.setJavaAccess(ACC_PUBLIC);
+ addGetter(className, memInfo);
+ addSetter(className, memInfo);
+ }
+ }
+ }
+
+ addMapField();
+ }
+
+ private void emitStaticInitializer() {
+ final MethodGenerator mi = makeStaticInitializer();
+ emitStaticInitPrefix(mi, className);
+
+ for (final MemberInfo memInfo : scriptClassInfo.getMembers()) {
+ if (memInfo.isConstructorFunction() || memInfo.isConstructorProperty()) {
+ linkerAddGetterSetter(mi, className, memInfo);
+ } else if (memInfo.isConstructorGetter()) {
+ final MemberInfo setter = scriptClassInfo.findSetter(memInfo);
+ linkerAddGetterSetter(mi, className, memInfo, setter);
+ }
+ }
+ emitStaticInitSuffix(mi, className);
+ }
+
+ private void emitConstructor() {
+ final MethodGenerator mi = makeConstructor();
+ mi.visitCode();
+ callSuper(mi);
+
+ if (memberCount > 0) {
+ // initialize Function type fields
+ initFunctionFields(mi);
+ // initialize data fields
+ initDataFields(mi);
+ }
+
+ if (constructor != null) {
+ final int arity = constructor.getArity();
+ if (arity != MemberInfo.DEFAULT_ARITY) {
+ mi.loadThis();
+ mi.push(arity);
+ mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETARITY,
+ SCRIPTFUNCTION_SETARITY_DESC);
+ }
+ }
+ mi.returnVoid();
+ mi.computeMaxs();
+ mi.visitEnd();
+ }
+
+ private void loadMap(final MethodGenerator mi) {
+ if (memberCount > 0) {
+ mi.getStatic(className, MAP_FIELD_NAME, MAP_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);
+ }
+ }
+
+ private void callSuper(final MethodGenerator mi) {
+ String superClass, superDesc;
+ mi.loadThis();
+ if (constructor == null) {
+ // call ScriptObject.<init>
+ superClass = SCRIPTOBJECT_TYPE;
+ superDesc = (memberCount > 0) ? SCRIPTOBJECT_INIT_DESC : DEFAULT_INIT_DESC;
+ loadMap(mi);
+ } else {
+ // call Function.<init>
+ superClass = SCRIPTFUNCTIONIMPL_TYPE;
+ superDesc = (memberCount > 0) ? SCRIPTFUNCTIONIMPL_INIT_DESC4 : SCRIPTFUNCTIONIMPL_INIT_DESC3;
+ mi.loadLiteral(constructor.getName());
+ mi.visitLdcInsn(new Handle(H_INVOKESTATIC, scriptClassInfo.getJavaName(), constructor.getJavaName(), constructor.getJavaDesc()));
+ loadMap(mi);
+ mi.memberInfoArray(scriptClassInfo.getJavaName(), specs); //pushes null if specs empty
+ }
+
+ mi.invokeSpecial(superClass, INIT, superDesc);
+ }
+
+ private void initFunctionFields(final MethodGenerator mi) {
+ for (final MemberInfo memInfo : scriptClassInfo.getMembers()) {
+ if (!memInfo.isConstructorFunction()) {
+ continue;
+ }
+ mi.loadThis();
+ newFunction(mi, scriptClassInfo.getJavaName(), memInfo, scriptClassInfo.findSpecializations(memInfo.getJavaName()));
+ mi.putField(className, memInfo.getJavaName(), OBJECT_DESC);
+ }
+ }
+
+ private void initDataFields(final MethodGenerator mi) {
+ for (final MemberInfo memInfo : scriptClassInfo.getMembers()) {
+ if (!memInfo.isConstructorProperty() || memInfo.isFinal()) {
+ continue;
+ }
+ final Object value = memInfo.getValue();
+ if (value != null) {
+ mi.loadThis();
+ mi.loadLiteral(value);
+ mi.putField(className, memInfo.getJavaName(), memInfo.getJavaDesc());
+ } else if (!memInfo.getInitClass().isEmpty()) {
+ final String clazz = memInfo.getInitClass();
+ mi.loadThis();
+ mi.newObject(clazz);
+ mi.dup();
+ mi.invokeSpecial(clazz, INIT, DEFAULT_INIT_DESC);
+ mi.putField(className, memInfo.getJavaName(), memInfo.getJavaDesc());
+ }
+ }
+
+ if (constructor != null) {
+ mi.loadThis();
+ final String protoName = scriptClassInfo.getPrototypeClassName();
+ mi.newObject(protoName);
+ mi.dup();
+ mi.invokeSpecial(protoName, INIT, DEFAULT_INIT_DESC);
+ mi.dup();
+ mi.loadThis();
+ mi.invokeStatic(PROTOTYPEOBJECT_TYPE, PROTOTYPEOBJECT_SETCONSTRUCTOR,
+ PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC);
+ mi.putField(SCRIPTFUNCTION_TYPE, PROTOTYPE, OBJECT_DESC);
+ }
+ }
+
+ /**
+ * Entry point for ConstructorGenerator run separately as an application. Will display
+ * usage. Takes one argument, a class name.
+ * @param args args vector
+ * @throws IOException if class can't be read
+ */
+ public static void main(final String[] args) throws IOException {
+ if (args.length != 1) {
+ System.err.println("Usage: " + ConstructorGenerator.class.getName() + " <class>");
+ System.exit(1);
+ }
+
+ final String className = args[0].replace('.', '/');
+ final ScriptClassInfo sci = getScriptClassInfo(className + ".class");
+ if (sci == null) {
+ System.err.println("No @ScriptClass in " + className);
+ System.exit(2);
+ throw new IOException(); // get rid of warning for sci.verify() below - may be null
+ }
+
+ try {
+ sci.verify();
+ } catch (final Exception e) {
+ System.err.println(e.getMessage());
+ System.exit(3);
+ }
+ final ConstructorGenerator gen = new ConstructorGenerator(sci);
+ try (FileOutputStream fos = new FileOutputStream(className + CONSTRUCTOR_SUFFIX + ".class")) {
+ fos.write(gen.getClassBytes());
+ }
+ }
+}
diff --git a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/Main.java b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/Main.java
new file mode 100644
index 00000000..96e49c1d
--- /dev/null
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/Main.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2010, 2012, 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.tools.nasgen;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
+
+/**
+ * Main class for the "nasgen" tool.
+ *
+ */
+public class Main {
+ private static final boolean DEBUG = Boolean.getBoolean("nasgen.debug");
+
+ private interface ErrorReporter {
+ public void error(String msg);
+ }
+
+ /**
+ * Public entry point for Nasgen if invoked from command line. Nasgen takes three arguments
+ * in order: input directory, package list, output directory
+ *
+ * @param args argument vector
+ */
+ public static void main(final String[] args) {
+ final ErrorReporter reporter = new ErrorReporter() {
+ @Override
+ public void error(final String msg) {
+ Main.error(msg, 1);
+ }
+ };
+ if (args.length == 3) {
+ processAll(args[0], args[1], args[2], reporter);
+ } else {
+ error("Usage: nasgen <input-dir> <package-list> <output-dir>", 1);
+ }
+ }
+
+ private static void processAll(final String in, final String pkgList, final String out, final ErrorReporter reporter) {
+ final File inDir = new File(in);
+ if (!inDir.exists() || !inDir.isDirectory()) {
+ reporter.error(in + " does not exist or not a directory");
+ return;
+ }
+
+ final File outDir = new File(out);
+ if (!outDir.exists() || !outDir.isDirectory()) {
+ reporter.error(out + " does not exist or not a directory");
+ return;
+ }
+
+ final String[] packages = pkgList.split(":");
+ for (String pkg : packages) {
+ pkg = pkg.replace('.', File.separatorChar);
+ final File dir = new File(inDir, pkg);
+ final File[] classes = dir.listFiles();
+ for (final File clazz : classes) {
+ if (clazz.isFile() && clazz.getName().endsWith(".class")) {
+ if (! process(clazz, new File(outDir, pkg), reporter)) {
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ private static boolean process(final File inFile, final File outDir, final ErrorReporter reporter) {
+ try {
+ byte[] buf = new byte[(int)inFile.length()];
+
+ try (FileInputStream fin = new FileInputStream(inFile)) {
+ fin.read(buf);
+ }
+
+ final ScriptClassInfo sci = ClassGenerator.getScriptClassInfo(buf);
+
+ if (sci != null) {
+ try {
+ sci.verify();
+ } catch (final Exception e) {
+ reporter.error(e.getMessage());
+ return false;
+ }
+
+ // create necessary output package dir
+ outDir.mkdirs();
+
+ // instrument @ScriptClass
+ final ClassWriter writer = ClassGenerator.makeClassWriter();
+ final ClassReader reader = new ClassReader(buf);
+ final ScriptClassInstrumentor inst = new ScriptClassInstrumentor(writer, sci);
+ reader.accept(inst, 0);
+ //noinspection UnusedAssignment
+
+ // write instrumented class
+ try (FileOutputStream fos = new FileOutputStream(new File(outDir, inFile.getName()))) {
+ buf = writer.toByteArray();
+ if (DEBUG) {
+ verify(buf);
+ }
+ fos.write(buf);
+ }
+
+ // simple class name without package prefix
+ String simpleName = inFile.getName();
+ simpleName = simpleName.substring(0, simpleName.indexOf(".class"));
+
+ if (sci.getPrototypeMemberCount() > 0) {
+ // generate prototype class
+ final PrototypeGenerator protGen = new PrototypeGenerator(sci);
+ buf = protGen.getClassBytes();
+ if (DEBUG) {
+ verify(buf);
+ }
+ try (FileOutputStream fos = new FileOutputStream(new File(outDir, simpleName + StringConstants.PROTOTYPE_SUFFIX + ".class"))) {
+ fos.write(buf);
+ }
+ }
+
+ if (sci.getConstructorMemberCount() > 0 || sci.getConstructor() != null) {
+ // generate constructor class
+ final ConstructorGenerator consGen = new ConstructorGenerator(sci);
+ buf = consGen.getClassBytes();
+ if (DEBUG) {
+ verify(buf);
+ }
+ try (FileOutputStream fos = new FileOutputStream(new File(outDir, simpleName + StringConstants.CONSTRUCTOR_SUFFIX + ".class"))) {
+ fos.write(buf);
+ }
+ }
+ }
+ return true;
+ } catch (final IOException | RuntimeException e) {
+ if (DEBUG) {
+ e.printStackTrace(System.err);
+ }
+ reporter.error(e.getMessage());
+
+ return false;
+ }
+ }
+
+ private static void verify(final byte[] buf) {
+ final ClassReader cr = new ClassReader(buf);
+ CheckClassAdapter.verify(cr, false, new PrintWriter(System.err));
+ }
+
+ private static void error(final String msg, final int exitCode) {
+ System.err.println(msg);
+ System.exit(exitCode);
+ }
+}
diff --git a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java
new file mode 100644
index 00000000..62e8de2a
--- /dev/null
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 2010, 2012, 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.tools.nasgen;
+
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_ARRAY_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC;
+
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.internal.org.objectweb.asm.Type;
+import jdk.nashorn.internal.objects.annotations.Where;
+
+/**
+ * Details about a Java method or field annotated with any of the field/method
+ * annotations from the jdk.nashorn.internal.objects.annotations package.
+ */
+public final class MemberInfo implements Cloneable {
+ /**
+ * The different kinds of available class annotations
+ */
+ public static enum Kind {
+ /** This is a script class */
+ SCRIPT_CLASS,
+ /** This is a constructor */
+ CONSTRUCTOR,
+ /** This is a function */
+ FUNCTION,
+ /** This is a getter */
+ GETTER,
+ /** This is a setter */
+ SETTER,
+ /** This is a property */
+ PROPERTY,
+ /** This is a specialized version of a function */
+ SPECIALIZED_FUNCTION,
+ /** This is a specialized version of a constructor */
+ SPECIALIZED_CONSTRUCTOR
+ }
+
+ // keep in sync with jdk.nashorn.internal.objects.annotations.Attribute
+ static final int DEFAULT_ATTRIBUTES = 0x0;
+
+ static final int DEFAULT_ARITY = -2;
+
+ // the kind of the script annotation - one of the above constants
+ private MemberInfo.Kind kind;
+ // script property name
+ private String name;
+ // script property attributes
+ private int attributes;
+ // name of the java member
+ private String javaName;
+ // type descriptor of the java member
+ private String javaDesc;
+ // access bits of the Java field or method
+ private int javaAccess;
+ // initial value for static @Property fields
+ private Object value;
+ // class whose object is created to fill property value
+ private String initClass;
+ // arity of the Function or Constructor
+ private int arity;
+
+ private Where where;
+
+ /**
+ * @return the kind
+ */
+ public Kind getKind() {
+ return kind;
+ }
+
+ /**
+ * @param kind the kind to set
+ */
+ public void setKind(final Kind kind) {
+ this.kind = kind;
+ }
+
+ /**
+ * @return the name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @param name the name to set
+ */
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ /**
+ * @return the attributes
+ */
+ public int getAttributes() {
+ return attributes;
+ }
+
+ /**
+ * @param attributes the attributes to set
+ */
+ public void setAttributes(final int attributes) {
+ this.attributes = attributes;
+ }
+
+ /**
+ * @return the javaName
+ */
+ public String getJavaName() {
+ return javaName;
+ }
+
+ /**
+ * @param javaName the javaName to set
+ */
+ public void setJavaName(final String javaName) {
+ this.javaName = javaName;
+ }
+
+ /**
+ * @return the javaDesc
+ */
+ public String getJavaDesc() {
+ return javaDesc;
+ }
+
+ void setJavaDesc(final String javaDesc) {
+ this.javaDesc = javaDesc;
+ }
+
+ int getJavaAccess() {
+ return javaAccess;
+ }
+
+ void setJavaAccess(final int access) {
+ this.javaAccess = access;
+ }
+
+ Object getValue() {
+ return value;
+ }
+
+ void setValue(final Object value) {
+ this.value = value;
+ }
+
+ Where getWhere() {
+ return where;
+ }
+
+ void setWhere(final Where where) {
+ this.where = where;
+ }
+
+ boolean isFinal() {
+ return (javaAccess & Opcodes.ACC_FINAL) != 0;
+ }
+
+ boolean isStatic() {
+ return (javaAccess & Opcodes.ACC_STATIC) != 0;
+ }
+
+ boolean isStaticFinal() {
+ return isStatic() && isFinal();
+ }
+
+ boolean isInstanceGetter() {
+ return kind == Kind.GETTER && where == Where.INSTANCE;
+ }
+
+ /**
+ * Check whether this MemberInfo is a getter that resides in the instance
+ * @return true if instance setter
+ */
+ boolean isInstanceSetter() {
+ return kind == Kind.SETTER && where == Where.INSTANCE;
+ }
+
+ boolean isInstanceProperty() {
+ return kind == Kind.PROPERTY && where == Where.INSTANCE;
+ }
+
+ boolean isInstanceFunction() {
+ return kind == Kind.FUNCTION && where == Where.INSTANCE;
+ }
+
+ boolean isPrototypeGetter() {
+ return kind == Kind.GETTER && where == Where.PROTOTYPE;
+ }
+
+ boolean isPrototypeSetter() {
+ return kind == Kind.SETTER && where == Where.PROTOTYPE;
+ }
+
+ boolean isPrototypeProperty() {
+ return kind == Kind.PROPERTY && where == Where.PROTOTYPE;
+ }
+
+ boolean isPrototypeFunction() {
+ return kind == Kind.FUNCTION && where == Where.PROTOTYPE;
+ }
+
+ boolean isConstructorGetter() {
+ return kind == Kind.GETTER && where == Where.CONSTRUCTOR;
+ }
+
+ boolean isConstructorSetter() {
+ return kind == Kind.SETTER && where == Where.CONSTRUCTOR;
+ }
+
+ boolean isConstructorProperty() {
+ return kind == Kind.PROPERTY && where == Where.CONSTRUCTOR;
+ }
+
+ boolean isConstructorFunction() {
+ return kind == Kind.FUNCTION && where == Where.CONSTRUCTOR;
+ }
+
+ boolean isConstructor() {
+ return kind == Kind.CONSTRUCTOR;
+ }
+
+ void verify() {
+ if (kind == Kind.CONSTRUCTOR) {
+ final Type returnType = Type.getReturnType(javaDesc);
+ if (! returnType.toString().equals(OBJECT_DESC)) {
+ error("return value should be of Object type, found" + returnType);
+ }
+ final Type[] argTypes = Type.getArgumentTypes(javaDesc);
+ if (argTypes.length < 2) {
+ error("constructor methods should have at least 2 args");
+ }
+ if (! argTypes[0].equals(Type.BOOLEAN_TYPE)) {
+ error("first argument should be of boolean type, found" + argTypes[0]);
+ }
+ if (! argTypes[1].toString().equals(OBJECT_DESC)) {
+ error("second argument should be of Object type, found" + argTypes[0]);
+ }
+
+ if (argTypes.length > 2) {
+ for (int i = 2; i < argTypes.length - 1; i++) {
+ if (! argTypes[i].toString().equals(OBJECT_DESC)) {
+ error(i + "'th argument should be of Object type, found " + argTypes[i]);
+ }
+ }
+
+ final String lastArgType = argTypes[argTypes.length - 1].toString();
+ final boolean isVarArg = lastArgType.equals(OBJECT_ARRAY_DESC);
+ if (!lastArgType.equals(OBJECT_DESC) && !isVarArg) {
+ error("last argument is neither Object nor Object[] type: " + lastArgType);
+ }
+
+ if (isVarArg && argTypes.length > 3) {
+ error("vararg constructor has more than 3 arguments");
+ }
+ }
+ } else if (kind == Kind.FUNCTION) {
+ final Type returnType = Type.getReturnType(javaDesc);
+ if (! returnType.toString().equals(OBJECT_DESC)) {
+ error("return value should be of Object type, found" + returnType);
+ }
+ final Type[] argTypes = Type.getArgumentTypes(javaDesc);
+ if (argTypes.length < 1) {
+ error("function methods should have at least 1 arg");
+ }
+ if (! argTypes[0].toString().equals(OBJECT_DESC)) {
+ error("first argument should be of Object type, found" + argTypes[0]);
+ }
+
+ if (argTypes.length > 1) {
+ for (int i = 1; i < argTypes.length - 1; i++) {
+ if (! argTypes[i].toString().equals(OBJECT_DESC)) {
+ error(i + "'th argument should be of Object type, found " + argTypes[i]);
+ }
+ }
+
+ final String lastArgType = argTypes[argTypes.length - 1].toString();
+ final boolean isVarArg = lastArgType.equals(OBJECT_ARRAY_DESC);
+ if (!lastArgType.equals(OBJECT_DESC) && !isVarArg) {
+ error("last argument is neither Object nor Object[] type: " + lastArgType);
+ }
+
+ if (isVarArg && argTypes.length > 2) {
+ error("vararg function has more than 2 arguments");
+ }
+ }
+ } else if (kind == Kind.GETTER) {
+ final Type[] argTypes = Type.getArgumentTypes(javaDesc);
+ if (argTypes.length != 1) {
+ error("getter methods should have one argument");
+ }
+ if (! argTypes[0].toString().equals(OBJECT_DESC)) {
+ error("first argument of getter should be of Object type, found: " + argTypes[0]);
+ }
+ if (Type.getReturnType(javaDesc).equals(Type.VOID_TYPE)) {
+ error("return type of getter should not be void");
+ }
+ } else if (kind == Kind.SETTER) {
+ final Type[] argTypes = Type.getArgumentTypes(javaDesc);
+ if (argTypes.length != 2) {
+ error("setter methods should have two arguments");
+ }
+ if (! argTypes[0].toString().equals(OBJECT_DESC)) {
+ error("first argument of setter should be of Object type, found: " + argTypes[0]);
+ }
+ if (!Type.getReturnType(javaDesc).toString().equals("V")) {
+ error("return type of setter should be void, found: " + Type.getReturnType(javaDesc));
+ }
+ }
+ }
+
+ private void error(final String msg) {
+ throw new RuntimeException(javaName + javaDesc + " : " + msg);
+ }
+
+ /**
+ * @return the initClass
+ */
+ String getInitClass() {
+ return initClass;
+ }
+
+ /**
+ * @param initClass the initClass to set
+ */
+ void setInitClass(final String initClass) {
+ this.initClass = initClass;
+ }
+
+ @Override
+ protected Object clone() {
+ try {
+ return super.clone();
+ } catch (final CloneNotSupportedException e) {
+ assert false : "clone not supported " + e;
+ return null;
+ }
+ }
+
+ /**
+ * @return the arity
+ */
+ int getArity() {
+ return arity;
+ }
+
+ /**
+ * @param arity the arity to set
+ */
+ void setArity(final int arity) {
+ this.arity = arity;
+ }
+}
diff --git a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java
new file mode 100644
index 00000000..500b8224
--- /dev/null
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 2010, 2012, 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.tools.nasgen;
+
+import static jdk.internal.org.objectweb.asm.Opcodes.AALOAD;
+import static jdk.internal.org.objectweb.asm.Opcodes.AASTORE;
+import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC;
+import static jdk.internal.org.objectweb.asm.Opcodes.ACONST_NULL;
+import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD;
+import static jdk.internal.org.objectweb.asm.Opcodes.ANEWARRAY;
+import static jdk.internal.org.objectweb.asm.Opcodes.ARETURN;
+import static jdk.internal.org.objectweb.asm.Opcodes.ASM4;
+import static jdk.internal.org.objectweb.asm.Opcodes.ASTORE;
+import static jdk.internal.org.objectweb.asm.Opcodes.BALOAD;
+import static jdk.internal.org.objectweb.asm.Opcodes.BASTORE;
+import static jdk.internal.org.objectweb.asm.Opcodes.BIPUSH;
+import static jdk.internal.org.objectweb.asm.Opcodes.CALOAD;
+import static jdk.internal.org.objectweb.asm.Opcodes.CASTORE;
+import static jdk.internal.org.objectweb.asm.Opcodes.CHECKCAST;
+import static jdk.internal.org.objectweb.asm.Opcodes.DALOAD;
+import static jdk.internal.org.objectweb.asm.Opcodes.DASTORE;
+import static jdk.internal.org.objectweb.asm.Opcodes.DCONST_0;
+import static jdk.internal.org.objectweb.asm.Opcodes.DRETURN;
+import static jdk.internal.org.objectweb.asm.Opcodes.DUP;
+import static jdk.internal.org.objectweb.asm.Opcodes.DUP2;
+import static jdk.internal.org.objectweb.asm.Opcodes.FALOAD;
+import static jdk.internal.org.objectweb.asm.Opcodes.FASTORE;
+import static jdk.internal.org.objectweb.asm.Opcodes.FCONST_0;
+import static jdk.internal.org.objectweb.asm.Opcodes.FRETURN;
+import static jdk.internal.org.objectweb.asm.Opcodes.GETFIELD;
+import static jdk.internal.org.objectweb.asm.Opcodes.GETSTATIC;
+import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC;
+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.INVOKESPECIAL;
+import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC;
+import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
+import static jdk.internal.org.objectweb.asm.Opcodes.IRETURN;
+import static jdk.internal.org.objectweb.asm.Opcodes.ISTORE;
+import static jdk.internal.org.objectweb.asm.Opcodes.LALOAD;
+import static jdk.internal.org.objectweb.asm.Opcodes.LASTORE;
+import static jdk.internal.org.objectweb.asm.Opcodes.LCONST_0;
+import static jdk.internal.org.objectweb.asm.Opcodes.LRETURN;
+import static jdk.internal.org.objectweb.asm.Opcodes.NEW;
+import static jdk.internal.org.objectweb.asm.Opcodes.POP;
+import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD;
+import static jdk.internal.org.objectweb.asm.Opcodes.PUTSTATIC;
+import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
+import static jdk.internal.org.objectweb.asm.Opcodes.SALOAD;
+import static jdk.internal.org.objectweb.asm.Opcodes.SASTORE;
+import static jdk.internal.org.objectweb.asm.Opcodes.SIPUSH;
+import static jdk.internal.org.objectweb.asm.Opcodes.SWAP;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.METHODHANDLE_TYPE;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_METHODHANDLE;
+
+import java.util.List;
+import jdk.internal.org.objectweb.asm.Handle;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Type;
+
+/**
+ * Base class for all method generating classes.
+ *
+ */
+public class MethodGenerator extends MethodVisitor {
+ private final int access;
+ private final String name;
+ private final String descriptor;
+ private final Type returnType;
+ private final Type[] argumentTypes;
+
+ MethodGenerator(final MethodVisitor mv, final int access, final String name, final String descriptor) {
+ super(ASM4, mv);
+ this.access = access;
+ this.name = name;
+ this.descriptor = descriptor;
+ this.returnType = Type.getReturnType(descriptor);
+ this.argumentTypes = Type.getArgumentTypes(descriptor);
+ }
+
+ int getAccess() {
+ return access;
+ }
+
+ final String getName() {
+ return name;
+ }
+
+ final String getDescriptor() {
+ return descriptor;
+ }
+
+ final Type getReturnType() {
+ return returnType;
+ }
+
+ final Type[] getArgumentTypes() {
+ return argumentTypes;
+ }
+
+ /**
+ * Check whether access for this method is static
+ * @return true if static
+ */
+ protected final boolean isStatic() {
+ return (getAccess() & ACC_STATIC) != 0;
+ }
+
+ /**
+ * Check whether this method is a constructor
+ * @return true if constructor
+ */
+ protected final boolean isConstructor() {
+ return "<init>".equals(name);
+ }
+
+ void newObject(final String type) {
+ super.visitTypeInsn(NEW, type);
+ }
+
+ void newObjectArray(final String type) {
+ super.visitTypeInsn(ANEWARRAY, type);
+ }
+
+ void loadThis() {
+ if ((access & ACC_STATIC) != 0) {
+ throw new IllegalStateException("no 'this' inside static method");
+ }
+ super.visitVarInsn(ALOAD, 0);
+ }
+
+ void returnValue() {
+ super.visitInsn(returnType.getOpcode(IRETURN));
+ }
+
+ void returnVoid() {
+ super.visitInsn(RETURN);
+ }
+
+ // load, store
+ void arrayLoad(final Type type) {
+ super.visitInsn(type.getOpcode(IALOAD));
+ }
+
+ void arrayLoad() {
+ super.visitInsn(AALOAD);
+ }
+
+ void arrayStore(final Type type) {
+ super.visitInsn(type.getOpcode(IASTORE));
+ }
+
+ void arrayStore() {
+ super.visitInsn(AASTORE);
+ }
+
+ void loadLiteral(final Object value) {
+ super.visitLdcInsn(value);
+ }
+
+ void classLiteral(final String className) {
+ super.visitLdcInsn(className);
+ }
+
+ void loadLocal(final Type type, final int index) {
+ super.visitVarInsn(type.getOpcode(ILOAD), index);
+ }
+
+ void loadLocal(final int index) {
+ super.visitVarInsn(ALOAD, index);
+ }
+
+ void storeLocal(final Type type, final int index) {
+ super.visitVarInsn(type.getOpcode(ISTORE), index);
+ }
+
+ void storeLocal(final int index) {
+ super.visitVarInsn(ASTORE, index);
+ }
+
+ void checkcast(final String type) {
+ super.visitTypeInsn(CHECKCAST, type);
+ }
+
+ // push constants/literals
+ void pushNull() {
+ super.visitInsn(ACONST_NULL);
+ }
+
+ void push(final int value) {
+ if (value >= -1 && value <= 5) {
+ super.visitInsn(ICONST_0 + value);
+ } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
+ super.visitIntInsn(BIPUSH, value);
+ } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
+ super.visitIntInsn(SIPUSH, value);
+ } else {
+ super.visitLdcInsn(value);
+ }
+ }
+
+ void loadClass(final String className) {
+ super.visitLdcInsn(Type.getObjectType(className));
+ }
+
+ void pop() {
+ super.visitInsn(POP);
+ }
+
+ // various "dups"
+ void dup() {
+ super.visitInsn(DUP);
+ }
+
+ void dup2() {
+ super.visitInsn(DUP2);
+ }
+
+ void swap() {
+ super.visitInsn(SWAP);
+ }
+
+ void dupArrayValue(final int arrayOpcode) {
+ switch (arrayOpcode) {
+ case IALOAD: case FALOAD:
+ case AALOAD: case BALOAD:
+ case CALOAD: case SALOAD:
+ case IASTORE: case FASTORE:
+ case AASTORE: case BASTORE:
+ case CASTORE: case SASTORE:
+ dup();
+ break;
+
+ case LALOAD: case DALOAD:
+ case LASTORE: case DASTORE:
+ dup2();
+ break;
+ default:
+ throw new AssertionError("invalid dup");
+ }
+ }
+
+ void dupReturnValue(final int returnOpcode) {
+ switch (returnOpcode) {
+ case IRETURN:
+ case FRETURN:
+ case ARETURN:
+ super.visitInsn(DUP);
+ return;
+ case LRETURN:
+ case DRETURN:
+ super.visitInsn(DUP2);
+ return;
+ case RETURN:
+ return;
+ default:
+ throw new IllegalArgumentException("not return");
+ }
+ }
+
+ void dupValue(final Type type) {
+ switch (type.getSize()) {
+ case 1:
+ dup();
+ break;
+ case 2:
+ dup2();
+ break;
+ default:
+ throw new AssertionError("invalid dup");
+ }
+ }
+
+ void dupValue(final String desc) {
+ final int typeCode = desc.charAt(0);
+ switch (typeCode) {
+ case '[':
+ case 'L':
+ case 'Z':
+ case 'C':
+ case 'B':
+ case 'S':
+ case 'I':
+ super.visitInsn(DUP);
+ break;
+ case 'J':
+ case 'D':
+ super.visitInsn(DUP2);
+ break;
+ default:
+ throw new RuntimeException("invalid signature");
+ }
+ }
+
+ // push default value of given type desc
+ void defaultValue(final String desc) {
+ final int typeCode = desc.charAt(0);
+ switch (typeCode) {
+ case '[':
+ case 'L':
+ super.visitInsn(ACONST_NULL);
+ break;
+ case 'Z':
+ case 'C':
+ case 'B':
+ case 'S':
+ case 'I':
+ super.visitInsn(ICONST_0);
+ break;
+ case 'J':
+ super.visitInsn(LCONST_0);
+ break;
+ case 'F':
+ super.visitInsn(FCONST_0);
+ break;
+ case 'D':
+ super.visitInsn(DCONST_0);
+ break;
+ default:
+ throw new AssertionError("invalid desc " + desc);
+ }
+ }
+
+ // invokes, field get/sets
+ void invokeVirtual(final String owner, final String method, final String desc) {
+ super.visitMethodInsn(INVOKEVIRTUAL, owner, method, desc);
+ }
+
+ void invokeSpecial(final String owner, final String method, final String desc) {
+ super.visitMethodInsn(INVOKESPECIAL, owner, method, desc);
+ }
+
+ void invokeStatic(final String owner, final String method, final String desc) {
+ super.visitMethodInsn(INVOKESTATIC, owner, method, desc);
+ }
+
+ void putStatic(final String owner, final String field, final String desc) {
+ super.visitFieldInsn(PUTSTATIC, owner, field, desc);
+ }
+
+ void getStatic(final String owner, final String field, final String desc) {
+ super.visitFieldInsn(GETSTATIC, owner, field, desc);
+ }
+
+ void putField(final String owner, final String field, final String desc) {
+ super.visitFieldInsn(PUTFIELD, owner, field, desc);
+ }
+
+ void getField(final String owner, final String field, final String desc) {
+ super.visitFieldInsn(GETFIELD, owner, field, desc);
+ }
+
+ void memberInfoArray(final String className, final List<MemberInfo> mis) {
+ if (mis.isEmpty()) {
+ pushNull();
+ return;
+ }
+
+ int pos = 0;
+ push(mis.size());
+ newObjectArray(METHODHANDLE_TYPE);
+ for (final MemberInfo mi : mis) {
+ dup();
+ push(pos++);
+ visitLdcInsn(new Handle(H_INVOKESTATIC, className, mi.getJavaName(), mi.getJavaDesc()));
+ arrayStore(TYPE_METHODHANDLE);
+ }
+ }
+
+ void computeMaxs() {
+ // These values are ignored as we create class writer
+ // with ClassWriter.COMPUTE_MAXS flag.
+ super.visitMaxs(Short.MAX_VALUE, Short.MAX_VALUE);
+ }
+
+ // debugging support - print calls
+ void println(final String msg) {
+ super.visitFieldInsn(GETSTATIC,
+ "java/lang/System",
+ "out",
+ "Ljava/io/PrintStream;");
+ super.visitLdcInsn(msg);
+ super.visitMethodInsn(INVOKEVIRTUAL,
+ "java/io/PrintStream",
+ "println",
+ "(Ljava/lang/String;)V");
+ }
+
+ // print the object on the top of the stack
+ void printObject() {
+ super.visitFieldInsn(GETSTATIC,
+ "java/lang/System",
+ "out",
+ "Ljava/io/PrintStream;");
+ super.visitInsn(SWAP);
+ super.visitMethodInsn(INVOKEVIRTUAL,
+ "java/io/PrintStream",
+ "println",
+ "(Ljava/lang/Object;)V");
+ }
+}
diff --git a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/NullVisitor.java b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/NullVisitor.java
new file mode 100644
index 00000000..7f585c03
--- /dev/null
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/NullVisitor.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2010, 2012, 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.tools.nasgen;
+
+import jdk.internal.org.objectweb.asm.AnnotationVisitor;
+import jdk.internal.org.objectweb.asm.ClassVisitor;
+import jdk.internal.org.objectweb.asm.FieldVisitor;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+
+/**
+ * A visitor that does nothing on visitXXX calls.
+ *
+ */
+public class NullVisitor extends ClassVisitor {
+ NullVisitor() {
+ super(Opcodes.ASM4);
+ }
+
+ @Override
+ public MethodVisitor visitMethod(
+ final int access,
+ final String name,
+ final String desc,
+ final String signature,
+ final String[] exceptions) {
+ return new MethodVisitor(Opcodes.ASM4) {
+ @Override
+ public AnnotationVisitor visitAnnotationDefault() {
+ return new NullAnnotationVisitor();
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+ return new NullAnnotationVisitor();
+ }
+ };
+ }
+
+ @Override
+ public FieldVisitor visitField(
+ final int access,
+ final String name,
+ final String desc,
+ final String signature,
+ final Object value) {
+ return new FieldVisitor(Opcodes.ASM4) {
+ @Override
+ public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+ return new NullAnnotationVisitor();
+ }
+ };
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
+ return new NullAnnotationVisitor();
+ }
+
+ private static class NullAnnotationVisitor extends AnnotationVisitor {
+ NullAnnotationVisitor() {
+ super(Opcodes.ASM4);
+ }
+ }
+}
diff --git a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java
new file mode 100644
index 00000000..a8b6e639
--- /dev/null
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2010, 2012, 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.tools.nasgen;
+
+import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
+import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER;
+import static jdk.internal.org.objectweb.asm.Opcodes.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.OBJECT_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_TYPE;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPE_SUFFIX;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_INIT_DESC;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * This class generates prototype class for a @ClassInfo annotated class.
+ *
+ */
+public class PrototypeGenerator extends ClassGenerator {
+ private final ScriptClassInfo scriptClassInfo;
+ private final String className;
+ private final int memberCount;
+
+ PrototypeGenerator(final ScriptClassInfo sci) {
+ this.scriptClassInfo = sci;
+ this.className = scriptClassInfo.getPrototypeClassName();
+ this.memberCount = scriptClassInfo.getPrototypeMemberCount();
+ }
+
+ byte[] getClassBytes() {
+ // new class extensing from ScriptObject
+ cw.visit(V1_7, ACC_PUBLIC | ACC_SUPER, className, null, PROTOTYPEOBJECT_TYPE, null);
+ if (memberCount > 0) {
+ // add fields
+ emitFields();
+ // add <clinit>
+ emitStaticInitializer();
+ }
+ // add <init>
+ emitConstructor();
+
+ // add getClassName()
+ emitGetClassName(scriptClassInfo.getName());
+
+ cw.visitEnd();
+ return cw.toByteArray();
+ }
+
+ // --Internals only below this point
+ private void emitFields() {
+ // introduce "Function" type instance fields for each
+ // prototype @Function in script class info
+ for (MemberInfo memInfo : scriptClassInfo.getMembers()) {
+ if (memInfo.isPrototypeFunction()) {
+ addFunctionField(memInfo.getJavaName());
+ memInfo = (MemberInfo)memInfo.clone();
+ memInfo.setJavaDesc(OBJECT_DESC);
+ addGetter(className, memInfo);
+ addSetter(className, memInfo);
+ } else if (memInfo.isPrototypeProperty()) {
+ if (memInfo.isStaticFinal()) {
+ addGetter(scriptClassInfo.getJavaName(), memInfo);
+ } else {
+ addField(memInfo.getJavaName(), memInfo.getJavaDesc());
+ memInfo = (MemberInfo)memInfo.clone();
+ memInfo.setJavaAccess(ACC_PUBLIC);
+ addGetter(className, memInfo);
+ addSetter(className, memInfo);
+ }
+ }
+ }
+
+ addMapField();
+ }
+
+ private void emitStaticInitializer() {
+ final MethodGenerator mi = makeStaticInitializer();
+ emitStaticInitPrefix(mi, className);
+ for (final MemberInfo memInfo : scriptClassInfo.getMembers()) {
+ if (memInfo.isPrototypeFunction() || memInfo.isPrototypeProperty()) {
+ linkerAddGetterSetter(mi, className, memInfo);
+ } else if (memInfo.isPrototypeGetter()) {
+ final MemberInfo setter = scriptClassInfo.findSetter(memInfo);
+ linkerAddGetterSetter(mi, className, memInfo, setter);
+ }
+ }
+ emitStaticInitSuffix(mi, className);
+ }
+
+ private void emitConstructor() {
+ final MethodGenerator mi = makeConstructor();
+ mi.visitCode();
+ mi.loadThis();
+ if (memberCount > 0) {
+ // call "super(map$)"
+ mi.getStatic(className, MAP_FIELD_NAME, MAP_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);
+ mi.invokeSpecial(PROTOTYPEOBJECT_TYPE, INIT, SCRIPTOBJECT_INIT_DESC);
+ // initialize Function type fields
+ initFunctionFields(mi);
+ } else {
+ // call "super()"
+ mi.invokeSpecial(PROTOTYPEOBJECT_TYPE, INIT, DEFAULT_INIT_DESC);
+ }
+ mi.returnVoid();
+ mi.computeMaxs();
+ mi.visitEnd();
+ }
+
+ private void initFunctionFields(final MethodGenerator mi) {
+ for (final MemberInfo memInfo : scriptClassInfo.getMembers()) {
+ if (! memInfo.isPrototypeFunction()) {
+ continue;
+ }
+ mi.loadThis();
+ newFunction(mi, scriptClassInfo.getJavaName(), memInfo, scriptClassInfo.findSpecializations(memInfo.getJavaName()));
+ mi.putField(className, memInfo.getJavaName(), OBJECT_DESC);
+ }
+ }
+
+ /**
+ * External entry point for PrototypeGenerator if called from the command line
+ *
+ * @param args arguments, takes 1 argument which is the class to process
+ * @throws IOException if class cannot be read
+ */
+ public static void main(final String[] args) throws IOException {
+ if (args.length != 1) {
+ System.err.println("Usage: " + ConstructorGenerator.class.getName() + " <class>");
+ System.exit(1);
+ }
+
+ final String className = args[0].replace('.', '/');
+ final ScriptClassInfo sci = getScriptClassInfo(className + ".class");
+ if (sci == null) {
+ System.err.println("No @ScriptClass in " + className);
+ System.exit(2);
+ throw new AssertionError(); //guard against warning that sci is null below
+ }
+ try {
+ sci.verify();
+ } catch (final Exception e) {
+ System.err.println(e.getMessage());
+ System.exit(3);
+ }
+ final PrototypeGenerator gen = new PrototypeGenerator(sci);
+ try (FileOutputStream fos = new FileOutputStream(className + PROTOTYPE_SUFFIX + ".class")) {
+ fos.write(gen.getClassBytes());
+ }
+ }
+}
diff --git a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfo.java b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfo.java
new file mode 100644
index 00000000..b5e28522
--- /dev/null
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfo.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2010, 2012, 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.tools.nasgen;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import jdk.internal.org.objectweb.asm.Type;
+import jdk.nashorn.internal.objects.annotations.Constructor;
+import jdk.nashorn.internal.objects.annotations.Function;
+import jdk.nashorn.internal.objects.annotations.Getter;
+import jdk.nashorn.internal.objects.annotations.Property;
+import jdk.nashorn.internal.objects.annotations.ScriptClass;
+import jdk.nashorn.internal.objects.annotations.Setter;
+import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
+import jdk.nashorn.internal.objects.annotations.Where;
+import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind;
+
+/**
+ * All annotation information from a class that is annotated with
+ * the annotation com.sun.oracle.objects.annotations.ScriptClass.
+ *
+ */
+public final class ScriptClassInfo {
+ // descriptots for various annotations
+ static final String SCRIPT_CLASS_ANNO_DESC = Type.getDescriptor(ScriptClass.class);
+ static final String CONSTRUCTOR_ANNO_DESC = Type.getDescriptor(Constructor.class);
+ static final String FUNCTION_ANNO_DESC = Type.getDescriptor(Function.class);
+ static final String GETTER_ANNO_DESC = Type.getDescriptor(Getter.class);
+ static final String SETTER_ANNO_DESC = Type.getDescriptor(Setter.class);
+ static final String PROPERTY_ANNO_DESC = Type.getDescriptor(Property.class);
+ static final String WHERE_ENUM_DESC = Type.getDescriptor(Where.class);
+ static final String SPECIALIZED_FUNCTION = Type.getDescriptor(SpecializedFunction.class);
+ static final String SPECIALIZED_CONSTRUCTOR = Type.getDescriptor(SpecializedConstructor.class);
+
+ static final Map<String, Kind> annotations = new HashMap<>();
+
+ static {
+ annotations.put(SCRIPT_CLASS_ANNO_DESC, Kind.SCRIPT_CLASS);
+ annotations.put(FUNCTION_ANNO_DESC, Kind.FUNCTION);
+ annotations.put(CONSTRUCTOR_ANNO_DESC, Kind.CONSTRUCTOR);
+ annotations.put(GETTER_ANNO_DESC, Kind.GETTER);
+ annotations.put(SETTER_ANNO_DESC, Kind.SETTER);
+ annotations.put(PROPERTY_ANNO_DESC, Kind.PROPERTY);
+ annotations.put(SPECIALIZED_FUNCTION, Kind.SPECIALIZED_FUNCTION);
+ annotations.put(SPECIALIZED_CONSTRUCTOR, Kind.SPECIALIZED_CONSTRUCTOR);
+ }
+
+ // name of the script class
+ private String name;
+ // member info for script properties
+ private List<MemberInfo> members = Collections.emptyList();
+ // java class name that is annotated with @ScriptClass
+ private String javaName;
+
+ /**
+ * @return the name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @param name the name to set
+ */
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ /**
+ * @return the members
+ */
+ public List<MemberInfo> getMembers() {
+ return Collections.unmodifiableList(members);
+ }
+
+ /**
+ * @param members the members to set
+ */
+ public void setMembers(final List<MemberInfo> members) {
+ this.members = members;
+ }
+
+ MemberInfo getConstructor() {
+ for (final MemberInfo memInfo : members) {
+ if (memInfo.getKind() == Kind.CONSTRUCTOR) {
+ return memInfo;
+ }
+ }
+ return null;
+ }
+
+ List<MemberInfo> getSpecializedConstructors() {
+ final List<MemberInfo> res = new LinkedList<>();
+ for (final MemberInfo memInfo : members) {
+ if (memInfo.getKind() == Kind.SPECIALIZED_CONSTRUCTOR) {
+ res.add(memInfo);
+ }
+ }
+ return res;
+ }
+
+ int getPrototypeMemberCount() {
+ int count = 0;
+ for (final MemberInfo memInfo : members) {
+ if (memInfo.getWhere() == Where.PROTOTYPE || memInfo.isConstructor()) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ int getConstructorMemberCount() {
+ int count = 0;
+ for (final MemberInfo memInfo : members) {
+ if (memInfo.getWhere() == Where.CONSTRUCTOR) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ int getInstancePropertyCount() {
+ int count = 0;
+ for (final MemberInfo memInfo : members) {
+ if (memInfo.getWhere() == Where.INSTANCE) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ MemberInfo find(final String findJavaName, final String findJavaDesc, final int findAccess) {
+ for (final MemberInfo memInfo : members) {
+ if (memInfo.getJavaName().equals(findJavaName) &&
+ memInfo.getJavaDesc().equals(findJavaDesc) &&
+ memInfo.getJavaAccess() == findAccess) {
+ return memInfo;
+ }
+ }
+ return null;
+ }
+
+ List<MemberInfo> findSpecializations(final String methodName) {
+ final List<MemberInfo> res = new LinkedList<>();
+ for (final MemberInfo memInfo : members) {
+ if (memInfo.getName().equals(methodName) &&
+ memInfo.getKind() == Kind.SPECIALIZED_FUNCTION) {
+ res.add(memInfo);
+ }
+ }
+ return res;
+ }
+
+ MemberInfo findSetter(final MemberInfo getter) {
+ assert getter.getKind() == Kind.GETTER : "getter expected";
+ final String getterName = getter.getName();
+ final Where getterWhere = getter.getWhere();
+ for (final MemberInfo memInfo : members) {
+ if (memInfo.getKind() == Kind.SETTER &&
+ getterName.equals(memInfo.getName()) &&
+ getterWhere == memInfo.getWhere()) {
+ return memInfo;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @return the javaName
+ */
+ public String getJavaName() {
+ return javaName;
+ }
+
+ /**
+ * @param javaName the javaName to set
+ */
+ void setJavaName(final String javaName) {
+ this.javaName = javaName;
+ }
+
+ String getConstructorClassName() {
+ return getJavaName() + StringConstants.CONSTRUCTOR_SUFFIX;
+ }
+
+ String getPrototypeClassName() {
+ return getJavaName() + StringConstants.PROTOTYPE_SUFFIX;
+ }
+
+ void verify() {
+ boolean constructorSeen = false;
+ for (final MemberInfo memInfo : getMembers()) {
+ if (memInfo.isConstructor()) {
+ if (constructorSeen) {
+ error("more than @Constructor method");
+ }
+ constructorSeen = true;
+ }
+ try {
+ memInfo.verify();
+ } catch (final Exception e) {
+ error(e.getMessage());
+ }
+ }
+ }
+
+ private void error(final String msg) throws RuntimeException {
+ throw new RuntimeException(javaName + " : " + msg);
+ }
+}
diff --git a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java
new file mode 100644
index 00000000..43c2bc6c
--- /dev/null
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2010, 2012, 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.tools.nasgen;
+
+import static jdk.nashorn.internal.tools.nasgen.ScriptClassInfo.SCRIPT_CLASS_ANNO_DESC;
+import static jdk.nashorn.internal.tools.nasgen.ScriptClassInfo.WHERE_ENUM_DESC;
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import jdk.internal.org.objectweb.asm.AnnotationVisitor;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassVisitor;
+import jdk.internal.org.objectweb.asm.FieldVisitor;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.nashorn.internal.objects.annotations.Where;
+import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind;
+
+/**
+ * This class collects all @ScriptClass and other annotation information from a
+ * compiled .class file. Enforces that @Function/@Getter/@Setter/@Constructor
+ * methods are declared to be 'static'.
+ */
+public class ScriptClassInfoCollector extends ClassVisitor {
+ private String scriptClassName;
+ private List<MemberInfo> scriptMembers;
+ private String javaClassName;
+
+ ScriptClassInfoCollector(final ClassVisitor visitor) {
+ super(Opcodes.ASM4, visitor);
+ }
+
+ ScriptClassInfoCollector() {
+ this(new NullVisitor());
+ }
+
+ private void addScriptMember(final MemberInfo memInfo) {
+ if (scriptMembers == null) {
+ scriptMembers = new ArrayList<>();
+ }
+ scriptMembers.add(memInfo);
+ }
+
+ @Override
+ public void visit(final int version, final int access, final String name, final String signature,
+ final String superName, final String[] interfaces) {
+ super.visit(version, access, name, signature, superName, interfaces);
+ javaClassName = name;
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
+ final AnnotationVisitor delegateAV = super.visitAnnotation(desc, visible);
+ if (SCRIPT_CLASS_ANNO_DESC.equals(desc)) {
+ return new AnnotationVisitor(Opcodes.ASM4, delegateAV) {
+ @Override
+ public void visit(final String name, final Object value) {
+ if ("value".equals(name)) {
+ scriptClassName = (String) value;
+ }
+ super.visit(name, value);
+ }
+ };
+ }
+
+ return delegateAV;
+ }
+
+ @Override
+ public FieldVisitor visitField(final int fieldAccess, final String fieldName, final String fieldDesc, final String signature, final Object value) {
+ final FieldVisitor delegateFV = super.visitField(fieldAccess, fieldName, fieldDesc, signature, value);
+
+ return new FieldVisitor(Opcodes.ASM4, delegateFV) {
+ @Override
+ public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+ final AnnotationVisitor delegateAV = super.visitAnnotation(descriptor, visible);
+
+ if (ScriptClassInfo.PROPERTY_ANNO_DESC.equals(descriptor)) {
+ final MemberInfo memInfo = new MemberInfo();
+
+ memInfo.setKind(Kind.PROPERTY);
+ memInfo.setJavaName(fieldName);
+ memInfo.setJavaDesc(fieldDesc);
+ memInfo.setJavaAccess(fieldAccess);
+
+ if ((fieldAccess & Opcodes.ACC_STATIC) != 0) {
+ memInfo.setValue(value);
+ }
+
+ addScriptMember(memInfo);
+
+ return new AnnotationVisitor(Opcodes.ASM4, delegateAV) {
+ // These could be "null" if values are not suppiled,
+ // in which case we have to use the default values.
+ private String name;
+ private Integer attributes;
+ private String clazz = "";
+ private Where where;
+
+ @Override
+ public void visit(final String annotationName, final Object annotationValue) {
+ switch (annotationName) {
+ case "name":
+ this.name = (String) annotationValue;
+ break;
+ case "attributes":
+ this.attributes = (Integer) annotationValue;
+ break;
+ case "clazz":
+ this.clazz = (annotationValue == null) ? "" : annotationValue.toString();
+ break;
+ default:
+ break;
+ }
+ super.visit(annotationName, annotationValue);
+ }
+
+ @Override
+ public void visitEnum(final String enumName, final String desc, final String enumValue) {
+ if ("where".equals(enumName) && WHERE_ENUM_DESC.equals(desc)) {
+ this.where = Where.valueOf(enumValue);
+ }
+ super.visitEnum(enumName, desc, enumValue);
+ }
+
+ @Override
+ public void visitEnd() {
+ super.visitEnd();
+ memInfo.setName(name == null ? fieldName : name);
+ memInfo.setAttributes(attributes == null
+ ? MemberInfo.DEFAULT_ATTRIBUTES : attributes);
+ clazz = clazz.replace('.', '/');
+ memInfo.setInitClass(clazz);
+ memInfo.setWhere(where == null? Where.INSTANCE : where);
+ }
+ };
+ }
+
+ return delegateAV;
+ }
+ };
+ }
+
+ private void error(final String javaName, final String javaDesc, final String msg) {
+ throw new RuntimeException(scriptClassName + "." + javaName + javaDesc + " : " + msg);
+ }
+
+ @Override
+ public MethodVisitor visitMethod(final int methodAccess, final String methodName,
+ final String methodDesc, final String signature, final String[] exceptions) {
+
+ final MethodVisitor delegateMV = super.visitMethod(methodAccess, methodName, methodDesc,
+ signature, exceptions);
+
+ return new MethodVisitor(Opcodes.ASM4, delegateMV) {
+
+ @Override
+ public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+ final AnnotationVisitor delegateAV = super.visitAnnotation(descriptor, visible);
+ final Kind annoKind = ScriptClassInfo.annotations.get(descriptor);
+
+ if (annoKind != null) {
+ if ((methodAccess & Opcodes.ACC_STATIC) == 0) {
+ error(methodName, methodDesc, "nasgen method annotations cannot be on instance methods");
+ }
+
+ final MemberInfo memInfo = new MemberInfo();
+
+ memInfo.setKind(annoKind);
+ memInfo.setJavaName(methodName);
+ memInfo.setJavaDesc(methodDesc);
+ memInfo.setJavaAccess(methodAccess);
+
+ addScriptMember(memInfo);
+
+ return new AnnotationVisitor(Opcodes.ASM4, delegateAV) {
+ // These could be "null" if values are not suppiled,
+ // in which case we have to use the default values.
+ private String name;
+ private Integer attributes;
+ private Integer arity;
+ private Where where;
+
+ @Override
+ public void visit(final String annotationName, final Object annotationValue) {
+ switch (annotationName) {
+ case "name":
+ this.name = (String)annotationValue;
+ break;
+ case "attributes":
+ this.attributes = (Integer)annotationValue;
+ break;
+ case "arity":
+ this.arity = (Integer)annotationValue;
+ break;
+ default:
+ break;
+ }
+
+ super.visit(annotationName, annotationValue);
+ }
+
+ @Override
+ public void visitEnum(final String enumName, final String desc, final String enumValue) {
+ if ("where".equals(enumName) && WHERE_ENUM_DESC.equals(desc)) {
+ this.where = Where.valueOf(enumValue);
+ }
+ super.visitEnum(enumName, desc, enumValue);
+ }
+
+ @Override
+ public void visitEnd() {
+ super.visitEnd();
+
+ if (memInfo.getKind() == Kind.CONSTRUCTOR) {
+ memInfo.setName(name == null ? scriptClassName : name);
+ } else {
+ memInfo.setName(name == null ? methodName : name);
+ }
+ memInfo.setAttributes(attributes == null ? MemberInfo.DEFAULT_ATTRIBUTES : attributes);
+
+ memInfo.setArity((arity == null)? MemberInfo.DEFAULT_ARITY : arity);
+ if (where == null) {
+ // by default @Getter/@Setter belongs to INSTANCE
+ // @Function belong to PROTOTYPE.
+ switch (memInfo.getKind()) {
+ case GETTER:
+ case SETTER:
+ where = Where.INSTANCE;
+ break;
+ case SPECIALIZED_CONSTRUCTOR:
+ case CONSTRUCTOR:
+ where = Where.CONSTRUCTOR;
+ break;
+ case FUNCTION:
+ where = Where.PROTOTYPE;
+ break;
+ case SPECIALIZED_FUNCTION:
+ //TODO is this correct
+ default:
+ break;
+ }
+ }
+ memInfo.setWhere(where);
+ }
+ };
+ }
+
+ return delegateAV;
+ }
+ };
+ }
+
+ ScriptClassInfo getScriptClassInfo() {
+ ScriptClassInfo sci = null;
+ if (scriptClassName != null) {
+ sci = new ScriptClassInfo();
+ sci.setName(scriptClassName);
+ if (scriptMembers == null) {
+ scriptMembers = Collections.emptyList();
+ }
+ sci.setMembers(scriptMembers);
+ sci.setJavaName(javaClassName);
+ }
+ return sci;
+ }
+
+ /**
+ * External entry point for ScriptClassInfoCollector if invoked from the command line
+ * @param args argument vector, args contains a class for which to collect info
+ * @throws IOException if there were problems parsing args or class
+ */
+ public static void main(final String[] args) throws IOException {
+ if (args.length != 1) {
+ System.err.println("Usage: " + ScriptClassInfoCollector.class.getName() + " <class>");
+ System.exit(1);
+ }
+
+ args[0] = args[0].replace('.', '/');
+ final ScriptClassInfoCollector scic = new ScriptClassInfoCollector();
+ try (final BufferedInputStream bis = new BufferedInputStream(new FileInputStream(args[0] + ".class"))) {
+ final ClassReader reader = new ClassReader(bis);
+ reader.accept(scic, 0);
+ }
+ final ScriptClassInfo sci = scic.getScriptClassInfo();
+ final PrintStream out = System.out;
+ if (sci != null) {
+ out.println("script class: " + sci.getName());
+ out.println("===================================");
+ for (final MemberInfo memInfo : sci.getMembers()) {
+ out.println("kind : " + memInfo.getKind());
+ out.println("name : " + memInfo.getName());
+ out.println("attributes: " + memInfo.getAttributes());
+ out.println("javaName: " + memInfo.getJavaName());
+ out.println("javaDesc: " + memInfo.getJavaDesc());
+ out.println("where: " + memInfo.getWhere());
+ out.println("=====================================");
+ }
+ } else {
+ out.println(args[0] + " is not a @ScriptClass");
+ }
+ }
+}
diff --git a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java
new file mode 100644
index 00000000..c8e97370
--- /dev/null
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2010, 2012, 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.tools.nasgen;
+
+import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD;
+import static jdk.internal.org.objectweb.asm.Opcodes.DUP;
+import static jdk.internal.org.objectweb.asm.Opcodes.GETSTATIC;
+import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL;
+import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC;
+import static jdk.internal.org.objectweb.asm.Opcodes.NEW;
+import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD;
+import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
+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;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import jdk.internal.org.objectweb.asm.AnnotationVisitor;
+import jdk.internal.org.objectweb.asm.Attribute;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassVisitor;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.FieldVisitor;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
+import jdk.nashorn.internal.objects.annotations.Where;
+import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind;
+
+/**
+ * This class instruments the java class annotated with @ScriptClass.
+ *
+ * Changes done are:
+ *
+ * 1) remove all jdk.nashorn.internal.objects.annotations.* annotations.
+ * 2) static final @Property fields stay here. Other @Property fields moved to
+ * respective classes depending on 'where' value of annotation.
+ * 2) add "Map" type static field named "$map".
+ * 3) add static initializer block to initialize map.
+ */
+
+public class ScriptClassInstrumentor extends ClassVisitor {
+ private final ScriptClassInfo scriptClassInfo;
+ private final int memberCount;
+ private boolean staticInitFound;
+
+ ScriptClassInstrumentor(final ClassVisitor visitor, final ScriptClassInfo sci) {
+ super(Opcodes.ASM4, visitor);
+ if (sci == null) {
+ throw new IllegalArgumentException("Null ScriptClassInfo, is the class annotated?");
+ }
+ this.scriptClassInfo = sci;
+ this.memberCount = scriptClassInfo.getInstancePropertyCount();
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
+ if (ScriptClassInfo.annotations.containsKey(desc)) {
+ // ignore @ScriptClass
+ return null;
+ }
+
+ return super.visitAnnotation(desc, visible);
+ }
+
+ @Override
+ public FieldVisitor visitField(final int fieldAccess, final String fieldName,
+ final String fieldDesc, final String signature, final Object value) {
+ final MemberInfo memInfo = scriptClassInfo.find(fieldName, fieldDesc, fieldAccess);
+ if (memInfo != null && memInfo.getKind() == Kind.PROPERTY &&
+ memInfo.getWhere() != Where.INSTANCE && !memInfo.isStaticFinal()) {
+ // non-instance @Property fields - these have to go elsewhere unless 'static final'
+ return null;
+ }
+
+ final FieldVisitor delegateFV = super.visitField(fieldAccess, fieldName, fieldDesc,
+ signature, value);
+ return new FieldVisitor(Opcodes.ASM4, delegateFV) {
+ @Override
+ public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
+ if (ScriptClassInfo.annotations.containsKey(desc)) {
+ // ignore script field annotations
+ return null;
+ }
+
+ return fv.visitAnnotation(desc, visible);
+ }
+
+ @Override
+ public void visitAttribute(final Attribute attr) {
+ fv.visitAttribute(attr);
+ }
+
+ @Override
+ public void visitEnd() {
+ fv.visitEnd();
+ }
+ };
+ }
+
+ @Override
+ public MethodVisitor visitMethod(final int methodAccess, final String methodName,
+ final String methodDesc, final String signature, final String[] exceptions) {
+
+ final boolean isConstructor = INIT.equals(methodName);
+ final boolean isStaticInit = CLINIT.equals(methodName);
+
+ if (isStaticInit) {
+ staticInitFound = true;
+ }
+
+ final MethodGenerator delegateMV = new MethodGenerator(super.visitMethod(methodAccess, methodName, methodDesc,
+ signature, exceptions), methodAccess, methodName, methodDesc);
+
+ return new MethodVisitor(Opcodes.ASM4, delegateMV) {
+ @Override
+ public void visitInsn(final int opcode) {
+ // call $clinit$ just before return from <clinit>
+ if (isStaticInit && opcode == RETURN) {
+ super.visitMethodInsn(INVOKESTATIC, scriptClassInfo.getJavaName(),
+ $CLINIT$, DEFAULT_INIT_DESC);
+ }
+ super.visitInsn(opcode);
+ }
+
+ @Override
+ 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)) {
+ super.visitFieldInsn(GETSTATIC, scriptClassInfo.getJavaName(),
+ MAP_FIELD_NAME, MAP_DESC);
+ super.visitMethodInsn(INVOKESPECIAL, SCRIPTOBJECT_TYPE, INIT,
+ SCRIPTOBJECT_INIT_DESC);
+
+ if (memberCount > 0) {
+ // initialize @Property fields if needed
+ for (final MemberInfo memInfo : scriptClassInfo.getMembers()) {
+ if (memInfo.isInstanceProperty() && !memInfo.getInitClass().isEmpty()) {
+ final String clazz = memInfo.getInitClass();
+ super.visitVarInsn(ALOAD, 0);
+ super.visitTypeInsn(NEW, clazz);
+ super.visitInsn(DUP);
+ super.visitMethodInsn(INVOKESPECIAL, clazz,
+ INIT, DEFAULT_INIT_DESC);
+ super.visitFieldInsn(PUTFIELD, scriptClassInfo.getJavaName(),
+ memInfo.getJavaName(), memInfo.getJavaDesc());
+ }
+
+ if (memInfo.isInstanceFunction()) {
+ super.visitVarInsn(ALOAD, 0);
+ ClassGenerator.newFunction(delegateMV, scriptClassInfo.getJavaName(), memInfo, scriptClassInfo.findSpecializations(memInfo.getJavaName()));
+ super.visitFieldInsn(PUTFIELD, scriptClassInfo.getJavaName(),
+ memInfo.getJavaName(), OBJECT_DESC);
+ }
+ }
+ }
+ } else {
+ super.visitMethodInsn(opcode, owner, name, desc);
+ }
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
+ if (ScriptClassInfo.annotations.containsKey(desc)) {
+ // ignore script method annotations
+ return null;
+ }
+ return super.visitAnnotation(desc, visible);
+ }
+ };
+ }
+
+ @Override
+ public void visitEnd() {
+ emitFields();
+ emitStaticInitializer();
+ emitGettersSetters();
+ super.visitEnd();
+ }
+
+ private void emitFields() {
+ // introduce "Function" type instance fields for each
+ // instance @Function in script class info
+ final String className = scriptClassInfo.getJavaName();
+ for (MemberInfo memInfo : scriptClassInfo.getMembers()) {
+ if (memInfo.isInstanceFunction()) {
+ ClassGenerator.addFunctionField(cv, memInfo.getJavaName());
+ memInfo = (MemberInfo)memInfo.clone();
+ memInfo.setJavaDesc(OBJECT_DESC);
+ ClassGenerator.addGetter(cv, className, memInfo);
+ ClassGenerator.addSetter(cv, className, memInfo);
+ }
+ }
+ ClassGenerator.addMapField(this);
+ }
+
+ void emitGettersSetters() {
+ if (memberCount > 0) {
+ for (final MemberInfo memInfo : scriptClassInfo.getMembers()) {
+ final String className = scriptClassInfo.getJavaName();
+ if (memInfo.isInstanceProperty()) {
+ ClassGenerator.addGetter(cv, className, memInfo);
+ if (! memInfo.isFinal()) {
+ ClassGenerator.addSetter(cv, className, memInfo);
+ }
+ }
+ }
+ }
+ }
+
+ private void emitStaticInitializer() {
+ final String className = scriptClassInfo.getJavaName();
+ if (! staticInitFound) {
+ // no user written <clinit> and so create one
+ final MethodVisitor mv = ClassGenerator.makeStaticInitializer(this);
+ mv.visitCode();
+ mv.visitInsn(RETURN);
+ mv.visitMaxs(Short.MAX_VALUE, 0);
+ mv.visitEnd();
+ }
+ // Now generate $clinit$
+ final MethodGenerator mi = ClassGenerator.makeStaticInitializer(this, $CLINIT$);
+ ClassGenerator.emitStaticInitPrefix(mi, className);
+ if (memberCount > 0) {
+ for (final MemberInfo memInfo : scriptClassInfo.getMembers()) {
+ if (memInfo.isInstanceProperty() || memInfo.isInstanceFunction()) {
+ ClassGenerator.linkerAddGetterSetter(mi, className, memInfo);
+ } else if (memInfo.isInstanceGetter()) {
+ final MemberInfo setter = scriptClassInfo.findSetter(memInfo);
+ ClassGenerator.linkerAddGetterSetter(mi, className, memInfo, setter);
+ }
+ }
+ }
+ ClassGenerator.emitStaticInitSuffix(mi, className);
+ }
+
+ /**
+ * External entry point for ScriptClassInfoCollector if run from the command line
+ *
+ * @param args arguments - one argument is needed, the name of the class to collect info from
+ *
+ * @throws IOException if there are problems reading class
+ */
+ public static void main(final String[] args) throws IOException {
+ if (args.length != 1) {
+ System.err.println("Usage: " + ScriptClassInfoCollector.class.getName() + " <class>");
+ System.exit(1);
+ }
+
+ final String fileName = args[0].replace('.', '/') + ".class";
+ final ScriptClassInfo sci = ClassGenerator.getScriptClassInfo(fileName);
+ if (sci == null) {
+ System.err.println("No @ScriptClass in " + fileName);
+ System.exit(2);
+ throw new AssertionError(); //guard against warning that sci is null below
+ }
+
+ try {
+ sci.verify();
+ } catch (final Exception e) {
+ System.err.println(e.getMessage());
+ System.exit(3);
+ }
+
+ final ClassWriter writer = ClassGenerator.makeClassWriter();
+ try (final BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fileName))) {
+ final ClassReader reader = new ClassReader(bis);
+ final CheckClassAdapter checker = new CheckClassAdapter(writer);
+ final ScriptClassInstrumentor instr = new ScriptClassInstrumentor(checker, sci);
+ reader.accept(instr, 0);
+ }
+
+ try (FileOutputStream fos = new FileOutputStream(fileName)) {
+ fos.write(writer.toByteArray());
+ }
+ }
+}
diff --git a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java
new file mode 100644
index 00000000..06032733
--- /dev/null
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2010, 2012, 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.tools.nasgen;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.reflect.Method;
+import jdk.internal.org.objectweb.asm.Type;
+import jdk.nashorn.internal.objects.PrototypeObject;
+import jdk.nashorn.internal.objects.ScriptFunctionImpl;
+import jdk.nashorn.internal.runtime.PropertyMap;
+import jdk.nashorn.internal.runtime.ScriptFunction;
+import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.linker.Lookup;
+
+/**
+ * String constants used for code generation/instrumentation.
+ */
+@SuppressWarnings("javadoc")
+public interface StringConstants {
+ 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);
+
+ // Nashorn types
+ static final Type TYPE_LOOKUP = Type.getType(Lookup.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);
+ static final Type TYPE_SCRIPTFUNCTIONIMPL = Type.getType(ScriptFunctionImpl.class);
+ static final Type TYPE_SCRIPTOBJECT = Type.getType(ScriptObject.class);
+
+ static final String PROTOTYPE = "prototype";
+ 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 $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);
+
+ 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 SCRIPTFUNCTION_TYPE = TYPE_SCRIPTFUNCTION.getInternalName();
+ 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 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);
+ 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 GETTER_PREFIX = "G$";
+ static final String SETTER_PREFIX = "S$";
+
+ // ScriptObject.getClassName() method.
+ static final String GET_CLASS_NAME = "getClassName";
+ static final String GET_CLASS_NAME_DESC = Type.getMethodDescriptor(TYPE_STRING);
+}