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

View File

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

View File

@ -233,15 +233,18 @@ enum TypeCode {
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_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_String = 8,
CONSTANT_Utf8 = 1
};

View File

@ -2197,6 +2197,16 @@ stringOffset(Thread*, object)
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
makeString(Thread* t, object data, unsigned offset, unsigned length, unsigned)
{
@ -2476,16 +2486,33 @@ fieldSize(Thread* t, object field)
}
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 count = 0;
unsigned footprint = 0;
MethodSpecIterator it(t, s);
for (; it.hasNext(); it.next()) {
while (it.hasNext()) {
++ count;
switch (*it.next()) {
case 'J':
case 'D':
footprint += 2;
break;
default:
++ footprint;
break;
}
}
if (not static_) {
++ footprint;
}
*parameterCount = count;
*parameterFootprint = footprint;
*returnCode = fieldCode(t, *it.returnSpec());
}

View File

@ -2136,6 +2136,58 @@ countConstructors(Thread* t, object c, bool publicOnly)
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
makeJmethod(Thread* t, object vmMethod, int index)
{
@ -3081,7 +3133,13 @@ EXPORT(JVM_FindLibraryEntry)(void* library, const char* name)
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
@ -3882,6 +3940,14 @@ EXPORT(JVM_DefineClassWithSource)(Thread* t, const char*, jobject loader,
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
EXPORT(JVM_GetClassName)(Thread* t, jclass c)
{
@ -3972,6 +4038,24 @@ EXPORT(JVM_GetClassSigners)(Thread* t, jclass c)
(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
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
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
EXPORT(JVM_GetMethodIxNameUTF)(Thread*, jclass, jint) { abort(); }

View File

@ -3296,11 +3296,12 @@ int
methodReferenceReturnCode(Thread* t, object reference)
{
unsigned parameterCount;
unsigned parameterFootprint;
unsigned returnCode;
scanMethodSpec
(t, reinterpret_cast<const char*>
(&byteArrayBody(t, referenceSpec(t, reference), 0)), &parameterCount,
&returnCode);
(&byteArrayBody(t, referenceSpec(t, reference), 0)), true,
&parameterCount, &parameterFootprint, &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;
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);
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 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);
if(DebugClassReader) {
@ -1013,6 +1013,68 @@ parsePoolEntry(Thread* t, Stream& s, uint32_t* index, object pool, unsigned i)
}
} 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);
}
}
@ -1078,6 +1140,21 @@ parsePool(Thread* t, Stream& s)
s.skip(s.read2());
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);
}
}
@ -2066,15 +2143,17 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
(&byteArrayBody(t, singletonObject(t, pool, spec - 1), 0));
unsigned parameterCount;
unsigned parameterFootprint;
unsigned returnCode;
scanMethodSpec(t, specString, &parameterCount, &returnCode);
scanMethodSpec(t, specString, flags & ACC_STATIC, &parameterCount,
&parameterFootprint, &returnCode);
object method = t->m->processor->makeMethod
(t,
0, // vm flags
returnCode,
parameterCount,
parameterFootprint(t, specString, flags & ACC_STATIC),
parameterFootprint,
flags,
0, // offset
singletonObject(t, pool, name - 1),
@ -5158,6 +5237,10 @@ parseUtf8(Thread* t, object array)
object
getCaller(Thread* t, unsigned target, bool skipMethodInvoke)
{
if (static_cast<int>(target) == -1) {
target = 2;
}
class Visitor: public Processor::StackVisitor {
public:
Visitor(Thread* t, unsigned target, bool skipMethodInvoke):

View File

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

View File

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

View File

@ -85,7 +85,13 @@ public class Regex {
expectNoMatch("[a-z&&[^d-f]]", "f");
expectSplit("^H", "Hello\nHobbes!", "", "ello\nHobbes!");
expectSplit("o.*?$", "Hello\r\nHobbes!", "Hello\r\nH");
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!");
expectMatch("a{2,5}", "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.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
("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
("xyz".split("", 1), new String[] { "xyz" }));
expect(arraysEqual
("xyz".split("", 2), new String[] { "", "xyz" }));
("xyz".split("", 2), new String[] { "", "xyz" })
|| arraysEqual
("xyz".split("", 2), new String[] { "x", "yz" }));
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
("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
("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
("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
("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", 1), new String[] { "" }));