mirror of
https://github.com/corda/corda.git
synced 2025-01-22 12:28:11 +00:00
Merge branch 'master' of oss:/var/local/git/avian into powerpc
This commit is contained in:
commit
61ecb56e21
@ -267,7 +267,7 @@ Java_java_lang_Runtime_exec(JNIEnv* e, jclass,
|
|||||||
|
|
||||||
// Error if here
|
// Error if here
|
||||||
char c = errno;
|
char c = errno;
|
||||||
write(msg[1], &c, 1);
|
ssize_t rv UNUSED = write(msg[1], &c, 1);
|
||||||
exit(127);
|
exit(127);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
# include <errno.h>
|
# include <errno.h>
|
||||||
# include <netdb.h>
|
# include <netdb.h>
|
||||||
# include <sys/select.h>
|
# include <sys/select.h>
|
||||||
|
# include <netinet/tcp.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define java_nio_channels_SelectionKey_OP_READ 1L
|
#define java_nio_channels_SelectionKey_OP_READ 1L
|
||||||
@ -88,6 +89,26 @@ throwIOException(JNIEnv* e)
|
|||||||
throwIOException(e, errorString(e));
|
throwIOException(e, errorString(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
throwSocketException(JNIEnv* e, const char* s)
|
||||||
|
{
|
||||||
|
throwNew(e, "java/net/SocketException", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
throwSocketException(JNIEnv* e, jbyteArray a)
|
||||||
|
{
|
||||||
|
jbyte* s = static_cast<jbyte*>(e->GetPrimitiveArrayCritical(a, 0));
|
||||||
|
throwSocketException(e, reinterpret_cast<const char*>(s));
|
||||||
|
e->ReleasePrimitiveArrayCritical(a, s, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
throwSocketException(JNIEnv* e)
|
||||||
|
{
|
||||||
|
throwSocketException(e, errorString(e));
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
init(JNIEnv* e, sockaddr_in* address, jstring hostString, jint port)
|
init(JNIEnv* e, sockaddr_in* address, jstring hostString, jint port)
|
||||||
{
|
{
|
||||||
@ -152,6 +173,19 @@ makeNonblocking(JNIEnv* e, int d)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
setTcpNoDelay(JNIEnv* e, int d, bool on)
|
||||||
|
{
|
||||||
|
int flag = on;
|
||||||
|
int r = setsockopt
|
||||||
|
(d, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&flag), sizeof(int));
|
||||||
|
if (r < 0) {
|
||||||
|
throwSocketException(e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
doListen(JNIEnv* e, int s, sockaddr_in* address)
|
doListen(JNIEnv* e, int s, sockaddr_in* address)
|
||||||
{
|
{
|
||||||
@ -277,6 +311,15 @@ Java_java_nio_channels_ServerSocketChannel_natDoListen(JNIEnv *e,
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT void JNICALL
|
||||||
|
Java_java_nio_channels_SocketChannel_natSetTcpNoDelay(JNIEnv *e,
|
||||||
|
jclass,
|
||||||
|
jint socket,
|
||||||
|
jboolean on)
|
||||||
|
{
|
||||||
|
setTcpNoDelay(e, socket, on);
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT jint JNICALL
|
extern "C" JNIEXPORT jint JNICALL
|
||||||
Java_java_nio_channels_SocketChannel_natDoConnect(JNIEnv *e,
|
Java_java_nio_channels_SocketChannel_natDoConnect(JNIEnv *e,
|
||||||
jclass,
|
jclass,
|
||||||
|
15
classpath/java/net/Socket.java
Normal file
15
classpath/java/net/Socket.java
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/* Copyright (c) 2008, Avian Contributors
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software
|
||||||
|
for any purpose with or without fee is hereby granted, provided
|
||||||
|
that the above copyright notice and this permission notice appear
|
||||||
|
in all copies.
|
||||||
|
|
||||||
|
There is NO WARRANTY for this software. See license.txt for
|
||||||
|
details. */
|
||||||
|
|
||||||
|
package java.net;
|
||||||
|
|
||||||
|
public abstract class Socket {
|
||||||
|
public abstract void setTcpNoDelay(boolean on) throws SocketException;
|
||||||
|
}
|
23
classpath/java/net/SocketException.java
Normal file
23
classpath/java/net/SocketException.java
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/* Copyright (c) 2008, Avian Contributors
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software
|
||||||
|
for any purpose with or without fee is hereby granted, provided
|
||||||
|
that the above copyright notice and this permission notice appear
|
||||||
|
in all copies.
|
||||||
|
|
||||||
|
There is NO WARRANTY for this software. See license.txt for
|
||||||
|
details. */
|
||||||
|
|
||||||
|
package java.net;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class SocketException extends IOException {
|
||||||
|
public SocketException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketException() {
|
||||||
|
this(null);
|
||||||
|
}
|
||||||
|
}
|
@ -16,11 +16,21 @@ import java.net.InetSocketAddress;
|
|||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
|
|
||||||
public class ServerSocketChannel extends SocketChannel {
|
public class ServerSocketChannel extends SelectableChannel {
|
||||||
|
private final SocketChannel channel = new SocketChannel();
|
||||||
|
|
||||||
public static ServerSocketChannel open() {
|
public static ServerSocketChannel open() {
|
||||||
return new ServerSocketChannel();
|
return new ServerSocketChannel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SelectableChannel configureBlocking(boolean v) {
|
||||||
|
return channel.configureBlocking(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws IOException {
|
||||||
|
channel.close();
|
||||||
|
}
|
||||||
|
|
||||||
public SocketChannel accept() throws Exception {
|
public SocketChannel accept() throws Exception {
|
||||||
SocketChannel c = new SocketChannel();
|
SocketChannel c = new SocketChannel();
|
||||||
c.socket = doAccept();
|
c.socket = doAccept();
|
||||||
@ -33,7 +43,7 @@ public class ServerSocketChannel extends SocketChannel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int doAccept() throws IOException {
|
private int doAccept() throws IOException {
|
||||||
return natDoAccept(socket);
|
return natDoAccept(channel.socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int doListen(String host, int port) throws IOException {
|
private int doListen(String host, int port) throws IOException {
|
||||||
@ -50,7 +60,7 @@ public class ServerSocketChannel extends SocketChannel {
|
|||||||
} catch (ClassCastException e) {
|
} catch (ClassCastException e) {
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
socket = doListen(a.getHostName(), a.getPort());
|
channel.socket = doListen(a.getHostName(), a.getPort());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,8 +11,10 @@
|
|||||||
package java.nio.channels;
|
package java.nio.channels;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.SocketException;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.Socket;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
public class SocketChannel extends SelectableChannel
|
public class SocketChannel extends SelectableChannel
|
||||||
@ -20,8 +22,8 @@ public class SocketChannel extends SelectableChannel
|
|||||||
{
|
{
|
||||||
public static final int InvalidSocket = -1;
|
public static final int InvalidSocket = -1;
|
||||||
|
|
||||||
protected int socket = InvalidSocket;
|
int socket = InvalidSocket;
|
||||||
protected boolean connected = false;
|
boolean connected = false;
|
||||||
|
|
||||||
public static SocketChannel open() {
|
public static SocketChannel open() {
|
||||||
return new SocketChannel();
|
return new SocketChannel();
|
||||||
@ -32,6 +34,10 @@ public class SocketChannel extends SelectableChannel
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Socket socket() {
|
||||||
|
return new Handle();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean connect(SocketAddress address) throws Exception {
|
public boolean connect(SocketAddress address) throws Exception {
|
||||||
InetSocketAddress a;
|
InetSocketAddress a;
|
||||||
try {
|
try {
|
||||||
@ -87,6 +93,15 @@ public class SocketChannel extends SelectableChannel
|
|||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class Handle extends Socket {
|
||||||
|
public void setTcpNoDelay(boolean on) throws SocketException {
|
||||||
|
natSetTcpNoDelay(socket, on);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static native void natSetTcpNoDelay(int socket, boolean on)
|
||||||
|
throws SocketException;
|
||||||
|
|
||||||
private static native int natDoConnect(String host, int port, boolean[] connected)
|
private static native int natDoConnect(String host, int port, boolean[] connected)
|
||||||
throws Exception;
|
throws Exception;
|
||||||
private static native int natRead(int socket, byte[] buffer, int offset, int length)
|
private static native int natRead(int socket, byte[] buffer, int offset, int length)
|
||||||
|
2
makefile
2
makefile
@ -59,7 +59,7 @@ rdynamic = -rdynamic
|
|||||||
warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self \
|
warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self \
|
||||||
-Wno-non-virtual-dtor
|
-Wno-non-virtual-dtor
|
||||||
|
|
||||||
common-cflags = $(warnings) -fno-rtti -fno-exceptions \
|
common-cflags = $(warnings) -fno-rtti -fno-exceptions -fno-omit-frame-pointer \
|
||||||
"-I$(JAVA_HOME)/include" -idirafter $(src) -I$(native-build) \
|
"-I$(JAVA_HOME)/include" -idirafter $(src) -I$(native-build) \
|
||||||
-D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \
|
-D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \
|
||||||
-DBOOT_CLASSPATH=\"[classpathJar]\"
|
-DBOOT_CLASSPATH=\"[classpathJar]\"
|
||||||
|
@ -5338,7 +5338,7 @@ compile(MyThread* t, object method)
|
|||||||
PROTECT(t, node);
|
PROTECT(t, node);
|
||||||
|
|
||||||
methodTree(t) = treeInsertNode
|
methodTree(t) = treeInsertNode
|
||||||
(t, methodTree(t), reinterpret_cast<intptr_t>
|
(t, &(context.zone), methodTree(t), reinterpret_cast<intptr_t>
|
||||||
(&singletonValue(t, compiled, 0)), node, methodTreeSentinal(t),
|
(&singletonValue(t, compiled, 0)), node, methodTreeSentinal(t),
|
||||||
compareIpToMethodBounds);
|
compareIpToMethodBounds);
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,7 @@ hash(object p, unsigned capacity)
|
|||||||
Set::Entry*
|
Set::Entry*
|
||||||
find(Context* c, object p)
|
find(Context* c, object p)
|
||||||
{
|
{
|
||||||
if (c->objects == 0) return false;
|
if (c->objects == 0) return 0;
|
||||||
|
|
||||||
for (int i = c->objects->index[hash(p, c->objects->capacity)]; i >= 0;) {
|
for (int i = c->objects->index[hash(p, c->objects->capacity)]; i >= 0;) {
|
||||||
Set::Entry* e = c->objects->entries + i;
|
Set::Entry* e = c->objects->entries + i;
|
||||||
@ -143,7 +143,7 @@ find(Context* c, object p)
|
|||||||
i = e->next;
|
i = e->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Set::Entry*
|
Set::Entry*
|
||||||
|
@ -482,9 +482,9 @@ void
|
|||||||
postCollect(Thread* t)
|
postCollect(Thread* t)
|
||||||
{
|
{
|
||||||
#ifdef VM_STRESS
|
#ifdef VM_STRESS
|
||||||
t->m->heap->free(t->defaultHeap, Thread::HeapSizeInBytes);
|
t->m->heap->free(t->defaultHeap, ThreadHeapSizeInBytes);
|
||||||
t->defaultHeap = static_cast<uintptr_t*>
|
t->defaultHeap = static_cast<uintptr_t*>
|
||||||
(t->m->heap->allocate(Thread::HeapSizeInBytes));
|
(t->m->heap->allocate(ThreadHeapSizeInBytes));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
t->heap = t->defaultHeap;
|
t->heap = t->defaultHeap;
|
||||||
@ -770,12 +770,8 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool)
|
|||||||
PROTECT(t, interfaceTable);
|
PROTECT(t, interfaceTable);
|
||||||
|
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
object it = hashMapIterator(t, map);
|
for (HashMapIterator it(t, map); it.hasMore();) {
|
||||||
PROTECT(t, it);
|
object interface = resolveClass(t, tripleFirst(t, it.next()));
|
||||||
|
|
||||||
for (; it; it = hashMapIteratorNext(t, it)) {
|
|
||||||
object interface = resolveClass
|
|
||||||
(t, tripleFirst(t, hashMapIteratorNode(t, it)));
|
|
||||||
if (UNLIKELY(t->exception)) return;
|
if (UNLIKELY(t->exception)) return;
|
||||||
|
|
||||||
set(t, interfaceTable, ArrayBody + (i * BytesPerWord), interface);
|
set(t, interfaceTable, ArrayBody + (i * BytesPerWord), interface);
|
||||||
@ -1243,10 +1239,8 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
|||||||
if (classFlags(t, class_) & ACC_INTERFACE) {
|
if (classFlags(t, class_) & ACC_INTERFACE) {
|
||||||
PROTECT(t, vtable);
|
PROTECT(t, vtable);
|
||||||
|
|
||||||
for (object it = hashMapIterator(t, virtualMap); it;
|
for (HashMapIterator it(t, virtualMap); it.hasMore();) {
|
||||||
it = hashMapIteratorNext(t, it))
|
object method = tripleFirst(t, it.next());
|
||||||
{
|
|
||||||
object method = tripleFirst(t, hashMapIteratorNode(t, it));
|
|
||||||
assert(t, arrayBody(t, vtable, methodOffset(t, method)) == 0);
|
assert(t, arrayBody(t, vtable, methodOffset(t, method)) == 0);
|
||||||
set(t, vtable, ArrayBody + (methodOffset(t, method) * BytesPerWord),
|
set(t, vtable, ArrayBody + (methodOffset(t, method) * BytesPerWord),
|
||||||
method);
|
method);
|
||||||
@ -1703,7 +1697,7 @@ Machine::dispose()
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned i = 0; i < heapPoolIndex; ++i) {
|
for (unsigned i = 0; i < heapPoolIndex; ++i) {
|
||||||
heap->free(heapPool[i], Thread::HeapSizeInBytes);
|
heap->free(heapPool[i], ThreadHeapSizeInBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
heap->free(properties, sizeof(const char*) * propertyCount);
|
heap->free(properties, sizeof(const char*) * propertyCount);
|
||||||
@ -1729,7 +1723,7 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent):
|
|||||||
protector(0),
|
protector(0),
|
||||||
runnable(this),
|
runnable(this),
|
||||||
defaultHeap(static_cast<uintptr_t*>
|
defaultHeap(static_cast<uintptr_t*>
|
||||||
(m->heap->allocate(HeapSizeInBytes))),
|
(m->heap->allocate(ThreadHeapSizeInBytes))),
|
||||||
heap(defaultHeap),
|
heap(defaultHeap),
|
||||||
backupHeap(0),
|
backupHeap(0),
|
||||||
backupHeapIndex(0),
|
backupHeapIndex(0),
|
||||||
@ -1870,7 +1864,7 @@ Thread::dispose()
|
|||||||
systemThread->dispose();
|
systemThread->dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
m->heap->free(defaultHeap, Thread::HeapSizeInBytes);
|
m->heap->free(defaultHeap, ThreadHeapSizeInBytes);
|
||||||
|
|
||||||
m->processor->dispose(this);
|
m->processor->dispose(this);
|
||||||
}
|
}
|
||||||
@ -2028,7 +2022,7 @@ allocate2(Thread* t, unsigned sizeInBytes, bool objectMask)
|
|||||||
{
|
{
|
||||||
return allocate3
|
return allocate3
|
||||||
(t, t->m->heap,
|
(t, t->m->heap,
|
||||||
ceiling(sizeInBytes, BytesPerWord) > Thread::HeapSizeInWords ?
|
ceiling(sizeInBytes, BytesPerWord) > ThreadHeapSizeInWords ?
|
||||||
Machine::FixedAllocation : Machine::MovableAllocation,
|
Machine::FixedAllocation : Machine::MovableAllocation,
|
||||||
sizeInBytes, objectMask);
|
sizeInBytes, objectMask);
|
||||||
}
|
}
|
||||||
@ -2047,7 +2041,7 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
|
|||||||
return o;
|
return o;
|
||||||
} else if (t->tracing) {
|
} else if (t->tracing) {
|
||||||
expect(t, t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
expect(t, t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
||||||
<= Thread::HeapSizeInWords);
|
<= ThreadHeapSizeInWords);
|
||||||
return allocateSmall(t, sizeInBytes);
|
return allocateSmall(t, sizeInBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2058,26 +2052,33 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
|
|||||||
// collection or some other reason. We give it a chance here.
|
// collection or some other reason. We give it a chance here.
|
||||||
ENTER(t, Thread::IdleState);
|
ENTER(t, Thread::IdleState);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == Machine::FixedAllocation) {
|
switch (type) {
|
||||||
if (t->m->fixedFootprint + sizeInBytes
|
case Machine::MovableAllocation:
|
||||||
> Machine::FixedFootprintThresholdInBytes)
|
if (t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
||||||
|
> ThreadHeapSizeInWords)
|
||||||
{
|
{
|
||||||
t->heap = 0;
|
t->heap = 0;
|
||||||
}
|
if (t->m->heapPoolIndex < ThreadHeapPoolSize) {
|
||||||
} else if (t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
t->heap = static_cast<uintptr_t*>
|
||||||
> Thread::HeapSizeInWords)
|
(t->m->heap->tryAllocate(ThreadHeapSizeInBytes));
|
||||||
{
|
if (t->heap) {
|
||||||
t->heap = 0;
|
t->m->heapPool[t->m->heapPoolIndex++] = t->heap;
|
||||||
if (t->m->heapPoolIndex < Machine::HeapPoolSize) {
|
t->heapOffset += t->heapIndex;
|
||||||
t->heap = static_cast<uintptr_t*>
|
t->heapIndex = 0;
|
||||||
(t->m->heap->tryAllocate(Thread::HeapSizeInBytes));
|
}
|
||||||
if (t->heap) {
|
|
||||||
t->m->heapPool[t->m->heapPoolIndex++] = t->heap;
|
|
||||||
t->heapOffset += t->heapIndex;
|
|
||||||
t->heapIndex = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Machine::FixedAllocation:
|
||||||
|
if (t->m->fixedFootprint + sizeInBytes > FixedFootprintThresholdInBytes) {
|
||||||
|
t->heap = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Machine::ImmortalAllocation:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t->heap == 0) {
|
if (t->heap == 0) {
|
||||||
@ -2758,7 +2759,7 @@ collect(Thread* t, Heap::CollectionType type)
|
|||||||
killZombies(t, m->rootThread);
|
killZombies(t, m->rootThread);
|
||||||
|
|
||||||
for (unsigned i = 0; i < m->heapPoolIndex; ++i) {
|
for (unsigned i = 0; i < m->heapPoolIndex; ++i) {
|
||||||
m->heap->free(m->heapPool[i], Thread::HeapSizeInBytes);
|
m->heap->free(m->heapPool[i], ThreadHeapSizeInBytes);
|
||||||
}
|
}
|
||||||
m->heapPoolIndex = 0;
|
m->heapPoolIndex = 0;
|
||||||
|
|
||||||
|
@ -45,6 +45,14 @@ const uintptr_t HashTakenMark = 1;
|
|||||||
const uintptr_t ExtendedMark = 2;
|
const uintptr_t ExtendedMark = 2;
|
||||||
const uintptr_t FixedMark = 3;
|
const uintptr_t FixedMark = 3;
|
||||||
|
|
||||||
|
const unsigned ThreadHeapSizeInBytes = 64 * 1024;
|
||||||
|
const unsigned ThreadHeapSizeInWords = ThreadHeapSizeInBytes / BytesPerWord;
|
||||||
|
|
||||||
|
const unsigned ThreadHeapPoolSize = 64;
|
||||||
|
|
||||||
|
const unsigned FixedFootprintThresholdInBytes
|
||||||
|
= ThreadHeapPoolSize * ThreadHeapSizeInBytes;
|
||||||
|
|
||||||
enum FieldCode {
|
enum FieldCode {
|
||||||
VoidField,
|
VoidField,
|
||||||
ByteField,
|
ByteField,
|
||||||
@ -1144,10 +1152,6 @@ class Machine {
|
|||||||
dispose();
|
dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
static const unsigned HeapPoolSize = 8;
|
|
||||||
|
|
||||||
static const unsigned FixedFootprintThresholdInBytes = 256 * 1024;
|
|
||||||
|
|
||||||
void dispose();
|
void dispose();
|
||||||
|
|
||||||
JavaVMVTable* vtable;
|
JavaVMVTable* vtable;
|
||||||
@ -1184,7 +1188,7 @@ class Machine {
|
|||||||
bool unsafe;
|
bool unsafe;
|
||||||
JavaVMVTable javaVMVTable;
|
JavaVMVTable javaVMVTable;
|
||||||
JNIEnvVTable jniEnvVTable;
|
JNIEnvVTable jniEnvVTable;
|
||||||
uintptr_t* heapPool[HeapPoolSize];
|
uintptr_t* heapPool[ThreadHeapPoolSize];
|
||||||
unsigned heapPoolIndex;
|
unsigned heapPoolIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1282,9 +1286,6 @@ class Thread {
|
|||||||
Thread* t;
|
Thread* t;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned HeapSizeInBytes = 64 * 1024;
|
|
||||||
static const unsigned HeapSizeInWords = HeapSizeInBytes / BytesPerWord;
|
|
||||||
|
|
||||||
Thread(Machine* m, object javaThread, Thread* parent);
|
Thread(Machine* m, object javaThread, Thread* parent);
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
@ -1452,7 +1453,7 @@ inline void
|
|||||||
ensure(Thread* t, unsigned sizeInBytes)
|
ensure(Thread* t, unsigned sizeInBytes)
|
||||||
{
|
{
|
||||||
if (t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
if (t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
||||||
> Thread::HeapSizeInWords)
|
> ThreadHeapSizeInWords)
|
||||||
{
|
{
|
||||||
expect(t, t->backupHeap == 0);
|
expect(t, t->backupHeap == 0);
|
||||||
t->backupHeap = static_cast<uintptr_t*>
|
t->backupHeap = static_cast<uintptr_t*>
|
||||||
@ -1484,7 +1485,7 @@ allocate(Thread* t, unsigned sizeInBytes, bool objectMask)
|
|||||||
stress(t);
|
stress(t);
|
||||||
|
|
||||||
if (UNLIKELY(t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
if (UNLIKELY(t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
||||||
> Thread::HeapSizeInWords
|
> ThreadHeapSizeInWords
|
||||||
or t->m->exclusive))
|
or t->m->exclusive))
|
||||||
{
|
{
|
||||||
return allocate2(t, sizeInBytes, objectMask);
|
return allocate2(t, sizeInBytes, objectMask);
|
||||||
|
@ -73,11 +73,6 @@
|
|||||||
(type weakHashMap
|
(type weakHashMap
|
||||||
(extends hashMap))
|
(extends hashMap))
|
||||||
|
|
||||||
(type hashMapIterator
|
|
||||||
(object map)
|
|
||||||
(object node)
|
|
||||||
(unsigned index))
|
|
||||||
|
|
||||||
(type list
|
(type list
|
||||||
(uint32_t size)
|
(uint32_t size)
|
||||||
(object front)
|
(object front)
|
||||||
@ -95,12 +90,6 @@
|
|||||||
(object value)
|
(object value)
|
||||||
(object left)
|
(object left)
|
||||||
(object right))
|
(object right))
|
||||||
|
|
||||||
(type treePath
|
|
||||||
(uintptr_t fresh)
|
|
||||||
(object node)
|
|
||||||
(object root)
|
|
||||||
(object ancestors))
|
|
||||||
|
|
||||||
(type callNode
|
(type callNode
|
||||||
(intptr_t address)
|
(intptr_t address)
|
||||||
|
230
src/util.cpp
230
src/util.cpp
@ -14,6 +14,54 @@ using namespace vm;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
class TreeContext {
|
||||||
|
public:
|
||||||
|
class Path {
|
||||||
|
public:
|
||||||
|
Path(object node, Path* next): node(node), next(next) { }
|
||||||
|
|
||||||
|
object node;
|
||||||
|
Path* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MyProtector: public Thread::Protector {
|
||||||
|
public:
|
||||||
|
MyProtector(Thread* thread, TreeContext* context):
|
||||||
|
Protector(thread), context(context)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
virtual void visit(Heap::Visitor* v) {
|
||||||
|
v->visit(&(context->root));
|
||||||
|
v->visit(&(context->node));
|
||||||
|
|
||||||
|
for (Path* p = context->ancestors; p; p = p->next) {
|
||||||
|
v->visit(&(p->node));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeContext* context;
|
||||||
|
};
|
||||||
|
|
||||||
|
TreeContext(Thread* thread, Zone* zone):
|
||||||
|
zone(zone), root(0), node(0), ancestors(0), protector(thread, this),
|
||||||
|
fresh(false)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
Zone* zone;
|
||||||
|
object root;
|
||||||
|
object node;
|
||||||
|
Path* ancestors;
|
||||||
|
MyProtector protector;
|
||||||
|
bool fresh;
|
||||||
|
};
|
||||||
|
|
||||||
|
TreeContext::Path*
|
||||||
|
path(TreeContext* c, object node, TreeContext::Path* next)
|
||||||
|
{
|
||||||
|
return new (c->zone->allocate(sizeof(TreeContext::Path)))
|
||||||
|
TreeContext::Path(node, next);
|
||||||
|
}
|
||||||
|
|
||||||
inline object
|
inline object
|
||||||
getTreeNodeValue(Thread*, object n)
|
getTreeNodeValue(Thread*, object n)
|
||||||
{
|
{
|
||||||
@ -58,8 +106,9 @@ cloneTreeNode(Thread* t, object n)
|
|||||||
return newNode;
|
return newNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
object
|
void
|
||||||
treeFind(Thread* t, object old, intptr_t key, object node, object sentinal,
|
treeFind(Thread* t, TreeContext* c, object old, intptr_t key, object node,
|
||||||
|
object sentinal,
|
||||||
intptr_t (*compare)(Thread* t, intptr_t key, object b))
|
intptr_t (*compare)(Thread* t, intptr_t key, object b))
|
||||||
{
|
{
|
||||||
PROTECT(t, old);
|
PROTECT(t, old);
|
||||||
@ -72,11 +121,8 @@ treeFind(Thread* t, object old, intptr_t key, object node, object sentinal,
|
|||||||
object new_ = newRoot;
|
object new_ = newRoot;
|
||||||
PROTECT(t, new_);
|
PROTECT(t, new_);
|
||||||
|
|
||||||
object ancestors = 0;
|
|
||||||
PROTECT(t, ancestors);
|
|
||||||
|
|
||||||
while (old != sentinal) {
|
while (old != sentinal) {
|
||||||
ancestors = makePair(t, new_, ancestors);
|
c->ancestors = path(c, new_, c->ancestors);
|
||||||
|
|
||||||
intptr_t difference = compare(t, key, getTreeNodeValue(t, old));
|
intptr_t difference = compare(t, key, getTreeNodeValue(t, old));
|
||||||
|
|
||||||
@ -91,13 +137,20 @@ treeFind(Thread* t, object old, intptr_t key, object node, object sentinal,
|
|||||||
set(t, new_, TreeNodeRight, n);
|
set(t, new_, TreeNodeRight, n);
|
||||||
new_ = n;
|
new_ = n;
|
||||||
} else {
|
} else {
|
||||||
return makeTreePath(t, false, new_, newRoot, pairSecond(t, ancestors));
|
c->fresh = false;
|
||||||
|
c->root = newRoot;
|
||||||
|
c->node = new_;
|
||||||
|
c->ancestors = c->ancestors->next;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setTreeNodeValue(t, new_, getTreeNodeValue(t, node));
|
setTreeNodeValue(t, new_, getTreeNodeValue(t, node));
|
||||||
|
|
||||||
return makeTreePath(t, true, new_, newRoot, ancestors);
|
c->fresh = true;
|
||||||
|
c->root = newRoot;
|
||||||
|
c->node = new_;
|
||||||
|
c->ancestors = c->ancestors;
|
||||||
}
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
@ -123,122 +176,109 @@ rightRotate(Thread* t, object n)
|
|||||||
}
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
treeAdd(Thread* t, object path)
|
treeAdd(Thread* t, TreeContext* c)
|
||||||
{
|
{
|
||||||
object new_ = treePathNode(t, path);
|
object new_ = c->node;
|
||||||
PROTECT(t, new_);
|
PROTECT(t, new_);
|
||||||
|
|
||||||
object newRoot = treePathRoot(t, path);
|
object newRoot = c->root;
|
||||||
PROTECT(t, newRoot);
|
PROTECT(t, newRoot);
|
||||||
|
|
||||||
object ancestors = treePathAncestors(t, path);
|
|
||||||
PROTECT(t, ancestors);
|
|
||||||
|
|
||||||
// rebalance
|
// rebalance
|
||||||
setTreeNodeRed(t, new_, true);
|
setTreeNodeRed(t, new_, true);
|
||||||
while (ancestors != 0 and treeNodeRed(t, pairFirst(t, ancestors))) {
|
while (c->ancestors != 0 and treeNodeRed(t, c->ancestors->node)) {
|
||||||
if (pairFirst(t, ancestors)
|
if (c->ancestors->node
|
||||||
== treeNodeLeft(t, pairFirst(t, pairSecond(t, ancestors))))
|
== treeNodeLeft(t, c->ancestors->next->node))
|
||||||
{
|
{
|
||||||
if (treeNodeRed
|
if (treeNodeRed
|
||||||
(t, treeNodeRight(t, pairFirst(t, pairSecond(t, ancestors)))))
|
(t, treeNodeRight(t, c->ancestors->next->node)))
|
||||||
{
|
{
|
||||||
setTreeNodeRed(t, pairFirst(t, ancestors), true);
|
setTreeNodeRed(t, c->ancestors->node, false);
|
||||||
|
|
||||||
object n = cloneTreeNode
|
object n = cloneTreeNode
|
||||||
(t, treeNodeRight(t, pairFirst(t, pairSecond(t, ancestors))));
|
(t, treeNodeRight(t, c->ancestors->next->node));
|
||||||
|
|
||||||
set(t, pairFirst(t, pairSecond(t, ancestors)), TreeNodeRight, n);
|
set(t, c->ancestors->next->node, TreeNodeRight, n);
|
||||||
|
|
||||||
setTreeNodeRed
|
setTreeNodeRed(t, treeNodeRight(t, c->ancestors->next->node), false);
|
||||||
(t, treeNodeRight
|
|
||||||
(t, pairFirst(t, pairSecond(t, ancestors))), false);
|
|
||||||
|
|
||||||
setTreeNodeRed(t, pairFirst(t, pairSecond(t, ancestors)), false);
|
setTreeNodeRed(t, c->ancestors->next->node, true);
|
||||||
|
|
||||||
new_ = pairFirst(t, pairSecond(t, ancestors));
|
new_ = c->ancestors->next->node;
|
||||||
ancestors = pairSecond(t, pairSecond(t, ancestors));
|
c->ancestors = c->ancestors->next->next;
|
||||||
} else {
|
} else {
|
||||||
if (new_ == treeNodeRight(t, pairFirst(t, ancestors))) {
|
if (new_ == treeNodeRight(t, c->ancestors->node)) {
|
||||||
new_ = pairFirst(t, ancestors);
|
new_ = c->ancestors->node;
|
||||||
ancestors = pairSecond(t, ancestors);
|
c->ancestors = c->ancestors->next;
|
||||||
|
|
||||||
object n = leftRotate(t, new_);
|
object n = leftRotate(t, new_);
|
||||||
|
|
||||||
if (new_ == treeNodeRight(t, pairFirst(t, ancestors))) {
|
if (new_ == treeNodeRight(t, c->ancestors->node)) {
|
||||||
set(t, pairFirst(t, ancestors), TreeNodeRight, n);
|
set(t, c->ancestors->node, TreeNodeRight, n);
|
||||||
} else {
|
} else {
|
||||||
set(t, pairFirst(t, ancestors), TreeNodeLeft, n);
|
set(t, c->ancestors->node, TreeNodeLeft, n);
|
||||||
}
|
}
|
||||||
ancestors = makePair(t, n, ancestors);
|
c->ancestors = path(c, n, c->ancestors);
|
||||||
}
|
}
|
||||||
setTreeNodeRed(t, pairFirst(t, ancestors), false);
|
setTreeNodeRed(t, c->ancestors->node, false);
|
||||||
setTreeNodeRed(t, pairFirst(t, pairSecond(t, ancestors)), true);
|
setTreeNodeRed(t, c->ancestors->next->node, true);
|
||||||
|
|
||||||
object n = rightRotate(t, pairFirst(t, pairSecond(t, ancestors)));
|
object n = rightRotate(t, c->ancestors->next->node);
|
||||||
if (pairSecond(t, pairSecond(t, ancestors)) == 0) {
|
if (c->ancestors->next->next == 0) {
|
||||||
newRoot = n;
|
newRoot = n;
|
||||||
} else if (treeNodeRight
|
} else if (treeNodeRight(t, c->ancestors->next->next->node)
|
||||||
(t, pairFirst(t, pairSecond(t, pairSecond(t, ancestors))))
|
== c->ancestors->next->node)
|
||||||
== pairFirst(t, pairSecond(t, ancestors)))
|
|
||||||
{
|
{
|
||||||
set(t, pairFirst(t, pairSecond(t, pairSecond(t, ancestors))),
|
set(t, c->ancestors->next->next->node, TreeNodeRight, n);
|
||||||
TreeNodeRight, n);
|
|
||||||
} else {
|
} else {
|
||||||
set(t, pairFirst(t, pairSecond(t, pairSecond(t, ancestors))),
|
set(t, c->ancestors->next->next->node, TreeNodeLeft, n);
|
||||||
TreeNodeLeft, n);
|
|
||||||
}
|
}
|
||||||
// done
|
// done
|
||||||
}
|
}
|
||||||
} else { // this is just the reverse of the code above (right and
|
} else { // this is just the reverse of the code above (right and
|
||||||
// left swapped):
|
// left swapped):
|
||||||
if (treeNodeRed
|
if (treeNodeRed
|
||||||
(t, treeNodeLeft(t, pairFirst(t, pairSecond(t, ancestors)))))
|
(t, treeNodeLeft(t, c->ancestors->next->node)))
|
||||||
{
|
{
|
||||||
setTreeNodeRed(t, pairFirst(t, ancestors), true);
|
setTreeNodeRed(t, c->ancestors->node, false);
|
||||||
|
|
||||||
object n = cloneTreeNode
|
object n = cloneTreeNode
|
||||||
(t, treeNodeLeft(t, pairFirst(t, pairSecond(t, ancestors))));
|
(t, treeNodeLeft(t, c->ancestors->next->node));
|
||||||
|
|
||||||
set(t, pairFirst(t, pairSecond(t, ancestors)), TreeNodeLeft, n);
|
set(t, c->ancestors->next->node, TreeNodeLeft, n);
|
||||||
|
|
||||||
setTreeNodeRed
|
setTreeNodeRed(t, treeNodeLeft(t, c->ancestors->next->node), false);
|
||||||
(t, treeNodeLeft
|
|
||||||
(t, pairFirst(t, pairSecond(t, ancestors))), false);
|
|
||||||
|
|
||||||
setTreeNodeRed(t, pairFirst(t, pairSecond(t, ancestors)), false);
|
setTreeNodeRed(t, c->ancestors->next->node, true);
|
||||||
|
|
||||||
new_ = pairFirst(t, pairSecond(t, ancestors));
|
new_ = c->ancestors->next->node;
|
||||||
ancestors = pairSecond(t, pairSecond(t, ancestors));
|
c->ancestors = c->ancestors->next->next;
|
||||||
} else {
|
} else {
|
||||||
if (new_ == treeNodeLeft(t, pairFirst(t, ancestors))) {
|
if (new_ == treeNodeLeft(t, c->ancestors->node)) {
|
||||||
new_ = pairFirst(t, ancestors);
|
new_ = c->ancestors->node;
|
||||||
ancestors = pairSecond(t, ancestors);
|
c->ancestors = c->ancestors->next;
|
||||||
|
|
||||||
object n = rightRotate(t, new_);
|
object n = rightRotate(t, new_);
|
||||||
|
|
||||||
if (new_ == treeNodeLeft(t, pairFirst(t, ancestors))) {
|
if (new_ == treeNodeLeft(t, c->ancestors->node)) {
|
||||||
set(t, pairFirst(t, ancestors), TreeNodeLeft, n);
|
set(t, c->ancestors->node, TreeNodeLeft, n);
|
||||||
} else {
|
} else {
|
||||||
set(t, pairFirst(t, ancestors), TreeNodeRight, n);
|
set(t, c->ancestors->node, TreeNodeRight, n);
|
||||||
}
|
}
|
||||||
ancestors = makePair(t, n, ancestors);
|
c->ancestors = path(c, n, c->ancestors);
|
||||||
}
|
}
|
||||||
setTreeNodeRed(t, pairFirst(t, ancestors), false);
|
setTreeNodeRed(t, c->ancestors->node, false);
|
||||||
setTreeNodeRed(t, pairFirst(t, pairSecond(t, ancestors)), true);
|
setTreeNodeRed(t, c->ancestors->next->node, true);
|
||||||
|
|
||||||
object n = leftRotate(t, pairFirst(t, pairSecond(t, ancestors)));
|
object n = leftRotate(t, c->ancestors->next->node);
|
||||||
if (pairSecond(t, pairSecond(t, ancestors)) == 0) {
|
if (c->ancestors->next->next == 0) {
|
||||||
newRoot = n;
|
newRoot = n;
|
||||||
} else if (treeNodeLeft
|
} else if (treeNodeLeft(t, c->ancestors->next->next->node)
|
||||||
(t, pairFirst(t, pairSecond(t, pairSecond(t, ancestors))))
|
== c->ancestors->next->node)
|
||||||
== pairFirst(t, pairSecond(t, ancestors)))
|
|
||||||
{
|
{
|
||||||
set(t, pairFirst(t, pairSecond(t, pairSecond(t, ancestors))),
|
set(t, c->ancestors->next->next->node, TreeNodeLeft, n);
|
||||||
TreeNodeLeft, n);
|
|
||||||
} else {
|
} else {
|
||||||
set(t, pairFirst(t, pairSecond(t, pairSecond(t, ancestors))),
|
set(t, c->ancestors->next->next->node, TreeNodeRight, n);
|
||||||
TreeNodeRight, n);
|
|
||||||
}
|
}
|
||||||
// done
|
// done
|
||||||
}
|
}
|
||||||
@ -442,40 +482,6 @@ hashMapRemove(Thread* t, object map, object key,
|
|||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
object
|
|
||||||
hashMapIterator(Thread* t, object map)
|
|
||||||
{
|
|
||||||
object array = hashMapArray(t, map);
|
|
||||||
if (array) {
|
|
||||||
for (unsigned i = 0; i < arrayLength(t, array); ++i) {
|
|
||||||
if (arrayBody(t, array, i)) {
|
|
||||||
return makeHashMapIterator(t, map, arrayBody(t, array, i), i + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
object
|
|
||||||
hashMapIteratorNext(Thread* t, object it)
|
|
||||||
{
|
|
||||||
object map = hashMapIteratorMap(t, it);
|
|
||||||
object node = hashMapIteratorNode(t, it);
|
|
||||||
unsigned index = hashMapIteratorIndex(t, it);
|
|
||||||
|
|
||||||
if (tripleThird(t, node)) {
|
|
||||||
return makeHashMapIterator(t, map, tripleThird(t, node), index);
|
|
||||||
} else {
|
|
||||||
object array = hashMapArray(t, map);
|
|
||||||
for (unsigned i = index; i < arrayLength(t, array); ++i) {
|
|
||||||
if (arrayBody(t, array, i)) {
|
|
||||||
return makeHashMapIterator(t, map, arrayBody(t, array, i), i + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
listAppend(Thread* t, object list, object value)
|
listAppend(Thread* t, object list, object value)
|
||||||
{
|
{
|
||||||
@ -541,16 +547,18 @@ treeQuery(Thread* t, object tree, intptr_t key, object sentinal,
|
|||||||
}
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
treeInsertNode(Thread* t, object tree, intptr_t key, object node,
|
treeInsertNode(Thread* t, Zone* zone, object tree, intptr_t key, object node,
|
||||||
object sentinal,
|
object sentinal,
|
||||||
intptr_t (*compare)(Thread* t, intptr_t key, object b))
|
intptr_t (*compare)(Thread* t, intptr_t key, object b))
|
||||||
{
|
{
|
||||||
PROTECT(t, tree);
|
PROTECT(t, tree);
|
||||||
PROTECT(t, sentinal);
|
PROTECT(t, sentinal);
|
||||||
|
|
||||||
object path = treeFind(t, tree, key, node, sentinal, compare);
|
TreeContext c(t, zone);
|
||||||
expect(t, treePathFresh(t, path));
|
treeFind(t, &c, tree, key, node, sentinal, compare);
|
||||||
return treeAdd(t, path);
|
expect(t, c.fresh);
|
||||||
|
|
||||||
|
return treeAdd(t, &c);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace vm
|
} // namespace vm
|
||||||
|
51
src/util.h
51
src/util.h
@ -12,6 +12,7 @@
|
|||||||
#define UTIL_H
|
#define UTIL_H
|
||||||
|
|
||||||
#include "machine.h"
|
#include "machine.h"
|
||||||
|
#include "zone.h"
|
||||||
|
|
||||||
namespace vm {
|
namespace vm {
|
||||||
|
|
||||||
@ -88,10 +89,58 @@ treeQuery(Thread* t, object tree, intptr_t key, object sentinal,
|
|||||||
intptr_t (*compare)(Thread* t, intptr_t key, object b));
|
intptr_t (*compare)(Thread* t, intptr_t key, object b));
|
||||||
|
|
||||||
object
|
object
|
||||||
treeInsertNode(Thread* t, object tree, intptr_t key, object node,
|
treeInsertNode(Thread* t, Zone* zone, object tree, intptr_t key, object node,
|
||||||
object sentinal,
|
object sentinal,
|
||||||
intptr_t (*compare)(Thread* t, intptr_t key, object b));
|
intptr_t (*compare)(Thread* t, intptr_t key, object b));
|
||||||
|
|
||||||
|
class HashMapIterator: public Thread::Protector {
|
||||||
|
public:
|
||||||
|
HashMapIterator(Thread* t, object map):
|
||||||
|
Protector(t), map(map), node(0), index(0)
|
||||||
|
{
|
||||||
|
find();
|
||||||
|
}
|
||||||
|
|
||||||
|
void find() {
|
||||||
|
object array = hashMapArray(t, map);
|
||||||
|
for (unsigned i = index; i < arrayLength(t, array); ++i) {
|
||||||
|
if (arrayBody(t, array, i)) {
|
||||||
|
node = arrayBody(t, array, i);
|
||||||
|
index = i + 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasMore() {
|
||||||
|
return node != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
object next() {
|
||||||
|
if (node) {
|
||||||
|
object n = node;
|
||||||
|
if (tripleThird(t, node)) {
|
||||||
|
node = tripleThird(t, node);
|
||||||
|
} else {
|
||||||
|
find();
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(Heap::Visitor* v) {
|
||||||
|
v->visit(&map);
|
||||||
|
v->visit(&node);
|
||||||
|
}
|
||||||
|
|
||||||
|
object map;
|
||||||
|
object node;
|
||||||
|
unsigned index;
|
||||||
|
};
|
||||||
|
|
||||||
} // vm
|
} // vm
|
||||||
|
|
||||||
#endif//UTIL_H
|
#endif//UTIL_H
|
||||||
|
Loading…
Reference in New Issue
Block a user