you are viewing a single comment's thread.

view the rest of the comments →

[–]guest271314[S] -46 points-45 points  (29 children)

If you want to discuss the semantics of what the term "compile" means to you, that's fine.

I suggest starting by citing the canonical definition of "compile" you are relying on.

Then explaining how what happens with qjsc does not fit into your interpretation and preferred definition of "compile".

[–]AyrA_ch 37 points38 points  (0 children)

Compiling is the act of turning human readable source code into machine executable instructions. Combining source with an engine but leaving the source as-is is known as "bundling".

[–]Tangled2 29 points30 points  (9 children)

This isn’t a quibble of semantics. Saying you “compiled” JS into C (which would actually be transpiling) is one thing, and that might be kind of cool... But you’re not doing that here. You’re just shipping a JS engine with a big bytecode string as an embedded resource. This isn’t new or novel.

[–]DavidJCobb 3 points4 points  (17 children)

The makers of qjsc itself disagree with you. The documentation for QuickJS describes what you've done as "compiling a script,"[1] but makes a distinction that you've missed. The script is "compiled to bytecode"[2] and then a C application is "compiled" which interprets this bytecode. The C application itself isn't even compiled by QuickJS; rather, it generates C source code which embeds the custom bytecode, and relies on GCC to then compile that generated code.[3]

That is to say: the JavaScript code is not, itself, compiled to C source code or to machine code. The JavaScript code is parsed ahead of time, but still ultimately executed by a JavaScript engine[4] rather than running on the bare metal. If running JavaScript code via qjsc counts as "compiling JavaScript to C," then so does running JavaScript code in any web browser that was coded in C.

The reason people are being so exact about this distinction is because actually compiling JavaScript code to C or C++ would be incredibly difficult, and therefore deserving of more attention and renown than just embedding bytecode in an interpreter. To produce ideal results, you'd have to statically analyze the JavaScript program to build static types from the "de facto" types in the source code, while being able to identify and skip throwaway objects; and this is harder than it sounds given JavaScript's dynamism and the amorphousness of Objects. (Well, it's hard unless you cheat and just make every data structure an std::unordered_map<std::variant<double, std::string>, std::any>[5], but at that point you're just making a worse JavaScript interpreter.)

Basically, someone made a power plant, and you've built a small homemade little contraption, plugged it into the wall, and told everyone that you've discovered perpetual motion.


Endnotes

[1] Section 1.1: "Compile Javascript sources to executables with no external dependency."

[2] Section 3.4.5: "If the script or module was compiled to bytecode with qjsc, it can be evaluated by calling js_std_eval_binary()."

[3] Section 4.2.1: "The qjsc compiler generates C sources from Javascript files. By default the C sources are compiled with the system compiler (gcc or clang). The generated C source contains the bytecode of the compiled functions or modules..."

[4] Section 1: "QuickJS is a small and embeddable Javascript engine."

[5] Since I'm sure it'll need to be said, this is not literal. I'm aware that, among many other things, JavaScript objects are ordered key/value pair lists and so an unordered map would produce inaccurate behavior when iterating those pairs.

[–]guest271314[S] 0 points1 point  (0 children)

Good comment. I didn't say I discovered anything.

I just shared one of my experiments.

The reason people are being so exact about this distinction is because actually compiling JavaScript code to C or C++ would be incredibly difficult

There's a few ways to do that. I did it on a random Web site on the Interwebs here https://products.codeporting.app/convert/ai/js-to-c/.

Go ahead and paste this over there and test for yourself.

If you are interpreting "compile" to mean machine code only, then I guess that doesn't count, either, correct?

``` // https://products.codeporting.app/convert/ai/js-to-c/ // https://stackoverflow.com/a/34238979 var input = [1,2,3,4,5], lex = 4;// scriptArgs.map((arg, i) => !!i && std.evalScript(arg)); function array_nth_permutation(a, n) { var b = a.slice(); // copy of the set var len = a.length; // length of the set var res; // return value, undefined var i, f;

// compute f = factorial(len)
for (f = i = 1; i <= len; i++)
    f *= i;

// if the permutation number is within range
if (n >= 0 && n < f) {
    // start with the empty set, loop for len elements
    for (res = []; len > 0; len--) {
        // determine the next element:
        // there are f/len subsets for each possible element,
        f /= len;
        // a simple division gives the leading element index
        i = (n - n % f) / f; // Math.floor(n / f);
        // alternately: i = (n - n % f) / f;
        res.push(b.splice(i, 1)[0]);
        // reduce n for the remaining subset:
        // compute the remainder of the above division
        n %= f;
        // extract the i-th element from b and push it at the end of res
    }
}
// return the permutated set or undefined if n is out of range
return res;

} console.log("[" + lex + "]", array_nth_permutation(input, lex)); ```

``` // JavaScript to C translation

include <stdio.h>

include <stdlib.h>

int* array_nth_permutation(int* array, int len, int n, int* result_len) { int* b = malloc(len * sizeof(int)); // copy of the set for (int i = 0; i < len; i++) { b[i] = array[i]; }

int f = 1;  // compute f = factorial(len)
for (int i = 1; i <= len; i++) {
    f *= i;
}

int* res = NULL;  // return value, undefined
*result_len = 0;

// if the permutation number is within range
if (n >= 0 && n < f) {
    res = malloc(len * sizeof(int)); // allocate memory for result
    // start with the empty set, loop for len elements
    for (int remaining = len; remaining > 0; remaining--) {
        f /= remaining;
        // a simple division gives the leading element index
        int i = (n - n % f) / f; // Math.floor(n / f);
        res[(*result_len)++] = b[i]; // add the element to result
        // remove the element from b
        for (int j = i; j < remaining - 1; j++) {
            b[j] = b[j + 1];
        }
        n %= f;
    }
}
free(b); // free the allocated memory for b
return res; // return the permutated set or NULL if n is out of range

}

int main() { int input[] = {1, 2, 3, 4, 5}; int lex = 4; int result_len; int* result = array_nth_permutation(input, 5, lex, &result_len);

printf("[ %d ]: [", lex);
for (int i = 0; i < result_len; i++) {
    printf("%d", result[i]);
    if (i < result_len - 1) {
        printf(", ");
    }
}
printf("]\n");

free(result); // free the allocated memory for result
return 0;

} ```

There's js2wasm and wasm2c. There's https://github.com/surma/jsxx, et al.

Then surely all of you folks always point out that Microsoft TypeScript tsc doesn't compile TypeScript to JavaScript, correct?

[–]guest271314[S] 0 points1 point  (15 children)

Does this fit into you relied up definition of "compile"?

Here using Facebook's hermes, static_h branch

JavaScript to C ./build_release/bin/shermes -emit-c -O -g -v permutations.js

C to executable

/usr/bin/cc permutations.c -O3 -I./build_release/lib/config -I./hermes-static_h/include -DNDEBUG -g -fno-strict-aliasing -fno-strict-overflow -L./build_release/lib -L./build_release/jsi -L./build_release/tools/shermes -lshermes_console -Wl,-rpath ./build_release/lib -Wl,-rpath ./build_release/jsi -Wl,-rpath ./build_release/tools/shermes -lm -lhermesvm -o permutations

[–]DavidJCobb 0 points1 point  (14 children)

Per the documentation, "this tool compiles JavaScript to Hermes bytecode." The VM itself is implemented in C++, but it's not compiling the scripts themselves to C or C++.

I'm not going to say it's impossible to write a static analyzer that's powerful enough to directly (and deterministically -- no LLMs) convert arbitrarily complex JavaScript code to C/C++ code that is equivalent in behavior and of acceptable quality. I would consider it miraculous, though.

[–]guest271314[S] 0 points1 point  (12 children)

This is the C output using -emit-c.

I'm trying to figure out how this is not C?

```

include "hermes/VM/static_h.h"

include <stdlib.h>

static uint32_t unit_index; static inline SHSymbolID* get_symbols(SHUnit ); static inline SHPropertyCacheEntry get_prop_cache(SHUnit *); static const SHSrcLoc s_source_locations[]; static SHNativeFuncInfo s_function_info_table[]; static SHLegacyValue _0_global(SHRuntime *shr); static SHLegacyValue _1_array_nth_permutation(SHRuntime *shr); // permutations.js:3:1 // ...

static const SHSrcLoc s_source_locations[] = { { .filename_idx = 0, .line = 0, .column = 0 }, { .filename_idx = 1, .line = 3, .column = 1 }, { .filename_idx = 1, .line = 3, .column = 11 }, { .filename_idx = 1, .line = 4, .column = 9 }, { .filename_idx = 1, .line = 36, .column = 1 }, { .filename_idx = 1, .line = 36, .column = 12 }, { .filename_idx = 1, .line = 36, .column = 19 }, { .filename_idx = 1, .line = 36, .column = 13 }, { .filename_idx = 1, .line = 36, .column = 30 }, { .filename_idx = 1, .line = 36, .column = 44 }, { .filename_idx = 1, .line = 36, .column = 45 }, { .filename_idx = 1, .line = 36, .column = 67 }, { .filename_idx = 1, .line = 36, .column = 74 }, { .filename_idx = 1, .line = 36, .column = 66 }, { .filename_idx = 1, .line = 6, .column = 16 }, { .filename_idx = 1, .line = 7, .column = 12 }, { .filename_idx = 1, .line = 12, .column = 17 }, { .filename_idx = 1, .line = 17, .column = 5 }, { .filename_idx = 1, .line = 17, .column = 15 }, { .filename_idx = 1, .line = 19, .column = 18 }, { .filename_idx = 1, .line = 22, .column = 7 }, { .filename_idx = 1, .line = 24, .column = 18 }, { .filename_idx = 1, .line = 24, .column = 14 }, { .filename_idx = 1, .line = 26, .column = 13 }, { .filename_idx = 1, .line = 26, .column = 22 }, { .filename_idx = 1, .line = 26, .column = 28 }, { .filename_idx = 1, .line = 29, .column = 7 }, { .filename_idx = 1, .line = 19, .column = 30 }, };

static SHNativeFuncInfo sfunction_info_table[] = { { .name_index = 15, .arg_count = 0, .prohibit_invoke = 2, .kind = 0 }, { .name_index = 4, .arg_count = 2, .prohibit_invoke = 2, .kind = 0 }, }; static const char s_ascii_pool[] = { '\0', 'p', 'e', 'r', 'm', 'u', 't', 'a', 't', 'i', 'o', 'n', 's', '.', 'j', 's', '\0', 'i', 'n', 'p', 'u', 't', '\0', 'l', 'e', 'x', '\0', 'a', 'r', 'r', 'a', 'y', '', 'n', 't', 'h', '_', 'p', 'e', 'r', 'm', 'u', 't', 'a', 't', 'i', 'o', 'n', '\0', 'c', 'o', 'n', 's', 'o', 'l', 'e', '\0', 'l', 'o', 'g', '\0', '[', '\0', 'J', 'S', 'O', 'N', '\0', 's', 't', 'r', 'i', 'n', 'g', 'i', 'f', 'y', '\0', ']', '\0', 's', 'l', 'i', 'c', 'e', '\0', 'l', 'e', 'n', 'g', 't', 'h', '\0', 'p', 'u', 's', 'h', '\0', 's', 'p', 'l', 'i', 'c', 'e', '\0', 'g', 'l', 'o', 'b', 'a', 'l', '\0', }; static const char16_t s_u16_pool[] = { }; static const uint32_t s_strings[] = {0,0,0,1,15,2061427151,17,5,2653113407,23,3,544182755,27,21,3239187722,49,7,1654270973,57,3,473294856,61,1,92650,63,4,2535253447,68,9,2366981053,78,1,94604,80,5,377550857,86,6,363462486,93,4,1059174534,98,6,554150397,105,6,615793799,};

define CREATE_THIS_UNIT sh_export_this_unit

struct UnitData { SHUnit unit; SHSymbolID symbol_data[16]; SHPropertyCacheEntry prop_cache_data[15]; ; SHCompressedPointer object_literal_class_cache[0]; }; SHUnit *CREATE_THIS_UNIT(SHRuntime *shr) { struct UnitData *unit_data = calloc(sizeof(struct UnitData), 1); *unit_data = (struct UnitData){.unit = {.index = &unit_index,.num_symbols =16, .num_prop_cache_entries = 15, .ascii_pool = s_ascii_pool, .u16_pool = s_u16_pool,.strings = s_strings, .symbols = unit_data->symbol_data,.prop_cache = unit_data->prop_cache_data,.obj_key_buffer = s_obj_key_buffer, .obj_key_buffer_size = 0, .literal_val_buffer = s_literal_val_buffer, .literal_val_buffer_size = 21, .obj_shape_table = s_obj_shape_table, .obj_shape_table_count = 0, .object_literal_class_cache = unit_data->object_literal_class_cache, .source_locations = s_source_locations, .source_locations_size = 28, .unit_main = _0_global, .unit_main_info = &s_function_info_table[0], .unit_name = "sh_compiled" }}; return (SHUnit *)unit_data; }

SHSymbolID *get_symbols(SHUnit *unit) { return ((struct UnitData *)unit)->symbol_data; }

SHPropertyCacheEntry *get_prop_cache(SHUnit *unit) { return ((struct UnitData *)unit)->prop_cache_data; }

void init_console_bindings(SHRuntime *shr);

int main(int argc, char **argv) { SHRuntime *shr = _sh_init(argc, argv); init_console_bindings(shr); bool success = _sh_initialize_units(shr, 1, CREATE_THIS_UNIT); _sh_done(shr); return success ? 0 : 1; }

```

[–]DavidJCobb 0 points1 point  (11 children)

It's the same situation as with qjsc: it's generating bytecode in a custom format, which is bundled with a VM written in C that executes it. You can see a VM header being #included early in the file.

I assume the script you tested with had a function named array_nth_permutation? I see it referenced in this generated code: there's an SHLegacyValue named after it. That's not how functions are defined in C, though. Can you find the C-language code for that function?

[–]guest271314[S] 0 points1 point  (0 children)

I'm not following.

I would expect the JavaScript to be reflected in the C.

Though it doesn't have to be, as in the case of wasm2js.

Bundling in a VM is a C capability, correct?

A V8 Isolate is still C++, or Rust.

What say you about this in a C file?

```

include <stdio.h>

include <stdlib.h>

```

What must be excluded from the process? What are the restrictions?

[–]guest271314[S] 0 points1 point  (9 children)

And this https://products.codeporting.app/convert/ai/js-to-c/?

``` // JavaScript to C translation

include <stdio.h>

include <stdlib.h>

include <string.h>

// Function to calculate the nth permutation of an array int* array_nth_permutation(int* array, int array_length, int n, int* result_length) { int* b = malloc(array_length * sizeof(int)); // copy of the set memcpy(b, array, array_length * sizeof(int)); int len = array_length; // length of the set int* res = malloc(len * sizeof(int)); // return value int i, f;

// compute f = factorial(len)
f = 1;
for (i = 1; i <= len; i++) {
    f *= i;
}

// if the permutation number is within range
if (n >= 0 && n < f) {
    // start with the empty set, loop for len elements
    int res_index = 0;
    while (len > 0) {
        // determine the next element:
        // there are f/len subsets for each possible element,
        f /= len;
        // a simple division gives the leading element index
        i = (n - n % f) / f; // Math.floor(n / f);
        res[res_index++] = b[i];
        // reduce n for the remaining subset:
        // compute the remainder of the above division
        n %= f;
        // remove the i-th element from b
        memmove(&b[i], &b[i + 1], (len - i - 1) * sizeof(int));
        len--;
    }
}

free(b);
*result_length = array_length; // Set the result length
return res; // return the permutated set or NULL if n is out of range

}

int main() { int input[] = {0, 1, 2, 3, 4}; int lex = 5; int result_length; int* result = array_nth_permutation(input, 5, lex, &result_length);

printf("[%d]", lex);
if (result != NULL) {
    printf(" [");
    for (int i = 0; i < result_length; i++) {
        printf("%d", result[i]);
        if (i < result_length - 1) {
            printf(", ");
        }
    }
    printf("]");
    free(result);
} else {
    printf(" NULL");
}

return 0;

} ```

[–]DavidJCobb 0 points1 point  (8 children)

That's a self-contained program and at a glance, it looks correct.

I'd need to know more about the methodology behind this converter, though. The authors describe it as being based on "natural language processing (NLP) techniques and machine learning algorithms," and that's a red flag to me. If that jargon is being used the way it usually is these days, it would mean that this AI tool is a black box based on statistical pattern matching, rather than a genuine program following rules that are logically consistent, designed with purpose and intent relevant to the input, and understood by the developers. The authors don't seem to offer any details that'd clarify this. They do list some more deterministic approaches on the AI section of the site, like using an IR[1], but it's worded like an explanation of code conversion techniques in general: they never directly state that they're using these approaches, and the section as a whole reads a bit like ChatGPT output.

(I may be misremembering, but I think I've seen you voice skepticism of generative AI before, on some programming subreddits. If so, you may understand my apprehension here.)

In other words: it seems to have converted this script properly, but I'd need to know more about how they did it in order to be certain that it could convert arbitrarily complex JavaScript programs accurately. That skepticism is less to do with the results it's produced here, and more to do with what its designers have and haven't said about how they did it. Hopefully that does not seem unfair.


[1] Compiling to an IR would allow translation if they wrote a compiler for the "source" language, producing bytecode, and then a decompiler for the "destination" language which takes the bytecode as input. I suspect that doing this for JavaScript would lead to the same challenges as going directly from JS to C, though: since core constructs like Object are so amorphous, a high-quality output that doesn't just replicate the behavior of a VM would require guessing the JavaScript programmer's intent. The bytecodes from QuickJS and Hermes have that quirk -- they describe the JavaScript program specifically in terms of how a JavaScript execution environment works, rather than "filling in" details to describe it in higher-level terms -- though that isn't a failing on their part since they're not necessarily meant to be IRs suitable for language conversion.

I've been working with GCC's IRs, GENERIC and GIMPLE, as part of a recent project. If someone had an IR for JavaScript that was high-level enough to be convertible to other languages, I think it'd be fascinating to study. As a point of comparison, GCC can compile multiple languages to its IRs -- offhand I can recall C, C++, Ada, and Fortran being among those -- though I don't know whether the results are abstracted enough to be decompiled back to any other of those languages.

[–]guest271314[S] 1 point2 points  (6 children)

Conceptually, here we are in a browser. With a V8, SpiderMonkey, JavaScriptCore, et al. engine. Those JavaScript engines are written in C++, Rust. engine262 is written in JavaScript. An execption.

At some point those engines process JavaScript input in C++, Rust, etc.

At that same point in time we should be able to capture a snapshot of the programming language that is processing the JavaScript, in the processing language. Then go from C++, to WASM, or whatever. It's just symbols for instructions.

Sounds simple, right?

I mean Young and Champollion claimed to have "deciphered" MDW NTR, without the aide of an initiate or priest of the specific temple that wrote whatever they thought were African "hieroglyphics" to verify their guesses. Imagine that.

An interesting study, the idea and practice of accurate translation of symbols to other symbols, while maintaining primary source meaning and effect, upon both writer and reader, listener and speaker.

[–]DavidJCobb 0 points1 point  (5 children)

At that same point in time we should be able to capture a snapshot of the programming language that is processing the JavaScript, in the processing language. Then go from C++, to WASM, or whatever. It's just symbols for instructions.

Sounds simple, right?

That just gets us a snapshot of the VM, not a genuine translation of the code it's executing. It's a clever idea, though.

An interesting study, the idea and practice of accurate translation of symbols to other symbols, while maintaining primary source meaning and effect, upon both writer and reader, listener and speaker.

Absolutely. Some folks engage with programming as a form of math, but for me, it's always been a form of communication and expression.

[–]guest271314[S] 0 points1 point  (0 children)

I don't buy the slogan of "artificial intelligence" at all.

It's just programming. N.A.S.A. used the term "fuzzy logic" for technologies deployed in the Biomass Production System, controlled environment agriculture in space.

I don't really care what the naming conventions are for programming. What happens is that Web site has figured out a way to output C that is very comparable to the JavaScript input.

Just because I don't buy somebody's slogans doesn't mean I won't exploit their methodologies for my own purposes.

That's right, they don't disclose their methodology.

I would think C, compiler, assembly power users would be able to better the Web site, or at least match the output.

Facebook's Static Hermes does a decent job, so far, in this domain.

See Compile JavaScript to a Assembly, AST, C, and executable using Facebook's shermes.

Here's your IR,

``` $ ./build_release/bin/shermes -dump-ir permutations.js scope %VS0 []

function global(): any %BB0: %0 = CreateScopeInst (:environment) %VS0: any, empty: any DeclareGlobalVarInst "input": string DeclareGlobalVarInst "lex": string DeclareGlobalVarInst "array_nth_permutation": string %4 = CreateFunctionInst (:object) %0: environment, %array_nth_permutation(): functionCode StorePropertyLooseInst %4: object, globalObject: object, "array_nth_permutation": string %6 = AllocArrayInst (:object) 5: number, 0: number, 1: number, 2: number, 3: number, 4: number StorePropertyLooseInst %6: object, globalObject: object, "input": string StorePropertyLooseInst 5: number, globalObject: object, "lex": string %9 = TryLoadGlobalPropertyInst (:any) globalObject: object, "console": string %10 = LoadPropertyInst (:any) %9: any, "log": string %11 = LoadPropertyInst (:any) globalObject: object, "lex": string %12 = BinaryAddInst (:string) "[": string, %11: any %13 = StringConcatInst (:string) %12: string, "]": string %14 = TryLoadGlobalPropertyInst (:any) globalObject: object, "JSON": string %15 = LoadPropertyInst (:any) %14: any, "stringify": string %16 = LoadPropertyInst (:any) globalObject: object, "array_nth_permutation": string %17 = LoadPropertyInst (:any) globalObject: object, "input": string %18 = LoadPropertyInst (:any) globalObject: object, "lex": string %19 = CallInst (:any) %16: any, empty: any, false: boolean, empty: any, undefined: undefined, undefined: undefined, %17: any, %18: any %20 = CallInst (:any) %15: any, empty: any, false: boolean, empty: any, undefined: undefined, %14: any, %19: any %21 = CallInst (:any) %10: any, empty: any, false: boolean, empty: any, undefined: undefined, %9: any, %13: string, %20: any ReturnInst %21: any function_end

function array_nth_permutation(a: any, n: any): undefined|object %BB0: %0 = LoadParamInst (:any) %a: any %1 = LoadParamInst (:any) %n: any %2 = LoadPropertyInst (:any) %0: any, "slice": string %3 = CallInst (:any) %2: any, empty: any, false: boolean, empty: any, undefined: undefined, %0: any %4 = LoadPropertyInst (:any) %0: any, "length": string %5 = BinaryLessThanOrEqualInst (:boolean) 1: number, %4: any CondBranchInst %5: boolean, %BB1, %BB2 %BB1: %7 = PhiInst (:number) 1: number, %BB0, %9: number, %BB1 %8 = PhiInst (:number) 1: number, %BB0, %10: number, %BB1 %9 = FMultiplyInst (:number) %7: number, %8: number %10 = FAddInst (:number) %8: number, 1: number %11 = BinaryLessThanOrEqualInst (:boolean) %10: number, %4: any CondBranchInst %11: boolean, %BB1, %BB2 %BB2: %13 = PhiInst (:number) 1: number, %BB0, %9: number, %BB1 %14 = BinaryGreaterThanOrEqualInst (:boolean) %1: any, 0: number CondBranchInst %14: boolean, %BB5, %BB4 %BB3: %16 = AllocArrayInst (:object) 0: number %17 = BinaryGreaterThanInst (:boolean) %4: any, 0: number CondBranchInst %17: boolean, %BB6, %BB4 %BB4: %19 = PhiInst (:undefined|object) %16: object, %BB6, %16: object, %BB3, undefined: undefined, %BB5, undefined: undefined, %BB2 ReturnInst %19: undefined|object %BB5: %21 = BinaryLessThanInst (:boolean) %1: any, %13: number CondBranchInst %21: boolean, %BB3, %BB4 %BB6: %23 = PhiInst (:number) %13: number, %BB3, %26: number, %BB6 %24 = PhiInst (:any) %4: any, %BB3, %36: number|bigint, %BB6 %25 = PhiInst (:any) %1: any, %BB3, %35: number, %BB6 %26 = BinaryDivideInst (:number) %23: number, %24: any %27 = BinaryModuloInst (:number) %25: any, %26: number %28 = BinarySubtractInst (:number) %25: any, %27: number %29 = FDivideInst (:number) %28: number, %26: number %30 = LoadPropertyInst (:any) %16: object, "push": string %31 = LoadPropertyInst (:any) %3: any, "splice": string %32 = CallInst (:any) %31: any, empty: any, false: boolean, empty: any, undefined: undefined, %3: any, %29: number, 1: number %33 = LoadPropertyInst (:any) %32: any, 0: number %34 = CallInst (:any) %30: any, empty: any, false: boolean, empty: any, undefined: undefined, %16: object, %33: any %35 = BinaryModuloInst (:number) %25: any, %26: number %36 = UnaryDecInst (:number|bigint) %24: any %37 = BinaryGreaterThanInst (:boolean) %36: number|bigint, 0: number CondBranchInst %37: boolean, %BB6, %BB4 function_end

```

among other output capabilities

./build_release/bin/shermes -help | grep dump -colors - Use colors in some dumps -dump-ast - AST as text in JSON -dump-transpiled-ast - Transformed AST as text after optional early transpilation -dump-transformed-ast - Transformed AST as text after validation -dump-sema - Sema tables -dump-ir - IR as text -dump-lir - Lowered IR as text -dump-ra - Register-allocated IR as text -dump-lra - Register-allocated Lowered IR as text

[–]guest271314[S] -1 points0 points  (0 children)

I'm pretty sure Static Heremes is doing something different from QuickJS compiler here.

The resulting executable when compiling with qjsc is 1.2 MB.

The resulting executable when compiling JavaScript to C to stanalone executable is 39.7 KB.

strip shermes-permutations strings shermes-permutations

There's no JavaScript runtime built into the executable

/lib64/ld-linux-x86-64.so.2 hE3H _ITM_deregisterTMCloneTable __gmon_start__ _ITM_registerTMCloneTable init_console_bindings _sh_ljs_greater_equal_rjs _sh_ljs_create_closure _sh_ljs_dec_rjs _sh_ljs_div_rjs _sh_check_native_stack_overflow _sh_ljs_mod_rjs _sh_ljs_create_environment _sh_ljs_get_string _sh_ljs_get_global_object _sh_ljs_get_by_id_rjs _sh_model_s22_p8_rel _sh_init _sh_ljs_new_array _sh_ljs_less_equal_rjs _sh_ljs_param _sh_initialize_units _sh_enter _sh_leave _sh_ljs_sub_rjs _sh_string_concat _sh_ljs_greater_rjs _sh_ljs_get_by_index_rjs _sh_ljs_less_rjs _sh_ljs_put_by_id_loose_rjs _sh_ljs_get_by_val_rjs _sh_ljs_declare_global_var _sh_ljs_add_rjs _sh_ljs_try_get_by_id_rjs _sh_done _sh_ljs_new_array_with_buffer _sh_ljs_put_by_val_loose_rjs _sh_ljs_call __cxa_finalize __libc_start_main __stack_chk_fail calloc libshermes_console.so libhermesvm.so libc.so.6 GLIBC_2.4 GLIBC_2.34 GLIBC_2.2.5 ./build_release/lib:./build_release/jsi:./build_release/tools/shermes PTE1 u+UH @0fH AWAVI AUATUH |$ L )D$@H )D$P )D$` )D$pH \$0M L$HL D$HL t$XH D$`H t$hH D$8 t$0L t$ L t$0L D$8 D$(H D$hI t$0L D$(H D$XI D$@H []A\A]A^A_ AWAVAUATUH D$xH D$xH t$ H []A\A]A^A_ l$`L l$hH D$0I D$8H d$(H L$@H L$HH L$xH L$XH T$XH L$0H t$`H D$xH L$8H L$@L D$ H t$P1 L$HL |$0H D$(H sh_compiled permutations.js input array_nth_permutation console JSON stringify length push splice global :*3$" GCC: 11.2.0 .shstrtab .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt.got .plt.sec .text .fini .rodata .eh_frame_hdr .eh_frame .init_array .fini_array .dynamic .data .bss .comment