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:
igor%mir2.org 2003-09-28 18:13:51 +00:00
Родитель 0335328a4b
Коммит b976cc3dce
2 изменённых файлов: 60 добавлений и 51 удалений

Просмотреть файл

@ -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 {