зеркало из https://github.com/mozilla/pluotsorbet.git
Use Class.java static initialization code.
This commit is contained in:
Родитель
5e79167004
Коммит
764c00beb4
13
actors.ts
13
actors.ts
|
@ -448,29 +448,20 @@ module J2ME {
|
|||
* are stored for this class.
|
||||
*/
|
||||
getClassObject(): java.lang.Class {
|
||||
return getRuntimeKlass($, this.klass).classObject;
|
||||
return $.getRuntimeKlass(this.klass).classObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Object that holds static properties for this class.
|
||||
*/
|
||||
getStaticObject(ctx: Context): java.lang.Object {
|
||||
return <java.lang.Object><any>getRuntimeKlass(ctx.runtime, this.klass);
|
||||
return <java.lang.Object><any>ctx.runtime.getRuntimeKlass(this.klass);
|
||||
}
|
||||
|
||||
getField(fieldKey: string) : FieldInfo {
|
||||
return CLASSES.getField(this, fieldKey);
|
||||
}
|
||||
|
||||
getClassInitLockObject(ctx: Context) {
|
||||
if (!(this.className in ctx.runtime.classInitLockObjects)) {
|
||||
ctx.runtime.classInitLockObjects[this.className] = {
|
||||
classInfo: this
|
||||
};
|
||||
}
|
||||
return ctx.runtime.classInitLockObjects[this.className];
|
||||
}
|
||||
|
||||
toString() {
|
||||
return "[class " + this.className + "]";
|
||||
}
|
||||
|
|
|
@ -320,6 +320,7 @@ com/sun/midp/lcdui/DisplayDevice.isPrimaryDisplay.()Z
|
|||
com/sun/midp/main/MIDletProxy.getClassName.()Ljava/lang/String;
|
||||
com/sun/midp/rms/RmsEnvironment.getSecureFilenameBase.(I)Ljava/lang/String;
|
||||
com/sun/midp/midletsuite/SuiteContainerAdapter.getSecureFilenameBase.(I)Ljava/lang/String;
|
||||
java/lang/Class.initialize.()V
|
||||
com/nokia/mid/ui/gestures/GestureEventImpl.getType.()I
|
||||
com/nokia/mid/ui/gestures/GestureEventImpl.getDragDistanceX.()I
|
||||
com/nokia/mid/ui/gestures/GestureEventImpl.getDragDistanceY.()I
|
||||
|
|
14
bindings.ts
14
bindings.ts
|
@ -11,6 +11,18 @@ module J2ME {
|
|||
}
|
||||
}
|
||||
},
|
||||
"java/lang/Class": {
|
||||
fields: {
|
||||
instanceSymbols: {
|
||||
"status.I": "status"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
instanceSymbols: {
|
||||
"initialize.()V": "initialize"
|
||||
}
|
||||
}
|
||||
},
|
||||
"java/lang/String": {
|
||||
fields: {
|
||||
instanceSymbols: {
|
||||
|
@ -195,6 +207,8 @@ module J2ME {
|
|||
* RuntimeKlass associated with this Class object.
|
||||
*/
|
||||
runtimeKlass: RuntimeKlass;
|
||||
status: number;
|
||||
initialize(): void;
|
||||
}
|
||||
|
||||
export interface String extends java.lang.Object {
|
||||
|
|
|
@ -26,6 +26,14 @@ module J2ME {
|
|||
traceWriter.writeLn(toDebugString(array) + "[" + index + "] (" + toDebugString(array[index]) + ")");
|
||||
}
|
||||
|
||||
function classInitAndUnwindCheck(classInfo: ClassInfo, pc: number) {
|
||||
classInitCheck(classInfo);
|
||||
if (U) {
|
||||
$.ctx.current().pc = pc;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimize method bytecode.
|
||||
*/
|
||||
|
@ -937,7 +945,7 @@ module J2ME {
|
|||
case Bytecodes.ANEWARRAY:
|
||||
index = frame.read16();
|
||||
classInfo = resolveClass(index, mi.classInfo, false);
|
||||
classInitCheck(classInfo, frame.pc - 3);
|
||||
classInitAndUnwindCheck(classInfo, frame.pc - 3);
|
||||
size = stack.pop();
|
||||
stack.push(newArray(classInfo.klass, size));
|
||||
break;
|
||||
|
@ -992,7 +1000,7 @@ module J2ME {
|
|||
case Bytecodes.GETSTATIC:
|
||||
index = frame.read16();
|
||||
fieldInfo = resolveField(index, mi.classInfo, true);
|
||||
classInitCheck(fieldInfo.classInfo, frame.pc - 3);
|
||||
classInitAndUnwindCheck(fieldInfo.classInfo, frame.pc - 3);
|
||||
if (U) {
|
||||
return;
|
||||
}
|
||||
|
@ -1002,7 +1010,7 @@ module J2ME {
|
|||
case Bytecodes.PUTSTATIC:
|
||||
index = frame.read16();
|
||||
fieldInfo = resolveField(index, mi.classInfo, true);
|
||||
classInitCheck(fieldInfo.classInfo, frame.pc - 3);
|
||||
classInitAndUnwindCheck(fieldInfo.classInfo, frame.pc - 3);
|
||||
if (U) {
|
||||
return;
|
||||
}
|
||||
|
@ -1011,7 +1019,7 @@ module J2ME {
|
|||
case Bytecodes.NEW:
|
||||
index = frame.read16();
|
||||
classInfo = resolveClass(index, mi.classInfo, false);
|
||||
classInitCheck(classInfo, frame.pc - 3);
|
||||
classInitAndUnwindCheck(classInfo, frame.pc - 3);
|
||||
if (U) {
|
||||
return;
|
||||
}
|
||||
|
@ -1140,7 +1148,7 @@ module J2ME {
|
|||
}
|
||||
|
||||
if (isStatic) {
|
||||
classInitCheck(calleeMethodInfo.classInfo, lastPC);
|
||||
classInitAndUnwindCheck(calleeMethodInfo.classInfo, lastPC);
|
||||
if (U) {
|
||||
return;
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,425 @@
|
|||
/*
|
||||
*
|
||||
*
|
||||
* Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at /legal/license.txt).
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa
|
||||
* Clara, CA 95054 or visit www.sun.com if you need additional
|
||||
* information or have any questions.
|
||||
*/
|
||||
|
||||
package java.lang;
|
||||
|
||||
/**
|
||||
* Instances of the class <code>Class</code> represent classes and interfaces
|
||||
* in a running Java application. Every array also belongs to a class that is
|
||||
* reflected as a <code>Class</code> object that is shared by all arrays with
|
||||
* the same element type and number of dimensions.
|
||||
*
|
||||
* <p> <code>Class</code> has no public constructor. Instead <code>Class</code>
|
||||
* objects are constructed automatically by the Java Virtual Machine as classes
|
||||
* are loaded.
|
||||
*
|
||||
* <p> The following example uses a <code>Class</code> object to print the
|
||||
* class name of an object:
|
||||
*
|
||||
* <p> <blockquote><pre>
|
||||
* void printClassName(Object obj) {
|
||||
* System.out.println("The class of " + obj +
|
||||
* " is " + obj.getClass().getName());
|
||||
* }
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @version 12/17/01 (CLDC 1.1)
|
||||
* @since JDK1.0, CLDC 1.0
|
||||
*/
|
||||
public final
|
||||
class Class {
|
||||
|
||||
/*
|
||||
* Constructor. Only the Java Virtual Machine creates Class
|
||||
* objects.
|
||||
*/
|
||||
private Class() {}
|
||||
|
||||
/**
|
||||
* Converts the object to a string. The string representation is the
|
||||
* string "class" or "interface", followed by a space, and then by the
|
||||
* fully qualified name of the class in the format returned by
|
||||
* <code>getName</code>. If this <code>Class</code> object represents a
|
||||
* primitive type, this method returns the name of the primitive type. If
|
||||
* this <code>Class</code> object represents void this method returns
|
||||
* "void".
|
||||
*
|
||||
* @return a string representation of this class object.
|
||||
*/
|
||||
public String toString() {
|
||||
return (isInterface() ? "interface " : "class ") + getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>Class</code> object associated with the class
|
||||
* with the given string name. Given the fully-qualified name for
|
||||
* a class or interface, this method attempts to locate, load and
|
||||
* link the class.
|
||||
* <p>
|
||||
* For example, the following code fragment returns the runtime
|
||||
* <code>Class</code> descriptor for the class named
|
||||
* <code>java.lang.Thread</code>:
|
||||
* <ul><code>
|
||||
* Class t = Class.forName("java.lang.Thread")
|
||||
* </code></ul>
|
||||
*
|
||||
* @param className the fully qualified name of the desired class.
|
||||
* @return the <code>Class</code> object for the class with the
|
||||
* specified name.
|
||||
* @exception ClassNotFoundException if the class could not be found.
|
||||
* @exception Error if the function fails for any other reason.
|
||||
* @since JDK1.0
|
||||
*/
|
||||
public static Class forName(String className) throws ClassNotFoundException {
|
||||
// forName is broken into two parts since forName0 may unwind.
|
||||
forName0(className);
|
||||
return forName1(className);
|
||||
}
|
||||
|
||||
private static native void forName0(String className) throws ClassNotFoundException;
|
||||
private static native Class forName1(String className);
|
||||
|
||||
/**
|
||||
* Creates a new instance of a class.
|
||||
*
|
||||
* @return a newly allocated instance of the class represented by this
|
||||
* object. This is done exactly as if by a <code>new</code>
|
||||
* expression with an empty argument list.
|
||||
* @exception IllegalAccessException if the class or initializer is
|
||||
* not accessible.
|
||||
* @exception InstantiationException if an application tries to
|
||||
* instantiate an abstract class or an interface, or if the
|
||||
* instantiation fails for some other reason.
|
||||
* @since JDK1.0
|
||||
*/
|
||||
public native Object newInstance()
|
||||
throws InstantiationException, IllegalAccessException;
|
||||
|
||||
/**
|
||||
* Determines if the specified <code>Object</code> is assignment-compatible
|
||||
* with the object represented by this <code>Class</code>. This method is
|
||||
* the dynamic equivalent of the Java language <code>instanceof</code>
|
||||
* operator. The method returns <code>true</code> if the specified
|
||||
* <code>Object</code> argument is non-null and can be cast to the
|
||||
* reference type represented by this <code>Class</code> object without
|
||||
* raising a <code>ClassCastException.</code> It returns <code>false</code>
|
||||
* otherwise.
|
||||
*
|
||||
* <p> Specifically, if this <code>Class</code> object represents a
|
||||
* declared class, this method returns <code>true</code> if the specified
|
||||
* <code>Object</code> argument is an instance of the represented class (or
|
||||
* of any of its subclasses); it returns <code>false</code> otherwise. If
|
||||
* this <code>Class</code> object represents an array class, this method
|
||||
* returns <code>true</code> if the specified <code>Object</code> argument
|
||||
* can be converted to an object of the array class by an identity
|
||||
* conversion or by a widening reference conversion; it returns
|
||||
* <code>false</code> otherwise. If this <code>Class</code> object
|
||||
* represents an interface, this method returns <code>true</code> if the
|
||||
* class or any superclass of the specified <code>Object</code> argument
|
||||
* implements this interface; it returns <code>false</code> otherwise. If
|
||||
* this <code>Class</code> object represents a primitive type, this method
|
||||
* returns <code>false</code>.
|
||||
*
|
||||
* @param obj the object to check
|
||||
* @return true if <code>obj</code> is an instance of this class
|
||||
*
|
||||
* @since JDK1.1
|
||||
*/
|
||||
public native boolean isInstance(Object obj);
|
||||
|
||||
/**
|
||||
* Determines if the class or interface represented by this
|
||||
* <code>Class</code> object is either the same as, or is a superclass or
|
||||
* superinterface of, the class or interface represented by the specified
|
||||
* <code>Class</code> parameter. It returns <code>true</code> if so;
|
||||
* otherwise it returns <code>false</code>. If this <code>Class</code>
|
||||
* object represents a primitive type, this method returns
|
||||
* <code>true</code> if the specified <code>Class</code> parameter is
|
||||
* exactly this <code>Class</code> object; otherwise it returns
|
||||
* <code>false</code>.
|
||||
*
|
||||
* <p> Specifically, this method tests whether the type represented by the
|
||||
* specified <code>Class</code> parameter can be converted to the type
|
||||
* represented by this <code>Class</code> object via an identity conversion
|
||||
* or via a widening reference conversion. See <em>The Java Language
|
||||
* Specification</em>, sections 5.1.1 and 5.1.4 , for details.
|
||||
*
|
||||
* @param cls the <code>Class</code> object to be checked
|
||||
* @return the <code>boolean</code> value indicating whether objects of the
|
||||
* type <code>cls</code> can be assigned to objects of this class
|
||||
* @exception NullPointerException if the specified Class parameter is
|
||||
* null.
|
||||
* @since JDK1.1
|
||||
*/
|
||||
public native boolean isAssignableFrom(Class cls);
|
||||
|
||||
/**
|
||||
* Determines if the specified <code>Class</code> object represents an
|
||||
* interface type.
|
||||
*
|
||||
* @return <code>true</code> if this object represents an interface;
|
||||
* <code>false</code> otherwise.
|
||||
*/
|
||||
public native boolean isInterface();
|
||||
|
||||
/**
|
||||
* Determines if this <code>Class</code> object represents an array class.
|
||||
*
|
||||
* @return <code>true</code> if this object represents an array class;
|
||||
* <code>false</code> otherwise.
|
||||
* @since JDK1.1
|
||||
*/
|
||||
public native boolean isArray();
|
||||
|
||||
/**
|
||||
* Returns the fully-qualified name of the entity (class, interface, array
|
||||
* class, primitive type, or void) represented by this <code>Class</code>
|
||||
* object, as a <code>String</code>.
|
||||
*
|
||||
* <p> If this <code>Class</code> object represents a class of arrays, then
|
||||
* the internal form of the name consists of the name of the element type
|
||||
* in Java signature format, preceded by one or more "<tt>[</tt>"
|
||||
* characters representing the depth of array nesting. Thus:
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* (new Object[3]).getClass().getName()
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* returns "<code>[Ljava.lang.Object;</code>" and:
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* (new int[3][4][5][6][7][8][9]).getClass().getName()
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* returns "<code>[[[[[[[I</code>". The encoding of element type names
|
||||
* is as follows:
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* B byte
|
||||
* C char
|
||||
* D double
|
||||
* F float
|
||||
* I int
|
||||
* J long
|
||||
* L<i>classname;</i> class or interface
|
||||
* S short
|
||||
* Z boolean
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* The class or interface name <tt><i>classname</i></tt> is given in fully
|
||||
* qualified form as shown in the example above.
|
||||
*
|
||||
* @return the fully qualified name of the class or interface
|
||||
* represented by this object.
|
||||
*/
|
||||
public native String getName();
|
||||
|
||||
/**
|
||||
* Finds a resource with a given name in the application's
|
||||
* JAR file. This method returns
|
||||
* <code>null</code> if no resource with this name is found
|
||||
* in the application's JAR file.
|
||||
* <p>
|
||||
* The resource names can be represented in two
|
||||
* different formats: absolute or relative.
|
||||
* <p>
|
||||
* Absolute format:
|
||||
* <ul><code>/packagePathName/resourceName</code></ul>
|
||||
* <p>
|
||||
* Relative format:
|
||||
* <ul><code>resourceName</code></ul>
|
||||
* <p>
|
||||
* In the absolute format, the programmer provides a fully
|
||||
* qualified name that includes both the full path and the
|
||||
* name of the resource inside the JAR file. In the path names,
|
||||
* the character "/" is used as the separator.
|
||||
* <p>
|
||||
* In the relative format, the programmer provides only
|
||||
* the name of the actual resource. Relative names are
|
||||
* converted to absolute names by the system by prepending
|
||||
* the resource name with the fully qualified package name
|
||||
* of class upon which the <code>getResourceAsStream</code>
|
||||
* method was called.
|
||||
*
|
||||
* @param name name of the desired resource
|
||||
* @return a <code>java.io.InputStream</code> object.
|
||||
*/
|
||||
public java.io.InputStream getResourceAsStream(String name) {
|
||||
try {
|
||||
if (name.length() > 0 && name.charAt(0) == '/') {
|
||||
/* Absolute format */
|
||||
name = name.substring(1);
|
||||
} else {
|
||||
/* Relative format */
|
||||
String className = this.getName();
|
||||
int dotIndex = className.lastIndexOf('.');
|
||||
if (dotIndex >= 0) {
|
||||
name = className.substring(0, dotIndex + 1).replace('.', '/')
|
||||
+ name;
|
||||
}
|
||||
}
|
||||
return new com.sun.cldc.io.ResourceInputStream(name);
|
||||
} catch (java.io.IOException x) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This private function is used during virtual machine initialization.
|
||||
* The user does not normally see this function.
|
||||
*/
|
||||
// private static void runCustomCode() {}
|
||||
|
||||
/* The code below is specific to this VM */
|
||||
|
||||
/**
|
||||
* Returns the <code>Class</code> representing the superclass of the entity
|
||||
* (class, interface, primitive type or void) represented by this
|
||||
* <code>Class</code>. If this <code>Class</code> represents either the
|
||||
* <code>Object</code> class, an interface, a primitive type, or void, then
|
||||
* null is returned. If this object represents an array class then the
|
||||
* <code>Class</code> object representing the <code>Object</code> class is
|
||||
* returned.
|
||||
*
|
||||
* Note that this method is not supported by CLDC.
|
||||
* We have made the method private, since it is
|
||||
* needed by our implementation.
|
||||
*
|
||||
* @return the superclass of the class represented by this object.
|
||||
*/
|
||||
private native Class getSuperclass();
|
||||
|
||||
/*
|
||||
* This private variable is used by the VM.
|
||||
* Users never see it.
|
||||
*/
|
||||
private transient Object vmClass;
|
||||
|
||||
private int status;
|
||||
private Thread thread;
|
||||
|
||||
private static final int IN_PROGRESS = 1;
|
||||
private static final int VERIFIED = 2;
|
||||
private static final int INITIALIZED = 4;
|
||||
private static final int ERROR = 8;
|
||||
|
||||
// Native for invoking <clinit>
|
||||
private native void invoke_clinit();
|
||||
|
||||
/**
|
||||
* Initialization at step 9:
|
||||
* If ENABLE_ISOLATES == false
|
||||
* Remove the <clinit> method after the class is initialized.
|
||||
* If ENABLE_ISOLATES == true, clear class initialization
|
||||
* barrier.
|
||||
*/
|
||||
private native void init9();
|
||||
|
||||
private native void invoke_verify();
|
||||
|
||||
/*
|
||||
* Implements the 11 step program detailed in Java Language Specification
|
||||
* 12.4.2
|
||||
*/
|
||||
void initialize() throws Throwable {
|
||||
// Step 1
|
||||
synchronized (this) {
|
||||
// Step 2
|
||||
while ((status & IN_PROGRESS) != 0 && thread != Thread.currentThread()) {
|
||||
try{
|
||||
wait();
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
|
||||
// Step 3
|
||||
if ((status & IN_PROGRESS) != 0 && thread == Thread.currentThread()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 4
|
||||
if ((status & INITIALIZED) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 5
|
||||
if (status == ERROR) {
|
||||
throw new NoClassDefFoundError(getName());
|
||||
}
|
||||
/* Note: CLDC 1.0 does not have NoClassDefFoundError class */
|
||||
|
||||
// Step 6
|
||||
status |= IN_PROGRESS;
|
||||
thread = Thread.currentThread();
|
||||
}
|
||||
|
||||
try {
|
||||
// Step 7
|
||||
invoke_verify();
|
||||
Class s = getSuperclass();
|
||||
if (s != null && (s.status & INITIALIZED) == 0) {
|
||||
// The test of s.status is not part of the spec, but
|
||||
// it saves us doing a lot of work in the most common
|
||||
// case.
|
||||
s.initialize();
|
||||
}
|
||||
|
||||
// Step 8
|
||||
invoke_clinit();
|
||||
|
||||
// Step 9
|
||||
synchronized (this) {
|
||||
status &= ~IN_PROGRESS;
|
||||
status |= INITIALIZED;
|
||||
thread = null;
|
||||
init9();
|
||||
notifyAll();
|
||||
}
|
||||
} catch(Throwable e) {
|
||||
// Step 10 and 11
|
||||
// CR 6224346, The cldc_vm threading mechanism is such that
|
||||
// we can just jam these values in without fear of another
|
||||
// thread doing the same since only this thread can be
|
||||
// executing the initialize() method and the scheduler is
|
||||
// non-preemptive. We do this here in case the monitorenter
|
||||
// fails due to OOME because some other thread holds the lock,
|
||||
// memory is low and we need to allocate a ConditionDesc to
|
||||
// wait for the lock.
|
||||
status = ERROR;
|
||||
thread = null;
|
||||
synchronized (this) {
|
||||
notifyAll();
|
||||
throwError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Error throwError(Throwable e) throws Error {
|
||||
throw (e instanceof Error) ? (Error)e
|
||||
: new Error("Static initializer: " + e.getClass().getName() +
|
||||
", " + e.getMessage());
|
||||
}
|
||||
}
|
|
@ -63,6 +63,7 @@ module J2ME {
|
|||
"java/lang/Class.newInstance.()Ljava/lang/Object;": YieldReason.Root,
|
||||
"java/lang/Thread.yield.()V": YieldReason.Root,
|
||||
"java/lang/Thread.start0.()V": YieldReason.Root,
|
||||
"java/lang/Class.forName0.(Ljava/lang/String;)V": YieldReason.Root,
|
||||
// Test Files:
|
||||
"gnu/testlet/vm/NativeTest.throwExceptionAfterPause.()V": YieldReason.Root,
|
||||
"gnu/testlet/vm/NativeTest.returnAfterPause.()I": YieldReason.Root,
|
||||
|
@ -192,6 +193,22 @@ module J2ME {
|
|||
|
||||
}
|
||||
|
||||
export function canStaticInitializerYield(classInfo: ClassInfo): YieldReason {
|
||||
var result = YieldReason.None;
|
||||
while (classInfo) {
|
||||
var staticInitializer = classInfo.staticInitializer;
|
||||
classInfo = classInfo.superClass;
|
||||
if (!staticInitializer) {
|
||||
continue;
|
||||
}
|
||||
result = canYield(staticInitializer);
|
||||
if (result !== YieldReason.None) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function canYield(methodInfo: MethodInfo): YieldReason {
|
||||
yieldWriter && yieldWriter.enter("> " + methodInfo.implKey);
|
||||
if (yieldMap[methodInfo.implKey] !== undefined) {
|
||||
|
@ -221,6 +238,14 @@ module J2ME {
|
|||
while (stream.currentBCI < methodInfo.code.length) {
|
||||
var op: Bytecodes = stream.currentBC();
|
||||
switch (op) {
|
||||
case Bytecodes.NEW:
|
||||
case Bytecodes.GETSTATIC:
|
||||
case Bytecodes.PUTSTATIC:
|
||||
var cpi = stream.readCPI();
|
||||
var fieldInfo = methodInfo.classInfo.resolve(cpi, true);
|
||||
var classInfo = fieldInfo.classInfo;
|
||||
result = canStaticInitializerYield(classInfo);
|
||||
break;
|
||||
case Bytecodes.MONITORENTER:
|
||||
case Bytecodes.MONITOREXIT:
|
||||
result = YieldReason.MonitorEnterExit;
|
||||
|
@ -246,6 +271,13 @@ module J2ME {
|
|||
}
|
||||
}
|
||||
|
||||
if (op === Bytecodes.INVOKESTATIC) {
|
||||
result = canStaticInitializerYield(methodInfo.classInfo);
|
||||
if (result !== YieldReason.None) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isStaticallyBound(op, callee)) {
|
||||
var callees = [];
|
||||
result = YieldReason.Virtual;
|
||||
|
|
|
@ -671,12 +671,18 @@ module J2ME {
|
|||
}
|
||||
|
||||
emitGetField(fieldInfo: FieldInfo, isStatic: boolean) {
|
||||
if (isStatic) {
|
||||
this.emitClassInitializationCheck(fieldInfo.classInfo);
|
||||
}
|
||||
var signature = TypeDescriptor.makeTypeDescriptor(fieldInfo.signature);
|
||||
var object = isStatic ? this.runtimeClass(fieldInfo.classInfo) : this.pop(Kind.Reference);
|
||||
this.emitPush(signature.kind, object + "." + fieldInfo.mangledName);
|
||||
}
|
||||
|
||||
emitPutField(fieldInfo: FieldInfo, isStatic: boolean) {
|
||||
if (isStatic) {
|
||||
this.emitClassInitializationCheck(fieldInfo.classInfo);
|
||||
}
|
||||
var signature = TypeDescriptor.makeTypeDescriptor(fieldInfo.signature);
|
||||
var value = this.pop(signature.kind);
|
||||
var object = isStatic ? this.runtimeClass(fieldInfo.classInfo) : this.pop(Kind.Reference);
|
||||
|
@ -740,14 +746,14 @@ module J2ME {
|
|||
var message = "Optimized ClassInitializationCheck: " + classInfo.className + ", self access.";
|
||||
emitDebugInfoComments && this.blockEmitter.writeLn("// " + message);
|
||||
baselineCounter && baselineCounter.count(message);
|
||||
} else if (this.methodInfo.classInfo.isAssignableTo(classInfo)) {
|
||||
} else if (!classInfo.isInterface && this.methodInfo.classInfo.isAssignableTo(classInfo)) {
|
||||
var message = "Optimized ClassInitializationCheck: " + classInfo.className + ", base access.";
|
||||
emitDebugInfoComments && this.blockEmitter.writeLn("// " + message);
|
||||
baselineCounter && baselineCounter.count(message);
|
||||
} else {
|
||||
baselineCounter && baselineCounter.count("ClassInitializationCheck: " + classInfo.className);
|
||||
this.blockEmitter.writeLn(this.runtimeClass(classInfo) + ";");
|
||||
if (classInfo.staticInitializer && canYield(classInfo.staticInitializer)) {
|
||||
this.blockEmitter.writeLn("if ($.initialized[\"" + classInfo.className + "\"] === undefined) { " + this.runtimeClassObject(classInfo) + ".initialize(); }");
|
||||
if (canStaticInitializerYield(classInfo)) {
|
||||
this.emitUnwind(this.blockEmitter, String(this.pc), String(this.pc));
|
||||
} else {
|
||||
emitCompilerAssertions && this.emitNoUnwindAssertion();
|
||||
|
@ -800,6 +806,7 @@ module J2ME {
|
|||
if (calleeCanYield) {
|
||||
this.emitUnwind(this.blockEmitter, String(this.pc), String(nextPC));
|
||||
} else {
|
||||
emitCompilerAssertions && this.emitUndefinedReturnAssertion();
|
||||
emitCompilerAssertions && this.emitNoUnwindAssertion();
|
||||
}
|
||||
if (types[0].kind !== Kind.Void) {
|
||||
|
@ -947,6 +954,10 @@ module J2ME {
|
|||
this.blockEmitter.writeLn("if (U) { J2ME.Debug.assert(false, 'Unexpected unwind.'); }");
|
||||
}
|
||||
|
||||
emitUndefinedReturnAssertion() {
|
||||
this.blockEmitter.writeLn("if (U && re !== undefined) { J2ME.Debug.assert(false, 'Unexpected return value during unwind.'); }");
|
||||
}
|
||||
|
||||
private emitMonitorEnter(emitter: Emitter, nextPC: number, object: string) {
|
||||
this.hasMonitorEnter = true;
|
||||
|
||||
|
|
87
native.js
87
native.js
|
@ -260,7 +260,7 @@ Native["com/sun/cldchi/jvm/JVM.monotonicTimeMillis.()J"] = function() {
|
|||
};
|
||||
|
||||
Native["java/lang/Object.getClass.()Ljava/lang/Class;"] = function() {
|
||||
return J2ME.getRuntimeKlass($.ctx.runtime, this.klass).classObject;
|
||||
return $.getRuntimeKlass(this.klass).classObject;
|
||||
};
|
||||
|
||||
Native["java/lang/Object.wait.(J)V"] = function(timeout) {
|
||||
|
@ -275,65 +275,56 @@ Native["java/lang/Object.notifyAll.()V"] = function() {
|
|||
$.ctx.notify(this, true);
|
||||
};
|
||||
|
||||
Native["java/lang/Class.invoke_clinit.()V"] = function() {
|
||||
var classInfo = this.classInfo;
|
||||
var className = classInfo.className;
|
||||
var runtime = $.ctx.runtime;
|
||||
if (runtime.initialized[className] || runtime.pending[className])
|
||||
return;
|
||||
runtime.pending[className] = true;
|
||||
if (className === "com/sun/cldc/isolate/Isolate") {
|
||||
// The very first isolate is granted access to the isolate API.
|
||||
var isolate = classInfo.getStaticObject($.ctx);
|
||||
CLASSES.getField(classInfo, "S._API_access_ok.I").set(isolate, 1);
|
||||
Native["java/lang/Class.getSuperclass.()Ljava/lang/Class;"] = function() {
|
||||
var superKlass = this.runtimeKlass.templateKlass.superKlass;
|
||||
if (!superKlass) {
|
||||
return null;
|
||||
}
|
||||
var clinit = CLASSES.getMethod(classInfo, "S.<clinit>.()V");
|
||||
return superKlass.classInfo.getClassObject();
|
||||
};
|
||||
|
||||
var frames = [];
|
||||
Native["java/lang/Class.invoke_clinit.()V"] = function() {
|
||||
var classInfo = this.runtimeKlass.templateKlass.classInfo;
|
||||
var className = classInfo.className;
|
||||
var clinit = CLASSES.getMethod(classInfo, "S.<clinit>.()V");
|
||||
if (clinit && clinit.classInfo.className === className) {
|
||||
frames.push(Frame.create(clinit, [], 0));
|
||||
}
|
||||
if (classInfo.superClass) {
|
||||
var classInitFrame = $.ctx.getClassInitFrame(classInfo.superClass);
|
||||
if (classInitFrame) {
|
||||
frames.push(classInitFrame);
|
||||
}
|
||||
}
|
||||
if (frames.length) {
|
||||
$.ctx.executeFrames(frames);
|
||||
$.ctx.executeFrames([Frame.create(clinit, [], 0)]);
|
||||
}
|
||||
};
|
||||
|
||||
Native["java/lang/Class.invoke_verify.()V"] = function() {
|
||||
// There is currently no verification.
|
||||
};
|
||||
|
||||
Native["java/lang/Class.init9.()V"] = function() {
|
||||
var classInfo = this.classInfo;
|
||||
var className = classInfo.className;
|
||||
var runtime = $.ctx.runtime;
|
||||
if (runtime.initialized[className])
|
||||
return;
|
||||
runtime.pending[className] = false;
|
||||
runtime.initialized[className] = true;
|
||||
$.setClassInitialized(this.runtimeKlass);
|
||||
};
|
||||
|
||||
Native["java/lang/Class.getName.()Ljava/lang/String;"] = function() {
|
||||
return J2ME.newString(this.runtimeKlass.templateKlass.classInfo.className.replace(/\//g, "."));
|
||||
};
|
||||
|
||||
Native["java/lang/Class.forName.(Ljava/lang/String;)Ljava/lang/Class;"] = function(name) {
|
||||
try {
|
||||
if (!name)
|
||||
throw new J2ME.ClassNotFoundException();
|
||||
var className = util.fromJavaString(name).replace(/\./g, "/");
|
||||
var classInfo = null;
|
||||
classInfo = CLASSES.getClass(className);
|
||||
} catch (e) {
|
||||
if (e instanceof (J2ME.ClassNotFoundException))
|
||||
throw $.newClassNotFoundException("'" + e.message + "' not found.");
|
||||
throw e;
|
||||
}
|
||||
J2ME.linkKlass(classInfo);
|
||||
var classObject = classInfo.getClassObject();
|
||||
J2ME.Debug.assert(!U, "Unwinding isn't currently supported here.");
|
||||
return classObject;
|
||||
Native["java/lang/Class.forName0.(Ljava/lang/String;)V"] = function(name) {
|
||||
var classInfo = null;
|
||||
try {
|
||||
if (!name)
|
||||
throw new J2ME.ClassNotFoundException();
|
||||
var className = util.fromJavaString(name).replace(/\./g, "/");
|
||||
classInfo = CLASSES.getClass(className);
|
||||
} catch (e) {
|
||||
if (e instanceof (J2ME.ClassNotFoundException))
|
||||
throw $.newClassNotFoundException("'" + e.message + "' not found.");
|
||||
throw e;
|
||||
}
|
||||
// The following can trigger an unwind.
|
||||
J2ME.classInitCheck(classInfo);
|
||||
};
|
||||
|
||||
Native["java/lang/Class.forName1.(Ljava/lang/String;)Ljava/lang/Class;"] = function(name) {
|
||||
var className = util.fromJavaString(name).replace(/\./g, "/");
|
||||
var classInfo = CLASSES.getClass(className);
|
||||
var classObject = classInfo.getClassObject();
|
||||
return classObject;
|
||||
};
|
||||
|
||||
Native["java/lang/Class.newInstance.()Ljava/lang/Object;"] = function() {
|
||||
|
@ -564,7 +555,7 @@ Native["java/lang/Thread.start0.()V"] = function() {
|
|||
])
|
||||
});
|
||||
|
||||
newCtx.start(new Frame(syntheticMethod, [ this ], 0));
|
||||
newCtx.start([new Frame(syntheticMethod, [ this ], 0)]);
|
||||
};
|
||||
|
||||
Native["java/lang/Thread.internalExit.()V"] = function() {
|
||||
|
|
|
@ -162,29 +162,29 @@ casper.test.begin("unit tests", 19 + gfxTests.length, function(test) {
|
|||
casper.waitForText("DONE", function() {
|
||||
test.assertTextExists("I m\n" +
|
||||
"I a ma\n" +
|
||||
"I 2\n" +
|
||||
"I 3\n" +
|
||||
"I ma\n" +
|
||||
"I 2\n" +
|
||||
"I 3\n" +
|
||||
"I 1 isolate\n" +
|
||||
"I Isolate ID correct\n" +
|
||||
"I 4\n" +
|
||||
"I 5\n" +
|
||||
"I 6\n" +
|
||||
"I 1 isolate\n" +
|
||||
"I ma\n" +
|
||||
"I ma\n" +
|
||||
"I 3 isolates\n" +
|
||||
"I 1 m1\n" +
|
||||
"I 4\n" +
|
||||
"I 2 m2\n" +
|
||||
"I 5\n" +
|
||||
"I 2 m2\n" +
|
||||
"I 6\n" +
|
||||
"I ma\n" +
|
||||
"I 1 isolate\n" +
|
||||
"I Isolates terminated\n" +
|
||||
"I r mar\n" +
|
||||
"I 2\n" +
|
||||
"I 3\n" +
|
||||
"I mar\n" +
|
||||
"I c marc\n" +
|
||||
"I 2\n" +
|
||||
"I 3\n" +
|
||||
"I marc\n" +
|
||||
"I Main isolate still running");
|
||||
});
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package java.lang;
|
||||
|
||||
import gnu.testlet.Testlet;
|
||||
import gnu.testlet.TestHarness;
|
||||
|
||||
class Monkey {
|
||||
public static final String name;
|
||||
|
||||
static {
|
||||
try {
|
||||
Thread.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
name = "Monkey";
|
||||
}
|
||||
}
|
||||
|
||||
public class TestStaticInitRaceCondition extends Thread implements Testlet {
|
||||
private TestHarness th;
|
||||
public int getExpectedPass() { return 2; }
|
||||
public int getExpectedFail() { return 0; }
|
||||
public int getExpectedKnownFail() { return 0; }
|
||||
|
||||
public void test(TestHarness th) {
|
||||
this.th = th;
|
||||
start();
|
||||
run();
|
||||
try {
|
||||
this.join();
|
||||
} catch (InterruptedException e) {
|
||||
th.fail();
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
th.check(Monkey.name, "Monkey");
|
||||
}
|
||||
}
|
|
@ -58,6 +58,7 @@ module J2ME {
|
|||
* because they don't have any static state.
|
||||
*/
|
||||
var classNames = [
|
||||
"com/sun/cldc/isolate/Isolate", // Not used frequently, but needs setup before we start the isolates.
|
||||
"java/lang/Integer",
|
||||
"java/lang/Character",
|
||||
"java/lang/Math",
|
||||
|
|
|
@ -439,85 +439,14 @@ module J2ME {
|
|||
return returnValue;
|
||||
}
|
||||
|
||||
getClassInitFrame(classInfo: ClassInfo) {
|
||||
if (this.runtime.initialized[classInfo.className]) {
|
||||
return;
|
||||
}
|
||||
classInfo.thread = this.thread;
|
||||
var syntheticMethod = new MethodInfo({
|
||||
name: "ClassInitSynthetic",
|
||||
signature: "()V",
|
||||
isStatic: false,
|
||||
classInfo: ClassInfo.createFromObject({
|
||||
className: {value: classInfo.className},
|
||||
vmc: {value: {}},
|
||||
vfc: {value: {}},
|
||||
constant_pool: {value: [
|
||||
null,
|
||||
{tag: TAGS.CONSTANT_Methodref, class_index: 2, name_and_type_index: 4},
|
||||
{tag: TAGS.CONSTANT_Class, name_index: 3},
|
||||
{bytes: "java/lang/Class"},
|
||||
{name_index: 5, signature_index: 6},
|
||||
{bytes: "invoke_clinit"},
|
||||
{bytes: "()V"},
|
||||
{tag: TAGS.CONSTANT_Methodref, class_index: 2, name_and_type_index: 8},
|
||||
{name_index: 9, signature_index: 10},
|
||||
{bytes: "init9"},
|
||||
{bytes: "()V"},
|
||||
]},
|
||||
}),
|
||||
code: new Uint8Array([
|
||||
0x2a, // aload_0
|
||||
0x59, // dup
|
||||
0x59, // dup
|
||||
0x59, // dup
|
||||
0xc2, // monitorenter
|
||||
0xb7, 0x00, 0x01, // invokespecial <idx=1>
|
||||
0xb7, 0x00, 0x07, // invokespecial <idx=7>
|
||||
0xc3, // monitorexit
|
||||
0xb1, // return
|
||||
])
|
||||
});
|
||||
return Frame.create(syntheticMethod, [classInfo.getClassInitLockObject(this)], 0);
|
||||
}
|
||||
|
||||
pushClassInitFrame(classInfo: ClassInfo) {
|
||||
if (this.runtime.initialized[classInfo.className] ||
|
||||
this.runtime.pending[classInfo.className]) {
|
||||
return;
|
||||
}
|
||||
var needsInitialization = true;
|
||||
if (!classInfo.staticInitializer) {
|
||||
needsInitialization = false;
|
||||
// Special case Isolate.
|
||||
if (classInfo.className === "com/sun/cldc/isolate/Isolate") {
|
||||
needsInitialization = true;
|
||||
}
|
||||
var superClass = classInfo.superClass;
|
||||
while (superClass) {
|
||||
if (!this.runtime.initialized[superClass.className] &&
|
||||
superClass.staticInitializer) {
|
||||
needsInitialization = true;
|
||||
break;
|
||||
}
|
||||
superClass = superClass.superClass;
|
||||
}
|
||||
}
|
||||
linkKlass(classInfo);
|
||||
if (!needsInitialization) {
|
||||
this.runtime.initialized[classInfo.className] = true;
|
||||
return;
|
||||
}
|
||||
var classInitFrame = this.getClassInitFrame(classInfo);
|
||||
this.executeFrames([classInitFrame]);
|
||||
}
|
||||
|
||||
createException(className: string, message?: string) {
|
||||
if (!message) {
|
||||
message = "";
|
||||
}
|
||||
message = "" + message;
|
||||
var classInfo = CLASSES.loadAndLinkClass(className);
|
||||
classInitCheck(classInfo);
|
||||
release || Debug.assert(!U, "Unexpected unwind during createException.");
|
||||
runtimeCounter && runtimeCounter.count("createException " + className);
|
||||
var exception = new classInfo.klass();
|
||||
var methodInfo = CLASSES.getMethod(classInfo, "I.<init>.(Ljava/lang/String;)V");
|
||||
|
@ -547,8 +476,9 @@ module J2ME {
|
|||
Context.setWriters(Context.writer);
|
||||
}
|
||||
|
||||
start(frame: Frame) {
|
||||
this.frames = [Frame.Start, frame];
|
||||
start(frames: Frame[]) {
|
||||
frames.unshift(Frame.Start);
|
||||
this.frames = frames;
|
||||
this.resume();
|
||||
}
|
||||
|
||||
|
|
54
vm/jvm.ts
54
vm/jvm.ts
|
@ -8,42 +8,49 @@ module J2ME {
|
|||
constructor() {
|
||||
// ...
|
||||
}
|
||||
|
||||
startIsolate0(className: string, args: string []) {
|
||||
|
||||
private createIsolateCtx(): Context {
|
||||
var runtime = new Runtime(this);
|
||||
var ctx = new Context(runtime);
|
||||
ctx.setAsCurrentContext();
|
||||
ctx.thread = runtime.mainThread = <java.lang.Thread>newObject(CLASSES.java_lang_Thread.klass);
|
||||
ctx.thread.pid = util.id();
|
||||
ctx.thread.alive = true;
|
||||
// The constructor will set the real priority, however one is needed for the scheduler.
|
||||
ctx.thread.priority = NORMAL_PRIORITY;
|
||||
runtime.preInitializeClasses(ctx);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
startIsolate0(className: string, args: string []) {
|
||||
var ctx = this.createIsolateCtx();
|
||||
|
||||
var isolateClassInfo = CLASSES.getClass("com/sun/cldc/isolate/Isolate");
|
||||
|
||||
linkKlass(isolateClassInfo);
|
||||
var isolate: Isolate = <Isolate>newObject(isolateClassInfo.klass);
|
||||
|
||||
isolate.id = util.id();
|
||||
|
||||
var array = newStringArray(args.length);
|
||||
for (var n = 0; n < args.length; ++n)
|
||||
array[n] = args[n] ? J2ME.newString(args[n]) : null;
|
||||
|
||||
ctx.executeFrames([
|
||||
// The <init> frames go at the end of the array so they are executed first to initialize the thread and isolate.
|
||||
ctx.start([
|
||||
Frame.create(CLASSES.getMethod(isolateClassInfo, "I.start.()V"), [ isolate ], 0),
|
||||
Frame.create(CLASSES.getMethod(isolateClassInfo, "I.<init>.(Ljava/lang/String;[Ljava/lang/String;)V"),
|
||||
[ isolate, J2ME.newString(className.replace(/\./g, "/")), array ], 0)
|
||||
[ isolate, J2ME.newString(className.replace(/\./g, "/")), array ], 0)
|
||||
]);
|
||||
|
||||
ctx.start(Frame.create(CLASSES.getMethod(isolateClassInfo, "I.start.()V"), [ isolate ], 0));
|
||||
release || Debug.assert(!U, "Unexpected unwind during isolate initialization.");
|
||||
}
|
||||
|
||||
startIsolate(isolate: Isolate) {
|
||||
var mainClass = util.fromJavaString(isolate.klass.classInfo.getField("I._mainClass.Ljava/lang/String;").get(isolate)).replace(/\./g, "/");
|
||||
var mainArgs = isolate.klass.classInfo.getField("I._mainArgs.[Ljava/lang/String;").get(isolate);
|
||||
var runtime = new J2ME.Runtime(this);
|
||||
var ctx = new Context(runtime);
|
||||
|
||||
var ctx = this.createIsolateCtx();
|
||||
var runtime = ctx.runtime;
|
||||
isolate.runtime = runtime;
|
||||
runtime.isolate = isolate;
|
||||
|
||||
runtime.updateStatus(RuntimeStatus.Started);
|
||||
|
||||
var mainClass = util.fromJavaString(isolate.klass.classInfo.getField("I._mainClass.Ljava/lang/String;").get(isolate)).replace(/\./g, "/");
|
||||
var mainArgs = isolate.klass.classInfo.getField("I._mainArgs.[Ljava/lang/String;").get(isolate);
|
||||
var classInfo = CLASSES.getClass(mainClass);
|
||||
linkKlass(classInfo);
|
||||
if (!classInfo)
|
||||
|
@ -53,22 +60,17 @@ module J2ME {
|
|||
if (!entryPoint)
|
||||
throw new Error("Could not find main method in class " + mainClass);
|
||||
|
||||
ctx.thread = runtime.mainThread = <java.lang.Thread>newObject(CLASSES.java_lang_Thread.klass);
|
||||
ctx.thread.pid = util.id();
|
||||
ctx.thread.alive = true;
|
||||
|
||||
var oldCtx = $.ctx;
|
||||
ctx.setAsCurrentContext();
|
||||
ctx.executeFrames([Frame.create(CLASSES.getMethod(CLASSES.java_lang_Thread, "I.<init>.(Ljava/lang/String;)V"),
|
||||
[ runtime.mainThread, J2ME.newString("main") ], 0)])
|
||||
oldCtx.setAsCurrentContext();
|
||||
|
||||
var args = J2ME.newStringArray(mainArgs.length);
|
||||
for (var n = 0; n < mainArgs.length; ++n) {
|
||||
args[n] = mainArgs[n];
|
||||
}
|
||||
|
||||
ctx.start(Frame.create(entryPoint, [ args ], 0));
|
||||
ctx.start([
|
||||
Frame.create(entryPoint, [ args ], 0),
|
||||
Frame.create(CLASSES.getMethod(CLASSES.java_lang_Thread, "I.<init>.(Ljava/lang/String;)V"),
|
||||
[ runtime.mainThread, J2ME.newString("main") ], 0)
|
||||
]);
|
||||
release || Debug.assert(!U, "Unexpected unwind during isolate initialization.");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -441,7 +441,6 @@ module J2ME {
|
|||
pending: any;
|
||||
staticFields: any;
|
||||
classObjects: any;
|
||||
classInitLockObjects: any;
|
||||
ctx: Context;
|
||||
|
||||
isolate: com.sun.cldc.isolate.Isolate;
|
||||
|
@ -461,10 +460,42 @@ module J2ME {
|
|||
this.staticFields = {};
|
||||
this.classObjects = {};
|
||||
this.ctx = null;
|
||||
this.classInitLockObjects = {};
|
||||
this._runtimeId = RuntimeTemplate._nextRuntimeId ++;
|
||||
this._nextHashCode = this._runtimeId << 24;
|
||||
}
|
||||
|
||||
preInitializeClasses(ctx: Context) {
|
||||
var prevCtx = $ ? $.ctx : null;
|
||||
var preInit = CLASSES.preInitializedClasses;
|
||||
ctx.setAsCurrentContext();
|
||||
for (var i = 0; i < preInit.length; i++) {
|
||||
var runtimeKlass = this.getRuntimeKlass(preInit[i].klass);
|
||||
runtimeKlass.classObject.initialize();
|
||||
release || Debug.assert(!U, "Unexpected unwind during preInitializeClasses.");
|
||||
}
|
||||
ctx.clearCurrentContext();
|
||||
if (prevCtx) {
|
||||
prevCtx.setAsCurrentContext();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* After class intialization is finished the init9 method will invoke this so
|
||||
* any further initialize calls can be avoided. This isn't set on the first call
|
||||
* to a class initializer because there can be multiple calls into initialize from
|
||||
* different threads that need trigger the Class.initialize() code so they block.
|
||||
*/
|
||||
setClassInitialized(runtimeKlass: RuntimeKlass) {
|
||||
var className = runtimeKlass.templateKlass.classInfo.className;
|
||||
this.initialized[className] = true;
|
||||
}
|
||||
|
||||
getRuntimeKlass(klass: Klass): RuntimeKlass {
|
||||
release || assert(!(klass instanceof RuntimeKlass));
|
||||
release || assert(klass.classInfo.mangledName);
|
||||
var runtimeKlass = this[klass.classInfo.mangledName];
|
||||
return runtimeKlass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new hash code for the specified |object|.
|
||||
|
@ -854,6 +885,15 @@ module J2ME {
|
|||
release || assert(!runtimeKlass.classObject);
|
||||
runtimeKlass.classObject = <java.lang.Class><any>new Klasses.java.lang.Class();
|
||||
runtimeKlass.classObject.runtimeKlass = runtimeKlass;
|
||||
var className = runtimeKlass.templateKlass.classInfo.className;
|
||||
if (className === "java/lang/Object" ||
|
||||
className === "java/lang/Class" ||
|
||||
className === "java/lang/String" ||
|
||||
className === "java/lang/Thread") {
|
||||
(<any>runtimeKlass.classObject).status = 4;
|
||||
$.setClassInitialized(runtimeKlass);
|
||||
return;
|
||||
}
|
||||
var fields = runtimeKlass.templateKlass.classInfo.fields;
|
||||
for (var i = 0; i < fields.length; i++) {
|
||||
var field = fields[i];
|
||||
|
@ -892,10 +932,6 @@ module J2ME {
|
|||
Object.defineProperty(this, classInfo.mangledName, {
|
||||
value: runtimeKlass
|
||||
});
|
||||
initWriter && initWriter.writeLn("Running Static Constructor: " + classInfo.className);
|
||||
$.ctx.pushClassInitFrame(classInfo);
|
||||
release || assert(!U, "Unwinding during static initializer not supported.");
|
||||
|
||||
return runtimeKlass;
|
||||
}
|
||||
});
|
||||
|
@ -952,14 +988,6 @@ module J2ME {
|
|||
}
|
||||
}
|
||||
|
||||
export function getRuntimeKlass(runtime: Runtime, klass: Klass): RuntimeKlass {
|
||||
release || assert(!(klass instanceof RuntimeKlass));
|
||||
release || assert(klass.classInfo.mangledName);
|
||||
var runtimeKlass = runtime[klass.classInfo.mangledName];
|
||||
// assert(runtimeKlass instanceof RuntimeKlass);
|
||||
return runtimeKlass;
|
||||
}
|
||||
|
||||
function setKlassSymbol(mangledName: string, klass: Klass) {
|
||||
Object.defineProperty(jsGlobal, mangledName, {
|
||||
value: klass
|
||||
|
@ -1340,6 +1368,7 @@ module J2ME {
|
|||
function linkKlassMethods(klass: Klass) {
|
||||
linkWriter && linkWriter.enter("Link Klass Methods: " + klass);
|
||||
var methods = klass.classInfo.methods;
|
||||
var classBindings = Bindings[klass.classInfo.className];
|
||||
for (var i = 0; i < methods.length; i++) {
|
||||
var methodInfo = methods[i];
|
||||
if (methodInfo.isAbstract) {
|
||||
|
@ -1389,6 +1418,12 @@ module J2ME {
|
|||
}
|
||||
if (!methodInfo.isStatic) {
|
||||
klass.prototype[methodInfo.mangledName] = fn;
|
||||
if (classBindings && classBindings.methods && classBindings.methods.instanceSymbols) {
|
||||
var methodKey = classBindings.methods.instanceSymbols[methodInfo.name + "." + methodInfo.signature];
|
||||
if (methodKey) {
|
||||
klass.prototype[methodKey] = fn;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1843,15 +1878,13 @@ module J2ME {
|
|||
return e;
|
||||
}
|
||||
|
||||
export function classInitCheck(classInfo: ClassInfo, pc: number) {
|
||||
if (classInfo.isArrayClass) {
|
||||
return;
|
||||
}
|
||||
$.ctx.pushClassInitFrame(classInfo);
|
||||
if (U) {
|
||||
$.ctx.current().pc = pc;
|
||||
export function classInitCheck(classInfo: ClassInfo) {
|
||||
if (classInfo.isArrayClass || $.initialized[classInfo.className]) {
|
||||
return;
|
||||
}
|
||||
linkKlass(classInfo);
|
||||
var runtimeKlass = $.getRuntimeKlass(classInfo.klass);
|
||||
runtimeKlass.classObject.initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Загрузка…
Ссылка в новой задаче