author | sundar |
Tue, 04 Aug 2015 18:18:54 +0530 | |
changeset 32048 | 8023426b93ab |
parent 27976 | ef54dfb4fc7d |
permissions | -rw-r--r-- |
16147 | 1 |
/* |
16151 | 2 |
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. |
16147 | 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.codegen; |
|
27 |
||
24719 | 28 |
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_OPTIMISTIC; |
29 |
||
16147 | 30 |
import java.util.Arrays; |
31 |
import java.util.EnumSet; |
|
32 |
import jdk.nashorn.internal.codegen.types.Type; |
|
33 |
import jdk.nashorn.internal.ir.Symbol; |
|
34 |
import jdk.nashorn.internal.runtime.ScriptObject; |
|
35 |
||
36 |
/** |
|
37 |
* A scope call or get operation that can be shared by several callsites. This generates a static |
|
38 |
* method that wraps the invokedynamic instructions to get or call scope variables. |
|
39 |
* The rationale for this is that initial linking of invokedynamic callsites is expensive, |
|
40 |
* so by sharing them we can reduce startup overhead and allow very large scripts to run that otherwise wouldn't. |
|
41 |
* |
|
42 |
* <p>Static methods generated by this class expect two parameters in addition to the parameters of the |
|
43 |
* function call: The current scope object and the depth of the target scope relative to the scope argument |
|
44 |
* for when this is known at compile-time (fast-scope access).</p> |
|
45 |
* |
|
46 |
* <p>The second argument may be -1 for non-fast-scope symbols, in which case the scope chain is checked |
|
47 |
* for each call. This may cause callsite invalidation when the shared method is used from different |
|
48 |
* scopes, but such sharing of non-fast scope calls may still be necessary for very large scripts.</p> |
|
49 |
* |
|
50 |
* <p>Scope calls must not be shared between normal callsites and callsites contained in a <tt>with</tt> |
|
51 |
* statement as this condition is not handled by current guards and will cause a runtime error.</p> |
|
52 |
*/ |
|
16240
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16233
diff
changeset
|
53 |
class SharedScopeCall { |
16147 | 54 |
|
55 |
/** Threshold for using shared scope calls with fast scope access. */ |
|
56 |
public static final int FAST_SCOPE_CALL_THRESHOLD = 4; |
|
57 |
/** Threshold for using shared scope calls with slow scope access. */ |
|
58 |
public static final int SLOW_SCOPE_CALL_THRESHOLD = 500; |
|
59 |
/** Threshold for using shared scope gets with fast scope access. */ |
|
60 |
public static final int FAST_SCOPE_GET_THRESHOLD = 200; |
|
61 |
||
62 |
final Type valueType; |
|
63 |
final Symbol symbol; |
|
64 |
final Type returnType; |
|
65 |
final Type[] paramTypes; |
|
66 |
final int flags; |
|
67 |
final boolean isCall; |
|
68 |
private CompileUnit compileUnit; |
|
69 |
private String methodName; |
|
70 |
private String staticSignature; |
|
71 |
||
72 |
/** |
|
73 |
* Constructor. |
|
74 |
* |
|
75 |
* @param symbol the symbol |
|
76 |
* @param valueType the type of the value |
|
77 |
* @param returnType the return type |
|
78 |
* @param paramTypes the function parameter types |
|
79 |
* @param flags the callsite flags |
|
80 |
*/ |
|
81 |
SharedScopeCall(final Symbol symbol, final Type valueType, final Type returnType, final Type[] paramTypes, final int flags) { |
|
82 |
this.symbol = symbol; |
|
83 |
this.valueType = valueType; |
|
84 |
this.returnType = returnType; |
|
85 |
this.paramTypes = paramTypes; |
|
24719 | 86 |
assert (flags & CALLSITE_OPTIMISTIC) == 0; |
16147 | 87 |
this.flags = flags; |
88 |
// If paramTypes is not null this is a call, otherwise it's just a get. |
|
89 |
this.isCall = paramTypes != null; |
|
90 |
} |
|
91 |
||
92 |
@Override |
|
93 |
public int hashCode() { |
|
94 |
return symbol.hashCode() ^ returnType.hashCode() ^ Arrays.hashCode(paramTypes) ^ flags; |
|
95 |
} |
|
96 |
||
97 |
@Override |
|
98 |
public boolean equals(final Object obj) { |
|
99 |
if (obj instanceof SharedScopeCall) { |
|
100 |
final SharedScopeCall c = (SharedScopeCall) obj; |
|
101 |
return symbol.equals(c.symbol) |
|
102 |
&& flags == c.flags |
|
103 |
&& returnType.equals(c.returnType) |
|
104 |
&& Arrays.equals(paramTypes, c.paramTypes); |
|
105 |
} |
|
106 |
return false; |
|
107 |
} |
|
108 |
||
109 |
/** |
|
110 |
* Set the compile unit and method name. |
|
111 |
* @param compileUnit the compile unit |
|
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16210
diff
changeset
|
112 |
* @param methodName the method name |
16147 | 113 |
*/ |
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16210
diff
changeset
|
114 |
protected void setClassAndName(final CompileUnit compileUnit, final String methodName) { |
16147 | 115 |
this.compileUnit = compileUnit; |
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16210
diff
changeset
|
116 |
this.methodName = methodName; |
16147 | 117 |
} |
118 |
||
119 |
/** |
|
120 |
* Generate the invoke instruction for this shared scope call. |
|
121 |
* @param method the method emitter |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
16240
diff
changeset
|
122 |
* @return the method emitter |
16147 | 123 |
*/ |
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
16240
diff
changeset
|
124 |
public MethodEmitter generateInvoke(final MethodEmitter method) { |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
16240
diff
changeset
|
125 |
return method.invokestatic(compileUnit.getUnitClassName(), methodName, getStaticSignature()); |
16147 | 126 |
} |
127 |
||
128 |
/** |
|
129 |
* Generate the method that implements the scope get or call. |
|
130 |
*/ |
|
131 |
protected void generateScopeCall() { |
|
132 |
final ClassEmitter classEmitter = compileUnit.getClassEmitter(); |
|
133 |
final EnumSet<ClassEmitter.Flag> methodFlags = EnumSet.of(ClassEmitter.Flag.STATIC); |
|
134 |
||
135 |
// This method expects two fixed parameters in addition to any parameters that may be |
|
136 |
// passed on to the function: A ScriptObject representing the caller's current scope object, |
|
137 |
// and an int specifying the distance to the target scope containing the symbol we want to |
|
138 |
// access, or -1 if this is not known at compile time (e.g. because of a "with" or "eval"). |
|
139 |
||
140 |
final MethodEmitter method = classEmitter.method(methodFlags, methodName, getStaticSignature()); |
|
141 |
method.begin(); |
|
142 |
||
143 |
// Load correct scope by calling getProto() on the scope argument as often as specified |
|
144 |
// by the second argument. |
|
16240
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16233
diff
changeset
|
145 |
final Label parentLoopStart = new Label("parent_loop_start"); |
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16233
diff
changeset
|
146 |
final Label parentLoopDone = new Label("parent_loop_done"); |
16147 | 147 |
method.load(Type.OBJECT, 0); |
148 |
method.label(parentLoopStart); |
|
149 |
method.load(Type.INT, 1); |
|
150 |
method.iinc(1, -1); |
|
151 |
method.ifle(parentLoopDone); |
|
152 |
method.invoke(ScriptObject.GET_PROTO); |
|
153 |
method._goto(parentLoopStart); |
|
154 |
method.label(parentLoopDone); |
|
155 |
||
24719 | 156 |
assert !isCall || valueType.isObject(); // Callables are always objects |
157 |
// If flags are optimistic, but we're doing a call, remove optimistic flags from the getter, as they obviously |
|
158 |
// only apply to the call. |
|
27976
ef54dfb4fc7d
8066669: dust.js performance regression caused by primitive field conversion
hannesw
parents:
25865
diff
changeset
|
159 |
method.dynamicGet(valueType, symbol.getName(), isCall ? CodeGenerator.nonOptimisticFlags(flags) : flags, isCall, false); |
16147 | 160 |
|
161 |
// If this is a get we're done, otherwise call the value as function. |
|
162 |
if (isCall) { |
|
163 |
method.convert(Type.OBJECT); |
|
164 |
// ScriptFunction will see CALLSITE_SCOPE and will bind scope accordingly. |
|
23372
09707b3e5fb0
8021350: Share script classes between threads/globals within context
hannesw
parents:
17769
diff
changeset
|
165 |
method.loadUndefined(Type.OBJECT); |
16147 | 166 |
int slot = 2; |
167 |
for (final Type type : paramTypes) { |
|
24725
7bb1f687a852
8033334: Make sure that scope depth information is maintained in the RecompilableScriptFunctionDatas, to avoid unnecessary slow proto linkage when doing on demand compilation
lagergren
parents:
24719
diff
changeset
|
168 |
method.load(type, slot); |
7bb1f687a852
8033334: Make sure that scope depth information is maintained in the RecompilableScriptFunctionDatas, to avoid unnecessary slow proto linkage when doing on demand compilation
lagergren
parents:
24719
diff
changeset
|
169 |
slot += type.getSlots(); |
16147 | 170 |
} |
24725
7bb1f687a852
8033334: Make sure that scope depth information is maintained in the RecompilableScriptFunctionDatas, to avoid unnecessary slow proto linkage when doing on demand compilation
lagergren
parents:
24719
diff
changeset
|
171 |
// Shared scope calls disabled in optimistic world. TODO is this right? |
32048
8023426b93ab
8073733: TypeError messages with "call" and "new" could be improved
sundar
parents:
27976
diff
changeset
|
172 |
method.dynamicCall(returnType, 2 + paramTypes.length, flags, symbol.getName()); |
16147 | 173 |
} |
174 |
||
175 |
method._return(returnType); |
|
176 |
method.end(); |
|
177 |
} |
|
178 |
||
179 |
private String getStaticSignature() { |
|
180 |
if (staticSignature == null) { |
|
181 |
if (paramTypes == null) { |
|
182 |
staticSignature = Type.getMethodDescriptor(returnType, Type.typeFor(ScriptObject.class), Type.INT); |
|
183 |
} else { |
|
184 |
final Type[] params = new Type[paramTypes.length + 2]; |
|
185 |
params[0] = Type.typeFor(ScriptObject.class); |
|
186 |
params[1] = Type.INT; |
|
24719 | 187 |
System.arraycopy(paramTypes, 0, params, 2, paramTypes.length); |
16147 | 188 |
staticSignature = Type.getMethodDescriptor(returnType, params); |
189 |
} |
|
190 |
} |
|
191 |
return staticSignature; |
|
192 |
} |
|
193 |
||
24719 | 194 |
@Override |
195 |
public String toString() { |
|
196 |
return methodName + " " + staticSignature; |
|
197 |
} |
|
198 |
||
16147 | 199 |
} |