add support for using the OpenJDK 8 class library

This ensures that all tests pass when Avian is built with an
openjdk=$path option such that $path points to either OpenJDK 7 or 8.

Note that I have not yet tried using the openjdk-src option with
OpenJDK 8.  I'll work on that next.
This commit is contained in:
Joel Dice 2014-04-23 15:22:10 -06:00
parent 5beb148df3
commit 7de555c797
11 changed files with 271 additions and 28 deletions

View File

@ -74,6 +74,7 @@ SUNWprivate_1.1 {
JVM_CurrentTimeMillis; JVM_CurrentTimeMillis;
JVM_DefineClass; JVM_DefineClass;
JVM_DefineClassWithSource; JVM_DefineClassWithSource;
JVM_DefineClassWithSourceCond;
JVM_DesiredAssertionStatus; JVM_DesiredAssertionStatus;
JVM_DisableCompiler; JVM_DisableCompiler;
JVM_DoPrivileged; JVM_DoPrivileged;
@ -127,12 +128,14 @@ SUNWprivate_1.1 {
JVM_GetClassNameUTF; JVM_GetClassNameUTF;
JVM_GetClassSignature; JVM_GetClassSignature;
JVM_GetClassSigners; JVM_GetClassSigners;
JVM_GetClassTypeAnnotations;
JVM_GetComponentType; JVM_GetComponentType;
JVM_GetDeclaredClasses; JVM_GetDeclaredClasses;
JVM_GetDeclaringClass; JVM_GetDeclaringClass;
JVM_GetEnclosingMethodInfo; JVM_GetEnclosingMethodInfo;
JVM_GetFieldAnnotations; JVM_GetFieldAnnotations;
JVM_GetFieldIxModifiers; JVM_GetFieldIxModifiers;
JVM_GetFieldTypeAnnotations;
JVM_GetHostName; JVM_GetHostName;
JVM_GetInheritedAccessControlContext; JVM_GetInheritedAccessControlContext;
JVM_GetInterfaceVersion; JVM_GetInterfaceVersion;
@ -185,6 +188,7 @@ SUNWprivate_1.1 {
JVM_IsSilentCompiler; JVM_IsSilentCompiler;
JVM_IsSupportedJNIVersion; JVM_IsSupportedJNIVersion;
JVM_IsThreadAlive; JVM_IsThreadAlive;
JVM_IsVMGeneratedMethodIx;
JVM_LatestUserDefinedLoader; JVM_LatestUserDefinedLoader;
JVM_Listen; JVM_Listen;
JVM_LoadClass0; JVM_LoadClass0;
@ -220,6 +224,7 @@ SUNWprivate_1.1 {
JVM_SetArrayElement; JVM_SetArrayElement;
JVM_SetClassSigners; JVM_SetClassSigners;
JVM_SetLength; JVM_SetLength;
JVM_SetNativeThreadName;
JVM_SetPrimitiveArrayElement; JVM_SetPrimitiveArrayElement;
JVM_SetProtectionDomain; JVM_SetProtectionDomain;
JVM_SetSockOpt; JVM_SetSockOpt;

View File

@ -239,8 +239,8 @@ loadLibrary(Thread* t, const char* path, const char* name, bool mapName,
runOnLoadIfFound(t, lib); runOnLoadIfFound(t, lib);
} }
} else if (throw_) { } else if (throw_) {
throwNew(t, Machine::UnsatisfiedLinkErrorType, "library not found: %s", throwNew(t, Machine::UnsatisfiedLinkErrorType,
name); "library not found in %s: %s", path, name);
} }
return lib; return lib;

View File

@ -233,15 +233,18 @@ enum TypeCode {
enum Constant { enum Constant {
CONSTANT_Class = 7, 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_Double = 6,
CONSTANT_Fieldref = 9,
CONSTANT_Float = 4,
CONSTANT_Integer = 3,
CONSTANT_InterfaceMethodref = 11,
CONSTANT_InvokeDynamic = 18,
CONSTANT_Long = 5,
CONSTANT_MethodHandle = 15,
CONSTANT_MethodType = 16,
CONSTANT_Methodref = 10,
CONSTANT_NameAndType = 12, CONSTANT_NameAndType = 12,
CONSTANT_String = 8,
CONSTANT_Utf8 = 1 CONSTANT_Utf8 = 1
}; };

View File

@ -2197,6 +2197,16 @@ stringOffset(Thread*, object)
return 0; return 0;
} }
# ifndef HAVE_StringHash32
inline object
makeString(Thread* t, object data, int32_t hash, int32_t)
{
return makeString(t, data, hash);
}
# endif // not HAVE_StringHash32
inline object inline object
makeString(Thread* t, object data, unsigned offset, unsigned length, unsigned) makeString(Thread* t, object data, unsigned offset, unsigned length, unsigned)
{ {
@ -2476,16 +2486,33 @@ fieldSize(Thread* t, object field)
} }
inline void inline void
scanMethodSpec(Thread* t, const char* s, unsigned* parameterCount, scanMethodSpec(Thread* t, const char* s, bool static_,
unsigned* parameterCount, unsigned* parameterFootprint,
unsigned* returnCode) unsigned* returnCode)
{ {
unsigned count = 0; unsigned count = 0;
unsigned footprint = 0;
MethodSpecIterator it(t, s); MethodSpecIterator it(t, s);
for (; it.hasNext(); it.next()) { while (it.hasNext()) {
++ count; ++ count;
switch (*it.next()) {
case 'J':
case 'D':
footprint += 2;
break;
default:
++ footprint;
break;
}
}
if (not static_) {
++ footprint;
} }
*parameterCount = count; *parameterCount = count;
*parameterFootprint = footprint;
*returnCode = fieldCode(t, *it.returnSpec()); *returnCode = fieldCode(t, *it.returnSpec());
} }

View File

@ -2136,6 +2136,58 @@ countConstructors(Thread* t, object c, bool publicOnly)
return count; return count;
} }
#ifdef HAVE_JexecutableHasRealParameterData
object
makeJmethod(Thread* t,
uint8_t override,
object securityCheckCache,
object clazz,
uint32_t slot,
object name,
object returnType,
object parameterTypes,
object exceptionTypes,
uint32_t modifiers,
object signature,
object genericInfo,
object annotations,
object parameterAnnotations,
object annotationDefault,
object methodAccessor,
object root,
object declaredAnnotations)
{
return makeJmethod
(t, override, securityCheckCache, 0, 0, declaredAnnotations, clazz, slot,
name, returnType, parameterTypes, exceptionTypes, modifiers, signature,
genericInfo, annotations, parameterAnnotations, annotationDefault,
methodAccessor, root);
}
object
makeJconstructor(Thread* t,
uint8_t override,
object securityCheckCache,
object clazz,
uint32_t slot,
object parameterTypes,
object exceptionTypes,
uint32_t modifiers,
object signature,
object genericInfo,
object annotations,
object parameterAnnotations,
object constructorAccessor,
object root,
object declaredAnnotations)
{
return makeJconstructor
(t, override, securityCheckCache, 0, 0, declaredAnnotations, clazz, slot,
parameterTypes, exceptionTypes, modifiers, signature, genericInfo,
annotations, parameterAnnotations, constructorAccessor, root);
}
#endif // HAVE_JexecutableHasRealParameterData
object object
makeJmethod(Thread* t, object vmMethod, int index) makeJmethod(Thread* t, object vmMethod, int index)
{ {
@ -3081,7 +3133,13 @@ EXPORT(JVM_FindLibraryEntry)(void* library, const char* name)
library = t->m->libraries; library = t->m->libraries;
} }
return static_cast<System::Library*>(library)->resolve(name); for (System::Library* lib = t->m->libraries; lib; lib = lib->next()) {
if (library == lib) {
return lib->resolve(name);
}
}
return 0;
} }
extern "C" AVIAN_EXPORT jboolean JNICALL extern "C" AVIAN_EXPORT jboolean JNICALL
@ -3882,6 +3940,14 @@ EXPORT(JVM_DefineClassWithSource)(Thread* t, const char*, jobject loader,
return EXPORT(JVM_DefineClass)(t, 0, loader, data, length, 0); return EXPORT(JVM_DefineClass)(t, 0, loader, data, length, 0);
} }
extern "C" AVIAN_EXPORT jclass JNICALL
EXPORT(JVM_DefineClassWithSourceCond)(Thread* t, const char*, jobject loader,
const uint8_t* data, jsize length,
jobject, const char*, jboolean)
{
return EXPORT(JVM_DefineClass)(t, 0, loader, data, length, 0);
}
extern "C" AVIAN_EXPORT jstring JNICALL extern "C" AVIAN_EXPORT jstring JNICALL
EXPORT(JVM_GetClassName)(Thread* t, jclass c) EXPORT(JVM_GetClassName)(Thread* t, jclass c)
{ {
@ -3972,6 +4038,24 @@ EXPORT(JVM_GetClassSigners)(Thread* t, jclass c)
(t, classRuntimeDataSigners(t, runtimeData)) : 0; (t, classRuntimeDataSigners(t, runtimeData)) : 0;
} }
extern "C" AVIAN_EXPORT jbyteArray JNICALL
EXPORT(JVM_GetClassTypeAnnotations)(Thread*, jclass)
{
abort();
}
extern "C" AVIAN_EXPORT jbyteArray JNICALL
EXPORT(JVM_GetFieldTypeAnnotations)(Thread*, jobject)
{
abort();
}
extern "C" AVIAN_EXPORT jbyteArray JNICALL
EXPORT(JVM_GetMethodTypeAnnotations)(Thread*, jobject)
{
abort();
}
extern "C" AVIAN_EXPORT void JNICALL extern "C" AVIAN_EXPORT void JNICALL
EXPORT(JVM_SetClassSigners)(Thread* t, jclass c, jobjectArray signers) EXPORT(JVM_SetClassSigners)(Thread* t, jclass c, jobjectArray signers)
{ {
@ -4653,6 +4737,9 @@ EXPORT(JVM_GetMethodIxMaxStack)(Thread*, jclass, int) { abort(); }
extern "C" AVIAN_EXPORT jboolean JNICALL extern "C" AVIAN_EXPORT jboolean JNICALL
EXPORT(JVM_IsConstructorIx)(Thread*, jclass, int) { abort(); } EXPORT(JVM_IsConstructorIx)(Thread*, jclass, int) { abort(); }
extern "C" AVIAN_EXPORT jboolean JNICALL
EXPORT(JVM_IsVMGeneratedMethodIx)(Thread*, jclass, int) { abort(); }
extern "C" AVIAN_EXPORT const char* JNICALL extern "C" AVIAN_EXPORT const char* JNICALL
EXPORT(JVM_GetMethodIxNameUTF)(Thread*, jclass, jint) { abort(); } EXPORT(JVM_GetMethodIxNameUTF)(Thread*, jclass, jint) { abort(); }

View File

@ -3296,11 +3296,12 @@ int
methodReferenceReturnCode(Thread* t, object reference) methodReferenceReturnCode(Thread* t, object reference)
{ {
unsigned parameterCount; unsigned parameterCount;
unsigned parameterFootprint;
unsigned returnCode; unsigned returnCode;
scanMethodSpec scanMethodSpec
(t, reinterpret_cast<const char*> (t, reinterpret_cast<const char*>
(&byteArrayBody(t, referenceSpec(t, reference), 0)), &parameterCount, (&byteArrayBody(t, referenceSpec(t, reference), 0)), true,
&returnCode); &parameterCount, &parameterFootprint, &returnCode);
return returnCode; return returnCode;
} }

View File

@ -945,7 +945,7 @@ parsePoolEntry(Thread* t, Stream& s, uint32_t* index, object pool, unsigned i)
unsigned si = s.read2() - 1; unsigned si = s.read2() - 1;
parsePoolEntry(t, s, index, pool, si); parsePoolEntry(t, s, index, pool, si);
object value = makeReference(t, 0, singletonObject(t, pool, si), 0); object value = makeReference(t, 0, 0, singletonObject(t, pool, si), 0);
set(t, pool, SingletonBody + (i * BytesPerWord), value); set(t, pool, SingletonBody + (i * BytesPerWord), value);
if(DebugClassReader) { if(DebugClassReader) {
@ -1004,7 +1004,7 @@ parsePoolEntry(Thread* t, Stream& s, uint32_t* index, object pool, unsigned i)
object nameAndType = singletonObject(t, pool, nti); object nameAndType = singletonObject(t, pool, nti);
object value = makeReference object value = makeReference
(t, class_, pairFirst(t, nameAndType), pairSecond(t, nameAndType)); (t, 0, class_, pairFirst(t, nameAndType), pairSecond(t, nameAndType));
set(t, pool, SingletonBody + (i * BytesPerWord), value); set(t, pool, SingletonBody + (i * BytesPerWord), value);
if(DebugClassReader) { if(DebugClassReader) {
@ -1013,6 +1013,68 @@ parsePoolEntry(Thread* t, Stream& s, uint32_t* index, object pool, unsigned i)
} }
} return 1; } return 1;
case CONSTANT_MethodHandle:
if (singletonObject(t, pool, i) == 0) {
unsigned kind = s.read1();
unsigned ri = s.read2() - 1;
parsePoolEntry(t, s, index, pool, ri);
object value = singletonObject(t, pool, ri);
if (DebugClassReader) {
fprintf(stderr, " consts[%d] = method handle %d %s.%s%s\n", i, kind,
&byteArrayBody(t, referenceClass(t, value), 0),
&byteArrayBody(t, referenceName(t, value), 0),
&byteArrayBody(t, referenceSpec(t, value), 0));
}
value = makeReference
(t, kind, referenceClass(t, value), referenceName(t, value),
referenceSpec(t, value));
set(t, pool, SingletonBody + (i * BytesPerWord), value);
} return 1;
case CONSTANT_MethodType:
if (singletonObject(t, pool, i) == 0) {
unsigned ni = s.read2() - 1;
parsePoolEntry(t, s, index, pool, ni);
set(t, pool, SingletonBody + (i * BytesPerWord),
singletonObject(t, pool, ni));
} return 1;
case CONSTANT_InvokeDynamic:
if (singletonObject(t, pool, i) == 0) {
unsigned bootstrap = s.read2();
unsigned nti = s.read2() - 1;
parsePoolEntry(t, s, index, pool, nti);
object nameAndType = singletonObject(t, pool, nti);
const char* specString = reinterpret_cast<const char*>
(&byteArrayBody(t, pairSecond(t, nameAndType), 0));
unsigned parameterCount;
unsigned parameterFootprint;
unsigned returnCode;
scanMethodSpec
(t, specString, true, &parameterCount, &parameterFootprint,
&returnCode);
object template_ = makeMethod
(t, 0, returnCode, parameterCount, parameterFootprint, 0, 0, 0, 0,
pairFirst(t, nameAndType), pairSecond(t, nameAndType), 0, 0, 0);
object value = makeInvocation
(t, bootstrap, -1, 0, pool, template_, 0);
set(t, pool, SingletonBody + (i * BytesPerWord), value);
} return 1;
default: abort(t); default: abort(t);
} }
} }
@ -1078,6 +1140,21 @@ parsePool(Thread* t, Stream& s)
s.skip(s.read2()); s.skip(s.read2());
break; break;
case CONSTANT_MethodHandle:
singletonMarkObject(t, pool, i);
s.skip(3);
break;
case CONSTANT_MethodType:
singletonMarkObject(t, pool, i);
s.skip(2);
break;
case CONSTANT_InvokeDynamic:
singletonMarkObject(t, pool, i);
s.skip(4);
break;
default: abort(t); default: abort(t);
} }
} }
@ -2066,15 +2143,17 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
(&byteArrayBody(t, singletonObject(t, pool, spec - 1), 0)); (&byteArrayBody(t, singletonObject(t, pool, spec - 1), 0));
unsigned parameterCount; unsigned parameterCount;
unsigned parameterFootprint;
unsigned returnCode; unsigned returnCode;
scanMethodSpec(t, specString, &parameterCount, &returnCode); scanMethodSpec(t, specString, flags & ACC_STATIC, &parameterCount,
&parameterFootprint, &returnCode);
object method = t->m->processor->makeMethod object method = t->m->processor->makeMethod
(t, (t,
0, // vm flags 0, // vm flags
returnCode, returnCode,
parameterCount, parameterCount,
parameterFootprint(t, specString, flags & ACC_STATIC), parameterFootprint,
flags, flags,
0, // offset 0, // offset
singletonObject(t, pool, name - 1), singletonObject(t, pool, name - 1),
@ -5158,6 +5237,10 @@ parseUtf8(Thread* t, object array)
object object
getCaller(Thread* t, unsigned target, bool skipMethodInvoke) getCaller(Thread* t, unsigned target, bool skipMethodInvoke)
{ {
if (static_cast<int>(target) == -1) {
target = 2;
}
class Visitor: public Processor::StackVisitor { class Visitor: public Processor::StackVisitor {
public: public:
Visitor(Thread* t, unsigned target, bool skipMethodInvoke): Visitor(Thread* t, unsigned target, bool skipMethodInvoke):

View File

@ -1061,6 +1061,7 @@ parseType(Finder* finder, Object::ObjectType type, Object* p,
} }
} client; } client;
System::Region* region = finder->find(append(javaName, ".class")); System::Region* region = finder->find(append(javaName, ".class"));
if (region == 0) return 0;
Stream s(&client, region->start(), region->length()); Stream s(&client, region->start(), region->length());
parseJavaClass(t, &s, declarations); parseJavaClass(t, &s, declarations);
region->dispose(); region->dispose();
@ -1109,8 +1110,10 @@ parse(Finder* finder, Input* in)
Object* o; Object* o;
while ((o = read(in, eos, 0)) != eos) { while ((o = read(in, eos, 0)) != eos) {
declarations.append Object* declaration = parseDeclaration(finder, o, declarations.first);
(parseDeclaration(finder, o, declarations.first)); if (declaration) {
declarations.append(declaration);
}
} }
return declarations.first; return declarations.first;

View File

@ -8,6 +8,8 @@
(type jaccessibleObject java/lang/reflect/AccessibleObject) (type jaccessibleObject java/lang/reflect/AccessibleObject)
(type jexecutable java/lang/reflect/Executable)
(type jfield java/lang/reflect/Field) (type jfield java/lang/reflect/Field)
(type jmethod java/lang/reflect/Method) (type jmethod java/lang/reflect/Method)
@ -87,10 +89,19 @@
(array uint8_t body)) (array uint8_t body))
(type reference (type reference
(uint8_t kind)
(object class) (object class)
(object name) (object name)
(object spec)) (object spec))
(type invocation
(uint16_t bootstrap)
(int32_t index)
(object class)
(object pool)
(object template)
(object site))
(type triple (type triple
(object first) (object first)
(object second) (object second)

View File

@ -85,7 +85,13 @@ public class Regex {
expectNoMatch("[a-z&&[^d-f]]", "f"); expectNoMatch("[a-z&&[^d-f]]", "f");
expectSplit("^H", "Hello\nHobbes!", "", "ello\nHobbes!"); expectSplit("^H", "Hello\nHobbes!", "", "ello\nHobbes!");
expectSplit("o.*?$", "Hello\r\nHobbes!", "Hello\r\nH"); expectSplit("o.*?$", "Hello\r\nHobbes!", "Hello\r\nH");
expectSplit("\\b", "a+ b + c\nd", "", "a", "+ ", "b", " + ", "c", "\n", "d"); try {
expectSplit("\\b", "a+ b + c\nd", "", "a", "+ ", "b", " + ", "c", "\n", "d");
} catch (RuntimeException e) {
// Java 8 changed the semantics of split, so if we're on 8, the
// above will fail and this will succeed:
expectSplit("\\b", "a+ b + c\nd", "a", "+ ", "b", " + ", "c", "\n", "d");
}
expectSplit("\\B", "Hi Cal!", "H", "i C", "a", "l!"); expectSplit("\\B", "Hi Cal!", "H", "i C", "a", "l!");
expectMatch("a{2,5}", "aaaa"); expectMatch("a{2,5}", "aaaa");
expectGroups("a??(a{2,5}?)", "aaaa", "aaaa"); expectGroups("a??(a{2,5}?)", "aaaa", "aaaa");

View File

@ -124,22 +124,39 @@ public class Strings {
expect(months.split("\u00ae").length == 3); expect(months.split("\u00ae").length == 3);
expect(months.replaceAll("\u00ae", ".").equals("Jan.Feb.Mar.")); expect(months.replaceAll("\u00ae", ".").equals("Jan.Feb.Mar."));
// Java 8 changed the semantics of String.split relative to
// previous versions, therefore we accept multiple possible
// results:
expect(arraysEqual expect(arraysEqual
("xyz".split("", 0), new String[] { "", "x", "y", "z" })); ("xyz".split("", 0), new String[] { "", "x", "y", "z" })
|| arraysEqual
("xyz".split("", 0), new String[] { "x", "y", "z" }));
expect(arraysEqual expect(arraysEqual
("xyz".split("", 1), new String[] { "xyz" })); ("xyz".split("", 1), new String[] { "xyz" }));
expect(arraysEqual expect(arraysEqual
("xyz".split("", 2), new String[] { "", "xyz" })); ("xyz".split("", 2), new String[] { "", "xyz" })
|| arraysEqual
("xyz".split("", 2), new String[] { "x", "yz" }));
expect(arraysEqual expect(arraysEqual
("xyz".split("", 3), new String[] { "", "x", "yz" })); ("xyz".split("", 3), new String[] { "", "x", "yz" })
|| arraysEqual
("xyz".split("", 3), new String[] { "x", "y", "z" }));
expect(arraysEqual expect(arraysEqual
("xyz".split("", 4), new String[] { "", "x", "y", "z" })); ("xyz".split("", 4), new String[] { "", "x", "y", "z" })
|| arraysEqual
("xyz".split("", 4), new String[] { "x", "y", "z", "" }));
expect(arraysEqual expect(arraysEqual
("xyz".split("", 5), new String[] { "", "x", "y", "z", "" })); ("xyz".split("", 5), new String[] { "", "x", "y", "z", "" })
|| arraysEqual
("xyz".split("", 5), new String[] { "x", "y", "z", "" }));
expect(arraysEqual expect(arraysEqual
("xyz".split("", 6), new String[] { "", "x", "y", "z", "" })); ("xyz".split("", 6), new String[] { "", "x", "y", "z", "" })
|| arraysEqual
("xyz".split("", 6), new String[] { "x", "y", "z", "" }));
expect(arraysEqual expect(arraysEqual
("xyz".split("", -1), new String[] { "", "x", "y", "z", "" })); ("xyz".split("", -1), new String[] { "", "x", "y", "z", "" })
|| arraysEqual
("xyz".split("", -1), new String[] { "x", "y", "z", "" }));
expect(arraysEqual("".split("xyz", 0), new String[] { "" })); expect(arraysEqual("".split("xyz", 0), new String[] { "" }));
expect(arraysEqual("".split("xyz", 1), new String[] { "" })); expect(arraysEqual("".split("xyz", 1), new String[] { "" }));