1 /* 2 * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 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 java.io.Serializable; 29 import java.util.Arrays; 30 import java.util.HashMap; 31 import java.util.Map; 32 33 /** 34 * Class representing a persistent compiled script. 35 */ 36 public final class StoredScript implements Serializable { 37 38 /** Compilation id */ 39 private final int compilationId; 40 41 /** Main class name. */ 42 private final String mainClassName; 43 44 /** Map of class names to class bytes. */ 45 @SuppressWarnings("serial") // Not statically typed as Serializable 46 private final Map<String, byte[]> classBytes; 47 48 /** Constants array. */ 49 @SuppressWarnings("serial") // Not statically typed as Serializable 50 private final Object[] constants; 51 52 /** Function initializers */ 53 @SuppressWarnings("serial") // Not statically typed as Serializable 54 private final Map<Integer, FunctionInitializer> initializers; 55 56 private static final long serialVersionUID = 2958227232195298340L; 57 58 /** 59 * Constructor. 60 * 61 * @param compilationId compilation id 62 * @param mainClassName main class name 63 * @param classBytes map of class names to class bytes 64 * @param initializers initializer map, id -> FunctionInitializer 65 * @param constants constants array 66 */ 67 public StoredScript(final int compilationId, final String mainClassName, final Map<String, byte[]> classBytes, final Map<Integer, FunctionInitializer> initializers, final Object[] constants) { 68 this.compilationId = compilationId; 69 this.mainClassName = mainClassName; 70 this.classBytes = classBytes; 71 this.constants = constants; 72 this.initializers = initializers; 73 } 74 75 /** 76 * Get the compilation id for this StoredScript 77 * @return compilation id 78 */ 79 public int getCompilationId() { 80 return compilationId; 81 } 82 83 private Map<String, Class<?>> installClasses(final Source source, final CodeInstaller installer) { 84 final Map<String, Class<?>> installedClasses = new HashMap<>(); 85 final byte[] mainClassBytes = classBytes.get(mainClassName); 86 final Class<?> mainClass = installer.install(mainClassName, mainClassBytes); 87 88 installedClasses.put(mainClassName, mainClass); 89 90 for (final Map.Entry<String, byte[]> entry : classBytes.entrySet()) { 91 final String className = entry.getKey(); 92 93 if (!className.equals(mainClassName)) { 94 installedClasses.put(className, installer.install(className, entry.getValue())); 95 } 96 } 97 98 installer.initialize(installedClasses.values(), source, constants); 99 return installedClasses; 100 } 101 102 FunctionInitializer installFunction(final RecompilableScriptFunctionData data, final CodeInstaller installer) { 103 final Map<String, Class<?>> installedClasses = installClasses(data.getSource(), installer); 104 105 assert initializers != null; 106 assert initializers.size() == 1; 107 final FunctionInitializer initializer = initializers.values().iterator().next(); 108 109 for (int i = 0; i < constants.length; i++) { 110 if (constants[i] instanceof RecompilableScriptFunctionData) { 111 // replace deserialized function data with the ones we already have 112 final RecompilableScriptFunctionData newData = data.getScriptFunctionData(((RecompilableScriptFunctionData) constants[i]).getFunctionNodeId()); 113 assert newData != null; 114 newData.initTransients(data.getSource(), installer); 115 constants[i] = newData; 116 } 117 } 118 119 initializer.setCode(installedClasses.get(initializer.getClassName())); 120 return initializer; 121 } 122 123 /** 124 * Install as script. 125 * 126 * @param source the source 127 * @param installer the installer 128 * @return main script class 129 */ 130 Class<?> installScript(final Source source, final CodeInstaller installer) { 131 132 final Map<String, Class<?>> installedClasses = installClasses(source, installer); 133 134 for (final Object constant : constants) { 135 if (constant instanceof RecompilableScriptFunctionData) { 136 final RecompilableScriptFunctionData data = (RecompilableScriptFunctionData) constant; 137 data.initTransients(source, installer); 138 final FunctionInitializer initializer = initializers.get(data.getFunctionNodeId()); 139 if (initializer != null) { 140 initializer.setCode(installedClasses.get(initializer.getClassName())); 141 data.initializeCode(initializer); 142 } 143 } 144 } 145 146 return installedClasses.get(mainClassName); 147 } 148 149 @Override 150 public int hashCode() { 151 int hash = mainClassName.hashCode(); 152 hash = 31 * hash + classBytes.hashCode(); 153 hash = 31 * hash + Arrays.hashCode(constants); 154 return hash; 155 } 156 157 @Override 158 public boolean equals(final Object obj) { 159 if (obj == this) { 160 return true; 161 } 162 if (!(obj instanceof StoredScript)) { 163 return false; 164 } 165 166 final StoredScript cs = (StoredScript) obj; 167 return mainClassName.equals(cs.mainClassName) 168 && classBytes.equals(cs.classBytes) 169 && Arrays.equals(constants, cs.constants); 170 } 171 }