corda/src/avian/machine.h

4074 lines
88 KiB
C
Raw Normal View History

2014-04-20 20:14:48 -06:00
/* Copyright (c) 2008-2014, Avian Contributors
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. */
2007-07-06 17:50:26 -06:00
#ifndef MACHINE_H
#define MACHINE_H
2007-06-24 19:34:07 -06:00
#include "avian/common.h"
#include "java-common.h"
#include <avian/system/system.h>
2014-02-21 17:06:17 -07:00
#include <avian/system/signal.h>
#include <avian/heap/heap.h>
2014-06-02 10:31:57 -06:00
#include <avian/util/slice.h>
#include "avian/finder.h"
#include "avian/processor.h"
#include "avian/constants.h"
#include "avian/arch.h"
2007-06-24 19:34:07 -06:00
using namespace avian::util;
#ifdef PLATFORM_WINDOWS
2007-10-24 11:24:19 -06:00
# define JNICALL __stdcall
#else
# define JNICALL
#endif
2007-06-24 19:34:07 -06:00
#define PROTECT(thread, name) \
Thread::SingleProtector MAKE_NAME(protector_) (thread, &name);
#define ACQUIRE(t, x) MonitorResource MAKE_NAME(monitorResource_) (t, x)
#define ACQUIRE_OBJECT(t, x) \
ObjectMonitorResource MAKE_NAME(monitorResource_) (t, x)
#define ACQUIRE_FIELD_FOR_READ(t, field) \
FieldReadResource MAKE_NAME(monitorResource_) (t, field)
#define ACQUIRE_FIELD_FOR_WRITE(t, field) \
FieldWriteResource MAKE_NAME(monitorResource_) (t, field)
#define ACQUIRE_RAW(t, x) RawMonitorResource MAKE_NAME(monitorResource_) (t, x)
#define ENTER(t, state) StateResource MAKE_NAME(stateResource_) (t, state)
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
#define THREAD_RESOURCE0(t, releaseBody) \
class MAKE_NAME(Resource_): public Thread::AutoResource { \
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
public: \
MAKE_NAME(Resource_)(Thread* t): AutoResource(t) { } \
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
~MAKE_NAME(Resource_)() { releaseBody; } \
virtual void release() \
{ this->MAKE_NAME(Resource_)::~MAKE_NAME(Resource_)(); } \
} MAKE_NAME(resource_)(t);
#define OBJECT_RESOURCE(t, name, releaseBody) \
class MAKE_NAME(Resource_): public Thread::AutoResource { \
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
public: \
MAKE_NAME(Resource_)(Thread* t, object name): \
AutoResource(t), name(name), protector(t, &(this->name)) { } \
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
~MAKE_NAME(Resource_)() { releaseBody; } \
virtual void release() \
{ this->MAKE_NAME(Resource_)::~MAKE_NAME(Resource_)(); } \
\
private: \
object name; \
Thread::SingleProtector protector; \
2014-05-28 22:17:25 -06:00
} MAKE_NAME(resource_)(t, reinterpret_cast<object>(name));
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
#define THREAD_RESOURCE(t, type, name, releaseBody) \
class MAKE_NAME(Resource_): public Thread::AutoResource { \
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
public: \
MAKE_NAME(Resource_)(Thread* t, type name): \
AutoResource(t), name(name) { } \
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
~MAKE_NAME(Resource_)() { releaseBody; } \
virtual void release() \
{ this->MAKE_NAME(Resource_)::~MAKE_NAME(Resource_)(); } \
\
private: \
type name; \
} MAKE_NAME(resource_)(t, name);
#define THREAD_RESOURCE2(t, type1, name1, type2, name2, releaseBody) \
class MAKE_NAME(Resource_): public Thread::AutoResource { \
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
public: \
MAKE_NAME(Resource_)(Thread* t, type1 name1, type2 name2): \
AutoResource(t), name1(name1), name2(name2) { } \
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
~MAKE_NAME(Resource_)() { releaseBody; } \
virtual void release() \
{ this->MAKE_NAME(Resource_)::~MAKE_NAME(Resource_)(); } \
\
private: \
type1 name1; \
type2 name2; \
} MAKE_NAME(resource_)(t, name1, name2);
2007-06-24 20:02:24 -06:00
namespace vm {
const bool Verbose = false;
2007-07-27 17:56:19 -06:00
const bool DebugRun = false;
const bool DebugStack = false;
2007-11-02 15:42:19 -06:00
const bool DebugMonitors = false;
const bool DebugReferences = false;
const bool AbortOnOutOfMemoryError = false;
const uintptr_t HashTakenMark = 1;
const uintptr_t ExtendedMark = 2;
const uintptr_t FixedMark = 3;
const unsigned ThreadHeapSizeInBytes = 64 * 1024;
const unsigned ThreadHeapSizeInWords = ThreadHeapSizeInBytes / BytesPerWord;
const unsigned ThreadBackupHeapSizeInBytes = 2 * 1024;
const unsigned ThreadBackupHeapSizeInWords
= ThreadBackupHeapSizeInBytes / BytesPerWord;
const unsigned ThreadHeapPoolSize = 64;
const unsigned FixedFootprintThresholdInBytes
= ThreadHeapPoolSize * ThreadHeapSizeInBytes;
// number of zombie threads which may accumulate before we force a GC
// to clean them up:
const unsigned ZombieCollectionThreshold = 16;
enum FieldCode {
VoidField,
ByteField,
CharField,
DoubleField,
FloatField,
IntField,
LongField,
ShortField,
BooleanField,
ObjectField
};
enum StackTag {
IntTag, // must be zero
ObjectTag
};
const int NativeLine = -2;
const int UnknownLine = -1;
2009-05-03 14:57:11 -06:00
// class vmFlags:
const unsigned ReferenceFlag = 1 << 0;
const unsigned WeakReferenceFlag = 1 << 1;
2007-07-28 10:10:13 -06:00
const unsigned NeedInitFlag = 1 << 2;
const unsigned InitFlag = 1 << 3;
const unsigned InitErrorFlag = 1 << 4;
const unsigned PrimitiveFlag = 1 << 5;
const unsigned BootstrapFlag = 1 << 6;
const unsigned HasFinalizerFlag = 1 << 7;
const unsigned LinkFlag = 1 << 8;
const unsigned HasFinalMemberFlag = 1 << 9;
const unsigned SingletonFlag = 1 << 10;
const unsigned ContinuationFlag = 1 << 11;
2009-05-03 14:57:11 -06:00
// method vmFlags:
const unsigned ClassInitFlag = 1 << 0;
const unsigned ConstructorFlag = 1 << 1;
2009-06-22 16:25:13 -06:00
#ifndef JNI_VERSION_1_6
#define JNI_VERSION_1_6 0x00010006
#endif
typedef Machine JavaVM;
typedef Thread JNIEnv;
2007-06-24 19:34:07 -06:00
struct JNINativeMethod {
char* name;
char* signature;
void* function;
};
2007-06-24 20:02:24 -06:00
struct JavaVMVTable {
2007-06-24 19:34:07 -06:00
void* reserved0;
void* reserved1;
void* reserved2;
jint
(JNICALL *DestroyJavaVM)
(JavaVM*);
jint
(JNICALL *AttachCurrentThread)
(JavaVM*, JNIEnv**, void*);
2007-06-24 19:34:07 -06:00
jint
(JNICALL *DetachCurrentThread)
(JavaVM*);
jint
(JNICALL *GetEnv)
(JavaVM*, JNIEnv**, jint);
2007-06-24 19:34:07 -06:00
jint
(JNICALL *AttachCurrentThreadAsDaemon)
(JavaVM*, JNIEnv**, void*);
2007-06-24 19:34:07 -06:00
};
2007-06-24 20:02:24 -06:00
struct JNIEnvVTable {
2007-06-24 19:34:07 -06:00
void* reserved0;
void* reserved1;
void* reserved2;
void* reserved3;
jint
(JNICALL *GetVersion)
(JNIEnv*);
jclass
(JNICALL *DefineClass)
(JNIEnv*, const char*, jobject, const jbyte*, jsize);
jclass
(JNICALL *FindClass)
(JNIEnv*, const char*);
jmethodID
(JNICALL *FromReflectedMethod)
(JNIEnv*, jobject);
jfieldID
(JNICALL *FromReflectedField)
(JNIEnv*, jobject);
jobject
(JNICALL *ToReflectedMethod)
(JNIEnv*, jclass, jmethodID, jboolean);
jclass
(JNICALL *GetSuperclass)
(JNIEnv*, jclass);
jboolean
(JNICALL *IsAssignableFrom)
(JNIEnv*, jclass, jclass);
jobject
(JNICALL *ToReflectedField)
(JNIEnv*, jclass, jfieldID, jboolean);
jint
(JNICALL *Throw)
(JNIEnv*, jthrowable);
jint
(JNICALL *ThrowNew)
(JNIEnv*, jclass, const char*);
jthrowable
(JNICALL *ExceptionOccurred)
(JNIEnv*);
void
(JNICALL *ExceptionDescribe)
(JNIEnv*);
void
(JNICALL *ExceptionClear)
(JNIEnv*);
void
(JNICALL *FatalError)
(JNIEnv*, const char*);
jint
(JNICALL *PushLocalFrame)
(JNIEnv*, jint);
jobject
(JNICALL *PopLocalFrame)
(JNIEnv*, jobject);
jobject
(JNICALL *NewGlobalRef)
(JNIEnv*, jobject);
void
(JNICALL *DeleteGlobalRef)
(JNIEnv*, jobject);
void
(JNICALL *DeleteLocalRef)
(JNIEnv*, jobject);
jboolean
(JNICALL *IsSameObject)
(JNIEnv*, jobject, jobject);
jobject
(JNICALL *NewLocalRef)
(JNIEnv*, jobject);
jint
(JNICALL *EnsureLocalCapacity)
(JNIEnv*, jint);
jobject
(JNICALL *AllocObject)
(JNIEnv*, jclass);
jobject
(JNICALL *NewObject)
(JNIEnv*, jclass, jmethodID, ...);
jobject
(JNICALL *NewObjectV)
(JNIEnv*, jclass, jmethodID, va_list);
jobject
(JNICALL *NewObjectA)
(JNIEnv*, jclass, jmethodID, const jvalue*);
jclass
(JNICALL *GetObjectClass)
(JNIEnv*, jobject);
jboolean
(JNICALL *IsInstanceOf)
(JNIEnv*, jobject, jclass);
jmethodID
(JNICALL *GetMethodID)
(JNIEnv*, jclass, const char*, const char*);
jobject
(JNICALL *CallObjectMethod)
(JNIEnv*, jobject, jmethodID, ...);
jobject
(JNICALL *CallObjectMethodV)
(JNIEnv*, jobject, jmethodID, va_list);
jobject
(JNICALL *CallObjectMethodA)
(JNIEnv*, jobject, jmethodID, const jvalue*);
jboolean
(JNICALL *CallBooleanMethod)
(JNIEnv*, jobject, jmethodID, ...);
jboolean
(JNICALL *CallBooleanMethodV)
(JNIEnv*, jobject, jmethodID, va_list);
jboolean
(JNICALL *CallBooleanMethodA)
(JNIEnv*, jobject, jmethodID, const jvalue*);
jbyte
(JNICALL *CallByteMethod)
(JNIEnv*, jobject, jmethodID, ...);
jbyte
(JNICALL *CallByteMethodV)
(JNIEnv*, jobject, jmethodID, va_list);
jbyte
(JNICALL *CallByteMethodA)
(JNIEnv*, jobject, jmethodID, const jvalue*);
jchar
(JNICALL *CallCharMethod)
(JNIEnv*, jobject, jmethodID, ...);
jchar
(JNICALL *CallCharMethodV)
(JNIEnv*, jobject, jmethodID, va_list);
jchar
(JNICALL *CallCharMethodA)
(JNIEnv*, jobject, jmethodID, const jvalue*);
jshort
(JNICALL *CallShortMethod)
(JNIEnv*, jobject, jmethodID, ...);
jshort
(JNICALL *CallShortMethodV)
(JNIEnv*, jobject, jmethodID, va_list);
jshort
(JNICALL *CallShortMethodA)
(JNIEnv*, jobject, jmethodID, const jvalue*);
jint
(JNICALL *CallIntMethod)
(JNIEnv*, jobject, jmethodID, ...);
jint
(JNICALL *CallIntMethodV)
(JNIEnv*, jobject, jmethodID, va_list);
jint
(JNICALL *CallIntMethodA)
(JNIEnv*, jobject, jmethodID, const jvalue*);
jlong
(JNICALL *CallLongMethod)
(JNIEnv*, jobject, jmethodID, ...);
jlong
(JNICALL *CallLongMethodV)
(JNIEnv*, jobject, jmethodID, va_list);
jlong
(JNICALL *CallLongMethodA)
(JNIEnv*, jobject, jmethodID, const jvalue*);
jfloat
(JNICALL *CallFloatMethod)
(JNIEnv*, jobject, jmethodID, ...);
jfloat
(JNICALL *CallFloatMethodV)
(JNIEnv*, jobject, jmethodID, va_list);
jfloat
(JNICALL *CallFloatMethodA)
(JNIEnv*, jobject, jmethodID, const jvalue*);
jdouble
(JNICALL *CallDoubleMethod)
(JNIEnv*, jobject, jmethodID, ...);
jdouble
(JNICALL *CallDoubleMethodV)
(JNIEnv*, jobject, jmethodID, va_list);
jdouble
(JNICALL *CallDoubleMethodA)
(JNIEnv*, jobject, jmethodID, const jvalue*);
void
(JNICALL *CallVoidMethod)
(JNIEnv*, jobject, jmethodID, ...);
void
(JNICALL *CallVoidMethodV)
(JNIEnv*, jobject, jmethodID, va_list);
void
(JNICALL *CallVoidMethodA)
(JNIEnv*, jobject, jmethodID, const jvalue*);
jobject
(JNICALL *CallNonvirtualObjectMethod)
(JNIEnv*, jobject, jclass, jmethodID, ...);
jobject
(JNICALL *CallNonvirtualObjectMethodV)
(JNIEnv*, jobject, jclass, jmethodID, va_list);
jobject
(JNICALL *CallNonvirtualObjectMethodA)
(JNIEnv*, jobject, jclass, jmethodID, const jvalue*);
jboolean
(JNICALL *CallNonvirtualBooleanMethod)
(JNIEnv*, jobject, jclass, jmethodID, ...);
jboolean
(JNICALL *CallNonvirtualBooleanMethodV)
(JNIEnv*, jobject, jclass, jmethodID, va_list);
jboolean
(JNICALL *CallNonvirtualBooleanMethodA)
(JNIEnv*, jobject, jclass, jmethodID, const jvalue*);
jbyte
(JNICALL *CallNonvirtualByteMethod)
(JNIEnv*, jobject, jclass, jmethodID, ...);
jbyte
(JNICALL *CallNonvirtualByteMethodV)
(JNIEnv*, jobject, jclass, jmethodID, va_list);
jbyte
(JNICALL *CallNonvirtualByteMethodA)
(JNIEnv*, jobject, jclass, jmethodID, const jvalue*);
jchar
(JNICALL *CallNonvirtualCharMethod)
(JNIEnv*, jobject, jclass, jmethodID, ...);
jchar
(JNICALL *CallNonvirtualCharMethodV)
(JNIEnv*, jobject, jclass, jmethodID, va_list);
jchar
(JNICALL *CallNonvirtualCharMethodA)
(JNIEnv*, jobject, jclass, jmethodID, const jvalue*);
jshort
(JNICALL *CallNonvirtualShortMethod)
(JNIEnv*, jobject, jclass, jmethodID, ...);
jshort
(JNICALL *CallNonvirtualShortMethodV)
(JNIEnv*, jobject, jclass, jmethodID,
va_list);
jshort
(JNICALL *CallNonvirtualShortMethodA)
(JNIEnv*, jobject, jclass, jmethodID,
const jvalue*);
jint
(JNICALL *CallNonvirtualIntMethod)
(JNIEnv*, jobject, jclass, jmethodID, ...);
jint
(JNICALL *CallNonvirtualIntMethodV)
(JNIEnv*, jobject, jclass, jmethodID,
va_list);
jint
(JNICALL *CallNonvirtualIntMethodA)
(JNIEnv*, jobject, jclass, jmethodID,
const jvalue*);
jlong
(JNICALL *CallNonvirtualLongMethod)
(JNIEnv*, jobject, jclass, jmethodID, ...);
jlong
(JNICALL *CallNonvirtualLongMethodV)
(JNIEnv*, jobject, jclass, jmethodID,
va_list);
jlong
(JNICALL *CallNonvirtualLongMethodA)
(JNIEnv*, jobject, jclass, jmethodID, const jvalue*);
jfloat
(JNICALL *CallNonvirtualFloatMethod)
(JNIEnv*, jobject, jclass, jmethodID, ...);
jfloat
(JNICALL *CallNonvirtualFloatMethodV)
(JNIEnv*, jobject, jclass, jmethodID, va_list);
jfloat
(JNICALL *CallNonvirtualFloatMethodA)
(JNIEnv*, jobject, jclass, jmethodID, const jvalue*);
jdouble
(JNICALL *CallNonvirtualDoubleMethod)
(JNIEnv*, jobject, jclass, jmethodID, ...);
jdouble
(JNICALL *CallNonvirtualDoubleMethodV)
(JNIEnv*, jobject, jclass, jmethodID, va_list);
jdouble
(JNICALL *CallNonvirtualDoubleMethodA)
(JNIEnv*, jobject, jclass, jmethodID, const jvalue*);
void
(JNICALL *CallNonvirtualVoidMethod)
(JNIEnv*, jobject, jclass, jmethodID, ...);
void
(JNICALL *CallNonvirtualVoidMethodV)
(JNIEnv*, jobject, jclass, jmethodID, va_list);
void
(JNICALL *CallNonvirtualVoidMethodA)
(JNIEnv*, jobject, jclass, jmethodID, const jvalue*);
jfieldID
(JNICALL *GetFieldID)
(JNIEnv*, jclass, const char*, const char*);
jobject
(JNICALL *GetObjectField)
(JNIEnv*, jobject, jfieldID);
jboolean
(JNICALL *GetBooleanField)
(JNIEnv*, jobject, jfieldID);
jbyte
(JNICALL *GetByteField)
(JNIEnv*, jobject, jfieldID);
jchar
(JNICALL *GetCharField)
(JNIEnv*, jobject, jfieldID);
jshort
(JNICALL *GetShortField)
(JNIEnv*, jobject, jfieldID);
jint
(JNICALL *GetIntField)
(JNIEnv*, jobject, jfieldID);
jlong
(JNICALL *GetLongField)
(JNIEnv*, jobject, jfieldID);
jfloat
(JNICALL *GetFloatField)
(JNIEnv*, jobject, jfieldID);
jdouble
(JNICALL *GetDoubleField)
(JNIEnv*, jobject, jfieldID);
void
(JNICALL *SetObjectField)
(JNIEnv*, jobject, jfieldID, jobject);
void
(JNICALL *SetBooleanField)
(JNIEnv*, jobject, jfieldID, jboolean);
void
(JNICALL *SetByteField)
(JNIEnv*, jobject, jfieldID, jbyte);
void
(JNICALL *SetCharField)
(JNIEnv*, jobject, jfieldID, jchar);
void
(JNICALL *SetShortField)
(JNIEnv*, jobject, jfieldID, jshort);
void
(JNICALL *SetIntField)
(JNIEnv*, jobject, jfieldID, jint);
void
(JNICALL *SetLongField)
(JNIEnv*, jobject, jfieldID, jlong);
void
(JNICALL *SetFloatField)
(JNIEnv*, jobject, jfieldID, jfloat);
void
(JNICALL *SetDoubleField)
(JNIEnv*, jobject, jfieldID, jdouble);
jmethodID
(JNICALL *GetStaticMethodID)
(JNIEnv*, jclass, const char*, const char*);
jobject
(JNICALL *CallStaticObjectMethod)
(JNIEnv*, jclass, jmethodID, ...);
jobject
(JNICALL *CallStaticObjectMethodV)
(JNIEnv*, jclass, jmethodID, va_list);
jobject
(JNICALL *CallStaticObjectMethodA)
(JNIEnv*, jclass, jmethodID, const jvalue*);
jboolean
(JNICALL *CallStaticBooleanMethod)
(JNIEnv*, jclass, jmethodID, ...);
jboolean
(JNICALL *CallStaticBooleanMethodV)
(JNIEnv*, jclass, jmethodID, va_list);
jboolean
(JNICALL *CallStaticBooleanMethodA)
(JNIEnv*, jclass, jmethodID, const jvalue*);
jbyte
(JNICALL *CallStaticByteMethod)
(JNIEnv*, jclass, jmethodID, ...);
jbyte
(JNICALL *CallStaticByteMethodV)
(JNIEnv*, jclass, jmethodID, va_list);
jbyte
(JNICALL *CallStaticByteMethodA)
(JNIEnv*, jclass, jmethodID, const jvalue*);
jchar
(JNICALL *CallStaticCharMethod)
(JNIEnv*, jclass, jmethodID, ...);
jchar
(JNICALL *CallStaticCharMethodV)
(JNIEnv*, jclass, jmethodID, va_list);
jchar
(JNICALL *CallStaticCharMethodA)
(JNIEnv*, jclass, jmethodID, const jvalue*);
jshort
(JNICALL *CallStaticShortMethod)
(JNIEnv*, jclass, jmethodID, ...);
jshort
(JNICALL *CallStaticShortMethodV)
(JNIEnv*, jclass, jmethodID, va_list);
jshort
(JNICALL *CallStaticShortMethodA)
(JNIEnv*, jclass, jmethodID, const jvalue*);
jint
(JNICALL *CallStaticIntMethod)
(JNIEnv*, jclass, jmethodID, ...);
jint
(JNICALL *CallStaticIntMethodV)
(JNIEnv*, jclass, jmethodID, va_list);
jint
(JNICALL *CallStaticIntMethodA)
(JNIEnv*, jclass, jmethodID, const jvalue*);
jlong
(JNICALL *CallStaticLongMethod)
(JNIEnv*, jclass, jmethodID, ...);
jlong
(JNICALL *CallStaticLongMethodV)
(JNIEnv*, jclass, jmethodID, va_list);
jlong
(JNICALL *CallStaticLongMethodA)
(JNIEnv*, jclass, jmethodID, const jvalue*);
jfloat
(JNICALL *CallStaticFloatMethod)
(JNIEnv*, jclass, jmethodID, ...);
jfloat
(JNICALL *CallStaticFloatMethodV)
(JNIEnv*, jclass, jmethodID, va_list);
jfloat
(JNICALL *CallStaticFloatMethodA)
(JNIEnv*, jclass, jmethodID, const jvalue*);
jdouble
(JNICALL *CallStaticDoubleMethod)
(JNIEnv*, jclass, jmethodID, ...);
jdouble
(JNICALL *CallStaticDoubleMethodV)
(JNIEnv*, jclass, jmethodID, va_list);
jdouble
(JNICALL *CallStaticDoubleMethodA)
(JNIEnv*, jclass, jmethodID, const jvalue*);
void
(JNICALL *CallStaticVoidMethod)
(JNIEnv*, jclass, jmethodID, ...);
void
(JNICALL *CallStaticVoidMethodV)
(JNIEnv*, jclass, jmethodID, va_list);
void
(JNICALL *CallStaticVoidMethodA)
(JNIEnv*, jclass, jmethodID, const jvalue*);
jfieldID
(JNICALL *GetStaticFieldID)
(JNIEnv*, jclass, const char*, const char*);
jobject
(JNICALL *GetStaticObjectField)
(JNIEnv*, jclass, jfieldID);
jboolean
(JNICALL *GetStaticBooleanField)
(JNIEnv*, jclass, jfieldID);
jbyte
(JNICALL *GetStaticByteField)
(JNIEnv*, jclass, jfieldID);
jchar
(JNICALL *GetStaticCharField)
(JNIEnv*, jclass, jfieldID);
jshort
(JNICALL *GetStaticShortField)
(JNIEnv*, jclass, jfieldID);
jint
(JNICALL *GetStaticIntField)
(JNIEnv*, jclass, jfieldID);
jlong
(JNICALL *GetStaticLongField)
(JNIEnv*, jclass, jfieldID);
jfloat
(JNICALL *GetStaticFloatField)
(JNIEnv*, jclass, jfieldID);
jdouble
(JNICALL *GetStaticDoubleField)
(JNIEnv*, jclass, jfieldID);
void
(JNICALL *SetStaticObjectField)
(JNIEnv*, jclass, jfieldID, jobject);
void
(JNICALL *SetStaticBooleanField)
(JNIEnv*, jclass, jfieldID, jboolean);
void
(JNICALL *SetStaticByteField)
(JNIEnv*, jclass, jfieldID, jbyte);
void
(JNICALL *SetStaticCharField)
(JNIEnv*, jclass, jfieldID, jchar);
void
(JNICALL *SetStaticShortField)
(JNIEnv*, jclass, jfieldID, jshort);
void
(JNICALL *SetStaticIntField)
(JNIEnv*, jclass, jfieldID, jint);
void
(JNICALL *SetStaticLongField)
(JNIEnv*, jclass, jfieldID, jlong);
void
(JNICALL *SetStaticFloatField)
(JNIEnv*, jclass, jfieldID, jfloat);
void
(JNICALL *SetStaticDoubleField)
(JNIEnv*, jclass, jfieldID, jdouble);
jstring
(JNICALL *NewString)
(JNIEnv*, const jchar*, jsize);
jsize
(JNICALL *GetStringLength)
(JNIEnv*, jstring);
const jchar*
(JNICALL *GetStringChars)
(JNIEnv*, jstring, jboolean*);
void
(JNICALL *ReleaseStringChars)
(JNIEnv*, jstring, const jchar*);
jstring
(JNICALL *NewStringUTF)
(JNIEnv*, const char*);
jsize
(JNICALL *GetStringUTFLength)
(JNIEnv*, jstring);
const char*
(JNICALL *GetStringUTFChars)
(JNIEnv*, jstring, jboolean*);
void
(JNICALL *ReleaseStringUTFChars)
(JNIEnv*, jstring, const char*);
jsize
(JNICALL *GetArrayLength)
(JNIEnv*, jarray);
jobjectArray
(JNICALL *NewObjectArray)
(JNIEnv*, jsize, jclass, jobject);
jobject
(JNICALL *GetObjectArrayElement)
(JNIEnv*, jobjectArray, jsize);
void
(JNICALL *SetObjectArrayElement)
(JNIEnv*, jobjectArray, jsize, jobject);
jbooleanArray
(JNICALL *NewBooleanArray)
(JNIEnv*, jsize);
jbyteArray
(JNICALL *NewByteArray)
(JNIEnv*, jsize);
jcharArray
(JNICALL *NewCharArray)
(JNIEnv*, jsize);
jshortArray
(JNICALL *NewShortArray)
(JNIEnv*, jsize);
jintArray
(JNICALL *NewIntArray)
(JNIEnv*, jsize);
jlongArray
(JNICALL *NewLongArray)
(JNIEnv*, jsize);
jfloatArray
(JNICALL *NewFloatArray)
(JNIEnv*, jsize);
jdoubleArray
(JNICALL *NewDoubleArray)
(JNIEnv*, jsize);
jboolean*
(JNICALL *GetBooleanArrayElements)
(JNIEnv*, jbooleanArray, jboolean*);
jbyte*
(JNICALL *GetByteArrayElements)
(JNIEnv*, jbyteArray, jboolean*);
jchar*
(JNICALL *GetCharArrayElements)
(JNIEnv*, jcharArray, jboolean*);
jshort*
(JNICALL *GetShortArrayElements)
(JNIEnv*, jshortArray, jboolean*);
jint*
(JNICALL *GetIntArrayElements)
(JNIEnv*, jintArray, jboolean*);
jlong*
(JNICALL *GetLongArrayElements)
(JNIEnv*, jlongArray, jboolean*);
jfloat*
(JNICALL *GetFloatArrayElements)
(JNIEnv*, jfloatArray, jboolean*);
jdouble*
(JNICALL *GetDoubleArrayElements)
(JNIEnv*, jdoubleArray, jboolean*);
void
(JNICALL *ReleaseBooleanArrayElements)
(JNIEnv*, jbooleanArray, jboolean*, jint);
void
(JNICALL *ReleaseByteArrayElements)
(JNIEnv*, jbyteArray, jbyte*, jint);
void
(JNICALL *ReleaseCharArrayElements)
(JNIEnv*, jcharArray, jchar*, jint);
void
(JNICALL *ReleaseShortArrayElements)
(JNIEnv*, jshortArray, jshort*, jint);
void
(JNICALL *ReleaseIntArrayElements)
(JNIEnv*, jintArray, jint*, jint);
void
(JNICALL *ReleaseLongArrayElements)
(JNIEnv*, jlongArray, jlong*, jint);
void
(JNICALL *ReleaseFloatArrayElements)
(JNIEnv*, jfloatArray, jfloat*, jint);
void
(JNICALL *ReleaseDoubleArrayElements)
(JNIEnv*, jdoubleArray, jdouble*, jint);
void
(JNICALL *GetBooleanArrayRegion)
(JNIEnv*, jbooleanArray, jsize, jsize, jboolean*);
void
(JNICALL *GetByteArrayRegion)
(JNIEnv*, jbyteArray, jsize, jsize, jbyte*);
void
(JNICALL *GetCharArrayRegion)
(JNIEnv*, jcharArray, jsize, jsize, jchar*);
void
(JNICALL *GetShortArrayRegion)
(JNIEnv*, jshortArray, jsize, jsize, jshort*);
void
(JNICALL *GetIntArrayRegion)
(JNIEnv*, jintArray, jsize, jsize, jint*);
void
(JNICALL *GetLongArrayRegion)
(JNIEnv*, jlongArray, jsize, jsize, jlong*);
void
(JNICALL *GetFloatArrayRegion)
(JNIEnv*, jfloatArray, jsize, jsize, jfloat*);
void
(JNICALL *GetDoubleArrayRegion)
(JNIEnv*, jdoubleArray, jsize, jsize, jdouble*);
void
(JNICALL *SetBooleanArrayRegion)
(JNIEnv*, jbooleanArray, jsize, jsize, const jboolean*);
void
(JNICALL *SetByteArrayRegion)
(JNIEnv*, jbyteArray, jsize, jsize, const jbyte*);
void
(JNICALL *SetCharArrayRegion)
(JNIEnv*, jcharArray, jsize, jsize, const jchar*);
void
(JNICALL *SetShortArrayRegion)
(JNIEnv*, jshortArray, jsize, jsize, const jshort*);
void
(JNICALL *SetIntArrayRegion)
(JNIEnv*, jintArray, jsize, jsize, const jint*);
void
(JNICALL *SetLongArrayRegion)
(JNIEnv*, jlongArray, jsize, jsize, const jlong*);
void
(JNICALL *SetFloatArrayRegion)
(JNIEnv*, jfloatArray, jsize, jsize, const jfloat*);
void
(JNICALL *SetDoubleArrayRegion)
(JNIEnv*, jdoubleArray, jsize, jsize, const jdouble*);
jint
(JNICALL *RegisterNatives)
(JNIEnv*, jclass, const JNINativeMethod*, jint);
jint
(JNICALL *UnregisterNatives)
(JNIEnv*, jclass);
jint
(JNICALL *MonitorEnter)
(JNIEnv*, jobject);
jint
(JNICALL *MonitorExit)
(JNIEnv*, jobject);
jint
(JNICALL *GetJavaVM)
(JNIEnv*, JavaVM**);
void
(JNICALL *GetStringRegion)
(JNIEnv*, jstring, jsize, jsize, jchar*);
void
(JNICALL *GetStringUTFRegion)
(JNIEnv*, jstring, jsize, jsize, char*);
void*
(JNICALL *GetPrimitiveArrayCritical)
(JNIEnv*, jarray, jboolean*);
void
(JNICALL *ReleasePrimitiveArrayCritical)
(JNIEnv*, jarray, void*, jint);
const jchar*
(JNICALL *GetStringCritical)
(JNIEnv*, jstring, jboolean*);
void
(JNICALL *ReleaseStringCritical)
(JNIEnv*, jstring, const jchar*);
jweak
(JNICALL *NewWeakGlobalRef)
(JNIEnv*, jobject);
void
(JNICALL *DeleteWeakGlobalRef)
(JNIEnv*, jweak);
jboolean
(JNICALL *ExceptionCheck)
(JNIEnv*);
jobject
(JNICALL *NewDirectByteBuffer)
(JNIEnv*, void*, jlong);
void*
(JNICALL *GetDirectBufferAddress)
(JNIEnv* env, jobject);
jlong
(JNICALL *GetDirectBufferCapacity)
(JNIEnv*, jobject);
2008-06-15 14:17:52 -06:00
2007-06-24 19:34:07 -06:00
};
inline void
atomicOr(uint32_t* p, int v)
{
for (uint32_t old = *p;
not atomicCompareAndSwap32(p, old, old | v);
old = *p)
{ }
}
inline void
atomicAnd(uint32_t* p, int v)
{
for (uint32_t old = *p;
not atomicCompareAndSwap32(p, old, old & v);
old = *p)
{ }
}
inline int
strcmp(const int8_t* a, const int8_t* b)
{
return ::strcmp(reinterpret_cast<const char*>(a),
reinterpret_cast<const char*>(b));
}
void
noop();
2007-09-07 17:20:21 -06:00
class Reference {
public:
Reference(object target, Reference** handle, bool weak):
2007-09-07 17:20:21 -06:00
target(target),
next(*handle),
handle(handle),
count(0),
weak(weak)
{
if (next) {
next->handle = &next;
}
*handle = this;
}
2007-09-07 17:20:21 -06:00
object target;
Reference* next;
Reference** handle;
unsigned count;
bool weak;
2007-09-07 17:20:21 -06:00
};
class Classpath;
2014-05-28 22:17:25 -06:00
class Gc {
public:
2007-09-12 21:15:16 -06:00
enum Type {
#include "type-enums.cpp"
2007-09-12 21:15:16 -06:00
};
2014-05-28 22:17:25 -06:00
};
class GcObject {
public:
template <class T>
T* as(Thread* t);
template <class T>
bool isa(Thread* t);
protected:
template <class T>
T& field_at(size_t offset)
{
return *reinterpret_cast<T*>(reinterpret_cast<uint8_t*>(this) + offset);
}
};
class GcFinalizer;
class GcClassLoader;
2014-05-28 22:17:25 -06:00
class Machine {
public:
enum AllocationType {
MovableAllocation,
FixedAllocation,
ImmortalAllocation
};
enum Root {
BootLoader,
AppLoader,
BootstrapClassMap,
PackageMap,
FindLoadedClassMethod,
LoadClassMethod,
MonitorMap,
StringMap,
ByteArrayMap,
PoolMap,
ClassRuntimeDataTable,
MethodRuntimeDataTable,
JNIMethodTable,
JNIFieldTable,
ShutdownHooks,
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
FinalizerThread,
ObjectsToFinalize,
ObjectsToClean,
NullPointerException,
ArithmeticException,
ArrayIndexOutOfBoundsException,
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
OutOfMemoryError,
Shutdown,
VirtualFileFinders,
2013-02-21 15:37:17 -07:00
VirtualFiles,
ArrayInterfaceTable,
ThreadTerminated
};
static const unsigned RootCount = ThreadTerminated + 1;
Machine(System* system, Heap* heap, Finder* bootFinder, Finder* appFinder,
Processor* processor, Classpath* classpath, const char** properties,
unsigned propertyCount, const char** arguments,
2012-03-14 12:36:42 -06:00
unsigned argumentCount, unsigned stackSizeInBytes);
2014-05-28 22:17:25 -06:00
~Machine() {
dispose();
}
void dispose();
JavaVMVTable* vtable;
System* system;
Heap::Client* heapClient;
Heap* heap;
Finder* bootFinder;
Finder* appFinder;
Processor* processor;
Classpath* classpath;
Thread* rootThread;
Thread* exclusive;
Thread* finalizeThread;
2007-09-07 17:20:21 -06:00
Reference* jniReferences;
char** properties;
unsigned propertyCount;
const char** arguments;
unsigned argumentCount;
unsigned threadCount;
unsigned activeCount;
unsigned liveCount;
unsigned daemonCount;
unsigned fixedFootprint;
2012-03-14 12:36:42 -06:00
unsigned stackSizeInBytes;
System::Local* localThread;
System::Monitor* stateLock;
System::Monitor* heapLock;
System::Monitor* classLock;
System::Monitor* referenceLock;
System::Monitor* shutdownLock;
System::Library* libraries;
FILE* errorLog;
BootImage* bootimage;
object types;
object roots;
2014-05-28 22:17:25 -06:00
GcFinalizer* finalizers;
GcFinalizer* tenuredFinalizers;
object finalizeQueue;
object weakReferences;
object tenuredWeakReferences;
bool unsafe;
bool collecting;
bool triedBuiltinOnLoad;
bool dumpedHeapOnOOM;
bool alive;
JavaVMVTable javaVMVTable;
JNIEnvVTable jniEnvVTable;
uintptr_t* heapPool[ThreadHeapPoolSize];
unsigned heapPoolIndex;
unsigned bootimageSize;
};
2007-07-28 15:28:25 -06:00
void
printTrace(Thread* t, object exception);
uint8_t&
threadInterrupted(Thread* t, object thread);
void
enterActiveState(Thread* t);
#ifdef VM_STRESS
inline void stress(Thread* t);
#else // not VM_STRESS
#define stress(t)
#endif // not VM_STRESS
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
uint64_t
runThread(Thread*, uintptr_t*);
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
uint64_t
run(Thread* t, uint64_t (*function)(Thread*, uintptr_t*),
uintptr_t* arguments);
void
checkDaemon(Thread* t);
object&
root(Thread* t, Machine::Root root);
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
extern "C" uint64_t
vmRun(uint64_t (*function)(Thread*, uintptr_t*), uintptr_t* arguments,
void* checkpoint);
extern "C" void
vmRun_returnAddress();
class Thread {
public:
enum State {
NoState,
ActiveState,
IdleState,
ZombieState,
2007-07-17 19:33:00 -06:00
JoinedState,
ExclusiveState,
ExitState
};
static const unsigned UseBackupHeapFlag = 1 << 0;
static const unsigned WaitingFlag = 1 << 1;
static const unsigned TracingFlag = 1 << 2;
static const unsigned DaemonFlag = 1 << 3;
static const unsigned StressFlag = 1 << 4;
static const unsigned ActiveFlag = 1 << 5;
static const unsigned SystemFlag = 1 << 6;
static const unsigned JoinFlag = 1 << 7;
class Protector {
public:
Protector(Thread* t): t(t), next(t->protector) {
t->protector = this;
}
~Protector() {
t->protector = next;
}
virtual void visit(Heap::Visitor* v) = 0;
Thread* t;
Protector* next;
};
class SingleProtector: public Protector {
public:
2014-05-28 22:17:25 -06:00
SingleProtector(Thread* t, void* p): Protector(t), p(p) { }
virtual void visit(Heap::Visitor* v) {
v->visit(p);
}
2014-05-28 22:17:25 -06:00
void* p;
};
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
class Resource {
public:
Resource(Thread* t, Resource* next): t(t), next(next) {
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
t->resource = this;
}
virtual void release() = 0;
Thread* t;
Resource* next;
};
class AutoResource: public Resource {
public:
AutoResource(Thread* t): Resource(t, t->resource) { }
~AutoResource() {
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
t->resource = next;
}
virtual void release() = 0;
};
class ClassInitStack: public AutoResource {
public:
2014-05-28 22:17:25 -06:00
ClassInitStack(Thread* t, GcClass* class_):
AutoResource(t),
next(t->classInitStack),
class_(class_),
protector(t, &(this->class_))
{
t->classInitStack = this;
}
~ClassInitStack() {
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
t->classInitStack = next;
}
virtual void release() {
this->ClassInitStack::~ClassInitStack();
}
ClassInitStack* next;
2014-05-28 22:17:25 -06:00
GcClass* class_;
SingleProtector protector;
};
class LibraryLoadStack: public AutoResource {
public:
LibraryLoadStack(Thread* t, GcClassLoader* classLoader)
: AutoResource(t),
next(t->libraryLoadStack),
classLoader(classLoader),
protector(t, &(this->classLoader))
{
t->libraryLoadStack = this;
}
~LibraryLoadStack() {
t->libraryLoadStack = next;
}
virtual void release() {
this->LibraryLoadStack::~LibraryLoadStack();
}
LibraryLoadStack* next;
GcClassLoader* classLoader;
SingleProtector protector;
};
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
class Checkpoint {
public:
Checkpoint(Thread* t):
t(t),
next(t->checkpoint),
resource(t->resource),
protector(t->protector),
noThrow(false)
{
t->checkpoint = this;
}
~Checkpoint() {
t->checkpoint = next;
}
virtual void NO_RETURN unwind() = 0;
Thread* t;
Checkpoint* next;
Resource* resource;
Protector* protector;
bool noThrow;
};
class RunCheckpoint: public Checkpoint {
public:
RunCheckpoint(Thread* t):
Checkpoint(t),
support stack unwinding without using a frame pointer Previously, we unwound the stack by following the chain of frame pointers for normal returns, stack trace creation, and exception unwinding. On x86, this required reserving EBP/RBP for frame pointer duties, making it unavailable for general computation and requiring that it be explicitly saved and restored on entry and exit, respectively. On PowerPC, we use an ABI that makes the stack pointer double as a frame pointer, so it doesn't cost us anything. We've been using the same convention on ARM, but it doesn't match the native calling convention, which makes it unusable when we want to call native code from Java and pass arguments on the stack. So far, the ARM calling convention mismatch hasn't been an issue because we've never passed more arguments from Java to native code than would fit in registers. However, we must now pass an extra argument (the thread pointer) to e.g. divideLong so it can throw an exception on divide by zero, which means the last argument must be passed on the stack. This will clobber the linkage area we've been using to hold the frame pointer, so we need to stop using it. One solution would be to use the same convention on ARM as we do on x86, but this would introduce the same overhead of making a register unavailable for general use and extra code at method entry and exit. Instead, this commit removes the need for a frame pointer. Unwinding involves consulting a map of instruction offsets to frame sizes which is generated at compile time. This is necessary because stack trace creation can happen at any time due to Thread.getStackTrace being called by another thread, and the frame size varies during the execution of a method. So far, only x86(_64) is working, and continuations and tail call optimization are probably broken. More to come.
2011-01-16 19:05:05 -07:00
stack(0)
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
{ }
virtual void unwind() {
void* stack = this->stack;
this->stack = 0;
expect(t->m->system, stack);
vmJump(voidPointer(vmRun_returnAddress), 0, stack, t, 0, 0);
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
}
void* stack;
};
2007-07-28 15:28:25 -06:00
class Runnable: public System::Runnable {
public:
Runnable(Thread* t): t(t) { }
virtual void attach(System::Thread* st) {
t->systemThread = st;
}
virtual void run() {
enterActiveState(t);
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
vm::run(t, runThread, 0);
if (t->exception and t->exception != root(t, Machine::Shutdown)) {
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
printTrace(t, t->exception);
2007-07-28 15:28:25 -06:00
}
t->exit();
}
virtual bool interrupted() {
return t->javaThread and threadInterrupted(t, t->javaThread);
2007-07-28 15:28:25 -06:00
}
virtual void setInterrupted(bool v) {
threadInterrupted(t, t->javaThread) = v;
}
Thread* t;
};
2007-07-23 19:44:20 -06:00
Thread(Machine* m, object javaThread, Thread* parent);
void init();
2007-07-07 12:09:16 -06:00
void exit();
void dispose();
JNIEnvVTable* vtable;
Machine* m;
2007-07-07 12:09:16 -06:00
Thread* parent;
Thread* peer;
Thread* child;
Thread* waitNext;
State state;
2007-09-07 17:20:21 -06:00
unsigned criticalLevel;
2007-07-07 12:09:16 -06:00
System::Thread* systemThread;
System::Monitor* lock;
2007-07-07 12:09:16 -06:00
object javaThread;
object exception;
unsigned heapIndex;
unsigned heapOffset;
Protector* protector;
ClassInitStack* classInitStack;
LibraryLoadStack* libraryLoadStack;
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
Resource* resource;
Checkpoint* checkpoint;
2007-07-28 15:28:25 -06:00
Runnable runnable;
uintptr_t* defaultHeap;
2007-09-12 21:15:16 -06:00
uintptr_t* heap;
uintptr_t backupHeap[ThreadBackupHeapSizeInWords];
2008-04-09 13:08:13 -06:00
unsigned backupHeapIndex;
unsigned flags;
};
class Classpath {
public:
virtual object
2014-05-28 22:17:25 -06:00
makeJclass(Thread* t, GcClass* class_) = 0;
virtual object
makeString(Thread* t, object array, int32_t offset, int32_t length) = 0;
virtual object
makeThread(Thread* t, Thread* parent) = 0;
virtual object
2014-05-28 22:17:25 -06:00
makeJMethod(Thread* t, GcMethod* vmMethod) = 0;
virtual object
getVMMethod(Thread* t, object jmethod) = 0;
virtual object
makeJField(Thread* t, object vmField) = 0;
virtual object
getVMField(Thread* t, object jfield) = 0;
virtual void
clearInterrupted(Thread* t) = 0;
virtual void
runThread(Thread* t) = 0;
virtual void
2014-05-28 22:17:25 -06:00
resolveNative(Thread* t, GcMethod* method) = 0;
virtual void
interceptMethods(Thread* t) = 0;
2013-02-22 14:41:24 -07:00
virtual void
preBoot(Thread* t) = 0;
virtual bool mayInitClasses() = 0;
virtual void
boot(Thread* t) = 0;
virtual const char*
bootClasspath() = 0;
2013-02-21 15:37:17 -07:00
virtual object
makeDirectByteBuffer(Thread* t, void* p, jlong capacity) = 0;
virtual void*
getDirectBufferAddress(Thread* t, object buffer) = 0;
virtual int64_t
getDirectBufferCapacity(Thread* t, object buffer) = 0;
virtual bool
2014-05-28 22:17:25 -06:00
canTailCall(Thread* t, GcMethod* caller, object calleeClassName,
object calleeMethodName, object calleeMethodSpec) = 0;
virtual GcClassLoader* libraryClassLoader(Thread* t, GcMethod* caller) = 0;
virtual void
shutDown(Thread* t) = 0;
virtual void
dispose() = 0;
};
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
#ifdef _MSC_VER
template <class T>
class ThreadRuntimeArray: public Thread::AutoResource {
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
public:
2011-02-02 08:15:07 -07:00
ThreadRuntimeArray(Thread* t, unsigned size):
AutoResource(t),
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
body(static_cast<T*>(t->m->heap->allocate(size * sizeof(T)))),
size(size)
{ }
2011-02-02 08:15:07 -07:00
~ThreadRuntimeArray() {
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
t->m->heap->free(body, size * sizeof(T));
}
virtual void release() {
2011-02-02 08:15:07 -07:00
ThreadRuntimeArray::~ThreadRuntimeArray();
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
}
T* body;
unsigned size;
};
# define THREAD_RUNTIME_ARRAY(thread, type, name, size) \
2011-02-02 08:15:07 -07:00
ThreadRuntimeArray<type> name(thread, size);
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
#else // not _MSC_VER
# define THREAD_RUNTIME_ARRAY(thread, type, name, size) \
type name##_body[size];
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
#endif // not _MSC_VER
Classpath*
makeClasspath(System* system, Allocator* allocator, const char* javaHome,
const char* embedPrefix);
2014-05-28 22:17:25 -06:00
typedef uint64_t (JNICALL *FastNativeFunction)(Thread*, GcMethod*, uintptr_t*);
2009-05-03 14:57:11 -06:00
2014-05-28 22:17:25 -06:00
inline GcClass*
objectClass(Thread*, object o)
{
2014-05-28 22:17:25 -06:00
return reinterpret_cast<GcClass*>(maskAlignedPointer(fieldAtOffset<object>(o, 0)));
}
inline GcClass*
objectClass(Thread*, GcObject* o)
{
return reinterpret_cast<GcClass*>(maskAlignedPointer(fieldAtOffset<object>(o, 0)));
}
2012-03-14 12:36:42 -06:00
inline unsigned
stackSizeInWords(Thread* t)
{
return t->m->stackSizeInBytes / BytesPerWord;
}
void
enter(Thread* t, Thread::State state);
inline void
enterActiveState(Thread* t)
{
enter(t, Thread::ActiveState);
}
class StateResource: public Thread::AutoResource {
public:
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
StateResource(Thread* t, Thread::State state):
AutoResource(t), oldState(t->state)
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
{
enter(t, state);
}
~StateResource() { enter(t, oldState); }
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
virtual void release() {
this->StateResource::~StateResource();
}
private:
Thread::State oldState;
};
inline void
dispose(Thread* t, Reference* r)
{
*(r->handle) = r->next;
if (r->next) {
r->next->handle = r->handle;
}
2008-04-13 12:15:04 -06:00
t->m->heap->free(r, sizeof(*r));
}
inline void
acquire(Thread*, Reference* r)
{
++ r->count;
}
inline void
release(Thread* t, Reference* r)
{
if ((-- r->count) == 0) {
dispose(t, r);
}
}
void
collect(Thread* t, Heap::CollectionType type, int pendingAllocation = 0);
void
shutDown(Thread* t);
#ifdef VM_STRESS
inline void
stress(Thread* t)
{
2010-12-09 22:17:57 -07:00
if ((not t->m->unsafe)
and (t->flags & (Thread::StressFlag | Thread::TracingFlag)) == 0
2007-07-16 18:23:23 -06:00
and t->state != Thread::NoState
and t->state != Thread::IdleState)
{
atomicOr(&(t->flags), Thread::StressFlag);
# ifdef VM_STRESS_MAJOR
collect(t, Heap::MajorCollection);
# else // not VM_STRESS_MAJOR
collect(t, Heap::MinorCollection);
# endif // not VM_STRESS_MAJOR
atomicAnd(&(t->flags), ~Thread::StressFlag);
}
}
#endif // not VM_STRESS
inline void
acquire(Thread* t, System::Monitor* m)
{
if (not m->tryAcquire(t->systemThread)) {
ENTER(t, Thread::IdleState);
m->acquire(t->systemThread);
}
stress(t);
}
inline void
release(Thread* t, System::Monitor* m)
{
m->release(t->systemThread);
}
class MonitorResource: public Thread::AutoResource {
public:
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
MonitorResource(Thread* t, System::Monitor* m):
AutoResource(t), m(m)
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
{
acquire(t, m);
}
~MonitorResource() {
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
vm::release(t, m);
}
virtual void release() {
this->MonitorResource::~MonitorResource();
}
private:
System::Monitor* m;
};
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
class RawMonitorResource: public Thread::Resource {
public:
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
RawMonitorResource(Thread* t, System::Monitor* m):
Resource(t, t->resource), m(m)
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
{
2007-08-13 18:37:00 -06:00
m->acquire(t->systemThread);
}
~RawMonitorResource() {
t->resource = next;
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
vm::release(t, m);
}
virtual void release() {
this->RawMonitorResource::~RawMonitorResource();
}
private:
System::Monitor* m;
};
inline Aborter* getAborter(Thread* t) {
return t->m->system;
}
inline bool
2008-04-09 13:08:13 -06:00
ensure(Thread* t, unsigned sizeInBytes)
{
2013-02-10 18:06:15 -07:00
if (t->heapIndex + ceilingDivide(sizeInBytes, BytesPerWord)
> ThreadHeapSizeInWords)
2008-04-09 13:08:13 -06:00
{
if (sizeInBytes <= ThreadBackupHeapSizeInBytes) {
expect(t, (t->flags & Thread::UseBackupHeapFlag) == 0);
atomicOr(&(t->flags), Thread::UseBackupHeapFlag);
return true;
} else {
return false;
}
} else {
return true;
2008-04-09 13:08:13 -06:00
}
}
2007-10-27 19:54:30 -06:00
object
allocate2(Thread* t, unsigned sizeInBytes, bool objectMask);
object
allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
2008-04-13 12:15:04 -06:00
unsigned sizeInBytes, bool objectMask);
inline object
allocateSmall(Thread* t, unsigned sizeInBytes)
{
assertT(t, t->heapIndex + ceilingDivide(sizeInBytes, BytesPerWord)
<= ThreadHeapSizeInWords);
object o = reinterpret_cast<object>(t->heap + t->heapIndex);
2013-02-10 18:06:15 -07:00
t->heapIndex += ceilingDivide(sizeInBytes, BytesPerWord);
return o;
}
inline object
2007-10-27 19:54:30 -06:00
allocate(Thread* t, unsigned sizeInBytes, bool objectMask)
{
stress(t);
2013-02-10 18:06:15 -07:00
if (UNLIKELY(t->heapIndex + ceilingDivide(sizeInBytes, BytesPerWord)
> ThreadHeapSizeInWords
or t->m->exclusive))
{
return allocate2(t, sizeInBytes, objectMask);
} else {
assertT(t, t->criticalLevel == 0);
return allocateSmall(t, sizeInBytes);
}
}
inline void
mark(Thread* t, object o, unsigned offset, unsigned count)
{
t->m->heap->mark(o, offset / BytesPerWord, count);
}
inline void
mark(Thread* t, object o, unsigned offset)
{
t->m->heap->mark(o, offset / BytesPerWord, 1);
}
2007-10-27 19:54:30 -06:00
2008-07-05 14:21:13 -06:00
inline void
set(Thread* t, object target, unsigned offset, object value)
{
2013-02-10 17:38:51 -07:00
fieldAtOffset<object>(target, offset) = value;
mark(t, target, offset);
}
2014-06-28 14:41:27 -06:00
inline void
set(Thread* t, GcObject* target, unsigned offset, GcObject* value)
{
fieldAtOffset<GcObject*>(target, offset) = value;
mark(t, reinterpret_cast<object>(target), offset);
}
inline void
setObject(Thread* t, GcObject* target, unsigned offset, GcObject* value)
{
set(t, target, offset, value);
}
inline void
2014-05-28 22:17:25 -06:00
setObjectClass(Thread*, object o, GcClass* c)
{
2013-02-10 17:38:51 -07:00
fieldAtOffset<object>(o, 0)
= reinterpret_cast<object>
2014-05-28 22:17:25 -06:00
(reinterpret_cast<intptr_alias_t>(c)
| (reinterpret_cast<intptr_alias_t>
2013-02-10 17:38:51 -07:00
(fieldAtOffset<object>(o, 0)) & (~PointerMask)));
}
inline const char*
findProperty(Machine* m, const char* name)
{
for (unsigned i = 0; i < m->propertyCount; ++i) {
const char* p = m->properties[i];
const char* n = name;
while (*p and *p != '=' and *n and *p == *n) {
++ p;
++ n;
}
if (*p == '=' and *n == 0) {
return p + 1;
}
}
return 0;
}
inline const char*
findProperty(Thread* t, const char* name)
{
return findProperty(t->m, name);
}
object&
arrayBodyUnsafe(Thread*, object, unsigned);
bool
2014-05-28 22:17:25 -06:00
instanceOf(Thread* t, GcClass* class_, object o);
template <class T>
T* GcObject::as(Thread* t UNUSED)
{
assertT(t,
2014-05-28 22:17:25 -06:00
t->m->unsafe
|| instanceOf(t, reinterpret_cast<GcClass*>(arrayBodyUnsafe(t, t->m->types, T::Type)), reinterpret_cast<object>(this)));
return static_cast<T*>(this);
}
template <class T>
bool GcObject::isa(Thread* t)
{
return instanceOf(t, reinterpret_cast<GcClass*>(arrayBodyUnsafe(t, t->m->types, T::Type)), reinterpret_cast<object>(this));
}
template <class T>
T* cast(Thread* t UNUSED, object o)
{
if(o == 0) {
return 0;
}
assertT(t,
2014-05-28 22:17:25 -06:00
t->m->unsafe || instanceOf(t,
reinterpret_cast<GcClass*>(arrayBodyUnsafe(
t, t->m->types, T::Type)),
o));
return reinterpret_cast<T*>(o);
}
#include "type-declarations.cpp"
inline object&
arrayBodyUnsafe(Thread*, object a, unsigned index)
{
return reinterpret_cast<GcArray*>(a)->body()[index];
}
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
inline uint64_t
runRaw(Thread* t,
uint64_t (*function)(Thread*, uintptr_t*), uintptr_t* arguments)
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
{
Thread::RunCheckpoint checkpoint(t);
return vmRun(function, arguments, &checkpoint);
}
inline uint64_t
run(Thread* t, uint64_t (*function)(Thread*, uintptr_t*), uintptr_t* arguments)
{
ENTER(t, Thread::ActiveState);
return runRaw(t, function, arguments);
}
inline void
runJavaThread(Thread* t)
{
t->m->classpath->runThread(t);
}
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
void
runFinalizeThread(Thread* t);
inline uint64_t
runThread(Thread* t, uintptr_t*)
{
t->m->localThread->set(t);
checkDaemon(t);
if (t == t->m->finalizeThread) {
runFinalizeThread(t);
} else if (t->javaThread) {
runJavaThread(t);
}
return 1;
}
inline bool
startThread(Thread* t, Thread* p)
{
p->flags |= Thread::JoinFlag;
return t->m->system->success(t->m->system->start(&(p->runnable)));
}
inline void
addThread(Thread* t, Thread* p)
{
ACQUIRE_RAW(t, t->m->stateLock);
assertT(t, p->state == Thread::NoState);
expect(t, t->state == Thread::ActiveState || t->state == Thread::ExclusiveState || t->state == Thread::NoState);
p->state = Thread::IdleState;
++ t->m->threadCount;
++ t->m->liveCount;
p->peer = p->parent->child;
p->parent->child = p;
if (p->javaThread) {
threadPeer(t, p->javaThread) = reinterpret_cast<jlong>(p);
}
}
inline void
removeThread(Thread* t, Thread* p)
{
ACQUIRE_RAW(t, t->m->stateLock);
assertT(t, p->state == Thread::IdleState);
-- t->m->liveCount;
-- t->m->threadCount;
t->m->stateLock->notifyAll(t->systemThread);
p->parent->child = p->peer;
if (p->javaThread) {
threadPeer(t, p->javaThread) = 0;
}
p->dispose();
}
inline Thread*
startThread(Thread* t, GcThread* javaThread)
{
{ PROTECT(t, javaThread);
2014-05-28 22:17:25 -06:00
stress(t);
ACQUIRE_RAW(t, t->m->stateLock);
2014-05-28 22:17:25 -06:00
if (t->m->threadCount > t->m->liveCount + ZombieCollectionThreshold) {
collect(t, Heap::MinorCollection);
}
}
Thread* p = t->m->processor->makeThread(t->m, javaThread, t);
addThread(t, p);
if (startThread(t, p)) {
return p;
} else {
removeThread(t, p);
return 0;
}
}
inline void
registerDaemon(Thread* t)
{
ACQUIRE_RAW(t, t->m->stateLock);
atomicOr(&(t->flags), Thread::DaemonFlag);
++ t->m->daemonCount;
2014-05-28 22:17:25 -06:00
t->m->stateLock->notifyAll(t->systemThread);
}
inline void
checkDaemon(Thread* t)
{
if (threadDaemon(t, t->javaThread)) {
registerDaemon(t);
}
}
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
inline uint64_t
initAttachedThread(Thread* t, uintptr_t* arguments)
{
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
bool daemon = arguments[0];
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
t->javaThread = t->m->classpath->makeThread(t, t->m->rootThread);
threadPeer(t, t->javaThread) = reinterpret_cast<jlong>(t);
if (daemon) {
threadDaemon(t, t->javaThread) = true;
registerDaemon(t);
}
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
t->m->localThread->set(t);
return 1;
}
inline Thread*
attachThread(Machine* m, bool daemon)
{
Thread* t = m->processor->makeThread(m, 0, m->rootThread);
m->system->attach(&(t->runnable));
addThread(t, t);
enter(t, Thread::ActiveState);
uintptr_t arguments[] = { daemon };
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
if (run(t, initAttachedThread, arguments)) {
enter(t, Thread::IdleState);
return t;
} else {
t->exit();
return 0;
}
}
inline object&
root(Thread* t, Machine::Root root)
{
return arrayBody(t, t->m->roots, root);
}
inline void
setRoot(Thread* t, Machine::Root root, object value)
{
set(t, t->m->roots, ArrayBody + (root * BytesPerWord), value);
}
2014-05-28 22:17:25 -06:00
inline GcClass*
type(Thread* t, Gc::Type type)
{
2014-05-28 22:17:25 -06:00
return cast<GcClass>(t, arrayBody(t, t->m->types, type));
}
inline void
2014-05-28 22:17:25 -06:00
setType(Thread* t, Gc::Type type, GcClass* value)
{
2014-05-28 22:17:25 -06:00
set(t, t->m->types, ArrayBody + (type * BytesPerWord), reinterpret_cast<object>(value));
}
inline bool
objectFixed(Thread*, object o)
{
return (alias(o, 0) & (~PointerMask)) == FixedMark;
}
inline bool
objectExtended(Thread*, object o)
{
return (alias(o, 0) & (~PointerMask)) == ExtendedMark;
}
inline bool
hashTaken(Thread*, object o)
{
return (alias(o, 0) & (~PointerMask)) == HashTakenMark;
}
inline unsigned
2014-05-28 22:17:25 -06:00
baseSize(Thread* t UNUSED, object o, GcClass* class_)
{
assertT(t, class_->fixedSize() >= BytesPerWord);
2014-05-28 22:17:25 -06:00
return ceilingDivide(class_->fixedSize(), BytesPerWord)
+ ceilingDivide(class_->arrayElementSize()
* fieldAtOffset<uintptr_t>(o, class_->fixedSize() - BytesPerWord),
BytesPerWord);
}
object
makeTrace(Thread* t, Processor::StackWalker* walker);
object
2008-04-09 13:08:13 -06:00
makeTrace(Thread* t, Thread* target);
inline object
makeTrace(Thread* t)
{
return makeTrace(t, t);
}
2008-07-05 14:21:13 -06:00
inline object
2014-05-28 22:17:25 -06:00
makeNew(Thread* t, GcClass* class_)
{
assertT(t, t->state == Thread::NoState or t->state == Thread::ActiveState);
PROTECT(t, class_);
2014-05-28 22:17:25 -06:00
unsigned sizeInBytes = pad(class_->fixedSize());
assertT(t, sizeInBytes);
2014-05-28 22:17:25 -06:00
object instance = allocate(t, sizeInBytes, class_->objectMask());
2007-10-27 19:54:30 -06:00
setObjectClass(t, instance, class_);
return instance;
}
object
2014-05-28 22:17:25 -06:00
makeNewGeneral(Thread* t, GcClass* class_);
inline object
2014-05-28 22:17:25 -06:00
make(Thread* t, GcClass* class_)
{
2014-05-28 22:17:25 -06:00
if (UNLIKELY(class_->vmFlags()
& (WeakReferenceFlag | HasFinalizerFlag)))
{
return makeNewGeneral(t, class_);
} else {
return makeNew(t, class_);
}
}
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
object
makeByteArrayV(Thread* t, const char* format, va_list a, int size);
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
object
makeByteArray(Thread* t, const char* format, ...);
object
makeString(Thread* t, const char* format, ...);
#ifndef HAVE_StringOffset
inline unsigned
stringLength(Thread* t, object string)
{
return charArrayLength(t, stringData(t, string));
}
inline unsigned
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)
{
if (offset == 0 and length == charArrayLength(t, data)) {
2014-05-28 22:17:25 -06:00
return reinterpret_cast<object>(makeString(t, data, 0, 0));
} else {
PROTECT(t, data);
2014-05-28 22:17:25 -06:00
object array = reinterpret_cast<object>(makeCharArray(t, length));
memcpy(&charArrayBody(t, array, 0), &charArrayBody(t, data, offset),
length * 2);
2014-05-28 22:17:25 -06:00
return reinterpret_cast<object>(makeString(t, array, 0, 0));
}
}
#endif // not HAVE_StringOffset
int
stringUTFLength(Thread* t, object string, unsigned start, unsigned length);
inline int
stringUTFLength(Thread* t, object string)
{
return stringUTFLength(t, string, 0, stringLength(t, string));
}
void
stringChars(Thread* t, object string, unsigned start, unsigned length,
char* chars);
inline void
stringChars(Thread* t, object string, char* chars)
{
stringChars(t, string, 0, stringLength(t, string), chars);
}
void
stringChars(Thread* t, object string, unsigned start, unsigned length,
uint16_t* chars);
inline void
stringChars(Thread* t, object string, uint16_t* chars)
{
stringChars(t, string, 0, stringLength(t, string), chars);
}
void
stringUTFChars(Thread* t, object string, unsigned start, unsigned length,
char* chars, unsigned charsLength);
inline void
stringUTFChars(Thread* t, object string, char* chars, unsigned charsLength)
{
2014-05-28 22:17:25 -06:00
stringUTFChars(t, string, 0, stringLength(t, string), chars, charsLength);
}
2007-07-23 19:44:20 -06:00
bool
2014-05-28 22:17:25 -06:00
isAssignableFrom(Thread* t, GcClass* a, GcClass* b);
2007-07-23 19:44:20 -06:00
2007-07-28 10:10:13 -06:00
object
2014-05-28 22:17:25 -06:00
classInitializer(Thread* t, GcClass* class_);
2007-07-28 10:10:13 -06:00
object
frameMethod(Thread* t, int frame);
inline uintptr_t&
extendedWord(Thread* t UNUSED, object o, unsigned baseSize)
{
assertT(t, objectExtended(t, o));
2013-02-10 17:38:51 -07:00
return fieldAtOffset<uintptr_t>(o, baseSize * BytesPerWord);
}
inline unsigned
extendedSize(Thread* t, object o, unsigned baseSize)
{
return baseSize + objectExtended(t, o);
}
inline void
markHashTaken(Thread* t, object o)
{
assertT(t, not objectExtended(t, o));
assertT(t, not objectFixed(t, o));
ACQUIRE_RAW(t, t->m->heapLock);
2007-10-27 19:54:30 -06:00
alias(o, 0) |= HashTakenMark;
t->m->heap->pad(o);
}
inline uint32_t
takeHash(Thread*, object o)
{
// some broken code implicitly relies on System.identityHashCode
// always returning a non-negative number (e.g. old versions of
// com/sun/xml/bind/v2/util/CollisionCheckStack.hash), hence the "&
// 0x7FFFFFFF":
return (reinterpret_cast<uintptr_t>(o) / BytesPerWord) & 0x7FFFFFFF;
}
inline uint32_t
objectHash(Thread* t, object o)
{
if (objectExtended(t, o)) {
return extendedWord(t, o, baseSize(t, o, objectClass(t, o)));
} else {
if (not objectFixed(t, o)) {
markHashTaken(t, o);
}
return takeHash(t, o);
}
}
inline bool
objectEqual(Thread*, object a, object b)
{
return a == b;
}
inline uint32_t
byteArrayHash(Thread* t, object array)
{
return hash(&byteArrayBody(t, array, 0), byteArrayLength(t, array));
}
2007-07-28 18:02:32 -06:00
inline uint32_t
charArrayHash(Thread* t, object array)
{
return hash(&charArrayBody(t, array, 0), charArrayLength(t, array));
}
inline bool
byteArrayEqual(Thread* t, object a, object b)
{
return a == b or
((byteArrayLength(t, a) == byteArrayLength(t, b)) and
memcmp(&byteArrayBody(t, a, 0), &byteArrayBody(t, b, 0),
byteArrayLength(t, a)) == 0);
}
2007-07-28 18:02:32 -06:00
inline uint32_t
stringHash(Thread* t, object s)
{
2007-08-19 14:24:26 -06:00
if (stringHashCode(t, s) == 0 and stringLength(t, s)) {
object data = reinterpret_cast<object>(stringData(t, s));
2014-05-28 22:17:25 -06:00
if (objectClass(t, data) == type(t, GcByteArray::Type)) {
2007-08-14 19:14:55 -06:00
stringHashCode(t, s) = hash
(&byteArrayBody(t, data, stringOffset(t, s)), stringLength(t, s));
2007-07-28 18:02:32 -06:00
} else {
2007-08-14 19:14:55 -06:00
stringHashCode(t, s) = hash
(&charArrayBody(t, data, stringOffset(t, s)), stringLength(t, s));
2007-07-28 18:02:32 -06:00
}
}
return stringHashCode(t, s);
}
inline uint16_t
stringCharAt(Thread* t, object s, int i)
{
object data = reinterpret_cast<object>(stringData(t, s));
2014-05-28 22:17:25 -06:00
if (objectClass(t, data) == type(t, GcByteArray::Type)) {
2009-06-06 16:36:07 -06:00
return byteArrayBody(t, data, stringOffset(t, s) + i);
2007-07-28 18:02:32 -06:00
} else {
2009-06-06 16:36:07 -06:00
return charArrayBody(t, data, stringOffset(t, s) + i);
2007-07-28 18:02:32 -06:00
}
}
inline bool
stringEqual(Thread* t, object a, object b)
{
if (a == b) {
return true;
} else if (stringLength(t, a) == stringLength(t, b)) {
for (unsigned i = 0; i < stringLength(t, a); ++i) {
2007-07-28 18:02:32 -06:00
if (stringCharAt(t, a, i) != stringCharAt(t, b, i)) {
return false;
}
}
return true;
} else {
return false;
}
}
inline uint32_t
2014-05-28 22:17:25 -06:00
methodHash(Thread* t, object mo)
{
2014-05-28 22:17:25 -06:00
GcMethod* method = cast<GcMethod>(t, mo);
return byteArrayHash(t, reinterpret_cast<object>(method->name()))
^ byteArrayHash(t, reinterpret_cast<object>(method->spec()));
}
inline bool
2014-05-28 22:17:25 -06:00
methodEqual(Thread* t, object ao, object bo)
{
2014-05-28 22:17:25 -06:00
GcMethod* a = cast<GcMethod>(t, ao);
GcMethod* b = cast<GcMethod>(t, bo);
return a == b or
(byteArrayEqual(t, reinterpret_cast<object>(a->name()), reinterpret_cast<object>(b->name())) and
byteArrayEqual(t, reinterpret_cast<object>(a->spec()), reinterpret_cast<object>(b->spec())));
}
class MethodSpecIterator {
public:
MethodSpecIterator(Thread* t, const char* s):
t(t), s(s + 1)
{ }
const char* next() {
assertT(t, *s != ')');
const char* p = s;
switch (*s) {
case 'L':
while (*s and *s != ';') ++ s;
++ s;
break;
case '[':
while (*s == '[') ++ s;
switch (*s) {
case 'L':
while (*s and *s != ';') ++ s;
++ s;
break;
default:
++ s;
break;
}
break;
2014-05-28 22:17:25 -06:00
default:
++ s;
break;
}
2014-05-28 22:17:25 -06:00
return p;
}
bool hasNext() {
return *s != ')';
}
const char* returnSpec() {
assertT(t, *s == ')');
return s + 1;
}
Thread* t;
const char* s;
};
unsigned
fieldCode(Thread* t, unsigned javaCode);
unsigned
fieldType(Thread* t, unsigned code);
unsigned
primitiveSize(Thread* t, unsigned code);
inline unsigned
2007-11-02 15:08:14 -06:00
fieldSize(Thread* t, unsigned code)
{
if (code == ObjectField) {
return BytesPerWord;
} else {
return primitiveSize(t, code);
}
}
2007-11-02 15:08:14 -06:00
inline unsigned
fieldSize(Thread* t, object field)
{
return fieldSize(t, fieldCode(t, field));
}
inline void
scanMethodSpec(Thread* t, const char* s, bool static_,
unsigned* parameterCount, unsigned* parameterFootprint,
unsigned* returnCode)
{
unsigned count = 0;
unsigned footprint = 0;
MethodSpecIterator it(t, s);
while (it.hasNext()) {
++ count;
switch (*it.next()) {
case 'J':
case 'D':
footprint += 2;
break;
default:
++ footprint;
2014-05-28 22:17:25 -06:00
break;
}
}
if (not static_) {
++ footprint;
}
*parameterCount = count;
*parameterFootprint = footprint;
*returnCode = fieldCode(t, *it.returnSpec());
}
2014-05-28 22:17:25 -06:00
GcClass*
2014-06-28 15:11:31 -06:00
findLoadedClass(Thread* t, GcClassLoader* loader, object spec);
2007-07-30 17:19:05 -06:00
inline bool
2014-06-27 22:00:05 -06:00
emptyMethod(Thread* t UNUSED, GcMethod* method)
{
2014-05-28 22:17:25 -06:00
return ((method->flags() & ACC_NATIVE) == 0)
2014-06-27 22:00:05 -06:00
and (method->code()->length() == 1)
and (method->code()->body()[0] == return_);
}
object
parseUtf8(Thread* t, const char* data, unsigned length);
object
parseUtf8(Thread* t, object array);
2014-05-28 22:17:25 -06:00
GcClass*
2014-06-28 15:11:31 -06:00
parseClass(Thread* t, GcClassLoader* loader, const uint8_t* data, unsigned length,
2014-05-28 22:17:25 -06:00
Gc::Type throwType = GcNoClassDefFoundError::Type);
2007-07-30 17:19:05 -06:00
2014-05-28 22:17:25 -06:00
GcClass*
2014-06-28 15:11:31 -06:00
resolveClass(Thread* t, GcClassLoader* loader, object name, bool throw_ = true,
2014-05-28 22:17:25 -06:00
Gc::Type throwType = GcNoClassDefFoundError::Type);
2014-05-28 22:17:25 -06:00
inline GcClass*
2014-06-28 15:11:31 -06:00
resolveClass(Thread* t, GcClassLoader* loader, const char* name, bool throw_ = true,
2014-05-28 22:17:25 -06:00
Gc::Type throwType = GcNoClassDefFoundError::Type)
{
PROTECT(t, loader);
object n = makeByteArray(t, "%s", name);
return resolveClass(t, loader, n, throw_, throwType);
}
2014-05-28 22:17:25 -06:00
GcClass*
resolveSystemClass
2014-06-28 15:11:31 -06:00
(Thread* t, GcClassLoader* loader, object name, bool throw_ = true,
2014-05-28 22:17:25 -06:00
Gc::Type throwType = GcNoClassDefFoundError::Type);
2014-05-28 22:17:25 -06:00
inline GcClass*
2014-06-28 15:11:31 -06:00
resolveSystemClass(Thread* t, GcClassLoader* loader, const char* name)
{
return resolveSystemClass(t, loader, makeByteArray(t, "%s", name));
}
void
2014-06-28 15:11:31 -06:00
linkClass(Thread* t, GcClassLoader* loader, GcClass* class_);
2014-05-28 22:17:25 -06:00
GcMethod*
resolveMethod(Thread* t, GcClass* class_, const char* methodName,
const char* methodSpec);
2014-05-28 22:17:25 -06:00
inline GcMethod*
2014-06-28 15:11:31 -06:00
resolveMethod(Thread* t, GcClassLoader* loader, const char* className,
const char* methodName, const char* methodSpec)
{
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
return resolveMethod
(t, resolveClass(t, loader, className), methodName, methodSpec);
}
object
2014-05-28 22:17:25 -06:00
resolveField(Thread* t, GcClass* class_, const char* fieldName,
const char* fieldSpec);
inline object
2014-06-28 15:11:31 -06:00
resolveField(Thread* t, GcClassLoader* loader, const char* className,
const char* fieldName, const char* fieldSpec)
{
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
return resolveField
(t, resolveClass(t, loader, className), fieldName, fieldSpec);
}
bool
2014-05-28 22:17:25 -06:00
classNeedsInit(Thread* t, GcClass* c);
bool
2014-05-28 22:17:25 -06:00
preInitClass(Thread* t, GcClass* c);
void
2014-05-28 22:17:25 -06:00
postInitClass(Thread* t, GcClass* c);
void
2014-05-28 22:17:25 -06:00
initClass(Thread* t, GcClass* c);
2014-05-28 22:17:25 -06:00
GcClass*
2014-06-28 15:11:31 -06:00
resolveObjectArrayClass(Thread* t, GcClassLoader* loader, object elementClass);
object
2014-05-28 22:17:25 -06:00
makeObjectArray(Thread* t, GcClass* elementClass, unsigned count);
inline object
makeObjectArray(Thread* t, unsigned count)
{
2014-05-28 22:17:25 -06:00
return makeObjectArray(t, type(t, GcJobject::Type), count);
}
object
2014-05-28 22:17:25 -06:00
findFieldInClass(Thread* t, GcClass* class_, object name, object spec);
inline object
2014-05-28 22:17:25 -06:00
findFieldInClass2(Thread* t, GcClass* class_, const char* name, const char* spec)
{
PROTECT(t, class_);
object n = makeByteArray(t, "%s", name);
PROTECT(t, n);
object s = makeByteArray(t, "%s", spec);
return findFieldInClass(t, class_, n, s);
}
object
2014-05-28 22:17:25 -06:00
findMethodInClass(Thread* t, GcClass* class_, object name, object spec);
inline object
makeThrowable
2014-05-28 22:17:25 -06:00
(Thread* t, Gc::Type type, object message = 0, object trace = 0,
object cause = 0)
{
PROTECT(t, message);
PROTECT(t, trace);
PROTECT(t, cause);
2014-05-28 22:17:25 -06:00
if (trace == 0) {
trace = makeTrace(t);
}
object result = make(t, vm::type(t, type));
2014-05-28 22:17:25 -06:00
set(t, result, ThrowableMessage, message);
set(t, result, ThrowableTrace, trace);
set(t, result, ThrowableCause, cause);
return result;
}
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
inline object
2014-05-28 22:17:25 -06:00
makeThrowableV(Thread* t, Gc::Type type, const char* format, va_list a,
int size)
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
{
object s = makeByteArrayV(t, format, a, size);
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
if (s) {
object message = t->m->classpath->makeString
(t, s, 0, byteArrayLength(t, s) - 1);
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
return makeThrowable(t, type, message);
} else {
return 0;
}
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
}
inline object
2014-05-28 22:17:25 -06:00
makeThrowable(Thread* t, Gc::Type type, const char* format, ...)
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
{
int size = 256;
while (true) {
va_list a;
va_start(a, format);
object r = makeThrowableV(t, type, format, a, size);
va_end(a);
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
if (r) {
return r;
} else {
size *= 2;
}
}
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
}
2011-01-27 11:54:41 -07:00
void
popResources(Thread* t);
} // namespace vm
AVIAN_EXPORT void
vmPrintTrace(vm::Thread* t);
AVIAN_EXPORT void
vmfPrintTrace(vm::Thread* t, FILE* out);
namespace vm {
void
dumpHeap(Thread* t, FILE* out);
2011-01-27 11:54:41 -07:00
inline void NO_RETURN
throw_(Thread* t, object e)
{
assertT(t, t->exception == 0);
assertT(t, e);
2011-01-27 11:54:41 -07:00
expect(t, not t->checkpoint->noThrow);
t->exception = e;
2014-05-28 22:17:25 -06:00
if (objectClass(t, e) == type(t, GcOutOfMemoryError::Type)) {
#ifdef AVIAN_HEAPDUMP
if (not t->m->dumpedHeapOnOOM) {
t->m->dumpedHeapOnOOM = true;
const char* path = findProperty(t, "avian.heap.dump");
if (path) {
FILE* out = vm::fopen(path, "wb");
if (out) {
dumpHeap(t, out);
fclose(out);
}
}
}
#endif//AVIAN_HEAPDUMP
if (AbortOnOutOfMemoryError) {
fprintf(stderr, "OutOfMemoryError\n");
vmPrintTrace(t);
abort();
}
}
// printTrace(t, e);
2011-01-27 11:54:41 -07:00
popResources(t);
t->checkpoint->unwind();
abort(t);
}
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
inline void NO_RETURN
throwNew
2014-05-28 22:17:25 -06:00
(Thread* t, Gc::Type type, object message = 0, object trace = 0,
object cause = 0)
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
{
throw_(t, makeThrowable(t, type, message, trace, cause));
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
}
inline void NO_RETURN
2014-05-28 22:17:25 -06:00
throwNew(Thread* t, Gc::Type type, const char* format, ...)
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
{
int size = 256;
while (true) {
va_list a;
va_start(a, format);
object r = makeThrowableV(t, type, format, a, size);
va_end(a);
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
if (r) {
throw_(t, r);
} else {
size *= 2;
}
}
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
}
object
2014-05-28 22:17:25 -06:00
findInHierarchyOrNull(Thread* t, GcClass* class_, object name, object spec,
object (*find)(Thread*, GcClass*, object, object));
inline object
2014-05-28 22:17:25 -06:00
findInHierarchy(Thread* t, GcClass* class_, object name, object spec,
object (*find)(Thread*, GcClass*, object, object),
Gc::Type errorType, bool throw_ = true)
{
object o = findInHierarchyOrNull(t, class_, name, spec, find);
if (throw_ and o == 0) {
rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
2010-12-27 15:55:23 -07:00
throwNew(t, errorType, "%s %s not found in %s",
&byteArrayBody(t, name, 0),
&byteArrayBody(t, spec, 0),
class_->name()->body().begin());
}
return o;
}
2014-05-28 22:17:25 -06:00
inline GcMethod*
findMethod(Thread* t, GcClass* class_, object name, object spec)
{
2014-05-28 22:17:25 -06:00
return cast<GcMethod>(t, findInHierarchy
(t, class_, name, spec, findMethodInClass, GcNoSuchMethodError::Type));
}
2014-05-28 22:17:25 -06:00
inline GcMethod*
findMethodOrNull(Thread* t, GcClass* class_, const char* name, const char* spec)
{
PROTECT(t, class_);
object n = makeByteArray(t, "%s", name);
PROTECT(t, n);
object s = makeByteArray(t, "%s", spec);
2014-05-28 22:17:25 -06:00
return cast<GcMethod>(t, findInHierarchyOrNull(t, class_, n, s, findMethodInClass));
}
2014-05-28 22:17:25 -06:00
inline GcMethod*
findVirtualMethod(Thread* t, GcMethod* method, GcClass* class_)
{
2014-05-28 22:17:25 -06:00
return cast<GcMethod>(t, arrayBody(t, class_->virtualTable(), method->offset()));
}
2014-05-28 22:17:25 -06:00
inline GcMethod*
findInterfaceMethod(Thread* t, GcMethod* method, GcClass* class_)
{
assertT(t, (class_->vmFlags() & BootstrapFlag) == 0);
GcClass* interface = method->class_();
2014-05-28 22:17:25 -06:00
object itable = class_->interfaceTable();
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
if (arrayBody(t, itable, i) == reinterpret_cast<object>(interface)) {
2014-05-28 22:17:25 -06:00
return cast<GcMethod>(t, arrayBody
(t, arrayBody(t, itable, i + 1), method->offset()));
}
}
abort(t);
}
inline unsigned
objectArrayLength(Thread* t UNUSED, object array)
{
assertT(t, objectClass(t, array)->fixedSize() == BytesPerWord * 2);
assertT(t, objectClass(t, array)->arrayElementSize() == BytesPerWord);
2013-02-10 17:38:51 -07:00
return fieldAtOffset<uintptr_t>(array, BytesPerWord);
}
inline object&
objectArrayBody(Thread* t UNUSED, object array, unsigned index)
{
assertT(t, objectClass(t, array)->fixedSize() == BytesPerWord * 2);
assertT(t, objectClass(t, array)->arrayElementSize() == BytesPerWord);
assertT(t, reinterpret_cast<object>(objectClass(t, array)->objectMask())
== classObjectMask(t, arrayBody
2014-05-28 22:17:25 -06:00
(t, t->m->types, GcArray::Type)));
2013-02-10 17:38:51 -07:00
return fieldAtOffset<object>(array, ArrayBody + (index * BytesPerWord));
}
unsigned
parameterFootprint(Thread* t, const char* s, bool static_);
2007-07-06 17:50:26 -06:00
void
addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object));
inline bool
acquireSystem(Thread* t, Thread* target)
{
ACQUIRE_RAW(t, t->m->stateLock);
if (t->state != Thread::JoinedState) {
atomicOr(&(target->flags), Thread::SystemFlag);
return true;
} else {
return false;
}
}
inline void
releaseSystem(Thread* t, Thread* target)
{
ACQUIRE_RAW(t, t->m->stateLock);
assertT(t, t->state != Thread::JoinedState);
atomicAnd(&(target->flags), ~Thread::SystemFlag);
}
inline bool
atomicCompareAndSwapObject(Thread* t, object target, unsigned offset,
object old, object new_)
{
2013-02-10 17:38:51 -07:00
if (atomicCompareAndSwap(&fieldAtOffset<uintptr_t>(target, offset),
reinterpret_cast<uintptr_t>(old),
reinterpret_cast<uintptr_t>(new_)))
{
mark(t, target, offset);
return true;
} else {
return false;
}
}
// The following two methods (monitorAtomicAppendAcquire and
// monitorAtomicPollAcquire) use the Michael and Scott Non-Blocking
// Queue Algorithm: http://www.cs.rochester.edu/u/michael/PODC96.html
inline void
monitorAtomicAppendAcquire(Thread* t, object monitor, object node)
{
if (node == 0) {
PROTECT(t, monitor);
2014-05-28 22:17:25 -06:00
node = reinterpret_cast<object>(makeMonitorNode(t, t, 0));
}
while (true) {
object tail = monitorAcquireTail(t, monitor);
2014-05-28 22:17:25 -06:00
loadMemoryBarrier();
object next = monitorNodeNext(t, tail);
loadMemoryBarrier();
if (tail == monitorAcquireTail(t, monitor)) {
if (next) {
atomicCompareAndSwapObject
(t, monitor, MonitorAcquireTail, tail, next);
} else if (atomicCompareAndSwapObject
(t, tail, MonitorNodeNext, 0, node))
{
atomicCompareAndSwapObject
(t, monitor, MonitorAcquireTail, tail, node);
return;
}
}
}
}
inline Thread*
monitorAtomicPollAcquire(Thread* t, object monitor, bool remove)
{
while (true) {
object head = monitorAcquireHead(t, monitor);
loadMemoryBarrier();
object tail = monitorAcquireTail(t, monitor);
loadMemoryBarrier();
object next = monitorNodeNext(t, head);
loadMemoryBarrier();
if (head == monitorAcquireHead(t, monitor)) {
if (head == tail) {
if (next) {
atomicCompareAndSwapObject
(t, monitor, MonitorAcquireTail, tail, next);
} else {
return 0;
}
} else {
Thread* value = static_cast<Thread*>(monitorNodeValue(t, next));
if ((not remove)
or atomicCompareAndSwapObject
(t, monitor, MonitorAcquireHead, head, next))
{
return value;
}
}
}
}
}
inline bool
monitorTryAcquire(Thread* t, object monitor)
{
if (monitorOwner(t, monitor) == t
or (monitorAtomicPollAcquire(t, monitor, false) == 0
and atomicCompareAndSwap
(reinterpret_cast<uintptr_t*>(&monitorOwner(t, monitor)), 0,
reinterpret_cast<uintptr_t>(t))))
{
++ monitorDepth(t, monitor);
return true;
} else {
return false;
}
}
inline void
monitorAcquire(Thread* t, object monitor, object node = 0)
{
if (not monitorTryAcquire(t, monitor)) {
PROTECT(t, monitor);
PROTECT(t, node);
ACQUIRE(t, t->lock);
monitorAtomicAppendAcquire(t, monitor, node);
2014-05-28 22:17:25 -06:00
// note that we don't try to acquire the lock until we're first in
// line, both because it's fair and because we don't support
// removing elements from arbitrary positions in the queue
while (not (t == monitorAtomicPollAcquire(t, monitor, false)
and atomicCompareAndSwap
(reinterpret_cast<uintptr_t*>(&monitorOwner(t, monitor)), 0,
reinterpret_cast<uintptr_t>(t))))
{
ENTER(t, Thread::IdleState);
2014-05-28 22:17:25 -06:00
t->lock->wait(t->systemThread, 0);
}
expect(t, t == monitorAtomicPollAcquire(t, monitor, true));
2014-05-28 22:17:25 -06:00
++ monitorDepth(t, monitor);
}
assertT(t, monitorOwner(t, monitor) == t);
}
inline void
monitorRelease(Thread* t, object monitor)
{
expect(t, monitorOwner(t, monitor) == t);
if (-- monitorDepth(t, monitor) == 0) {
monitorOwner(t, monitor) = 0;
storeLoadMemoryBarrier();
2014-05-28 22:17:25 -06:00
Thread* next = monitorAtomicPollAcquire(t, monitor, false);
if (next and acquireSystem(t, next)) {
ACQUIRE(t, next->lock);
2014-05-28 22:17:25 -06:00
next->lock->notify(t->systemThread);
releaseSystem(t, next);
}
}
}
inline void
monitorAppendWait(Thread* t, object monitor)
{
assertT(t, monitorOwner(t, monitor) == t);
expect(t, (t->flags & Thread::WaitingFlag) == 0);
expect(t, t->waitNext == 0);
atomicOr(&(t->flags), Thread::WaitingFlag);
if (monitorWaitTail(t, monitor)) {
static_cast<Thread*>(monitorWaitTail(t, monitor))->waitNext = t;
} else {
monitorWaitHead(t, monitor) = t;
}
monitorWaitTail(t, monitor) = t;
}
inline void
monitorRemoveWait(Thread* t, object monitor)
{
assertT(t, monitorOwner(t, monitor) == t);
Thread* previous = 0;
for (Thread* current = static_cast<Thread*>(monitorWaitHead(t, monitor));
current; current = current->waitNext)
{
if (t == current) {
if (t == monitorWaitHead(t, monitor)) {
monitorWaitHead(t, monitor) = t->waitNext;
} else {
previous->waitNext = t->waitNext;
}
if (t == monitorWaitTail(t, monitor)) {
assertT(t, t->waitNext == 0);
monitorWaitTail(t, monitor) = previous;
}
t->waitNext = 0;
atomicAnd(&(t->flags), ~Thread::WaitingFlag);
return;
} else {
previous = current;
}
}
abort(t);
}
inline bool
monitorFindWait(Thread* t, object monitor)
{
assertT(t, monitorOwner(t, monitor) == t);
for (Thread* current = static_cast<Thread*>(monitorWaitHead(t, monitor));
current; current = current->waitNext)
{
if (t == current) {
return true;
}
}
return false;
}
inline bool
monitorWait(Thread* t, object monitor, int64_t time)
{
expect(t, monitorOwner(t, monitor) == t);
bool interrupted;
unsigned depth;
PROTECT(t, monitor);
// pre-allocate monitor node so we don't get an OutOfMemoryError
// when we try to re-acquire the monitor below
2014-05-28 22:17:25 -06:00
object monitorNode = reinterpret_cast<object>(makeMonitorNode(t, t, 0));
PROTECT(t, monitorNode);
{ ACQUIRE(t, t->lock);
monitorAppendWait(t, monitor);
depth = monitorDepth(t, monitor);
monitorDepth(t, monitor) = 1;
monitorRelease(t, monitor);
ENTER(t, Thread::IdleState);
interrupted = t->lock->waitAndClearInterrupted(t->systemThread, time);
}
monitorAcquire(t, monitor, monitorNode);
monitorDepth(t, monitor) = depth;
if (t->flags & Thread::WaitingFlag) {
monitorRemoveWait(t, monitor);
} else {
expect(t, not monitorFindWait(t, monitor));
}
assertT(t, monitorOwner(t, monitor) == t);
return interrupted;
}
inline Thread*
monitorPollWait(Thread* t, object monitor)
{
assertT(t, monitorOwner(t, monitor) == t);
Thread* next = static_cast<Thread*>(monitorWaitHead(t, monitor));
if (next) {
monitorWaitHead(t, monitor) = next->waitNext;
atomicAnd(&(next->flags), ~Thread::WaitingFlag);
next->waitNext = 0;
if (next == monitorWaitTail(t, monitor)) {
monitorWaitTail(t, monitor) = 0;
}
} else {
assertT(t, monitorWaitTail(t, monitor) == 0);
}
return next;
}
inline bool
monitorNotify(Thread* t, object monitor)
{
expect(t, monitorOwner(t, monitor) == t);
2014-05-28 22:17:25 -06:00
Thread* next = monitorPollWait(t, monitor);
if (next) {
ACQUIRE(t, next->lock);
next->lock->notify(t->systemThread);
return true;
} else {
return false;
}
}
inline void
monitorNotifyAll(Thread* t, object monitor)
{
PROTECT(t, monitor);
while (monitorNotify(t, monitor)) { }
}
class ObjectMonitorResource {
public:
ObjectMonitorResource(Thread* t, object o): o(o), protector(t, &(this->o)) {
monitorAcquire(protector.t, o);
}
~ObjectMonitorResource() {
monitorRelease(protector.t, o);
}
private:
object o;
Thread::SingleProtector protector;
};
object
2007-11-27 15:23:00 -07:00
objectMonitor(Thread* t, object o, bool createNew);
2007-07-06 17:50:26 -06:00
2007-07-07 17:47:35 -06:00
inline void
acquire(Thread* t, object o)
{
unsigned hash;
if (DebugMonitors) {
hash = objectHash(t, o);
}
object m = objectMonitor(t, o, true);
2007-07-10 22:19:26 -06:00
if (DebugMonitors) {
fprintf(stderr, "thread %p acquires %p for %x\n", t, m, hash);
2007-07-10 22:19:26 -06:00
}
monitorAcquire(t, m);
2007-07-07 17:47:35 -06:00
}
inline void
release(Thread* t, object o)
{
unsigned hash;
if (DebugMonitors) {
hash = objectHash(t, o);
}
object m = objectMonitor(t, o, false);
2007-07-10 22:19:26 -06:00
if (DebugMonitors) {
fprintf(stderr, "thread %p releases %p for %x\n", t, m, hash);
2007-07-10 22:19:26 -06:00
}
monitorRelease(t, m);
2007-07-07 17:47:35 -06:00
}
inline void
wait(Thread* t, object o, int64_t milliseconds)
{
unsigned hash;
if (DebugMonitors) {
hash = objectHash(t, o);
}
object m = objectMonitor(t, o, false);
2007-07-10 22:19:26 -06:00
if (DebugMonitors) {
2009-10-14 10:01:37 -06:00
fprintf(stderr, "thread %p waits %d millis on %p for %x\n",
t, static_cast<int>(milliseconds), m, hash);
2007-07-10 22:19:26 -06:00
}
if (m and monitorOwner(t, m) == t) {
PROTECT(t, m);
bool interrupted = monitorWait(t, m, milliseconds);
2007-07-28 15:28:25 -06:00
if (interrupted) {
if (t->m->alive or (t->flags & Thread::DaemonFlag) == 0) {
t->m->classpath->clearInterrupted(t);
2014-05-28 22:17:25 -06:00
throwNew(t, GcInterruptedException::Type);
} else {
throw_(t, root(t, Machine::Shutdown));
}
2007-07-28 15:28:25 -06:00
}
2007-07-07 17:47:35 -06:00
} else {
2014-05-28 22:17:25 -06:00
throwNew(t, GcIllegalMonitorStateException::Type);
2007-07-07 17:47:35 -06:00
}
2007-07-10 22:19:26 -06:00
if (DebugMonitors) {
fprintf(stderr, "thread %p wakes up on %p for %x\n",
t, m, hash);
2007-07-10 22:19:26 -06:00
}
2007-07-19 17:45:44 -06:00
stress(t);
2007-07-07 17:47:35 -06:00
}
inline void
notify(Thread* t, object o)
{
unsigned hash;
if (DebugMonitors) {
hash = objectHash(t, o);
}
object m = objectMonitor(t, o, false);
2007-07-10 22:19:26 -06:00
if (DebugMonitors) {
fprintf(stderr, "thread %p notifies on %p for %x\n",
t, m, hash);
2007-07-10 22:19:26 -06:00
}
if (m and monitorOwner(t, m) == t) {
monitorNotify(t, m);
2007-07-07 17:47:35 -06:00
} else {
2014-05-28 22:17:25 -06:00
throwNew(t, GcIllegalMonitorStateException::Type);
2007-07-07 17:47:35 -06:00
}
}
inline void
notifyAll(Thread* t, object o)
{
object m = objectMonitor(t, o, false);
2007-07-10 22:19:26 -06:00
if (DebugMonitors) {
fprintf(stderr, "thread %p notifies all on %p for %x\n",
t, m, objectHash(t, o));
}
if (m and monitorOwner(t, m) == t) {
monitorNotifyAll(t, m);
2007-07-07 17:47:35 -06:00
} else {
2014-05-28 22:17:25 -06:00
throwNew(t, GcIllegalMonitorStateException::Type);
2007-07-07 17:47:35 -06:00
}
}
inline void
interrupt(Thread* t, Thread* target)
{
if (acquireSystem(t, target)) {
target->systemThread->interrupt();
releaseSystem(t, target);
}
}
inline bool
getAndClearInterrupted(Thread* t, Thread* target)
{
if (acquireSystem(t, target)) {
bool result = target->systemThread->getAndClearInterrupted();
releaseSystem(t, target);
return result;
} else {
return false;
}
}
inline bool
2014-05-28 22:17:25 -06:00
exceptionMatch(Thread* t, GcClass* type, object exception)
{
return type == 0
or (exception != root(t, Machine::Shutdown)
and instanceOf(t, type, t->exception));
}
2007-07-28 18:02:32 -06:00
object
intern(Thread* t, object s);
void
walk(Thread* t, Heap::Walker* w, object o, unsigned start);
int
walkNext(Thread* t, object o, int previous);
void
visitRoots(Machine* m, Heap::Visitor* v);
2007-09-24 07:46:48 -06:00
inline jobject
makeLocalReference(Thread* t, object o)
{
return t->m->processor->makeLocalReference(t, o);
}
2007-09-24 07:46:48 -06:00
inline void
disposeLocalReference(Thread* t, jobject r)
{
t->m->processor->disposeLocalReference(t, r);
}
2007-11-05 07:28:46 -07:00
inline bool
methodVirtual(Thread* t UNUSED, GcMethod* method)
2007-11-05 07:28:46 -07:00
{
2014-05-28 22:17:25 -06:00
return (method->flags() & (ACC_STATIC | ACC_PRIVATE)) == 0
and method->name()->body()[0] != '<';
2007-11-05 07:28:46 -07:00
}
inline unsigned
singletonMaskSize(unsigned count, unsigned bitsPerWord)
{
if (count) {
2013-02-10 18:06:15 -07:00
return ceilingDivide(count + 2, bitsPerWord);
}
return 0;
}
inline unsigned
singletonMaskSize(unsigned count)
{
return singletonMaskSize(count, BitsPerWord);
}
inline unsigned
2014-05-28 22:17:25 -06:00
singletonMaskSize(Thread* t UNUSED, GcSingleton* singleton)
{
2014-05-28 22:17:25 -06:00
unsigned length = singleton->length();
if (length) {
2013-02-10 18:06:15 -07:00
return ceilingDivide(length + 2, BitsPerWord + 1);
}
return 0;
}
inline unsigned
2014-05-28 22:17:25 -06:00
singletonCount(Thread* t, GcSingleton* singleton)
{
2014-05-28 22:17:25 -06:00
return singleton->length() - singletonMaskSize(t, singleton);
}
inline uint32_t*
2014-05-28 22:17:25 -06:00
singletonMask(Thread* t, GcSingleton* singleton)
{
assertT(t, singleton->length());
return reinterpret_cast<uint32_t*>
2014-05-28 22:17:25 -06:00
(&singletonBody(t, reinterpret_cast<object>(singleton), singletonCount(t, singleton)));
}
inline void
singletonMarkObject(uint32_t* mask, unsigned index)
{
mask[(index + 2) / 32]
|= (static_cast<uint32_t>(1) << ((index + 2) % 32));
}
inline void
2014-05-28 22:17:25 -06:00
singletonMarkObject(Thread* t, GcSingleton* singleton, unsigned index)
{
singletonMarkObject(singletonMask(t, singleton), index);
}
inline bool
2014-05-28 22:17:25 -06:00
singletonIsObject(Thread* t, GcSingleton* singleton, unsigned index)
{
assertT(t, index < singletonCount(t, singleton));
return (singletonMask(t, singleton)[(index + 2) / 32]
& (static_cast<uint32_t>(1) << ((index + 2) % 32))) != 0;
}
2007-11-06 08:29:05 -07:00
inline object&
2014-05-28 22:17:25 -06:00
singletonObject(Thread* t, GcSingleton* singleton, unsigned index)
{
assertT(t, singletonIsObject(t, singleton, index));
2014-05-28 22:17:25 -06:00
return reinterpret_cast<object&>(singletonBody(t, reinterpret_cast<object>(singleton), index));
}
inline uintptr_t&
2014-05-28 22:17:25 -06:00
singletonValue(Thread* t, GcSingleton* singleton, unsigned index)
{
assertT(t, not singletonIsObject(t, singleton, index));
2014-05-28 22:17:25 -06:00
return singletonBody(t, reinterpret_cast<object>(singleton), index);
}
2014-05-28 22:17:25 -06:00
inline GcSingleton*
makeSingletonOfSize(Thread* t, unsigned count)
{
2014-05-28 22:17:25 -06:00
GcSingleton* o = makeSingleton(t, count + singletonMaskSize(count));
assertT(t, o->length() == count + singletonMaskSize(t, o));
if (count) {
singletonMask(t, o)[0] = 1;
}
return o;
}
inline void
2014-05-28 22:17:25 -06:00
singletonSetBit(Thread* t, GcSingleton* singleton, unsigned start, unsigned index)
{
singletonValue(t, singleton, start + (index / BitsPerWord))
|= static_cast<uintptr_t>(1) << (index % BitsPerWord);
}
inline bool
2014-05-28 22:17:25 -06:00
singletonBit(Thread* t, GcSingleton* singleton, unsigned start, unsigned index)
{
return (singletonValue(t, singleton, start + (index / BitsPerWord))
& (static_cast<uintptr_t>(1) << (index % BitsPerWord))) != 0;
}
inline unsigned
poolMaskSize(unsigned count, unsigned bitsPerWord)
{
2013-02-10 18:06:15 -07:00
return ceilingDivide(count, bitsPerWord);
}
inline unsigned
poolMaskSize(unsigned count)
{
return poolMaskSize(count, BitsPerWord);
}
inline unsigned
2014-05-28 22:17:25 -06:00
poolMaskSize(Thread* t, GcSingleton* pool)
{
2013-02-10 18:06:15 -07:00
return ceilingDivide(singletonCount(t, pool), BitsPerWord + 1);
}
inline unsigned
2014-05-28 22:17:25 -06:00
poolSize(Thread* t, GcSingleton* pool)
{
return singletonCount(t, pool) - poolMaskSize(t, pool);
}
2014-05-28 22:17:25 -06:00
inline GcClass*
2014-06-28 15:11:31 -06:00
resolveClassInObject(Thread* t, GcClassLoader* loader, object container,
unsigned classOffset, bool throw_ = true)
{
2013-02-10 17:38:51 -07:00
object o = fieldAtOffset<object>(container, classOffset);
2014-05-28 22:17:25 -06:00
loadMemoryBarrier();
2014-05-28 22:17:25 -06:00
if (objectClass(t, o) == type(t, GcByteArray::Type)) {
PROTECT(t, container);
2014-05-28 22:17:25 -06:00
GcClass* c = resolveClass(t, loader, o, throw_);
if (c) {
storeStoreMemoryBarrier();
2014-05-28 22:17:25 -06:00
set(t, container, classOffset, reinterpret_cast<object>(c));
}
2014-05-28 22:17:25 -06:00
return c;
}
2014-05-28 22:17:25 -06:00
return cast<GcClass>(t, o);
}
2014-05-28 22:17:25 -06:00
inline GcClass*
2014-06-28 15:11:31 -06:00
resolveClassInPool(Thread* t, GcClassLoader* loader, GcMethod* method, unsigned index,
bool throw_ = true)
{
2014-06-27 22:00:05 -06:00
object o = singletonObject(t, method->code()->pool(), index);
loadMemoryBarrier();
2014-05-28 22:17:25 -06:00
if (objectClass(t, o) == type(t, GcReference::Type)) {
PROTECT(t, method);
2014-05-28 22:17:25 -06:00
GcClass* c = resolveClass(t, loader, referenceName(t, o), throw_);
if (c) {
storeStoreMemoryBarrier();
2014-06-27 22:00:05 -06:00
set(t, reinterpret_cast<object>(method->code()->pool()),
2014-05-28 22:17:25 -06:00
SingletonBody + (index * BytesPerWord), reinterpret_cast<object>(c));
}
2014-05-28 22:17:25 -06:00
return c;
}
2014-05-28 22:17:25 -06:00
return cast<GcClass>(t, o);
}
2014-05-28 22:17:25 -06:00
inline GcClass*
resolveClassInPool(Thread* t, GcMethod* method, unsigned index,
bool throw_ = true)
{
2014-06-28 15:11:31 -06:00
return resolveClassInPool(t, method->class_()->loader(),
method, index, throw_);
}
inline object
2014-06-28 15:11:31 -06:00
resolve(Thread* t, GcClassLoader* loader, GcMethod* method, unsigned index,
2014-05-28 22:17:25 -06:00
object (*find)(vm::Thread*, GcClass*, object, object),
Gc::Type errorType, bool throw_ = true)
{
2014-06-27 22:00:05 -06:00
object o = singletonObject(t, method->code()->pool(), index);
2014-05-28 22:17:25 -06:00
loadMemoryBarrier();
2014-05-28 22:17:25 -06:00
if (objectClass(t, o) == type(t, GcReference::Type)) {
PROTECT(t, method);
object reference = o;
PROTECT(t, reference);
2014-05-28 22:17:25 -06:00
GcClass* class_ = resolveClassInObject(t, loader, o, ReferenceClass, throw_);
if (class_) {
o = findInHierarchy
(t, class_, referenceName(t, reference), referenceSpec(t, reference),
find, errorType, throw_);
2014-05-28 22:17:25 -06:00
if (o) {
storeStoreMemoryBarrier();
2014-06-27 22:00:05 -06:00
set(t, reinterpret_cast<object>(method->code()->pool()),
SingletonBody + (index * BytesPerWord), o);
}
} else {
o = 0;
}
}
return o;
}
inline object
2014-06-28 15:11:31 -06:00
resolveField(Thread* t, GcClassLoader* loader, GcMethod* method, unsigned index,
bool throw_ = true)
{
return resolve(t, loader, method, index, findFieldInClass,
2014-05-28 22:17:25 -06:00
GcNoSuchFieldError::Type, throw_);
}
inline object
2014-05-28 22:17:25 -06:00
resolveField(Thread* t, GcMethod* method, unsigned index, bool throw_ = true)
{
return resolveField
2014-06-28 15:11:31 -06:00
(t, method->class_()->loader(), method, index, throw_);
}
inline void
acquireFieldForRead(Thread* t, object field)
{
if (UNLIKELY((fieldFlags(t, field) & ACC_VOLATILE)
and BytesPerWord == 4
and (fieldCode(t, field) == DoubleField
or fieldCode(t, field) == LongField)))
{
2014-05-28 22:17:25 -06:00
acquire(t, field);
}
}
inline void
releaseFieldForRead(Thread* t, object field)
{
if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) {
if (BytesPerWord == 4
and (fieldCode(t, field) == DoubleField
or fieldCode(t, field) == LongField))
{
2014-05-28 22:17:25 -06:00
release(t, field);
} else {
loadMemoryBarrier();
}
}
}
class FieldReadResource {
public:
FieldReadResource(Thread* t, object o): o(o), protector(t, &(this->o)) {
acquireFieldForRead(protector.t, o);
}
~FieldReadResource() {
releaseFieldForRead(protector.t, o);
}
private:
object o;
Thread::SingleProtector protector;
};
inline void
acquireFieldForWrite(Thread* t, object field)
{
if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) {
if (BytesPerWord == 4
and (fieldCode(t, field) == DoubleField
or fieldCode(t, field) == LongField))
{
2014-05-28 22:17:25 -06:00
acquire(t, field);
} else {
storeStoreMemoryBarrier();
}
}
}
inline void
releaseFieldForWrite(Thread* t, object field)
{
if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) {
if (BytesPerWord == 4
and (fieldCode(t, field) == DoubleField
or fieldCode(t, field) == LongField))
{
2014-05-28 22:17:25 -06:00
release(t, field);
} else {
storeLoadMemoryBarrier();
}
}
}
class FieldWriteResource {
public:
FieldWriteResource(Thread* t, object o): o(o), protector(t, &(this->o)) {
acquireFieldForWrite(protector.t, o);
}
~FieldWriteResource() {
releaseFieldForWrite(protector.t, o);
}
private:
object o;
Thread::SingleProtector protector;
};
2014-05-28 22:17:25 -06:00
inline GcMethod*
2014-06-28 15:11:31 -06:00
resolveMethod(Thread* t, GcClassLoader* loader, GcMethod* method, unsigned index,
bool throw_ = true)
{
2014-05-28 22:17:25 -06:00
return cast<GcMethod>(t, resolve(t, loader, method, index, findMethodInClass,
GcNoSuchMethodError::Type, throw_));
}
2014-05-28 22:17:25 -06:00
inline GcMethod*
resolveMethod(Thread* t, GcMethod* method, unsigned index, bool throw_ = true)
{
return resolveMethod
2014-06-28 15:11:31 -06:00
(t, method->class_()->loader(), method, index, throw_);
}
2014-06-28 14:41:27 -06:00
GcVector*
vectorAppend(Thread*, GcVector*, object);
inline object
getClassRuntimeDataIfExists(Thread* t, object c)
{
if (classRuntimeDataIndex(t, c)) {
return vectorBody(t, root(t, Machine::ClassRuntimeDataTable),
classRuntimeDataIndex(t, c) - 1);
} else {
return 0;
}
}
inline object
2014-05-28 22:17:25 -06:00
getClassRuntimeData(Thread* t, GcClass* c)
{
2014-05-28 22:17:25 -06:00
if (c->runtimeDataIndex() == 0) {
PROTECT(t, c);
ACQUIRE(t, t->m->classLock);
2014-05-28 22:17:25 -06:00
if (c->runtimeDataIndex() == 0) {
object runtimeData = reinterpret_cast<object>(makeClassRuntimeData(t, 0, 0, 0, 0));
2014-06-28 14:41:27 -06:00
setRoot(t, Machine::ClassRuntimeDataTable, reinterpret_cast<object>(vectorAppend
(t, cast<GcVector>(t, root(t, Machine::ClassRuntimeDataTable)), runtimeData)));
2014-05-28 22:17:25 -06:00
c->runtimeDataIndex() = vectorSize
(t, root(t, Machine::ClassRuntimeDataTable));
}
}
return vectorBody(t, root(t, Machine::ClassRuntimeDataTable),
2014-05-28 22:17:25 -06:00
c->runtimeDataIndex() - 1);
}
inline object
2014-05-28 22:17:25 -06:00
getMethodRuntimeData(Thread* t, GcMethod* method)
{
2014-05-28 22:17:25 -06:00
int index = method->runtimeDataIndex();
loadMemoryBarrier();
if (index == 0) {
PROTECT(t, method);
ACQUIRE(t, t->m->classLock);
2014-05-28 22:17:25 -06:00
if (method->runtimeDataIndex() == 0) {
object runtimeData = reinterpret_cast<object>(makeMethodRuntimeData(t, 0));
2014-06-28 14:41:27 -06:00
setRoot(t, Machine::MethodRuntimeDataTable, reinterpret_cast<object>(vectorAppend
(t, cast<GcVector>(t, root(t, Machine::MethodRuntimeDataTable)), runtimeData)));
storeStoreMemoryBarrier();
2014-05-28 22:17:25 -06:00
method->runtimeDataIndex() = vectorSize
(t, root(t, Machine::MethodRuntimeDataTable));
}
}
return vectorBody(t, root(t, Machine::MethodRuntimeDataTable),
2014-05-28 22:17:25 -06:00
method->runtimeDataIndex() - 1);
}
inline GcJclass*
2014-05-28 22:17:25 -06:00
getJClass(Thread* t, GcClass* c)
{
2010-12-09 22:17:57 -07:00
PROTECT(t, c);
GcJclass* jclass = cast<GcJclass>(t, classRuntimeDataJclass(t, getClassRuntimeData(t, c)));
loadMemoryBarrier();
if (jclass == 0) {
ACQUIRE(t, t->m->classLock);
jclass = cast<GcJclass>(t, classRuntimeDataJclass(t, getClassRuntimeData(t, c)));
if (jclass == 0) {
jclass = cast<GcJclass>(t, t->m->classpath->makeJclass(t, c));
storeStoreMemoryBarrier();
2014-05-28 22:17:25 -06:00
set(t, getClassRuntimeData(t, c), ClassRuntimeDataJclass, reinterpret_cast<object>(jclass));
}
}
return jclass;
}
2014-05-28 22:17:25 -06:00
inline GcClass*
primitiveClass(Thread* t, char name)
{
switch (name) {
2014-05-28 22:17:25 -06:00
case 'B': return type(t, GcJbyte::Type);
case 'C': return type(t, GcJchar::Type);
case 'D': return type(t, GcJdouble::Type);
case 'F': return type(t, GcJfloat::Type);
case 'I': return type(t, GcJint::Type);
case 'J': return type(t, GcJlong::Type);
case 'S': return type(t, GcJshort::Type);
case 'V': return type(t, GcJvoid::Type);
case 'Z': return type(t, GcJboolean::Type);
default: throwNew(t, GcIllegalArgumentException::Type);
}
}
inline void
2014-05-28 22:17:25 -06:00
registerNative(Thread* t, GcMethod* method, void* function)
{
PROTECT(t, method);
2014-05-28 22:17:25 -06:00
expect(t, method->flags() & ACC_NATIVE);
2014-05-28 22:17:25 -06:00
object native = reinterpret_cast<object>(makeNative(t, function, false));
PROTECT(t, native);
object runtimeData = getMethodRuntimeData(t, method);
// ensure other threads only see the methodRuntimeDataNative field
// populated once the object it points to has been populated:
storeStoreMemoryBarrier();
set(t, runtimeData, MethodRuntimeDataNative, native);
}
inline void
unregisterNatives(Thread* t, object c)
{
if (classMethodTable(t, c)) {
for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) {
2014-05-28 22:17:25 -06:00
GcMethod* method = cast<GcMethod>(t, arrayBody(t, classMethodTable(t, c), i));
if (method->flags() & ACC_NATIVE) {
set(t, getMethodRuntimeData(t, method), MethodRuntimeDataNative, 0);
}
}
}
}
void
populateMultiArray(Thread* t, object array, int32_t* counts,
unsigned index, unsigned dimensions);
2014-05-28 22:17:25 -06:00
GcMethod*
getCaller(Thread* t, unsigned target, bool skipMethodInvoke = false);
object
2014-06-28 15:11:31 -06:00
defineClass(Thread* t, GcClassLoader* loader, const uint8_t* buffer, unsigned length);
2014-05-28 22:17:25 -06:00
inline GcMethod*
methodClone(Thread* t, GcMethod* method)
{
return makeMethod
2014-05-28 22:17:25 -06:00
(t, method->vmFlags(),
method->returnCode(),
method->parameterCount(),
method->parameterFootprint(),
method->flags(),
method->offset(),
method->nativeID(),
method->runtimeDataIndex(),
method->name(),
method->spec(),
method->addendum(),
method->class_(),
method->code());
}
inline uint64_t
exceptionHandler(uint64_t start, uint64_t end, uint64_t ip, uint64_t catchType)
{
return (start << 48) | (end << 32) | (ip << 16) | catchType;
}
inline unsigned
exceptionHandlerStart(uint64_t eh)
{
return eh >> 48;
}
inline unsigned
exceptionHandlerEnd(uint64_t eh)
{
return (eh >> 32) & 0xFFFF;
}
inline unsigned
exceptionHandlerIp(uint64_t eh)
{
return (eh >> 16) & 0xFFFF;
}
inline unsigned
exceptionHandlerCatchType(uint64_t eh)
{
return eh & 0xFFFF;
}
inline uint64_t
lineNumber(uint64_t ip, uint64_t line)
{
return (ip << 32) | line;
}
inline unsigned
lineNumberIp(uint64_t ln)
{
return ln >> 32;
}
inline unsigned
lineNumberLine(uint64_t ln)
{
return ln & 0xFFFFFFFF;
}
object
interruptLock(Thread* t, object thread);
void
clearInterrupted(Thread* t);
void
threadInterrupt(Thread* t, object thread);
bool
threadIsInterrupted(Thread* t, object thread, bool clear);
inline FILE*
errorLog(Thread* t)
{
if (t->m->errorLog == 0) {
const char* path = findProperty(t, "avian.error.log");
if (path) {
t->m->errorLog = vm::fopen(path, "wb");
} else {
t->m->errorLog = stderr;
}
}
return t->m->errorLog;
}
2007-06-24 20:02:24 -06:00
} // namespace vm
AVIAN_EXPORT void*
vmAddressFromLine(vm::Thread* t, vm::object m, unsigned line);
2007-07-06 17:50:26 -06:00
#endif//MACHINE_H