Re: libseed-list importer GC bug (was Re: js extensions for native modules)
- From: "Alan Knowles" <alan akbkhome com>
- To: "Jonatan Liljedahl" <j r liljedahl gmail com>
- Cc: libseed-list gnome org
- Subject: Re: libseed-list importer GC bug (was Re: js extensions for native modules)
- Date: Tue, 29 Jun 2010 23:07:48 +0800
Commited in, I changed it to JSValueProtect, to get rid of the compiler warnings.
Regards
Alan
--- On 29/Jun/2010, Jonatan Liljedahl wrote:
> This change exposed another bug: sometimes the object returned from
> imports.sandbox was screwed up.
>
> The reason this happens is that the GC won't find the module in our
> cached file_imports hash table, thus allowing the GC to collect it and
> we'll get a wild pointer in the file_imports cache.
>
> And the reason this never happened before is that it didn't reuse the
> cached module object but always made a new one for each reference of
> imports.sandbox.
>
> Solution: protect the module object after adding it to the file_imports
> cache. Updated patch attached.
>
> I don't know if this should be done for js-modules or gir-modules too?
>
> PS. With this patch the "workaround WebKit GC bug" (which actually was a
> seed bug) in seed-cairo.c shouldn't be needed anymore.
>
> /Jonatan
>
> Jonatan Liljedahl wrote:
> > I did a fresh clone from git.gnome.org/seed and now it all seems up to
> > date again..
> >
> > I think I found the problem: in handle_native_module(), file_path is
> > used as a key to the file_imports hash table, but the key is free'd
> > after insertion. So each time a native module is requested, it's a new
> > copy, which means that any additions by the extension-file wouldn't stick.
> >
> > Attached patch fixes that and implements the following behaviour: When
> > loading a native module, also try running libseed_NAME.js in the same
> > dir as the module. This allows the script to extend the module.
> >
> > Here's the libseed_sandbox.js that I find useful:
> >
> > imports.sandbox.Context.prototype.eval_file = function(fn) {
> > var script = {};
> > GLib.file_get_contents(fn,script);
> > return this.eval(script.contents);
> > };
> >
> > /Jonatan
> >
> > Jonatan Liljedahl wrote:
> >> Alan Knowles wrote:
> >>> Ok - rebuilt from head:
> >>>
> >>> If you run it on the seed interpreter - it will not work.
> >>>
> >>> If you make a file of it, and run that, it works perfectly..
> >>
> >> What's the reason for this?
> >>
> >> I did a change in seed-importer that runs seed_importer_handle_file()
> >> on libseed_NAME.js in the same dir as libseed_NAME.so, and tried
> >> adding the imports.sandbox.Context.prototype.eval_file = ... in
> >> libseed_sandbox.js.
> >>
> >> A print() in libseed_sandbox.js tells me that it's running this file,
> >> but 'c.eval_file()' still gives me "TypeError Result of expression
> >> 'c.eval_file' [undefined] is not a function." even though it's a file
> >> in this case.
> >>
> >> Could this be for the same reason that an imported js file can't
> >> extend the built-in prototypes (Array, String, etc..)? Perhaps the
> >> extension-file must not be evaluated in a new context?
> >>
> >> Also I have a GIT question, I tried to get a diff with my recent
> >> changes with 'git diff seed-importer.c' but then the diff also
> >> includes my old changes which you already commited. Do I have the
> >> wrong git branch or how does it work?
> >>
> >> /Jonatan
> >>
> >>> Regards
> >>> Alan
> >>>
> >>> --- On 29/Jun/2010, Alan Knowles wrote:
> >>>> This is a bit strange, My portable (Ubuntu 10.4) managed to do this
> >>>> fine this morning, however, pretty much every other box I've got
> >>>> shows the same errors that you get..
> >>>>
> >>>> I've just reverted the get_global_object stuff, as it's not needed
> >>>> (.global was already there)
> >>>>
> >>>> Testing on a fresh build to see if I can get it to work.
> >>>>
> >>>> Regards
> >>>> Alan
> >>>>
> >>>> --- On 29/Jun/2010, Jonatan Liljedahl wrote:
> >>>>> I reverted my seed-sandbox.c to current git, but I had only this
> >>>>> small change which I thought was a typo fix:
> >>>>>
> >>>>> --- a/modules/sandbox/seed-sandbox.c
> >>>>> +++ b/modules/sandbox/seed-sandbox.c
> >>>>> @@ -126,7 +126,7 @@ seed_static_function context_funcs[] = {
> >>>>> {"eval", seed_context_eval, 0},
> >>>>> {"add_globals", seed_sandbox_context_add_globals, 0},
> >>>>> {"destroy", seed_sandbox_context_destroy, 0},
> >>>>> - {"get_global_object", seed_sandbox_context_get_global_object },
> >>>>> + {"get_global_object", seed_sandbox_context_get_global_object, 0},
> >>>>> {NULL, NULL, 0}
> >>>>> };
> >>>>>
> >>>>> Anyhow, now it loads the sandbox module...
> >>>>>
> >>>>> But I still can't add to the prototype:
> >>>>>
> >>>>> > imports.sandbox.Context.prototype.foo = function() {
> >>>>> print("test") };
> >>>>> function () { print("test"); }
> >>>>> > c = new imports.sandbox.Context
> >>>>> [object Context]
> >>>>> > c.foo()
> >>>>> TypeError Result of expression 'c.foo' [undefined] is not a function.
> >>>>> > c.eval("1+2")
> >>>>> 3
> >>>>>
> >>>>> Could this be a difference in JSC version? I'm with webkit
> >>>>> 1.1.15.2-1 in ubuntu.
> >>>>>
> >>>>> /Jonatan
> >>>>>
> >>>>> Alan Knowles wrote:
> >>>>>> It failed to load the sandbox module by the looks of things.
> >>>>>>
> >>>>>> It's probably worth running with --seed-debug=all to find out
> >>>>>> what's going on. - if you built seed with debug on.
> >>>>>>
> >>>>>> Regards
> >>>>>> Alan
> >>>>>>
> >>>>>>
> >>>>>> --- On 29/Jun/2010, Jonatan Liljedahl wrote:
> >>>>>>> Doesn't work here, but now something else is strange (first try
> >>>>>>> to get sandbox failed):
> >>>>>>>
> >>>>>>> > imports.sandbox.Context.prototype.foo = function() {
> >>>>>>> print("test") };
> >>>>>>> function () { print("test"); }
> >>>>>>> > c = new imports.sandbox.Context
> >>>>>>> TypeError Result of expression 'imports.sandbox' [undefined] is
> >>>>>>> not an object.
> >>>>>>> > c = new imports.sandbox.Context
> >>>>>>> [object Context]
> >>>>>>> > c.foo()
> >>>>>>> TypeError Result of expression 'c.foo' [undefined] is not a
> >>>>>>> function.
> >>>>>>> >
> >>>>>>>
> >>>>>>>
> >>>>>>> Alan Knowles wrote:
> >>>>>>>> Did I miss something - this works perfectly..
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> GLib = imports.gi.GLib;
> >>>>>>>>
> >>>>>>>> imports.sandbox.Context.prototype.eval_file = function(fn) {
> >>>>>>>> var script = {}; print("load " + fn);
> >>>>>>>> GLib.file_get_contents(fn,script); return
> >>>>>>>> this.eval(script.contents); };
> >>>>>>>>
> >>>>>>>> c = new imports.sandbox.Context;
> >>>>>>>> c.eval_file("test.js");
> >>>>>>>>
> >>>>>>>> #output>>>
> >>>>>>>> load test.js
> >>>>>>>>
> >>>>>>>> ** (seed:3644): CRITICAL **: Line 10 in /tmp/seedtest.js:
> >>>>>>>> GFileError Failed to open file 'test.js': No such file or directory
> >>>>>>>>
> >>>>>>>> Regards
> >>>>>>>> Alan
> >>>>>>>>
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> --- On 29/Jun/2010, Jonatan Liljedahl wrote:
> >>>>>>>>>> This should be made to work - It's probably going to take a
> >>>>>>>>>> bit of
> >>>>>>>>> > working out how to support it...
> >>>>>>>>>
> >>>>>>>>> I'm trying to understand how this works, am I right that native
> >>>>>>>>> modules create their classes with seed_create_class()
> >>>>>>>>> (JSClassCreate()), while the Gir importer sets up an object
> >>>>>>>>> with a 'prototype' property "by hand"?
> >>>>>>>>>
> >>>>>>>>> From the JSC API docs:
> >>>>>>>>>
> >>>>>>>>> "Standard JavaScript practice calls for storing function
> >>>>>>>>> objects in prototypes, so they can be shared. The default
> >>>>>>>>> JSClass created by JSClassCreate follows this idiom,
> >>>>>>>>> instantiating objects with a shared, automatically generating
> >>>>>>>>> prototype containing the class's function objects. The
> >>>>>>>>> kJSClassAttributeNoAutomaticPrototype attribute specifies that
> >>>>>>>>> a JSClass should not automatically generate such a prototype."
> >>>>>>>>>
> >>>>>>>>> So, the question is why the prototype is not writable and if it
> >>>>>>>>> can be made to be that. I tried this hackish function on the
> >>>>>>>>> constructor but it didn't work:
> >>>>>>>>>
> >>>>>>>>> gboolean
> >>>>>>>>> seed_make_extendable (JSContextRef ctx, JSObjectRef object)
> >>>>>>>>> {
> >>>>>>>>> JSStringRef jname = JSStringCreateWithUTF8CString
> >>>>>>>>> ("prototype");
> >>>>>>>>> JSValueRef exception = NULL;
> >>>>>>>>> JSValueRef proto = JSObjectGetPrototype(ctx, object);
> >>>>>>>>> if (proto)
> >>>>>>>>> {
> >>>>>>>>> JSObjectSetProperty (ctx, (JSObjectRef) object, jname,
> >>>>>>>>> proto,
> >>>>>>>>>
> >>>>>>>>> kJSPropertyAttributeDontEnum|kJSPropertyAttributeDontDelete,
> >>>>>>>>> &exception);
> >>>>>>>>> }
> >>>>>>>>>
> >>>>>>>>> JSStringRelease (jname);
> >>>>>>>>> return TRUE;
> >>>>>>>>> }
> >>>>>>>>>
> >>>>>>>>> Once JSClassCreate has made the prototype, it seems to be fixed
> >>>>>>>>> and read-only.
> >>>>>>>>>
> >>>>>>>>> Perhaps one should create classes more "manually" like the Gir
> >>>>>>>>> importer does instead of using JSClassCreate()?
> >>>>>>>>>
> >>>>>>>>>> Looking through the code, it's either we have to explicitly
> >>>>>>>>>> overlay
> >>>>>>>>>> the prototype properties in the constructor, or we set the
> >>>>>>>>>> parent_class of Context to a standard object..
> >>>>>>>>> parent_class can only be a JSClassRef, and it says it should be
> >>>>>>>>> NULL for the normal Object class, which I guess it should be.
> >>>>>>>>> Seems like JavaScriptCore has classic inherited OOP internally,
> >>>>>>>>> and that parent_class has nothing to do with prototype. (but
> >>>>>>>>> that all objects has Object as parent_class)
> >>>>>>>>>
> >>>>>>>>> I'm not sure I understand what you mean by overlay the
> >>>>>>>>> prototype properties..
> >>>>>>>>>
> >>>>>>>>> /Jonatan
> >>>>>>>>>
> >>>>>>>>>> Regarsd Alan
> >>>>>>>>>>
> >>>>>>>>>> --- On 21/Jun/2010, Jonatan Liljedahl wrote:
> >>>>>>>>>>> Also, it should work to add methods to SomeClass.prototype in
> >>>>>>>>>>> native modules. Currently it does not:
> >>>>>>>>>>>
> >>>>>>>>>>> imports.sandbox.Context.prototype.eval_file = function(fn) { var
> >>>>>>>>>>> script = {}; GLib.file_get_contents(fn,script); return
> >>>>>>>>>>> this.eval(script.contents); };
> >>>>>>>>>>>
> >>>>>>>>>>> c = new imports.sandbox.Context; c.eval_file(foobar);
> >>>>>>>>>>>
> >>>>>>>>>>> TypeError Result of expression 'ctx.eval_file' [undefined] is
> >>>>>>>>>>> not a
> >>>>>>>>>>> function.
> >>>>>>>>>>>
> >>>>>>>>>>> It does work for GI modules, as seen in extensions/Gtk.js
> >>>>>>>>>>>
> >>>>>>>>>>> /Jonatan
> >>>>>>>>>>>
> >>>>>>>>>>> Jonatan Liljedahl wrote:
> >>>>>>>>>>>> The gi_importer tries to import extensions/name.js by
> >>>>>>>>>>>> evaluating
> >>>>>>>>>>>> "imports.extensions.name". It would be nice if this also
> >>>>>>>>>>>> worked
> >>>>>>>>>>>> for native modules, I imagine it to be quite common that you
> >>>>>>>>>>>> write a module with core parts in C and some high-level
> >>>>>>>>>>>> stuff in
> >>>>>>>>>>>> js.
> >>>>>>>>>>>>
> >>>>>>>>>>>> The question is, how should this be handled regarding
> >>>>>>>>>>>> searchpaths
> >>>>>>>>>>>> etc?
> >>>>>>>>>>>>
> >>>>>>>>>>>> If your module is installed in /usr/local/lib/seed, then you
> >>>>>>>>>>>> probably installed the extension js in
> >>>>>>>>>>>> /usr/local/share/seed/extensions, and imports.extensions
> >>>>>>>>>>>> would be
> >>>>>>>>>>>> the right thing.
> >>>>>>>>>>>>
> >>>>>>>>>>>> But what happens if your module is installed somewhere else? It
> >>>>>>>>>>>> should probably start with the same dir as the native module,
> >>>>>>>>>>>> then go on with imports.searchPath, and if the file is found
> >>>>>>>>>>>> call
> >>>>>>>>>>>> seed_importer_handle_file() on it..
> >>>>>>>>>>>>
> >>>>>>>>>>>> BTW, what happens if you have 'extensions' folder in more than
> >>>>>>>>>>>> one search path? will extensions.foo search for 'foo' in all of
> >>>>>>>>>>>> those or only the first match for 'extensions'? Just doing a
> >>>>>>>>>>>> 'imports.extensions' will of course create only one
> >>>>>>>>>>>> dir_importer
> >>>>>>>>>>>> for that folder, hiding possible 'extensions' folders later in
> >>>>>>>>>>>> the searchpath. I don't know if this is a good thing...
> >>>>>>>>>>>>
> >>>>>>>>>>>> /Jonatan _______________________________________________
> >>>>>>>>>>>> libseed-list mailing list libseed-list gnome org
> >>>>>>>>>>>> http://mail.gnome.org/mailman/listinfo/libseed-list
> >>>>>>>>>>> _______________________________________________ libseed-list
> >>>>>>>>>>> mailing list libseed-list gnome org
> >>>>>>>>>>> http://mail.gnome.org/mailman/listinfo/libseed-list
> >>>>>>>>>> _______________________________________________ libseed-list
> >>>>>>>>>> mailing
> >>>>>>>>>> list libseed-list gnome org
> >>>>>>>>>> http://mail.gnome.org/mailman/listinfo/libseed-list
> >>>> _______________________________________________
> >>>> libseed-list mailing list
> >>>> libseed-list gnome org
> >>>> http://mail.gnome.org/mailman/listinfo/libseed-list
> >>>
> >>
> >
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]