blob: 80a27d70f6b61992a295a54c19a66470948dcf7d [file] [log] [blame]
#include <stdio.h>
#include <string.h>
#include <vector>
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/DataLayout.h"
#include "j3/j3.h"
#include "j3/j3class.h"
#include "j3/j3classloader.h"
#include "j3/j3reader.h"
#include "j3/j3constants.h"
#include "j3/j3method.h"
#include "j3/j3mangler.h"
#include "j3/j3object.h"
#include "j3/j3thread.h"
#include "j3/j3field.h"
#include "j3/j3attribute.h"
#include "j3/j3codegen.h"
using namespace j3;
/*
* ------------ J3Type ------------
*/
J3Type::J3Type(J3ClassLoader* loader, const vmkit::Name* name) {
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&_mutex, &attr);
_loader = loader;
_name = name;
}
const char* J3Type::genId(const char* prefix, const char* suffix) {
size_t plen = prefix ? strlen(prefix) : 0;
size_t slen = suffix ? strlen(suffix) : 0;
size_t len = nativeNameLength();
char* id = (char*)loader()->allocator()->allocate(plen + len + slen + 1);
memcpy(id, prefix, plen);
memcpy(id+plen, nativeName(), len);
memcpy(id+plen+plen, suffix, slen);
return id;
}
void* J3Type::getSymbolAddress() {
return this;
}
const char* J3Type::vtId() {
const char* id = vtSymbol()->id();
if(!id)
vtSymbol()->setId(id = genId("vt_"));
return id;
}
J3VirtualTable* J3Type::vt() {
return vtSymbol()->vt();
}
void J3Type::dump() {
fprintf(stderr, "Type: %s", name()->cStr());
}
J3ObjectHandle* J3Type::javaClass(bool doPush, J3ObjectHandle* protectionDomain) {
if(!_javaClass) {
lock();
if(!_javaClass) {
J3* vm = J3Thread::get()->vm();
J3ObjectHandle* prev = J3Thread::get()->tell();
_javaClass = loader()->globalReferences()->add(J3ObjectHandle::doNewObject(vm->classClass));
J3Thread::get()->restore(prev);
_javaClass->setLong(vm->classClassVMData, (int64_t)(uintptr_t)this);
vm->classClassInit->invokeSpecial(_javaClass);
}
unlock();
}
return doPush ? J3Thread::get()->push(_javaClass) : _javaClass;
}
void J3Type::doNativeName() {
J3::internalError("should not happen");
}
char* J3Type::nativeName() {
if(!_nativeName)
doNativeName();
return _nativeName;
}
uint32_t J3Type::nativeNameLength() {
if(!_nativeNameLength)
doNativeName();
return _nativeNameLength;
}
J3ArrayClass* J3Type::getArray(uint32_t prof, const vmkit::Name* name) {
if(!_array) {
lock();
if(!_array) {
_array = new(loader()->allocator()) J3ArrayClass(loader(), this, name);
}
unlock();
}
return prof > 1 ? _array->getArray(prof-1) : _array;
}
uint64_t J3Type::getSizeInBits() {
return 1 << (logSize()+3);
}
bool J3Type::isAssignableTo(J3Type* parent) {
resolve();
parent->resolve();
return vt()->isAssignableTo(parent->vt());
}
J3Type* J3Type::resolve() {
if(status < RESOLVED)
doResolve(0, 0);
return this;
}
J3Type* J3Type::resolve(J3Field* hiddenFields, uint32_t nbHiddenFields) {
if(status < RESOLVED)
doResolve(hiddenFields, nbHiddenFields);
else
J3::internalError("trying to resolve class %s with hidden fields while it is already loaded", name()->cStr());
return this;
}
J3Type* J3Type::initialise() {
if(status < INITED)
doInitialise();
return this;
}
J3Class* J3Type::asClass() {
if(!isClass())
J3::internalError("should not happen");
return (J3Class*)this;
}
J3Layout* J3Type::asLayout() {
if(!isLayout())
J3::internalError("should not happen");
return (J3Layout*)this;
}
J3StaticLayout* J3Type::asStaticLayout() {
if(!isStaticLayout())
J3::internalError("should not happen");
return (J3StaticLayout*)this;
}
J3Primitive* J3Type::asPrimitive() {
if(!isPrimitive())
J3::internalError("should not happen");
return (J3Primitive*)this;
}
J3ArrayClass* J3Type::asArrayClass() {
if(!isArrayClass())
J3::internalError("should not happen");
return (J3ArrayClass*)this;
}
J3ObjectType* J3Type::asObjectType() {
if(!isObjectType())
J3::internalError("should not happen");
return (J3ObjectType*)this;
}
/*
* ------------ J3ObjectType ------------
*/
J3ObjectType::J3ObjectType(J3ClassLoader* loader, const vmkit::Name* name) : J3Type(loader, name) {
}
llvm::Type* J3ObjectType::llvmType() {
return J3Thread::get()->vm()->typeJ3ObjectPtr;
}
J3Method* J3ObjectType::findMethod(uint32_t access, const vmkit::Name* name, J3Signature* signature, bool error) {
J3::internalError("should not happen - findMethod: %s::%s\n", J3ObjectType::name()->cStr(), name->cStr());
}
J3ObjectType* J3ObjectType::nativeClass(J3ObjectHandle* handle) {
return (J3ObjectType*)(uintptr_t)handle->getLong(J3Thread::get()->vm()->classClassVMData);
}
J3ObjectHandle* J3ObjectType::clone(J3ObjectHandle* obj) {
J3::internalError("should not happen");
}
uint16_t J3ObjectType::access() {
J3::internalError("should not happen");
}
uint16_t J3ObjectType::modifiers() {
J3::internalError("should not happen");
}
J3Class* J3ObjectType::super() {
J3::internalError("should not happen");
}
void J3ObjectType::prepareInterfaceTable() {
//fprintf(stderr, "prepare interface table of %s\n", name()->cStr());
uint32_t total = 0;
J3InterfaceSlotDescriptor* slots = _interfaceSlotDescriptors;
for(uint32_t i=0; i<vt()->checker.nbSecondaryTypes; i++) {
J3Type* type = vt()->checker.secondaryTypes[i]->type();
if(type->isClass()) {
J3Class* ifce = vt()->checker.secondaryTypes[i]->type()->asClass();
if(J3Cst::isInterface(ifce->access())) {
//fprintf(stderr, " processing interface: %s\n", ifce->name()->cStr());
for(uint32_t j=0; j<ifce->nbMethods(); j++) {
J3Method* base = ifce->methods()[j];
//fprintf(stderr, " processing %s method %s %s\n",
//J3Cst::isAbstract(base->access()) ? "abstract" : "concrete",
//base->signature()->cStr(), base->name()->cStr());
J3Method* method = findMethod(0, base->name(), base->signature(), J3Cst::isAbstract(base->access()));
if(!method)
method = base;
uint32_t index = base->interfaceIndex() % J3VirtualTable::nbInterfaceMethodTable;
uint32_t found = 0;
for(uint32_t i=0; !found && i<slots[index].nbMethods; i++)
if(slots[index].methods[i] == method)
found=1;
if(!found) {
total++;
J3Method** tmp = (J3Method**)alloca(sizeof(J3Method*)*(slots[index].nbMethods+1));
memcpy(tmp, slots[index].methods, sizeof(J3Method*)*slots[index].nbMethods);
tmp[slots[index].nbMethods] = method;
slots[index].methods = tmp;
slots[index].nbMethods++;
}
}
}
}
}
J3Method** methods = (J3Method**)loader()->allocator()->allocate(total*sizeof(J3Method*));
uint32_t cur = 0;
for(uint32_t i=0; i<J3VirtualTable::nbInterfaceMethodTable; i++) {
memcpy(methods + cur, slots[i].methods, slots[i].nbMethods*sizeof(J3Method*));
slots[i].methods = methods + cur;
cur += slots[i].nbMethods;
}
//dumpInterfaceSlotDescriptors();
}
void J3ObjectType::dumpInterfaceSlotDescriptors() {
J3InterfaceSlotDescriptor* slots = _interfaceSlotDescriptors;
fprintf(stderr, "slot descriptors of %s\n", name()->cStr());
for(uint32_t i=0; i<J3VirtualTable::nbInterfaceMethodTable; i++) {
if(slots[i].nbMethods) {
fprintf(stderr, " slot[%d]:\n", i);
for(uint32_t j=0; j<slots[i].nbMethods; j++)
fprintf(stderr, " %s::%s %s\n",
slots[i].methods[j]->cl()->name()->cStr(),
slots[i].methods[j]->name()->cStr(),
slots[i].methods[j]->signature()->name()->cStr());
}
}
}
/*
* ------------ J3Layout ------------
*/
J3StaticLayout::J3StaticLayout(J3ClassLoader* loader, J3Class* cl, const vmkit::Name* name) : J3Layout(loader, name) {
_cl = cl;
}
J3ObjectHandle* J3StaticLayout::extractAttribute(J3Attribute* attr) {
return cl()->extractAttribute(attr);
}
J3Layout::J3Layout(J3ClassLoader* loader, const vmkit::Name* name) : J3ObjectType(loader, name) {
}
uintptr_t J3Layout::structSize() {
return _structSize;
}
J3Method* J3Layout::localFindMethod(const vmkit::Name* name, J3Signature* signature) {
//fprintf(stderr, " --- lookup %s%s in %s\n", name->cStr(), signature->name()->cStr(), J3Layout::name()->cStr());
for(size_t i=0; i<nbMethods(); i++) {
J3Method* cur = methods()[i];
//fprintf(stderr, "%s::%s%s\n", cur->cl()->name()->cStr(), cur->name()->cStr(), cur->signature()->name()->cStr());
if(cur->name() == name && cur->signature()->name() == signature->name()) {
return cur;
}
}
return 0;
}
J3Field* J3Layout::localFindField(const vmkit::Name* name, const J3Type* type) {
for(size_t i=0; i<nbFields(); i++) {
J3Field* cur = fields() + i;
//printf(" compare with %s - %s\n", cur->name()->cStr(), cur->type()->name()->cStr());
if(cur->name() == name && cur->type() == type) {
return cur;
}
}
return 0;
}
/*
* ------------ J3Class ------------
*/
J3Class::J3Class(J3ClassLoader* loader, const vmkit::Name* name, J3ClassBytes* bytes, J3ObjectHandle* protectionDomain, const char* source) :
J3Layout(loader, name),
_staticLayout(loader, this, name) {
_protectionDomain = protectionDomain ? loader->globalReferences()->add(protectionDomain) : 0;
_source = source;
_bytes = bytes;
status = LOADED;
/* allocating the J3ObjectHande looks a little strange, but it will become important to reload AOT compiled class loaders */
_staticObjectSymbol = new(loader->staticObjects()) J3StaticObjectSymbol(loader->staticObjectHandles()->push());
}
void J3Class::compileAll() {
resolve();
for(uint32_t i=0; i<nbMethods(); i++) {
if(!J3Cst::isAbstract(methods()[i]->access()))
methods()[i]->ensureCompiled(J3CodeGen::WithMethod);
}
for(uint32_t i=0; i<staticLayout()->nbMethods(); i++) {
if(!J3Cst::isAbstract(staticLayout()->methods()[i]->access()))
staticLayout()->methods()[i]->ensureCompiled(J3CodeGen::WithMethod);
}
}
void J3Class::aotSnapshot(llvm::Linker* linker) {
for(uint32_t i=0; i<nbMethods(); i++) {
methods()[i]->aotSnapshot(linker);
}
for(uint32_t i=0; i<staticLayout()->nbMethods(); i++) {
staticLayout()->methods()[i]->aotSnapshot(linker);
}
}
uint16_t J3Class::modifiers() {
return access();
#if 0
if (isEnum(res) && cl->getSuper() != vm->upcalls->EnumClass) {
// javac may put that flag to inner classes of enum classes.
res &= ~ACC_ENUM;
}
#endif
}
J3ObjectHandle* J3Class::clone(J3ObjectHandle* obj) {
//fprintf(stderr, " cloning %p with %lu bytes\n", obj->obj(), structSize());
J3ObjectHandle* res = J3ObjectHandle::doNewObject(this);
obj->rawObjectCopyTo(0, res, 0, structSize() - sizeof(J3Object));
return res;
}
J3ObjectHandle* J3Class::extractAttribute(J3Attribute* attr) {
if(attr)
J3::internalError("extract attribute");
else
return J3ObjectHandle::doNewArray(J3Thread::get()->vm()->typeByte->getArray(), 0);
}
J3Method* J3Class::findInterfaceMethodRecursive(const vmkit::Name* name, J3Signature* signature) {
J3Class* cur = this;
while(1) {
J3Method* res = cur->localFindMethod(name, signature);
if(res)
return res;
switch(cur->nbInterfaces()) {
case 1: cur = cur->interfaces()[0]; break;
default:
for(uint32_t i=0; i<cur->nbInterfaces(); i++) {
res = cur->interfaces()[i]->findInterfaceMethodRecursive(name, signature);
if(res)
return res;
}
case 0:
return 0;
}
}
}
J3Method* J3Class::findInterfaceMethod(const vmkit::Name* name, J3Signature* signature, bool error) {
resolve();
J3Method* res = findInterfaceMethodRecursive(name, signature);
if(res)
return res;
if(error)
J3::noSuchMethodError("no such interface method", this, name, signature);
else
return 0;
}
J3Method* J3Class::findMethod(uint32_t access, const vmkit::Name* name, J3Signature* signature, bool error) {
resolve();
J3Class* cur = this;
while(1) {
J3Layout* layout = J3Cst::isStatic(access) ? (J3Layout*)cur->staticLayout() : cur;
J3Method* res = layout->localFindMethod(name, signature);
if(res)
return res;
if(cur == cur->super()) {
if(error)
J3::noSuchMethodError("no such method", this, name, signature);
else
return 0;
}
cur = cur->super();
}
}
J3Field* J3Class::findInterfaceFieldRecursive(const vmkit::Name* name, J3Type* type) {
J3Class* cur = this;
while(1) {
J3Field* res = cur->staticLayout()->localFindField(name, type);
if(res)
return res;
switch(cur->nbInterfaces()) {
case 1: cur = cur->interfaces()[0]; break;
default:
for(uint32_t i=0; i<cur->nbInterfaces(); i++) {
res = cur->interfaces()[i]->findInterfaceFieldRecursive(name, type);
if(res)
return res;
}
case 0:
return 0;
}
}
}
J3Field* J3Class::findField(uint32_t access, const vmkit::Name* name, J3Type* type, bool error) {
resolve();
J3Class* cur = this;
while(1) {
J3Layout* layout = J3Cst::isStatic(access) ? (J3Layout*)cur->staticLayout() : cur;
J3Field* res = layout->localFindField(name, type);
//fprintf(stderr, "[%d] Lookup: %s %s in %s\n", access, type->name()->cStr(), name->cStr(), cur->name()->cStr());
if(res)
return res;
if(cur == cur->super()) {
if(J3Cst::isStatic(access)) {
J3Class* prev = 0;
for(cur=this; cur!=prev; cur=cur->super()) {
for(uint32_t i=0; i<cur->nbInterfaces(); i++) {
res = cur->interfaces()[i]->findInterfaceFieldRecursive(name, type);
if(res)
return res;
}
prev = cur;
}
}
if(error)
J3::noSuchFieldError("no such field", this, name, type);
else
return 0;
}
cur = cur->super();
}
}
void J3Class::registerNative(const vmkit::Name* name, const vmkit::Name* signatureName, void* fnPtr) {
resolve();
J3Signature* signature = loader()->getSignature(this, signatureName);
J3Method* res = staticLayout()->localFindMethod(name, signature);
if(!res)
res = localFindMethod(name, signature);
if(!res || !J3Cst::isNative(res->access()))
J3::noSuchMethodError("unable to find native method", this, name, signature);
res->registerNative(fnPtr);
}
const char* J3Class::staticObjectId() {
const char* id = staticObjectSymbol()->id();
if(!id)
staticObjectSymbol()->setId(id = genId("static_"));
return id;
}
void J3Class::doInitialise() {
resolve();
lock();
if(status < INITED) {
J3* vm = J3Thread::get()->vm();
if(vm->options()->debugIniting)
fprintf(stderr, "Initing: %s\n", name()->cStr());
status = INITED;
super()->initialise();
for(size_t i=0; i<nbInterfaces(); i++)
interfaces()[i]->initialise();
J3ObjectHandle* prev = J3Thread::get()->tell();
J3ObjectHandle* stacked = J3ObjectHandle::allocate(staticLayout()->vt(), staticLayout()->structSize());
staticObjectSymbol()->setHandle(stacked);
J3Thread::get()->restore(prev);
for(size_t i=0; i<staticLayout()->nbFields(); i++) {
J3Field* cur = staticLayout()->fields() + i;
J3Attribute* attr = cur->attributes()->lookup(vm->constantValueAttribute);
if(attr) {
J3Reader reader(bytes());
reader.seek(attr->offset(), reader.SeekSet);
uint32_t length = reader.readU4();
if(length != 2)
J3::classFormatError(this, "bad length for ConstantAttribute");
uint32_t idx = reader.readU2();
J3ObjectHandle* staticObject = staticObjectSymbol()->handle();
switch(getCtpType(idx)) {
case J3Cst::CONSTANT_Long: staticObject->setLong(cur, longAt(idx)); break;
case J3Cst::CONSTANT_Float: staticObject->setFloat(cur, floatAt(idx)); break;
case J3Cst::CONSTANT_Double: staticObject->setDouble(cur, doubleAt(idx)); break;
case J3Cst::CONSTANT_Integer: staticObject->setInteger(cur, integerAt(idx)); break;
case J3Cst::CONSTANT_String: staticObject->setObject(cur, stringAt(idx)->handle()); break;
default:
J3::classFormatError(this, "invalid ctp entry ConstantAttribute with type %d", getCtpType(idx));
}
}
}
J3Method* clinit = staticLayout()->localFindMethod(vm->clinitName, vm->clinitSign);
if(clinit)
clinit->invokeStatic();
}
unlock();
}
void J3Class::doResolve(J3Field* hiddenFields, size_t nbHiddenFields) {
lock();
if(status < RESOLVED) {
if(J3Thread::get()->vm()->options()->debugResolve)
fprintf(stderr, "Resolving: %s\n", name()->cStr());
status = RESOLVED;
readClassBytes(hiddenFields, nbHiddenFields);
staticLayout()->vtSymbol()->setVt(J3VirtualTable::create(staticLayout()));
vtSymbol()->setVt(J3VirtualTable::create(this));
if(!J3Cst::isInterface(access()) && !J3Cst::isAbstract(access()))
prepareInterfaceTable();
}
unlock();
}
void J3Class::readClassBytes(J3Field* hiddenFields, uint32_t nbHiddenFields) {
J3Reader reader(_bytes);
uint32_t magic = reader.readU4();
if(magic != J3Cst::MAGIC)
J3::classFormatError(this, "bad magic");
/* uint16_t minor = */reader.readU2();
/* uint16_t major = */reader.readU2();
nbCtp = reader.readU2();
if(nbCtp < 1)
J3::classFormatError(this, "zero-sized constant pool");
ctpTypes = (uint8_t*)loader()->allocator()->allocate(nbCtp * sizeof(uint8_t));
ctpValues = (uint32_t*)loader()->allocator()->allocate(nbCtp * sizeof(uint32_t));
ctpResolved = (void**)loader()->allocator()->allocate(nbCtp * sizeof(void*));
ctpTypes[0] = 0;
for(uint32_t i=1; i<nbCtp; i++) {
switch(ctpTypes[i] = reader.readU1()) {
case J3Cst::CONSTANT_Utf8:
ctpValues[i] = reader.tell();
reader.seek(reader.readU2(), reader.SeekCur);
break;
case J3Cst::CONSTANT_MethodType:
case J3Cst::CONSTANT_String:
case J3Cst::CONSTANT_Class:
ctpValues[i] = reader.readU2();
break;
case J3Cst::CONSTANT_InvokeDynamic:
case J3Cst::CONSTANT_Float:
case J3Cst::CONSTANT_Integer:
case J3Cst::CONSTANT_Fieldref:
case J3Cst::CONSTANT_Methodref:
case J3Cst::CONSTANT_InterfaceMethodref:
case J3Cst::CONSTANT_NameAndType:
ctpValues[i] = reader.readU4();
break;
case J3Cst::CONSTANT_Long:
case J3Cst::CONSTANT_Double:
ctpValues[i] = reader.readU4();
ctpValues[i+1] = reader.readU4();
i++;
break;
case J3Cst::CONSTANT_MethodHandle:
ctpValues[i] = reader.readU1() << 16;
ctpValues[i] |= reader.readU2();
break;
default:
J3::classFormatError(this, "wrong constant pool entry type: %d", ctpTypes[i]);
}
}
_access = reader.readU2();
J3ObjectType* self = classAt(reader.readU2());
if(self != this)
J3::classFormatError(this, "wrong class file (describes class %s)", self->name()->cStr());
uint16_t superIdx = reader.readU2();
_super = superIdx ? classAt(superIdx)->asClass() : this;
_nbInterfaces = reader.readU2();
_interfaces = (J3Class**)loader()->allocator()->allocate(nbInterfaces()*sizeof(J3Class*));
for(size_t i=0; i<nbInterfaces(); i++) {
_interfaces[i] = classAt(reader.readU2())->asClass();
}
size_t n = nbHiddenFields + reader.readU2(), nbStaticFields = 0, nbVirtualFields = 0;
_fields = (J3Field*)alloca(sizeof(J3Field)*n);
J3Field* pFields0[n]; size_t i0 = 0; /* sort fields by reverse size */
J3Field* pFields1[n]; size_t i1 = 0;
J3Field* pFields2[n]; size_t i2 = 0;
J3Field* pFields3[n]; size_t i3 = 0;
memset(fields(), 0, sizeof(J3Field)*n);
for(size_t i=0; i<n; i++) {
J3Field* f = fields() + i;
if(i < nbHiddenFields) {
f->_access = hiddenFields[i].access();
f->_name = hiddenFields[i].name();
f->_type = hiddenFields[i].type();
f->_attributes = new (loader()->allocator(), 0) J3Attributes(0);
} else {
f->_access = reader.readU2();
f->_name = nameAt(reader.readU2());
f->_type = loader()->getTypeFromDescriptor(this, nameAt(reader.readU2()));
f->_attributes = readAttributes(&reader);
}
if(J3Cst::isStatic(f->access())) {
f->_layout = staticLayout();
nbStaticFields++;
} else {
f->_layout = this;
nbVirtualFields++;
}
switch(f->_type->logSize()) {
case 0: pFields0[i0++] = f; break;
case 1: pFields1[i1++] = f; break;
case 2: pFields2[i2++] = f; break;
case 3: pFields3[i3++] = f; break;
default: J3::internalError("should not happen");
}
}
staticLayout()->_fields = new(loader()->allocator()) J3Field[nbStaticFields];
_fields = new(loader()->allocator()) J3Field[nbVirtualFields];
if(super() == this)
_structSize = sizeof(J3Object);
else {
super()->resolve();
_structSize = super()->structSize();
}
_staticLayout._structSize = sizeof(J3Object);
_structSize = ((_structSize - 1) & -sizeof(uintptr_t)) + sizeof(uintptr_t);
fillFields(pFields3, i3);
fillFields(pFields2, i2);
fillFields(pFields1, i1);
fillFields(pFields0, i0);
size_t nbVirtualMethods = 0, nbStaticMethods = 0;
n = reader.readU2();
J3Method** methodsTmp = (J3Method**)alloca(sizeof(J3Method*)*n);
for(size_t i=0; i<n; i++) {
uint16_t access = reader.readU2();
const vmkit::Name* name = nameAt(reader.readU2());
J3Signature* signature = loader()->getSignature(this, nameAt(reader.readU2()));
J3Method* method = new(loader()->allocator()) J3Method(access, this, name, signature);
J3Attributes* attributes = readAttributes(&reader);
method->postInitialise(access, attributes);
methodsTmp[i] = method;
if(J3Cst::isStatic(access))
nbStaticMethods++;
else
nbVirtualMethods++;
}
staticLayout()->_methods = (J3Method**)loader()->allocator()->allocate(sizeof(J3Method*)*nbStaticMethods);
_methods = (J3Method**)loader()->allocator()->allocate(sizeof(J3Method*)*nbVirtualMethods);
for(int i=0; i<n; i++) {
J3Layout* layout;
if(J3Cst::isStatic(methodsTmp[i]->access()))
layout = staticLayout();
else {
layout = this;
if(methodsTmp[i]->name() == J3Thread::get()->vm()->initName) {
_nbConstructors++;
if(J3Cst::isPublic(methodsTmp[i]->access()))
_nbPublicConstructors++;
}
}
methodsTmp[i]->_slot = layout->_nbMethods;
layout->_methods[layout->_nbMethods++] = methodsTmp[i];
if(J3Cst::isPublic(methodsTmp[i]->access()))
layout->_nbPublicMethods++;
}
_attributes = readAttributes(&reader);
}
void J3Class::fillFields(J3Field** fields, size_t n) {
for(size_t i=0; i<n; i++) {
J3Field* cur = fields[i];
J3Layout* layout = J3Cst::isStatic(fields[i]->access()) ? (J3Layout*)staticLayout() : this;
//if(name() == J3Thread::get()->vm()->names()->get("java/lang/ClassLoader"))
//fprintf(stderr, " field %s: %s\n", J3Cst::isStatic(fields[i]->access()) ? "static" : "virtual", fields[i]->name()->cStr());
cur->_offset = layout->structSize();
cur->_slot = layout->_nbFields;
layout->_structSize += 1 << fields[i]->type()->logSize();
layout->fields()[layout->_nbFields++] = *fields[i];
if(J3Cst::isPublic(fields[i]->access()))
layout->_nbPublicFields++;
}
}
J3Attributes* J3Class::readAttributes(J3Reader* reader) {
size_t nbAttributes = reader->readU2();
J3Attributes* res = new (loader()->allocator(), nbAttributes) J3Attributes(nbAttributes);
for(size_t i=0; i<nbAttributes; i++) {
res->attribute(i)->_id = nameAt(reader->readU2());
res->attribute(i)->_offset = reader->tell();
reader->seek(reader->readU4(), reader->SeekCur);
}
return res;
}
uint8_t J3Class::getCtpType(uint16_t idx) {
check(idx);
return ctpTypes[idx];
}
void* J3Class::getCtpResolved(uint16_t idx) {
check(idx);
return ctpResolved[idx];
}
J3StringSymbol* J3Class::stringAt(uint16_t idx) {
check(idx, J3Cst::CONSTANT_String);
J3StringSymbol* res = (J3StringSymbol*)ctpResolved[idx];
if(!res) {
ctpResolved[idx] = res = loader()->newStringSymbol(J3Thread::get()->vm()->nameToString(nameAt(ctpValues[idx]), 0));
loader()->addSymbol(res->id(), res);
}
return res;
}
float J3Class::floatAt(uint16_t idx) {
check(idx, J3Cst::CONSTANT_Float);
J3Value v;
v.valInteger = ctpValues[idx];
return v.valFloat;
}
double J3Class::doubleAt(uint16_t idx) {
check(idx, J3Cst::CONSTANT_Double);
J3Value v;
v.valLong = ((uint64_t)ctpValues[idx] << 32) + (uint64_t)ctpValues[idx+1];
return v.valDouble;
}
uint32_t J3Class::integerAt(uint16_t idx) {
check(idx, J3Cst::CONSTANT_Integer);
return ctpValues[idx];
}
uint64_t J3Class::longAt(uint16_t idx) {
check(idx, J3Cst::CONSTANT_Long);
return ((uint64_t)ctpValues[idx] << 32) + (uint64_t)ctpValues[idx+1];
}
J3Method* J3Class::interfaceOrMethodAt(uint16_t idx, uint16_t access, bool isInterfaceMethod) {
J3Method* res = (J3Method*)ctpResolved[idx];
if(res) {
if((res->access() & J3Cst::ACC_STATIC) != (access & J3Cst::ACC_STATIC))
J3::classFormatError(this, "inconsistent use of virtual and static methods");
return res;
}
uint16_t ntIdx = ctpValues[idx] & 0xffff;
J3ObjectType* cl = classAt(ctpValues[idx] >> 16);
check(ntIdx, J3Cst::CONSTANT_NameAndType);
const vmkit::Name* name = nameAt(ctpValues[ntIdx] >> 16);
J3Signature* signature = (J3Signature*)ctpResolved[ntIdx];
if(!signature)
ctpResolved[idx] = signature = loader()->getSignature(this, nameAt(ctpValues[ntIdx] & 0xffff));
res = (isInterfaceMethod && J3Cst::isInterface(cl->access())) ?
cl->asClass()->findInterfaceMethod(name, signature) :
cl->findMethod(access, name, signature);
ctpResolved[idx] = res;
return res;
}
J3Method* J3Class::methodAt(uint16_t idx, uint16_t access) {
check(idx, J3Cst::CONSTANT_Methodref);
return interfaceOrMethodAt(idx, access, 0);
}
J3Method* J3Class::interfaceMethodAt(uint16_t idx, uint16_t access) {
check(idx, J3Cst::CONSTANT_InterfaceMethodref);
return interfaceOrMethodAt(idx, access, 1);
}
J3Field* J3Class::fieldAt(uint16_t idx, uint16_t access) {
check(idx, J3Cst::CONSTANT_Fieldref);
J3Field* res = (J3Field*)ctpResolved[idx];
if(res) {
if((res->access() & J3Cst::ACC_STATIC) != (access & J3Cst::ACC_STATIC))
J3::classFormatError(this, "inconstitent use of virtual and static field");
return res;
}
uint16_t ntIdx = ctpValues[idx] & 0xffff;
J3Class* cl = classAt(ctpValues[idx] >> 16)->asClass();
check(ntIdx, J3Cst::CONSTANT_NameAndType);
const vmkit::Name* name = nameAt(ctpValues[ntIdx] >> 16);
J3Type* type = (J3Type*)ctpResolved[ntIdx];
if(!type)
ctpResolved[ntIdx] = type = loader()->getTypeFromDescriptor(this, nameAt(ctpValues[ntIdx] & 0xffff));
res = cl->findField(access, name, type);
return res;
}
J3ObjectType* J3Class::classAt(uint16_t idx) {
check(idx, J3Cst::CONSTANT_Class);
J3ObjectType* res = (J3ObjectType*)ctpResolved[idx];
if(res)
return res;
const char* buf;
size_t length;
utfAt(ctpValues[idx], &buf, &length);
res = loader()->getTypeFromQualified(this, buf, length);
ctpResolved[idx] = res;
return res;
}
void J3Class::utfAt(uint16_t idx, const char** buf, size_t* length) {
check(idx, J3Cst::CONSTANT_Utf8);
J3Reader reader(_bytes);
reader.seek(ctpValues[idx], reader.SeekSet);
*length = reader.readU2();
*buf = (const char*)reader.pointer();
}
const vmkit::Name* J3Class::nameAt(uint16_t idx) {
check(idx, J3Cst::CONSTANT_Utf8);
const vmkit::Name* res = (const vmkit::Name*)ctpResolved[idx];
if(res)
return res;
const char* buf;
size_t length;
utfAt(idx, &buf, &length);
res = J3Thread::get()->vm()->names()->get(buf, 0, length);//(const char*)reader.pointer(), 0, len);
ctpResolved[idx] = (void*)res;
return res;
}
void J3Class::check(uint16_t idx, uint32_t id) {
if(idx > nbCtp || (id != -1 && ctpTypes[idx] != id))
J3::classFormatError(this, "wrong constant pool type %d at index %d for %d", id, idx, nbCtp);
}
void J3Class::doNativeName() {
J3Mangler mangler(this);
mangler.mangle(name());
_nativeNameLength = mangler.length() + 3;
_nativeName = (char*)loader()->allocator()->allocate(_nativeNameLength + 1);
_nativeName[0] = 'L';
memcpy(_nativeName + 1, mangler.cStr(), mangler.length());
_nativeName[_nativeNameLength-2] = '_';
_nativeName[_nativeNameLength-1] = '2';
_nativeName[_nativeNameLength] = 0;
}
/*
* ------------ J3ArrayClass ------------
*/
J3ArrayClass::J3ArrayClass(J3ClassLoader* loader, J3Type* component, const vmkit::Name* name) : J3ObjectType(loader, name) {
_component = component;
if(!name) {
const vmkit::Name* compName = component->name();
uint32_t len = compName->length();
char buf[len + 16];
uint32_t pos = 0;
//printf(" build array of %s\n", component->name()->cStr());
buf[pos++] = J3Cst::ID_Array;
if(component->isClass())
buf[pos++] = J3Cst::ID_Classname;
memcpy(buf+pos, compName->cStr(), len * sizeof(char));
pos += len;
if(component->isClass())
buf[pos++] = J3Cst::ID_End;
buf[pos] = 0;
_name = J3Thread::get()->vm()->names()->get(buf);
}
}
J3ObjectHandle* J3ArrayClass::clone(J3ObjectHandle* obj) {
size_t n = obj->arrayLength();
J3ObjectHandle* res = J3ObjectHandle::doNewArray(this, n);
obj->rawArrayCopyTo(0, res, 0, n<<component()->logSize());
return res;
}
uint16_t J3ArrayClass::access() {
return super()->access();
}
uint16_t J3ArrayClass::modifiers() {
return super()->modifiers();
}
J3Class* J3ArrayClass::super() {
return J3Thread::get()->vm()->objectClass;
}
J3Method* J3ArrayClass::findMethod(uint32_t access, const vmkit::Name* name, J3Signature* signature, bool error) {
return super()->findMethod(access, name, signature, error);
}
void J3ArrayClass::doResolve(J3Field* hiddenFields, size_t nbHiddenFields) {
lock();
if(status < RESOLVED) {
status = RESOLVED;
vtSymbol()->setVt(J3VirtualTable::create(this));
prepareInterfaceTable();
}
unlock();
}
void J3ArrayClass::doInitialise() {
resolve();
status = INITED;
}
void J3ArrayClass::doNativeName() {
uint32_t len = component()->nativeNameLength();
_nativeNameLength = len + 2;
_nativeName = (char*)loader()->allocator()->allocate(_nativeNameLength + 1);
_nativeName[0] = '_';
_nativeName[1] = '3';
memcpy(_nativeName+2, component()->nativeName(), len);
_nativeName[_nativeNameLength] = 0;
}
J3ObjectHandle* J3ArrayClass::multianewArray(uint32_t dim, uint32_t* args) {
J3ObjectHandle* res = J3ObjectHandle::doNewArray(this, args[0]);
if(dim > 1)
for(uint32_t i=0; i<args[0]; i++)
res->setObjectAt(i, component()->asArrayClass()->multianewArray(dim-1, args+1));
return res;
}
/*
* ------------ J3Primitive ------------
*/
J3Primitive::J3Primitive(J3ClassLoader* loader, char id, llvm::Type* type, uint32_t logSize) :
J3Type(loader, J3Thread::get()->vm()->names()->get(id)) {
_llvmType = type;
_nativeName = (char*)loader->allocator()->allocate(2);
_nativeName[0] = id;
_nativeName[1] = 0;
_nativeNameLength = 1;
vtSymbol()->setVt(J3VirtualTable::create(this));
_logSize = logSize;
}
void J3Primitive::defineJavaClass(const char* className) {
J3* vm = J3Thread::get()->vm();
_javaClass = vm->initialClassLoader->loadClass(vm->names()->get(className))->javaClass(0);
}