Changes necessary to generate adapter classes to files with associated optimizer package.

This commit is contained in:
norris%netscape.com 1999-09-20 21:16:45 +00:00
Родитель a43dc3b347
Коммит d66f23fafa
16 изменённых файлов: 520 добавлений и 128 удалений

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

@ -31,4 +31,8 @@ public interface ClassNameHelper {
public String getTargetClassFileName(String className);
public String getGeneratingDirectory();
public void setTargetExtends(Class extendsClass);
public void setTargetImplements(Class[] implementsClasses);
}

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

@ -1278,6 +1278,29 @@ public final class Context {
public boolean isInterpreterClass(Class cl) {
return cl == Interpreter.class;
}
/**
* Set the class that the generated target will extend.
*
* @param extendsClass the class it extends
*/
public void setTargetExtends(Class extendsClass) {
if (nameHelper != null) {
nameHelper.setTargetExtends(extendsClass);
}
}
/**
* Set the interfaces that the generated target will implement.
*
* @param implementsClasses an array of Class objects, one for each
* interface the target will extend
*/
public void setTargetImplements(Class[] implementsClasses) {
if (nameHelper != null) {
nameHelper.setTargetImplements(implementsClasses);
}
}
/**** debugger oriented portion of API ****/
@ -1826,9 +1849,9 @@ public final class Context {
requireSecurityDomain = s.equals("true");
} catch (java.util.MissingResourceException mre) {
requireSecurityDomain = true;
throw new SecurityException("Resource \"" + securityResourceName +
"\" not found.");
}
} catch (SecurityException se) {
requireSecurityDomain = true;
}
}
static final boolean useJSObject = false;

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

@ -50,29 +50,51 @@ public class JavaAdapter extends ScriptableObject {
}
intfs[interfaceCount++] = c;
}
StringBuffer sb = new StringBuffer("adapter");
sb.append(serial++);
String genName = sb.toString();
ClassFileWriter cfw = new ClassFileWriter(genName,
Class[] interfaces = new Class[interfaceCount];
System.arraycopy(intfs, 0, interfaces, 0, interfaceCount);
Scriptable obj = (Scriptable) args[args.length - 1];
Class adapterClass = createAdapterClass(cx, obj, sb.toString(),
superClass, interfaces,
null, null);
Class[] ctorParms = { FlattenedObject.class };
Object[] ctorArgs = { new FlattenedObject(obj) };
Object v = adapterClass.getConstructor(ctorParms).newInstance(ctorArgs);
return cx.toObject(v, ScriptableObject.getTopLevelScope(ctorObj));
}
public static Class createAdapterClass(Context cx, Scriptable jsObj,
String name, Class superClass,
Class[] interfaces,
String scriptClassName,
ClassNameHelper nameHelper)
throws ClassNotFoundException
{
ClassFileWriter cfw = new ClassFileWriter(name,
superClass.getName(),
"<adapter>");
cfw.addField("o", "Lorg/mozilla/javascript/FlattenedObject;",
ClassFileWriter.ACC_PRIVATE);
cfw.addField("self", "Lorg/mozilla/javascript/Scriptable;",
(short) (ClassFileWriter.ACC_PUBLIC | ClassFileWriter.ACC_FINAL));
for (int i = 0; i < interfaceCount; i++) {
if (intfs[i] != null)
cfw.addInterface(intfs[i].getName());
(short) (ClassFileWriter.ACC_PUBLIC |
ClassFileWriter.ACC_FINAL));
int interfacesCount = interfaces == null ? 0 : interfaces.length;
for (int i=0; i < interfacesCount; i++) {
if (interfaces[i] != null)
cfw.addInterface(interfaces[i].getName());
}
generateCtor(cfw, genName, superClass);
generateCtor(cfw, name, superClass);
if (scriptClassName != null)
generateEmptyCtor(cfw, name, superClass, scriptClassName);
Hashtable generatedOverrides = new Hashtable();
Hashtable generatedMethods = new Hashtable();
// if abstract class was specified, then generate appropriate overrides.
for (int i = 0; i < interfaceCount; i++) {
Method[] methods = intfs[i].getMethods();
for (int i = 0; i < interfacesCount; i++) {
Method[] methods = interfaces[i].getMethods();
for (int j = 0; j < methods.length; j++) {
Method method = methods[j];
int mods = method.getModifiers();
@ -82,18 +104,22 @@ public class JavaAdapter extends ScriptableObject {
// method/signature.
String methodKey = getMethodSignature(method);
if (! generatedOverrides.containsKey(methodKey)) {
generateOverride(cfw, genName, method);
generatedOverrides.put(methodKey, methodKey);
Class[] parms = method.getParameterTypes();
generateMethod(cfw, name, method.getName(), parms,
method.getReturnType());
generatedOverrides.put(methodKey, methodKey);
generatedMethods.put(method.getName(), Boolean.TRUE);
}
}
}
// Now, go through the superclasses methods, checking for abstract methods
// or additional methods to override.
FlattenedObject obj = new FlattenedObject(
(Scriptable) args[args.length - 1]);
// Now, go through the superclasses methods, checking for abstract
// methods or additional methods to override.
FlattenedObject obj = jsObj != null
? new FlattenedObject(jsObj)
: null;
// generate any additional overrides that the object might contain.
// generate any additional overrides that the object might contain.
Method[] methods = superClass.getMethods();
for (int j = 0; j < methods.length; j++) {
Method method = methods[j];
@ -103,20 +129,47 @@ public class JavaAdapter extends ScriptableObject {
// if a method is marked abstract, must implement it or the
// resulting class won't be instantiable. otherwise, if the object
// has a property of the same name, then an override is intended.
if (Modifier.isAbstract(mods) || obj.hasProperty(method.getName())) {
if (Modifier.isAbstract(mods) ||
(obj != null && obj.hasProperty(method.getName())))
{
// make sure to generate only one instance of a particular
// method/signature.
String methodKey = getMethodSignature(method);
if (! generatedOverrides.containsKey(methodKey)) {
generateOverride(cfw, genName, method);
Class[] parms = method.getParameterTypes();
generateMethod(cfw, name, method.getName(), parms,
method.getReturnType());
generatedOverrides.put(methodKey, method);
generatedMethods.put(method.getName(), Boolean.TRUE);
}
}
}
// TODO: generate Java methods, fields for remaining properties that
// are not overrides? Probably not necessary to generate methods
// that aren't overrides.
// Generate Java methods, fields for remaining properties that
// are not overrides.
Object[] ids = obj.getIds();
for (int j=0; j < ids.length; j++) {
if (!(ids[j] instanceof String))
continue;
if (generatedMethods.containsKey((String) ids[j]))
continue;
Object f = obj.getProperty(ids[j]);
int length;
if (f instanceof FlattenedObject) {
Object p = ((FlattenedObject) f).getObject();
if (!(p instanceof Function))
continue;
length = (int) Context.toNumber(((FlattenedObject) f).getProperty("length"));
} else if (f instanceof FunctionNode) {
length = ((FunctionNode) f).getVariableTable().getParameterCount();
} else {
continue;
}
Class[] parms = new Class[length];
for (int k=0; k < length; k++)
parms[k] = Object.class;
generateMethod(cfw, name, (String) ids[j], parms, Object.class);
}
ByteArrayOutputStream out = new ByteArrayOutputStream(512);
try {
@ -126,21 +179,34 @@ public class JavaAdapter extends ScriptableObject {
throw new RuntimeException("unexpected IOException");
}
byte[] bytes = out.toByteArray();
if (nameHelper != null && nameHelper.getGeneratingDirectory() != null)
{
try {
int lastDot = name.lastIndexOf('.');
if (lastDot != -1)
name = name.substring(lastDot+1);
String filename = nameHelper.getTargetClassFileName(name);
FileOutputStream file = new FileOutputStream(filename);
file.write(bytes);
file.close();
}
catch (IOException iox) {
throw WrappedException.wrapException(iox);
}
return null;
}
SecuritySupport ss = cx.getSecuritySupport();
Class c;
if (ss != null) {
Object securityDomain = cx.getSecurityDomainForStackDepth(-1);
c = ss.defineClass(genName, bytes, securityDomain);
return ss.defineClass(name, bytes, securityDomain);
} else {
if (classLoader == null)
classLoader = new MyClassLoader();
classLoader.defineClass(genName, bytes);
c = classLoader.loadClass(genName, true);
classLoader.defineClass(name, bytes);
return classLoader.loadClass(name, true);
}
Class[] ctorParms = { FlattenedObject.class };
Object[] ctorArgs = { obj };
Object v = c.getConstructor(ctorParms).newInstance(ctorArgs);
return cx.toObject(v, ScriptableObject.getTopLevelScope(ctorObj));
}
/**
@ -152,20 +218,28 @@ public class JavaAdapter extends ScriptableObject {
{
Context cx = Context.enter();
try {
return (object.hasProperty(methodId)
? object.callMethod(methodId, args)
: Context.getUndefinedValue());
if (object.hasProperty(methodId))
return object.callMethod(methodId, args);
} catch (PropertyException ex) {
// shouldn't occur
} catch (NotAFunctionException ex) {
// TODO: could occur
} catch (JavaScriptException ex) {
// TODO: could occur
/*
} catch (Exception ex) {
// TODO: wouldn't it be better to let the exception propagate
// up so that it could be dealt with by the calling code?
ex.printStackTrace(System.err);
throw new Error(ex.getMessage());
*/
} finally {
Context.exit();
}
return Context.getUndefinedValue();
}
private static void generateCtor(ClassFileWriter cfw, String genName,
private static void generateCtor(ClassFileWriter cfw, String name,
Class superClass)
{
cfw.startMethod("<init>",
@ -178,13 +252,24 @@ public class JavaAdapter extends ScriptableObject {
superClass.getName().replace('.', '/'),
"<init>", "()", "V");
// Set the prototype of the js object to be a LiveConnect
// wapper of the generated class's object
cfw.add(ByteCode.ALOAD_1); // first arg
cfw.add(ByteCode.ALOAD_0); // this
cfw.add(ByteCode.INVOKESTATIC,
"org/mozilla/javascript/ScriptRuntime",
"setAdapterProto",
"(Lorg/mozilla/javascript/FlattenedObject;" +
"Ljava/lang/Object;)",
"V");
// Save parameter in instance variable
cfw.add(ByteCode.ALOAD_0); // this
cfw.add(ByteCode.ALOAD_1); // first arg
cfw.add(ByteCode.PUTFIELD, genName, "o",
cfw.add(ByteCode.PUTFIELD, name, "o",
"Lorg/mozilla/javascript/FlattenedObject;");
// Store Scriptable object in "self" a public instance variable,
// Store Scriptable object in "self", a public instance variable,
// so scripts can read it.
cfw.add(ByteCode.ALOAD_0); // this
cfw.add(ByteCode.ALOAD_1); // first arg
@ -192,13 +277,70 @@ public class JavaAdapter extends ScriptableObject {
"org/mozilla/javascript/FlattenedObject",
"getObject", "()",
"Lorg/mozilla/javascript/Scriptable;");
cfw.add(ByteCode.PUTFIELD, genName, "self",
cfw.add(ByteCode.PUTFIELD, name, "self",
"Lorg/mozilla/javascript/Scriptable;");
cfw.add(ByteCode.RETURN);
cfw.stopMethod((short)20, null); // TODO: magic number "20"
}
private static void generateEmptyCtor(ClassFileWriter cfw, String name,
Class superClass,
String scriptClassName)
{
cfw.startMethod("<init>", "()V", ClassFileWriter.ACC_PUBLIC);
// Invoke base class constructor
cfw.add(ByteCode.ALOAD_0); // this
cfw.add(ByteCode.INVOKESPECIAL,
superClass.getName().replace('.', '/'),
"<init>", "()", "V");
// Load script class
cfw.add(ByteCode.NEW, scriptClassName);
cfw.add(ByteCode.DUP);
cfw.add(ByteCode.INVOKESPECIAL, scriptClassName, "<init>", "()", "V");
// Run script and save resulting scope
cfw.add(ByteCode.INVOKESTATIC,
"org/mozilla/javascript/ScriptRuntime",
"runScript",
"(Lorg/mozilla/javascript/Script;)",
"Lorg/mozilla/javascript/FlattenedObject;");
cfw.add(ByteCode.ASTORE_1);
// Save the FlattenedObject in instance variable
cfw.add(ByteCode.ALOAD_0); // this
cfw.add(ByteCode.ALOAD_1); // the FlattenedObject
cfw.add(ByteCode.PUTFIELD, name, "o",
"Lorg/mozilla/javascript/FlattenedObject;");
// Store Scriptable object in "self", a public instance variable,
// so scripts can read it.
cfw.add(ByteCode.ALOAD_0); // this
cfw.add(ByteCode.ALOAD_1); // the FlattenedObject
cfw.add(ByteCode.INVOKEVIRTUAL,
"org/mozilla/javascript/FlattenedObject",
"getObject", "()",
"Lorg/mozilla/javascript/Scriptable;");
cfw.add(ByteCode.PUTFIELD, name, "self",
"Lorg/mozilla/javascript/Scriptable;");
// Set the prototype of the js object to be a LiveConnect
// wapper of the generated class's object
cfw.add(ByteCode.ALOAD_1); // the FlattenedObject
cfw.add(ByteCode.ALOAD_0); // this
cfw.add(ByteCode.INVOKESTATIC,
"org/mozilla/javascript/ScriptRuntime",
"setAdapterProto",
"(Lorg/mozilla/javascript/FlattenedObject;" +
"Ljava/lang/Object;)",
"V");
cfw.add(ByteCode.RETURN);
cfw.stopMethod((short)20, null); // TODO: magic number "20"
}
/**
* Generates code to create a java.lang.Boolean, java.lang.Character or a
* java.lang.Double to wrap the specified primitive parameter. Leaves the
@ -360,10 +502,10 @@ public class JavaAdapter extends ScriptableObject {
}
}
private static void generateOverride(ClassFileWriter cfw, String genName,
Method m)
private static void generateMethod(ClassFileWriter cfw, String genName,
String methodName, Class[] parms,
Class returnType)
{
Class[] parms = m.getParameterTypes();
StringBuffer sb = new StringBuffer();
sb.append('(');
short arrayLocal = 1; // includes this.
@ -376,11 +518,11 @@ public class JavaAdapter extends ScriptableObject {
arrayLocal += 1;
}
sb.append(')');
appendTypeString(sb, m.getReturnType());
appendTypeString(sb, returnType);
String methodSignature = sb.toString();
// System.out.println("generating " + m.getName() + methodSignature);
// System.out.flush();
cfw.startMethod(m.getName(), methodSignature,
cfw.startMethod(methodName, methodSignature,
ClassFileWriter.ACC_PUBLIC);
cfw.add(ByteCode.BIPUSH, (byte) parms.length); // > 255 parms?
cfw.add(ByteCode.ANEWARRAY, "java/lang/Object");
@ -434,7 +576,7 @@ public class JavaAdapter extends ScriptableObject {
cfw.add(ByteCode.GETFIELD, genName, "o",
"Lorg/mozilla/javascript/FlattenedObject;");
cfw.addLoadConstant(m.getName());
cfw.addLoadConstant(methodName);
cfw.add(ByteCode.ALOAD, arrayLocal);
// go through utility method, which creates a Context to run the
@ -446,7 +588,7 @@ public class JavaAdapter extends ScriptableObject {
"Ljava/lang/Object;[Ljava/lang/Object;)",
"Ljava/lang/Object;");
Class retType = m.getReturnType();
Class retType = returnType;
if (retType.equals(Void.TYPE)) {
cfw.add(ByteCode.POP);
cfw.add(ByteCode.RETURN);

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

@ -164,21 +164,23 @@ public class NativeJavaMethod extends NativeFunction implements Function {
args[i] = NativeJavaObject.coerceType(paramTypes[i], args[i]);
}
Object javaObject;
try {
javaObject = ((NativeJavaObject) thisObj).unwrap();
}
catch (ClassCastException e) {
if (Modifier.isStatic(meth.getModifiers())) {
javaObject = null; // don't need it anyway
} else {
Object errArgs[] = { names[0] };
throw Context.reportRuntimeError(
Context.getMessage("msg.nonjava.method", errArgs));
if (Modifier.isStatic(meth.getModifiers())) {
javaObject = null; // don't need an object
} else {
Scriptable o = thisObj;
while (!(o instanceof NativeJavaObject)) {
o = o.getPrototype();
if (o == null) {
Object errArgs[] = { names[0] };
throw Context.reportRuntimeError(
Context.getMessage("msg.nonjava.method", errArgs));
}
}
javaObject = ((NativeJavaObject) o).unwrap();
}
try {
if (debug) {
printDebug("Calling", meth, args);
printDebug("Calling ", meth, args);
}
Object retval = meth.invoke(javaObject, args);

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

@ -127,7 +127,7 @@ public class NativeJavaPackage extends ScriptableObject {
// Can't add properties to Java packages. Sorry.
}
public synchronized Object get(String id, Scriptable start) {
public Object get(String id, Scriptable start) {
return getPkgProperty(id, start, true);
}

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

@ -1851,8 +1851,8 @@ public class ScriptRuntime {
catch (JavaScriptException e) {
throw WrappedException.wrapException(e);
}
for (int i=1; i < args.length; i++) {
argsObj.put(i-1, argsObj, args[i]);
for (int i=0; i < args.length; i++) {
argsObj.put(i, argsObj, args[i]);
}
global.put("arguments", global, argsObj);
@ -1868,6 +1868,9 @@ public class ScriptRuntime {
}
catch (IllegalAccessException e) {
}
finally {
Context.exit();
}
throw new RuntimeException("Error creating script object");
}
@ -1912,6 +1915,28 @@ public class ScriptRuntime {
return scope;
}
public static FlattenedObject runScript(Script script) {
Context cx = Context.enter();
Scriptable global = cx.initStandardObjects(new ImporterTopLevel());
try {
script.exec(cx, global);
} catch (JavaScriptException e) {
throw new Error(e.toString());
}
Context.exit();
return new FlattenedObject(global);
}
public static void setAdapterProto(FlattenedObject fobj, Object adapter) {
Scriptable obj = fobj.getObject();
Scriptable p = obj.getPrototype();
Scriptable scope = ScriptableObject.getTopLevelScope(obj);
if (p == null || p == ScriptableObject.getObjectPrototype(scope)) {
Scriptable wrapped = (Scriptable) Context.toObject(adapter, scope);
obj.setPrototype(wrapped);
}
}
public static Scriptable initVarObj(Context cx, Scriptable scope,
NativeFunction funObj,
Scriptable thisObj, Object[] args)

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

@ -26,7 +26,7 @@ import java.util.Enumeration;
* @see Node
* @author Norris Boyd
*/
class ShallowNodeIterator implements Enumeration {
public class ShallowNodeIterator implements Enumeration {
public ShallowNodeIterator(Node n) {
current = n;

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

@ -117,7 +117,7 @@ msg.bad.esc.mask =\
# NativeJavaClass
msg.cant.instantiate =\
error instantiating {0}: class {1} is interface or abstract
error instantiating ({0}): class {1} is interface or abstract
msg.bad.ctor.sig =\
Found constructor with wrong signature: \

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

@ -31,4 +31,8 @@ public interface ClassNameHelper {
public String getTargetClassFileName(String className);
public String getGeneratingDirectory();
public void setTargetExtends(Class extendsClass);
public void setTargetImplements(Class[] implementsClasses);
}

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

@ -1278,6 +1278,29 @@ public final class Context {
public boolean isInterpreterClass(Class cl) {
return cl == Interpreter.class;
}
/**
* Set the class that the generated target will extend.
*
* @param extendsClass the class it extends
*/
public void setTargetExtends(Class extendsClass) {
if (nameHelper != null) {
nameHelper.setTargetExtends(extendsClass);
}
}
/**
* Set the interfaces that the generated target will implement.
*
* @param implementsClasses an array of Class objects, one for each
* interface the target will extend
*/
public void setTargetImplements(Class[] implementsClasses) {
if (nameHelper != null) {
nameHelper.setTargetImplements(implementsClasses);
}
}
/**** debugger oriented portion of API ****/
@ -1826,9 +1849,9 @@ public final class Context {
requireSecurityDomain = s.equals("true");
} catch (java.util.MissingResourceException mre) {
requireSecurityDomain = true;
throw new SecurityException("Resource \"" + securityResourceName +
"\" not found.");
}
} catch (SecurityException se) {
requireSecurityDomain = true;
}
}
static final boolean useJSObject = false;

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

@ -50,29 +50,51 @@ public class JavaAdapter extends ScriptableObject {
}
intfs[interfaceCount++] = c;
}
StringBuffer sb = new StringBuffer("adapter");
sb.append(serial++);
String genName = sb.toString();
ClassFileWriter cfw = new ClassFileWriter(genName,
Class[] interfaces = new Class[interfaceCount];
System.arraycopy(intfs, 0, interfaces, 0, interfaceCount);
Scriptable obj = (Scriptable) args[args.length - 1];
Class adapterClass = createAdapterClass(cx, obj, sb.toString(),
superClass, interfaces,
null, null);
Class[] ctorParms = { FlattenedObject.class };
Object[] ctorArgs = { new FlattenedObject(obj) };
Object v = adapterClass.getConstructor(ctorParms).newInstance(ctorArgs);
return cx.toObject(v, ScriptableObject.getTopLevelScope(ctorObj));
}
public static Class createAdapterClass(Context cx, Scriptable jsObj,
String name, Class superClass,
Class[] interfaces,
String scriptClassName,
ClassNameHelper nameHelper)
throws ClassNotFoundException
{
ClassFileWriter cfw = new ClassFileWriter(name,
superClass.getName(),
"<adapter>");
cfw.addField("o", "Lorg/mozilla/javascript/FlattenedObject;",
ClassFileWriter.ACC_PRIVATE);
cfw.addField("self", "Lorg/mozilla/javascript/Scriptable;",
(short) (ClassFileWriter.ACC_PUBLIC | ClassFileWriter.ACC_FINAL));
for (int i = 0; i < interfaceCount; i++) {
if (intfs[i] != null)
cfw.addInterface(intfs[i].getName());
(short) (ClassFileWriter.ACC_PUBLIC |
ClassFileWriter.ACC_FINAL));
int interfacesCount = interfaces == null ? 0 : interfaces.length;
for (int i=0; i < interfacesCount; i++) {
if (interfaces[i] != null)
cfw.addInterface(interfaces[i].getName());
}
generateCtor(cfw, genName, superClass);
generateCtor(cfw, name, superClass);
if (scriptClassName != null)
generateEmptyCtor(cfw, name, superClass, scriptClassName);
Hashtable generatedOverrides = new Hashtable();
Hashtable generatedMethods = new Hashtable();
// if abstract class was specified, then generate appropriate overrides.
for (int i = 0; i < interfaceCount; i++) {
Method[] methods = intfs[i].getMethods();
for (int i = 0; i < interfacesCount; i++) {
Method[] methods = interfaces[i].getMethods();
for (int j = 0; j < methods.length; j++) {
Method method = methods[j];
int mods = method.getModifiers();
@ -82,18 +104,22 @@ public class JavaAdapter extends ScriptableObject {
// method/signature.
String methodKey = getMethodSignature(method);
if (! generatedOverrides.containsKey(methodKey)) {
generateOverride(cfw, genName, method);
generatedOverrides.put(methodKey, methodKey);
Class[] parms = method.getParameterTypes();
generateMethod(cfw, name, method.getName(), parms,
method.getReturnType());
generatedOverrides.put(methodKey, methodKey);
generatedMethods.put(method.getName(), Boolean.TRUE);
}
}
}
// Now, go through the superclasses methods, checking for abstract methods
// or additional methods to override.
FlattenedObject obj = new FlattenedObject(
(Scriptable) args[args.length - 1]);
// Now, go through the superclasses methods, checking for abstract
// methods or additional methods to override.
FlattenedObject obj = jsObj != null
? new FlattenedObject(jsObj)
: null;
// generate any additional overrides that the object might contain.
// generate any additional overrides that the object might contain.
Method[] methods = superClass.getMethods();
for (int j = 0; j < methods.length; j++) {
Method method = methods[j];
@ -103,20 +129,47 @@ public class JavaAdapter extends ScriptableObject {
// if a method is marked abstract, must implement it or the
// resulting class won't be instantiable. otherwise, if the object
// has a property of the same name, then an override is intended.
if (Modifier.isAbstract(mods) || obj.hasProperty(method.getName())) {
if (Modifier.isAbstract(mods) ||
(obj != null && obj.hasProperty(method.getName())))
{
// make sure to generate only one instance of a particular
// method/signature.
String methodKey = getMethodSignature(method);
if (! generatedOverrides.containsKey(methodKey)) {
generateOverride(cfw, genName, method);
Class[] parms = method.getParameterTypes();
generateMethod(cfw, name, method.getName(), parms,
method.getReturnType());
generatedOverrides.put(methodKey, method);
generatedMethods.put(method.getName(), Boolean.TRUE);
}
}
}
// TODO: generate Java methods, fields for remaining properties that
// are not overrides? Probably not necessary to generate methods
// that aren't overrides.
// Generate Java methods, fields for remaining properties that
// are not overrides.
Object[] ids = obj.getIds();
for (int j=0; j < ids.length; j++) {
if (!(ids[j] instanceof String))
continue;
if (generatedMethods.containsKey((String) ids[j]))
continue;
Object f = obj.getProperty(ids[j]);
int length;
if (f instanceof FlattenedObject) {
Object p = ((FlattenedObject) f).getObject();
if (!(p instanceof Function))
continue;
length = (int) Context.toNumber(((FlattenedObject) f).getProperty("length"));
} else if (f instanceof FunctionNode) {
length = ((FunctionNode) f).getVariableTable().getParameterCount();
} else {
continue;
}
Class[] parms = new Class[length];
for (int k=0; k < length; k++)
parms[k] = Object.class;
generateMethod(cfw, name, (String) ids[j], parms, Object.class);
}
ByteArrayOutputStream out = new ByteArrayOutputStream(512);
try {
@ -126,21 +179,34 @@ public class JavaAdapter extends ScriptableObject {
throw new RuntimeException("unexpected IOException");
}
byte[] bytes = out.toByteArray();
if (nameHelper != null && nameHelper.getGeneratingDirectory() != null)
{
try {
int lastDot = name.lastIndexOf('.');
if (lastDot != -1)
name = name.substring(lastDot+1);
String filename = nameHelper.getTargetClassFileName(name);
FileOutputStream file = new FileOutputStream(filename);
file.write(bytes);
file.close();
}
catch (IOException iox) {
throw WrappedException.wrapException(iox);
}
return null;
}
SecuritySupport ss = cx.getSecuritySupport();
Class c;
if (ss != null) {
Object securityDomain = cx.getSecurityDomainForStackDepth(-1);
c = ss.defineClass(genName, bytes, securityDomain);
return ss.defineClass(name, bytes, securityDomain);
} else {
if (classLoader == null)
classLoader = new MyClassLoader();
classLoader.defineClass(genName, bytes);
c = classLoader.loadClass(genName, true);
classLoader.defineClass(name, bytes);
return classLoader.loadClass(name, true);
}
Class[] ctorParms = { FlattenedObject.class };
Object[] ctorArgs = { obj };
Object v = c.getConstructor(ctorParms).newInstance(ctorArgs);
return cx.toObject(v, ScriptableObject.getTopLevelScope(ctorObj));
}
/**
@ -152,20 +218,28 @@ public class JavaAdapter extends ScriptableObject {
{
Context cx = Context.enter();
try {
return (object.hasProperty(methodId)
? object.callMethod(methodId, args)
: Context.getUndefinedValue());
if (object.hasProperty(methodId))
return object.callMethod(methodId, args);
} catch (PropertyException ex) {
// shouldn't occur
} catch (NotAFunctionException ex) {
// TODO: could occur
} catch (JavaScriptException ex) {
// TODO: could occur
/*
} catch (Exception ex) {
// TODO: wouldn't it be better to let the exception propagate
// up so that it could be dealt with by the calling code?
ex.printStackTrace(System.err);
throw new Error(ex.getMessage());
*/
} finally {
Context.exit();
}
return Context.getUndefinedValue();
}
private static void generateCtor(ClassFileWriter cfw, String genName,
private static void generateCtor(ClassFileWriter cfw, String name,
Class superClass)
{
cfw.startMethod("<init>",
@ -178,13 +252,24 @@ public class JavaAdapter extends ScriptableObject {
superClass.getName().replace('.', '/'),
"<init>", "()", "V");
// Set the prototype of the js object to be a LiveConnect
// wapper of the generated class's object
cfw.add(ByteCode.ALOAD_1); // first arg
cfw.add(ByteCode.ALOAD_0); // this
cfw.add(ByteCode.INVOKESTATIC,
"org/mozilla/javascript/ScriptRuntime",
"setAdapterProto",
"(Lorg/mozilla/javascript/FlattenedObject;" +
"Ljava/lang/Object;)",
"V");
// Save parameter in instance variable
cfw.add(ByteCode.ALOAD_0); // this
cfw.add(ByteCode.ALOAD_1); // first arg
cfw.add(ByteCode.PUTFIELD, genName, "o",
cfw.add(ByteCode.PUTFIELD, name, "o",
"Lorg/mozilla/javascript/FlattenedObject;");
// Store Scriptable object in "self" a public instance variable,
// Store Scriptable object in "self", a public instance variable,
// so scripts can read it.
cfw.add(ByteCode.ALOAD_0); // this
cfw.add(ByteCode.ALOAD_1); // first arg
@ -192,13 +277,70 @@ public class JavaAdapter extends ScriptableObject {
"org/mozilla/javascript/FlattenedObject",
"getObject", "()",
"Lorg/mozilla/javascript/Scriptable;");
cfw.add(ByteCode.PUTFIELD, genName, "self",
cfw.add(ByteCode.PUTFIELD, name, "self",
"Lorg/mozilla/javascript/Scriptable;");
cfw.add(ByteCode.RETURN);
cfw.stopMethod((short)20, null); // TODO: magic number "20"
}
private static void generateEmptyCtor(ClassFileWriter cfw, String name,
Class superClass,
String scriptClassName)
{
cfw.startMethod("<init>", "()V", ClassFileWriter.ACC_PUBLIC);
// Invoke base class constructor
cfw.add(ByteCode.ALOAD_0); // this
cfw.add(ByteCode.INVOKESPECIAL,
superClass.getName().replace('.', '/'),
"<init>", "()", "V");
// Load script class
cfw.add(ByteCode.NEW, scriptClassName);
cfw.add(ByteCode.DUP);
cfw.add(ByteCode.INVOKESPECIAL, scriptClassName, "<init>", "()", "V");
// Run script and save resulting scope
cfw.add(ByteCode.INVOKESTATIC,
"org/mozilla/javascript/ScriptRuntime",
"runScript",
"(Lorg/mozilla/javascript/Script;)",
"Lorg/mozilla/javascript/FlattenedObject;");
cfw.add(ByteCode.ASTORE_1);
// Save the FlattenedObject in instance variable
cfw.add(ByteCode.ALOAD_0); // this
cfw.add(ByteCode.ALOAD_1); // the FlattenedObject
cfw.add(ByteCode.PUTFIELD, name, "o",
"Lorg/mozilla/javascript/FlattenedObject;");
// Store Scriptable object in "self", a public instance variable,
// so scripts can read it.
cfw.add(ByteCode.ALOAD_0); // this
cfw.add(ByteCode.ALOAD_1); // the FlattenedObject
cfw.add(ByteCode.INVOKEVIRTUAL,
"org/mozilla/javascript/FlattenedObject",
"getObject", "()",
"Lorg/mozilla/javascript/Scriptable;");
cfw.add(ByteCode.PUTFIELD, name, "self",
"Lorg/mozilla/javascript/Scriptable;");
// Set the prototype of the js object to be a LiveConnect
// wapper of the generated class's object
cfw.add(ByteCode.ALOAD_1); // the FlattenedObject
cfw.add(ByteCode.ALOAD_0); // this
cfw.add(ByteCode.INVOKESTATIC,
"org/mozilla/javascript/ScriptRuntime",
"setAdapterProto",
"(Lorg/mozilla/javascript/FlattenedObject;" +
"Ljava/lang/Object;)",
"V");
cfw.add(ByteCode.RETURN);
cfw.stopMethod((short)20, null); // TODO: magic number "20"
}
/**
* Generates code to create a java.lang.Boolean, java.lang.Character or a
* java.lang.Double to wrap the specified primitive parameter. Leaves the
@ -360,10 +502,10 @@ public class JavaAdapter extends ScriptableObject {
}
}
private static void generateOverride(ClassFileWriter cfw, String genName,
Method m)
private static void generateMethod(ClassFileWriter cfw, String genName,
String methodName, Class[] parms,
Class returnType)
{
Class[] parms = m.getParameterTypes();
StringBuffer sb = new StringBuffer();
sb.append('(');
short arrayLocal = 1; // includes this.
@ -376,11 +518,11 @@ public class JavaAdapter extends ScriptableObject {
arrayLocal += 1;
}
sb.append(')');
appendTypeString(sb, m.getReturnType());
appendTypeString(sb, returnType);
String methodSignature = sb.toString();
// System.out.println("generating " + m.getName() + methodSignature);
// System.out.flush();
cfw.startMethod(m.getName(), methodSignature,
cfw.startMethod(methodName, methodSignature,
ClassFileWriter.ACC_PUBLIC);
cfw.add(ByteCode.BIPUSH, (byte) parms.length); // > 255 parms?
cfw.add(ByteCode.ANEWARRAY, "java/lang/Object");
@ -434,7 +576,7 @@ public class JavaAdapter extends ScriptableObject {
cfw.add(ByteCode.GETFIELD, genName, "o",
"Lorg/mozilla/javascript/FlattenedObject;");
cfw.addLoadConstant(m.getName());
cfw.addLoadConstant(methodName);
cfw.add(ByteCode.ALOAD, arrayLocal);
// go through utility method, which creates a Context to run the
@ -446,7 +588,7 @@ public class JavaAdapter extends ScriptableObject {
"Ljava/lang/Object;[Ljava/lang/Object;)",
"Ljava/lang/Object;");
Class retType = m.getReturnType();
Class retType = returnType;
if (retType.equals(Void.TYPE)) {
cfw.add(ByteCode.POP);
cfw.add(ByteCode.RETURN);

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

@ -164,21 +164,23 @@ public class NativeJavaMethod extends NativeFunction implements Function {
args[i] = NativeJavaObject.coerceType(paramTypes[i], args[i]);
}
Object javaObject;
try {
javaObject = ((NativeJavaObject) thisObj).unwrap();
}
catch (ClassCastException e) {
if (Modifier.isStatic(meth.getModifiers())) {
javaObject = null; // don't need it anyway
} else {
Object errArgs[] = { names[0] };
throw Context.reportRuntimeError(
Context.getMessage("msg.nonjava.method", errArgs));
if (Modifier.isStatic(meth.getModifiers())) {
javaObject = null; // don't need an object
} else {
Scriptable o = thisObj;
while (!(o instanceof NativeJavaObject)) {
o = o.getPrototype();
if (o == null) {
Object errArgs[] = { names[0] };
throw Context.reportRuntimeError(
Context.getMessage("msg.nonjava.method", errArgs));
}
}
javaObject = ((NativeJavaObject) o).unwrap();
}
try {
if (debug) {
printDebug("Calling", meth, args);
printDebug("Calling ", meth, args);
}
Object retval = meth.invoke(javaObject, args);

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

@ -127,7 +127,7 @@ public class NativeJavaPackage extends ScriptableObject {
// Can't add properties to Java packages. Sorry.
}
public synchronized Object get(String id, Scriptable start) {
public Object get(String id, Scriptable start) {
return getPkgProperty(id, start, true);
}

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

@ -1851,8 +1851,8 @@ public class ScriptRuntime {
catch (JavaScriptException e) {
throw WrappedException.wrapException(e);
}
for (int i=1; i < args.length; i++) {
argsObj.put(i-1, argsObj, args[i]);
for (int i=0; i < args.length; i++) {
argsObj.put(i, argsObj, args[i]);
}
global.put("arguments", global, argsObj);
@ -1868,6 +1868,9 @@ public class ScriptRuntime {
}
catch (IllegalAccessException e) {
}
finally {
Context.exit();
}
throw new RuntimeException("Error creating script object");
}
@ -1912,6 +1915,28 @@ public class ScriptRuntime {
return scope;
}
public static FlattenedObject runScript(Script script) {
Context cx = Context.enter();
Scriptable global = cx.initStandardObjects(new ImporterTopLevel());
try {
script.exec(cx, global);
} catch (JavaScriptException e) {
throw new Error(e.toString());
}
Context.exit();
return new FlattenedObject(global);
}
public static void setAdapterProto(FlattenedObject fobj, Object adapter) {
Scriptable obj = fobj.getObject();
Scriptable p = obj.getPrototype();
Scriptable scope = ScriptableObject.getTopLevelScope(obj);
if (p == null || p == ScriptableObject.getObjectPrototype(scope)) {
Scriptable wrapped = (Scriptable) Context.toObject(adapter, scope);
obj.setPrototype(wrapped);
}
}
public static Scriptable initVarObj(Context cx, Scriptable scope,
NativeFunction funObj,
Scriptable thisObj, Object[] args)

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

@ -26,7 +26,7 @@ import java.util.Enumeration;
* @see Node
* @author Norris Boyd
*/
class ShallowNodeIterator implements Enumeration {
public class ShallowNodeIterator implements Enumeration {
public ShallowNodeIterator(Node n) {
current = n;

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

@ -117,7 +117,7 @@ msg.bad.esc.mask =\
# NativeJavaClass
msg.cant.instantiate =\
error instantiating {0}: class {1} is interface or abstract
error instantiating ({0}): class {1} is interface or abstract
msg.bad.ctor.sig =\
Found constructor with wrong signature: \