Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix EXPORT_ES6 + USE_PTHREADS #8306

Merged
merged 187 commits into from
May 24, 2019
Merged

Conversation

VirtualTim
Copy link
Collaborator

I haven't managed to get this working, and I think I'm stuck, but I figured I'd create this PR so people can pick up where I left off. Or point out if I'm doing something wrong.

Import returns a promise, so things had to be rearranged. I think I could have used promise.resolve() instead, but that's something to revisit if I can actually get this working.
@VirtualTim
Copy link
Collaborator Author

VirtualTim commented Mar 20, 2019

Currently "_emscripten_futex_wake" is being optimised away, so I need to compile with -s EXPORTED_FUNCTIONS='["_emscripten_futex_wake"]'. I'm sure there is a way to force-preserve this, but I don't know where to add that. Anyone want to point me to the right file to add this to?

Edit: Seems to be fixed now. Not sure how that happened.

emcc.py Outdated Show resolved Hide resolved
@VirtualTim
Copy link
Collaborator Author

VirtualTim commented Mar 25, 2019

Things seem to be mostly working now. I don't know why the test are failing, those webgl tests seem kind of flaky on firefox, so maybe it's unrelated.
It doesn't yet work with WASM=1, it throws with TypeError: Cannot assign to read only property trying to reassign functions. Should be fixed.

Edit: I'll probably also need to update shell_minimal.js at some point.

@VirtualTim
Copy link
Collaborator Author

@kripken or @sbc100, since you both commented on the original issue, could one of you take a look at this PR? I think I've got it working, I'm pretty sure the test failures are unrelated.

I also want to add a test case for this, but I'm not really sure how to test something like this. I think I need some JS which loads the compiled ES6 module, but I don't rally know how to integrate this with the existing test framework.

Copy link
Collaborator

@sbc100 sbc100 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@juj probably has more insight into all things pthreads.

emcc.py Outdated
if shared.Settings.EXPORT_ES6:
GETSCRIPT = "import.meta.url"
else:
GETSCRIPT = "typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to make this local variable uppercase.

Would this be better names "script_url" or something like that?

Why is the js var called _scripteDir? Isn't it the full URL?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah good point. I didn't name that, but it is a bit confusing. _scriptDir can be a blob, or path to a script. Later on _scriptDir is assigned to scriptDirectory, which contains the directory of the script. I'm not sure what scriptDirectory is used for.
Anyway import.meta.url seems to return the same thing as document.currentScript.src, the difference being that import.meta.url works in a module, while document.currentScript.src doesn't.

emcc.py Outdated Show resolved Hide resolved
emscripten.py Outdated
@@ -1666,6 +1666,10 @@ def create_receiving(function_table_data, function_tables_defs, exported_impleme

shared.Settings.MODULE_EXPORTS = module_exports = exported_implemented_functions + function_tables(function_table_data)

# Should only need to do this in the main thread.
if shared.Settings.USE_PTHREADS:
receiving = "if (!ENVIRONMENT_IS_PTHREAD) {\n" + receiving + "}\n"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But the stuff added to receiving below we do want on non-main-threads? Can you explain, perhaps write more in the comment here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my testing it seems like these functions were already shared with the non-main-threads by the main thread. Calling these from a non-main-thread attempted to redefine them (as the same thing). No idea if that's how it's supposed to work.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on where this line is, it just puts the runtime assertions stuff behind this check. What's special about them? As @sbc100 said, I think this should all be needed in pthreads too - do you have a test that fails without this change?

Copy link
Collaborator Author

@VirtualTim VirtualTim Apr 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I tried to run the code before this change I was getting errors about the vars in this block being redefined. It seems like when initialising a thread these functions have already been defined (not sure how). Normally var redefinition isn't an issue as everything gets hoisted, so I assumed it was an ES6 module thing. I'll have to do some more testing, I can't remember exactly what error I was trying to avoid.

Although looking at that again I should add a check for if receiving is an empty string.

Edit: The actual error I get is:
Uncaught (in promise) TypeError: Cannot assign to read only property '__ZSt18uncaught_exceptionv' of object '[object Object]'
__ZSt18uncaught_exceptionv just happens to be the first in the list, it seems to error on all of them, causing initialising pthreads to fail.
I had assumed that these were getting defined twice, once in the main thread, once in workers, but it looks like you can't just redefine things like that in an ES6 module. I don't know why. I'll change the settings check to if shared.Settings.USE_PTHREADS and shared.Settings.EXPORT_ES6 and receiving: if I can't figure out how to get this working.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a very odd error - I don't think we use read-only properties anywhere?

Copy link
Member

@kripken kripken May 14, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, and sorry for my mistake earlier!

Ok, what I think is happening here is: when loaded as an ES6 module, the wasm exports object is an ES6 module export object, or behaves like one, and those are more "static" than normal JS objects. And we try to replace them with wrappers to add extra runtime error handling, and that fails.

But that doesn't explain why this is a problem only on workers but not on the main thread. It sounds like that could be a browser bug, in fact. That asm object is a wasm export object on both locations, so it should behave the same? Unless somehow only the worker is an ES6 context - I'm not too familiar with how those are created?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regardless, we can split this out from the rest of this PR, if it's separable.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I don't really know too much about all that stuff either.
The change on that line allows EXPORT_ES6 + USE_PTHREADS to work with ASSERTIONS != 0. I think the best thing is to merge this PR as is, since by default ASSERTIONS=1.

Perhaps after this is merged another bug can be opened to fix those assertions?\

If you'd prefer I'm happy to remove that line, and just say that currently EXPORT_ES6 + USE_PTHREADS only work with ASSERTIONS=0.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, let's separate it out - a comment that says something like your last line there sounds good enough for now.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I changed it to an assert, since the next line would just throw anyway. At least this way the developer gets a clear message about this not working. Once this is merged I'll open another issue to fix USE_PTHREADS + EXPORT_ES6 +ASSERTIONS.

src/shell_pthreads.js Outdated Show resolved Hide resolved
@VirtualTim VirtualTim marked this pull request as ready for review April 2, 2019 09:18
@VirtualTim
Copy link
Collaborator Author

Well the tests failed because the test_openjpeg test didn't find the symbol __memory_base. Not sure why test_the_bullet failed, but that seems to be failing for everyone at the moment.
I'm pretty sure those are unrelated to my changes.

I'm happy for this to be merged, if everyone else is happy with the changes.

@VirtualTim VirtualTim changed the title [WIP] Attempt to fix EXPORT_ES6 + USE_PTHREADS Fix EXPORT_ES6 + USE_PTHREADS Apr 3, 2019
emcc.py Show resolved Hide resolved
emscripten.py Outdated
@@ -1666,6 +1666,10 @@ def create_receiving(function_table_data, function_tables_defs, exported_impleme

shared.Settings.MODULE_EXPORTS = module_exports = exported_implemented_functions + function_tables(function_table_data)

# Should only need to do this in the main thread.
if shared.Settings.USE_PTHREADS:
receiving = "if (!ENVIRONMENT_IS_PTHREAD) {\n" + receiving + "}\n"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on where this line is, it just puts the runtime assertions stuff behind this check. What's special about them? As @sbc100 said, I think this should all be needed in pthreads too - do you have a test that fails without this change?

src/worker.js Show resolved Hide resolved
@kripken
Copy link
Member

kripken commented Apr 3, 2019

The test_openjpeg failures are unrelated, yeah, that was an issue we had (that should now be fixed on incoming I think).

kripken and others added 19 commits May 21, 2019 09:35
)

This helps wasm2js and pthreads currently, as those modes use a mem file.
…ke_context_current (emscripten-core#8613)

And add a complete test for both that and for emscripten_webgl_create_context in that mode (which also tests emscripten-core#8579)
…en-core#8601)

Also, add a mechanism for supporting renamed settings.  This enables
users in non-strict mode to use old name for the settings, but users
in strict mode must use the modern name.

Part of emscripten-core#8317
emscripten-core#8600)

Specifying WASM_OBJECT_FILES=0 on the link line is current needed if
one want to select LTO libraries.  However this should not exclude
some input being wasm object files.

Fixes emscripten-core#8599
…pten-core#8618)

* Update fetch API documentation because streaming is Firefox only

* Added note about EMSCRIPTEN_FETCH_STREAM_DATA being Firefox only
This test now passed with the llvm backend.
Returning EINVAL error when trying to call fsync on fd representing
UNIX pipe.

This fixes http://posixtest.sourceforge.net/ fsync/7-1 test.
Previously these tests weren't actually checking the right thing. This should fix the logic to what I think the author was trying to do.

Fixes emscripten-core#8620.
This works with the wasm backend, whether generating wasm or asm.js.

Also added `emscripten_return_address` which implements the functionality of `__builtin_return_address` when running both wasm and asm.js.
Once detached threads are finished their execution they emit the 'exit' command. Instead of a noop they should rejoin the pool.

Resolves emscripten-core#8201.
*    Make sure to note temp files that we create there. We missed one.
*    Don't eagerly remove temp files there - they will be removed later anyhow. And we do need to keep alive the temp file that we return.
…emscripten-core#8643)

We only use this in JS during startup (before compiled code is ready to run). Other usages should call malloc/sbrk directly for the full functionality.

Fixes emscripten-core#8637
@VirtualTim
Copy link
Collaborator Author

Well I merged everything from Incoming into my PR, but unfortunately I did a rebase instead of a regular merge. I'm not sure how to fix this without creating more mess (or if it even needs fixing?).
What do you think @kripken? Is this mergable, or should I just delete this PR and re-create it?
At least the tests all passed...

Copy link
Member

@kripken kripken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thanks, just some minor comments.

It's fine to leave things rebased (+ any more commits), whatever's easier - we'll squash it all when we land it anyhow, so the details of the commits in the PR don't matter.

emscripten.py Outdated
@@ -1699,6 +1699,10 @@ def create_receiving(function_table_data, function_tables_defs, exported_impleme

shared.Settings.MODULE_EXPORTS = module_exports = exported_implemented_functions + function_tables(function_table_data)

# Should only need to do this in the main thread.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please clarify this in the comment. I believe the issue is that when assertions are on, we emit code that is incompatible with ES6 currently? Can add a TODO in the comment to fix that.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I missed the comment what I changed the behaviour.

@@ -35,6 +34,10 @@ var __performance_now_clock_drift = 0;
// Cannot use console.log or console.error in a web worker, since that would risk a browser deadlock! https://bugzilla.mozilla.org/show_bug.cgi?id=1049091
// Therefore implement custom logging facility for threads running in a worker, which queue the messages to main thread to print.
var Module = {};
#if EXPORT_ES6
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we should also emit these lines if MODULARIZE as we do assign to them there as well (line 144/158), and for the same reason?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The difference is that in normal (aka sloppy) JS you can define things without var/const/let. So defining PThread like PThread = Module['PThread']; is perfectly valid. However this is not valid inside an ES6 module as that enforces strict mode. That's why I had to declare them here.
I can change #if EXPORT_ES6 to #if MODULARIZE if you want, but there may be a reason that it was initially done like that and I didn't want to break existing modularize code.

@@ -149,6 +163,7 @@ this.onmessage = function(e) {
if (typeof FS !== 'undefined' && typeof FS.createStandardStreams === 'function') FS.createStandardStreams();
#endif
postMessage({ cmd: 'loaded' });
#endif
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add a comment // MODULARIZE && EXPORT_ES6 so it's easier to match up the if and its end

@kripken
Copy link
Member

kripken commented May 24, 2019

Sounds good. I'll do the modularize changes as a separate commit later, which is probably better anyhow.

I'm rerunning the chrome tests which all failed here - probably that's just bad luck, and the rerun will pass. I'll land this if so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.