bytenode/bytenode

Compiled code only working if bytenode.compileFile is executed using the dev console

paulr113 opened this issue · 15 comments

I'm running into a very strange issue while using bytenode to compile the .js files of my Electron app.
I have a compile.js file, which will compile all my code into bytecode. If i try to use it by running require("./compile") from any .js file within the render process the compiled code won't work and gives me an error message. If I on the other hand run require("./compile") from the dev tools console the compiled code works just fine.

compile.js:

const bytenode = require("bytenode")
const fs = require('fs');
const v8 = require('v8');

v8.setFlagsFromString('--no-lazy');

bytenode.compileFile("./src/modules/file.js", "./src/modules/file.jsc");

Error message:

#
# Fatal error in , line 0
# ignored
#
#
#
#FailureMessage Object: 0x7ffeee8750900   Electron Framework                  0x0000000108da5a59 v8::internal::SetupIsolateDelegate::SetupHeap(v8::internal::Heap*) + 12223577
1   Electron Framework                  0x0000000108cfe163 v8::internal::SetupIsolateDelegate::SetupHeap(v8::internal::Heap*) + 11537251
2   Electron Framework                  0x000000010aa3771b v8::internal::SetupIsolateDelegate::SetupHeap(v8::internal::Heap*) + 42180891
3   Electron Framework                  0x000000010aa19823 v8::internal::SetupIsolateDelegate::SetupHeap(v8::internal::Heap*) + 42058275
4   Electron Framework                  0x0000000107737f84 v8::internal::Parser::DoParseFunction(v8::internal::Isolate*, v8::internal::ParseInfo*, v8::internal::AstRawString const*) + 340
5   Electron Framework                  0x0000000107737a4c v8::internal::Parser::ParseFunction(v8::internal::Isolate*, v8::internal::ParseInfo*, v8::internal::Handle<v8::internal::SharedFunctionInfo>) + 524
6   Electron Framework                  0x0000000107a7c1e8 v8::internal::parsing::ParseFunction(v8::internal::ParseInfo*, v8::internal::Handle<v8::internal::SharedFunctionInfo>, v8::internal::Isolate*, v8::internal::parsing::ReportErrorsAndStatisticsMode) + 248
7   Electron Framework                  0x00000001077fbae1 v8::internal::Compiler::CollectSourcePositions(v8::internal::Isolate*, v8::internal::Handle<v8::internal::SharedFunctionInfo>) + 1025
8   Electron Framework                  0x0000000107885d32 v8::internal::Factory::NewProperSubString(v8::internal::Handle<v8::internal::String>, int, int) + 2258
9   Electron Framework                  0x0000000107885bb6 v8::internal::Factory::NewProperSubString(v8::internal::Handle<v8::internal::String>, int, int) + 1878
10  Electron Framework                  0x00000001078acd58 v8::internal::Factory::NewStackFrameInfo(v8::internal::Handle<v8::internal::FrameArray>, int) + 264
11  Electron Framework                  0x0000000107a62f39 v8::internal::ScopeInfo::InferredFunctionName() const + 11849
12  Electron Framework                  0x0000000107a623e7 v8::internal::ScopeInfo::InferredFunctionName() const + 8951
13  Electron Framework                  0x000000010765c3b8 v8::StackFrame::GetFunctionName() const + 56
14  Electron Framework                  0x0000000107dba93e v8_inspector::V8StackTraceId::V8StackTraceId(unsigned long, std::__1::pair<long long, long long>) + 78
15  Electron Framework                  0x0000000107da7ae2 v8_inspector::V8StackTraceId::V8StackTraceId() + 21282
16  Electron Framework                  0x0000000107dbb357 v8_inspector::V8StackTraceId::V8StackTraceId(unsigned long, std::__1::pair<long long, long long>) + 2663
17  Electron Framework                  0x0000000107da6056 v8_inspector::V8StackTraceId::V8StackTraceId() + 14486
18  Electron Framework                  0x0000000107da35df v8_inspector::V8StackTraceId::V8StackTraceId() + 3615
19  Electron Framework                  0x0000000107d8a2e3 v8_inspector::DumpAsyncTaskStacksStateForTest(v8_inspector::V8Inspector*) + 30947
20  Electron Framework                  0x0000000107d88694 v8_inspector::DumpAsyncTaskStacksStateForTest(v8_inspector::V8Inspector*) + 23700
21  Electron Framework                  0x0000000107d88753 v8_inspector::DumpAsyncTaskStacksStateForTest(v8_inspector::V8Inspector*) + 23891
22  Electron Framework                  0x00000001077e3444 v8::internal::Accessors::MakeAccessor(v8::internal::Isolate*, v8::internal::Handle<v8::internal::Name>, void (*)(v8::Local<v8::Name>, v8::PropertyCallbackInfo<v8::Value> const&), void (*)(v8::Local<v8::Name>, v8::Local<v8::Value>, v8::PropertyCallbackInfo<v8::Boolean> const&)) + 283572
23  Electron Framework                  0x00000001077ad235 v8::internal::Accessors::MakeAccessor(v8::internal::Isolate*, v8::internal::Handle<v8::internal::Name>, void (*)(v8::Local<v8::Name>, v8::PropertyCallbackInfo<v8::Value> const&), void (*)(v8::Local<v8::Name>, v8::Local<v8::Value>, v8::PropertyCallbackInfo<v8::Boolean> const&)) + 61861
24  Electron Framework                  0x0000000108167fb9 v8::internal::compiler::ZoneStats::ReturnZone(v8::internal::Zone*) + 839161
25  Electron Framework                  0x00000001080ee001 v8::internal::compiler::ZoneStats::ReturnZone(v8::internal::Zone*) + 339521
26  Electron Framework                  0x00000001081186d0 v8::internal::compiler::ZoneStats::ReturnZone(v8::internal::Zone*) + 513296
27  Electron Framework                  0x000000010813c972 v8::internal::compiler::ZoneStats::ReturnZone(v8::internal::Zone*) + 661426

Could you please start with something similar to this example? That example uses a very simple logic that can be easily adapted to your needs, and it works with no issues.

Let me know if this solves your issue.

I have used your example to compile all .js files needed for my main process (worked fine). My problem is, that I'm trying to compile the .js files needed for my render process.

I guess your problem is that you are trying to run your compiled code inside the browser v8 engine, not node v8 engine. The compiled code depends on the APIs that node exposes, so without them it won't run.

So, if we have a setup like this, it WON'T work after compilation:

<!-- index.html -->
<script src="/path/to/jquery.js"></script>
<script>
  const bytenode = require('bytenode');
  require('./compiled-file.jsc');
</script>
// compiled-file.js
$(document).ready(function() {
  $("#target1").css("color", "red");
});

If you want to make it work, you have to use a setup like this:

<!-- index.html -->
<script src="/path/to/jquery.js"></script>
<script>
  const bytenode = require('bytenode');
  require('./compiled-file.jsc')(document, jQuery); // or you can pass the window object itself, or whatever suits your needs.
</script>
// compiled-file.js
module.exports = function(document, $) {
  $(document).ready(function() {
    $("#target1").css("color", "red");
  });
}

This didn't fix my issue. It might be worth pointing out, that my BrowserWindows is using nodeIntegration: true. The file I'm trying to compile is using various node features such as fs, child_process and util.promisify

Could you please provide a minimal app that reproduce the problem?

I have uploaded an example to https://github.com/paulr113/bytenode_bug_example. Im pretty sure setTimeout is causing the crash.

I can reproduce the error. Promise.delay too causes the same crash, not only setTimeout.

Do you have any idea why this is happening?

Still investigating...

I looks like the issue isn't related to setTimeout but to async arrow functions in general.
This code works:

document.getElementById("testBtn").onclick = (ev) => {
    document.getElementById("testP").innerHTML = "Before delay"
    delay(1000).then(() => {
        document.getElementById("testP").innerHTML = "After delay"
    })
}

This code works aswell:

document.getElementById("testBtn").onclick = async function (ev) {
    document.getElementById("testP").innerHTML = "Before delay"
    await delay(1000);
    document.getElementById("testP").innerHTML = "After delay"
}

This code will result in a crash:

document.getElementById("testBtn").onclick = async (ev) => {
    document.getElementById("testP").innerHTML = "Before delay"
    await delay(1000);
    document.getElementById("testP").innerHTML = "After delay"
}

delay():

function delay(delay) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            return resolve();
        }, delay)
    })
}

Thank you for your analysis. I added this to the list of know limitations.

I have made a new pull request (#49 ) which fixes the issue.

@OsamaAbbas So, there is no work around for this other than not using async arrow functions?

@OsamaAbbas So, there is no work around for this other than not using async arrow functions?

Check the pull request by paulr113 (#49), he managed to achieve what you are looking for by using babel.

Is there an open electron issue that I can follow for this?