store webidl temporary strings in an optimized memory structure, avoiding stack overflows
This commit is contained in:
Родитель
56a9132753
Коммит
4d95be2ae7
|
@ -218,6 +218,13 @@ try {
|
|||
s.Print(123, null); // Expects a string or a wrapped pointer
|
||||
} catch (e) {}
|
||||
|
||||
// Check for overflowing the stack
|
||||
|
||||
for (var i = 0; i < 1000000; i++) {
|
||||
var temp = new TheModule.StringUser('abc', 1);
|
||||
TheModule.destroy(temp);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
TheModule.print('\ndone.')
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Part 1
|
||||
|
||||
|
@ -54,6 +55,7 @@ class StringUser {
|
|||
int i;
|
||||
public:
|
||||
StringUser(char *string="NO", int integer=99) : s(strdup(string)), i(integer) {}
|
||||
~StringUser() { free(s); }
|
||||
void Print(int anotherInteger, char *anotherString) {
|
||||
printf("|%s|%d|%s|%d|\n", s, i, anotherString, anotherInteger);
|
||||
}
|
||||
|
|
|
@ -138,9 +138,59 @@ function getClass(obj) {
|
|||
}
|
||||
Module['getClass'] = getClass;
|
||||
|
||||
// Converts a value into a C-style string.
|
||||
// Converts a value into a C-style string, storing it in temporary space
|
||||
|
||||
var ensureStringCache = {
|
||||
buffer: 0, // the main buffer of temporary storage
|
||||
size: 0, // the size of buffer
|
||||
pos: 0, // the next free offset in buffer
|
||||
temps: [], // extra allocations
|
||||
needed: 0, // the total size we need next time
|
||||
|
||||
prepare: function() {
|
||||
if (this.needed) {
|
||||
// clear the temps
|
||||
for (var i = 0; i < this.temps.length; i++) {
|
||||
Module['_free'](this.temps[i]);
|
||||
}
|
||||
this.temps.length = 0;
|
||||
// prepare to allocate a bigger buffer
|
||||
Module['_free'](this.buffer);
|
||||
this.buffer = 0;
|
||||
this.size += this.needed;
|
||||
// clean up
|
||||
this.needed = 0;
|
||||
}
|
||||
if (!this.buffer) { // happens first time, or when we need to grow
|
||||
this.size += 100; // heuristic, avoid many small grow events
|
||||
this.buffer = Module['_malloc'](this.size);
|
||||
assert(this.buffer);
|
||||
}
|
||||
this.pos = 0;
|
||||
},
|
||||
alloc: function(value) {
|
||||
assert(this.buffer);
|
||||
var array = intArrayFromString(value);
|
||||
var len = array.length;
|
||||
var ret;
|
||||
if (this.pos + len >= this.size) {
|
||||
// we failed to allocate in the buffer, this time around :(
|
||||
assert(len > 0); // null terminator, at least
|
||||
this.needed += len;
|
||||
ret = Module['_malloc'](len);
|
||||
this.temps.push(ret);
|
||||
} else {
|
||||
// we can allocate in the buffer
|
||||
ret = this.buffer + this.pos;
|
||||
this.pos += len;
|
||||
}
|
||||
writeArrayToMemory(array, ret);
|
||||
return ret;
|
||||
},
|
||||
};
|
||||
|
||||
function ensureString(value) {
|
||||
if (typeof value == 'string') return allocate(intArrayFromString(value), 'i8', ALLOC_STACK);
|
||||
if (typeof value === 'string') return ensureStringCache.alloc(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -255,6 +305,12 @@ def render_function(class_name, func_name, sigs, return_type, non_pointer, copy,
|
|||
body = ''
|
||||
pre_arg = []
|
||||
|
||||
for i in range(max_args):
|
||||
arg = all_args[i]
|
||||
if arg.type.isString():
|
||||
body += ' ensureStringCache.prepare();\n'
|
||||
break
|
||||
|
||||
full_name = "%s::%s" % (class_name, func_name)
|
||||
|
||||
for i in range(max_args):
|
||||
|
@ -314,7 +370,8 @@ def render_function(class_name, func_name, sigs, return_type, non_pointer, copy,
|
|||
|
||||
if do_default:
|
||||
body += " if (arg%d && typeof arg%d === 'object') arg%d = arg%d.ptr;\n" % (i, i, i, i)
|
||||
body += " else arg%d = ensureString(arg%d);\n" % (i, i)
|
||||
if arg.type.isString():
|
||||
body += " else arg%d = ensureString(arg%d);\n" % (i, i)
|
||||
|
||||
|
||||
for i in range(min_args, max_args):
|
||||
|
|
Загрузка…
Ссылка в новой задаче