12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package jdk.nashorn.internal.runtime;
27
28 import static jdk.nashorn.internal.codegen.CompilerConstants.CONSTANTS;
29 import static jdk.nashorn.internal.codegen.CompilerConstants.CREATE_PROGRAM_FUNCTION;
30 import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE;
31 import static jdk.nashorn.internal.codegen.CompilerConstants.STRICT_MODE;
32 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
33 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
34 import static jdk.nashorn.internal.runtime.Source.sourceFor;
35
36 import java.io.File;
37 import java.io.IOException;
38 import java.io.PrintWriter;
39 import java.lang.invoke.MethodHandle;
40 import java.lang.invoke.MethodHandles;
41 import java.lang.invoke.MethodType;
42 import java.lang.ref.ReferenceQueue;
43 import java.lang.ref.SoftReference;
44 import java.lang.reflect.Field;
45 import java.lang.reflect.Modifier;
46 import java.net.MalformedURLException;
47 import java.net.URL;
48 import java.security.AccessControlContext;
49 import java.security.AccessController;
50 import java.security.CodeSigner;
51 import java.security.CodeSource;
183 } catch (final PrivilegedActionException e) {
184 throw new RuntimeException(e);
185 }
186 }
187
188 @Override
189 public void verify(final byte[] code) {
190 context.verify(code);
191 }
192
193 @Override
194 public long getUniqueScriptId() {
195 return context.getUniqueScriptId();
196 }
197
198 @Override
199 public void storeScript(final String cacheKey, final Source source, final String mainClassName,
200 final Map<String,byte[]> classBytes, final Map<Integer, FunctionInitializer> initializers,
201 final Object[] constants, final int compilationId) {
202 if (context.codeStore != null) {
203 context.codeStore.storeScript(cacheKey, source, mainClassName, classBytes, initializers, constants, compilationId);
204 }
205 }
206
207 @Override
208 public StoredScript loadScript(final Source source, final String functionKey) {
209 if (context.codeStore != null) {
210 return context.codeStore.loadScript(source, functionKey);
211 }
212 return null;
213 }
214 }
215
216 /** Is Context global debug mode enabled ? */
217 public static final boolean DEBUG = Options.getBooleanProperty("nashorn.debug");
218
219 private static final ThreadLocal<Global> currentGlobal = new ThreadLocal<>();
220
221 // in-memory cache for loaded classes
222 private ClassCache classCache;
223
224 // persistent code store
225 private CodeStore codeStore;
226
227 /**
228 * Get the current global scope
229 * @return the current global scope
230 */
446 // if user passed -classpath option, make a class loader with that and set it as
447 // thread context class loader so that script can access classes from that path.
448 final String classPath = options.getString("classpath");
449 if (!env._compile_only && classPath != null && !classPath.isEmpty()) {
450 // make sure that caller can create a class loader.
451 if (sm != null) {
452 sm.checkPermission(new RuntimePermission("createClassLoader"));
453 }
454 this.classPathLoader = NashornLoader.createClassLoader(classPath);
455 } else {
456 this.classPathLoader = null;
457 }
458
459 final int cacheSize = env._class_cache_size;
460 if (cacheSize > 0) {
461 classCache = new ClassCache(cacheSize);
462 }
463
464 if (env._persistent_cache) {
465 try {
466 final String cacheDir = Options.getStringProperty("nashorn.persistent.code.cache", "nashorn_code_cache");
467 codeStore = new CodeStore(this, cacheDir);
468 } catch (final IOException e) {
469 throw new RuntimeException("Error initializing code cache", e);
470 }
471 }
472
473 // print version info if asked.
474 if (env._version) {
475 getErr().println("nashorn " + Version.version());
476 }
477
478 if (env._fullversion) {
479 getErr().println("nashorn full version " + Version.fullVersion());
480 }
481
482 initLoggers();
483 }
484
485
486 /**
487 * Get the class filter for this context
1100
1101 private synchronized Class<?> compile(final Source source, final ErrorManager errMan, final boolean strict) {
1102 // start with no errors, no warnings.
1103 errMan.reset();
1104
1105 Class<?> script = findCachedClass(source);
1106 if (script != null) {
1107 final DebugLogger log = getLogger(Compiler.class);
1108 if (log.isEnabled()) {
1109 log.fine(new RuntimeEvent<>(Level.INFO, source), "Code cache hit for ", source, " avoiding recompile.");
1110 }
1111 return script;
1112 }
1113
1114 StoredScript storedScript = null;
1115 FunctionNode functionNode = null;
1116 final boolean useCodeStore = env._persistent_cache && !env._parse_only && !env._optimistic_types;
1117 final String cacheKey = useCodeStore ? CodeStore.getCacheKey(0, null) : null;
1118
1119 if (useCodeStore) {
1120 storedScript = codeStore.loadScript(source, cacheKey);
1121 }
1122
1123 if (storedScript == null) {
1124 functionNode = new Parser(env, source, errMan, strict, getLogger(Parser.class)).parse();
1125
1126 if (errMan.hasErrors()) {
1127 return null;
1128 }
1129
1130 if (env._print_ast || functionNode.getFlag(FunctionNode.IS_PRINT_AST)) {
1131 getErr().println(new ASTWriter(functionNode));
1132 }
1133
1134 if (env._print_parse || functionNode.getFlag(FunctionNode.IS_PRINT_PARSE)) {
1135 getErr().println(new PrintVisitor(functionNode, true, false));
1136 }
1137 }
1138
1139 if (env._parse_only) {
1140 return null;
1177 @Override
1178 public ScriptLoader run() {
1179 return new ScriptLoader(appLoader, Context.this);
1180 }
1181 }, CREATE_LOADER_ACC_CTXT);
1182 }
1183
1184 private long getUniqueScriptId() {
1185 return uniqueScriptId.getAndIncrement();
1186 }
1187
1188 /**
1189 * Install a previously compiled class from the code cache.
1190 *
1191 * @param storedScript cached script containing class bytes and constants
1192 * @return main script class
1193 */
1194 private static Class<?> install(final StoredScript storedScript, final Source source, final CodeInstaller<ScriptEnvironment> installer) {
1195
1196 final Map<String, Class<?>> installedClasses = new HashMap<>();
1197 final Object[] constants = storedScript.getConstants();
1198 final String mainClassName = storedScript.getMainClassName();
1199 final byte[] mainClassBytes = storedScript.getClassBytes().get(mainClassName);
1200 final Class<?> mainClass = installer.install(mainClassName, mainClassBytes);
1201 final Map<Integer, FunctionInitializer> initialzers = storedScript.getInitializers();
1202
1203 installedClasses.put(mainClassName, mainClass);
1204
1205 for (final Map.Entry<String, byte[]> entry : storedScript.getClassBytes().entrySet()) {
1206 final String className = entry.getKey();
1207 if (className.equals(mainClassName)) {
1208 continue;
1209 }
1210 final byte[] code = entry.getValue();
1211
1212 installedClasses.put(className, installer.install(className, code));
1213 }
1214
1215 installer.initialize(installedClasses.values(), source, constants);
1216
1217 for (final Object constant : constants) {
1218 if (constant instanceof RecompilableScriptFunctionData) {
1219 final RecompilableScriptFunctionData data = (RecompilableScriptFunctionData) constant;
1220 data.initTransients(source, installer);
1221 if (initialzers != null) {
1222 final FunctionInitializer initializer = initialzers.get(data.getFunctionNodeId());
1223 initializer.setCode(installedClasses.get(initializer.getClassName()));
1224 data.initializeCode(initializer);
1225 }
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package jdk.nashorn.internal.runtime;
27
28 import static jdk.nashorn.internal.codegen.CompilerConstants.CONSTANTS;
29 import static jdk.nashorn.internal.codegen.CompilerConstants.CREATE_PROGRAM_FUNCTION;
30 import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE;
31 import static jdk.nashorn.internal.codegen.CompilerConstants.STRICT_MODE;
32 import static jdk.nashorn.internal.runtime.CodeStore.newCodeStore;
33 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
34 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
35 import static jdk.nashorn.internal.runtime.Source.sourceFor;
36
37 import java.io.File;
38 import java.io.IOException;
39 import java.io.PrintWriter;
40 import java.lang.invoke.MethodHandle;
41 import java.lang.invoke.MethodHandles;
42 import java.lang.invoke.MethodType;
43 import java.lang.ref.ReferenceQueue;
44 import java.lang.ref.SoftReference;
45 import java.lang.reflect.Field;
46 import java.lang.reflect.Modifier;
47 import java.net.MalformedURLException;
48 import java.net.URL;
49 import java.security.AccessControlContext;
50 import java.security.AccessController;
51 import java.security.CodeSigner;
52 import java.security.CodeSource;
184 } catch (final PrivilegedActionException e) {
185 throw new RuntimeException(e);
186 }
187 }
188
189 @Override
190 public void verify(final byte[] code) {
191 context.verify(code);
192 }
193
194 @Override
195 public long getUniqueScriptId() {
196 return context.getUniqueScriptId();
197 }
198
199 @Override
200 public void storeScript(final String cacheKey, final Source source, final String mainClassName,
201 final Map<String,byte[]> classBytes, final Map<Integer, FunctionInitializer> initializers,
202 final Object[] constants, final int compilationId) {
203 if (context.codeStore != null) {
204 context.codeStore.store(cacheKey, source, mainClassName, classBytes, initializers, constants, compilationId);
205 }
206 }
207
208 @Override
209 public StoredScript loadScript(final Source source, final String functionKey) {
210 if (context.codeStore != null) {
211 return context.codeStore.load(source, functionKey);
212 }
213 return null;
214 }
215 }
216
217 /** Is Context global debug mode enabled ? */
218 public static final boolean DEBUG = Options.getBooleanProperty("nashorn.debug");
219
220 private static final ThreadLocal<Global> currentGlobal = new ThreadLocal<>();
221
222 // in-memory cache for loaded classes
223 private ClassCache classCache;
224
225 // persistent code store
226 private CodeStore codeStore;
227
228 /**
229 * Get the current global scope
230 * @return the current global scope
231 */
447 // if user passed -classpath option, make a class loader with that and set it as
448 // thread context class loader so that script can access classes from that path.
449 final String classPath = options.getString("classpath");
450 if (!env._compile_only && classPath != null && !classPath.isEmpty()) {
451 // make sure that caller can create a class loader.
452 if (sm != null) {
453 sm.checkPermission(new RuntimePermission("createClassLoader"));
454 }
455 this.classPathLoader = NashornLoader.createClassLoader(classPath);
456 } else {
457 this.classPathLoader = null;
458 }
459
460 final int cacheSize = env._class_cache_size;
461 if (cacheSize > 0) {
462 classCache = new ClassCache(cacheSize);
463 }
464
465 if (env._persistent_cache) {
466 try {
467 codeStore = newCodeStore(this);
468 } catch (final IOException e) {
469 throw new RuntimeException("Error initializing code cache", e);
470 }
471 }
472
473 // print version info if asked.
474 if (env._version) {
475 getErr().println("nashorn " + Version.version());
476 }
477
478 if (env._fullversion) {
479 getErr().println("nashorn full version " + Version.fullVersion());
480 }
481
482 initLoggers();
483 }
484
485
486 /**
487 * Get the class filter for this context
1100
1101 private synchronized Class<?> compile(final Source source, final ErrorManager errMan, final boolean strict) {
1102 // start with no errors, no warnings.
1103 errMan.reset();
1104
1105 Class<?> script = findCachedClass(source);
1106 if (script != null) {
1107 final DebugLogger log = getLogger(Compiler.class);
1108 if (log.isEnabled()) {
1109 log.fine(new RuntimeEvent<>(Level.INFO, source), "Code cache hit for ", source, " avoiding recompile.");
1110 }
1111 return script;
1112 }
1113
1114 StoredScript storedScript = null;
1115 FunctionNode functionNode = null;
1116 final boolean useCodeStore = env._persistent_cache && !env._parse_only && !env._optimistic_types;
1117 final String cacheKey = useCodeStore ? CodeStore.getCacheKey(0, null) : null;
1118
1119 if (useCodeStore) {
1120 storedScript = codeStore.load(source, cacheKey);
1121 }
1122
1123 if (storedScript == null) {
1124 functionNode = new Parser(env, source, errMan, strict, getLogger(Parser.class)).parse();
1125
1126 if (errMan.hasErrors()) {
1127 return null;
1128 }
1129
1130 if (env._print_ast || functionNode.getFlag(FunctionNode.IS_PRINT_AST)) {
1131 getErr().println(new ASTWriter(functionNode));
1132 }
1133
1134 if (env._print_parse || functionNode.getFlag(FunctionNode.IS_PRINT_PARSE)) {
1135 getErr().println(new PrintVisitor(functionNode, true, false));
1136 }
1137 }
1138
1139 if (env._parse_only) {
1140 return null;
1177 @Override
1178 public ScriptLoader run() {
1179 return new ScriptLoader(appLoader, Context.this);
1180 }
1181 }, CREATE_LOADER_ACC_CTXT);
1182 }
1183
1184 private long getUniqueScriptId() {
1185 return uniqueScriptId.getAndIncrement();
1186 }
1187
1188 /**
1189 * Install a previously compiled class from the code cache.
1190 *
1191 * @param storedScript cached script containing class bytes and constants
1192 * @return main script class
1193 */
1194 private static Class<?> install(final StoredScript storedScript, final Source source, final CodeInstaller<ScriptEnvironment> installer) {
1195
1196 final Map<String, Class<?>> installedClasses = new HashMap<>();
1197 final Map<String, byte[]> classBytes = storedScript.getClassBytes();
1198 final Object[] constants = storedScript.getConstants();
1199 final String mainClassName = storedScript.getMainClassName();
1200 final byte[] mainClassBytes = classBytes.get(mainClassName);
1201 final Class<?> mainClass = installer.install(mainClassName, mainClassBytes);
1202 final Map<Integer, FunctionInitializer> initialzers = storedScript.getInitializers();
1203
1204 installedClasses.put(mainClassName, mainClass);
1205
1206 for (final Map.Entry<String, byte[]> entry : classBytes.entrySet()) {
1207 final String className = entry.getKey();
1208 if (className.equals(mainClassName)) {
1209 continue;
1210 }
1211 final byte[] code = entry.getValue();
1212
1213 installedClasses.put(className, installer.install(className, code));
1214 }
1215
1216 installer.initialize(installedClasses.values(), source, constants);
1217
1218 for (final Object constant : constants) {
1219 if (constant instanceof RecompilableScriptFunctionData) {
1220 final RecompilableScriptFunctionData data = (RecompilableScriptFunctionData) constant;
1221 data.initTransients(source, installer);
1222 if (initialzers != null) {
1223 final FunctionInitializer initializer = initialzers.get(data.getFunctionNodeId());
1224 initializer.setCode(installedClasses.get(initializer.getClassName()));
1225 data.initializeCode(initializer);
1226 }
|