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

Generated bytecode from JS_WriteObject gives errors when loaded with JS_ReadObject #53

Closed
ammarahm-ed opened this issue Sep 3, 2023 · 13 comments

Comments

@ammarahm-ed
Copy link

Hey @ErosZy I am using quickjs in a project, everything works fine without using bytecode. As soon as I generate the bytecode and relaunch the app and load bytecode, it gives errors with Undefined variables and modules.

The issue does not happen in bellard's quickjs. I think the issue is coming due to changes related to column support.

@ErosZy
Copy link
Member

ErosZy commented Sep 3, 2023

Hi @ammarahm-ed ,WebF has also encountered this kind of problem, you need to check that your bytecode corresponds to the correct checksum, and that you are using this project's qjsc for compilation.

@ammarahm-ed
Copy link
Author

ammarahm-ed commented Sep 3, 2023

Hi @ammarahm-ed ,WebF has also encountered this kind of problem, you need to check that your bytecode corresponds to the correct checksum, and that you are using this project's qjsc for compilation.

Basically on first app launch I do the following
Load the JS bundle script file
Dump bytecode using JS_WriteObject to file.
App runs fine at this point

On 2nd launch I am loading the bytecode generated earlier but it doesn't work. Gives undefined variables and modules error.

Are you saying that if I want to use bytecode I need to put compiled bytecode using qjsc on desktop?

By the way I am running this on android, not sure if bytecode compiled on my computer will work on mobile

@ErosZy
Copy link
Member

ErosZy commented Sep 3, 2023

@ammarahm-ed any demo or example project that I can run and test locally

@ammarahm-ed
Copy link
Author

@ammarahm-ed any demo or example project that I can run and test locally

I will share with you the project.

@ammarahm-ed
Copy link
Author

ammarahm-ed commented Sep 3, 2023

Hey @ErosZy I have got the project on github: https://github.com/ammarahm-ed/react-native-quickjs/tree/openwebf

It's a react-native project, you need to follow the below steps to run it.

git clone https://github.com/ammarahm-ed/react-native-quickjs.git

cd react-native-quickjs

//Switch the branch to `openwebf`

git checkout openwebf

Run yarn

yarn

Navigate to example with cd example

yarn react-native run-android

This should run the app on your emulator or device. If you face some error, you can check the official env setup guide here: https://reactnative.dev/docs/environment-setup?platform=android&package-manager=npm

Once the app launches, it will show "Hello World".

If you restart the app, it will try to load bytecode and crash red screen error. Cannot read property NODE_ENV of undefined.

Here's the function responsible for loading the Javascript: https://github.com/ammarahm-ed/react-native-quickjs/blob/8bd9403fbf5161f9c33b4cc6da8f605c60629c29/cpp/QuickJSRuntime.cpp#L232

If you use Android Studio, you should be able to step through the code in the example when app launches

You can also switch to master branch which uses bellard's quickjs where bytecode loads normally.

The example is using this commit of quickjs: f411910

I haven't modified the source much except adding a few helper functions in runtime.c and quickjs.h files at the bottom.

Thanks for looking into it. This is an amazing effort, the performance difference is day and night with openwebf/quickjs vs quickjs.

@ErosZy
Copy link
Member

ErosZy commented Sep 5, 2023

@ammarahm-ed i will check it, thx!

@ammarahm-ed
Copy link
Author

Hey @ErosZy Did you get time to check it out

@ammarahm-ed
Copy link
Author

ammarahm-ed commented Sep 15, 2023

Hey, I got the minimal js code that will reproduce the issue if you compile it to bytecode and run anywhere:

var __BUNDLE_START_TIME__=this.nativePerformanceNow?nativePerformanceNow():Date.now(),__DEV__=false,process=this.process||{},__METRO_GLOBAL_PREFIX__='';process.env=process.env||{};process.env.NODE_ENV=process.env.NODE_ENV||"production";
!(function(r){"use strict";r.__r=i,r[__METRO_GLOBAL_PREFIX__+"__d"]=function(r,n,o){if(null!=e[n])return;var i={dependencyMap:o,factory:r,hasError:!1,importedAll:t,importedDefault:t,isInitialized:!1,publicModule:{exports:{}}};e[n]=i},r.__c=o,r.__registerSegment=function(r,t,n){s[r]=t,n&&n.forEach((function(t){e[t]||v.has(t)||v.set(t,r)}))};var e=o(),t={},n={}.hasOwnProperty;function o(){return e=Object.create(null)}function i(r){var t=r,n=e[t];return n&&n.isInitialized?n.publicModule.exports:d(t,n)}function l(r){var n=r;if(e[n]&&e[n].importedDefault!==t)return e[n].importedDefault;var o=i(n),l=o&&o.__esModule?o.default:o;return e[n].importedDefault=l}function a(r){var o=r;if(e[o]&&e[o].importedAll!==t)return e[o].importedAll;var l,a=i(o);if(a&&a.__esModule)l=a;else{if(l={},a)for(var u in a)n.call(a,u)&&(l[u]=a[u]);l.default=a}return e[o].importedAll=l}i.importDefault=l,i.importAll=a,i.context=function(){throw new Error("The experimental Metro feature `require.context` is not enabled in your project.")};var u=!1;function d(e,t){if(!u&&r.ErrorUtils){var n;u=!0;try{n=_(e,t)}catch(e){r.ErrorUtils.reportFatalError(e)}return u=!1,n}return _(e,t)}var f=16,c=65535;function p(r){return{segmentId:r>>>f,localId:r&c}}i.unpackModuleId=p,i.packModuleId=function(r){return(r.segmentId<<f)+r.localId};var s=[],v=new Map;function _(t,n){if(!n&&s.length>0){var o,u=null!==(o=v.get(t))&&void 0!==o?o:0,d=s[u];null!=d&&(d(t),n=e[t],v.delete(t))}var f=r.nativeRequire;if(!n&&f){var c=p(t),_=c.segmentId;f(c.localId,_),n=e[t]}if(!n)throw Error('Requiring unknown module "'+t+'".');if(n.hasError)throw n.error;n.isInitialized=!0;var h=n,m=h.factory,M=h.dependencyMap;try{var y=n.publicModule;return y.id=t,m(r,i,l,a,y,y.exports,M),n.factory=void 0,n.dependencyMap=void 0,y.exports}catch(r){throw n.hasError=!0,n.error=r,n.isInitialized=!1,n.publicModule.exports=void 0,r}}})('undefined'!=typeof globalThis?globalThis:'undefined'!=typeof global?global:'undefined'!=typeof window?window:this);
!(function(n){var e=(function(){function n(n,e){return n}function e(n){var e={};return n.forEach((function(n,t){e[n]=!0})),e}function t(n,t,a){if(n.formatValueCalls++,n.formatValueCalls>200)return"[TOO BIG formatValueCalls "+n.formatValueCalls+" exceeded limit of 200]";var f=r(n,t);if(f)return f;var c=Object.keys(t),s=e(c);if(d(t)&&(c.indexOf('message')>=0||c.indexOf('description')>=0))return o(t);if(0===c.length){if(v(t)){var g=t.name?': '+t.name:'';return n.stylize('[Function'+g+']','special')}if(p(t))return n.stylize(RegExp.prototype.toString.call(t),'regexp');if(y(t))return n.stylize(Date.prototype.toString.call(t),'date');if(d(t))return o(t)}var h,b,m='',j=!1,O=['{','}'];(h=t,Array.isArray(h)&&(j=!0,O=['[',']']),v(t))&&(m=' [Function'+(t.name?': '+t.name:'')+']');return p(t)&&(m=' '+RegExp.prototype.toString.call(t)),y(t)&&(m=' '+Date.prototype.toUTCString.call(t)),d(t)&&(m=' '+o(t)),0!==c.length||j&&0!=t.length?a<0?p(t)?n.stylize(RegExp.prototype.toString.call(t),'regexp'):n.stylize('[Object]','special'):(n.seen.push(t),b=j?i(n,t,a,s,c):c.map((function(e){return l(n,t,a,s,e,j)})),n.seen.pop(),u(b,m,O)):O[0]+m+O[1]}function r(n,e){if(s(e))return n.stylize('undefined','undefined');if('string'==typeof e){var t="'"+JSON.stringify(e).replace(/^"|"$/g,'').replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return n.stylize(t,'string')}return c(e)?n.stylize(''+e,'number'):a(e)?n.stylize(''+e,'boolean'):f(e)?n.stylize('null','null'):void 0}function o(n){return'['+Error.prototype.toString.call(n)+']'}function i(n,e,t,r,o){for(var i=[],u=0,a=e.length;u<a;++u)b(e,String(u))?i.push(l(n,e,t,r,String(u),!0)):i.push('');return o.forEach((function(o){o.match(/^\d+$/)||i.push(l(n,e,t,r,o,!0))})),i}function l(n,e,r,o,i,l){var u,a,c;if((c=Object.getOwnPropertyDescriptor(e,i)||{value:e[i]}).get?a=c.set?n.stylize('[Getter/Setter]','special'):n.stylize('[Getter]','special'):c.set&&(a=n.stylize('[Setter]','special')),b(o,i)||(u='['+i+']'),a||(n.seen.indexOf(c.value)<0?(a=f(r)?t(n,c.value,null):t(n,c.value,r-1)).indexOf('\n')>-1&&(a=l?a.split('\n').map((function(n){return'  '+n})).join('\n').substr(2):'\n'+a.split('\n').map((function(n){return'   '+n})).join('\n')):a=n.stylize('[Circular]','special')),s(u)){if(l&&i.match(/^\d+$/))return a;(u=JSON.stringify(''+i)).match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(u=u.substr(1,u.length-2),u=n.stylize(u,'name')):(u=u.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),u=n.stylize(u,'string'))}return u+': '+a}function u(n,e,t){return n.reduce((function(n,e){return e.indexOf('\n')>=0&&0,n+e.replace(/\u001b\[\d\d?m/g,'').length+1}),0)>60?t[0]+(''===e?'':e+'\n ')+' '+n.join(',\n  ')+' '+t[1]:t[0]+e+' '+n.join(', ')+' '+t[1]}function a(n){return'boolean'==typeof n}function f(n){return null===n}function c(n){return'number'==typeof n}function s(n){return void 0===n}function p(n){return g(n)&&'[object RegExp]'===h(n)}function g(n){return'object'==typeof n&&null!==n}function y(n){return g(n)&&'[object Date]'===h(n)}function d(n){return g(n)&&('[object Error]'===h(n)||n instanceof Error)}function v(n){return'function'==typeof n}function h(n){return Object.prototype.toString.call(n)}function b(n,e){return Object.prototype.hasOwnProperty.call(n,e)}return function(e,r){return t({seen:[],formatValueCalls:0,stylize:n},e,r.depth)}})(),t=0,r=1,o=2,i=3,l=[];l[t]='debug',l[r]='log',l[o]='warning',l[i]='error';function u(t){return function(){var r;r=1===arguments.length&&'string'==typeof arguments[0]?arguments[0]:Array.prototype.map.call(arguments,(function(n){return e(n,{depth:10})})).join(', ');var u=arguments[0],a=t;'string'==typeof u&&'Warning: '===u.slice(0,9)&&a>=i&&(a=o),n.__inspectorLog&&n.__inspectorLog(l[a],r,[].slice.call(arguments),1),f.length&&(r=c('',r)),n.nativeLoggingHook(r,a)}}function a(n,e){return Array.apply(null,Array(e)).map((function(){return n}))}var f=[];function c(n,e){return f.join('')+n+' '+(e||'')}if(n.nativeLoggingHook){n.console;n.console={error:u(i),info:u(r),log:u(r),warn:u(o),trace:u(t),debug:u(t),table:function(e){if(!Array.isArray(e)){var t=e;for(var o in e=[],t)if(t.hasOwnProperty(o)){var i=t[o];i["(index)"]=o,e.push(i)}}if(0!==e.length){var l=Object.keys(e[0]).sort(),u=[],f=[];l.forEach((function(n,t){f[t]=n.length;for(var r=0;r<e.length;r++){var o=(e[r][n]||'?').toString();u[r]=u[r]||[],u[r][t]=o,f[t]=Math.max(f[t],o.length)}}));for(var c=g(f.map((function(n){return a('-',n).join('')})),'-'),s=[g(l),c],p=0;p<e.length;p++)s.push(g(u[p]));n.nativeLoggingHook('\n'+s.join('\n'),r)}else n.nativeLoggingHook('',r);function g(n,e){var t=n.map((function(n,e){return n+a(' ',f[e]-n.length).join('')}));return e=e||' ',t.join(e+'|'+e)}},group:function(e){n.nativeLoggingHook(c("\u2510",e),r),f.push("\u2502")},groupEnd:function(){f.pop(),n.nativeLoggingHook(c("\u2518"),r)},groupCollapsed:function(e){n.nativeLoggingHook(c("\u2518",e),r),f.push("\u2502")},assert:function(e,t){e||n.nativeLoggingHook('Assertion failed: '+t,i)}},Object.defineProperty(console,'_isPolyfilled',{value:!0,enumerable:!1})}else if(!n.console){var s=function(){},p=n.print||s;n.console={debug:p,error:p,info:p,log:p,trace:p,warn:p,assert:function(n,e){n||p('Assertion failed: '+e)},clear:s,dir:s,dirxml:s,group:s,groupCollapsed:s,groupEnd:s,profile:s,profileEnd:s,table:s},Object.defineProperty(console,'_isPolyfilled',{value:!0,enumerable:!1})}})('undefined'!=typeof globalThis?globalThis:'undefined'!=typeof global?global:'undefined'!=typeof window?window:this);
!(function(n){var r=0,t=function(n,r){throw n},l={setGlobalHandler:function(n){t=n},getGlobalHandler:function(){return t},reportError:function(n){t&&t(n,!1)},reportFatalError:function(n){t&&t(n,!0)},applyWithGuard:function(n,t,u,o,e){try{return r++,n.apply(t,u)}catch(n){l.reportError(n)}finally{r--}return null},applyWithGuardIfNeeded:function(n,r,t){return l.inGuard()?n.apply(r,t):(l.applyWithGuard(n,r,t),null)},inGuard:function(){return!!r},guard:function(n,r,t){var u;if('function'!=typeof n)return console.warn('A function must be passed to ErrorUtils.guard, got ',n),null;var o=null!=(u=null!=r?r:n.name)?u:'<generated guard>';return function(){for(var r=arguments.length,u=new Array(r),e=0;e<r;e++)u[e]=arguments[e];return l.applyWithGuard(n,null!=t?t:this,u,null,o)}}};n.ErrorUtils=l})('undefined'!=typeof globalThis?globalThis:'undefined'!=typeof global?global:'undefined'!=typeof window?window:this);
'undefined'!=typeof globalThis?globalThis:'undefined'!=typeof global?global:'undefined'!=typeof window&&window,(function(){'use strict';var e=Object.prototype.hasOwnProperty;'function'!=typeof Object.entries&&(Object.entries=function(n){if(null==n)throw new TypeError('Object.entries called on non-object');var o=[];for(var t in n)e.call(n,t)&&o.push([t,n[t]]);return o}),'function'!=typeof Object.values&&(Object.values=function(n){if(null==n)throw new TypeError('Object.values called on non-object');var o=[];for(var t in n)e.call(n,t)&&o.push(n[t]);return o})})();
__d((function(g,r,i,a,m,e,d){}),0,[]);
__r(0);
//# sourceMappingURL=index.android.bundle.map
console.log(__BUNDLE_START_TIME__)

On running bytecode, it should give error Cannot read properties of undefined NODE_ENV`.

This works fine on my mac after running as an executable with bytecode compiled with qjsc, but still causes error on android.

@ErosZy
Copy link
Member

ErosZy commented Oct 7, 2023

@ammarahm-ed I'm very sorry, there's been a lot of work related stuff going on lately, I'll take a look at this as soon as I can.

@ammarahm-ed
Copy link
Author

@ErosZy Awesome, thanks. No rush.

@ErosZy
Copy link
Member

ErosZy commented Jan 3, 2024

@ammarahm-ed Are you using Bellard's QuickJS and the qjsc tool to generate corresponding bytecode, and then executing it with openwebf/quickjs? I tried it, and there were no issues with the bytecode generated by openwebf/quickjs's qjsc. However, if I use Bellard's QuickJS's qjsc, it produces the corresponding error: SyntaxError: invalid atom index (pos=1970).

Only happended at android platform, right?

@ErosZy
Copy link
Member

ErosZy commented Jan 4, 2024

@ammarahm-ed you can follow quickjs-ng/quickjs, we already fix proto poly ic bug and ready to merge to quickjs-ng/quickjs. quickjs-ng/quickjs#244 thx.

@ErosZy ErosZy closed this as completed Jan 4, 2024
@ammarahm-ed
Copy link
Author

@ErosZy Thanks! that's great

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

No branches or pull requests

2 participants