CompileUnit.java revision 1177:8e86c58cbb00
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.io.Serializable;
29import java.util.Objects;
30import java.util.Set;
31import java.util.TreeSet;
32import jdk.nashorn.internal.ir.CompileUnitHolder;
33
34/**
35  * Used to track split class compilation. Note that instances of the class are serializable, but all fields are
36  * transient, making the serialized version of the class only useful for tracking the referential topology of other
37  * AST nodes referencing the same or different compile units. We do want to preserve this topology though as
38  * {@link CompileUnitHolder}s in a deserialized AST will undergo reinitialization.
39  */
40public final class CompileUnit implements Comparable<CompileUnit>, Serializable {
41    private static final long serialVersionUID = 1L;
42
43    /** Current class name */
44    private transient final String className;
45
46    /** Current class generator */
47    private transient ClassEmitter classEmitter;
48
49    private transient long weight;
50
51    private transient Class<?> clazz;
52
53    private transient boolean isUsed;
54
55    private static int emittedUnitCount;
56
57    CompileUnit(final String className, final ClassEmitter classEmitter, final long initialWeight) {
58        this.className    = className;
59        this.weight       = initialWeight;
60        this.classEmitter = classEmitter;
61    }
62
63    static Set<CompileUnit> createCompileUnitSet() {
64        return new TreeSet<>();
65    }
66
67    static void increaseEmitCount() {
68        emittedUnitCount++;
69    }
70
71    /**
72     * Get the amount of emitted compile units so far in the system
73     * @return emitted compile unit count
74     */
75    public static int getEmittedUnitCount() {
76        return emittedUnitCount;
77    }
78
79    /**
80     * Check if this compile unit is used
81     * @return true if tagged as in use - i.e active code that needs to be generated
82     */
83    public boolean isUsed() {
84        return isUsed;
85    }
86
87    /**
88     * Check if a compile unit has code, not counting inits and clinits
89     * @return true of if there is "real code" in the compile unit
90     */
91    public boolean hasCode() {
92        return (classEmitter.getMethodCount() - classEmitter.getInitCount() - classEmitter.getClinitCount()) > 0;
93    }
94
95    /**
96     * Tag this compile unit as used
97     */
98    public void setUsed() {
99        this.isUsed = true;
100    }
101
102    /**
103     * Return the class that contains the code for this unit, null if not
104     * generated yet
105     *
106     * @return class with compile unit code
107     */
108    public Class<?> getCode() {
109        return clazz;
110    }
111
112    /**
113     * Set class when it exists. Only accessible from compiler
114     * @param clazz class with code for this compile unit
115     */
116    void setCode(final Class<?> clazz) {
117        Objects.requireNonNull(clazz);
118        this.clazz = clazz;
119        // Revisit this - refactor to avoid null-ed out non-final fields
120        // null out emitter
121        this.classEmitter = null;
122    }
123
124    /**
125     * Add weight to this compile unit
126     * @param w weight to add
127     */
128    void addWeight(final long w) {
129        this.weight += w;
130    }
131
132    /**
133     * Check if this compile unit can hold {@code weight} more units of weight
134     * @param w weight to check if can be added
135     * @return true if weight fits in this compile unit
136     */
137    public boolean canHold(final long w) {
138        return (this.weight + w) < Splitter.SPLIT_THRESHOLD;
139    }
140
141    /**
142     * Get the class emitter for this compile unit
143     * @return class emitter
144     */
145    public ClassEmitter getClassEmitter() {
146        return classEmitter;
147    }
148
149    /**
150     * Get the class name for this compile unit
151     * @return the class name
152     */
153    public String getUnitClassName() {
154        return className;
155    }
156
157    private static String shortName(final String name) {
158        return name == null ? null : name.lastIndexOf('/') == -1 ? name : name.substring(name.lastIndexOf('/') + 1);
159    }
160
161    @Override
162    public String toString() {
163        final String methods = classEmitter != null ? classEmitter.getMethodNames().toString() : "<anon>";
164        return "[CompileUnit className=" + shortName(className) + " weight=" + weight + '/' + Splitter.SPLIT_THRESHOLD + " hasCode=" + methods + ']';
165    }
166
167    @Override
168    public int compareTo(final CompileUnit o) {
169        return className.compareTo(o.className);
170    }
171}
172