зеркало из https://github.com/mozilla/gecko-dev.git
JavaAdapter.createAdapterCode now takes the function name to function arity instead of Scriptable object. It allows to remove a hack from optimizer/Codegen where it created a temporary Scriptable just to populate it with FunctionNode as a source of arity values thus violating requirement on types of JS values.
The rest of JavaAdapter code is updated to use the ned form of the method as well.
This commit is contained in:
Родитель
0335328a4b
Коммит
b976cc3dce
|
@ -89,10 +89,15 @@ public final class JavaAdapter
|
||||||
|
|
||||||
static Object js_createAdpter(Context cx, Scriptable scope, Object[] args)
|
static Object js_createAdpter(Context cx, Scriptable scope, Object[] args)
|
||||||
{
|
{
|
||||||
|
int N = args.length;
|
||||||
|
if (N == 0) {
|
||||||
|
throw ScriptRuntime.typeError0("msg.adapter.zero.args");
|
||||||
|
}
|
||||||
|
|
||||||
Class superClass = null;
|
Class superClass = null;
|
||||||
Class[] intfs = new Class[args.length-1];
|
Class[] intfs = new Class[N - 1];
|
||||||
int interfaceCount = 0;
|
int interfaceCount = 0;
|
||||||
for (int i=0; i < args.length-1; i++) {
|
for (int i = 0; i != N - 1; ++i) {
|
||||||
Object arg = args[i];
|
Object arg = args[i];
|
||||||
if (!(arg instanceof NativeJavaClass)) {
|
if (!(arg instanceof NativeJavaClass)) {
|
||||||
throw ScriptRuntime.typeError2("msg.not.java.class.arg",
|
throw ScriptRuntime.typeError2("msg.not.java.class.arg",
|
||||||
|
@ -116,7 +121,7 @@ public final class JavaAdapter
|
||||||
|
|
||||||
Class[] interfaces = new Class[interfaceCount];
|
Class[] interfaces = new Class[interfaceCount];
|
||||||
System.arraycopy(intfs, 0, interfaces, 0, interfaceCount);
|
System.arraycopy(intfs, 0, interfaces, 0, interfaceCount);
|
||||||
Scriptable obj = (Scriptable) args[args.length - 1];
|
Scriptable obj = ScriptRuntime.toObject(cx, scope, args[N - 1]);
|
||||||
|
|
||||||
JavaAdapterSignature sig;
|
JavaAdapterSignature sig;
|
||||||
sig = new JavaAdapterSignature(superClass, interfaces, obj);
|
sig = new JavaAdapterSignature(superClass, interfaces, obj);
|
||||||
|
@ -126,7 +131,8 @@ public final class JavaAdapter
|
||||||
synchronized (generatedClasses) {
|
synchronized (generatedClasses) {
|
||||||
adapterName = "adapter" + serial++;
|
adapterName = "adapter" + serial++;
|
||||||
}
|
}
|
||||||
byte[] code = createAdapterCode(cx, obj, adapterName,
|
ObjToIntMap names = getObjectFunctionNames(obj);
|
||||||
|
byte[] code = createAdapterCode(names, adapterName,
|
||||||
superClass, interfaces, null);
|
superClass, interfaces, null);
|
||||||
|
|
||||||
adapterClass = loadAdapterClass(cx, adapterName, code);
|
adapterClass = loadAdapterClass(cx, adapterName, code);
|
||||||
|
@ -158,10 +164,11 @@ public final class JavaAdapter
|
||||||
synchronized (generatedClasses) {
|
synchronized (generatedClasses) {
|
||||||
adapterName = "adapter" + serial++;
|
adapterName = "adapter" + serial++;
|
||||||
}
|
}
|
||||||
|
ObjToIntMap names = getObjectFunctionNames(obj);
|
||||||
|
byte[] code = createAdapterCode(names, adapterName,
|
||||||
|
superClass, interfaces, null);
|
||||||
Context cx = Context.enter();
|
Context cx = Context.enter();
|
||||||
try {
|
try {
|
||||||
byte[] code = createAdapterCode(cx, obj, adapterName,
|
|
||||||
superClass, interfaces, null);
|
|
||||||
adapterClass = loadAdapterClass(cx, adapterName, code);
|
adapterClass = loadAdapterClass(cx, adapterName, code);
|
||||||
generatedClasses.put(sig, adapterClass);
|
generatedClasses.put(sig, adapterClass);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -185,7 +192,29 @@ public final class JavaAdapter
|
||||||
throw new ClassNotFoundException("adapter");
|
throw new ClassNotFoundException("adapter");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] createAdapterCode(Context cx, Scriptable jsObj,
|
private static ObjToIntMap getObjectFunctionNames(Scriptable obj)
|
||||||
|
{
|
||||||
|
Object[] ids = ScriptableObject.getPropertyIds(obj);
|
||||||
|
ObjToIntMap map = new ObjToIntMap(ids.length);
|
||||||
|
for (int i = 0; i != ids.length; ++i) {
|
||||||
|
if (!(ids[i] instanceof String))
|
||||||
|
continue;
|
||||||
|
String id = (String) ids[i];
|
||||||
|
Object value = ScriptableObject.getProperty(obj, id);
|
||||||
|
if (value instanceof Function) {
|
||||||
|
Function f = (Function)value;
|
||||||
|
int length = ScriptRuntime.toInt32(
|
||||||
|
ScriptableObject.getProperty(f, "length"));
|
||||||
|
if (length < 0) {
|
||||||
|
length = 0;
|
||||||
|
}
|
||||||
|
map.put(id, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] createAdapterCode(ObjToIntMap functionNames,
|
||||||
String adapterName,
|
String adapterName,
|
||||||
Class superClass,
|
Class superClass,
|
||||||
Class[] interfaces,
|
Class[] interfaces,
|
||||||
|
@ -221,14 +250,13 @@ public final class JavaAdapter
|
||||||
for (int j = 0; j < methods.length; j++) {
|
for (int j = 0; j < methods.length; j++) {
|
||||||
Method method = methods[j];
|
Method method = methods[j];
|
||||||
int mods = method.getModifiers();
|
int mods = method.getModifiers();
|
||||||
if (Modifier.isStatic(mods) || Modifier.isFinal(mods) ||
|
if (Modifier.isStatic(mods) || Modifier.isFinal(mods)) {
|
||||||
jsObj == null)
|
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!ScriptableObject.hasProperty(jsObj, method.getName())) {
|
String methodName = method.getName();
|
||||||
|
if (!functionNames.has(methodName)) {
|
||||||
try {
|
try {
|
||||||
superClass.getMethod(method.getName(),
|
superClass.getMethod(methodName,
|
||||||
method.getParameterTypes());
|
method.getParameterTypes());
|
||||||
// The class we're extending implements this method and
|
// The class we're extending implements this method and
|
||||||
// the JavaScript object doesn't have an override. See
|
// the JavaScript object doesn't have an override. See
|
||||||
|
@ -240,7 +268,6 @@ public final class JavaAdapter
|
||||||
}
|
}
|
||||||
// make sure to generate only one instance of a particular
|
// make sure to generate only one instance of a particular
|
||||||
// method/signature.
|
// method/signature.
|
||||||
String methodName = method.getName();
|
|
||||||
String methodKey = methodName + getMethodSignature(method);
|
String methodKey = methodName + getMethodSignature(method);
|
||||||
if (! generatedOverrides.has(methodKey)) {
|
if (! generatedOverrides.has(methodKey)) {
|
||||||
generateMethod(cfw, adapterName, methodName,
|
generateMethod(cfw, adapterName, methodName,
|
||||||
|
@ -266,12 +293,10 @@ public final class JavaAdapter
|
||||||
// resulting class won't be instantiable. otherwise, if the object
|
// resulting class won't be instantiable. otherwise, if the object
|
||||||
// has a property of the same name, then an override is intended.
|
// has a property of the same name, then an override is intended.
|
||||||
boolean isAbstractMethod = Modifier.isAbstract(mods);
|
boolean isAbstractMethod = Modifier.isAbstract(mods);
|
||||||
if (isAbstractMethod ||
|
String methodName = method.getName();
|
||||||
(jsObj != null && ScriptableObject.hasProperty(jsObj,method.getName())))
|
if (isAbstractMethod || functionNames.has(methodName)) {
|
||||||
{
|
|
||||||
// make sure to generate only one instance of a particular
|
// make sure to generate only one instance of a particular
|
||||||
// method/signature.
|
// method/signature.
|
||||||
String methodName = method.getName();
|
|
||||||
String methodSignature = getMethodSignature(method);
|
String methodSignature = getMethodSignature(method);
|
||||||
String methodKey = methodName + methodSignature;
|
String methodKey = methodName + methodSignature;
|
||||||
if (! generatedOverrides.has(methodKey)) {
|
if (! generatedOverrides.has(methodKey)) {
|
||||||
|
@ -292,34 +317,19 @@ public final class JavaAdapter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate Java methods, fields for remaining properties that
|
// Generate Java methods for remaining properties that are not
|
||||||
// are not overrides.
|
// overrides.
|
||||||
if (jsObj != null) {
|
ObjToIntMap.Iterator iter = new ObjToIntMap.Iterator(functionNames);
|
||||||
Object[] ids = ScriptableObject.getPropertyIds(jsObj);
|
for (iter.start(); !iter.done(); iter.next()) {
|
||||||
for (int i = 0; i != ids.length; ++i) {
|
String functionName = (String)iter.getKey();
|
||||||
if (!(ids[i] instanceof String))
|
if (generatedMethods.has(functionName))
|
||||||
continue;
|
continue;
|
||||||
String id = (String) ids[i];
|
int length = iter.getValue();
|
||||||
if (generatedMethods.has(id))
|
Class[] parms = new Class[length];
|
||||||
continue;
|
for (int k=0; k < length; k++)
|
||||||
Object f = ScriptableObject.getProperty(jsObj, id);
|
parms[k] = ScriptRuntime.ObjectClass;
|
||||||
int length;
|
generateMethod(cfw, adapterName, functionName, parms,
|
||||||
if (f instanceof Function) {
|
ScriptRuntime.ObjectClass);
|
||||||
Function p = (Function) f;
|
|
||||||
length = (int) Context.toNumber(
|
|
||||||
ScriptableObject.getProperty(p, "length"));
|
|
||||||
} else if (f instanceof FunctionNode) {
|
|
||||||
// This is used only by optimizer/Codegen
|
|
||||||
length = ((FunctionNode)f).getParamCount();
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Class[] parms = new Class[length];
|
|
||||||
for (int k=0; k < length; k++)
|
|
||||||
parms[k] = ScriptRuntime.ObjectClass;
|
|
||||||
generateMethod(cfw, adapterName, id, parms,
|
|
||||||
ScriptRuntime.ObjectClass);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return cfw.toByteArray();
|
return cfw.toByteArray();
|
||||||
}
|
}
|
||||||
|
@ -655,7 +665,7 @@ public final class JavaAdapter
|
||||||
// System.out.flush();
|
// System.out.flush();
|
||||||
cfw.startMethod(methodName, methodSignature,
|
cfw.startMethod(methodName, methodSignature,
|
||||||
ClassFileWriter.ACC_PUBLIC);
|
ClassFileWriter.ACC_PUBLIC);
|
||||||
cfw.add(ByteCode.BIPUSH, (byte) parms.length); // > 255 parms?
|
cfw.addPush(parms.length);
|
||||||
cfw.add(ByteCode.ANEWARRAY, "java/lang/Object");
|
cfw.add(ByteCode.ANEWARRAY, "java/lang/Object");
|
||||||
cfw.add(ByteCode.ASTORE, arrayLocal);
|
cfw.add(ByteCode.ASTORE, arrayLocal);
|
||||||
|
|
||||||
|
|
|
@ -152,21 +152,20 @@ public class Codegen extends Interpreter {
|
||||||
|
|
||||||
if (!isPrimary) {
|
if (!isPrimary) {
|
||||||
String adapterClassName = nameHelper.getScriptClassName(true);
|
String adapterClassName = nameHelper.getScriptClassName(true);
|
||||||
ScriptableObject obj = new NativeObject();
|
|
||||||
int functionCount = scriptOrFn.getFunctionCount();
|
int functionCount = scriptOrFn.getFunctionCount();
|
||||||
|
ObjToIntMap functionNames = new ObjToIntMap(functionCount);
|
||||||
for (int i = 0; i != functionCount; ++i) {
|
for (int i = 0; i != functionCount; ++i) {
|
||||||
OptFunctionNode fn;
|
FunctionNode fn = scriptOrFn.getFunctionNode(i);
|
||||||
fn = (OptFunctionNode)scriptOrFn.getFunctionNode(i);
|
|
||||||
String name = fn.getFunctionName();
|
String name = fn.getFunctionName();
|
||||||
if (name != null && name.length() != 0) {
|
if (name != null && name.length() != 0) {
|
||||||
obj.put(fn.getFunctionName(), obj, fn);
|
functionNames.put(name, fn.getParamCount());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (superClass == null) {
|
if (superClass == null) {
|
||||||
superClass = ScriptRuntime.ObjectClass;
|
superClass = ScriptRuntime.ObjectClass;
|
||||||
}
|
}
|
||||||
byte[] classFile = JavaAdapter.createAdapterCode(
|
byte[] classFile = JavaAdapter.createAdapterCode(
|
||||||
cx, obj, adapterClassName,
|
functionNames, adapterClassName,
|
||||||
superClass, interfaces,
|
superClass, interfaces,
|
||||||
mainClassName);
|
mainClassName);
|
||||||
try {
|
try {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче