sketch of Runtime.exec() and Calendar; misc bugfixes

This commit is contained in:
Joel Dice 2007-09-12 18:21:37 -06:00
parent 182414c6e0
commit 7cb3a30a91
21 changed files with 339 additions and 54 deletions

View File

@ -14,16 +14,24 @@ Java_java_lang_System_getProperty(JNIEnv* e, jclass, jint code)
{
enum {
LineSeparator = 100,
OsName = 101
FileSeparator = 101,
OsName = 102,
JavaIoTmpdir = 103
};
switch (code) {
case LineSeparator:
return e->NewStringUTF("\n");
case FileSeparator:
return e->NewStringUTF("/");
case OsName:
return e->NewStringUTF("posix");
case JavaIoTmpdir:
return e->NewStringUTF("/tmp");
default:
throwNew(e, "java/lang/RuntimeException", 0);
return 0;

View File

@ -7,7 +7,7 @@ public class FileDescriptor {
final int value;
private FileDescriptor(int value) {
public FileDescriptor(int value) {
this.value = value;
}

View File

@ -31,8 +31,20 @@ public final class Class <T> {
return getName();
}
private static byte[] replace(int a, int b, byte[] s, int offset,
int length)
{
byte[] array = new byte[length];
for (int i = 0; i < length; ++i) {
byte c = s[i];
array[i] = (byte) (c == a ? b : c);
}
return array;
}
public String getName() {
return new String(name, 0, name.length - 1, false);
return new String
(replace('/', '.', name, 0, name.length - 1), 0, name.length - 1, false);
}
public Object[] staticTable() {

View File

@ -0,0 +1,18 @@
package java.lang;
import java.io.InputStream;
import java.io.OutputStream;
public abstract class Process {
public abstract void destroy();
public abstract int exitValue();
public abstract InputStream getInputStream();
public abstract OutputStream getOutputStream();
public abstract InputStream getErrorStream();
public abstract int waitFor() throws InterruptedException;
}

View File

@ -1,5 +1,11 @@
package java.lang;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;
import java.io.FileDescriptor;
public class Runtime {
private static final Runtime instance = new Runtime();
@ -25,6 +31,26 @@ public class Runtime {
}
}
public Process exec(String command) {
int[] process = new int[4];
exec(command, process);
return new MyProcess(process[0], process[1], process[2], process[3]);
}
public Process exec(String[] command) {
int[] process = new int[4];
exec(command, process);
return new MyProcess(process[0], process[1], process[2], process[3]);
}
private static native void exec(String command, int[] process);
private static native void exec(String[] command, int[] process);
private static native int exitValue(int pid);
private static native int waitFor(int pid);
private static native void load(String name, boolean mapName);
public native void gc();
@ -32,4 +58,50 @@ public class Runtime {
public native void exit(int code);
public native long freeMemory();
private static class MyProcess extends Process {
private int pid;
private final int in;
private final int out;
private final int err;
private int exitCode;
public MyProcess(int pid, int in, int out, int err) {
this.pid = pid;
this.in = in;
this.out = out;
this.err = err;
}
public void destroy() {
throw new RuntimeException("not implemented");
}
public int exitValue() {
if (pid != 0) {
exitCode = Runtime.exitValue(pid);
}
return exitCode;
}
public InputStream getInputStream() {
return new FileInputStream(new FileDescriptor(in));
}
public OutputStream getOutputStream() {
return new FileOutputStream(new FileDescriptor(out));
}
public InputStream getErrorStream() {
return new FileInputStream(new FileDescriptor(err));
}
public int waitFor() throws InterruptedException {
if (pid != 0) {
exitCode = Runtime.waitFor(pid);
pid = 0;
}
return exitCode;
}
}
}

View File

@ -294,7 +294,9 @@ public final class String implements Comparable<String> {
return b;
}
public byte[] getBytes(String format) {
public byte[] getBytes(String format)
throws java.io.UnsupportedEncodingException
{
return getBytes();
}

View File

@ -50,6 +50,11 @@ public class StringBuffer {
return this;
}
public synchronized StringBuffer insert(int i, char c) {
sb.insert(i, c);
return this;
}
public synchronized StringBuffer deleteCharAt(int i) {
sb.deleteCharAt(i);
return this;

View File

@ -135,6 +135,10 @@ public class StringBuilder {
return this;
}
public StringBuilder insert(int i, char c) {
return insert(i, new String(new char[] { c }, 0, 1, false));
}
public StringBuilder deleteCharAt(int i) {
if (i < 0 || i >= length) {
throw new IndexOutOfBoundsException();

View File

@ -12,7 +12,9 @@ public abstract class System {
private static final int Unknown = 0;
private static final int JavaClassPath = 1;
private static final int LineSeparator = 100;
private static final int OsName = 101;
private static final int FileSeparator = 101;
private static final int OsName = 102;
private static final int JavaIoTmpdir = 103;
private static Property properties;
@ -42,8 +44,12 @@ public abstract class System {
int code = Unknown;
if (name.equals("java.class.path")) {
code = JavaClassPath;
} else if (name.equals("java.io.tmpdir")) {
code = JavaIoTmpdir;
} else if (name.equals("line.separator")) {
code = LineSeparator;
} else if (name.equals("file.separator")) {
code = FileSeparator;
} else if (name.equals("os.name")) {
code = OsName;
}

View File

@ -51,22 +51,28 @@ public class Field<T> extends AccessibleObject {
Object v = class_.staticTable()[offset];
switch (code) {
case ByteField:
return Byte.valueOf((byte) ((Integer) v).intValue());
return Byte.valueOf
((byte) (v == null ? 0 : ((Integer) v).intValue()));
case BooleanField:
return Boolean.valueOf(((Integer) v) != 0);
return Boolean.valueOf
(v == null ? false : ((Integer) v) != 0);
case CharField:
return Character.valueOf((char) ((Integer) v).intValue());
return Character.valueOf
((char) (v == null ? 0 : ((Integer) v).intValue()));
case ShortField:
return Short.valueOf((short) ((Integer) v).intValue());
return Short.valueOf
((short) (v == null ? 0 : ((Integer) v).intValue()));
case FloatField:
return Float.valueOf(Float.intBitsToFloat((Integer) v));
return Float.valueOf
(Float.intBitsToFloat(v == null ? 0 : (Integer) v));
case DoubleField:
return Double.valueOf(Double.longBitsToDouble((Long) v));
return Double.valueOf
(Double.longBitsToDouble(v == null ? 0 : (Long) v));
case IntField:
case LongField:

View File

@ -1,5 +1,13 @@
package java.text;
public class DateFormatSymbols {
private String[] ampm = new String[] { "AM", "PM" };
public String[] getAmPmStrings() {
return ampm;
}
public void setAmPmStrings(String[] v) {
ampm = v;
}
}

View File

@ -3,7 +3,7 @@ package java.text;
import java.util.Locale;
public class MessageFormat extends Format {
private final String pattern;
private String pattern;
private final Locale locale;
public MessageFormat(String pattern, Locale locale) {
@ -19,4 +19,8 @@ public class MessageFormat extends Format {
// todo
return target.append(pattern);
}
public void applyPattern(String pattern) {
this.pattern = pattern;
}
}

View File

@ -11,4 +11,77 @@ public abstract class Calendar {
public static final int PM = 1;
public static final int SECOND = 13;
public static final int YEAR = 1;
public static final int FIELD_COUNT = 17;
protected long time;
protected boolean isTimeSet;
protected int[] fields = new int[FIELD_COUNT];
protected boolean areFieldsSet;
protected boolean[] isSet = new boolean[FIELD_COUNT];
protected Calendar() { }
public static Calendar getInstance() {
return new MyCalendar(System.currentTimeMillis());
}
public int get(int field) {
return fields[field];
}
public void set(int field, int value) {
fields[field] = value;
}
public abstract void roll(int field, boolean up);
public void roll(int field, int amount) {
boolean up = amount >= 0;
if (! up) {
amount = - amount;
}
for (int i = 0; i < amount; ++i) {
roll(field, up);
}
}
public abstract int getMinimum(int field);
public abstract int getMaximum(int field);
public abstract int getActualMinimum(int field);
public abstract int getActualMaximum(int field);
private static class MyCalendar extends Calendar {
public MyCalendar(long time) {
this.time = time;
this.isTimeSet = true;
}
public void roll(int field, boolean up) {
// todo
}
public int getMinimum(int field) {
// todo
return 0;
}
public int getMaximum(int field) {
// todo
return 0;
}
public int getActualMinimum(int field) {
// todo
return 0;
}
public int getActualMaximum(int field) {
// todo
return 0;
}
}
}

View File

@ -16,8 +16,10 @@ src = src
classpath = classpath
test = test
jscheme = $(HOME)/p/jscheme-7.2/src
swt = $(HOME)/p/swt-3.3/bin
input = $(cls)/GC.class
swt-input = $(cls)/HelloSWT.class
cxx = g++
cc = gcc
@ -139,10 +141,13 @@ args = $(flags) $(call class-name,$(input))
jscheme-command = jscheme/REPL build/make.scm -main commandMain ""
swt-command = $(call class-name,$(swt-input))
.PHONY: build
build: $(executable)
$(input): $(classpath-objects)
$(swt-input): $(classpath-objects)
.PHONY: run
run: $(executable) $(input)
@ -162,25 +167,37 @@ test: $(executable) $(classpath-objects) $(test-classes)
$(<) $(mode) "$(flags)" $(call class-names,$(test-classes))
.PHONY: run-jscheme
run-jscheme: $(executable) $(input)
run-jscheme: $(executable)
LD_LIBRARY_PATH=$(bld) $(<) -cp $(cls):$(jscheme) $(jscheme-command)
.PHONY: debug-jscheme
debug-jscheme: $(executable) $(input)
debug-jscheme: $(executable)
LD_LIBRARY_PATH=$(bld) $(db) $(<) -cp $(cls):$(jscheme) $(jscheme-command)
.PHONY: vg-jscheme
vg-jscheme: $(executable) $(input)
vg-jscheme: $(executable)
LD_LIBRARY_PATH=$(bld) $(vg) $(<) -cp $(cls):$(jscheme) $(jscheme-command)
.PHONY: profile-jscheme
profile-jscheme: $(executable) $(input)
profile-jscheme: $(executable)
opcontrol --start; \
echo '(+ 5 6)' | LD_LIBRARY_PATH=$(bld) \
$(<) -cp $(cls):$(jscheme) jscheme/REPL; \
opcontrol --stop; \
opreport -l $(<)
.PHONY: run-swt
run-swt: $(executable) $(swt-input)
LD_LIBRARY_PATH=$(bld) $(<) -cp $(cls):$(swt) $(swt-command)
.PHONY: debug-swt
debug-swt: $(executable) $(swt-input)
LD_LIBRARY_PATH=$(bld) $(db) $(<) -cp $(cls):$(swt) $(swt-command)
.PHONY: vg-swt
vg-swt: $(executable) $(swt-input)
LD_LIBRARY_PATH=$(bld) $(vg) $(<) -cp $(cls):$(swt) $(swt-command)
.PHONY: clean
clean:
@echo "removing build"
@ -202,7 +219,8 @@ $(bld)/type-generator.o: \
define compile-class
@echo "compiling $(@)"
@mkdir -p $(dir $(@))
$(javac) -bootclasspath $(classpath) -classpath $(classpath) -d $(cls) $(<)
$(javac) -bootclasspath $(classpath) -classpath $(classpath):$(swt) \
-d $(cls) $(<)
endef
$(cls)/%.class: $(classpath)/%.java

View File

@ -419,7 +419,7 @@ Runtime_load(Thread* t, jclass, jstring name, jboolean mapName)
t->vm->libraries = lib;
} else {
object message = makeString(t, "library not found: %s", n);
t->exception = makeRuntimeException(t, message);
t->exception = makeUnsatisfiedLinkError(t, message);
}
}
@ -558,11 +558,13 @@ jint JNICALL
ResourceInputStream_read2(Thread* t, jclass, jlong peer, jint position,
jbyteArray b, jint offset, jint length)
{
if (length == 0) return 0;
Finder::Data* d = reinterpret_cast<Finder::Data*>(peer);
if (length > static_cast<jint>(d->length()) - position) {
length = static_cast<jint>(d->length()) - position;
}
if (length < 0) {
if (length <= 0) {
return -1;
} else {
memcpy(&byteArrayBody(t, *b, offset), d->start() + position, length);

View File

@ -153,10 +153,10 @@ findMethod(Thread* t, object class_, const char* name, const char* spec)
{
ENTER(t, Thread::ActiveState);
object n = makeString(t, "%s", name);
object n = makeByteArray(t, "%s", name);
PROTECT(t, n);
object s = makeString(t, "%s", spec);
object s = makeByteArray(t, "%s", spec);
return vm::findMethod(t, class_, n, s);
}
@ -184,7 +184,7 @@ GetMethodID(Thread* t, jclass c, const char* name, const char* spec)
return (vectorSize(t, t->vm->jniInterfaceTable) - 1) | InterfaceMethodID;
} else {
return methodOffset(t, method);
return methodOffset(t, method) + 1;
}
}
@ -196,7 +196,7 @@ GetStaticMethodID(Thread* t, jclass c, const char* name, const char* spec)
object method = findMethod(t, *c, name, spec);
if (UNLIKELY(t->exception)) return 0;
return methodOffset(t, method);
return methodOffset(t, method) + 1;
}
inline object
@ -205,7 +205,7 @@ getMethod(Thread* t, object o, jmethodID m)
if (m & InterfaceMethodID) {
return vectorBody(t, t->vm->jniInterfaceTable, m & (~InterfaceMethodID));
} else {
return arrayBody(t, classVirtualTable(t, objectClass(t, o)), m);
return arrayBody(t, classVirtualTable(t, objectClass(t, o)), m - 1);
}
}
@ -634,10 +634,10 @@ CallStaticVoidMethod(Thread* t, jclass c, jmethodID m, ...)
object
findField(Thread* t, object class_, const char* name, const char* spec)
{
object n = makeString(t, "%s", name);
object n = makeByteArray(t, "%s", name);
PROTECT(t, n);
object s = makeString(t, "%s", spec);
object s = makeByteArray(t, "%s", spec);
return vm::findField(t, class_, n, s);
}
@ -820,7 +820,8 @@ GetStaticBooleanField(Thread* t, jclass c, jfieldID field)
{
ENTER(t, Thread::ActiveState);
return intValue(t, arrayBody(t, classStaticTable(t, *c), field)) != 0;
object v = arrayBody(t, classStaticTable(t, *c), field);
return v ? intValue(t, v) != 0 : false;
}
jbyte JNICALL
@ -828,8 +829,8 @@ GetStaticByteField(Thread* t, jclass c, jfieldID field)
{
ENTER(t, Thread::ActiveState);
return static_cast<jbyte>
(intValue(t, arrayBody(t, classStaticTable(t, *c), field)));
object v = arrayBody(t, classStaticTable(t, *c), field);
return static_cast<jbyte>(v ? intValue(t, v) : 0);
}
jchar JNICALL
@ -837,8 +838,8 @@ GetStaticCharField(Thread* t, jclass c, jfieldID field)
{
ENTER(t, Thread::ActiveState);
return static_cast<jchar>
(intValue(t, arrayBody(t, classStaticTable(t, *c), field)));
object v = arrayBody(t, classStaticTable(t, *c), field);
return static_cast<jchar>(v ? intValue(t, v) : 0);
}
jshort JNICALL
@ -846,8 +847,8 @@ GetStaticShortField(Thread* t, jclass c, jfieldID field)
{
ENTER(t, Thread::ActiveState);
return static_cast<jshort>
(intValue(t, arrayBody(t, classStaticTable(t, *c), field)));
object v = arrayBody(t, classStaticTable(t, *c), field);
return static_cast<jshort>(v ? intValue(t, v) : 0);
}
jint JNICALL
@ -855,13 +856,17 @@ GetStaticIntField(Thread* t, jclass c, jfieldID field)
{
ENTER(t, Thread::ActiveState);
return intValue(t, arrayBody(t, classStaticTable(t, *c), field));
object v = arrayBody(t, classStaticTable(t, *c), field);
return v ? intValue(t, v) : 0;
}
jlong JNICALL
GetStaticLongField(Thread* t, jclass c, jfieldID field)
{
return longValue(t, arrayBody(t, classStaticTable(t, *c), field));
ENTER(t, Thread::ActiveState);
object v = arrayBody(t, classStaticTable(t, *c), field);
return static_cast<jlong>(v ? longValue(t, v) : 0);
}
jfloat JNICALL
@ -869,9 +874,10 @@ GetStaticFloatField(Thread* t, jclass c, jfieldID field)
{
ENTER(t, Thread::ActiveState);
jint i = intValue(t, arrayBody(t, classStaticTable(t, *c), field));
jfloat v; memcpy(&v, &i, 4);
return v;
object v = arrayBody(t, classStaticTable(t, *c), field);
jint i = v ? intValue(t, v) : 0;
jfloat f; memcpy(&f, &i, 4);
return f;
}
jdouble JNICALL
@ -879,9 +885,10 @@ GetStaticDoubleField(Thread* t, jclass c, jfieldID field)
{
ENTER(t, Thread::ActiveState);
jlong i = longValue(t, arrayBody(t, classStaticTable(t, *c), field));
jdouble v; memcpy(&v, &i, 8);
return v;
object v = arrayBody(t, classStaticTable(t, *c), field);
jlong i = v ? longValue(t, v) : 0;
jdouble f; memcpy(&f, &i, 4);
return f;
}
void JNICALL

View File

@ -794,7 +794,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
classObjectMask(t, classSuper(t, class_)));
} else {
object mask = makeIntArray
(t, ceiling(classFixedSize(t, class_), BitsPerWord * BytesPerWord), true);
(t, ceiling(classFixedSize(t, class_), 32 * BytesPerWord), true);
intArrayBody(t, mask, 0) = 1;
object superMask = 0;
@ -2334,7 +2334,7 @@ resolveObjectArrayClass(Thread* t, object elementSpec)
object spec;
if (byteArrayBody(t, elementSpec, 0) == '[') {
spec = makeByteArray(t, byteArrayLength(t, elementSpec) + 1, false);
byteArrayBody(t, elementSpec, 0) = '[';
byteArrayBody(t, spec, 0) = '[';
memcpy(&byteArrayBody(t, spec, 1),
&byteArrayBody(t, elementSpec, 0),
byteArrayLength(t, elementSpec));

View File

@ -1592,6 +1592,9 @@ instanceOf(Thread* t, object class_, object o);
object
classInitializer(Thread* t, object class_);
object
frameMethod(Thread* t, int frame);
inline void
pushObject(Thread* t, object o)
{

View File

@ -368,10 +368,13 @@ invokeNative(Thread* t, object method)
sp += 2;
} break;
case POINTER_TYPE:
args[offset++] = reinterpret_cast<uintptr_t>
(t->stack + ((sp++) * 2) + 1);
break;
case POINTER_TYPE: {
object* v = reinterpret_cast<object*>(t->stack + ((sp++) * 2) + 1);
if (*v == 0) {
v = 0;
}
args[offset++] = reinterpret_cast<uintptr_t>(v);
} break;
default: abort(t);
}
@ -506,6 +509,14 @@ codeReadInt32(Thread* t, unsigned& i)
return ((v1 << 24) | (v2 << 16) | (v3 << 8) | v4);
}
inline void
store(Thread* t, unsigned index)
{
memcpy(t->stack + ((frameBase(t, t->frame) + index) * 2),
t->stack + ((-- t->sp) * 2),
BytesPerWord * 2);
}
object
run(Thread* t)
{
@ -659,23 +670,23 @@ run(Thread* t)
} goto loop;
case astore: {
setLocalObject(t, codeBody(t, code, ip++), popObject(t));
store(t, codeBody(t, code, ip++));
} goto loop;
case astore_0: {
setLocalObject(t, 0, popObject(t));
store(t, 0);
} goto loop;
case astore_1: {
setLocalObject(t, 1, popObject(t));
store(t, 1);
} goto loop;
case astore_2: {
setLocalObject(t, 2, popObject(t));
store(t, 2);
} goto loop;
case astore_3: {
setLocalObject(t, 3, popObject(t));
store(t, 3);
} goto loop;
case athrow: {
@ -1164,12 +1175,12 @@ run(Thread* t)
case ShortField:
case FloatField:
case IntField:
pushInt(t, intValue(t, v));
pushInt(t, v ? intValue(t, v) : 0);
break;
case DoubleField:
case LongField:
pushLong(t, longValue(t, v));
pushLong(t, v ? longValue(t, v) : 0);
break;
case ObjectField:

View File

@ -544,6 +544,7 @@ class MySystem: public System {
Library(this, p, n, mapName, next);
return 0;
} else {
// fprintf(stderr, "dlerror: %s\n", dlerror());
return 1;
}
}

25
test/HelloSWT.java Normal file
View File

@ -0,0 +1,25 @@
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Label;
public class HelloSWT {
public static void main (String[] args) {
Display display = new Display();
final Shell shell = new Shell(display);
RowLayout layout = new RowLayout();
layout.justify = true;
layout.pack = true;
shell.setLayout(layout);
shell.setText("Hello, World!");
Label label = new Label(shell, SWT.CENTER);
label.setText("Hello, world!");
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) display.sleep();
}
display.dispose();
}
}