store webidl temporary strings in an optimized memory structure, avoiding stack overflows

This commit is contained in:
Alon Zakai 2015-07-14 14:44:43 -07:00
Родитель 56a9132753
Коммит 4d95be2ae7
3 изменённых файлов: 69 добавлений и 3 удалений

Просмотреть файл

@ -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):