1 /* 2 * Copyright (c) 2010, 2014, 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 private final Map<String, byte[]> classBytes; 46 47 /** Constants array. */ 48 private final Object[] constants; 49 50 /** Function initializers */ 51 private final Map<Integer, FunctionInitializer> initializers; 52 53 private static final long serialVersionUID = 2958227232195298340L; 54 55 /** 56 * Constructor. 57 * 58 * @param compilationId compilation id 59 * @param mainClassName main class name 60 * @param classBytes map of class names to class bytes 61 * @param initializers initializer map, id -> FunctionInitializer 62 * @param constants constants array 63 */ 64 public StoredScript(final int compilationId, final String mainClassName, final Map<String, byte[]> classBytes, final Map<Integer, FunctionInitializer> initializers, final Object[] constants) { 65 this.compilationId = compilationId; 66 this.mainClassName = mainClassName; 67 this.classBytes = classBytes; 68 this.constants = constants; 69 this.initializers = initializers; 70 } 71 72 /** 73 * Get the compilation id for this StoredScript 74 * @return compilation id 75 */ 76 public int getCompilationId() { 77 return compilationId; 78 } 79 80 private Map<String, Class<?>> installClasses(final Source source, final CodeInstaller<ScriptEnvironment> installer) { 81 final Map<String, Class<?>> installedClasses = new HashMap<>(); 82 final byte[] mainClassBytes = classBytes.get(mainClassName); 83 final Class<?> mainClass = installer.install(mainClassName, mainClassBytes); 84 85 installedClasses.put(mainClassName, mainClass); 86 87 for (final Map.Entry<String, byte[]> entry : classBytes.entrySet()) { 88 final String className = entry.getKey(); 89 90 if (!className.equals(mainClassName)) { 91 installedClasses.put(className, installer.install(className, entry.getValue())); 92 } 93 } 94 95 installer.initialize(installedClasses.values(), source, constants); 96 return installedClasses; 97 } 98 99 FunctionInitializer installFunction(final RecompilableScriptFunctionData data, final CodeInstaller<ScriptEnvironment> installer) { 100 final Map<String, Class<?>> installedClasses = installClasses(data.getSource(), installer); 101 102 assert initializers != null; 103 assert initializers.size() == 1; 104 final FunctionInitializer initializer = initializers.values().iterator().next(); 105 106 for (int i = 0; i < constants.length; i++) { 107 if (constants[i] instanceof RecompilableScriptFunctionData) { 108 // replace deserialized function data with the ones we already have 109 final RecompilableScriptFunctionData newData = data.getScriptFunctionData(((RecompilableScriptFunctionData) constants[i]).getFunctionNodeId()); 110 assert newData != null; 111 newData.initTransients(data.getSource(), installer); 112 constants[i] = newData; 113 } 114 } 115 116 initializer.setCode(installedClasses.get(initializer.getClassName())); 117 return initializer; 118 } 119 120 /** 121 * Install as script. 122 * 123 * @param source the source 124 * @param installer the installer 125 * @return main script class 126 */ 127 Class<?> installScript(final Source source, final CodeInstaller<ScriptEnvironment> installer) { 128 129 final Map<String, Class<?>> installedClasses = installClasses(source, installer); 130 131 for (final Object constant : constants) { 132 if (constant instanceof RecompilableScriptFunctionData) { 133 final RecompilableScriptFunctionData data = (RecompilableScriptFunctionData) constant; 134 data.initTransients(source, installer); 135 final FunctionInitializer initializer = initializers.get(data.getFunctionNodeId()); 136 if (initializer != null) { 137 initializer.setCode(installedClasses.get(initializer.getClassName())); 138 data.initializeCode(initializer); 139 } 140 } 141 } 142 143 return installedClasses.get(mainClassName); 144 } 145 146 @Override 147 public int hashCode() { 148 int hash = mainClassName.hashCode(); 149 hash = 31 * hash + classBytes.hashCode(); 150 hash = 31 * hash + Arrays.hashCode(constants); 151 return hash; 152 } 153 154 @Override 155 public boolean equals(final Object obj) { 156 if (obj == this) { 157 return true; 158 } 159 if (!(obj instanceof StoredScript)) { 160 return false; 161 } 162 163 final StoredScript cs = (StoredScript) obj; 164 return mainClassName.equals(cs.mainClassName) 165 && classBytes.equals(cs.classBytes) 166 && Arrays.equals(constants, cs.constants); 167 } 168 }