Here’s a 64-bit JIT compiler for the RPN calculator.  Each expression entered in a REPL is compiled by cc() in-memory and then called with a single instruction in exe().

You can see 64-bit  overflow:

$ gcc r.c -o r
$ ./r
>9223372036854775807 1 +
-9223372036854775808

64-bit reverse polish JIT compiler

2 thoughts on “64-bit reverse polish JIT compiler

  • 2016-10-05 at 3:11 am
    Permalink

    Problems:
    – Obfuscated code. Poorly named variables and functions. Degrades readability and understand-ability.
    – A lot of functions indicate they should return a value and don’t. User a stronger compiler warning setting to catch this.
    – Unnecessary assignment within conditional. Doing to much on one line does not improve readability.
    – mmap() is Linux only. Code doesn’t port to Windows without changes.
    – asm line is not portable. Code doesn’t port to Windows Visual C++ without changes.
    – Some compilers still don’t handle ellipses … in macros which makes this code painful to port.
    – #define abuse. No point in O, PE, CASE, R, Z macros. Degrade readability.
    – There is a preference to use comma (,) operator over just using { and }. Degrades readability.
    – Poor formatting. I’m pretty sure most people will agree that this code is hard to read.
    – Functions within a function. Unusual and some compilers will have problems with this. Leads to other portability issues.
    – m and m0 are globals. Should pass these in to make the code easier to use in a threaded environment.
    – Consider using stdint.h for types instead.

    Refactored the code to what I would expect as (somewhat) quality example of the above. I couldn’t test it because I’m on Windows and didn’t spend the time to figure out the mmap replacement. (Hopefully formatting is not lost in this post.)

    //RPN CompileInputr: E:EEf|n f:[+-*/] n:[0-9]+

    // include
    #include
    #include
    #include
    //#include

    // Types
    typedef unsigned char Byte;

    // globals
    Byte *_compiledByteBuffer = (Byte *) -1;
    Byte *_compiledByteBuffer0 = (Byte *) -1;

    // Run the CompileInputd rpn
    int64_t Run(void)
    {
    _compiledByteBuffer = _compiledByteBuffer0;
    asm(“call *%0;”::”g”(_compiledByteBuffer0):);
    }

    // Get the next character from the input.
    int64_t GetCharacter(int64_t *c)
    {
    if (*c == EOF)
    {
    exit(1);
    }

    *c = getchar();
    return *c;
    }

    // Get the next non-space character from the input.
    void GetNonSpaceCharacter(int64_t *c)
    {
    while (*c == ‘ ‘)
    {
    GetCharacter(c);
    }
    }

    // Get a number from the input.
    int64_t GetNumber(int64_t *c)
    {
    int64_t i = 0,
    k = 0;

    while (‘0’ <= *c && *c = 0)
    {
    CompiledByteBufferAppend(“\x48\xb8”);
    CompiledByteBufferAppendInt(i);
    }
    else
    {
    CompiledByteBufferAppend(“\x58\x5b”);
    switch(*c)
    {
    case ‘+’:
    CompiledByteBufferAppend(“\x48\x01\xd8”);
    break;

    case ‘-‘:
    CompiledByteBufferAppend(“\x48\x29\xd8”);
    break;

    case ‘*’:
    CompiledByteBufferAppend(“\x48\x0f\xaf\xc3”);
    break;

    case ‘/’:
    CompiledByteBufferAppend(“\x48\x99\x48\x89\xec”);
    break;

    default:
    printf(“‘lex\n”);
    fflush(stdout);
    exit(1);
    }

    GetCharacter(c);
    }

    CompiledByteBufferAppend(“\x50”);
    GetNonSpaceCharacter(c);
    }
    CompiledByteBufferAppend(“\x48\x89\xec”);
    CompiledByteBufferAppend(“\xc3”);
    }

    // ProcessInput
    void ProcessInput(void)
    {
    // Variable for character input.
    int64_t c = ‘ ‘;

    while (1)
    {
    // Display command prompt.
    printf(“>”);
    fflush(stdout);

    // Get input.
    GetCharacter(&c);

    // Quit program on EOF event.
    if (c == EOF)
    {
    break;
    }

    // Compile input.
    CompileInput(&c);

    // Display execution.
    printf(“%lld\n”, Run());
    fflush(stdout);
    }
    }

    // Main function.
    int main(int acount, char **alist)
    {
    // Make buffer for the CompileInputd code.
    // Linux only, not portable to Windows.
    _compiledByteBuffer0 =
    _compiledByteBuffer = (Byte *) mmap(NULL, 1 << 20, 7, 0x22, 0, 0);

    // Check if the buffer
    if (_compiledByteBuffer0 < 0)
    {
    perror("pe");
    exit(2);
    }

    // Process input.
    ProcessInput();

    // Missed return value.
    return 0;
    }

    Reply

Leave a Reply

Your email address will not be published.