aboutsummaryrefslogtreecommitdiff
path: root/src/jdk/nashorn/internal/codegen/TypeMap.java
blob: 11efce1a3dbcc1661a3524afc2a6f1cf1ff7a72c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/*
 * Copyright (c) 2010-2014, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package jdk.nashorn.internal.codegen;

import java.lang.invoke.MethodType;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.runtime.ScriptFunction;

/**
 * A data structure that maps one or several function nodes (by their unique id:s, not by
 * the FunctionNode object itself, due to copy on write changing it several times through
 * code generation.
 */
public class TypeMap {
    private final Map<Integer, Type[]> paramTypeMap  = new HashMap<>();
    private final Map<Integer, Type>   returnTypeMap = new HashMap<>();
    private final boolean needsCallee;

    /**
     * Constructor
     * @param functionNodeId function node id
     * @param type           method type found at runtime corresponding to parameter guess
     * @param needsCallee    does the function using this type map need a callee
     */
    public TypeMap(final int functionNodeId, final MethodType type, final boolean needsCallee) {
        final Type[] types = new Type[type.parameterCount()];
        int pos = 0;
        for (final Class<?> p : type.parameterArray()) {
            types[pos++] = Type.typeFor(p);
        }
        paramTypeMap.put(functionNodeId, types);
        returnTypeMap.put(functionNodeId, Type.typeFor(type.returnType()));

        this.needsCallee = needsCallee;
    }

    /**
     * Returns the array of parameter types for a particular function node
     * @param functionNodeId the ID of the function node
     * @return an array of parameter types
     * @throws NoSuchElementException if the type map has no mapping for the requested function
     */
    public Type[] getParameterTypes(final int functionNodeId) {
        final Type[] paramTypes = paramTypeMap.get(functionNodeId);
        if (paramTypes == null) {
            throw new NoSuchElementException(Integer.toString(functionNodeId));
        }
        return paramTypes.clone();
    }

    MethodType getCallSiteType(final FunctionNode functionNode) {
        final Type[] types = paramTypeMap.get(functionNode.getId());
        if (types == null) {
            return null;
        }

        MethodType mt = MethodType.methodType(returnTypeMap.get(functionNode.getId()).getTypeClass());
        if (needsCallee) {
            mt = mt.appendParameterTypes(ScriptFunction.class);
        }

        mt = mt.appendParameterTypes(Object.class); //this

        for (final Type type : types) {
            if (type == null) {
                return null; // not all parameter information is supplied
            }
            mt = mt.appendParameterTypes(type.getTypeClass());
        }

        return mt;
    }

    /**
     * Does the function using this TypeMap need a callee argument. This is used
     * to compute correct param index offsets in {@link jdk.nashorn.internal.codegen.ApplySpecialization}
     * @return true if a callee is needed, false otherwise
     */
    public boolean needsCallee() {
        return needsCallee;
    }

    /**
     * Get the parameter type for this parameter position, or
     * null if now known
     * @param functionNode functionNode
     * @param pos position
     * @return parameter type for this callsite if known
     */
    Type get(final FunctionNode functionNode, final int pos) {
        final Type[] types = paramTypeMap.get(functionNode.getId());
        assert types == null || pos < types.length : "fn = " + functionNode.getId() + " " + "types=" + Arrays.toString(types) + " || pos=" + pos + " >= length=" + types.length + " in " + this;
        if (types != null && pos < types.length) {
            return types[pos];
        }
        return null;
    }

    boolean has(final FunctionNode functionNode) {
        final int id = functionNode.getId();
        final Type[] paramTypes = paramTypeMap.get(id);
        assert (paramTypes == null) == (returnTypeMap.get(id) == null) : "inconsistent param and return types in param map";
        return paramTypes != null;
    }

    @Override
    public String toString() {
        return toString("");
    }

    String toString(final String prefix) {
        final StringBuilder sb = new StringBuilder();

        if (paramTypeMap.isEmpty()) {
            sb.append(prefix).append("\t<empty>");
            return sb.toString();
        }

        for (final Map.Entry<Integer, Type[]> entry : paramTypeMap.entrySet()) {
            final int id = entry.getKey();
            sb.append(prefix).append('\t');
            sb.append("function ").append(id).append('\n');
            sb.append(prefix).append("\t\tparamTypes=");
            if (entry.getValue() == null) {
                sb.append("[]");
            } else {
                sb.append(Arrays.toString(entry.getValue()));
            }
            sb.append('\n');
            sb.append(prefix).append("\t\treturnType=");
            final Type ret = returnTypeMap.get(id);
            sb.append(ret == null ? "N/A" : ret);
            sb.append('\n');
        }

        return sb.toString();
    }
}