2010-12-05 20:21:09 -07:00
|
|
|
/* Copyright (c) 2008-2010, Avian Contributors
|
2008-02-19 11:06:52 -07:00
|
|
|
|
|
|
|
Permission to use, copy, modify, and/or distribute this software
|
|
|
|
for any purpose with or without fee is hereby granted, provided
|
|
|
|
that the above copyright notice and this permission notice appear
|
|
|
|
in all copies.
|
|
|
|
|
|
|
|
There is NO WARRANTY for this software. See license.txt for
|
|
|
|
details. */
|
|
|
|
|
2007-07-06 17:50:26 -06:00
|
|
|
#ifndef MACHINE_H
|
|
|
|
#define MACHINE_H
|
2007-06-24 19:34:07 -06:00
|
|
|
|
2007-07-06 09:24:06 -06:00
|
|
|
#include "common.h"
|
|
|
|
#include "system.h"
|
|
|
|
#include "heap.h"
|
2007-08-10 17:45:47 -06:00
|
|
|
#include "finder.h"
|
2007-09-23 19:39:03 -06:00
|
|
|
#include "processor.h"
|
2007-11-05 07:28:46 -07:00
|
|
|
#include "constants.h"
|
2010-02-04 17:56:21 -07:00
|
|
|
#include "arch.h"
|
2007-06-24 19:34:07 -06:00
|
|
|
|
2009-08-26 18:26:44 -06:00
|
|
|
#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
|
|
|
|
2007-07-06 09:24:06 -06:00
|
|
|
#define PROTECT(thread, name) \
|
2007-10-12 11:56:43 -06:00
|
|
|
Thread::SingleProtector MAKE_NAME(protector_) (thread, &name);
|
2007-07-06 09:24:06 -06:00
|
|
|
|
|
|
|
#define ACQUIRE(t, x) MonitorResource MAKE_NAME(monitorResource_) (t, x)
|
|
|
|
|
2010-09-16 19:43:27 -06:00
|
|
|
#define ACQUIRE_OBJECT(t, x) \
|
|
|
|
ObjectMonitorResource MAKE_NAME(monitorResource_) (t, x)
|
|
|
|
|
2011-03-15 17:52:02 -06:00
|
|
|
#define ACQUIRE_FIELD_FOR_READ(t, field) \
|
|
|
|
FieldReadResource MAKE_NAME(monitorResource_) (t, field)
|
|
|
|
|
|
|
|
#define ACQUIRE_FIELD_FOR_WRITE(t, field) \
|
2011-04-10 14:42:46 -06:00
|
|
|
FieldWriteResource MAKE_NAME(monitorResource_) (t, field)
|
2011-03-15 17:52:02 -06:00
|
|
|
|
2007-07-06 09:24:06 -06:00
|
|
|
#define ACQUIRE_RAW(t, x) RawMonitorResource MAKE_NAME(monitorResource_) (t, x)
|
|
|
|
|
|
|
|
#define ENTER(t, state) StateResource MAKE_NAME(stateResource_) (t, state)
|
|
|
|
|
2010-12-27 15:55:23 -07:00
|
|
|
#define THREAD_RESOURCE0(t, releaseBody) \
|
|
|
|
class MAKE_NAME(Resource_): public Thread::Resource { \
|
|
|
|
public: \
|
|
|
|
MAKE_NAME(Resource_)(Thread* t): Resource(t) { } \
|
|
|
|
~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::Resource { \
|
|
|
|
public: \
|
|
|
|
MAKE_NAME(Resource_)(Thread* t, object name): \
|
|
|
|
Resource(t), name(name), protector(t, &(this->name)) { } \
|
|
|
|
~MAKE_NAME(Resource_)() { releaseBody; } \
|
|
|
|
virtual void release() \
|
|
|
|
{ this->MAKE_NAME(Resource_)::~MAKE_NAME(Resource_)(); } \
|
|
|
|
\
|
|
|
|
private: \
|
|
|
|
object name; \
|
|
|
|
Thread::SingleProtector protector; \
|
|
|
|
} MAKE_NAME(resource_)(t, name);
|
|
|
|
|
|
|
|
#define THREAD_RESOURCE(t, type, name, releaseBody) \
|
|
|
|
class MAKE_NAME(Resource_): public Thread::Resource { \
|
|
|
|
public: \
|
|
|
|
MAKE_NAME(Resource_)(Thread* t, type name): \
|
|
|
|
Resource(t), name(name) { } \
|
|
|
|
~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::Resource { \
|
|
|
|
public: \
|
|
|
|
MAKE_NAME(Resource_)(Thread* t, type1 name1, type2 name2): \
|
|
|
|
Resource(t), name1(name1), name2(name2) { } \
|
|
|
|
~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 {
|
|
|
|
|
2007-07-06 09:24:06 -06:00
|
|
|
const bool Verbose = false;
|
2007-07-27 17:56:19 -06:00
|
|
|
const bool DebugRun = false;
|
2007-07-09 21:04:49 -06:00
|
|
|
const bool DebugStack = false;
|
2007-11-02 15:42:19 -06:00
|
|
|
const bool DebugMonitors = false;
|
2007-11-05 08:39:48 -07:00
|
|
|
const bool DebugReferences = false;
|
2007-07-06 09:24:06 -06:00
|
|
|
|
|
|
|
const uintptr_t HashTakenMark = 1;
|
|
|
|
const uintptr_t ExtendedMark = 2;
|
2007-10-22 11:22:30 -06:00
|
|
|
const uintptr_t FixedMark = 3;
|
2007-07-06 09:24:06 -06:00
|
|
|
|
2008-11-22 14:47:18 -07:00
|
|
|
const unsigned ThreadHeapSizeInBytes = 64 * 1024;
|
|
|
|
const unsigned ThreadHeapSizeInWords = ThreadHeapSizeInBytes / BytesPerWord;
|
|
|
|
|
2010-06-19 16:40:21 -06:00
|
|
|
const unsigned ThreadBackupHeapSizeInBytes = 2 * 1024;
|
|
|
|
const unsigned ThreadBackupHeapSizeInWords
|
|
|
|
= ThreadBackupHeapSizeInBytes / BytesPerWord;
|
|
|
|
|
2011-02-07 11:45:39 -07:00
|
|
|
const unsigned StackSizeInBytes = 128 * 1024;
|
2010-12-19 15:23:19 -07:00
|
|
|
const unsigned StackSizeInWords = StackSizeInBytes / BytesPerWord;
|
|
|
|
|
2008-11-22 14:48:10 -07:00
|
|
|
const unsigned ThreadHeapPoolSize = 64;
|
2008-11-22 14:47:18 -07:00
|
|
|
|
|
|
|
const unsigned FixedFootprintThresholdInBytes
|
|
|
|
= ThreadHeapPoolSize * ThreadHeapSizeInBytes;
|
|
|
|
|
2007-07-06 09:24:06 -06:00
|
|
|
enum FieldCode {
|
|
|
|
VoidField,
|
|
|
|
ByteField,
|
|
|
|
CharField,
|
|
|
|
DoubleField,
|
|
|
|
FloatField,
|
|
|
|
IntField,
|
|
|
|
LongField,
|
|
|
|
ShortField,
|
|
|
|
BooleanField,
|
|
|
|
ObjectField
|
|
|
|
};
|
|
|
|
|
|
|
|
enum StackTag {
|
|
|
|
IntTag, // must be zero
|
|
|
|
ObjectTag
|
|
|
|
};
|
|
|
|
|
2011-03-17 09:41:23 -06:00
|
|
|
const int NativeLine = -2;
|
|
|
|
const int UnknownLine = -1;
|
2007-07-06 09:24:06 -06:00
|
|
|
|
2009-05-03 14:57:11 -06:00
|
|
|
// class vmFlags:
|
2007-07-19 21:18:25 -06:00
|
|
|
const unsigned ReferenceFlag = 1 << 0;
|
|
|
|
const unsigned WeakReferenceFlag = 1 << 1;
|
2007-07-28 10:10:13 -06:00
|
|
|
const unsigned NeedInitFlag = 1 << 2;
|
2007-08-01 17:48:36 -06:00
|
|
|
const unsigned InitFlag = 1 << 3;
|
2009-07-20 14:12:38 -06:00
|
|
|
const unsigned InitErrorFlag = 1 << 4;
|
|
|
|
const unsigned PrimitiveFlag = 1 << 5;
|
|
|
|
const unsigned BootstrapFlag = 1 << 6;
|
2009-07-21 18:57:55 -06:00
|
|
|
const unsigned HasFinalizerFlag = 1 << 7;
|
2009-08-18 14:26:28 -06:00
|
|
|
const unsigned LinkFlag = 1 << 8;
|
|
|
|
const unsigned HasFinalMemberFlag = 1 << 9;
|
|
|
|
const unsigned SingletonFlag = 1 << 10;
|
|
|
|
const unsigned ContinuationFlag = 1 << 11;
|
2007-08-01 17:48:36 -06:00
|
|
|
|
2009-05-03 14:57:11 -06:00
|
|
|
// method vmFlags:
|
2007-08-01 17:48:36 -06:00
|
|
|
const unsigned ClassInitFlag = 1 << 0;
|
2007-09-25 17:53:11 -06:00
|
|
|
const unsigned CompiledFlag = 1 << 1;
|
2009-03-02 20:18:15 -07:00
|
|
|
const unsigned ConstructorFlag = 1 << 2;
|
2007-07-19 21:18:25 -06:00
|
|
|
|
2009-06-22 16:25:13 -06:00
|
|
|
#ifndef JNI_VERSION_1_6
|
|
|
|
#define JNI_VERSION_1_6 0x00010006
|
|
|
|
#endif
|
|
|
|
|
2007-09-10 17:33:58 -06:00
|
|
|
typedef Machine JavaVM;
|
2007-07-06 09:24:06 -06:00
|
|
|
typedef Thread JNIEnv;
|
|
|
|
|
2007-06-24 19:34:07 -06:00
|
|
|
typedef uint8_t jboolean;
|
|
|
|
typedef int8_t jbyte;
|
|
|
|
typedef uint16_t jchar;
|
|
|
|
typedef int16_t jshort;
|
|
|
|
typedef int32_t jint;
|
|
|
|
typedef int64_t jlong;
|
|
|
|
typedef float jfloat;
|
|
|
|
typedef double jdouble;
|
|
|
|
|
|
|
|
typedef jint jsize;
|
|
|
|
|
2007-09-06 18:21:52 -06:00
|
|
|
typedef object* jobject;
|
2007-06-24 19:34:07 -06:00
|
|
|
|
|
|
|
typedef jobject jclass;
|
|
|
|
typedef jobject jthrowable;
|
|
|
|
typedef jobject jstring;
|
|
|
|
typedef jobject jweak;
|
|
|
|
|
|
|
|
typedef jobject jarray;
|
|
|
|
typedef jarray jbooleanArray;
|
|
|
|
typedef jarray jbyteArray;
|
|
|
|
typedef jarray jcharArray;
|
|
|
|
typedef jarray jshortArray;
|
|
|
|
typedef jarray jintArray;
|
|
|
|
typedef jarray jlongArray;
|
|
|
|
typedef jarray jfloatArray;
|
|
|
|
typedef jarray jdoubleArray;
|
|
|
|
typedef jarray jobjectArray;
|
|
|
|
|
2007-09-06 18:21:52 -06:00
|
|
|
typedef uintptr_t jfieldID;
|
|
|
|
typedef uintptr_t jmethodID;
|
2007-06-24 19:34:07 -06:00
|
|
|
|
|
|
|
union jvalue {
|
|
|
|
jboolean z;
|
|
|
|
jbyte b;
|
|
|
|
jchar c;
|
|
|
|
jshort s;
|
|
|
|
jint i;
|
|
|
|
jlong j;
|
|
|
|
jfloat f;
|
|
|
|
jdouble d;
|
|
|
|
jobject l;
|
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2008-06-15 14:17:52 -06:00
|
|
|
#if (! TARGET_RT_MAC_CFM) && defined(__ppc__)
|
|
|
|
void* cfm_vectors[4];
|
|
|
|
#endif
|
|
|
|
|
2007-06-24 19:34:07 -06:00
|
|
|
jint
|
|
|
|
(JNICALL *DestroyJavaVM)
|
|
|
|
(JavaVM*);
|
|
|
|
|
|
|
|
jint
|
|
|
|
(JNICALL *AttachCurrentThread)
|
2007-09-10 17:33:58 -06:00
|
|
|
(JavaVM*, JNIEnv**, void*);
|
2007-06-24 19:34:07 -06:00
|
|
|
|
|
|
|
jint
|
|
|
|
(JNICALL *DetachCurrentThread)
|
|
|
|
(JavaVM*);
|
|
|
|
|
|
|
|
jint
|
|
|
|
(JNICALL *GetEnv)
|
2007-09-10 17:33:58 -06:00
|
|
|
(JavaVM*, JNIEnv**, jint);
|
2007-06-24 19:34:07 -06:00
|
|
|
|
|
|
|
jint
|
|
|
|
(JNICALL *AttachCurrentThreadAsDaemon)
|
2007-09-10 17:33:58 -06:00
|
|
|
(JavaVM*, JNIEnv**, void*);
|
2008-06-15 14:17:52 -06:00
|
|
|
|
|
|
|
#if TARGET_RT_MAC_CFM && defined(__ppc__)
|
|
|
|
void* real_functions[5];
|
|
|
|
#endif
|
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;
|
|
|
|
|
2008-06-15 12:51:04 -06:00
|
|
|
#if (! TARGET_RT_MAC_CFM) && defined(__ppc__)
|
|
|
|
void* cfm_vectors[225];
|
|
|
|
#endif
|
|
|
|
|
2007-06-24 19:34:07 -06:00
|
|
|
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
|
|
|
|
|
|
|
#if TARGET_RT_MAC_CFM && defined(__ppc__)
|
|
|
|
void* real_functions[228];
|
|
|
|
#endif
|
2007-06-24 19:34:07 -06:00
|
|
|
};
|
|
|
|
|
2010-09-14 10:49:41 -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)
|
|
|
|
{ }
|
|
|
|
}
|
|
|
|
|
2007-07-06 09:24:06 -06:00
|
|
|
inline int
|
|
|
|
strcmp(const int8_t* a, const int8_t* b)
|
|
|
|
{
|
|
|
|
return ::strcmp(reinterpret_cast<const char*>(a),
|
|
|
|
reinterpret_cast<const char*>(b));
|
|
|
|
}
|
|
|
|
|
2007-07-09 19:43:43 -06:00
|
|
|
void
|
|
|
|
noop();
|
|
|
|
|
2007-09-07 17:20:21 -06:00
|
|
|
class Reference {
|
|
|
|
public:
|
2007-09-29 21:33:38 -06:00
|
|
|
Reference(object target, Reference** handle):
|
2007-09-07 17:20:21 -06:00
|
|
|
target(target),
|
2007-09-29 21:33:38 -06:00
|
|
|
next(*handle),
|
2009-12-16 19:16:51 -07:00
|
|
|
handle(handle),
|
|
|
|
count(0)
|
2007-09-29 21:33:38 -06:00
|
|
|
{
|
|
|
|
if (next) {
|
|
|
|
next->handle = &next;
|
|
|
|
}
|
|
|
|
*handle = this;
|
|
|
|
}
|
2007-09-07 17:20:21 -06:00
|
|
|
|
|
|
|
object target;
|
|
|
|
Reference* next;
|
2007-09-29 21:33:38 -06:00
|
|
|
Reference** handle;
|
2009-12-16 19:16:51 -07:00
|
|
|
unsigned count;
|
2007-09-07 17:20:21 -06:00
|
|
|
};
|
|
|
|
|
2010-09-10 15:05:29 -06:00
|
|
|
class Classpath;
|
|
|
|
|
2007-07-06 09:24:06 -06:00
|
|
|
class Machine {
|
|
|
|
public:
|
2007-09-12 21:15:16 -06:00
|
|
|
enum Type {
|
2007-07-06 09:24:06 -06:00
|
|
|
#include "type-enums.cpp"
|
2007-09-12 21:15:16 -06:00
|
|
|
};
|
2007-07-06 09:24:06 -06:00
|
|
|
|
2008-01-09 18:20:36 -07:00
|
|
|
enum AllocationType {
|
|
|
|
MovableAllocation,
|
|
|
|
FixedAllocation,
|
|
|
|
ImmortalAllocation
|
2007-10-13 19:18:25 -06:00
|
|
|
};
|
|
|
|
|
2010-09-14 10:49:41 -06:00
|
|
|
enum Root {
|
|
|
|
BootLoader,
|
|
|
|
AppLoader,
|
|
|
|
BootstrapClassMap,
|
2010-09-22 13:58:46 -06:00
|
|
|
FindLoadedClassMethod,
|
|
|
|
LoadClassMethod,
|
2010-09-14 10:49:41 -06:00
|
|
|
MonitorMap,
|
|
|
|
StringMap,
|
|
|
|
ByteArrayMap,
|
2010-11-26 12:41:31 -07:00
|
|
|
ClassRuntimeDataTable,
|
|
|
|
MethodRuntimeDataTable,
|
2010-09-14 10:49:41 -06:00
|
|
|
JNIMethodTable,
|
2011-03-15 19:34:00 -06:00
|
|
|
JNIFieldTable,
|
2010-09-14 10:49:41 -06:00
|
|
|
ShutdownHooks,
|
2010-12-27 15:55:23 -07:00
|
|
|
FinalizerThread,
|
2010-09-14 10:49:41 -06:00
|
|
|
ObjectsToFinalize,
|
2011-03-25 19:11:38 -06:00
|
|
|
ObjectsToClean,
|
2010-09-14 10:49:41 -06:00
|
|
|
NullPointerException,
|
2010-12-19 17:47:21 -07:00
|
|
|
ArithmeticException,
|
2010-11-05 13:18:28 -06:00
|
|
|
ArrayIndexOutOfBoundsException,
|
2010-12-27 15:55:23 -07:00
|
|
|
OutOfMemoryError,
|
2010-11-05 13:18:28 -06:00
|
|
|
VirtualFileFinders,
|
|
|
|
VirtualFiles
|
2010-09-14 10:49:41 -06:00
|
|
|
};
|
|
|
|
|
2010-11-05 13:18:28 -06:00
|
|
|
static const unsigned RootCount = VirtualFiles + 1;
|
2010-09-14 10:49:41 -06:00
|
|
|
|
|
|
|
Machine(System* system, Heap* heap, Finder* bootFinder, Finder* appFinder,
|
|
|
|
Processor* processor, Classpath* classpath, const char** properties,
|
2010-09-10 15:05:29 -06:00
|
|
|
unsigned propertyCount);
|
2007-07-06 09:24:06 -06:00
|
|
|
|
|
|
|
~Machine() {
|
|
|
|
dispose();
|
|
|
|
}
|
|
|
|
|
|
|
|
void dispose();
|
|
|
|
|
2007-09-10 17:33:58 -06:00
|
|
|
JavaVMVTable* vtable;
|
2007-07-06 09:24:06 -06:00
|
|
|
System* system;
|
2008-01-13 15:05:08 -07:00
|
|
|
Heap::Client* heapClient;
|
2007-07-06 09:24:06 -06:00
|
|
|
Heap* heap;
|
2010-09-14 10:49:41 -06:00
|
|
|
Finder* bootFinder;
|
|
|
|
Finder* appFinder;
|
2007-09-23 19:39:03 -06:00
|
|
|
Processor* processor;
|
2010-09-10 15:05:29 -06:00
|
|
|
Classpath* classpath;
|
2007-07-06 09:24:06 -06:00
|
|
|
Thread* rootThread;
|
|
|
|
Thread* exclusive;
|
2009-08-24 17:51:31 -06:00
|
|
|
Thread* finalizeThread;
|
2007-09-07 17:20:21 -06:00
|
|
|
Reference* jniReferences;
|
2008-11-11 08:20:49 -07:00
|
|
|
const char** properties;
|
|
|
|
unsigned propertyCount;
|
2007-07-06 09:24:06 -06:00
|
|
|
unsigned activeCount;
|
|
|
|
unsigned liveCount;
|
2009-08-19 14:27:03 -06:00
|
|
|
unsigned daemonCount;
|
2007-10-28 13:14:53 -06:00
|
|
|
unsigned fixedFootprint;
|
2007-09-10 17:33:58 -06:00
|
|
|
System::Local* localThread;
|
2007-07-06 09:24:06 -06:00
|
|
|
System::Monitor* stateLock;
|
|
|
|
System::Monitor* heapLock;
|
|
|
|
System::Monitor* classLock;
|
2007-07-19 21:18:25 -06:00
|
|
|
System::Monitor* referenceLock;
|
2009-08-19 14:27:03 -06:00
|
|
|
System::Monitor* shutdownLock;
|
2008-01-29 08:19:15 -07:00
|
|
|
System::Library* libraries;
|
2011-03-15 17:27:17 -06:00
|
|
|
FILE* errorLog;
|
2007-07-06 09:24:06 -06:00
|
|
|
object types;
|
2010-09-14 10:49:41 -06:00
|
|
|
object roots;
|
2007-07-06 09:24:06 -06:00
|
|
|
object finalizers;
|
2007-07-09 19:43:43 -06:00
|
|
|
object tenuredFinalizers;
|
|
|
|
object finalizeQueue;
|
2007-07-06 09:24:06 -06:00
|
|
|
object weakReferences;
|
2007-07-09 19:43:43 -06:00
|
|
|
object tenuredWeakReferences;
|
2007-07-06 09:24:06 -06:00
|
|
|
bool unsafe;
|
2011-03-25 19:11:38 -06:00
|
|
|
bool collecting;
|
2009-06-10 18:15:00 -06:00
|
|
|
bool triedBuiltinOnLoad;
|
2011-02-02 08:46:20 -07:00
|
|
|
bool dumpedHeapOnOOM;
|
2007-09-10 17:33:58 -06:00
|
|
|
JavaVMVTable javaVMVTable;
|
2007-07-06 09:24:06 -06:00
|
|
|
JNIEnvVTable jniEnvVTable;
|
2008-11-22 14:47:18 -07:00
|
|
|
uintptr_t* heapPool[ThreadHeapPoolSize];
|
2007-08-22 08:50:29 -06:00
|
|
|
unsigned heapPoolIndex;
|
2007-07-06 09:24:06 -06:00
|
|
|
};
|
|
|
|
|
2007-07-28 15:28:25 -06:00
|
|
|
void
|
|
|
|
printTrace(Thread* t, object exception);
|
|
|
|
|
|
|
|
uint8_t&
|
|
|
|
threadInterrupted(Thread* t, object thread);
|
|
|
|
|
2007-10-23 16:21:28 -06:00
|
|
|
void
|
|
|
|
enterActiveState(Thread* t);
|
|
|
|
|
2008-01-13 15:05:08 -07:00
|
|
|
#ifdef VM_STRESS
|
|
|
|
|
|
|
|
inline void stress(Thread* t);
|
|
|
|
|
|
|
|
#else // not VM_STRESS
|
|
|
|
|
|
|
|
#define stress(t)
|
|
|
|
|
|
|
|
#endif // not VM_STRESS
|
|
|
|
|
2010-12-27 15:55:23 -07:00
|
|
|
uint64_t
|
|
|
|
runThread(Thread*, uintptr_t*);
|
2008-06-25 10:28:11 -06:00
|
|
|
|
2010-12-27 15:55:23 -07:00
|
|
|
uint64_t
|
|
|
|
run(Thread* t, uint64_t (*function)(Thread*, uintptr_t*),
|
|
|
|
uintptr_t* arguments);
|
2009-08-24 17:51:31 -06:00
|
|
|
|
avoid inifinite recursion if java.lang.Object is missing; refactoring
When trying to create an array class, we try to resolve
java.lang.Object so we can use its vtable in the array class.
However, if Object is missing, we'll try to create and throw a
ClassNotFoundException, which requires creating an array to store the
stack trace, which requires creating an array class, which requires
resolving Object, etc.. This commit short-circuits this process by
telling resolveClass not to create and throw an exception if it can't
find Object.
While doing the above work, I noticed that the implementations of
Classpath::makeThrowable in classpath-avian.cpp and
classpath-openjdk.cpp were identical, so I made makeThrowable a
top-level function.
Finally, I discovered that Thread.setDaemon can only be called before
the target thread has been started, which allowed me to simplify the
code to track daemon threads in the VM.
2010-12-09 19:38:12 -07:00
|
|
|
void
|
|
|
|
checkDaemon(Thread* t);
|
|
|
|
|
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();
|
|
|
|
|
2007-07-06 09:24:06 -06:00
|
|
|
class Thread {
|
|
|
|
public:
|
|
|
|
enum State {
|
|
|
|
NoState,
|
|
|
|
ActiveState,
|
|
|
|
IdleState,
|
|
|
|
ZombieState,
|
2007-07-17 19:33:00 -06:00
|
|
|
JoinedState,
|
2007-07-06 09:24:06 -06:00
|
|
|
ExclusiveState,
|
|
|
|
ExitState
|
|
|
|
};
|
|
|
|
|
2010-09-14 10:49:41 -06:00
|
|
|
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;
|
2010-11-16 10:50:19 -07:00
|
|
|
static const unsigned SystemFlag = 1 << 6;
|
2011-02-28 10:14:01 -07:00
|
|
|
static const unsigned DisposeFlag = 1 << 7;
|
2010-09-14 10:49:41 -06:00
|
|
|
|
2007-07-06 09:24:06 -06:00
|
|
|
class Protector {
|
|
|
|
public:
|
2007-10-12 11:56:43 -06:00
|
|
|
Protector(Thread* t): t(t), next(t->protector) {
|
2007-07-06 09:24:06 -06:00
|
|
|
t->protector = this;
|
|
|
|
}
|
|
|
|
|
2008-11-11 08:20:49 -07:00
|
|
|
~Protector() {
|
2007-07-06 09:24:06 -06:00
|
|
|
t->protector = next;
|
|
|
|
}
|
|
|
|
|
2007-10-12 11:56:43 -06:00
|
|
|
virtual void visit(Heap::Visitor* v) = 0;
|
|
|
|
|
2007-07-06 09:24:06 -06:00
|
|
|
Thread* t;
|
|
|
|
Protector* next;
|
|
|
|
};
|
|
|
|
|
2007-10-12 11:56:43 -06:00
|
|
|
class SingleProtector: public Protector {
|
|
|
|
public:
|
|
|
|
SingleProtector(Thread* t, object* p): Protector(t), p(p) { }
|
|
|
|
|
|
|
|
virtual void visit(Heap::Visitor* v) {
|
2007-10-28 13:14:53 -06:00
|
|
|
v->visit(p);
|
2007-10-12 11:56:43 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
object* p;
|
|
|
|
};
|
|
|
|
|
2010-12-27 15:55:23 -07:00
|
|
|
class Resource {
|
|
|
|
public:
|
|
|
|
Resource(Thread* t): t(t), next(t->resource) {
|
|
|
|
t->resource = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
~Resource() {
|
|
|
|
t->resource = next;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void release() = 0;
|
|
|
|
|
|
|
|
Thread* t;
|
|
|
|
Resource* next;
|
|
|
|
};
|
|
|
|
|
|
|
|
class ClassInitStack: public Resource {
|
2009-07-20 14:12:38 -06:00
|
|
|
public:
|
|
|
|
ClassInitStack(Thread* t, object class_):
|
2010-12-27 15:55:23 -07:00
|
|
|
Resource(t),
|
2009-07-20 14:12:38 -06:00
|
|
|
next(t->classInitStack),
|
|
|
|
class_(class_),
|
|
|
|
protector(t, &(this->class_))
|
|
|
|
{
|
|
|
|
t->classInitStack = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
~ClassInitStack() {
|
2010-12-27 15:55:23 -07:00
|
|
|
t->classInitStack = next;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void release() {
|
|
|
|
this->ClassInitStack::~ClassInitStack();
|
2009-07-20 14:12:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
ClassInitStack* next;
|
|
|
|
object class_;
|
|
|
|
SingleProtector protector;
|
|
|
|
};
|
|
|
|
|
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)
|
2010-12-27 15:55:23 -07:00
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual void unwind() {
|
|
|
|
void* stack = this->stack;
|
|
|
|
this->stack = 0;
|
|
|
|
expect(t->m->system, stack);
|
2011-01-27 21:06:01 -07:00
|
|
|
vmJump(voidPointer(vmRun_returnAddress), 0, stack, t, 0, 0);
|
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() {
|
2007-10-23 16:21:28 -06:00
|
|
|
enterActiveState(t);
|
|
|
|
|
2010-12-27 15:55:23 -07:00
|
|
|
vm::run(t, runThread, 0);
|
avoid inifinite recursion if java.lang.Object is missing; refactoring
When trying to create an array class, we try to resolve
java.lang.Object so we can use its vtable in the array class.
However, if Object is missing, we'll try to create and throw a
ClassNotFoundException, which requires creating an array to store the
stack trace, which requires creating an array class, which requires
resolving Object, etc.. This commit short-circuits this process by
telling resolveClass not to create and throw an exception if it can't
find Object.
While doing the above work, I noticed that the implementations of
Classpath::makeThrowable in classpath-avian.cpp and
classpath-openjdk.cpp were identical, so I made makeThrowable a
top-level function.
Finally, I discovered that Thread.setDaemon can only be called before
the target thread has been started, which allowed me to simplify the
code to track daemon threads in the VM.
2010-12-09 19:38:12 -07:00
|
|
|
|
2010-12-27 15:55:23 -07:00
|
|
|
if (t->exception) {
|
|
|
|
printTrace(t, t->exception);
|
2007-07-28 15:28:25 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
t->exit();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool interrupted() {
|
2011-02-15 21:44:27 -07:00
|
|
|
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);
|
2007-07-06 09:24:06 -06:00
|
|
|
|
2007-10-25 16:06:05 -06:00
|
|
|
void init();
|
2007-07-07 12:09:16 -06:00
|
|
|
void exit();
|
2007-07-06 09:24:06 -06:00
|
|
|
void dispose();
|
|
|
|
|
|
|
|
JNIEnvVTable* vtable;
|
2007-09-23 19:39:03 -06:00
|
|
|
Machine* m;
|
2007-07-07 12:09:16 -06:00
|
|
|
Thread* parent;
|
|
|
|
Thread* peer;
|
2007-07-06 09:24:06 -06:00
|
|
|
Thread* child;
|
2010-02-04 17:56:21 -07:00
|
|
|
Thread* waitNext;
|
2007-07-06 09:24:06 -06:00
|
|
|
State state;
|
2007-09-07 17:20:21 -06:00
|
|
|
unsigned criticalLevel;
|
2007-07-07 12:09:16 -06:00
|
|
|
System::Thread* systemThread;
|
2010-02-04 17:56:21 -07:00
|
|
|
System::Monitor* lock;
|
2007-07-07 12:09:16 -06:00
|
|
|
object javaThread;
|
2007-07-06 09:24:06 -06:00
|
|
|
object exception;
|
|
|
|
unsigned heapIndex;
|
2007-08-22 20:24:25 -06:00
|
|
|
unsigned heapOffset;
|
2007-07-06 09:24:06 -06:00
|
|
|
Protector* protector;
|
2009-07-20 14:12:38 -06:00
|
|
|
ClassInitStack* classInitStack;
|
2010-12-27 15:55:23 -07:00
|
|
|
Resource* resource;
|
|
|
|
Checkpoint* checkpoint;
|
2007-07-28 15:28:25 -06:00
|
|
|
Runnable runnable;
|
2007-09-06 18:21:52 -06:00
|
|
|
uintptr_t* defaultHeap;
|
2007-09-12 21:15:16 -06:00
|
|
|
uintptr_t* heap;
|
2010-06-19 16:40:21 -06:00
|
|
|
uintptr_t backupHeap[ThreadBackupHeapSizeInWords];
|
2008-04-09 13:08:13 -06:00
|
|
|
unsigned backupHeapIndex;
|
2010-09-14 10:49:41 -06:00
|
|
|
unsigned flags;
|
2007-07-06 09:24:06 -06:00
|
|
|
};
|
|
|
|
|
2010-09-10 15:05:29 -06:00
|
|
|
class Classpath {
|
|
|
|
public:
|
|
|
|
virtual object
|
|
|
|
makeJclass(Thread* t, object 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 void
|
|
|
|
runThread(Thread* t) = 0;
|
|
|
|
|
2011-04-10 11:26:44 -06:00
|
|
|
virtual void
|
|
|
|
resolveNative(Thread* t, object method) = 0;
|
|
|
|
|
2010-09-10 15:05:29 -06:00
|
|
|
virtual void
|
|
|
|
boot(Thread* t) = 0;
|
|
|
|
|
2010-09-20 17:31:23 -06:00
|
|
|
virtual const char*
|
|
|
|
bootClasspath() = 0;
|
|
|
|
|
2010-09-10 15:05:29 -06:00
|
|
|
virtual void
|
|
|
|
dispose() = 0;
|
|
|
|
};
|
|
|
|
|
2010-12-27 15:55:23 -07:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
|
|
|
|
template <class T>
|
2011-02-02 08:15:07 -07:00
|
|
|
class ThreadRuntimeArray: public Thread::Resource {
|
2010-12-27 15:55:23 -07:00
|
|
|
public:
|
2011-02-02 08:15:07 -07:00
|
|
|
ThreadRuntimeArray(Thread* t, unsigned size):
|
2010-12-27 15:55:23 -07:00
|
|
|
Resource(t),
|
|
|
|
body(static_cast<T*>(t->m->heap->allocate(size * sizeof(T)))),
|
|
|
|
size(size)
|
|
|
|
{ }
|
|
|
|
|
2011-02-02 08:15:07 -07:00
|
|
|
~ThreadRuntimeArray() {
|
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();
|
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);
|
2010-12-27 15:55:23 -07:00
|
|
|
|
|
|
|
#else // not _MSC_VER
|
|
|
|
|
|
|
|
# define THREAD_RUNTIME_ARRAY(thread, type, name, size) type name[size];
|
|
|
|
|
|
|
|
#endif // not _MSC_VER
|
|
|
|
|
2010-09-10 15:05:29 -06:00
|
|
|
Classpath*
|
2010-11-05 13:18:28 -06:00
|
|
|
makeClasspath(System* system, Allocator* allocator, const char* javaHome,
|
|
|
|
const char* embedPrefix);
|
2010-09-10 15:05:29 -06:00
|
|
|
|
2009-06-01 12:12:29 -06:00
|
|
|
typedef uint64_t (JNICALL *FastNativeFunction)(Thread*, object, uintptr_t*);
|
2009-05-03 14:57:11 -06:00
|
|
|
|
2007-07-06 09:24:06 -06:00
|
|
|
inline object
|
|
|
|
objectClass(Thread*, object o)
|
|
|
|
{
|
|
|
|
return mask(cast<object>(o, 0));
|
|
|
|
}
|
|
|
|
|
2007-07-15 19:03:02 -06:00
|
|
|
void
|
|
|
|
enter(Thread* t, Thread::State state);
|
2007-07-06 09:24:06 -06:00
|
|
|
|
2007-10-23 16:21:28 -06:00
|
|
|
inline void
|
|
|
|
enterActiveState(Thread* t)
|
|
|
|
{
|
|
|
|
enter(t, Thread::ActiveState);
|
|
|
|
}
|
|
|
|
|
2010-12-27 15:55:23 -07:00
|
|
|
class StateResource: public Thread::Resource {
|
2007-07-06 09:24:06 -06:00
|
|
|
public:
|
2010-12-27 15:55:23 -07:00
|
|
|
StateResource(Thread* t, Thread::State state):
|
|
|
|
Resource(t), oldState(t->state)
|
|
|
|
{
|
2007-07-06 09:24:06 -06:00
|
|
|
enter(t, state);
|
|
|
|
}
|
|
|
|
|
|
|
|
~StateResource() { enter(t, oldState); }
|
|
|
|
|
2010-12-27 15:55:23 -07:00
|
|
|
virtual void release() {
|
|
|
|
this->StateResource::~StateResource();
|
|
|
|
}
|
|
|
|
|
2007-07-06 09:24:06 -06:00
|
|
|
private:
|
|
|
|
Thread::State oldState;
|
|
|
|
};
|
|
|
|
|
2007-09-29 21:33:38 -06:00
|
|
|
inline void
|
|
|
|
dispose(Thread* t, Reference* r)
|
|
|
|
{
|
|
|
|
*(r->handle) = r->next;
|
2007-10-08 15:41:41 -06:00
|
|
|
if (r->next) {
|
|
|
|
r->next->handle = r->handle;
|
|
|
|
}
|
2008-04-13 12:15:04 -06:00
|
|
|
t->m->heap->free(r, sizeof(*r));
|
2007-09-29 21:33:38 -06:00
|
|
|
}
|
|
|
|
|
2009-12-16 19:16:51 -07:00
|
|
|
inline void
|
|
|
|
acquire(Thread*, Reference* r)
|
|
|
|
{
|
|
|
|
++ r->count;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
release(Thread* t, Reference* r)
|
|
|
|
{
|
|
|
|
if ((-- r->count) == 0) {
|
|
|
|
dispose(t, r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-15 19:03:02 -06:00
|
|
|
void
|
|
|
|
collect(Thread* t, Heap::CollectionType type);
|
|
|
|
|
2009-08-19 14:27:03 -06:00
|
|
|
void
|
|
|
|
shutDown(Thread* t);
|
|
|
|
|
2007-07-15 19:03:02 -06:00
|
|
|
#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)
|
|
|
|
{
|
2010-09-16 19:43:27 -06:00
|
|
|
atomicOr(&(t->flags), Thread::StressFlag);
|
2007-07-15 19:03:02 -06:00
|
|
|
|
|
|
|
# ifdef VM_STRESS_MAJOR
|
2010-09-16 19:43:27 -06:00
|
|
|
collect(t, Heap::MajorCollection);
|
2007-07-15 19:03:02 -06:00
|
|
|
# else // not VM_STRESS_MAJOR
|
2010-09-16 19:43:27 -06:00
|
|
|
collect(t, Heap::MinorCollection);
|
2007-07-15 19:03:02 -06:00
|
|
|
# endif // not VM_STRESS_MAJOR
|
|
|
|
|
2010-09-16 19:43:27 -06:00
|
|
|
atomicAnd(&(t->flags), ~Thread::StressFlag);
|
2007-07-15 19:03:02 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // not VM_STRESS
|
|
|
|
|
2007-08-01 17:48:36 -06:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2010-12-27 15:55:23 -07:00
|
|
|
class MonitorResource: public Thread::Resource {
|
2007-07-06 09:24:06 -06:00
|
|
|
public:
|
2010-12-27 15:55:23 -07:00
|
|
|
MonitorResource(Thread* t, System::Monitor* m):
|
|
|
|
Resource(t), m(m)
|
|
|
|
{
|
2007-08-01 17:48:36 -06:00
|
|
|
acquire(t, m);
|
2007-07-06 09:24:06 -06:00
|
|
|
}
|
|
|
|
|
2007-08-01 17:48:36 -06:00
|
|
|
~MonitorResource() {
|
2010-12-27 15:55:23 -07:00
|
|
|
vm::release(t, m);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void release() {
|
|
|
|
this->MonitorResource::~MonitorResource();
|
2007-08-01 17:48:36 -06:00
|
|
|
}
|
2007-07-06 09:24:06 -06:00
|
|
|
|
|
|
|
private:
|
|
|
|
System::Monitor* m;
|
|
|
|
};
|
|
|
|
|
2010-12-27 15:55:23 -07:00
|
|
|
class RawMonitorResource: public Thread::Resource {
|
2007-07-06 09:24:06 -06:00
|
|
|
public:
|
2010-12-27 15:55:23 -07:00
|
|
|
RawMonitorResource(Thread* t, System::Monitor* m):
|
|
|
|
Resource(t), m(m)
|
|
|
|
{
|
2007-08-13 18:37:00 -06:00
|
|
|
m->acquire(t->systemThread);
|
2007-07-06 09:24:06 -06:00
|
|
|
}
|
|
|
|
|
2007-08-01 17:48:36 -06:00
|
|
|
~RawMonitorResource() {
|
2010-12-27 15:55:23 -07:00
|
|
|
vm::release(t, m);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void release() {
|
|
|
|
this->RawMonitorResource::~RawMonitorResource();
|
2007-08-01 17:48:36 -06:00
|
|
|
}
|
2007-07-06 09:24:06 -06:00
|
|
|
|
|
|
|
private:
|
|
|
|
System::Monitor* m;
|
|
|
|
};
|
|
|
|
|
|
|
|
inline void NO_RETURN
|
|
|
|
abort(Thread* t)
|
|
|
|
{
|
2007-09-23 19:39:03 -06:00
|
|
|
abort(t->m->system);
|
2007-07-06 09:24:06 -06:00
|
|
|
}
|
|
|
|
|
2007-08-19 13:45:51 -06:00
|
|
|
#ifndef NDEBUG
|
2007-07-06 09:24:06 -06:00
|
|
|
inline void
|
|
|
|
assert(Thread* t, bool v)
|
|
|
|
{
|
2007-09-23 19:39:03 -06:00
|
|
|
assert(t->m->system, v);
|
2007-07-06 09:24:06 -06:00
|
|
|
}
|
2007-08-19 13:45:51 -06:00
|
|
|
#endif // not NDEBUG
|
2007-07-06 09:24:06 -06:00
|
|
|
|
|
|
|
inline void
|
|
|
|
expect(Thread* t, bool v)
|
|
|
|
{
|
2007-09-23 19:39:03 -06:00
|
|
|
expect(t->m->system, v);
|
2007-07-06 09:24:06 -06:00
|
|
|
}
|
|
|
|
|
2008-12-01 19:38:00 -07:00
|
|
|
class FixedAllocator: public Allocator {
|
|
|
|
public:
|
2009-04-05 15:42:10 -06:00
|
|
|
FixedAllocator(System* s, uint8_t* base, unsigned capacity):
|
|
|
|
s(s), base(base), offset(0), capacity(capacity)
|
2008-12-01 19:38:00 -07:00
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual void* tryAllocate(unsigned) {
|
2009-04-05 15:42:10 -06:00
|
|
|
abort(s);
|
2008-12-01 19:38:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void* allocate(unsigned size) {
|
|
|
|
unsigned paddedSize = pad(size);
|
2009-04-05 15:42:10 -06:00
|
|
|
expect(s, offset + paddedSize < capacity);
|
2008-12-01 19:38:00 -07:00
|
|
|
|
|
|
|
void* p = base + offset;
|
|
|
|
offset += paddedSize;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2010-12-27 15:55:23 -07:00
|
|
|
virtual void free(const void* p, unsigned size) {
|
|
|
|
if (p >= base and static_cast<const uint8_t*>(p) + size == base + offset) {
|
|
|
|
offset -= size;
|
|
|
|
} else {
|
|
|
|
abort(s);
|
|
|
|
}
|
2008-12-01 19:38:00 -07:00
|
|
|
}
|
|
|
|
|
2009-04-05 15:42:10 -06:00
|
|
|
System* s;
|
2008-12-01 19:38:00 -07:00
|
|
|
uint8_t* base;
|
|
|
|
unsigned offset;
|
|
|
|
unsigned capacity;
|
|
|
|
};
|
|
|
|
|
2010-06-19 16:40:21 -06:00
|
|
|
inline bool
|
2008-04-09 13:08:13 -06:00
|
|
|
ensure(Thread* t, unsigned sizeInBytes)
|
|
|
|
{
|
|
|
|
if (t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
2008-11-22 14:47:18 -07:00
|
|
|
> ThreadHeapSizeInWords)
|
2008-04-09 13:08:13 -06:00
|
|
|
{
|
2010-06-19 16:40:21 -06:00
|
|
|
if (sizeInBytes <= ThreadBackupHeapSizeInBytes) {
|
2010-09-14 10:49:41 -06:00
|
|
|
expect(t, (t->flags & Thread::UseBackupHeapFlag) == 0);
|
2009-03-03 20:05:48 -07:00
|
|
|
|
2010-09-14 10:49:41 -06:00
|
|
|
atomicOr(&(t->flags), Thread::UseBackupHeapFlag);
|
2009-03-03 20:05:48 -07:00
|
|
|
|
2010-06-19 16:40:21 -06:00
|
|
|
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
|
2008-01-09 18:20:36 -07:00
|
|
|
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);
|
2007-07-06 09:24:06 -06:00
|
|
|
|
|
|
|
inline object
|
|
|
|
allocateSmall(Thread* t, unsigned sizeInBytes)
|
|
|
|
{
|
2009-07-17 19:37:46 -06:00
|
|
|
assert(t, t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
|
|
|
<= ThreadHeapSizeInWords);
|
|
|
|
|
2007-09-06 18:21:52 -06:00
|
|
|
object o = reinterpret_cast<object>(t->heap + t->heapIndex);
|
2007-07-25 18:48:28 -06:00
|
|
|
t->heapIndex += ceiling(sizeInBytes, BytesPerWord);
|
2007-07-06 09:24:06 -06:00
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline object
|
2007-10-27 19:54:30 -06:00
|
|
|
allocate(Thread* t, unsigned sizeInBytes, bool objectMask)
|
2007-07-06 09:24:06 -06:00
|
|
|
{
|
2007-07-15 19:03:02 -06:00
|
|
|
stress(t);
|
|
|
|
|
2007-07-25 18:48:28 -06:00
|
|
|
if (UNLIKELY(t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
2008-11-22 14:47:18 -07:00
|
|
|
> ThreadHeapSizeInWords
|
2007-09-23 19:39:03 -06:00
|
|
|
or t->m->exclusive))
|
2007-07-06 09:24:06 -06:00
|
|
|
{
|
2008-01-09 18:20:36 -07:00
|
|
|
return allocate2(t, sizeInBytes, objectMask);
|
2007-07-06 09:24:06 -06:00
|
|
|
} else {
|
|
|
|
return allocateSmall(t, sizeInBytes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-28 13:14:53 -06:00
|
|
|
inline void
|
|
|
|
mark(Thread* t, object o, unsigned offset, unsigned count)
|
|
|
|
{
|
2009-11-19 18:13:00 -07:00
|
|
|
t->m->heap->mark(o, offset / BytesPerWord, count);
|
2007-10-28 13:14:53 -06:00
|
|
|
}
|
2007-07-06 09:24:06 -06:00
|
|
|
|
2007-10-28 13:14:53 -06:00
|
|
|
inline void
|
|
|
|
mark(Thread* t, object o, unsigned offset)
|
|
|
|
{
|
2009-11-19 18:13:00 -07:00
|
|
|
t->m->heap->mark(o, offset / BytesPerWord, 1);
|
2007-10-28 13:14:53 -06:00
|
|
|
}
|
2007-10-27 19:54:30 -06:00
|
|
|
|
2008-07-05 14:21:13 -06:00
|
|
|
inline void
|
2007-10-22 11:22:30 -06:00
|
|
|
set(Thread* t, object target, unsigned offset, object value)
|
2007-07-16 17:58:37 -06:00
|
|
|
{
|
2007-10-22 11:22:30 -06:00
|
|
|
cast<object>(target, offset) = value;
|
|
|
|
mark(t, target, offset);
|
2007-07-16 17:58:37 -06:00
|
|
|
}
|
|
|
|
|
2007-07-14 11:31:01 -06:00
|
|
|
inline void
|
2008-01-09 18:20:36 -07:00
|
|
|
setObjectClass(Thread*, object o, object value)
|
2007-07-14 11:31:01 -06:00
|
|
|
{
|
2008-01-09 18:20:36 -07:00
|
|
|
cast<object>(o, 0)
|
|
|
|
= reinterpret_cast<object>
|
2011-02-14 11:47:59 -07:00
|
|
|
(reinterpret_cast<intptr_alias_t>(value)
|
|
|
|
| (reinterpret_cast<intptr_alias_t>
|
|
|
|
(cast<object>(o, 0)) & (~PointerMask)));
|
2007-07-14 11:31:01 -06:00
|
|
|
}
|
|
|
|
|
2008-11-11 08:20:49 -07:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2007-07-06 09:24:06 -06:00
|
|
|
object&
|
|
|
|
arrayBodyUnsafe(Thread*, object, unsigned);
|
|
|
|
|
2007-11-04 14:15:28 -07:00
|
|
|
bool
|
|
|
|
instanceOf(Thread* t, object class_, object o);
|
|
|
|
|
2007-07-06 09:24:06 -06:00
|
|
|
#include "type-declarations.cpp"
|
|
|
|
|
2010-12-27 15:55:23 -07:00
|
|
|
inline uint64_t
|
2011-02-01 17:45:43 -07:00
|
|
|
runRaw(Thread* t,
|
|
|
|
uint64_t (*function)(Thread*, uintptr_t*), uintptr_t* arguments)
|
2010-12-27 15:55:23 -07:00
|
|
|
{
|
|
|
|
Thread::RunCheckpoint checkpoint(t);
|
|
|
|
return vmRun(function, arguments, &checkpoint);
|
|
|
|
}
|
|
|
|
|
2011-02-01 17:45:43 -07:00
|
|
|
inline uint64_t
|
|
|
|
run(Thread* t, uint64_t (*function)(Thread*, uintptr_t*), uintptr_t* arguments)
|
|
|
|
{
|
|
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
return runRaw(t, function, arguments);
|
|
|
|
}
|
|
|
|
|
2010-12-01 15:42:46 -07:00
|
|
|
inline void
|
|
|
|
runJavaThread(Thread* t)
|
|
|
|
{
|
|
|
|
t->m->classpath->runThread(t);
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
avoid inifinite recursion if java.lang.Object is missing; refactoring
When trying to create an array class, we try to resolve
java.lang.Object so we can use its vtable in the array class.
However, if Object is missing, we'll try to create and throw a
ClassNotFoundException, which requires creating an array to store the
stack trace, which requires creating an array class, which requires
resolving Object, etc.. This commit short-circuits this process by
telling resolveClass not to create and throw an exception if it can't
find Object.
While doing the above work, I noticed that the implementations of
Classpath::makeThrowable in classpath-avian.cpp and
classpath-openjdk.cpp were identical, so I made makeThrowable a
top-level function.
Finally, I discovered that Thread.setDaemon can only be called before
the target thread has been started, which allowed me to simplify the
code to track daemon threads in the VM.
2010-12-09 19:38:12 -07:00
|
|
|
inline bool
|
|
|
|
startThread(Thread* t, Thread* p)
|
|
|
|
{
|
|
|
|
return t->m->system->success(t->m->system->start(&(p->runnable)));
|
|
|
|
}
|
|
|
|
|
2010-12-20 19:00:23 -07:00
|
|
|
inline void
|
|
|
|
addThread(Thread* t, Thread* p)
|
|
|
|
{
|
|
|
|
ACQUIRE_RAW(t, t->m->stateLock);
|
|
|
|
|
|
|
|
assert(t, p->state == Thread::NoState);
|
|
|
|
|
|
|
|
p->state = Thread::IdleState;
|
|
|
|
++ t->m->liveCount;
|
|
|
|
|
|
|
|
p->peer = p->parent->child;
|
|
|
|
p->parent->child = p;
|
2011-02-11 21:13:11 -07:00
|
|
|
|
2011-02-15 08:47:48 -07:00
|
|
|
if (p->javaThread) {
|
|
|
|
threadPeer(t, p->javaThread) = reinterpret_cast<jlong>(p);
|
|
|
|
}
|
2010-12-20 19:00:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
removeThread(Thread* t, Thread* p)
|
|
|
|
{
|
|
|
|
ACQUIRE_RAW(t, t->m->stateLock);
|
|
|
|
|
|
|
|
assert(t, p->state == Thread::IdleState);
|
|
|
|
|
|
|
|
-- t->m->liveCount;
|
|
|
|
|
|
|
|
t->m->stateLock->notifyAll(t->systemThread);
|
|
|
|
|
|
|
|
p->parent->child = p->peer;
|
2011-02-11 21:13:11 -07:00
|
|
|
|
2011-02-15 08:47:48 -07:00
|
|
|
if (p->javaThread) {
|
|
|
|
threadPeer(t, p->javaThread) = 0;
|
|
|
|
}
|
2010-12-20 19:00:23 -07:00
|
|
|
}
|
|
|
|
|
avoid inifinite recursion if java.lang.Object is missing; refactoring
When trying to create an array class, we try to resolve
java.lang.Object so we can use its vtable in the array class.
However, if Object is missing, we'll try to create and throw a
ClassNotFoundException, which requires creating an array to store the
stack trace, which requires creating an array class, which requires
resolving Object, etc.. This commit short-circuits this process by
telling resolveClass not to create and throw an exception if it can't
find Object.
While doing the above work, I noticed that the implementations of
Classpath::makeThrowable in classpath-avian.cpp and
classpath-openjdk.cpp were identical, so I made makeThrowable a
top-level function.
Finally, I discovered that Thread.setDaemon can only be called before
the target thread has been started, which allowed me to simplify the
code to track daemon threads in the VM.
2010-12-09 19:38:12 -07:00
|
|
|
inline Thread*
|
|
|
|
startThread(Thread* t, object javaThread)
|
|
|
|
{
|
|
|
|
Thread* p = t->m->processor->makeThread(t->m, javaThread, t);
|
|
|
|
|
2010-12-20 19:00:23 -07:00
|
|
|
addThread(t, p);
|
|
|
|
|
avoid inifinite recursion if java.lang.Object is missing; refactoring
When trying to create an array class, we try to resolve
java.lang.Object so we can use its vtable in the array class.
However, if Object is missing, we'll try to create and throw a
ClassNotFoundException, which requires creating an array to store the
stack trace, which requires creating an array class, which requires
resolving Object, etc.. This commit short-circuits this process by
telling resolveClass not to create and throw an exception if it can't
find Object.
While doing the above work, I noticed that the implementations of
Classpath::makeThrowable in classpath-avian.cpp and
classpath-openjdk.cpp were identical, so I made makeThrowable a
top-level function.
Finally, I discovered that Thread.setDaemon can only be called before
the target thread has been started, which allowed me to simplify the
code to track daemon threads in the VM.
2010-12-09 19:38:12 -07:00
|
|
|
if (startThread(t, p)) {
|
|
|
|
return p;
|
|
|
|
} else {
|
2010-12-20 19:00:23 -07:00
|
|
|
removeThread(t, p);
|
avoid inifinite recursion if java.lang.Object is missing; refactoring
When trying to create an array class, we try to resolve
java.lang.Object so we can use its vtable in the array class.
However, if Object is missing, we'll try to create and throw a
ClassNotFoundException, which requires creating an array to store the
stack trace, which requires creating an array class, which requires
resolving Object, etc.. This commit short-circuits this process by
telling resolveClass not to create and throw an exception if it can't
find Object.
While doing the above work, I noticed that the implementations of
Classpath::makeThrowable in classpath-avian.cpp and
classpath-openjdk.cpp were identical, so I made makeThrowable a
top-level function.
Finally, I discovered that Thread.setDaemon can only be called before
the target thread has been started, which allowed me to simplify the
code to track daemon threads in the VM.
2010-12-09 19:38:12 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
registerDaemon(Thread* t)
|
|
|
|
{
|
|
|
|
ACQUIRE_RAW(t, t->m->stateLock);
|
|
|
|
|
|
|
|
atomicOr(&(t->flags), Thread::DaemonFlag);
|
|
|
|
|
|
|
|
++ t->m->daemonCount;
|
|
|
|
|
|
|
|
t->m->stateLock->notifyAll(t->systemThread);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
checkDaemon(Thread* t)
|
|
|
|
{
|
|
|
|
if (threadDaemon(t, t->javaThread)) {
|
|
|
|
registerDaemon(t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-27 15:55:23 -07:00
|
|
|
inline uint64_t
|
|
|
|
initAttachedThread(Thread* t, uintptr_t* arguments)
|
avoid inifinite recursion if java.lang.Object is missing; refactoring
When trying to create an array class, we try to resolve
java.lang.Object so we can use its vtable in the array class.
However, if Object is missing, we'll try to create and throw a
ClassNotFoundException, which requires creating an array to store the
stack trace, which requires creating an array class, which requires
resolving Object, etc.. This commit short-circuits this process by
telling resolveClass not to create and throw an exception if it can't
find Object.
While doing the above work, I noticed that the implementations of
Classpath::makeThrowable in classpath-avian.cpp and
classpath-openjdk.cpp were identical, so I made makeThrowable a
top-level function.
Finally, I discovered that Thread.setDaemon can only be called before
the target thread has been started, which allowed me to simplify the
code to track daemon threads in the VM.
2010-12-09 19:38:12 -07:00
|
|
|
{
|
2010-12-27 15:55:23 -07:00
|
|
|
bool daemon = arguments[0];
|
avoid inifinite recursion if java.lang.Object is missing; refactoring
When trying to create an array class, we try to resolve
java.lang.Object so we can use its vtable in the array class.
However, if Object is missing, we'll try to create and throw a
ClassNotFoundException, which requires creating an array to store the
stack trace, which requires creating an array class, which requires
resolving Object, etc.. This commit short-circuits this process by
telling resolveClass not to create and throw an exception if it can't
find Object.
While doing the above work, I noticed that the implementations of
Classpath::makeThrowable in classpath-avian.cpp and
classpath-openjdk.cpp were identical, so I made makeThrowable a
top-level function.
Finally, I discovered that Thread.setDaemon can only be called before
the target thread has been started, which allowed me to simplify the
code to track daemon threads in the VM.
2010-12-09 19:38:12 -07:00
|
|
|
|
2010-12-27 15:55:23 -07:00
|
|
|
t->javaThread = t->m->classpath->makeThread(t, t->m->rootThread);
|
avoid inifinite recursion if java.lang.Object is missing; refactoring
When trying to create an array class, we try to resolve
java.lang.Object so we can use its vtable in the array class.
However, if Object is missing, we'll try to create and throw a
ClassNotFoundException, which requires creating an array to store the
stack trace, which requires creating an array class, which requires
resolving Object, etc.. This commit short-circuits this process by
telling resolveClass not to create and throw an exception if it can't
find Object.
While doing the above work, I noticed that the implementations of
Classpath::makeThrowable in classpath-avian.cpp and
classpath-openjdk.cpp were identical, so I made makeThrowable a
top-level function.
Finally, I discovered that Thread.setDaemon can only be called before
the target thread has been started, which allowed me to simplify the
code to track daemon threads in the VM.
2010-12-09 19:38:12 -07:00
|
|
|
|
|
|
|
threadPeer(t, t->javaThread) = reinterpret_cast<jlong>(t);
|
|
|
|
|
|
|
|
if (daemon) {
|
|
|
|
threadDaemon(t, t->javaThread) = true;
|
|
|
|
|
|
|
|
registerDaemon(t);
|
|
|
|
}
|
|
|
|
|
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);
|
avoid inifinite recursion if java.lang.Object is missing; refactoring
When trying to create an array class, we try to resolve
java.lang.Object so we can use its vtable in the array class.
However, if Object is missing, we'll try to create and throw a
ClassNotFoundException, which requires creating an array to store the
stack trace, which requires creating an array class, which requires
resolving Object, etc.. This commit short-circuits this process by
telling resolveClass not to create and throw an exception if it can't
find Object.
While doing the above work, I noticed that the implementations of
Classpath::makeThrowable in classpath-avian.cpp and
classpath-openjdk.cpp were identical, so I made makeThrowable a
top-level function.
Finally, I discovered that Thread.setDaemon can only be called before
the target thread has been started, which allowed me to simplify the
code to track daemon threads in the VM.
2010-12-09 19:38:12 -07:00
|
|
|
|
2011-02-15 21:44:27 -07:00
|
|
|
uintptr_t arguments[] = { daemon };
|
|
|
|
|
2010-12-27 15:55:23 -07:00
|
|
|
if (run(t, initAttachedThread, arguments)) {
|
|
|
|
enter(t, Thread::IdleState);
|
|
|
|
return t;
|
|
|
|
} else {
|
|
|
|
t->exit();
|
|
|
|
return 0;
|
|
|
|
}
|
avoid inifinite recursion if java.lang.Object is missing; refactoring
When trying to create an array class, we try to resolve
java.lang.Object so we can use its vtable in the array class.
However, if Object is missing, we'll try to create and throw a
ClassNotFoundException, which requires creating an array to store the
stack trace, which requires creating an array class, which requires
resolving Object, etc.. This commit short-circuits this process by
telling resolveClass not to create and throw an exception if it can't
find Object.
While doing the above work, I noticed that the implementations of
Classpath::makeThrowable in classpath-avian.cpp and
classpath-openjdk.cpp were identical, so I made makeThrowable a
top-level function.
Finally, I discovered that Thread.setDaemon can only be called before
the target thread has been started, which allowed me to simplify the
code to track daemon threads in the VM.
2010-12-09 19:38:12 -07:00
|
|
|
}
|
|
|
|
|
2010-09-14 10:49:41 -06:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline object
|
|
|
|
type(Thread* t, Machine::Type type)
|
|
|
|
{
|
|
|
|
return arrayBody(t, t->m->types, type);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
setType(Thread* t, Machine::Type type, object value)
|
|
|
|
{
|
|
|
|
set(t, t->m->types, ArrayBody + (type * BytesPerWord), value);
|
|
|
|
}
|
|
|
|
|
2007-10-22 11:22:30 -06:00
|
|
|
inline bool
|
|
|
|
objectFixed(Thread*, object o)
|
|
|
|
{
|
2011-02-14 11:47:59 -07:00
|
|
|
return (alias(o, 0) & (~PointerMask)) == FixedMark;
|
2007-10-22 11:22:30 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
inline bool
|
|
|
|
objectExtended(Thread*, object o)
|
|
|
|
{
|
2011-02-14 11:47:59 -07:00
|
|
|
return (alias(o, 0) & (~PointerMask)) == ExtendedMark;
|
2007-10-22 11:22:30 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
inline bool
|
|
|
|
hashTaken(Thread*, object o)
|
|
|
|
{
|
2011-02-14 11:47:59 -07:00
|
|
|
return (alias(o, 0) & (~PointerMask)) == HashTakenMark;
|
2007-10-22 11:22:30 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
inline unsigned
|
|
|
|
baseSize(Thread* t, object o, object class_)
|
|
|
|
{
|
|
|
|
return ceiling(classFixedSize(t, class_), BytesPerWord)
|
|
|
|
+ ceiling(classArrayElementSize(t, class_)
|
|
|
|
* cast<uintptr_t>(o, classFixedSize(t, class_) - BytesPerWord),
|
|
|
|
BytesPerWord);
|
|
|
|
}
|
|
|
|
|
2007-07-06 09:24:06 -06:00
|
|
|
object
|
2007-11-25 16:00:55 -07:00
|
|
|
makeTrace(Thread* t, Processor::StackWalker* walker);
|
2007-07-06 09:24:06 -06:00
|
|
|
|
2007-11-25 16:00:55 -07:00
|
|
|
object
|
2008-04-09 13:08:13 -06:00
|
|
|
makeTrace(Thread* t, Thread* target);
|
|
|
|
|
|
|
|
inline object
|
|
|
|
makeTrace(Thread* t)
|
|
|
|
{
|
|
|
|
return makeTrace(t, t);
|
|
|
|
}
|
2007-07-06 09:24:06 -06:00
|
|
|
|
2008-07-05 14:21:13 -06:00
|
|
|
inline object
|
2007-09-27 16:20:54 -06:00
|
|
|
makeNew(Thread* t, object class_)
|
|
|
|
{
|
2010-09-10 15:05:29 -06:00
|
|
|
assert(t, t->state == Thread::NoState or t->state == Thread::ActiveState);
|
2008-01-17 18:27:44 -07:00
|
|
|
|
2007-09-27 16:20:54 -06:00
|
|
|
PROTECT(t, class_);
|
|
|
|
unsigned sizeInBytes = pad(classFixedSize(t, class_));
|
2009-08-18 14:26:28 -06:00
|
|
|
assert(t, sizeInBytes);
|
2007-10-27 19:54:30 -06:00
|
|
|
object instance = allocate(t, sizeInBytes, classObjectMask(t, class_));
|
|
|
|
setObjectClass(t, instance, class_);
|
2007-09-27 16:20:54 -06:00
|
|
|
|
|
|
|
return instance;
|
|
|
|
}
|
|
|
|
|
2009-07-21 18:57:55 -06:00
|
|
|
object
|
|
|
|
makeNewGeneral(Thread* t, object class_);
|
2007-09-27 16:20:54 -06:00
|
|
|
|
|
|
|
inline object
|
|
|
|
make(Thread* t, object class_)
|
|
|
|
{
|
2009-07-21 18:57:55 -06:00
|
|
|
if (UNLIKELY(classVmFlags(t, class_)
|
|
|
|
& (WeakReferenceFlag | HasFinalizerFlag)))
|
|
|
|
{
|
|
|
|
return makeNewGeneral(t, class_);
|
2007-09-27 16:20:54 -06:00
|
|
|
} else {
|
|
|
|
return makeNew(t, class_);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-27 15:55:23 -07:00
|
|
|
object
|
|
|
|
makeByteArray(Thread* t, const char* format, va_list a);
|
|
|
|
|
2007-07-06 09:24:06 -06:00
|
|
|
object
|
|
|
|
makeByteArray(Thread* t, const char* format, ...);
|
|
|
|
|
|
|
|
object
|
|
|
|
makeString(Thread* t, const char* format, ...);
|
|
|
|
|
2010-04-20 10:03:07 -06:00
|
|
|
int
|
2010-09-10 15:05:29 -06:00
|
|
|
stringUTFLength(Thread* t, object string, unsigned start, unsigned length);
|
|
|
|
|
|
|
|
inline int
|
|
|
|
stringUTFLength(Thread* t, object string)
|
|
|
|
{
|
|
|
|
return stringUTFLength(t, string, 0, stringLength(t, string));
|
|
|
|
}
|
2010-04-20 10:03:07 -06:00
|
|
|
|
2007-07-07 19:06:32 -06:00
|
|
|
void
|
2010-09-10 15:05:29 -06:00
|
|
|
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);
|
|
|
|
}
|
2007-07-07 19:06:32 -06:00
|
|
|
|
2008-04-01 17:24:43 -06:00
|
|
|
void
|
2010-09-10 15:05:29 -06:00
|
|
|
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);
|
|
|
|
}
|
2008-04-01 17:24:43 -06:00
|
|
|
|
2010-04-20 10:03:07 -06:00
|
|
|
void
|
2010-09-10 15:05:29 -06:00
|
|
|
stringUTFChars(Thread* t, object string, unsigned start, unsigned length,
|
|
|
|
char* chars, unsigned charsLength);
|
|
|
|
|
|
|
|
inline void
|
|
|
|
stringUTFChars(Thread* t, object string, char* chars, unsigned charsLength)
|
|
|
|
{
|
|
|
|
stringUTFChars(t, string, 0, stringLength(t, string), chars, charsLength);
|
|
|
|
}
|
2010-04-20 10:03:07 -06:00
|
|
|
|
2007-07-23 19:44:20 -06:00
|
|
|
bool
|
|
|
|
isAssignableFrom(Thread* t, object a, object b);
|
|
|
|
|
2007-07-28 10:10:13 -06:00
|
|
|
object
|
|
|
|
classInitializer(Thread* t, object class_);
|
|
|
|
|
2007-09-12 18:21:37 -06:00
|
|
|
object
|
|
|
|
frameMethod(Thread* t, int frame);
|
|
|
|
|
2007-07-06 09:24:06 -06:00
|
|
|
inline uintptr_t&
|
2007-08-19 13:45:51 -06:00
|
|
|
extendedWord(Thread* t UNUSED, object o, unsigned baseSize)
|
2007-07-06 09:24:06 -06:00
|
|
|
{
|
|
|
|
assert(t, objectExtended(t, o));
|
|
|
|
return cast<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)
|
|
|
|
{
|
|
|
|
assert(t, not objectExtended(t, o));
|
2007-10-22 11:22:30 -06:00
|
|
|
assert(t, not objectFixed(t, o));
|
2007-08-18 15:24:29 -06:00
|
|
|
|
2007-09-23 19:39:03 -06:00
|
|
|
ACQUIRE_RAW(t, t->m->heapLock);
|
2007-10-27 19:54:30 -06:00
|
|
|
|
2011-02-14 11:47:59 -07:00
|
|
|
alias(o, 0) |= HashTakenMark;
|
2008-01-14 09:39:57 -07:00
|
|
|
t->m->heap->pad(o);
|
2007-07-06 09:24:06 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
inline uint32_t
|
|
|
|
takeHash(Thread*, object o)
|
|
|
|
{
|
2011-03-27 20:22:59 -06:00
|
|
|
// 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;
|
2007-07-06 09:24:06 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
inline uint32_t
|
|
|
|
objectHash(Thread* t, object o)
|
|
|
|
{
|
|
|
|
if (objectExtended(t, o)) {
|
|
|
|
return extendedWord(t, o, baseSize(t, o, objectClass(t, o)));
|
|
|
|
} else {
|
2007-10-22 11:22:30 -06:00
|
|
|
if (not objectFixed(t, o)) {
|
|
|
|
markHashTaken(t, o);
|
|
|
|
}
|
2007-07-06 09:24:06 -06:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2007-07-06 09:24:06 -06:00
|
|
|
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)) {
|
2007-07-28 18:02:32 -06:00
|
|
|
object data = stringData(t, s);
|
2010-09-14 10:49:41 -06:00
|
|
|
if (objectClass(t, data) == type(t, Machine::ByteArrayType)) {
|
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 = stringData(t, s);
|
2010-09-14 10:49:41 -06:00
|
|
|
if (objectClass(t, data) == type(t, Machine::ByteArrayType)) {
|
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)) {
|
2007-11-04 14:15:28 -07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-06 09:24:06 -06:00
|
|
|
inline uint32_t
|
|
|
|
methodHash(Thread* t, object method)
|
|
|
|
{
|
|
|
|
return byteArrayHash(t, methodName(t, method))
|
|
|
|
^ byteArrayHash(t, methodSpec(t, method));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool
|
|
|
|
methodEqual(Thread* t, object a, object b)
|
|
|
|
{
|
|
|
|
return a == b or
|
|
|
|
(byteArrayEqual(t, methodName(t, a), methodName(t, b)) and
|
|
|
|
byteArrayEqual(t, methodSpec(t, a), methodSpec(t, b)));
|
|
|
|
}
|
|
|
|
|
2007-09-28 17:41:03 -06:00
|
|
|
class MethodSpecIterator {
|
|
|
|
public:
|
|
|
|
MethodSpecIterator(Thread* t, const char* s):
|
|
|
|
t(t), s(s + 1)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
const char* next() {
|
|
|
|
assert(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;
|
|
|
|
|
|
|
|
default:
|
|
|
|
++ s;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool hasNext() {
|
|
|
|
return *s != ')';
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* returnSpec() {
|
|
|
|
assert(t, *s == ')');
|
|
|
|
return s + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
Thread* t;
|
|
|
|
const char* s;
|
|
|
|
};
|
|
|
|
|
2007-07-14 11:31:01 -06:00
|
|
|
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)
|
2007-07-14 11:31:01 -06:00
|
|
|
{
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2011-03-15 17:52:02 -06:00
|
|
|
inline void
|
|
|
|
scanMethodSpec(Thread* t, const char* s, unsigned* parameterCount,
|
|
|
|
unsigned* returnCode)
|
|
|
|
{
|
|
|
|
unsigned count = 0;
|
|
|
|
MethodSpecIterator it(t, s);
|
|
|
|
for (; it.hasNext(); it.next()) {
|
|
|
|
++ count;
|
|
|
|
}
|
|
|
|
|
|
|
|
*parameterCount = count;
|
|
|
|
*returnCode = fieldCode(t, *it.returnSpec());
|
|
|
|
}
|
|
|
|
|
2007-07-30 17:19:05 -06:00
|
|
|
object
|
2010-09-14 10:49:41 -06:00
|
|
|
findLoadedClass(Thread* t, object loader, object spec);
|
2007-07-30 17:19:05 -06:00
|
|
|
|
2009-07-21 18:57:55 -06:00
|
|
|
inline bool
|
|
|
|
emptyMethod(Thread* t, object method)
|
|
|
|
{
|
|
|
|
return ((methodFlags(t, method) & ACC_NATIVE) == 0)
|
|
|
|
and (codeLength(t, methodCode(t, method)) == 1)
|
|
|
|
and (codeBody(t, methodCode(t, method), 0) == return_);
|
|
|
|
}
|
|
|
|
|
2010-09-10 15:05:29 -06:00
|
|
|
object
|
|
|
|
parseUtf8(Thread* t, const char* data, unsigned length);
|
|
|
|
|
2007-07-30 17:19:05 -06:00
|
|
|
object
|
2011-03-17 21:42:15 -06:00
|
|
|
parseClass(Thread* t, object loader, const uint8_t* data, unsigned length,
|
|
|
|
Machine::Type throwType = Machine::NoClassDefFoundErrorType);
|
2007-07-30 17:19:05 -06:00
|
|
|
|
2007-07-14 11:31:01 -06:00
|
|
|
object
|
2011-03-17 21:42:15 -06:00
|
|
|
resolveClass(Thread* t, object loader, object name, bool throw_ = true,
|
|
|
|
Machine::Type throwType = Machine::NoClassDefFoundErrorType);
|
2009-06-10 18:15:00 -06:00
|
|
|
|
|
|
|
inline object
|
2011-03-17 21:42:15 -06:00
|
|
|
resolveClass(Thread* t, object loader, const char* name, bool throw_ = true,
|
|
|
|
Machine::Type throwType = Machine::NoClassDefFoundErrorType)
|
2009-06-10 18:15:00 -06:00
|
|
|
{
|
2009-08-10 07:56:16 -06:00
|
|
|
PROTECT(t, loader);
|
|
|
|
object n = makeByteArray(t, "%s", name);
|
2011-03-17 21:42:15 -06:00
|
|
|
return resolveClass(t, loader, n, throw_, throwType);
|
2009-08-10 07:56:16 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
object
|
2011-03-17 21:42:15 -06:00
|
|
|
resolveSystemClass
|
|
|
|
(Thread* t, object loader, object name, bool throw_ = true,
|
|
|
|
Machine::Type throwType = Machine::NoClassDefFoundErrorType);
|
2009-08-10 07:56:16 -06:00
|
|
|
|
|
|
|
inline object
|
2010-09-14 10:49:41 -06:00
|
|
|
resolveSystemClass(Thread* t, object loader, const char* name)
|
2009-08-10 07:56:16 -06:00
|
|
|
{
|
2010-09-14 10:49:41 -06:00
|
|
|
return resolveSystemClass(t, loader, makeByteArray(t, "%s", name));
|
2009-06-10 18:15:00 -06:00
|
|
|
}
|
2007-07-14 11:31:01 -06:00
|
|
|
|
2009-08-18 14:26:28 -06:00
|
|
|
void
|
|
|
|
linkClass(Thread* t, object loader, object class_);
|
|
|
|
|
2007-09-23 19:39:03 -06:00
|
|
|
object
|
2009-06-10 18:15:00 -06:00
|
|
|
resolveMethod(Thread* t, object class_, const char* methodName,
|
2007-09-23 19:39:03 -06:00
|
|
|
const char* methodSpec);
|
|
|
|
|
2009-06-10 18:15:00 -06:00
|
|
|
inline object
|
2009-08-10 07:56:16 -06:00
|
|
|
resolveMethod(Thread* t, object loader, const char* className,
|
|
|
|
const char* methodName, const char* methodSpec)
|
2009-06-10 18:15:00 -06:00
|
|
|
{
|
2010-12-27 15:55:23 -07:00
|
|
|
return resolveMethod
|
|
|
|
(t, resolveClass(t, loader, className), methodName, methodSpec);
|
2009-06-10 18:15:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
object
|
|
|
|
resolveField(Thread* t, object class_, const char* fieldName,
|
|
|
|
const char* fieldSpec);
|
|
|
|
|
|
|
|
inline object
|
2009-08-10 07:56:16 -06:00
|
|
|
resolveField(Thread* t, object loader, const char* className,
|
|
|
|
const char* fieldName, const char* fieldSpec)
|
2009-06-10 18:15:00 -06:00
|
|
|
{
|
2010-12-27 15:55:23 -07:00
|
|
|
return resolveField
|
|
|
|
(t, resolveClass(t, loader, className), fieldName, fieldSpec);
|
2009-06-10 18:15:00 -06:00
|
|
|
}
|
|
|
|
|
2009-07-20 14:12:38 -06:00
|
|
|
bool
|
|
|
|
classNeedsInit(Thread* t, object c);
|
2008-11-29 21:58:09 -07:00
|
|
|
|
2009-07-20 14:12:38 -06:00
|
|
|
bool
|
|
|
|
preInitClass(Thread* t, object c);
|
|
|
|
|
|
|
|
void
|
|
|
|
postInitClass(Thread* t, object c);
|
|
|
|
|
|
|
|
void
|
|
|
|
initClass(Thread* t, object c);
|
2007-08-22 21:30:37 -06:00
|
|
|
|
2010-11-27 16:27:30 -07:00
|
|
|
object
|
|
|
|
resolveObjectArrayClass(Thread* t, object loader, object elementClass);
|
|
|
|
|
2007-07-14 11:31:01 -06:00
|
|
|
object
|
2010-09-14 10:49:41 -06:00
|
|
|
makeObjectArray(Thread* t, object elementClass, unsigned count);
|
2007-07-14 11:31:01 -06:00
|
|
|
|
2009-09-18 18:01:54 -06:00
|
|
|
inline object
|
|
|
|
makeObjectArray(Thread* t, unsigned count)
|
|
|
|
{
|
2010-09-14 10:49:41 -06:00
|
|
|
return makeObjectArray(t, type(t, Machine::JobjectType), count);
|
2009-09-18 18:01:54 -06:00
|
|
|
}
|
|
|
|
|
2007-09-06 18:21:52 -06:00
|
|
|
object
|
|
|
|
findInTable(Thread* t, object table, object name, object spec,
|
|
|
|
object& (*getName)(Thread*, object),
|
|
|
|
object& (*getSpec)(Thread*, object));
|
|
|
|
|
|
|
|
inline object
|
|
|
|
findFieldInClass(Thread* t, object class_, object name, object spec)
|
|
|
|
{
|
|
|
|
return findInTable
|
|
|
|
(t, classFieldTable(t, class_), name, spec, fieldName, fieldSpec);
|
|
|
|
}
|
|
|
|
|
2010-11-04 11:02:09 -06:00
|
|
|
inline object
|
|
|
|
findFieldInClass2(Thread* t, object 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);
|
|
|
|
}
|
|
|
|
|
2007-09-06 18:21:52 -06:00
|
|
|
inline object
|
|
|
|
findMethodInClass(Thread* t, object class_, object name, object spec)
|
|
|
|
{
|
|
|
|
return findInTable
|
|
|
|
(t, classMethodTable(t, class_), name, spec, methodName, methodSpec);
|
|
|
|
}
|
|
|
|
|
avoid inifinite recursion if java.lang.Object is missing; refactoring
When trying to create an array class, we try to resolve
java.lang.Object so we can use its vtable in the array class.
However, if Object is missing, we'll try to create and throw a
ClassNotFoundException, which requires creating an array to store the
stack trace, which requires creating an array class, which requires
resolving Object, etc.. This commit short-circuits this process by
telling resolveClass not to create and throw an exception if it can't
find Object.
While doing the above work, I noticed that the implementations of
Classpath::makeThrowable in classpath-avian.cpp and
classpath-openjdk.cpp were identical, so I made makeThrowable a
top-level function.
Finally, I discovered that Thread.setDaemon can only be called before
the target thread has been started, which allowed me to simplify the
code to track daemon threads in the VM.
2010-12-09 19:38:12 -07:00
|
|
|
inline object
|
|
|
|
makeThrowable
|
|
|
|
(Thread* t, Machine::Type type, object message = 0, object trace = 0,
|
|
|
|
object cause = 0)
|
|
|
|
{
|
|
|
|
PROTECT(t, message);
|
|
|
|
PROTECT(t, trace);
|
|
|
|
PROTECT(t, cause);
|
|
|
|
|
|
|
|
if (trace == 0) {
|
|
|
|
trace = makeTrace(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
object result = make(t, vm::type(t, type));
|
|
|
|
|
|
|
|
set(t, result, ThrowableMessage, message);
|
|
|
|
set(t, result, ThrowableTrace, trace);
|
|
|
|
set(t, result, ThrowableCause, cause);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2010-12-27 15:55:23 -07:00
|
|
|
inline object
|
|
|
|
makeThrowable(Thread* t, Machine::Type type, const char* format, va_list a)
|
|
|
|
{
|
|
|
|
object s = makeByteArray(t, format, a);
|
|
|
|
|
|
|
|
object message = t->m->classpath->makeString
|
|
|
|
(t, s, 0, byteArrayLength(t, s) - 1);
|
|
|
|
|
|
|
|
return makeThrowable(t, type, message);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline object
|
|
|
|
makeThrowable(Thread* t, Machine::Type type, const char* format, ...)
|
|
|
|
{
|
|
|
|
va_list a;
|
|
|
|
va_start(a, format);
|
|
|
|
object r = makeThrowable(t, type, format, a);
|
|
|
|
va_end(a);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2011-01-27 11:54:41 -07:00
|
|
|
void
|
|
|
|
popResources(Thread* t);
|
|
|
|
|
|
|
|
inline void NO_RETURN
|
|
|
|
throw_(Thread* t, object e)
|
|
|
|
{
|
|
|
|
assert(t, t->exception == 0);
|
2011-03-04 16:01:50 -07:00
|
|
|
assert(t, e);
|
2011-01-27 11:54:41 -07:00
|
|
|
|
|
|
|
expect(t, not t->checkpoint->noThrow);
|
|
|
|
|
|
|
|
t->exception = e;
|
|
|
|
|
2011-02-11 21:13:11 -07:00
|
|
|
// printTrace(t, e);
|
|
|
|
|
2011-01-27 11:54:41 -07:00
|
|
|
popResources(t);
|
|
|
|
|
|
|
|
t->checkpoint->unwind();
|
|
|
|
|
|
|
|
abort(t);
|
|
|
|
}
|
2010-12-27 15:55:23 -07:00
|
|
|
|
|
|
|
inline void NO_RETURN
|
2011-02-11 21:13:11 -07:00
|
|
|
throwNew
|
|
|
|
(Thread* t, Machine::Type type, object message = 0, object trace = 0,
|
|
|
|
object cause = 0)
|
2010-12-27 15:55:23 -07:00
|
|
|
{
|
2011-02-11 21:13:11 -07:00
|
|
|
throw_(t, makeThrowable(t, type, message, trace, cause));
|
2010-12-27 15:55:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void NO_RETURN
|
|
|
|
throwNew(Thread* t, Machine::Type type, const char* format, ...)
|
|
|
|
{
|
|
|
|
va_list a;
|
|
|
|
va_start(a, format);
|
|
|
|
object r = makeThrowable(t, type, format, a);
|
|
|
|
va_end(a);
|
|
|
|
|
|
|
|
throw_(t, r);
|
|
|
|
}
|
|
|
|
|
2007-09-06 18:21:52 -06:00
|
|
|
object
|
2010-11-04 11:02:09 -06:00
|
|
|
findInHierarchyOrNull(Thread* t, object class_, object name, object spec,
|
|
|
|
object (*find)(Thread*, object, object, object));
|
|
|
|
|
|
|
|
inline object
|
2007-09-06 18:21:52 -06:00
|
|
|
findInHierarchy(Thread* t, object class_, object name, object spec,
|
|
|
|
object (*find)(Thread*, object, object, object),
|
2011-03-15 17:52:02 -06:00
|
|
|
Machine::Type errorType, bool throw_ = true)
|
2010-11-04 11:02:09 -06:00
|
|
|
{
|
|
|
|
object o = findInHierarchyOrNull(t, class_, name, spec, find);
|
|
|
|
|
2011-03-15 17:52:02 -06:00
|
|
|
if (throw_ and o == 0) {
|
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),
|
|
|
|
&byteArrayBody(t, className(t, class_), 0));
|
2010-11-04 11:02:09 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return o;
|
|
|
|
}
|
2007-09-06 18:21:52 -06:00
|
|
|
|
|
|
|
inline object
|
|
|
|
findMethod(Thread* t, object class_, object name, object spec)
|
|
|
|
{
|
|
|
|
return findInHierarchy
|
2010-09-10 15:05:29 -06:00
|
|
|
(t, class_, name, spec, findMethodInClass, Machine::NoSuchMethodErrorType);
|
2007-09-06 18:21:52 -06:00
|
|
|
}
|
|
|
|
|
2010-11-04 11:02:09 -06:00
|
|
|
inline object
|
|
|
|
findMethodOrNull(Thread* t, object 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 findInHierarchyOrNull(t, class_, n, s, findMethodInClass);
|
|
|
|
}
|
|
|
|
|
2008-06-25 10:28:11 -06:00
|
|
|
inline object
|
2009-08-13 09:17:05 -06:00
|
|
|
findVirtualMethod(Thread* t, object method, object class_)
|
2008-06-25 10:28:11 -06:00
|
|
|
{
|
2010-12-27 15:55:23 -07:00
|
|
|
return arrayBody(t, classVirtualTable(t, class_), methodOffset(t, method));
|
2008-06-25 10:28:11 -06:00
|
|
|
}
|
|
|
|
|
2009-09-18 18:01:54 -06:00
|
|
|
inline object
|
|
|
|
findInterfaceMethod(Thread* t, object method, object class_)
|
|
|
|
{
|
|
|
|
assert(t, (classVmFlags(t, class_) & BootstrapFlag) == 0);
|
|
|
|
|
|
|
|
object interface = methodClass(t, method);
|
|
|
|
object itable = classInterfaceTable(t, class_);
|
|
|
|
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
|
|
|
|
if (arrayBody(t, itable, i) == interface) {
|
2010-12-27 15:55:23 -07:00
|
|
|
return arrayBody
|
|
|
|
(t, arrayBody(t, itable, i + 1), methodOffset(t, method));
|
2009-09-18 18:01:54 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
abort(t);
|
|
|
|
}
|
|
|
|
|
2007-07-14 11:31:01 -06:00
|
|
|
inline unsigned
|
2007-08-19 13:45:51 -06:00
|
|
|
objectArrayLength(Thread* t UNUSED, object array)
|
2007-07-14 11:31:01 -06:00
|
|
|
{
|
|
|
|
assert(t, classFixedSize(t, objectClass(t, array)) == BytesPerWord * 2);
|
|
|
|
assert(t, classArrayElementSize(t, objectClass(t, array)) == BytesPerWord);
|
|
|
|
return cast<uintptr_t>(array, BytesPerWord);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline object&
|
2007-08-19 13:45:51 -06:00
|
|
|
objectArrayBody(Thread* t UNUSED, object array, unsigned index)
|
2007-07-14 11:31:01 -06:00
|
|
|
{
|
|
|
|
assert(t, classFixedSize(t, objectClass(t, array)) == BytesPerWord * 2);
|
|
|
|
assert(t, classArrayElementSize(t, objectClass(t, array)) == BytesPerWord);
|
|
|
|
assert(t, classObjectMask(t, objectClass(t, array))
|
|
|
|
== classObjectMask(t, arrayBody
|
2007-09-23 19:39:03 -06:00
|
|
|
(t, t->m->types, Machine::ArrayType)));
|
2009-09-18 18:01:54 -06:00
|
|
|
return cast<object>(array, ArrayBody + (index * BytesPerWord));
|
2007-07-14 11:31:01 -06:00
|
|
|
}
|
|
|
|
|
2007-11-20 15:24:02 -07:00
|
|
|
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));
|
|
|
|
|
2010-12-16 16:46:25 -07:00
|
|
|
inline bool
|
|
|
|
zombified(Thread* t)
|
|
|
|
{
|
|
|
|
return t->state == Thread::ZombieState
|
|
|
|
or t->state == Thread::JoinedState;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool
|
|
|
|
acquireSystem(Thread* t, Thread* target)
|
|
|
|
{
|
|
|
|
ACQUIRE_RAW(t, t->m->stateLock);
|
|
|
|
|
|
|
|
if (not zombified(target)) {
|
|
|
|
atomicOr(&(target->flags), Thread::SystemFlag);
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
releaseSystem(Thread* t, Thread* target)
|
|
|
|
{
|
|
|
|
ACQUIRE_RAW(t, t->m->stateLock);
|
|
|
|
|
|
|
|
assert(t, not zombified(target));
|
|
|
|
|
|
|
|
atomicAnd(&(target->flags), ~Thread::SystemFlag);
|
|
|
|
}
|
|
|
|
|
2010-02-04 17:56:21 -07:00
|
|
|
inline bool
|
|
|
|
atomicCompareAndSwapObject(Thread* t, object target, unsigned offset,
|
|
|
|
object old, object new_)
|
|
|
|
{
|
|
|
|
if (atomicCompareAndSwap(&cast<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
|
2011-03-25 18:21:15 -06:00
|
|
|
monitorAtomicAppendAcquire(Thread* t, object monitor, object node)
|
2010-02-04 17:56:21 -07:00
|
|
|
{
|
2011-03-25 18:21:15 -06:00
|
|
|
if (node == 0) {
|
|
|
|
PROTECT(t, monitor);
|
2010-02-04 17:56:21 -07:00
|
|
|
|
2011-03-25 18:21:15 -06:00
|
|
|
node = makeMonitorNode(t, t, 0);
|
|
|
|
}
|
2010-02-04 17:56:21 -07:00
|
|
|
|
|
|
|
while (true) {
|
|
|
|
object tail = monitorAcquireTail(t, monitor);
|
|
|
|
|
|
|
|
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
|
2011-03-25 18:21:15 -06:00
|
|
|
monitorAcquire(Thread* t, object monitor, object node = 0)
|
2010-02-04 17:56:21 -07:00
|
|
|
{
|
|
|
|
if (not monitorTryAcquire(t, monitor)) {
|
|
|
|
PROTECT(t, monitor);
|
2011-03-25 18:21:15 -06:00
|
|
|
PROTECT(t, node);
|
2010-02-04 17:56:21 -07:00
|
|
|
|
|
|
|
ACQUIRE(t, t->lock);
|
|
|
|
|
2011-03-25 18:21:15 -06:00
|
|
|
monitorAtomicAppendAcquire(t, monitor, node);
|
2010-02-04 17:56:21 -07: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);
|
|
|
|
|
|
|
|
t->lock->wait(t->systemThread, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
expect(t, t == monitorAtomicPollAcquire(t, monitor, true));
|
|
|
|
|
|
|
|
++ monitorDepth(t, monitor);
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(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();
|
|
|
|
|
|
|
|
Thread* next = monitorAtomicPollAcquire(t, monitor, false);
|
|
|
|
|
2010-12-16 16:46:25 -07:00
|
|
|
if (next and acquireSystem(t, next)) {
|
2010-02-04 17:56:21 -07:00
|
|
|
ACQUIRE(t, next->lock);
|
|
|
|
|
|
|
|
next->lock->notify(t->systemThread);
|
2010-12-16 16:46:25 -07:00
|
|
|
|
|
|
|
releaseSystem(t, next);
|
2010-02-04 17:56:21 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
monitorAppendWait(Thread* t, object monitor)
|
|
|
|
{
|
|
|
|
assert(t, monitorOwner(t, monitor) == t);
|
|
|
|
|
2010-09-14 10:49:41 -06:00
|
|
|
expect(t, (t->flags & Thread::WaitingFlag) == 0);
|
2010-02-04 17:56:21 -07:00
|
|
|
expect(t, t->waitNext == 0);
|
|
|
|
|
2010-09-14 10:49:41 -06:00
|
|
|
atomicOr(&(t->flags), Thread::WaitingFlag);
|
2010-02-04 17:56:21 -07:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
assert(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)) {
|
|
|
|
assert(t, t->waitNext == 0);
|
|
|
|
monitorWaitTail(t, monitor) = previous;
|
|
|
|
}
|
|
|
|
|
|
|
|
t->waitNext = 0;
|
2010-09-14 10:49:41 -06:00
|
|
|
atomicAnd(&(t->flags), ~Thread::WaitingFlag);
|
2010-02-04 17:56:21 -07:00
|
|
|
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
previous = current;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
abort(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool
|
|
|
|
monitorFindWait(Thread* t, object monitor)
|
|
|
|
{
|
|
|
|
assert(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);
|
|
|
|
|
2011-03-25 18:21:15 -06:00
|
|
|
// pre-allocate monitor node so we don't get an OutOfMemoryError
|
|
|
|
// when we try to re-acquire the monitor below
|
|
|
|
object monitorNode = makeMonitorNode(t, t, 0);
|
|
|
|
PROTECT(t, monitorNode);
|
|
|
|
|
2010-02-04 17:56:21 -07:00
|
|
|
{ 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->wait(t->systemThread, time);
|
|
|
|
}
|
|
|
|
|
2011-03-25 18:21:15 -06:00
|
|
|
monitorAcquire(t, monitor, monitorNode);
|
2010-02-04 17:56:21 -07:00
|
|
|
|
|
|
|
monitorDepth(t, monitor) = depth;
|
|
|
|
|
2010-09-14 10:49:41 -06:00
|
|
|
if (t->flags & Thread::WaitingFlag) {
|
2010-02-04 17:56:21 -07:00
|
|
|
monitorRemoveWait(t, monitor);
|
|
|
|
} else {
|
|
|
|
expect(t, not monitorFindWait(t, monitor));
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(t, monitorOwner(t, monitor) == t);
|
|
|
|
|
|
|
|
return interrupted;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline Thread*
|
|
|
|
monitorPollWait(Thread* t, object monitor)
|
|
|
|
{
|
|
|
|
assert(t, monitorOwner(t, monitor) == t);
|
|
|
|
|
|
|
|
Thread* next = static_cast<Thread*>(monitorWaitHead(t, monitor));
|
|
|
|
|
|
|
|
if (next) {
|
|
|
|
monitorWaitHead(t, monitor) = next->waitNext;
|
2010-09-14 10:49:41 -06:00
|
|
|
atomicAnd(&(next->flags), ~Thread::WaitingFlag);
|
2010-02-04 17:56:21 -07:00
|
|
|
next->waitNext = 0;
|
|
|
|
if (next == monitorWaitTail(t, monitor)) {
|
|
|
|
monitorWaitTail(t, monitor) = 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
assert(t, monitorWaitTail(t, monitor) == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return next;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool
|
|
|
|
monitorNotify(Thread* t, object monitor)
|
|
|
|
{
|
|
|
|
expect(t, monitorOwner(t, monitor) == t);
|
|
|
|
|
|
|
|
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)) { }
|
|
|
|
}
|
|
|
|
|
2010-09-16 19:43:27 -06:00
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
2010-02-04 17:56:21 -07:00
|
|
|
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)
|
|
|
|
{
|
2008-01-19 13:12:16 -07:00
|
|
|
unsigned hash;
|
|
|
|
if (DebugMonitors) {
|
|
|
|
hash = objectHash(t, o);
|
|
|
|
}
|
|
|
|
|
2010-02-04 17:56:21 -07:00
|
|
|
object m = objectMonitor(t, o, true);
|
2007-07-10 22:19:26 -06:00
|
|
|
|
|
|
|
if (DebugMonitors) {
|
2010-09-16 19:43:27 -06:00
|
|
|
fprintf(stderr, "thread %p acquires %p for %x\n", t, m, hash);
|
2007-07-10 22:19:26 -06:00
|
|
|
}
|
|
|
|
|
2010-02-04 17:56:21 -07:00
|
|
|
monitorAcquire(t, m);
|
2007-07-07 17:47:35 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
release(Thread* t, object o)
|
|
|
|
{
|
2008-01-19 13:12:16 -07:00
|
|
|
unsigned hash;
|
|
|
|
if (DebugMonitors) {
|
|
|
|
hash = objectHash(t, o);
|
|
|
|
}
|
|
|
|
|
2010-02-04 17:56:21 -07:00
|
|
|
object m = objectMonitor(t, o, false);
|
2007-07-10 22:19:26 -06:00
|
|
|
|
|
|
|
if (DebugMonitors) {
|
2010-09-16 19:43:27 -06:00
|
|
|
fprintf(stderr, "thread %p releases %p for %x\n", t, m, hash);
|
2007-07-10 22:19:26 -06:00
|
|
|
}
|
|
|
|
|
2010-02-04 17:56:21 -07:00
|
|
|
monitorRelease(t, m);
|
2007-07-07 17:47:35 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
wait(Thread* t, object o, int64_t milliseconds)
|
|
|
|
{
|
2008-01-19 13:12:16 -07:00
|
|
|
unsigned hash;
|
|
|
|
if (DebugMonitors) {
|
|
|
|
hash = objectHash(t, o);
|
|
|
|
}
|
|
|
|
|
2010-02-04 17:56:21 -07:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2010-02-04 17:56:21 -07: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) {
|
2010-12-27 15:55:23 -07:00
|
|
|
throwNew(t, Machine::InterruptedExceptionType);
|
2007-07-28 15:28:25 -06:00
|
|
|
}
|
2007-07-07 17:47:35 -06:00
|
|
|
} else {
|
2010-12-27 15:55:23 -07:00
|
|
|
throwNew(t, Machine::IllegalMonitorStateExceptionType);
|
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",
|
2008-01-19 13:12:16 -07:00
|
|
|
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)
|
|
|
|
{
|
2008-01-19 13:12:16 -07:00
|
|
|
unsigned hash;
|
|
|
|
if (DebugMonitors) {
|
|
|
|
hash = objectHash(t, o);
|
|
|
|
}
|
|
|
|
|
2010-02-04 17:56:21 -07:00
|
|
|
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",
|
2008-01-19 13:12:16 -07:00
|
|
|
t, m, hash);
|
2007-07-10 22:19:26 -06:00
|
|
|
}
|
|
|
|
|
2010-02-04 17:56:21 -07:00
|
|
|
if (m and monitorOwner(t, m) == t) {
|
|
|
|
monitorNotify(t, m);
|
2007-07-07 17:47:35 -06:00
|
|
|
} else {
|
2010-12-27 15:55:23 -07:00
|
|
|
throwNew(t, Machine::IllegalMonitorStateExceptionType);
|
2007-07-07 17:47:35 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
notifyAll(Thread* t, object o)
|
|
|
|
{
|
2010-02-04 17:56:21 -07:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2010-02-04 17:56:21 -07:00
|
|
|
if (m and monitorOwner(t, m) == t) {
|
|
|
|
monitorNotifyAll(t, m);
|
2007-07-07 17:47:35 -06:00
|
|
|
} else {
|
2010-12-27 15:55:23 -07:00
|
|
|
throwNew(t, Machine::IllegalMonitorStateExceptionType);
|
2007-07-07 17:47:35 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-16 10:50:19 -07:00
|
|
|
inline void
|
|
|
|
interrupt(Thread* t, Thread* target)
|
|
|
|
{
|
|
|
|
if (acquireSystem(t, target)) {
|
2010-11-09 15:46:16 -07:00
|
|
|
target->systemThread->interrupt();
|
2010-11-16 10:50:19 -07:00
|
|
|
releaseSystem(t, target);
|
2010-11-09 15:46:16 -07:00
|
|
|
}
|
2007-07-20 08:36:31 -06:00
|
|
|
}
|
|
|
|
|
2007-07-28 18:02:32 -06:00
|
|
|
object
|
|
|
|
intern(Thread* t, object s);
|
|
|
|
|
2008-11-21 16:20:35 -07:00
|
|
|
void
|
|
|
|
walk(Thread* t, Heap::Walker* w, object o, unsigned start);
|
|
|
|
|
2008-11-11 08:20:49 -07:00
|
|
|
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-23 19:39:03 -06:00
|
|
|
|
2007-09-24 07:46:48 -06:00
|
|
|
inline void
|
|
|
|
disposeLocalReference(Thread* t, jobject r)
|
|
|
|
{
|
|
|
|
t->m->processor->disposeLocalReference(t, r);
|
|
|
|
}
|
2007-09-23 19:39:03 -06:00
|
|
|
|
2007-11-05 07:28:46 -07:00
|
|
|
inline bool
|
|
|
|
methodVirtual(Thread* t, object method)
|
|
|
|
{
|
|
|
|
return (methodFlags(t, method) & (ACC_STATIC | ACC_PRIVATE)) == 0
|
|
|
|
and byteArrayBody(t, methodName(t, method), 0) != '<';
|
|
|
|
}
|
|
|
|
|
2007-11-05 14:40:17 -07:00
|
|
|
inline unsigned
|
|
|
|
singletonMaskSize(unsigned count)
|
|
|
|
{
|
|
|
|
if (count) {
|
|
|
|
return ceiling(count + 2, BitsPerWord);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline unsigned
|
|
|
|
singletonMaskSize(Thread* t, object singleton)
|
|
|
|
{
|
|
|
|
unsigned length = singletonLength(t, singleton);
|
|
|
|
if (length) {
|
|
|
|
return ceiling(length + 2, BitsPerWord + 1);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline unsigned
|
|
|
|
singletonCount(Thread* t, object singleton)
|
|
|
|
{
|
|
|
|
return singletonLength(t, singleton) - singletonMaskSize(t, singleton);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline uint32_t*
|
|
|
|
singletonMask(Thread* t, object singleton)
|
|
|
|
{
|
|
|
|
assert(t, singletonLength(t, singleton));
|
|
|
|
return reinterpret_cast<uint32_t*>
|
|
|
|
(&singletonBody(t, singleton, singletonCount(t, singleton)));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
singletonMarkObject(Thread* t, object singleton, unsigned index)
|
|
|
|
{
|
|
|
|
singletonMask(t, singleton)[(index + 2) / 32]
|
|
|
|
|= (static_cast<uint32_t>(1) << ((index + 2) % 32));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool
|
|
|
|
singletonIsObject(Thread* t, object singleton, unsigned index)
|
|
|
|
{
|
|
|
|
assert(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&
|
2007-11-05 14:40:17 -07:00
|
|
|
singletonObject(Thread* t, object singleton, unsigned index)
|
|
|
|
{
|
|
|
|
assert(t, singletonIsObject(t, singleton, index));
|
2007-11-06 08:29:05 -07:00
|
|
|
return reinterpret_cast<object&>(singletonBody(t, singleton, index));
|
2007-11-05 14:40:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
inline uintptr_t&
|
|
|
|
singletonValue(Thread* t, object singleton, unsigned index)
|
|
|
|
{
|
|
|
|
assert(t, not singletonIsObject(t, singleton, index));
|
|
|
|
return singletonBody(t, singleton, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline object
|
2009-03-03 20:05:48 -07:00
|
|
|
makeSingletonOfSize(Thread* t, unsigned count)
|
2007-11-05 14:40:17 -07:00
|
|
|
{
|
2009-03-03 20:05:48 -07:00
|
|
|
object o = makeSingleton(t, count + singletonMaskSize(count));
|
2008-04-11 15:00:18 -06:00
|
|
|
assert(t, singletonLength(t, o) == count + singletonMaskSize(t, o));
|
2007-11-05 14:40:17 -07:00
|
|
|
if (count) {
|
|
|
|
singletonMask(t, o)[0] = 1;
|
|
|
|
}
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
2009-08-10 13:20:23 -06:00
|
|
|
inline void
|
2009-10-17 20:11:03 -06:00
|
|
|
singletonSetBit(Thread* t, object singleton, unsigned start, unsigned index)
|
2009-08-10 13:20:23 -06:00
|
|
|
{
|
2009-10-17 20:11:03 -06:00
|
|
|
singletonValue(t, singleton, start + (index / BitsPerWord))
|
|
|
|
|= static_cast<uintptr_t>(1) << (index % BitsPerWord);
|
2009-08-10 13:20:23 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
inline bool
|
2009-10-17 20:11:03 -06:00
|
|
|
singletonBit(Thread* t, object singleton, unsigned start, unsigned index)
|
2009-08-10 13:20:23 -06:00
|
|
|
{
|
2009-10-17 20:11:03 -06:00
|
|
|
return (singletonValue(t, singleton, start + (index / BitsPerWord))
|
|
|
|
& (static_cast<uintptr_t>(1) << (index % BitsPerWord))) != 0;
|
2009-08-10 13:20:23 -06:00
|
|
|
}
|
|
|
|
|
2009-10-17 20:11:03 -06:00
|
|
|
inline unsigned
|
|
|
|
poolMaskSize(unsigned count)
|
|
|
|
{
|
|
|
|
return ceiling(count, BitsPerWord);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline unsigned
|
|
|
|
poolMaskSize(Thread* t, object pool)
|
|
|
|
{
|
|
|
|
return ceiling(singletonCount(t, pool), BitsPerWord + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline unsigned
|
|
|
|
poolSize(Thread* t, object pool)
|
2009-08-10 13:20:23 -06:00
|
|
|
{
|
2009-10-17 20:11:03 -06:00
|
|
|
return singletonCount(t, pool) - poolMaskSize(t, pool);
|
2009-08-10 13:20:23 -06:00
|
|
|
}
|
|
|
|
|
2009-08-18 14:26:28 -06:00
|
|
|
inline object
|
|
|
|
resolveClassInObject(Thread* t, object loader, object container,
|
2011-03-15 17:52:02 -06:00
|
|
|
unsigned classOffset, bool throw_ = true)
|
2009-08-18 14:26:28 -06:00
|
|
|
{
|
|
|
|
object o = cast<object>(container, classOffset);
|
2011-03-15 17:52:02 -06:00
|
|
|
|
|
|
|
loadMemoryBarrier();
|
|
|
|
|
2010-09-14 10:49:41 -06:00
|
|
|
if (objectClass(t, o) == type(t, Machine::ByteArrayType)) {
|
2009-08-18 14:26:28 -06:00
|
|
|
PROTECT(t, container);
|
|
|
|
|
2011-03-15 17:52:02 -06:00
|
|
|
o = resolveClass(t, loader, o, throw_);
|
2009-08-18 14:26:28 -06:00
|
|
|
|
2011-03-15 17:52:02 -06:00
|
|
|
if (o) {
|
|
|
|
storeStoreMemoryBarrier();
|
|
|
|
|
|
|
|
set(t, container, classOffset, o);
|
|
|
|
}
|
2009-08-18 14:26:28 -06:00
|
|
|
}
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline object
|
2011-03-15 17:52:02 -06:00
|
|
|
resolveClassInPool(Thread* t, object loader, object method, unsigned index,
|
|
|
|
bool throw_ = true)
|
2009-08-18 14:26:28 -06:00
|
|
|
{
|
|
|
|
object o = singletonObject(t, codePool(t, methodCode(t, method)), index);
|
2011-03-15 17:52:02 -06:00
|
|
|
|
|
|
|
loadMemoryBarrier();
|
|
|
|
|
2010-09-14 10:49:41 -06:00
|
|
|
if (objectClass(t, o) == type(t, Machine::ReferenceType)) {
|
2009-08-18 14:26:28 -06:00
|
|
|
PROTECT(t, method);
|
|
|
|
|
2011-03-15 17:52:02 -06:00
|
|
|
o = resolveClass(t, loader, referenceName(t, o), throw_);
|
2009-08-18 14:26:28 -06:00
|
|
|
|
2011-03-15 17:52:02 -06:00
|
|
|
if (o) {
|
|
|
|
storeStoreMemoryBarrier();
|
|
|
|
|
|
|
|
set(t, codePool(t, methodCode(t, method)),
|
|
|
|
SingletonBody + (index * BytesPerWord), o);
|
|
|
|
}
|
2009-08-18 14:26:28 -06:00
|
|
|
}
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline object
|
2011-03-15 17:52:02 -06:00
|
|
|
resolveClassInPool(Thread* t, object method, unsigned index,
|
|
|
|
bool throw_ = true)
|
2009-08-18 14:26:28 -06:00
|
|
|
{
|
|
|
|
return resolveClassInPool(t, classLoader(t, methodClass(t, method)),
|
2011-03-15 17:52:02 -06:00
|
|
|
method, index, throw_);
|
2009-08-18 14:26:28 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
inline object
|
|
|
|
resolve(Thread* t, object loader, object method, unsigned index,
|
|
|
|
object (*find)(vm::Thread*, object, object, object),
|
2011-03-15 17:52:02 -06:00
|
|
|
Machine::Type errorType, bool throw_ = true)
|
2009-08-18 14:26:28 -06:00
|
|
|
{
|
|
|
|
object o = singletonObject(t, codePool(t, methodCode(t, method)), index);
|
2011-03-15 17:52:02 -06:00
|
|
|
|
|
|
|
loadMemoryBarrier();
|
|
|
|
|
|
|
|
if (objectClass(t, o) == type(t, Machine::ReferenceType)) {
|
2009-08-18 14:26:28 -06:00
|
|
|
PROTECT(t, method);
|
|
|
|
|
|
|
|
object reference = o;
|
|
|
|
PROTECT(t, reference);
|
|
|
|
|
2011-03-15 17:52:02 -06:00
|
|
|
object class_ = resolveClassInObject(t, loader, o, ReferenceClass, throw_);
|
2009-08-18 14:26:28 -06:00
|
|
|
|
2011-03-15 17:52:02 -06:00
|
|
|
if (class_) {
|
|
|
|
o = findInHierarchy
|
|
|
|
(t, class_, referenceName(t, reference), referenceSpec(t, reference),
|
|
|
|
find, errorType, throw_);
|
2009-08-18 14:26:28 -06:00
|
|
|
|
2011-03-15 17:52:02 -06:00
|
|
|
if (o) {
|
|
|
|
storeStoreMemoryBarrier();
|
|
|
|
|
|
|
|
set(t, codePool(t, methodCode(t, method)),
|
|
|
|
SingletonBody + (index * BytesPerWord), o);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
o = 0;
|
|
|
|
}
|
2009-08-18 14:26:28 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline object
|
2011-03-15 17:52:02 -06:00
|
|
|
resolveField(Thread* t, object loader, object method, unsigned index,
|
|
|
|
bool throw_ = true)
|
2009-08-18 14:26:28 -06:00
|
|
|
{
|
|
|
|
return resolve(t, loader, method, index, findFieldInClass,
|
2011-03-15 17:52:02 -06:00
|
|
|
Machine::NoSuchFieldErrorType, throw_);
|
2009-08-18 14:26:28 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
inline object
|
2011-03-15 17:52:02 -06:00
|
|
|
resolveField(Thread* t, object method, unsigned index, bool throw_ = true)
|
2009-08-18 14:26:28 -06:00
|
|
|
{
|
|
|
|
return resolveField
|
2011-03-15 17:52:02 -06:00
|
|
|
(t, classLoader(t, methodClass(t, method)), 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)))
|
|
|
|
{
|
|
|
|
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))
|
|
|
|
{
|
|
|
|
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))
|
|
|
|
{
|
|
|
|
acquire(t, field);
|
|
|
|
} else {
|
|
|
|
storeStoreMemoryBarrier();
|
|
|
|
}
|
|
|
|
}
|
2009-08-18 14:26:28 -06:00
|
|
|
}
|
|
|
|
|
2011-03-15 17:52:02 -06:00
|
|
|
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))
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
2009-08-18 14:26:28 -06:00
|
|
|
inline object
|
2011-03-15 17:52:02 -06:00
|
|
|
resolveMethod(Thread* t, object loader, object method, unsigned index,
|
|
|
|
bool throw_ = true)
|
2009-08-18 14:26:28 -06:00
|
|
|
{
|
|
|
|
return resolve(t, loader, method, index, findMethodInClass,
|
2011-03-15 17:52:02 -06:00
|
|
|
Machine::NoSuchMethodErrorType, throw_);
|
2009-08-18 14:26:28 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
inline object
|
2011-03-15 17:52:02 -06:00
|
|
|
resolveMethod(Thread* t, object method, unsigned index, bool throw_ = true)
|
2009-08-18 14:26:28 -06:00
|
|
|
{
|
|
|
|
return resolveMethod
|
2011-03-15 17:52:02 -06:00
|
|
|
(t, classLoader(t, methodClass(t, method)), method, index, throw_);
|
2009-08-18 14:26:28 -06:00
|
|
|
}
|
|
|
|
|
2010-11-26 12:41:31 -07:00
|
|
|
object
|
|
|
|
vectorAppend(Thread*, object, object);
|
|
|
|
|
2010-11-27 11:25:02 -07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-01 10:13:52 -06:00
|
|
|
inline object
|
2010-11-26 12:41:31 -07:00
|
|
|
getClassRuntimeData(Thread* t, object c)
|
2010-09-01 10:13:52 -06:00
|
|
|
{
|
2010-11-26 12:41:31 -07:00
|
|
|
if (classRuntimeDataIndex(t, c) == 0) {
|
2010-09-10 15:05:29 -06:00
|
|
|
PROTECT(t, c);
|
|
|
|
|
2010-09-01 10:13:52 -06:00
|
|
|
ACQUIRE(t, t->m->classLock);
|
|
|
|
|
2010-11-26 12:41:31 -07:00
|
|
|
if (classRuntimeDataIndex(t, c) == 0) {
|
2010-11-27 11:25:02 -07:00
|
|
|
object runtimeData = makeClassRuntimeData(t, 0, 0, 0, 0);
|
2010-11-26 12:41:31 -07:00
|
|
|
|
|
|
|
setRoot(t, Machine::ClassRuntimeDataTable, vectorAppend
|
|
|
|
(t, root(t, Machine::ClassRuntimeDataTable), runtimeData));
|
|
|
|
|
|
|
|
classRuntimeDataIndex(t, c) = vectorSize
|
|
|
|
(t, root(t, Machine::ClassRuntimeDataTable));
|
|
|
|
}
|
2010-09-01 10:13:52 -06:00
|
|
|
}
|
|
|
|
|
2010-11-26 12:41:31 -07:00
|
|
|
return vectorBody(t, root(t, Machine::ClassRuntimeDataTable),
|
|
|
|
classRuntimeDataIndex(t, c) - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline object
|
|
|
|
getMethodRuntimeData(Thread* t, object method)
|
|
|
|
{
|
2011-04-10 14:46:53 -06:00
|
|
|
int index = methodRuntimeDataIndex(t, method);
|
|
|
|
|
|
|
|
loadMemoryBarrier();
|
|
|
|
|
|
|
|
if (index == 0) {
|
2010-11-26 12:41:31 -07:00
|
|
|
PROTECT(t, method);
|
|
|
|
|
|
|
|
ACQUIRE(t, t->m->classLock);
|
|
|
|
|
|
|
|
if (methodRuntimeDataIndex(t, method) == 0) {
|
|
|
|
object runtimeData = makeMethodRuntimeData(t, 0);
|
|
|
|
|
|
|
|
setRoot(t, Machine::MethodRuntimeDataTable, vectorAppend
|
|
|
|
(t, root(t, Machine::MethodRuntimeDataTable), runtimeData));
|
|
|
|
|
2011-04-10 14:46:53 -06:00
|
|
|
storeStoreMemoryBarrier();
|
|
|
|
|
2010-11-26 12:41:31 -07:00
|
|
|
methodRuntimeDataIndex(t, method) = vectorSize
|
|
|
|
(t, root(t, Machine::MethodRuntimeDataTable));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return vectorBody(t, root(t, Machine::MethodRuntimeDataTable),
|
|
|
|
methodRuntimeDataIndex(t, method) - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline object
|
|
|
|
getJClass(Thread* t, object c)
|
|
|
|
{
|
2010-12-09 22:17:57 -07:00
|
|
|
PROTECT(t, c);
|
|
|
|
|
2010-11-26 12:41:31 -07:00
|
|
|
object jclass = classRuntimeDataJclass(t, getClassRuntimeData(t, c));
|
2011-04-10 14:46:53 -06:00
|
|
|
|
|
|
|
loadMemoryBarrier();
|
|
|
|
|
2010-09-01 10:13:52 -06:00
|
|
|
if (jclass == 0) {
|
|
|
|
ACQUIRE(t, t->m->classLock);
|
|
|
|
|
2010-11-26 12:41:31 -07:00
|
|
|
jclass = classRuntimeDataJclass(t, getClassRuntimeData(t, c));
|
|
|
|
if (jclass == 0) {
|
|
|
|
jclass = t->m->classpath->makeJclass(t, c);
|
2011-04-10 14:46:53 -06:00
|
|
|
|
|
|
|
storeStoreMemoryBarrier();
|
2010-09-01 10:13:52 -06:00
|
|
|
|
2010-11-26 12:41:31 -07:00
|
|
|
set(t, getClassRuntimeData(t, c), ClassRuntimeDataJclass, jclass);
|
|
|
|
}
|
2010-09-01 10:13:52 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return jclass;
|
|
|
|
}
|
|
|
|
|
2010-09-10 15:05:29 -06:00
|
|
|
inline object
|
|
|
|
primitiveClass(Thread* t, char name)
|
|
|
|
{
|
|
|
|
switch (name) {
|
2010-09-14 10:49:41 -06:00
|
|
|
case 'B': return type(t, Machine::JbyteType);
|
|
|
|
case 'C': return type(t, Machine::JcharType);
|
|
|
|
case 'D': return type(t, Machine::JdoubleType);
|
|
|
|
case 'F': return type(t, Machine::JfloatType);
|
|
|
|
case 'I': return type(t, Machine::JintType);
|
|
|
|
case 'J': return type(t, Machine::JlongType);
|
|
|
|
case 'S': return type(t, Machine::JshortType);
|
|
|
|
case 'V': return type(t, Machine::JvoidType);
|
|
|
|
case 'Z': return type(t, Machine::JbooleanType);
|
2010-12-27 15:55:23 -07:00
|
|
|
default: throwNew(t, Machine::IllegalArgumentExceptionType);
|
2010-09-10 15:05:29 -06:00
|
|
|
}
|
|
|
|
}
|
2010-09-14 10:49:41 -06:00
|
|
|
|
|
|
|
inline void
|
|
|
|
registerNative(Thread* t, object method, void* function)
|
|
|
|
{
|
|
|
|
PROTECT(t, method);
|
|
|
|
|
|
|
|
expect(t, methodFlags(t, method) & ACC_NATIVE);
|
|
|
|
|
|
|
|
object native = makeNative(t, function, false);
|
2010-11-26 12:41:31 -07:00
|
|
|
PROTECT(t, native);
|
|
|
|
|
|
|
|
object runtimeData = getMethodRuntimeData(t, method);
|
2010-09-14 10:49:41 -06:00
|
|
|
|
2010-11-26 12:41:31 -07:00
|
|
|
// ensure other threads only see the methodRuntimeDataNative field
|
|
|
|
// populated once the object it points to has been populated:
|
2010-09-14 10:49:41 -06:00
|
|
|
storeStoreMemoryBarrier();
|
|
|
|
|
2010-11-26 12:41:31 -07:00
|
|
|
set(t, runtimeData, MethodRuntimeDataNative, native);
|
2010-09-14 10:49:41 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
2010-09-25 15:54:01 -06:00
|
|
|
unregisterNatives(Thread* t, object c)
|
|
|
|
{
|
2010-09-14 10:49:41 -06:00
|
|
|
if (classMethodTable(t, c)) {
|
|
|
|
for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) {
|
|
|
|
object method = arrayBody(t, classMethodTable(t, c), i);
|
|
|
|
if (methodFlags(t, method) & ACC_NATIVE) {
|
2010-11-26 12:41:31 -07:00
|
|
|
set(t, getMethodRuntimeData(t, method), MethodRuntimeDataNative, 0);
|
2010-09-14 10:49:41 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-09-10 15:05:29 -06:00
|
|
|
|
2011-03-26 11:15:52 -06:00
|
|
|
void
|
|
|
|
populateMultiArray(Thread* t, object array, int32_t* counts,
|
|
|
|
unsigned index, unsigned dimensions);
|
|
|
|
|
2010-09-25 15:54:01 -06:00
|
|
|
object
|
|
|
|
getCaller(Thread* t, unsigned target);
|
|
|
|
|
2010-09-10 15:05:29 -06:00
|
|
|
object
|
|
|
|
defineClass(Thread* t, object loader, const uint8_t* buffer, unsigned length);
|
|
|
|
|
2008-11-11 08:20:49 -07:00
|
|
|
void
|
|
|
|
dumpHeap(Thread* t, FILE* out);
|
|
|
|
|
2010-11-04 11:02:09 -06:00
|
|
|
inline object
|
|
|
|
methodClone(Thread* t, object method)
|
|
|
|
{
|
|
|
|
return makeMethod
|
|
|
|
(t, methodVmFlags(t, method),
|
|
|
|
methodReturnCode(t, method),
|
|
|
|
methodParameterCount(t, method),
|
|
|
|
methodParameterFootprint(t, method),
|
|
|
|
methodFlags(t, method),
|
|
|
|
methodOffset(t, method),
|
|
|
|
methodNativeID(t, method),
|
2010-11-26 12:41:31 -07:00
|
|
|
methodRuntimeDataIndex(t, method),
|
2010-11-04 11:02:09 -06:00
|
|
|
methodName(t, method),
|
|
|
|
methodSpec(t, method),
|
|
|
|
methodAddendum(t, method),
|
|
|
|
methodClass(t, method),
|
|
|
|
methodCode(t, method));
|
|
|
|
}
|
|
|
|
|
2011-03-15 17:27:17 -06:00
|
|
|
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
|
|
|
|
|
2008-01-28 08:12:06 -07:00
|
|
|
void
|
|
|
|
vmPrintTrace(vm::Thread* t);
|
|
|
|
|
2009-06-11 09:45:35 -06:00
|
|
|
void*
|
|
|
|
vmAddressFromLine(vm::Thread* t, vm::object m, unsigned line);
|
|
|
|
|
2007-07-06 17:50:26 -06:00
|
|
|
#endif//MACHINE_H
|