JIT: Fix issue where the 'jit' keyword got included in compiled code

JIT: If using a builtin global function (eg digitalWrite), use it directly rather than searching by name
This commit is contained in:
Gordon Williams 2024-04-17 14:46:19 +01:00
parent 176a23cf1b
commit 0f21d49c86
3 changed files with 31 additions and 9 deletions

View File

@ -26,6 +26,8 @@
Storage.readJSON will now read numeric field names like "{1:1}" which can be produced by writeJSON (fix #2484)
Ensure `Bangle.load(".bootcde")` just calls `load()` if no uiRemove - fix error loading clock without widgets
Forward errors encountered while loading modules back into Espruino (fix #2485)
JIT: Fix issue where the 'jit' keyword got included in compiled code
JIT: If using a builtin global function (eg digitalWrite), use it directly rather than searching by name
2v21 : nRF52: free up 800b more flash by removing vector table padding
Throw Exception when a Promise tries to resolve with another Promise (#2450)

View File

@ -25,18 +25,18 @@ Works:
Doesn't work:
* Everything else
* `new X(...)`
* Everything not mentioned under `Works`
Performance:
* When calling a JIT function, we use existing FunctionCall code to set up args and an execution scope (so args can be passed in)
* Variables are referenced at the start just once and stored on the stack
* We could also maybe extend it to allow caching of constant field access, for instance 'console.log'
* Built-in functions could be called directly, which would be a TON faster
* We could also maybe extend it to allow caching of constant field accesses, for instance 'console.log'
* Built-in global functions are called directly which is a ton faster, but methods like 'console.log' are not currently
* Peephole optimisation could still be added (eg. removing `push r0, pop r0`) but this is the least of our worries
* Stuff is in place to allow ints to be stored on the stack and converted when needed. This could maybe allow us to keep some vars as ints.
* Stuff is in place to allow ints to be stored on the stack and converted when needed. This could allow us to keep some vars as ints, but control flow makes this hard
* When a function is called we load up the address as a 32 bit literal each time. We could maybe have a constant pool or local stub functions?
* When we emit code, we just use StringAppend which can be very slow. We should use an iterator (it's an easy win for compile performance)
Possible improvements:

View File

@ -17,6 +17,7 @@
#include "jsjit.h"
#include "jsjitc.h"
#include "jsinteractive.h"
#include "jswrapper.h"
#define JSP_ASSERT_MATCH(TOKEN) { assert(0+lex->tk==(TOKEN));jslGetNextToken(); } // Match where if we have the wrong token, it's an internal error
#define JSP_MATCH_WITH_RETURN(TOKEN, RETURN_VAL) if (!jslMatch((TOKEN))) return RETURN_VAL;
@ -234,12 +235,31 @@ void jsjFactorIDAndUnLock(JsVar *name, LEX_TYPES creationOp) {
// We don't have it yet - create a var list entry
varIndexVal = jsvNewFromInteger(jit.varCount++);
jsvSetValueOfName(varIndex, varIndexVal);
jsjcLiteralString(0, name, true); // null terminated string in r0
// Now add the code which will create the variable right at the start of the file
if (creationOp==LEX_ID) { // Just a normal ID
jsjcDebugPrintf("; Find Variable %j\n", name);
jsjcCall(jspGetNamedVariable); // Find the var in the current scopes (always returns something even if it's jsvNewChild)
// See if it's a builtin function, if builtinFunction!=0
char tokenName[JSLEX_MAX_TOKEN_LENGTH];
size_t tokenL = jsvGetString(name, tokenName, sizeof(tokenName));
tokenName[tokenL] = 0; // null termination
JsVar *builtin = jswFindBuiltInFunction(0, tokenName);
if (jsvIsNativeFunction(builtin)) { // it's a built-in function - just create it in place rather than searching
jsjcDebugPrintf("; Native Function %j\n", name);
jsjcLiteral32(0, builtin->varData.native.ptr);
jsjcLiteral16(1, false, builtin->varData.native.argTypes);
jsjcCall(jsvNewNativeFunction); // JsVar *jsvNewNativeFunction(void (*ptr)(void), unsigned short argTypes)
} else if (jsvIsPin(builtin)) { // it's a built-in pin - just create it in place rather than searching
jsjcDebugPrintf("; Native Pin %j\n", name);
jsjcLiteral32(0, jsvGetInteger(builtin));
jsjcCall(jsvNewFromPin); // JsVar *jsvNewNativeFunction(void (*ptr)(void), unsigned short argTypes)
} else { // it's not a builtin function - just search for the variable the normal way
jsjcDebugPrintf("; Find Variable %j\n", name);
jsjcLiteralString(0, name, true); // null terminated string in r0
jsjcCall(jspGetNamedVariable); // Find the var in the current scopes (always returns something even if it's jsvNewChild)
}
jsvUnLock(builtin);
} else if (creationOp==LEX_R_VAR || creationOp==LEX_R_LET || creationOp==LEX_R_CONST) {
jsjcDebugPrintf("; Variable Decl %j\n", name);
jsjcLiteralString(0, name, true); // null terminated string in r0
// _jsxAddVar(r0:name)
jsjcCall(_jsxAddVar); // add the variable
} else assert(0);
@ -1110,7 +1130,7 @@ JsVar *jsjParseFunction() {
// Function init code
jsjFunctionStart();
// Parse the function
size_t codeStartPosition = lex->tokenLastStart;
size_t codeStartPosition = lex->tokenStart; // otherwise we include 'jit' too!
jit.phase = JSJP_SCAN; DEBUG_JIT("; ============ SCAN PHASE\n");
jsjBlockNoBrackets();
if (JSJ_PARSING) { // if no error, re-parse and create code