зеркало из https://github.com/mozilla/pluotsorbet.git
Merge pull request #1828 from brendandahl/intex-gc
Force collection at every unwind.
This commit is contained in:
Коммит
819eb8b7b0
|
@ -25,7 +25,6 @@ img/icon-512.png
|
|||
index.html
|
||||
index.js
|
||||
style/main.css
|
||||
native.js
|
||||
|
||||
# These are generated by the Java pre-processor. They're generated from
|
||||
# their *.jpp equivalents. Keep them up-to-date when you add *.jpp files!
|
||||
|
|
1
Makefile
1
Makefile
|
@ -189,7 +189,6 @@ PREPROCESS_SRCS = \
|
|||
./index.js.in \
|
||||
./main.html.in \
|
||||
./manifest.webapp.in \
|
||||
./native.js.in \
|
||||
./style/main.css.in \
|
||||
./tests/index.js.in \
|
||||
$(NULL)
|
||||
|
|
|
@ -17,3 +17,4 @@
|
|||
/** @const */ var release: boolean = @RELEASE@;
|
||||
/** @const */ var profile: number = @PROFILE@;
|
||||
/** @const */ var profileFormat: string = "@PROFILE_FORMAT@";
|
||||
/** @const */ var asmJsTotalMemory: number = @ASMJS_TOTAL_MEMORY@;
|
||||
|
|
7
int.ts
7
int.ts
|
@ -619,6 +619,13 @@ module J2ME {
|
|||
while (unwound.length) {
|
||||
pending.push(unwound.pop());
|
||||
}
|
||||
// Garbage collection is disabled during compiled code which can lead to OOM's if
|
||||
// we consistently stay in compiled code. Most code unwinds often enough that we can
|
||||
// force collection here since at the end of an unwind all frames are
|
||||
// stored back on the heap.
|
||||
if (getFreeMemory() < Constants.FREE_MEMORY_TARGET) {
|
||||
ASM._forceCollection();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -49,56 +49,57 @@ LocalMsgConnection.prototype.waitConnection = function() {
|
|||
}).bind(this));
|
||||
}
|
||||
|
||||
LocalMsgConnection.prototype.copyMessage = function(messageQueue, data) {
|
||||
LocalMsgConnection.prototype.copyMessage = function(messageQueue, dataAddr) {
|
||||
var msg = messageQueue.shift();
|
||||
|
||||
var data = J2ME.getArrayFromAddr(dataAddr);
|
||||
for (var i = 0; i < msg.length; i++) {
|
||||
data[i] = msg.data[i + msg.offset];
|
||||
}
|
||||
|
||||
J2ME.unsetUncollectable(dataAddr);
|
||||
return msg.length;
|
||||
}
|
||||
|
||||
LocalMsgConnection.prototype.sendMessageToClient = function(data, offset, length) {
|
||||
this.clientMessages.push(new LocalMsgConnectionMessage(data, offset, length));
|
||||
LocalMsgConnection.prototype.sendMessageToClient = function(dataAddr, offset, length) {
|
||||
this.clientMessages.push(new LocalMsgConnectionMessage(dataAddr, offset, length));
|
||||
|
||||
if (this.clientWaiting.length > 0) {
|
||||
this.clientWaiting.shift()();
|
||||
}
|
||||
}
|
||||
|
||||
LocalMsgConnection.prototype.getClientMessage = function(data) {
|
||||
return this.copyMessage(this.clientMessages, data);
|
||||
LocalMsgConnection.prototype.getClientMessage = function(dataAddr) {
|
||||
return this.copyMessage(this.clientMessages, dataAddr);
|
||||
}
|
||||
|
||||
LocalMsgConnection.prototype.waitClientMessage = function(data) {
|
||||
LocalMsgConnection.prototype.waitClientMessage = function(dataAddr) {
|
||||
asyncImpl("I", new Promise((function(resolve, reject) {
|
||||
this.clientWaiting.push(function() {
|
||||
resolve(this.getClientMessage(data));
|
||||
resolve(this.getClientMessage(dataAddr));
|
||||
}.bind(this));
|
||||
}).bind(this)));
|
||||
}
|
||||
|
||||
LocalMsgConnection.prototype.sendMessageToServer = function(data, offset, length) {
|
||||
this.serverMessages.push(new LocalMsgConnectionMessage(data, offset, length));
|
||||
LocalMsgConnection.prototype.sendMessageToServer = function(dataAddr, offset, length) {
|
||||
this.serverMessages.push(new LocalMsgConnectionMessage(dataAddr, offset, length));
|
||||
|
||||
if (this.serverWaiting.length > 0) {
|
||||
this.serverWaiting.shift()(true);
|
||||
}
|
||||
}
|
||||
|
||||
LocalMsgConnection.prototype.getServerMessage = function(data) {
|
||||
return this.copyMessage(this.serverMessages, data);
|
||||
LocalMsgConnection.prototype.getServerMessage = function(dataAddr) {
|
||||
return this.copyMessage(this.serverMessages, dataAddr);
|
||||
}
|
||||
|
||||
LocalMsgConnection.prototype.waitServerMessage = function(data) {
|
||||
LocalMsgConnection.prototype.waitServerMessage = function(dataAddr) {
|
||||
var ctx = $.ctx;
|
||||
|
||||
asyncImpl("I", new Promise((function(resolve, reject) {
|
||||
this.serverWaiting.push(function(successful) {
|
||||
if (successful) {
|
||||
resolve(this.getServerMessage(data));
|
||||
resolve(this.getServerMessage(dataAddr));
|
||||
} else {
|
||||
J2ME.unsetUncollectable(dataAddr);
|
||||
ctx.setAsCurrentContext();
|
||||
reject($.newIOException("Client disconnected"));
|
||||
}
|
||||
|
@ -1101,33 +1102,40 @@ Native["org/mozilla/io/LocalMsgConnection.waitConnection.()V"] = function(addr)
|
|||
};
|
||||
|
||||
Native["org/mozilla/io/LocalMsgConnection.sendData.([BII)V"] = function(addr, dataAddr, offset, length) {
|
||||
// Clone the data since it may be GC'ed.
|
||||
var dataClone = new Int8Array(length);
|
||||
var data = J2ME.getArrayFromAddr(dataAddr);
|
||||
for (var i = 0; i < length; i++) {
|
||||
dataClone[i] = data[offset + i];
|
||||
}
|
||||
|
||||
var connection = NativeConnectionMap[addr];
|
||||
var info = NativeMap.get(addr);
|
||||
|
||||
if (info.server) {
|
||||
connection.sendMessageToClient(data, offset, length);
|
||||
connection.sendMessageToClient(dataClone, 0, dataClone.length);
|
||||
} else {
|
||||
if (MIDP.FakeLocalMsgServers.indexOf(info.protocolName) != -1) {
|
||||
console.warn("sendData (" + util.decodeUtf8(data.subarray(offset, offset + length)) +
|
||||
console.warn("sendData (" + util.decodeUtf8(dataClone) +
|
||||
") to an unimplemented localmsg server (" + info.protocolName + ")");
|
||||
}
|
||||
|
||||
connection.sendMessageToServer(data, offset, length);
|
||||
connection.sendMessageToServer(dataClone, 0, dataClone.length);
|
||||
}
|
||||
};
|
||||
|
||||
Native["org/mozilla/io/LocalMsgConnection.receiveData.([B)I"] = function(addr, dataAddr) {
|
||||
var data = J2ME.getArrayFromAddr(dataAddr);
|
||||
J2ME.setUncollectable(dataAddr);
|
||||
|
||||
var connection = NativeConnectionMap[addr];
|
||||
var info = NativeMap.get(addr);
|
||||
|
||||
if (info.server) {
|
||||
if (connection.serverMessages.length > 0) {
|
||||
return connection.getServerMessage(data);
|
||||
return connection.getServerMessage(dataAddr);
|
||||
}
|
||||
|
||||
connection.waitServerMessage(data);
|
||||
connection.waitServerMessage(dataAddr);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1136,8 +1144,8 @@ Native["org/mozilla/io/LocalMsgConnection.receiveData.([B)I"] = function(addr, d
|
|||
}
|
||||
|
||||
if (connection.clientMessages.length > 0) {
|
||||
return connection.getClientMessage(data);
|
||||
return connection.getClientMessage(dataAddr);
|
||||
}
|
||||
|
||||
connection.waitClientMessage(data);
|
||||
connection.waitClientMessage(dataAddr);
|
||||
};
|
||||
|
|
|
@ -489,11 +489,11 @@ Native["java/lang/Double.longBitsToDouble.(J)D"] = function(addr, l, h) {
|
|||
}
|
||||
|
||||
Native["java/lang/Runtime.freeMemory.()J"] = function(addr) {
|
||||
return J2ME.returnLongValue(@ASMJS_TOTAL_MEMORY@ - ASM._getUsedHeapSize());
|
||||
return J2ME.returnLongValue(J2ME.getFreeMemory());
|
||||
};
|
||||
|
||||
Native["java/lang/Runtime.totalMemory.()J"] = function(addr) {
|
||||
return J2ME.returnLongValue(@ASMJS_TOTAL_MEMORY@);
|
||||
return J2ME.returnLongValue(asmJsTotalMemory);
|
||||
};
|
||||
|
||||
Native["java/lang/Runtime.gc.()V"] = function(addr) {
|
|
@ -402,8 +402,8 @@ module J2ME {
|
|||
this.CO = this.classObjectAddresses = Object.create(null);
|
||||
this.ctx = null;
|
||||
this.allCtxs = new Set();
|
||||
this._runtimeId = RuntimeTemplate._nextRuntimeId ++;
|
||||
this._nextHashCode = this._runtimeId << 24;
|
||||
this._runtimeId = RuntimeTemplate._nextRuntimeId++;
|
||||
this._nextHashCode = (this._runtimeId << 24) | 1; // Increase by one so the first hashcode isn't zero.
|
||||
}
|
||||
|
||||
preInitializeClasses(ctx: Context) {
|
||||
|
@ -666,6 +666,11 @@ module J2ME {
|
|||
TWO_PWR_32_DBL = 4294967296,
|
||||
TWO_PWR_63_DBL = 9223372036854776000,
|
||||
|
||||
// The target amount of free memory(in bytes) before garbage collection is forced on unwind.
|
||||
// Note: This number was chosen somewhat randomly to allow some space for allocation
|
||||
// during forceCollection, though it has not been verified it needs any space.
|
||||
FREE_MEMORY_TARGET = 4086,
|
||||
|
||||
// The size in bytes of the header in the memory allocated to the object.
|
||||
OBJ_HDR_SIZE = 8,
|
||||
|
||||
|
@ -773,7 +778,12 @@ module J2ME {
|
|||
export function getMonitor(ref: number): any {
|
||||
release || assert(typeof ref === "number", "monitor reference is a number");
|
||||
|
||||
return monitorMap[ref] || (monitorMap[ref] = Object.create(null));
|
||||
var hash = i32[ref + Constants.HASH_CODE_OFFSET >> 2];
|
||||
if (hash === Constants.NULL) {
|
||||
hash = i32[ref + Constants.HASH_CODE_OFFSET >> 2] = $.nextHashCode()
|
||||
}
|
||||
|
||||
return monitorMap[hash] || (monitorMap[hash] = Object.create(null));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1271,6 +1281,10 @@ module J2ME {
|
|||
return address;
|
||||
}
|
||||
|
||||
export function getFreeMemory(): number {
|
||||
return asmJsTotalMemory - ASM._getUsedHeapSize();
|
||||
}
|
||||
|
||||
export function onFinalize(addr: number): void {
|
||||
NativeMap.delete(addr);
|
||||
}
|
||||
|
@ -1412,17 +1426,27 @@ module J2ME {
|
|||
return arrayObject;
|
||||
}
|
||||
|
||||
var uncollectableAddress = gcMallocUncollectable(16);
|
||||
var uncollectableMaxNumber = 4;
|
||||
var uncollectableNumber = -1;
|
||||
var uncollectableMaxNumber = 16;
|
||||
var uncollectableAddress = gcMallocUncollectable(uncollectableMaxNumber << 2);
|
||||
export function setUncollectable(addr: number) {
|
||||
uncollectableNumber++;
|
||||
release || assert(uncollectableNumber < uncollectableMaxNumber, "Max " + uncollectableMaxNumber + " calls to setUncollectable at a time");
|
||||
i32[(uncollectableAddress >> 2) + uncollectableNumber] = addr;
|
||||
for (var i = 0; i < uncollectableMaxNumber; i++) {
|
||||
var address = (uncollectableAddress >> 2) + i;
|
||||
if (i32[address] === Constants.NULL) {
|
||||
i32[address] = addr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
release || Debug.assertUnreachable("There must be a free slot.");
|
||||
}
|
||||
export function unsetUncollectable(addr: number) {
|
||||
i32[(uncollectableAddress >> 2) + uncollectableNumber] = 0;
|
||||
uncollectableNumber--;
|
||||
for (var i = 0; i < uncollectableMaxNumber; i++) {
|
||||
var address = (uncollectableAddress >> 2) + i;
|
||||
if (i32[address] === addr) {
|
||||
i32[address] = Constants.NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
release || Debug.assertUnreachable("The adddress was not found in the uncollectables.");
|
||||
}
|
||||
|
||||
export function newArray(elementClassInfo: ClassInfo, size: number): number {
|
||||
|
|
Загрузка…
Ссылка в новой задаче