2014-04-21 02:14:48 +00:00
|
|
|
/* Copyright (c) 2008-2014, Avian Contributors
|
2010-09-10 21:05:29 +00:00
|
|
|
|
|
|
|
Permission to use, copy, modify, and/or distribute this software
|
|
|
|
for any purpose with or without fee is hereby granted, provided
|
|
|
|
that the above copyright notice and this permission notice appear
|
|
|
|
in all copies.
|
|
|
|
|
|
|
|
There is NO WARRANTY for this software. See license.txt for
|
|
|
|
details. */
|
|
|
|
|
|
|
|
#ifndef CLASSPATH_COMMON_H
|
|
|
|
#define CLASSPATH_COMMON_H
|
|
|
|
|
2013-02-21 23:18:20 +00:00
|
|
|
#include <avian/util/string.h>
|
2013-02-20 05:56:05 +00:00
|
|
|
#include <avian/util/runtime-array.h>
|
2010-09-20 23:31:23 +00:00
|
|
|
|
2013-02-21 23:18:20 +00:00
|
|
|
using namespace avian::util;
|
2013-02-11 00:51:59 +00:00
|
|
|
|
2010-09-10 21:05:29 +00:00
|
|
|
namespace vm {
|
|
|
|
|
2010-09-20 23:31:23 +00:00
|
|
|
object
|
2010-09-10 21:05:29 +00:00
|
|
|
getTrace(Thread* t, unsigned skipCount)
|
|
|
|
{
|
|
|
|
class Visitor: public Processor::StackVisitor {
|
|
|
|
public:
|
|
|
|
Visitor(Thread* t, int skipCount):
|
|
|
|
t(t), trace(0), skipCount(skipCount)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual bool visit(Processor::StackWalker* walker) {
|
|
|
|
if (skipCount == 0) {
|
2014-05-29 04:17:25 +00:00
|
|
|
GcMethod* method = walker->method();
|
2010-09-10 21:05:29 +00:00
|
|
|
if (isAssignableFrom
|
2014-06-21 04:16:33 +00:00
|
|
|
(t, type(t, GcThrowable::Type), method->class_())
|
2010-09-10 21:05:29 +00:00
|
|
|
and vm::strcmp(reinterpret_cast<const int8_t*>("<init>"),
|
2014-06-21 04:16:33 +00:00
|
|
|
method->name()->body().begin())
|
2010-09-10 21:05:29 +00:00
|
|
|
== 0)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
} else {
|
2014-05-29 04:17:25 +00:00
|
|
|
trace = reinterpret_cast<object>(makeTrace(t, walker));
|
2010-09-10 21:05:29 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
-- skipCount;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Thread* t;
|
|
|
|
object trace;
|
|
|
|
unsigned skipCount;
|
|
|
|
} v(t, skipCount);
|
|
|
|
|
|
|
|
t->m->processor->walkStack(t, &v);
|
|
|
|
|
2014-07-11 14:38:56 +00:00
|
|
|
if (v.trace == 0) v.trace = reinterpret_cast<object>(makeObjectArray(t, 0));
|
2010-09-10 21:05:29 +00:00
|
|
|
|
|
|
|
return v.trace;
|
|
|
|
}
|
|
|
|
|
2010-09-20 23:31:23 +00:00
|
|
|
bool
|
2014-07-11 14:38:56 +00:00
|
|
|
compatibleArrayTypes(Thread* t, object ao, object bo)
|
2010-09-10 21:05:29 +00:00
|
|
|
{
|
2014-07-11 14:38:56 +00:00
|
|
|
GcClass* a = cast<GcClass>(t, ao);
|
|
|
|
GcClass* b = cast<GcClass>(t, bo);
|
|
|
|
return a->arrayElementSize()
|
|
|
|
and b->arrayElementSize()
|
2010-09-10 21:05:29 +00:00
|
|
|
and (a == b
|
2014-07-11 14:38:56 +00:00
|
|
|
or (not ((a->vmFlags() & PrimitiveFlag)
|
|
|
|
or (b->vmFlags() & PrimitiveFlag))));
|
2010-09-10 21:05:29 +00:00
|
|
|
}
|
|
|
|
|
2010-09-20 23:31:23 +00:00
|
|
|
void
|
2010-09-10 21:05:29 +00:00
|
|
|
arrayCopy(Thread* t, object src, int32_t srcOffset, object dst,
|
|
|
|
int32_t dstOffset, int32_t length)
|
|
|
|
{
|
|
|
|
if (LIKELY(src and dst)) {
|
|
|
|
if (LIKELY(compatibleArrayTypes
|
2014-05-29 04:17:25 +00:00
|
|
|
(t, reinterpret_cast<object>(objectClass(t, src)), reinterpret_cast<object>(objectClass(t, dst)))))
|
2010-09-10 21:05:29 +00:00
|
|
|
{
|
2014-05-29 04:17:25 +00:00
|
|
|
unsigned elementSize = objectClass(t, src)->arrayElementSize();
|
2010-09-10 21:05:29 +00:00
|
|
|
|
|
|
|
if (LIKELY(elementSize)) {
|
2013-02-11 00:38:51 +00:00
|
|
|
intptr_t sl = fieldAtOffset<uintptr_t>(src, BytesPerWord);
|
|
|
|
intptr_t dl = fieldAtOffset<uintptr_t>(dst, BytesPerWord);
|
2010-09-10 21:05:29 +00:00
|
|
|
if (LIKELY(length > 0)) {
|
|
|
|
if (LIKELY(srcOffset >= 0 and srcOffset + length <= sl and
|
|
|
|
dstOffset >= 0 and dstOffset + length <= dl))
|
|
|
|
{
|
2013-02-11 00:38:51 +00:00
|
|
|
uint8_t* sbody = &fieldAtOffset<uint8_t>(src, ArrayBody);
|
|
|
|
uint8_t* dbody = &fieldAtOffset<uint8_t>(dst, ArrayBody);
|
2010-09-10 21:05:29 +00:00
|
|
|
if (src == dst) {
|
|
|
|
memmove(dbody + (dstOffset * elementSize),
|
|
|
|
sbody + (srcOffset * elementSize),
|
|
|
|
length * elementSize);
|
|
|
|
} else {
|
|
|
|
memcpy(dbody + (dstOffset * elementSize),
|
|
|
|
sbody + (srcOffset * elementSize),
|
|
|
|
length * elementSize);
|
|
|
|
}
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
if (objectClass(t, dst)->objectMask()) {
|
2010-09-10 21:05:29 +00:00
|
|
|
mark(t, dst, ArrayBody + (dstOffset * BytesPerWord), length);
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
} else {
|
2014-05-29 04:17:25 +00:00
|
|
|
throwNew(t, GcIndexOutOfBoundsException::Type);
|
2010-09-10 21:05:29 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2014-05-29 04:17:25 +00:00
|
|
|
throwNew(t, GcNullPointerException::Type);
|
2010-09-10 21:05:29 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
throwNew(t, GcArrayStoreException::Type);
|
2010-09-10 21:05:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
runOnLoadIfFound(Thread* t, System::Library* library)
|
|
|
|
{
|
|
|
|
void* p = library->resolve("JNI_OnLoad");
|
2012-03-19 02:10:42 +00:00
|
|
|
|
|
|
|
#ifdef PLATFORM_WINDOWS
|
|
|
|
if (p == 0) {
|
|
|
|
p = library->resolve("_JNI_OnLoad@8");
|
|
|
|
if (p == 0) {
|
|
|
|
p = library->resolve("JNI_OnLoad@8");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-09-10 21:05:29 +00:00
|
|
|
if (p) {
|
|
|
|
jint (JNICALL * JNI_OnLoad)(Machine*, void*);
|
|
|
|
memcpy(&JNI_OnLoad, &p, sizeof(void*));
|
|
|
|
JNI_OnLoad(t->m, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
System::Library*
|
2010-09-20 23:31:23 +00:00
|
|
|
loadLibrary(Thread* t, const char* name)
|
2010-09-10 21:05:29 +00:00
|
|
|
{
|
|
|
|
ACQUIRE(t, t->m->classLock);
|
|
|
|
|
|
|
|
System::Library* last = t->m->libraries;
|
|
|
|
for (System::Library* lib = t->m->libraries; lib; lib = lib->next()) {
|
2010-09-20 23:31:23 +00:00
|
|
|
if (lib->name() and ::strcmp(lib->name(), name) == 0) {
|
2010-09-10 21:05:29 +00:00
|
|
|
// already loaded
|
|
|
|
return lib;
|
|
|
|
}
|
|
|
|
last = lib;
|
|
|
|
}
|
|
|
|
|
|
|
|
System::Library* lib;
|
2010-09-22 19:58:46 +00:00
|
|
|
if (t->m->system->success(t->m->system->load(&lib, name))) {
|
2010-09-10 21:05:29 +00:00
|
|
|
last->setNext(lib);
|
2010-09-20 23:31:23 +00:00
|
|
|
return lib;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
System::Library*
|
|
|
|
loadLibrary(Thread* t, const char* path, const char* name, bool mapName,
|
2013-02-27 18:34:43 +00:00
|
|
|
bool runOnLoad, bool throw_ = true)
|
2010-09-20 23:31:23 +00:00
|
|
|
{
|
|
|
|
ACQUIRE(t, t->m->classLock);
|
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
char* mappedName;
|
2010-09-20 23:31:23 +00:00
|
|
|
unsigned nameLength = strlen(name);
|
|
|
|
if (mapName) {
|
|
|
|
const char* builtins = findProperty(t, "avian.builtins");
|
|
|
|
if (builtins) {
|
|
|
|
const char* s = builtins;
|
|
|
|
while (*s) {
|
|
|
|
if (::strncmp(s, name, nameLength) == 0
|
|
|
|
and (s[nameLength] == ',' or s[nameLength] == 0))
|
|
|
|
{
|
|
|
|
// library is built in to this executable
|
|
|
|
if (runOnLoad and not t->m->triedBuiltinOnLoad) {
|
|
|
|
t->m->triedBuiltinOnLoad = true;
|
2010-12-09 04:36:02 +00:00
|
|
|
// todo: release the classLock before calling this to
|
|
|
|
// avoid the possibility of deadlock:
|
2010-09-20 23:31:23 +00:00
|
|
|
runOnLoadIfFound(t, t->m->libraries);
|
|
|
|
}
|
|
|
|
return t->m->libraries;
|
|
|
|
} else {
|
|
|
|
while (*s and *s != ',') ++ s;
|
|
|
|
if (*s) ++ s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* prefix = t->m->system->libraryPrefix();
|
|
|
|
const char* suffix = t->m->system->librarySuffix();
|
|
|
|
unsigned mappedNameLength = nameLength + strlen(prefix) + strlen(suffix);
|
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
mappedName = static_cast<char*>
|
2010-09-20 23:31:23 +00:00
|
|
|
(t->m->heap->allocate(mappedNameLength + 1));
|
|
|
|
|
|
|
|
snprintf(mappedName, mappedNameLength + 1, "%s%s%s", prefix, name, suffix);
|
|
|
|
|
|
|
|
name = mappedName;
|
|
|
|
nameLength = mappedNameLength;
|
2010-12-27 22:55:23 +00:00
|
|
|
} else {
|
|
|
|
mappedName = 0;
|
2010-09-20 23:31:23 +00:00
|
|
|
}
|
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
THREAD_RESOURCE2
|
|
|
|
(t, char*, mappedName, unsigned, nameLength, if (mappedName) {
|
|
|
|
t->m->heap->free(mappedName, nameLength + 1);
|
|
|
|
});
|
|
|
|
|
2010-09-20 23:31:23 +00:00
|
|
|
System::Library* lib = 0;
|
|
|
|
for (Tokenizer tokenizer(path, t->m->system->pathSeparator());
|
|
|
|
tokenizer.hasMore();)
|
|
|
|
{
|
2013-02-21 23:18:20 +00:00
|
|
|
String token(tokenizer.next());
|
2010-09-20 23:31:23 +00:00
|
|
|
|
|
|
|
unsigned fullNameLength = token.length + 1 + nameLength;
|
2010-12-27 22:55:23 +00:00
|
|
|
THREAD_RUNTIME_ARRAY(t, char, fullName, fullNameLength + 1);
|
2010-09-20 23:31:23 +00:00
|
|
|
|
|
|
|
snprintf(RUNTIME_ARRAY_BODY(fullName), fullNameLength + 1,
|
2013-02-21 23:18:20 +00:00
|
|
|
"%.*s/%s", token.length, token.text, name);
|
2010-09-20 23:31:23 +00:00
|
|
|
|
|
|
|
lib = loadLibrary(t, RUNTIME_ARRAY_BODY(fullName));
|
|
|
|
if (lib) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lib == 0) {
|
|
|
|
lib = loadLibrary(t, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lib) {
|
2010-09-10 21:05:29 +00:00
|
|
|
if (runOnLoad) {
|
|
|
|
runOnLoadIfFound(t, lib);
|
|
|
|
}
|
2013-02-27 18:34:43 +00:00
|
|
|
} else if (throw_) {
|
2014-05-29 04:17:25 +00:00
|
|
|
throwNew(t, GcUnsatisfiedLinkError::Type,
|
2014-04-23 21:22:10 +00:00
|
|
|
"library not found in %s: %s", path, name);
|
2010-09-20 23:31:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return lib;
|
2010-09-10 21:05:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
object
|
|
|
|
clone(Thread* t, object o)
|
|
|
|
{
|
|
|
|
PROTECT(t, o);
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
GcClass* class_ = objectClass(t, o);
|
2010-09-10 21:05:29 +00:00
|
|
|
unsigned size = baseSize(t, o, class_) * BytesPerWord;
|
|
|
|
object clone;
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
if (class_->arrayElementSize()) {
|
|
|
|
clone = static_cast<object>(allocate(t, size, class_->objectMask()));
|
2010-09-10 21:05:29 +00:00
|
|
|
memcpy(clone, o, size);
|
|
|
|
// clear any object header flags:
|
|
|
|
setObjectClass(t, o, objectClass(t, o));
|
2014-05-29 04:17:25 +00:00
|
|
|
} else if (instanceOf(t, type(t, GcCloneable::Type), o)) {
|
2010-09-10 21:05:29 +00:00
|
|
|
clone = make(t, class_);
|
|
|
|
memcpy(reinterpret_cast<void**>(clone) + 1,
|
|
|
|
reinterpret_cast<void**>(o) + 1,
|
|
|
|
size - BytesPerWord);
|
2013-04-23 03:19:01 +00:00
|
|
|
} else {
|
2014-07-11 14:38:56 +00:00
|
|
|
GcByteArray* classNameSlash = objectClass(t, o)->name();
|
|
|
|
THREAD_RUNTIME_ARRAY(t, char, classNameDot, classNameSlash->length());
|
2013-05-13 23:23:03 +00:00
|
|
|
replace('/', '.', RUNTIME_ARRAY_BODY(classNameDot),
|
2014-07-11 14:38:56 +00:00
|
|
|
reinterpret_cast<char*>(classNameSlash->body().begin()));
|
2014-05-29 04:17:25 +00:00
|
|
|
throwNew(t, GcCloneNotSupportedException::Type, "%s",
|
2013-05-13 23:23:03 +00:00
|
|
|
RUNTIME_ARRAY_BODY(classNameDot));
|
2010-09-10 21:05:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return clone;
|
|
|
|
}
|
|
|
|
|
2014-07-11 14:38:56 +00:00
|
|
|
GcStackTraceElement*
|
|
|
|
makeStackTraceElement(Thread* t, GcTraceElement* e)
|
2010-09-10 21:05:29 +00:00
|
|
|
{
|
|
|
|
PROTECT(t, e);
|
|
|
|
|
2014-07-11 14:38:56 +00:00
|
|
|
GcMethod* method = cast<GcMethod>(t, e->method());
|
2014-06-02 16:31:57 +00:00
|
|
|
PROTECT(t, method);
|
|
|
|
|
2014-07-11 14:38:56 +00:00
|
|
|
GcByteArray* class_name = method->class_()->name();
|
2014-05-29 04:17:25 +00:00
|
|
|
PROTECT(t, class_name);
|
2010-09-10 21:05:29 +00:00
|
|
|
|
2014-07-11 14:38:56 +00:00
|
|
|
THREAD_RUNTIME_ARRAY(t, char, s, class_name->length());
|
2010-09-10 21:05:29 +00:00
|
|
|
replace('/', '.', RUNTIME_ARRAY_BODY(s),
|
2014-07-11 14:38:56 +00:00
|
|
|
reinterpret_cast<char*>(class_name->body().begin()));
|
|
|
|
GcString* class_name_string = makeString(t, "%s", RUNTIME_ARRAY_BODY(s));
|
|
|
|
PROTECT(t, class_name_string);
|
2010-09-10 21:05:29 +00:00
|
|
|
|
2014-07-11 14:38:56 +00:00
|
|
|
GcByteArray* method_name = method->name();
|
2014-06-02 16:31:57 +00:00
|
|
|
PROTECT(t, method_name);
|
2010-09-10 21:05:29 +00:00
|
|
|
|
2014-07-11 14:38:56 +00:00
|
|
|
GcString* method_name_string = t->m->classpath->makeString
|
|
|
|
(t, reinterpret_cast<object>(method_name), 0, method_name->length() - 1);
|
|
|
|
PROTECT(t, method_name_string);
|
2010-09-10 21:05:29 +00:00
|
|
|
|
|
|
|
unsigned line = t->m->processor->lineNumber
|
2014-07-11 14:38:56 +00:00
|
|
|
(t, method, e->ip());
|
2010-09-10 21:05:29 +00:00
|
|
|
|
2014-07-11 14:38:56 +00:00
|
|
|
GcByteArray* file = method->class_()->sourceFile();
|
|
|
|
GcString* file_string = file ? t->m->classpath->makeString
|
|
|
|
(t, reinterpret_cast<object>(file), 0, file->length() - 1) : 0;
|
2010-09-10 21:05:29 +00:00
|
|
|
|
2014-07-11 14:38:56 +00:00
|
|
|
return makeStackTraceElement(t, class_name_string, method_name_string, file_string, line);
|
2010-09-10 21:05:29 +00:00
|
|
|
}
|
|
|
|
|
2011-02-23 00:54:56 +00:00
|
|
|
object
|
|
|
|
translateInvokeResult(Thread* t, unsigned returnCode, object o)
|
|
|
|
{
|
|
|
|
switch (returnCode) {
|
|
|
|
case ByteField:
|
2014-07-11 14:38:56 +00:00
|
|
|
return reinterpret_cast<object>(makeByte(t, cast<GcInt>(t, o)->value()));
|
2011-02-23 00:54:56 +00:00
|
|
|
|
|
|
|
case BooleanField:
|
2014-07-11 14:38:56 +00:00
|
|
|
return reinterpret_cast<object>(makeBoolean(t, cast<GcInt>(t, o)->value() != 0));
|
2011-02-23 00:54:56 +00:00
|
|
|
|
|
|
|
case CharField:
|
2014-07-11 14:38:56 +00:00
|
|
|
return reinterpret_cast<object>(makeChar(t, cast<GcInt>(t, o)->value()));
|
2011-02-23 00:54:56 +00:00
|
|
|
|
|
|
|
case ShortField:
|
2014-07-11 14:38:56 +00:00
|
|
|
return reinterpret_cast<object>(makeShort(t, cast<GcInt>(t, o)->value()));
|
2011-02-23 00:54:56 +00:00
|
|
|
|
|
|
|
case FloatField:
|
2014-07-11 14:38:56 +00:00
|
|
|
return reinterpret_cast<object>(makeFloat(t, cast<GcInt>(t, o)->value()));
|
2011-02-23 00:54:56 +00:00
|
|
|
|
|
|
|
case IntField:
|
|
|
|
case LongField:
|
|
|
|
case ObjectField:
|
|
|
|
case VoidField:
|
|
|
|
return o;
|
|
|
|
|
|
|
|
case DoubleField:
|
2014-07-11 14:38:56 +00:00
|
|
|
return reinterpret_cast<object>(makeDouble(t, cast<GcLong>(t, o)->value()));
|
2011-02-23 00:54:56 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
abort(t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
GcClass*
|
2014-06-28 21:11:31 +00:00
|
|
|
resolveClassBySpec(Thread* t, GcClassLoader* loader, const char* spec,
|
2013-02-20 17:22:40 +00:00
|
|
|
unsigned specLength)
|
|
|
|
{
|
|
|
|
switch (*spec) {
|
|
|
|
case 'L': {
|
|
|
|
THREAD_RUNTIME_ARRAY(t, char, s, specLength - 1);
|
|
|
|
memcpy(RUNTIME_ARRAY_BODY(s), spec + 1, specLength - 2);
|
|
|
|
RUNTIME_ARRAY_BODY(s)[specLength - 2] = 0;
|
2013-02-22 21:50:15 +00:00
|
|
|
return resolveClass(t, loader, RUNTIME_ARRAY_BODY(s));
|
2013-02-20 17:22:40 +00:00
|
|
|
}
|
2014-05-29 04:17:25 +00:00
|
|
|
|
2013-02-20 17:22:40 +00:00
|
|
|
case '[': {
|
|
|
|
THREAD_RUNTIME_ARRAY(t, char, s, specLength + 1);
|
|
|
|
memcpy(RUNTIME_ARRAY_BODY(s), spec, specLength);
|
|
|
|
RUNTIME_ARRAY_BODY(s)[specLength] = 0;
|
2013-02-22 21:50:15 +00:00
|
|
|
return resolveClass(t, loader, RUNTIME_ARRAY_BODY(s));
|
2013-02-20 17:22:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
return primitiveClass(t, *spec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-21 04:16:33 +00:00
|
|
|
GcJclass*
|
2014-06-28 21:11:31 +00:00
|
|
|
resolveJType(Thread* t, GcClassLoader* loader, const char* spec, unsigned specLength)
|
2013-02-21 22:37:17 +00:00
|
|
|
{
|
|
|
|
return getJClass(t, resolveClassBySpec(t, loader, spec, specLength));
|
|
|
|
}
|
|
|
|
|
2014-07-11 14:38:56 +00:00
|
|
|
GcPair*
|
2014-06-28 21:11:31 +00:00
|
|
|
resolveParameterTypes(Thread* t, GcClassLoader* loader, GcByteArray* spec,
|
2013-02-21 22:37:17 +00:00
|
|
|
unsigned* parameterCount, unsigned* returnTypeSpec)
|
|
|
|
{
|
|
|
|
PROTECT(t, loader);
|
|
|
|
PROTECT(t, spec);
|
|
|
|
|
2014-07-11 14:38:56 +00:00
|
|
|
GcPair* list = 0;
|
2013-02-21 22:37:17 +00:00
|
|
|
PROTECT(t, list);
|
|
|
|
|
|
|
|
unsigned offset = 1;
|
|
|
|
unsigned count = 0;
|
2014-06-28 21:11:31 +00:00
|
|
|
while (spec->body()[offset] != ')') {
|
|
|
|
switch (spec->body()[offset]) {
|
2013-02-21 22:37:17 +00:00
|
|
|
case 'L': {
|
|
|
|
unsigned start = offset;
|
|
|
|
++ offset;
|
2014-06-28 21:11:31 +00:00
|
|
|
while (spec->body()[offset] != ';') ++ offset;
|
2013-02-21 22:37:17 +00:00
|
|
|
++ offset;
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
GcClass* type = resolveClassBySpec
|
2014-06-28 21:11:31 +00:00
|
|
|
(t, loader, reinterpret_cast<char*>(&spec->body()[start]),
|
2013-02-21 22:37:17 +00:00
|
|
|
offset - start);
|
2014-05-29 04:17:25 +00:00
|
|
|
|
2014-07-11 14:38:56 +00:00
|
|
|
list = makePair(t, reinterpret_cast<object>(type), reinterpret_cast<object>(list));
|
2013-02-21 22:37:17 +00:00
|
|
|
|
|
|
|
++ count;
|
|
|
|
} break;
|
2014-05-29 04:17:25 +00:00
|
|
|
|
2013-02-21 22:37:17 +00:00
|
|
|
case '[': {
|
|
|
|
unsigned start = offset;
|
2014-06-28 21:11:31 +00:00
|
|
|
while (spec->body()[offset] == '[') ++ offset;
|
|
|
|
switch (spec->body()[offset]) {
|
2013-02-21 22:37:17 +00:00
|
|
|
case 'L':
|
|
|
|
++ offset;
|
2014-06-28 21:11:31 +00:00
|
|
|
while (spec->body()[offset] != ';') ++ offset;
|
2013-02-21 22:37:17 +00:00
|
|
|
++ offset;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
++ offset;
|
|
|
|
break;
|
|
|
|
}
|
2014-05-29 04:17:25 +00:00
|
|
|
|
|
|
|
GcClass* type = resolveClassBySpec
|
2014-06-28 21:11:31 +00:00
|
|
|
(t, loader, reinterpret_cast<char*>(&spec->body()[start]),
|
2013-02-21 22:37:17 +00:00
|
|
|
offset - start);
|
2014-05-29 04:17:25 +00:00
|
|
|
|
2014-07-11 14:38:56 +00:00
|
|
|
list = makePair(t, reinterpret_cast<object>(type), reinterpret_cast<object>(list));
|
2013-02-21 22:37:17 +00:00
|
|
|
++ count;
|
|
|
|
} break;
|
|
|
|
|
|
|
|
default:
|
2014-07-11 14:38:56 +00:00
|
|
|
list = makePair
|
|
|
|
(t, reinterpret_cast<object>(primitiveClass(t, spec->body()[offset])), reinterpret_cast<object>(list));
|
2013-02-21 22:37:17 +00:00
|
|
|
++ offset;
|
|
|
|
++ count;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*parameterCount = count;
|
|
|
|
*returnTypeSpec = offset + 1;
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
object
|
2014-06-28 21:11:31 +00:00
|
|
|
resolveParameterJTypes(Thread* t, GcClassLoader* loader, GcByteArray* spec,
|
2013-02-21 22:37:17 +00:00
|
|
|
unsigned* parameterCount, unsigned* returnTypeSpec)
|
|
|
|
{
|
2014-07-11 14:38:56 +00:00
|
|
|
GcPair* list = resolveParameterTypes
|
2013-02-21 22:37:17 +00:00
|
|
|
(t, loader, spec, parameterCount, returnTypeSpec);
|
|
|
|
|
|
|
|
PROTECT(t, list);
|
2014-05-29 04:17:25 +00:00
|
|
|
|
2013-02-21 22:37:17 +00:00
|
|
|
object array = makeObjectArray
|
2014-05-29 04:17:25 +00:00
|
|
|
(t, type(t, GcJclass::Type), *parameterCount);
|
2013-02-21 22:37:17 +00:00
|
|
|
PROTECT(t, array);
|
|
|
|
|
|
|
|
for (int i = *parameterCount - 1; i >= 0; --i) {
|
2014-07-11 14:38:56 +00:00
|
|
|
object c = reinterpret_cast<object>(getJClass(t, cast<GcClass>(t, list->first())));
|
2013-02-21 22:37:17 +00:00
|
|
|
set(t, array, ArrayBody + (i * BytesPerWord), c);
|
2014-07-11 14:38:56 +00:00
|
|
|
list = cast<GcPair>(t, list->second());
|
2013-02-21 22:37:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return array;
|
|
|
|
}
|
|
|
|
|
|
|
|
object
|
2014-06-28 21:11:31 +00:00
|
|
|
resolveExceptionJTypes(Thread* t, GcClassLoader* loader, GcMethodAddendum* addendum)
|
2013-02-21 22:37:17 +00:00
|
|
|
{
|
2014-06-28 21:11:31 +00:00
|
|
|
if (addendum == 0 or addendum->exceptionTable() == 0) {
|
2014-05-29 04:17:25 +00:00
|
|
|
return makeObjectArray(t, type(t, GcJclass::Type), 0);
|
2013-02-21 22:37:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PROTECT(t, loader);
|
|
|
|
PROTECT(t, addendum);
|
|
|
|
|
2014-07-11 14:38:56 +00:00
|
|
|
GcShortArray* exceptionTable = cast<GcShortArray>(t, addendum->exceptionTable());
|
|
|
|
PROTECT(t, exceptionTable);
|
|
|
|
|
2013-02-21 22:37:17 +00:00
|
|
|
object array = makeObjectArray
|
2014-05-29 04:17:25 +00:00
|
|
|
(t, type(t, GcJclass::Type),
|
2014-07-11 14:38:56 +00:00
|
|
|
exceptionTable->length());
|
2013-02-21 22:37:17 +00:00
|
|
|
PROTECT(t, array);
|
|
|
|
|
2014-07-11 14:38:56 +00:00
|
|
|
for (unsigned i = 0; i < exceptionTable->length(); ++i)
|
2013-02-21 22:37:17 +00:00
|
|
|
{
|
2014-07-11 14:38:56 +00:00
|
|
|
uint16_t index = exceptionTable->body()[i] - 1;
|
2013-02-21 22:37:17 +00:00
|
|
|
|
2014-07-11 14:38:56 +00:00
|
|
|
object o = singletonObject(t, addendum->pool()->as<GcSingleton>(t), index);
|
2014-05-29 04:17:25 +00:00
|
|
|
|
|
|
|
if (objectClass(t, o) == type(t, GcReference::Type)) {
|
2014-06-29 03:18:22 +00:00
|
|
|
o = reinterpret_cast<object>(resolveClass(t, loader, cast<GcReference>(t, o)->name()));
|
2013-02-21 22:37:17 +00:00
|
|
|
|
2014-06-28 21:11:31 +00:00
|
|
|
set(t, reinterpret_cast<object>(addendum->pool()), SingletonBody + (index * BytesPerWord),
|
2013-02-21 22:37:17 +00:00
|
|
|
o);
|
|
|
|
}
|
|
|
|
|
2014-06-21 04:16:33 +00:00
|
|
|
o = reinterpret_cast<object>(getJClass(t, cast<GcClass>(t, o)));
|
2013-02-21 22:37:17 +00:00
|
|
|
|
2014-06-27 00:17:16 +00:00
|
|
|
set(t, reinterpret_cast<object>(array), ArrayBody + (i * BytesPerWord), o);
|
2013-02-21 22:37:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return array;
|
|
|
|
}
|
|
|
|
|
|
|
|
object
|
2014-05-29 04:17:25 +00:00
|
|
|
invoke(Thread* t, GcMethod* method, object instance, object args)
|
2013-02-21 22:37:17 +00:00
|
|
|
{
|
|
|
|
PROTECT(t, method);
|
|
|
|
PROTECT(t, instance);
|
|
|
|
PROTECT(t, args);
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
if (method->flags() & ACC_STATIC) {
|
2013-02-21 22:37:17 +00:00
|
|
|
instance = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((args == 0 ? 0 : objectArrayLength(t, args))
|
2014-05-29 04:17:25 +00:00
|
|
|
!= method->parameterCount())
|
2013-02-21 22:37:17 +00:00
|
|
|
{
|
2014-05-29 04:17:25 +00:00
|
|
|
throwNew(t, GcIllegalArgumentException::Type);
|
2013-02-21 22:37:17 +00:00
|
|
|
}
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
if (method->parameterCount()) {
|
2014-06-21 04:16:33 +00:00
|
|
|
unsigned specLength = method->spec()->length();
|
2013-02-21 22:37:17 +00:00
|
|
|
THREAD_RUNTIME_ARRAY(t, char, spec, specLength);
|
2013-02-22 21:50:15 +00:00
|
|
|
memcpy(RUNTIME_ARRAY_BODY(spec),
|
2014-06-21 04:16:33 +00:00
|
|
|
method->spec()->body().begin(), specLength);
|
2013-02-21 22:37:17 +00:00
|
|
|
unsigned i = 0;
|
2013-02-22 21:50:15 +00:00
|
|
|
for (MethodSpecIterator it(t, RUNTIME_ARRAY_BODY(spec)); it.hasNext();) {
|
2014-05-29 04:17:25 +00:00
|
|
|
GcClass* type;
|
2013-02-21 22:37:17 +00:00
|
|
|
bool objectType = false;
|
|
|
|
const char* p = it.next();
|
|
|
|
switch (*p) {
|
2014-05-29 04:17:25 +00:00
|
|
|
case 'Z': type = vm::type(t, GcBoolean::Type); break;
|
|
|
|
case 'B': type = vm::type(t, GcByte::Type); break;
|
|
|
|
case 'S': type = vm::type(t, GcShort::Type); break;
|
|
|
|
case 'C': type = vm::type(t, GcChar::Type); break;
|
|
|
|
case 'I': type = vm::type(t, GcInt::Type); break;
|
|
|
|
case 'F': type = vm::type(t, GcFloat::Type); break;
|
|
|
|
case 'J': type = vm::type(t, GcLong::Type); break;
|
|
|
|
case 'D': type = vm::type(t, GcDouble::Type); break;
|
2013-02-21 22:37:17 +00:00
|
|
|
|
2013-04-23 00:57:26 +00:00
|
|
|
case 'L':
|
2013-02-21 22:37:17 +00:00
|
|
|
case '[': {
|
|
|
|
objectType = true;
|
2013-04-23 00:57:26 +00:00
|
|
|
unsigned nameLength;
|
|
|
|
if (*p == 'L') {
|
|
|
|
++ p;
|
|
|
|
nameLength = it.s - p;
|
|
|
|
} else {
|
|
|
|
nameLength = (it.s - p) + 1;
|
|
|
|
}
|
2013-02-21 22:37:17 +00:00
|
|
|
THREAD_RUNTIME_ARRAY(t, char, name, nameLength);
|
2013-02-22 21:50:15 +00:00
|
|
|
memcpy(RUNTIME_ARRAY_BODY(name), p, nameLength - 1);
|
|
|
|
RUNTIME_ARRAY_BODY(name)[nameLength - 1] = 0;
|
2013-02-21 22:37:17 +00:00
|
|
|
type = resolveClass
|
2014-06-28 21:11:31 +00:00
|
|
|
(t, method->class_()->loader(),
|
2013-02-22 21:50:15 +00:00
|
|
|
RUNTIME_ARRAY_BODY(name));
|
2013-02-21 22:37:17 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
object arg = objectArrayBody(t, args, i++);
|
|
|
|
if ((arg == 0 and (not objectType))
|
|
|
|
or (arg and (not instanceOf(t, type, arg))))
|
|
|
|
{
|
|
|
|
// fprintf(stderr, "%s is not a %s\n", arg ? &byteArrayBody(t, className(t, objectClass(t, arg)), 0) : reinterpret_cast<const int8_t*>("<null>"), &byteArrayBody(t, className(t, type), 0));
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
throwNew(t, GcIllegalArgumentException::Type);
|
2013-02-21 22:37:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-21 04:16:33 +00:00
|
|
|
initClass(t, method->class_());
|
2013-12-06 05:28:13 +00:00
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
unsigned returnCode = method->returnCode();
|
2013-02-21 22:37:17 +00:00
|
|
|
|
|
|
|
THREAD_RESOURCE0(t, {
|
|
|
|
if (t->exception) {
|
|
|
|
t->exception = makeThrowable
|
2014-05-29 04:17:25 +00:00
|
|
|
(t, GcInvocationTargetException::Type, 0, 0, t->exception);
|
|
|
|
|
2013-04-18 17:23:59 +00:00
|
|
|
set(t, t->exception, InvocationTargetExceptionTarget,
|
2014-06-28 23:24:24 +00:00
|
|
|
t->exception->cause());
|
2013-02-21 22:37:17 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
object result;
|
|
|
|
if (args) {
|
|
|
|
result = t->m->processor->invokeArray(t, method, instance, args);
|
|
|
|
} else {
|
|
|
|
result = t->m->processor->invoke(t, method, instance);
|
|
|
|
}
|
|
|
|
|
|
|
|
return translateInvokeResult(t, returnCode, result);
|
|
|
|
}
|
|
|
|
|
|
|
|
// only safe to call during bootstrap when there's only one thread
|
|
|
|
// running:
|
|
|
|
void
|
2014-05-29 04:17:25 +00:00
|
|
|
intercept(Thread* t, GcClass* c, const char* name, const char* spec,
|
2013-03-15 19:28:01 +00:00
|
|
|
void* function, bool updateRuntimeData)
|
2013-02-21 22:37:17 +00:00
|
|
|
{
|
2014-05-29 04:17:25 +00:00
|
|
|
GcMethod* m = findMethodOrNull(t, c, name, spec);
|
2013-02-21 22:37:17 +00:00
|
|
|
if (m) {
|
|
|
|
PROTECT(t, m);
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
m->flags() |= ACC_NATIVE;
|
2013-06-04 19:32:22 +00:00
|
|
|
|
2013-03-15 19:28:01 +00:00
|
|
|
if (updateRuntimeData) {
|
2014-05-29 04:17:25 +00:00
|
|
|
GcMethod* clone = methodClone(t, m);
|
2013-02-21 22:37:17 +00:00
|
|
|
|
2013-03-15 19:28:01 +00:00
|
|
|
// make clone private to prevent vtable updates at compilation
|
|
|
|
// time. Otherwise, our interception might be bypassed by calls
|
|
|
|
// through the vtable.
|
2014-05-29 04:17:25 +00:00
|
|
|
clone->flags() |= ACC_PRIVATE;
|
|
|
|
|
2014-07-11 14:38:56 +00:00
|
|
|
GcNativeIntercept* native = makeNativeIntercept(t, function, true, reinterpret_cast<object>(clone));
|
2013-02-21 22:37:17 +00:00
|
|
|
|
2013-03-15 19:28:01 +00:00
|
|
|
PROTECT(t, native);
|
2014-05-29 04:17:25 +00:00
|
|
|
|
2014-07-11 14:38:56 +00:00
|
|
|
GcMethodRuntimeData* runtimeData = getMethodRuntimeData(t, m);
|
2014-05-29 04:17:25 +00:00
|
|
|
|
2013-03-15 19:28:01 +00:00
|
|
|
set(t, runtimeData, MethodRuntimeDataNative, native);
|
|
|
|
}
|
2013-02-21 22:37:17 +00:00
|
|
|
} else {
|
|
|
|
// If we can't find the method, just ignore it, since ProGuard may
|
|
|
|
// have stripped it out as unused. Otherwise, the code below can
|
|
|
|
// be uncommented for debugging purposes.
|
|
|
|
|
|
|
|
// fprintf(stderr, "unable to find %s%s in %s\n",
|
2014-07-11 14:38:56 +00:00
|
|
|
// name, spec, &byteArrayBody(t, c->name(), 0));
|
2013-02-21 22:37:17 +00:00
|
|
|
|
|
|
|
// abort(t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-23 00:23:59 +00:00
|
|
|
Finder*
|
|
|
|
getFinder(Thread* t, const char* name, unsigned nameLength)
|
|
|
|
{
|
|
|
|
ACQUIRE(t, t->m->referenceLock);
|
2014-05-29 04:17:25 +00:00
|
|
|
|
2014-06-30 01:44:41 +00:00
|
|
|
for (GcFinder* p = roots(t)->virtualFileFinders();
|
2014-07-11 14:38:56 +00:00
|
|
|
p; p = p->next())
|
2013-02-23 00:23:59 +00:00
|
|
|
{
|
2014-07-11 14:38:56 +00:00
|
|
|
if (p->name()->length() == nameLength
|
2013-02-23 00:23:59 +00:00
|
|
|
and strncmp(reinterpret_cast<const char*>
|
2014-07-11 14:38:56 +00:00
|
|
|
(p->name()->body().begin()),
|
2013-02-23 00:23:59 +00:00
|
|
|
name, nameLength))
|
|
|
|
{
|
2014-07-11 14:38:56 +00:00
|
|
|
return static_cast<Finder*>(p->finder());
|
2013-02-23 00:23:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 14:38:56 +00:00
|
|
|
GcByteArray* n = makeByteArray(t, nameLength + 1);
|
|
|
|
memcpy(n->body().begin(), name, nameLength);
|
2013-02-23 00:23:59 +00:00
|
|
|
|
|
|
|
void* p = t->m->libraries->resolve
|
2014-07-11 14:38:56 +00:00
|
|
|
(reinterpret_cast<const char*>(n->body().begin()));
|
2013-02-23 00:23:59 +00:00
|
|
|
|
|
|
|
if (p) {
|
|
|
|
uint8_t* (*function)(unsigned*);
|
|
|
|
memcpy(&function, &p, BytesPerWord);
|
|
|
|
|
|
|
|
unsigned size;
|
|
|
|
uint8_t* data = function(&size);
|
|
|
|
if (data) {
|
|
|
|
Finder* f = makeFinder(t->m->system, t->m->heap, data, size);
|
2014-07-11 14:38:56 +00:00
|
|
|
GcFinder* finder = makeFinder
|
2014-06-30 01:44:41 +00:00
|
|
|
(t, f, n, roots(t)->virtualFileFinders());
|
2013-02-23 00:23:59 +00:00
|
|
|
|
2014-06-30 01:44:41 +00:00
|
|
|
set(t, roots(t), RootsVirtualFileFinders, finder);
|
2013-02-23 00:23:59 +00:00
|
|
|
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-12-06 22:45:46 +00:00
|
|
|
object
|
2014-07-11 14:38:56 +00:00
|
|
|
getDeclaredClasses(Thread* t, GcClass* c, bool publicOnly)
|
2013-12-06 22:45:46 +00:00
|
|
|
{
|
2014-07-11 14:38:56 +00:00
|
|
|
GcClassAddendum* addendum = c->addendum();
|
2013-12-06 22:45:46 +00:00
|
|
|
if (addendum) {
|
2014-07-11 14:38:56 +00:00
|
|
|
GcArray* table = cast<GcArray>(t, addendum->innerClassTable());
|
2013-12-06 22:45:46 +00:00
|
|
|
if (table) {
|
|
|
|
PROTECT(t, table);
|
|
|
|
|
|
|
|
unsigned count = 0;
|
2014-07-11 14:38:56 +00:00
|
|
|
for (unsigned i = 0; i < table->length(); ++i) {
|
|
|
|
GcInnerClassReference* reference = cast<GcInnerClassReference>(t, table->body()[i]);
|
|
|
|
GcByteArray* outer = reference->outer();
|
|
|
|
if (outer and byteArrayEqual(t, reinterpret_cast<object>(outer), reinterpret_cast<object>(c->name()))
|
2013-12-06 22:45:46 +00:00
|
|
|
and ((not publicOnly)
|
2014-07-11 14:38:56 +00:00
|
|
|
or (reference->flags() & ACC_PUBLIC)))
|
2013-12-06 22:45:46 +00:00
|
|
|
{
|
|
|
|
++ count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
object result = makeObjectArray(t, type(t, GcJclass::Type), count);
|
2013-12-06 22:45:46 +00:00
|
|
|
PROTECT(t, result);
|
|
|
|
|
2014-07-11 14:38:56 +00:00
|
|
|
for (unsigned i = 0; i < table->length(); ++i) {
|
|
|
|
GcInnerClassReference* reference = cast<GcInnerClassReference>(t, table->body()[i]);
|
|
|
|
GcByteArray* outer = reference->outer();
|
|
|
|
if (outer and byteArrayEqual(t, reinterpret_cast<object>(outer), reinterpret_cast<object>(c->name()))
|
2013-12-06 22:45:46 +00:00
|
|
|
and ((not publicOnly)
|
2014-07-11 14:38:56 +00:00
|
|
|
or (reference->flags() & ACC_PUBLIC)))
|
2013-12-06 22:45:46 +00:00
|
|
|
{
|
2014-06-21 04:16:33 +00:00
|
|
|
object inner = reinterpret_cast<object>(getJClass(
|
2014-05-29 04:17:25 +00:00
|
|
|
t,
|
|
|
|
resolveClass(
|
|
|
|
t,
|
2014-07-11 14:38:56 +00:00
|
|
|
c->loader(),
|
|
|
|
reference->inner())));
|
2014-05-29 04:17:25 +00:00
|
|
|
|
2013-12-06 22:45:46 +00:00
|
|
|
-- count;
|
|
|
|
set(t, result, ArrayBody + (count * BytesPerWord), inner);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
return makeObjectArray(t, type(t, GcJclass::Type), 0);
|
2013-12-06 22:45:46 +00:00
|
|
|
}
|
|
|
|
|
2014-06-21 04:16:33 +00:00
|
|
|
GcJclass*
|
2014-07-11 14:38:56 +00:00
|
|
|
getDeclaringClass(Thread* t, GcClass* c)
|
2013-12-06 22:45:46 +00:00
|
|
|
{
|
2014-07-11 14:38:56 +00:00
|
|
|
GcClassAddendum* addendum = c->addendum();
|
2013-12-06 22:45:46 +00:00
|
|
|
if (addendum) {
|
2014-07-11 14:38:56 +00:00
|
|
|
GcArray* table = cast<GcArray>(t, addendum->innerClassTable());
|
2013-12-06 22:45:46 +00:00
|
|
|
if (table) {
|
2014-07-11 14:38:56 +00:00
|
|
|
for (unsigned i = 0; i < table->length(); ++i) {
|
|
|
|
GcInnerClassReference* reference = cast<GcInnerClassReference>(t, table->body()[i]);
|
|
|
|
if (reference->outer() and strcmp
|
|
|
|
(reference->inner()->body().begin(),
|
|
|
|
c->name()->body().begin()) == 0)
|
2013-12-06 22:45:46 +00:00
|
|
|
{
|
2014-05-29 04:17:25 +00:00
|
|
|
return getJClass(
|
|
|
|
t,
|
|
|
|
resolveClass(t,
|
2014-07-11 14:38:56 +00:00
|
|
|
c->loader(),
|
|
|
|
reference->outer()));
|
2013-12-06 22:45:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-03-06 22:01:44 +00:00
|
|
|
unsigned
|
2014-07-11 14:38:56 +00:00
|
|
|
classModifiers(Thread* t, GcClass* c)
|
2014-03-06 22:01:44 +00:00
|
|
|
{
|
2014-07-11 14:38:56 +00:00
|
|
|
GcClassAddendum* addendum = c->addendum();
|
2014-03-06 22:01:44 +00:00
|
|
|
if (addendum) {
|
2014-07-11 14:38:56 +00:00
|
|
|
GcArray* table = cast<GcArray>(t, addendum->innerClassTable());
|
2014-03-06 22:01:44 +00:00
|
|
|
if (table) {
|
2014-07-11 14:38:56 +00:00
|
|
|
for (unsigned i = 0; i < table->length(); ++i) {
|
|
|
|
GcInnerClassReference* reference = cast<GcInnerClassReference>(t, table->body()[i]);
|
2014-03-06 22:01:44 +00:00
|
|
|
if (0 == strcmp
|
2014-07-11 14:38:56 +00:00
|
|
|
(c->name()->body().begin(),
|
|
|
|
reference->inner()->body().begin()))
|
2014-03-06 22:01:44 +00:00
|
|
|
{
|
2014-07-11 14:38:56 +00:00
|
|
|
return reference->flags();
|
2014-05-29 04:17:25 +00:00
|
|
|
}
|
2014-03-06 22:01:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 14:38:56 +00:00
|
|
|
return c->flags();
|
2014-03-06 22:01:44 +00:00
|
|
|
}
|
|
|
|
|
2010-09-10 21:05:29 +00:00
|
|
|
} // namespace vm
|
|
|
|
|
|
|
|
#endif//CLASSPATH_COMMON_H
|