[go: nahoru, domu]

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

Implement Global Instructions #89

Merged
merged 1 commit into from
May 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions src/jit/Backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@

#include "runtime/JITExec.h"
#include "runtime/Memory.h"
#include "runtime/Global.h"
#include "jit/Compiler.h"
#include "util/MathOperation.h"
#include "runtime/Instance.h"

#include <math.h>
#include <map>
Expand Down Expand Up @@ -84,6 +86,11 @@ class JITFieldAccessor {
{
return offsetof(Memory, m_buffer);
}

static sljit_sw globalValueOffset()
{
return offsetof(Global, m_value) + offsetof(Value, m_i32);
}
};

class SlowCase {
Expand Down Expand Up @@ -120,6 +127,8 @@ struct CompileContext {
, trapLabel(nullptr)
, memoryTrapLabel(nullptr)
{
sljit_sw offset = Instance::alignedSize();
globalsStart = offset + sizeof(void*) * compiler->module()->numberOfMemoryTypes();
}

static CompileContext* get(sljit_compiler* compiler)
Expand All @@ -136,6 +145,7 @@ struct CompileContext {
sljit_label* memoryTrapLabel;
sljit_label* returnToLabel;
sljit_uw branchTableOffset;
sljit_sw globalsStart;
std::vector<TrapBlock> trapBlocks;
std::vector<SlowCase*> slowCases;
std::vector<sljit_jump*> earlyReturns;
Expand Down Expand Up @@ -424,6 +434,42 @@ static void emitMove32(sljit_compiler* compiler, Instruction* instr)
sljit_emit_op1(compiler, SLJIT_MOV32, dst.arg, dst.argw, src.arg, src.argw);
}

static void emitGlobalGet32(sljit_compiler* compiler, Instruction* instr)
{
CompileContext* context = CompileContext::get(compiler);
Operand* operands = instr->operands();
JITArg dst;

operandToArg(operands, dst);

GlobalGet32* globalGet = reinterpret_cast<GlobalGet32*>(instr->byteCode());

sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(kContextReg), OffsetOfContextField(instance));
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R0), context->globalsStart + globalGet->index() * sizeof(void*));
sljit_emit_op1(compiler, SLJIT_MOV, dst.arg, dst.argw, SLJIT_MEM1(SLJIT_R0), JITFieldAccessor::globalValueOffset());
}

static void emitGlobalSet32(sljit_compiler* compiler, Instruction* instr)
{
CompileContext* context = CompileContext::get(compiler);
Operand* operands = instr->operands();
JITArg src;

operandToArg(operands, src);

GlobalSet32* globalSet = reinterpret_cast<GlobalSet32*>(instr->byteCode());

if (SLJIT_IS_MEM(src.arg)) {
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R1, 0, src.arg, src.argw);
kulcsaradam marked this conversation as resolved.
Show resolved Hide resolved
src.arg = SLJIT_R1;
src.argw = 0;
}

sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(kContextReg), OffsetOfContextField(instance));
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R0), context->globalsStart + globalSet->index() * sizeof(void*));
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_MEM1(SLJIT_R0), JITFieldAccessor::globalValueOffset(), src.arg, src.argw);
kulcsaradam marked this conversation as resolved.
Show resolved Hide resolved
}

JITModule::~JITModule()
{
delete m_instanceConstData->trapHandlers;
Expand Down Expand Up @@ -570,6 +616,22 @@ JITModule* JITCompiler::compile()
emitMemory(m_compiler, item->asInstruction());
break;
}
case Instruction::GlobalGet: {
if (item->asInstruction()->opcode() == GlobalGet32Opcode) {
emitGlobalGet32(m_compiler, item->asInstruction());
} else {
emitGlobalGet64(m_compiler, item->asInstruction());
}
break;
}
case Instruction::GlobalSet: {
if (item->asInstruction()->opcode() == GlobalSet32Opcode) {
emitGlobalSet32(m_compiler, item->asInstruction());
} else {
emitGlobalSet64(m_compiler, item->asInstruction());
}
break;
}
case Instruction::Move: {
if (item->asInstruction()->opcode() == Move32Opcode) {
emitMove32(m_compiler, item->asInstruction());
Expand Down
42 changes: 41 additions & 1 deletion src/jit/ByteCodeParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,46 @@ static void createInstructionList(JITCompiler* compiler, ModuleFunction* functio
operands[1].offset = STACK_OFFSET(move64->dstOffset());
break;
}
case GlobalGet32Opcode: {
Instruction* instr = compiler->append(byteCode, Instruction::GlobalGet, GlobalGet32Opcode, 0, 1);

GlobalGet32* globalGet32 = reinterpret_cast<GlobalGet32*>(byteCode);
Operand* operands = instr->operands();

operands[0].item = nullptr;
operands[0].offset = STACK_OFFSET(globalGet32->dstOffset());
break;
}
case GlobalGet64Opcode: {
Instruction* instr = compiler->append(byteCode, Instruction::GlobalGet, GlobalGet64Opcode, 0, 1);

GlobalGet64* globalGet64 = reinterpret_cast<GlobalGet64*>(byteCode);
Operand* operands = instr->operands();

operands[0].item = nullptr;
operands[0].offset = STACK_OFFSET(globalGet64->dstOffset());
break;
}
case GlobalSet32Opcode: {
Instruction* instr = compiler->append(byteCode, Instruction::GlobalSet, GlobalSet32Opcode, 1, 0);

GlobalSet32* globalSet32 = reinterpret_cast<GlobalSet32*>(byteCode);
Operand* operands = instr->operands();

operands[0].item = nullptr;
operands[0].offset = STACK_OFFSET(globalSet32->srcOffset());
break;
}
case GlobalSet64Opcode: {
Instruction* instr = compiler->append(byteCode, Instruction::GlobalSet, GlobalSet64Opcode, 1, 0);

GlobalSet64* globalSet64 = reinterpret_cast<GlobalSet64*>(byteCode);
Operand* operands = instr->operands();

operands[0].item = nullptr;
operands[0].offset = STACK_OFFSET(globalSet64->srcOffset());
break;
}
case EndOpcode: {
uint32_t size = function->functionType()->result().size();

Expand Down Expand Up @@ -621,7 +661,7 @@ void Module::jitCompile(int verboseLevel)
return;
}

JITCompiler compiler(verboseLevel);
JITCompiler compiler(this, verboseLevel);

for (size_t i = 0; i < functionCount; i++) {
if (verboseLevel >= 1) {
Expand Down
9 changes: 8 additions & 1 deletion src/jit/Compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ class InstructionListItem {
Memory,
// Move operation. (e.g. Move32, Move64)
Move,
// GlobalGet operation (e.g. GlobalGet32, GlobalGet64)
GlobalGet,
// GlobalSet operation (e.g. GlobalSet32, GlobalSet64)
GlobalSet,
};

virtual ~InstructionListItem() {}
Expand Down Expand Up @@ -397,12 +401,13 @@ class JITCompiler {
public:
static const uint32_t kHasCondMov = 1 << 0;

JITCompiler(int verboseLevel)
JITCompiler(Module* module, int verboseLevel)
: m_first(nullptr)
, m_last(nullptr)
, m_functionListFirst(nullptr)
, m_functionListLast(nullptr)
, m_compiler(nullptr)
, m_module(module)
, m_branchTableSize(0)
, m_verboseLevel(verboseLevel)
, m_options(0)
Expand All @@ -416,6 +421,7 @@ class JITCompiler {
releaseFunctionList();
}

Module* module() { return m_module; }
int verboseLevel() { return m_verboseLevel; }
uint32_t options() { return m_options; }
InstructionListItem* first() { return m_first; }
Expand Down Expand Up @@ -484,6 +490,7 @@ class JITCompiler {
InstructionListItem* m_functionListLast;

sljit_compiler* m_compiler;
Module* m_module;
size_t m_branchTableSize;
int m_verboseLevel;
uint32_t m_options;
Expand Down
41 changes: 41 additions & 0 deletions src/jit/IntMath32Inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1159,3 +1159,44 @@ static void emitMove64(sljit_compiler* compiler, Instruction* instr)
sljit_emit_op1(compiler, SLJIT_MOV, dst.arg1, dst.arg1w, src.arg1, src.arg1w);
sljit_emit_op1(compiler, SLJIT_MOV, dst.arg2, dst.arg2w, src.arg2, src.arg2w);
}

static void emitGlobalGet64(sljit_compiler* compiler, Instruction* instr)
{
CompileContext* context = CompileContext::get(compiler);
Operand* operands = instr->operands();
JITArgPair dst;

operandToArgPair(operands, dst);

GlobalGet64* globalGet = reinterpret_cast<GlobalGet64*>(instr->byteCode());

sljit_emit_op1(compiler, SLJIT_MOV_P, SLJIT_R0, 0, SLJIT_MEM1(kContextReg), OffsetOfContextField(instance));
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R0), context->globalsStart + globalGet->index() * sizeof(void*));
sljit_emit_op1(compiler, SLJIT_MOV, dst.arg1, dst.arg1w, SLJIT_MEM1(SLJIT_R0), JITFieldAccessor::globalValueOffset() + WORD_LOW_OFFSET);
sljit_emit_op1(compiler, SLJIT_MOV, dst.arg2, dst.arg2w, SLJIT_MEM1(SLJIT_R0), JITFieldAccessor::globalValueOffset() + WORD_HIGH_OFFSET);
}

static void emitGlobalSet64(sljit_compiler* compiler, Instruction* instr)
{
CompileContext* context = CompileContext::get(compiler);
Operand* operands = instr->operands();
JITArgPair src;

operandToArgPair(operands, src);

GlobalSet32* globalSet = reinterpret_cast<GlobalSet32*>(instr->byteCode());

if (SLJIT_IS_MEM(src.arg1)) {
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R1, 0, src.arg1, src.arg1w);
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R2, 0, src.arg2, src.arg2w);
src.arg1 = SLJIT_R1;
src.arg1w = 0;
src.arg2 = SLJIT_R2;
src.arg2w = 0;
}

sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(kContextReg), OffsetOfContextField(instance));
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R0), context->globalsStart + globalSet->index() * sizeof(void*));
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_MEM1(SLJIT_R0), JITFieldAccessor::globalValueOffset() + WORD_LOW_OFFSET, src.arg1, src.arg1w);
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_MEM1(SLJIT_R0), JITFieldAccessor::globalValueOffset() + WORD_HIGH_OFFSET, src.arg2, src.arg2w);
}
36 changes: 36 additions & 0 deletions src/jit/IntMath64Inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -561,3 +561,39 @@ static void emitMove64(sljit_compiler* compiler, Instruction* instr)

sljit_emit_op1(compiler, SLJIT_MOV, dst.arg, dst.argw, src.arg, src.argw);
}

static void emitGlobalGet64(sljit_compiler* compiler, Instruction* instr)
{
CompileContext* context = CompileContext::get(compiler);
Operand* operands = instr->operands();
JITArg dst;

operandToArg(operands, dst);

GlobalGet64* globalGet = reinterpret_cast<GlobalGet64*>(instr->byteCode());

sljit_emit_op1(compiler, SLJIT_MOV_P, SLJIT_R0, 0, SLJIT_MEM1(kContextReg), OffsetOfContextField(instance));
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R0), context->globalsStart + globalGet->index() * sizeof(void*));
sljit_emit_op1(compiler, SLJIT_MOV, dst.arg, dst.argw, SLJIT_MEM1(SLJIT_R0), JITFieldAccessor::globalValueOffset());
}

static void emitGlobalSet64(sljit_compiler* compiler, Instruction* instr)
{
CompileContext* context = CompileContext::get(compiler);
Operand* operands = instr->operands();
JITArg src;

operandToArg(operands, src);

GlobalSet64* globalSet = reinterpret_cast<GlobalSet64*>(instr->byteCode());

if (SLJIT_IS_MEM(src.arg)) {
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R1, 0, src.arg, src.argw);
src.arg = SLJIT_R1;
src.argw = 0;
}

sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(kContextReg), OffsetOfContextField(instance));
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R0), context->globalsStart + globalSet->index() * sizeof(void*));
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_MEM1(SLJIT_R0), JITFieldAccessor::globalValueOffset(), src.arg, src.argw);
kulcsaradam marked this conversation as resolved.
Show resolved Hide resolved
}
2 changes: 2 additions & 0 deletions src/runtime/Global.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
namespace Walrus {

class Global : public Extern {
friend class JITFieldAccessor;

public:
static Global* createGlobal(Store* store, const Value& value)
{
Expand Down
10 changes: 5 additions & 5 deletions src/runtime/Instance.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ class Instance : public Object {
return true;
}

static size_t alignedSize()
{
return (sizeof(Instance) + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
}

Module* module() const { return m_module; }

Function* function(uint32_t index) const { return m_functions[index]; }
Expand Down Expand Up @@ -124,11 +129,6 @@ class Instance : public Object {
Instance(Module* module);
~Instance() {}

static size_t alignedSize()
{
return (sizeof(Instance) + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
}

Module* m_module;

// The initialization in Module::instantiate and Instance::newInstance must follow this order.
Expand Down
2 changes: 2 additions & 0 deletions src/runtime/Value.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ size_t stackAllocatedSize()
}

class Value {
friend class JITFieldAccessor;

public:
// https://webassembly.github.io/spec/core/syntax/types.html

Expand Down
56 changes: 56 additions & 0 deletions test/jit/global.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
(module

(global $a (mut i32) (i32.const 1))
(global $b (mut i64) (i64.const 2))
(global (;2;) i32 (i32.const 3))
(global (;3;) i64 (i64.const 4))
(global $c (mut f32) (f32.const 5.5))
(global $d (mut f64) (f64.const 6.6))
(global (;6;) f32 (f32.const 7.7))
(global (;7;) f64 (f64.const 8.8))

(func (export "global_a") (result i32) global.get $a )
(func (export "global_b") (result i64) global.get $b )
(func (export "global_c") (result f32) global.get $c )
(func (export "global_d") (result f64) global.get $d )

(func (export "global_2") (result i32) global.get 2 )
(func (export "global_3") (result i64) global.get 3 )
(func (export "global_6") (result f32) global.get 6 )
(func (export "global_7") (result f64) global.get 7 )

(func (export "global_set_a") (param i32) (global.set $a (local.get 0)) )
(func (export "global_set_b") (param i64) (global.set $b (local.get 0)) )
(func (export "global_set_c") (param f32) (global.set $c (local.get 0)) )
(func (export "global_set_d") (param f64) (global.set $d (local.get 0)) )

(global $r externref (ref.null extern))
(global $mr externref (ref.null extern))
(global $fr funcref (ref.null func))

(func (export "global_r") (result externref) global.get $r )
(func (export "global_mr") (result externref) global.get $mr )
(func (export "global_fr") (result funcref) global.get $fr )

)

(assert_return (invoke "global_a" ) (i32.const 1))
(assert_return (invoke "global_b" ) (i64.const 2))
(assert_return (invoke "global_c" ) (f32.const 5.5))
(assert_return (invoke "global_d" ) (f64.const 6.6))
(assert_return (invoke "global_2" ) (i32.const 3))
(assert_return (invoke "global_3" ) (i64.const 4))
(assert_return (invoke "global_6" ) (f32.const 7.7))
(assert_return (invoke "global_7" ) (f64.const 8.8))
(assert_return (invoke "global_set_a" (i32.const 11)))
(assert_return (invoke "global_a" ) (i32.const 11))
(assert_return (invoke "global_set_b" (i64.const 22)))
(assert_return (invoke "global_b" ) (i64.const 22))
(assert_return (invoke "global_set_c" (f32.const 55.5)))
(assert_return (invoke "global_c" ) (f32.const 55.5))
(assert_return (invoke "global_set_d" (f64.const 66.6)))
(assert_return (invoke "global_d" ) (f64.const 66.6))

(assert_return (invoke "global_r") (ref.null extern))
(assert_return (invoke "global_mr") (ref.null extern))
(assert_return (invoke "global_fr") ( ref.null func))