final class VMThread
{
    // Note: when this thread dies, this reference is *not* cleared
    private Thread thread;

    private VMThread(Thread thread, long stacksize)
    {
	this.thread = thread;
	start(stacksize);
    }

    // NOTE stop() should take care not to stop the thread if this method
    // is running.
    private void run()
    {
	try
	{
	    try
	    {
		thread.run();
	    }
	    catch(Throwable t)
	    {
		ThreadGroup group = thread.group;
		if(group != null)
		{
		    try
		    {
			group.uncaughtException(thread, t);
		    }
		    catch(Throwable ignore)
		    {
		    }
		}
	    }
	}
	finally
	{
	    ThreadGroup group = thread.group;
	    if(group != null)
	    {
		synchronized(thread)
		{
		    // NOTE consider doing this in native code, to work around
		    // the stop() issue.
		    group.removeThread(thread);
		    thread.vmThread = null;
		}
	    }
	}
    }

    static VMThread create(Thread thread, long stacksize)
    {
	VMThread vmThread = new VMThread(thread, stacksize);
	// memory barrier, to make sure VMThread is fully inialized before it
	// is seen from another thread
	synchronized(thread) {}
	synchronized(thread) {}
	return vmThread;
    }

    static Thread currentThread()
    {
	VMThread vmThread = currentVMThread();
	Thread t = vmThread.thread;
	if(t == null)
	{
	    t = new Thread(vmThread, null, Thread.NORM_PRIORITY, false);
	    // memory barrier, to make sure Thread is fully inialized before it
	    // is seen from another thread
	    synchronized(t) {}
	    synchronized(t) {}
	    vmThread.thread = t;
	}
	return t;
    }

    String getName()
    {
	return thread.name;
    }

    void setName(String name)
    {
    }

    int getPriority()
    {
        return thread.priority;
    }

    boolean isDaemon()
    {
        return thread.daemon;
    }

    int countStackFrames()
    {
	return 0;
    }

    void join(long ms, int ns) throws InterruptedException
    {
	if (ms == 0 && ns == 0)
	    while (thread.isAlive())
		sleep(1);
	else
	{
	    while (--ms >= 0)
	    {
		if (! thread.isAlive())
		    return;
		sleep(1);
	    }
	    sleep(0, ns);
	}
    }

    native void start(long stacksize);
    native void interrupt();
    native boolean isInterrupted();
    native void suspend();
    native void resume();
    native void setPriority(int priority);
    native void stop(Throwable t);

    static native VMThread currentVMThread();
    static native void yield();
    static native void sleep(long ms, int ns) throws InterruptedException;
    static native boolean interrupted();
    static native boolean holdsLock(Object obj);
}
