1/*
2 * Copyright (c) 2005, 2015, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24package jdk.test.lib.jittester;
25
26import java.util.ArrayList;
27import java.util.Collection;
28import java.util.HashMap;
29import java.util.Map;
30import java.util.Stack;
31import java.util.stream.Collectors;
32import jdk.test.lib.jittester.types.TypeKlass;
33
34
35public class SymbolTable {
36
37    private static final Stack<HashMap<Type, ArrayList<Symbol>>> SYMBOL_STACK
38            = new Stack<>();
39    private static int VARIABLE_NUMBER = 0;
40    private static int FUNCTION_NUMBER = 0;
41
42    private static void initExternalSymbols() {
43
44        String classList = ProductionParams.addExternalSymbols.value();
45        if (classList.equals("all")) {
46            TypeList.getReferenceTypes()
47                    .forEach(Type::exportSymbols);
48        } else {
49            String[] splittedList = classList.split(",");
50            for (Type type : TypeList.getReferenceTypes()) {
51                for (String str : splittedList) {
52                    if (type.getName().equals(str)) {
53                        type.exportSymbols();
54                        break;
55                    }
56                }
57            }
58        }
59
60    }
61
62    static {
63        SYMBOL_STACK.push(new HashMap<>());
64        if (!ProductionParams.disableExternalSymbols.value()) {
65            initExternalSymbols();
66        }
67    }
68
69    public static void add(Symbol symbol) {
70        HashMap<Type, ArrayList<Symbol>> vars = SYMBOL_STACK.peek();
71        if (!vars.containsKey(symbol.type)) {
72            vars.put(symbol.type, new ArrayList<>());
73        }
74        vars.get(symbol.type).add(symbol);
75    }
76
77    public static void remove(Symbol symbol) {
78        HashMap<Type, ArrayList<Symbol>> vars = SYMBOL_STACK.peek();
79        if (vars.containsKey(symbol.type)) {
80            ArrayList<Symbol> symbolsOfType = vars.get(symbol.type);
81            symbolsOfType.remove(symbol);
82            if (symbolsOfType.isEmpty()) {
83                vars.remove(symbol.type);
84            }
85        }
86    }
87
88    protected static Collection<Symbol> get(Type type) {
89        HashMap<Type, ArrayList<Symbol>> vars = SYMBOL_STACK.peek();
90        if (vars.containsKey(type)) {
91            return vars.get(type);
92        }
93        return new ArrayList<>();
94    }
95
96    public static Collection<Symbol> get(Type type, Class<?> classToCheck) {
97        HashMap<Type, ArrayList<Symbol>> vars = SYMBOL_STACK.peek();
98        if (vars.containsKey(type)) {
99            return vars.get(type).stream()
100                .filter(classToCheck::isInstance)
101                .collect(Collectors.toList());
102        }
103        return new ArrayList<>();
104    }
105
106    protected static Collection<Symbol> get(TypeKlass typeKlass, Type type,
107            Class<?> classToCheck) {
108        HashMap<Type, ArrayList<Symbol>> vars = SYMBOL_STACK.peek();
109        if (vars.containsKey(type)) {
110            ArrayList<Symbol> result = new ArrayList<>();
111            for (Symbol symbol : vars.get(type)) {
112                if (classToCheck.isInstance(symbol) && typeKlass.equals(symbol.owner)) {
113                    result.add(symbol);
114                }
115            }
116            return result;
117        }
118        return new ArrayList<>();
119    }
120
121    protected static HashMap<Type, ArrayList<Symbol>> getAll() {
122        return SYMBOL_STACK.peek();
123    }
124
125    protected static HashMap<Type, ArrayList<Symbol>> getAll(Class<?> classToCheck) {
126        HashMap<Type, ArrayList<Symbol>> result = new HashMap<>();
127
128        for (Type type : SYMBOL_STACK.peek().keySet()) {
129            ArrayList<Symbol> symbolsOfType = SYMBOL_STACK.peek().get(type);
130            for (Symbol symbol : symbolsOfType) {
131                if (classToCheck.isInstance(symbol)) {
132                    if (!result.containsKey(type)) {
133                        result.put(type, new ArrayList<>());
134                    }
135                    result.get(type).add(symbol);
136                }
137            }
138        }
139
140        return result;
141    }
142
143    protected static HashMap<Type, ArrayList<Symbol>> getAll(TypeKlass typeKlass, Class<?> classToCheck) {
144        HashMap<Type, ArrayList<Symbol>> result = new HashMap<>();
145
146        for (Type type : SYMBOL_STACK.peek().keySet()) {
147            ArrayList<Symbol> symbolsOfType =  SYMBOL_STACK.peek().get(type);
148            for (Symbol symbol : symbolsOfType) {
149                if (classToCheck.isInstance(symbol) && typeKlass.equals(symbol.owner)) {
150                    if (!result.containsKey(type)) {
151                        result.put(type, new ArrayList<>());
152                    }
153                    result.get(type).add(symbol);
154                }
155            }
156        }
157
158        return result;
159    }
160
161    protected static ArrayList<Symbol> getAllCombined() {
162        ArrayList<Symbol> result = new ArrayList<>();
163        for (Type type : SYMBOL_STACK.peek().keySet()) {
164            ArrayList<Symbol> symbolsOfType = SYMBOL_STACK.peek().get(type);
165            for (Symbol symbol : symbolsOfType) {
166                result.add(symbol);
167            }
168        }
169
170        return result;
171    }
172
173    public static ArrayList<Symbol> getAllCombined(Class<?> classToCheck) {
174        ArrayList<Symbol> result = new ArrayList<>();
175        for (Type type : SYMBOL_STACK.peek().keySet()) {
176            ArrayList<Symbol> symbolsOfType = SYMBOL_STACK.peek().get(type);
177            for (Symbol symbol : symbolsOfType) {
178                if (classToCheck.isInstance(symbol)) {
179                    result.add(symbol);
180                }
181            }
182        }
183
184        return result;
185    }
186
187    public static ArrayList<Symbol> getAllCombined(TypeKlass typeKlass, Class<?> classToCheck) {
188        ArrayList<Symbol> result = new ArrayList<>();
189        for (Type type : SYMBOL_STACK.peek().keySet()) {
190            ArrayList<Symbol> symbolsOfType = SYMBOL_STACK.peek().get(type);
191            for (Symbol symbol : symbolsOfType) {
192                if (classToCheck.isInstance(symbol) && typeKlass.equals(symbol.owner)) {
193                    result.add(symbol);
194                }
195            }
196        }
197
198        return result;
199    }
200
201    public static ArrayList<Symbol> getAllCombined(TypeKlass typeKlass) {
202        ArrayList<Symbol> result = new ArrayList<>();
203        for (Type t : SYMBOL_STACK.peek().keySet()) {
204            ArrayList<Symbol> symbolsOfType = SYMBOL_STACK.peek().get(t);
205            for (Symbol symbol : symbolsOfType) {
206                if (typeKlass.equals(symbol.owner)) {
207                    result.add(symbol);
208                }
209            }
210        }
211
212        return result;
213    }
214
215    protected static ArrayList<Symbol> getAllCombined(String name, Class<?> classToCheck) {
216        ArrayList<Symbol> result = new ArrayList<>();
217        for (Type type : SYMBOL_STACK.peek().keySet()) {
218            ArrayList<Symbol> symbolsOfType = SYMBOL_STACK.peek().get(type);
219            for (Symbol symbol : symbolsOfType) {
220                if (classToCheck.isInstance(symbol) && name.equals(symbol.name)) {
221                    result.add(symbol);
222                }
223            }
224        }
225
226        return result;
227    }
228
229    public static Symbol get(String name, Class<?> classToCheck) {
230        for (Type type : SYMBOL_STACK.peek().keySet()) {
231            ArrayList<Symbol> symbolsOfType = SYMBOL_STACK.peek().get(type);
232            for (Symbol symbol : symbolsOfType) {
233                if (classToCheck.isInstance(symbol) && name.equals(symbol.name)) {
234                    return symbol;
235                }
236            }
237        }
238        return null;
239    }
240
241    public static void removeAll() {
242        SYMBOL_STACK.clear();
243        SYMBOL_STACK.push(new HashMap<>());
244        VARIABLE_NUMBER = 0;
245        FUNCTION_NUMBER = 0;
246        if (!ProductionParams.disableExternalSymbols.value()) {
247            initExternalSymbols();
248        }
249    }
250
251    public static void push() {
252        // Do deep cloning..
253        HashMap<Type, ArrayList<Symbol>> prev = SYMBOL_STACK.peek();
254        HashMap<Type, ArrayList<Symbol>> top = new HashMap<>(prev.size());
255        SYMBOL_STACK.push(top);
256        for (Map.Entry<Type, ArrayList<Symbol>> entry : prev.entrySet()) {
257            ArrayList<Symbol> prevArray = entry.getValue();
258            ArrayList<Symbol> topArray = new ArrayList<>(prevArray.size());
259            top.put(entry.getKey(), topArray);
260            for (Symbol symbol : prevArray) {
261                topArray.add(symbol.copy());
262            }
263        }
264    }
265
266    public static void merge() {
267        // Merging means moving element at the top of stack one step down, while removing the
268        // previous element.
269        HashMap<Type, ArrayList<Symbol>> top = SYMBOL_STACK.pop();
270        SYMBOL_STACK.pop();
271        SYMBOL_STACK.push(top);
272    }
273
274    public static void pop() {
275        SYMBOL_STACK.pop();
276    }
277
278    public static int getNextVariableNumber() {
279        return ++VARIABLE_NUMBER;
280    }
281
282    public static int getNextFunctionNumber() {
283        return ++FUNCTION_NUMBER;
284    }
285
286    @Override
287    public String toString() {
288        return SYMBOL_STACK.toString();
289    }
290}
291