diff --git a/src/constants.h b/src/constants.h index 262cecbe07..c72ec917df 100644 --- a/src/constants.h +++ b/src/constants.h @@ -200,6 +200,20 @@ enum TypeCode { T_LONG = 11 }; +enum Constant { + CONSTANT_Class = 7, + CONSTANT_Fieldref = 9, + CONSTANT_Methodref = 10, + CONSTANT_InterfaceMethodref = 11, + CONSTANT_String = 8, + CONSTANT_Integer = 3, + CONSTANT_Float = 4, + CONSTANT_Long = 5, + CONSTANT_Double = 6, + CONSTANT_NameAndType = 12, + CONSTANT_Utf8 = 1 +}; + const unsigned ACC_PUBLIC = 1 << 0; const unsigned ACC_FINAL = 1 << 4; const unsigned ACC_SUPER = 1 << 5; diff --git a/src/stream.h b/src/stream.h new file mode 100644 index 0000000000..973f21bfc5 --- /dev/null +++ b/src/stream.h @@ -0,0 +1,74 @@ +#ifndef STREAM_H +#define STREAM_H + +#include "common.h" + +class Stream { + public: + class Client { + public: + virtual ~Client() { } + virtual void NO_RETURN handleEOS() = 0; + }; + + Stream(Client* client, const uint8_t* data, unsigned size): + client(client), data(data), size(size), position(0) + { } + + void skip(unsigned size) { + if (size > this->size - position) { + client->handleEOS(); + } else { + position += size; + } + } + + void read(uint8_t* data, unsigned size) { + if (size > this->size - position) { + client->handleEOS(); + } else { + memcpy(data, this->data + position, size); + position += size; + } + } + + uint8_t read1() { + uint8_t v; + read(&v, 1); + return v; + } + + uint16_t read2() { + uint16_t a = read1(); + uint16_t b = read1(); + return (a << 8) | b; + } + + uint32_t read4() { + uint32_t a = read2(); + uint32_t b = read2(); + return (a << 16) | b; + } + + uint64_t read8() { + uint64_t a = read4(); + uint64_t b = read4(); + return (a << 32) | b; + } + + uint32_t readFloat() { +#error todo + } + + uint64_t readDouble() { +#error todo + } + + private: + Client* client; + const uint8_t* data; + unsigned size; + unsigned position; +}; + +#endif//STREAM_H diff --git a/src/vm.cpp b/src/vm.cpp index 587a22bf65..89b92198fb 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -2,6 +2,7 @@ #include "system.h" #include "heap.h" #include "class_finder.h" +#include "stream.h" #define PROTECT(thread, name) \ Thread::Protector MAKE_NAME(protector_) (thread, &name); @@ -42,6 +43,7 @@ class Machine { Thread* exclusive; unsigned activeCount; unsigned liveCount; + unsigned nextClassId; System::Monitor* stateLock; System::Monitor* heapLock; System::Monitor* classLock; @@ -144,6 +146,7 @@ init(Machine* m, System* sys, Heap* heap, ClassFinder* classFinder) m->sys = sys; m->heap = heap; m->classFinder = classFinder; + m->nextClassId = OtherType + 1; if (not sys->success(sys->make(&(m->stateLock))) or not sys->success(sys->make(&(m->heapLock))) or @@ -692,6 +695,186 @@ hashMapInsert(Thread* t, object map, uint32_t hash, object key, object value) set(t, rawArrayBody(t, map)[index], n); } +object +parseClass(Thread* t, const uint8_t* data, unsigned size) +{ + class Client : public Stream::Client { + public: + Client(Thread* t): t(t) { } + + virtual void NO_RETURN handleEOS() { + abort(t); + } + + private: + Thread* t; + } client(t); + + Stream s(&client, data, size); + + uint32_t magic = s.read4(); + assert(t, magic == 0xCAFEBABE); + s.read2(); // minor version + s.read2(); // major version + + unsigned poolCount = s.read2(); + object pool = makeRawArray(t, poolCount); + PROTECT(t, pool); + + for (unsigned i = 0; i < poolCount; ++i) { + switch (s.read1()) { + case CONSTANT_Class: { + set(t, rawArrayBody(t, pool)[i], rawArrayBody(t, pool)[s.read2()]); + } break; + + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: { + object c = rawArrayBody(t, pool)[s.read2()]; + object nameAndType = rawArrayBody(t, pool)[s.read2()]; + object value = makeReference + (t, c, pairFirst(t, nameAndType), pairSecond(t, nameAndType)); + set(t, rawArrayBody(t, pool)[i], value); + } break; + + case CONSTANT_String: { + object bytes = rawArrayBody(t, pool)[s.read2()]; + object value = makeString(t, bytes, 0, byteArrayLength(t, bytes), 0); + set(t, rawArrayBody(t, pool)[i], value); + } break; + + case CONSTANT_Integer: { + object value = makeInt(t, s.read4()); + set(t, rawArrayBody(t, pool)[i], value); + } break; + + case CONSTANT_Float: { + object value = makeFloat(t, s.readFloat()); + set(t, rawArrayBody(t, pool)[i], value); + } break; + + case CONSTANT_Long: { + object value = makeLong(t, s.read8()); + set(t, rawArrayBody(t, pool)[i], value); + } break; + + case CONSTANT_Double: { + object value = makeLong(t, s.readDouble()); + set(t, rawArrayBody(t, pool)[i], value); + } break; + + case CONSTANT_NameAndType: { + object name = rawArrayBody(t, pool)[s.read2()]; + object type = rawArrayBody(t, pool)[s.read2()]; + object value = makePair(t, name, type); + set(t, rawArrayBody(t, pool)[i], value); + } break; + + case CONSTANT_Utf8: { + unsigned length = s.read2(); + object value = makeByteArray(t, length); + s.read(reinterpret_cast(byteArrayBody(t, value)), length); + set(t, rawArrayBody(t, pool)[i], value); + } break; + + default: abort(t); + } + } + + unsigned flags = s.read2(); + unsigned name = s.read2(); + unsigned super = s.read2(); + + unsigned interfaceCount = s.read2(); + object interfaces = makeRawArray(t, interfaceCount * 2); + PROTECT(t, interfaces); + + for (unsigned i = 0; i < interfaceCount * 2; i += 2) { + set(t, rawArrayBody(t, interfaces)[i], rawArrayBody(t, pool)[s.read2()]); + rawArrayBody(t, interfaces)[i + 1] = 0; + } + + object class_ = makeClass(t, + t->vm->nextClassId++, + 0, // fixed size + 0, // array size + 0, // object mask + flags, + rawArrayBody(t, pool)[name], + rawArrayBody(t, pool)[super], + interfaces, + 0, // fields + 0, // methods + 0, // static table + 0); // initializers + PROTECT(t, class_); + + unsigned fieldCount = s.read2(); + object fields = makeRawArray(t, fieldCount * 2); + set(t, classFieldTable(t, class_), fields); + PROTECT(t, fields); + + for (unsigned i = 0; i < fieldCount; ++i) { + unsigned flags = s.read2(); + unsigned name = s.read2(); + unsigned spec = s.read2(); + + unsigned attributeCount = s.read2(); + for (unsigned j = 0; j < attributeCount; ++j) { + s.read2(); + s.skip(s.read4()); + } + + object value = makeField(t, + flags, + 0, // offset + rawArrayBody(t, pool)[name], + rawArrayBody(t, pool)[spec], + class_); + + set(t, rawArrayBody(t, fields)[i], value); + } + + unsigned methodCount = s.read2(); + object methods = makeRawArray(t, methodCount * 2); + set(t, classMethodTable(t, class_), methods); + PROTECT(t, methods); + + for (unsigned i = 0; i < methodCount; ++i) { + unsigned flags = s.read2(); + unsigned name = s.read2(); + unsigned spec = s.read2(); + + object code = 0; + unsigned attributeCount = s.read2(); + for (unsigned j = 0; j < attributeCount; ++j) { + object name = rawArrayBody(t, pool)[s.read2()]; + if (strcmp(reinterpret_cast("Code"), + byteArrayBody(t, name)) == 0) + { + unsigned length = s.read2(); + code = makeByteArray(t, length); + s.read(reinterpret_cast(byteArrayBody(t, code)), length); + } else { + s.skip(s.read4()); + } + } + + object value = makeMethod(t, + flags, + 0, // offset + parameterCount(rawArrayBody(t, pool)[spec]), + rawArrayBody(t, pool)[name], + rawArrayBody(t, pool)[spec], + class_, + code); + + set(t, rawArrayBody(t, methods)[i], value); + } + + return class_; +} + object resolveClass(Thread* t, object spec) { @@ -706,11 +889,30 @@ resolveClass(Thread* t, object spec) (reinterpret_cast(byteArrayBody(t, spec)), &size); if (data) { + // parse class file class_ = parseClass(t, data, size); t->vm->classFinder->free(data); PROTECT(t, class_); + + // resolve superclass + object super = resolveClass(t, classSuper(t, class_)); + if (UNLIKELY(t->exception)) return 0; + + set(t, classSuper(t, class_), super); + +#error todo + // merge interface table with that of superclass and generate + // vtables + + // concatenate field table with those of superclass and populate + // offsets + + // merge method table with that of superclass and populate + // offsets + + // cache class hashMapInsert(t, t->vm->classMap, h, spec, class_); } else { object message = makeString(t, "%s", byteArrayBody(t, spec));