Skip to content

Commit af1dc9a

Browse files
committed
WebIDL: Implement Owner Extended Attribute, fix #77
Currently the ensureCache create a temporary pointer that will transfer the value to the WASM/C part and recycle it with to use in the next value, but since the libass struct pointers are owned by the library, the pointers can't be recycled or freed or can lead into an undefined behavior. This configure the binder to tranfer the pointer ownership instead of recycle it. To avoid creating complex code, I decided to fix it in the webidl binder.
1 parent d1072f3 commit af1dc9a

File tree

3 files changed

+64
-36
lines changed

3 files changed

+64
-36
lines changed

build/WebIDL.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
## JavascriptSubtitlesOctopus
22
## Patched to:
33
## - add integer pointers (IntPtr)
4+
## - add [Owner] Extended attribute
45
## From https://github.com/emscripten-core/emscripten/blob/f36f9fcaf83db93e6a6d0f0cdc47ab6379ade139/third_party/WebIDL.py
56

67
# from https://hg.mozilla.org/mozilla-central/file/tip/dom/bindings/parser/WebIDL.py
@@ -2863,6 +2864,7 @@ def handleExtendedAttribute(self, attr):
28632864
identifier == "AvailableIn" or
28642865
identifier == "Const" or
28652866
identifier == "Value" or
2867+
identifier == "Owner" or
28662868
identifier == "BoundsChecked" or
28672869
identifier == "NewObject"):
28682870
# Known attributes that we don't need to do anything with here
@@ -2938,7 +2940,7 @@ def addExtendedAttributes(self, attrs):
29382940
self.enforceRange = True
29392941
elif identifier == "TreatNonCallableAsNull":
29402942
self._allowTreatNonCallableAsNull = True
2941-
elif identifier in ['Ref', 'Const']:
2943+
elif identifier in ['Ref', 'Const', 'Owner']:
29422944
# ok in emscripten
29432945
self._extraAttributes[identifier] = True
29442946
else:

build/webidl_binder.py

Lines changed: 52 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
## Patched to:
33
## - add integer pointers (IntPtr)
44
## - implement ByteString type
5+
## - add [Owner] Extended attribute for Pointer Ownership transfer
56
## From https://github.com/emscripten-core/emscripten/blob/f36f9fcaf83db93e6a6d0f0cdc47ab6379ade139/tools/webidl_binder.py
67

78
# Copyright 2014 The Emscripten Authors. All rights reserved.
@@ -174,6 +175,7 @@ def build_constructor(name):
174175
size: 0, // the size of buffer
175176
pos: 0, // the next free offset in buffer
176177
temps: [], // extra allocations
178+
owned: [], // Owned allocations
177179
needed: 0, // the total size we need next time
178180
179181
prepare: function() {
@@ -197,22 +199,29 @@ def build_constructor(name):
197199
}
198200
ensureCache.pos = 0;
199201
},
200-
alloc: function(array, view) {
202+
alloc: function(array, view, owner) {
201203
assert(ensureCache.buffer);
202204
var bytes = view.BYTES_PER_ELEMENT;
203205
var len = array.length * bytes;
204206
len = (len + 7) & -8; // keep things aligned to 8 byte boundaries
205207
var ret;
206-
if (ensureCache.pos + len >= ensureCache.size) {
207-
// we failed to allocate in the buffer, ensureCache time around :(
208+
if (owner) {
208209
assert(len > 0); // null terminator, at least
209210
ensureCache.needed += len;
210211
ret = Module['_malloc'](len);
211-
ensureCache.temps.push(ret);
212+
ensureCache.owned.push(ret);
212213
} else {
213-
// we can allocate in the buffer
214-
ret = ensureCache.buffer + ensureCache.pos;
215-
ensureCache.pos += len;
214+
if (ensureCache.pos + len >= ensureCache.size) {
215+
// we failed to allocate in the buffer, ensureCache time around :(
216+
assert(len > 0); // null terminator, at least
217+
ensureCache.needed += len;
218+
ret = Module['_malloc'](len);
219+
ensureCache.temps.push(ret);
220+
} else {
221+
// we can allocate in the buffer
222+
ret = ensureCache.buffer + ensureCache.pos;
223+
ensureCache.pos += len;
224+
}
216225
}
217226
return ret;
218227
},
@@ -228,58 +237,73 @@ def build_constructor(name):
228237
view[offset + i] = array[i];
229238
}
230239
},
240+
clear: function(clearOwned) {
241+
for (var i = 0; i < ensureCache.temps.length; i++) {
242+
Module['_free'](ensureCache.temps[i]);
243+
}
244+
if (clearOwned) {
245+
for (var i = 0; i < ensureCache.owned.length; i++) {
246+
Module['_free'](ensureCache.owned[i]);
247+
}
248+
}
249+
ensureCache.temps.length = 0;
250+
Module['_free'](ensureCache.buffer);
251+
ensureCache.buffer = 0;
252+
ensureCache.size = 0;
253+
ensureCache.needed = 0;
254+
}
231255
};
232256
233257
/** @suppress {duplicate} (TODO: avoid emitting this multiple times, it is redundant) */
234-
function ensureString(value) {
258+
function ensureString(value, owner) {
235259
if (typeof value === 'string') {
236260
var intArray = intArrayFromString(value);
237-
var offset = ensureCache.alloc(intArray, HEAP8);
261+
var offset = ensureCache.alloc(intArray, HEAP8, owner);
238262
ensureCache.copy(intArray, HEAP8, offset);
239263
return offset;
240264
}
241265
return value;
242266
}
243267
/** @suppress {duplicate} (TODO: avoid emitting this multiple times, it is redundant) */
244-
function ensureInt8(value) {
268+
function ensureInt8(value, owner) {
245269
if (typeof value === 'object') {
246-
var offset = ensureCache.alloc(value, HEAP8);
270+
var offset = ensureCache.alloc(value, HEAP8, owner);
247271
ensureCache.copy(value, HEAP8, offset);
248272
return offset;
249273
}
250274
return value;
251275
}
252276
/** @suppress {duplicate} (TODO: avoid emitting this multiple times, it is redundant) */
253-
function ensureInt16(value) {
277+
function ensureInt16(value, owner) {
254278
if (typeof value === 'object') {
255-
var offset = ensureCache.alloc(value, HEAP16);
279+
var offset = ensureCache.alloc(value, HEAP16, owner);
256280
ensureCache.copy(value, HEAP16, offset);
257281
return offset;
258282
}
259283
return value;
260284
}
261285
/** @suppress {duplicate} (TODO: avoid emitting this multiple times, it is redundant) */
262-
function ensureInt32(value) {
286+
function ensureInt32(value, owner) {
263287
if (typeof value === 'object') {
264-
var offset = ensureCache.alloc(value, HEAP32);
288+
var offset = ensureCache.alloc(value, HEAP32, owner);
265289
ensureCache.copy(value, HEAP32, offset);
266290
return offset;
267291
}
268292
return value;
269293
}
270294
/** @suppress {duplicate} (TODO: avoid emitting this multiple times, it is redundant) */
271-
function ensureFloat32(value) {
295+
function ensureFloat32(value, owner) {
272296
if (typeof value === 'object') {
273-
var offset = ensureCache.alloc(value, HEAPF32);
297+
var offset = ensureCache.alloc(value, HEAPF32, owner);
274298
ensureCache.copy(value, HEAPF32, offset);
275299
return offset;
276300
}
277301
return value;
278302
}
279303
/** @suppress {duplicate} (TODO: avoid emitting this multiple times, it is redundant) */
280-
function ensureFloat64(value) {
304+
function ensureFloat64(value, owner) {
281305
if (typeof value === 'object') {
282-
var offset = ensureCache.alloc(value, HEAPF64);
306+
var offset = ensureCache.alloc(value, HEAPF64, owner);
283307
ensureCache.copy(value, HEAPF64, offset);
284308
return offset;
285309
}
@@ -390,7 +414,7 @@ def type_to_cdec(raw):
390414

391415
def render_function(class_name, func_name, sigs, return_type, non_pointer,
392416
copy, operator, constructor, func_scope,
393-
call_content=None, const=False, array_attribute=False):
417+
call_content=None, const=False, owned=False, array_attribute=False):
394418
legacy_mode = CHECKS not in ['ALL', 'FAST']
395419
all_checks = CHECKS == 'ALL'
396420

@@ -505,20 +529,20 @@ def render_function(class_name, func_name, sigs, return_type, non_pointer,
505529
if not (arg.type.isArray() and not array_attribute):
506530
body += " if ({0} && typeof {0} === 'object') {0} = {0}.ptr;\n".format(js_arg)
507531
if arg.type.isString():
508-
body += " else {0} = ensureString({0});\n".format(js_arg)
532+
body += " else {0} = ensureString({0}, {1});\n".format(js_arg, "true" if (owned) else "false")
509533
else:
510534
# an array can be received here
511535
arg_type = arg.type.name
512536
if arg_type in ['Byte', 'Octet']:
513-
body += " if (typeof {0} == 'object') {{ {0} = ensureInt8({0}); }}\n".format(js_arg)
537+
body += " if (typeof {0} == 'object') {{ {0} = ensureInt8({0}, {1}); }}\n".format(js_arg, "true" if (owned) else "false")
514538
elif arg_type in ['Short', 'UnsignedShort']:
515-
body += " if (typeof {0} == 'object') {{ {0} = ensureInt16({0}); }}\n".format(js_arg)
539+
body += " if (typeof {0} == 'object') {{ {0} = ensureInt16({0}, {1}); }}\n".format(js_arg, "true" if (owned) else "false")
516540
elif arg_type in ['Long', 'UnsignedLong']:
517-
body += " if (typeof {0} == 'object') {{ {0} = ensureInt32({0}); }}\n".format(js_arg)
541+
body += " if (typeof {0} == 'object') {{ {0} = ensureInt32({0}, {1}); }}\n".format(js_arg, "true" if (owned) else "false")
518542
elif arg_type == 'Float':
519-
body += " if (typeof {0} == 'object') {{ {0} = ensureFloat32({0}); }}\n".format(js_arg)
543+
body += " if (typeof {0} == 'object') {{ {0} = ensureFloat32({0}, {1}); }}\n".format(js_arg, "true" if (owned) else "false")
520544
elif arg_type == 'Double':
521-
body += " if (typeof {0} == 'object') {{ {0} = ensureFloat64({0}); }}\n".format(js_arg)
545+
body += " if (typeof {0} == 'object') {{ {0} = ensureFloat64({0}, {1}); }}\n".format(js_arg, "true" if (owned) else "false")
522546

523547
c_names = {}
524548
for i in range(min_args, max_args):
@@ -737,6 +761,7 @@ def render_function(class_name, func_name, sigs, return_type, non_pointer,
737761
func_scope=interface,
738762
call_content=get_call_content,
739763
const=m.getExtendedAttribute('Const'),
764+
owned=m.getExtendedAttribute('Owner'),
740765
array_attribute=m.type.isArray())
741766

742767
if m.readonly:
@@ -755,6 +780,7 @@ def render_function(class_name, func_name, sigs, return_type, non_pointer,
755780
func_scope=interface,
756781
call_content=set_call_content,
757782
const=m.getExtendedAttribute('Const'),
783+
owned=m.getExtendedAttribute('Owner'),
758784
array_attribute=m.type.isArray())
759785
mid_js += [r'''
760786
Object.defineProperty(%s.prototype, '%s', { get: %s.prototype.%s, set: %s.prototype.%s });''' % (name, attr, name, get_name, name, set_name)]

src/SubtitleOctopus.idl

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ interface ASS_Image {
1212

1313
[NoDelete]
1414
interface ASS_Style {
15-
attribute DOMString Name;
16-
attribute DOMString FontName;
15+
[Owner] attribute DOMString Name;
16+
[Owner] attribute DOMString FontName;
1717
attribute double FontSize;
1818
attribute unsigned long PrimaryColour;
1919
attribute unsigned long SecondaryColour;
@@ -47,12 +47,12 @@ interface ASS_Event {
4747
attribute long ReadOrder;
4848
attribute long Layer;
4949
attribute long Style;
50-
attribute DOMString Name;
50+
[Owner] attribute DOMString Name;
5151
attribute long MarginL;
5252
attribute long MarginR;
5353
attribute long MarginV;
54-
attribute DOMString Effect;
55-
attribute DOMString Text;
54+
[Owner] attribute DOMString Effect;
55+
[Owner] attribute DOMString Text;
5656
};
5757

5858
[NoDelete]
@@ -63,17 +63,17 @@ interface ASS_Track {
6363
attribute long max_events;
6464
[Value] attribute ASS_Style[] styles;
6565
[Value] attribute ASS_Event[] events;
66-
attribute DOMString style_format;
67-
attribute DOMString event_format;
66+
[Owner] attribute DOMString style_format;
67+
[Owner] attribute DOMString event_format;
6868
attribute long PlayResX;
6969
attribute long PlayResY;
7070
attribute double Timer;
7171
attribute long WrapStyle;
7272
attribute long ScaledBorderAndShadow;
7373
attribute long Kerning;
74-
attribute DOMString Language;
74+
[Owner] attribute DOMString Language;
7575
attribute long default_style;
76-
attribute DOMString name;
76+
[Owner] attribute DOMString name;
7777
};
7878

7979
enum ASS_Hinting {

0 commit comments

Comments
 (0)