Files
ark_runtime_core/docs/interpreter-language-extensions.md
T
wanyanglan 14c9021696 add ark runtime_core
Signed-off-by: wanyanglan <wanyanglan1@huawei.com>
Change-Id: I2564094cef9c6c41263e37faf9ffbbec14223dc7
2021-09-05 20:53:43 +08:00

3.0 KiB

Interpreter Language Specific Extension

Builtins mechanism allows for optimization of bytecode for a particular language by introducing language-specific builtins. Builtins should be added to the interpreter main loop on build time.

Interpreter main loop

The interpreter main loop is implemented using the computed goto approach:

template <...>
void ExecuteImpl(ManagedThread* thread, const uint8_t *pc, Frame* frame) {
    static std::array<const void*, NUM_OPS> dispatch_table{
        &&HANDLE_OP1,
        &&HANDLE_OP2,
        ...
    }

    ...

    InstructionHandlerState<...> state(thread, pc, frame);

    DISPATCH(...);

HANDLE_OP1: {
        InstructionHandler<...> handler(&state);
        handler.template HandleOp1<Format1>();
        DISPATCH(...);
    }

HANDLE_OP2: {
        InstructionHandler<...> handler(&state);
        handler.template HandleOp2<Format2>();
        DISPATCH(...);
    }

    ...
}

It uses one dispatch table for public ISA opcodes and builtins.

The interpreter uses InstructionHandlerState objects to encapsulate internal state that contains current thread, pc, frame, etc. It's used to construct an InstructionHandler instance that implements the Handle<Opcode> method with opcode implementation. We create a new instance for each opcode.

InstructionHandler contains implementation of all public ISA opcodes and common builtins. It extends the InstructionHandlerBase class with helper methods that doesn't contains any opcode implementation.

Language specific instructions

To add a language specific builtin, we need to add a new class that will extend InstructionHandlerBase. For example:

template <...>
class ECMAInstructionHandler : public InstructionHandlerBase<...> {
public:
    ALWAYS_INLINE inline ECMAInstructionHandler(InstructionHandlerState<enable_profiling>* state)
        : InstructionHandlerBase<...>(state) {}

    template <Format format>
    ALWAYS_INLINE void HandleEcmaOp1() {
        ...
        this->template MoveToNextInst<format, false>();
    }
}

Use the added class in the interpreter main loop:

template <...>
void ExecuteImpl(ManagedThread* thread, const uint8_t *pc, Frame* frame) {
    static std::array<const void*, NUM_OPS> dispatch_table{
        &&HANDLE_OP1,
        ...
        &&HANDLE_ECMA_OP1,
        ...
    }

    ...

    InstructionHandlerState<...> state(thread, pc, frame);

    DISPATCH(...);

HANDLE_OP1: {
        InstructionHandler<...> handler(&state);
        handler.template HandleOp1<Format1>();
        DISPATCH(...);
    }

    ...

HANDLE_ECMA_OP1: {
        ECMAInstructionHandler<...> handler(&state);
        handler.template HandleEcmaOp1<Format2>();
        DISPATCH(...);
    }

    ...
}

ECMAInstructionHandler should be located in runtime/ecmascript/interpreter directory and included to interpreter-inl.h.