CompileUnit.java revision 953:221a84ef44c0
1/*
2 * Copyright (c) 2010, 2013, 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
26package jdk.nashorn.internal.codegen;
27
28import java.util.Collections;
29import java.util.LinkedHashSet;
30import java.util.Set;
31import java.util.TreeSet;
32import jdk.nashorn.internal.ir.FunctionNode;
33import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
34
35/**
36 * Used to track split class compilation.
37 */
38public final class CompileUnit implements Comparable<CompileUnit> {
39    /** Current class name */
40    private final String className;
41
42    /** Current class generator */
43    private ClassEmitter classEmitter;
44
45    private long weight;
46
47    private Class<?> clazz;
48
49    private Set<FunctionInitializer> functionInitializers = new LinkedHashSet<>();
50
51    private static class FunctionInitializer {
52        final RecompilableScriptFunctionData data;
53        final FunctionNode functionNode;
54
55        FunctionInitializer(final RecompilableScriptFunctionData data, final FunctionNode functionNode) {
56            this.data = data;
57            this.functionNode = functionNode;
58        }
59
60        void initializeCode() {
61            data.initializeCode(functionNode);
62        }
63
64        @Override
65        public int hashCode() {
66            return data.hashCode() + 31 * functionNode.hashCode();
67        }
68
69        @Override
70        public boolean equals(final Object obj) {
71            if (obj == null || obj.getClass() != FunctionInitializer.class) {
72                return false;
73            }
74            final FunctionInitializer other = (FunctionInitializer)obj;
75            return data == other.data && functionNode == other.functionNode;
76        }
77    }
78
79    CompileUnit(final String className, final ClassEmitter classEmitter, final long initialWeight) {
80        this.className    = className;
81        this.weight       = initialWeight;
82        this.classEmitter = classEmitter;
83    }
84
85    static Set<CompileUnit> createCompileUnitSet() {
86        return new TreeSet<>();
87    }
88
89    /**
90     * Return the class that contains the code for this unit, null if not
91     * generated yet
92     *
93     * @return class with compile unit code
94     */
95    public Class<?> getCode() {
96        return clazz;
97    }
98
99    /**
100     * Set class when it exists. Only accessible from compiler
101     * @param clazz class with code for this compile unit
102     */
103    void setCode(final Class<?> clazz) {
104        clazz.getClass(); // null check
105        this.clazz = clazz;
106        // Revisit this - refactor to avoid null-ed out non-final fields
107        // null out emitter
108        this.classEmitter = null;
109    }
110
111    void addFunctionInitializer(final RecompilableScriptFunctionData data, final FunctionNode functionNode) {
112        functionInitializers.add(new FunctionInitializer(data, functionNode));
113    }
114
115    /**
116     * Returns true if this compile unit is responsible for initializing the specified function data with specified
117     * function node.
118     * @param data the function data to check
119     * @param functionNode the function node to check
120     * @return true if this unit is responsible for initializing the function data with the function node, otherwise
121     * false
122     */
123    public boolean isInitializing(final RecompilableScriptFunctionData data, final FunctionNode functionNode) {
124        return functionInitializers.contains(new FunctionInitializer(data, functionNode));
125    }
126
127    void initializeFunctionsCode() {
128        for(final FunctionInitializer init : functionInitializers) {
129            init.initializeCode();
130        }
131        functionInitializers = Collections.emptySet();
132    }
133
134    /**
135     * Add weight to this compile unit
136     * @param w weight to add
137     */
138    void addWeight(final long w) {
139        this.weight += w;
140    }
141
142    /**
143     * Get the current weight of the compile unit.
144     * @return the unit's weight
145     */
146    long getWeight() {
147        return weight;
148    }
149
150    /**
151     * Check if this compile unit can hold {@code weight} more units of weight
152     * @param w weight to check if can be added
153     * @return true if weight fits in this compile unit
154     */
155    public boolean canHold(final long w) {
156        return (this.weight + w) < Splitter.SPLIT_THRESHOLD;
157    }
158
159    /**
160     * Get the class emitter for this compile unit
161     * @return class emitter
162     */
163    public ClassEmitter getClassEmitter() {
164        return classEmitter;
165    }
166
167    /**
168     * Get the class name for this compile unit
169     * @return the class name
170     */
171    public String getUnitClassName() {
172        return className;
173    }
174
175    private static String shortName(final String name) {
176        return name.lastIndexOf('/') == -1 ? name : name.substring(name.lastIndexOf('/') + 1);
177    }
178
179    @Override
180    public String toString() {
181        return "[CompileUnit className=" + shortName(className) + " weight=" + weight + '/' + Splitter.SPLIT_THRESHOLD + ']';
182    }
183
184    @Override
185    public int compareTo(final CompileUnit o) {
186        return className.compareTo(o.className);
187    }
188}
189