diff --git a/src/Bytecode/Instruction/execute.c b/src/Bytecode/Instruction/execute.c index f7c0113..5f4c25d 100644 --- a/src/Bytecode/Instruction/execute.c +++ b/src/Bytecode/Instruction/execute.c @@ -5,6 +5,7 @@ #include #include #include +#include #define HEAP_GET(heap, idx) (&(heap)->heap[(idx)]) #define HEAP_SET(heap, idx, val) ((heap)->heap[(idx)] = (val)) @@ -40,6 +41,17 @@ static void printValue(GroundBytecodeValue* val) { } } +static ffi_type* ffiTypeFromGroundType(GroundType* type) { + switch (type->type) { + case GroundType_Int: return &ffi_type_sint64; + case GroundType_Double: return &ffi_type_double; + case GroundType_Char: return &ffi_type_schar; + case GroundType_Bool: return &ffi_type_uint8; + case GroundType_String: return &ffi_type_pointer; + default: return &ffi_type_pointer; // FIXME implement stuff for everything else + } +} + struct GroundExecutionResult _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction, GroundBytecodeHeap* heap) { static const void* jumpTable[] = { @@ -757,7 +769,100 @@ struct GroundExecutionResult _GroundBytecodeInstructionExecute(GroundBytecodeIns GroundBytecodeFunction* function = &HEAP_GET(heap, instruction->args.at[0])->as.Function; if (function->isNativeFunction) { - // TODO implement calling native functions + + // Ensure we have the right amount and types of arguments first + if (function->args.count != instruction->args.len - 2) { + Ground.Log.Error("incorrect amount of arguments for native function in Ground.Bytecode.Instruction.execute"); + Ground.Flags.error = true; + return CONTINUE; + } + + ffi_type* argTypes[function->args.count]; + void* args[function->args.count]; + + for (GroundSize i = 0; i < function->args.count; i++) { + if (function->args.at[i].as.type.type != HEAP_GET(heap, instruction->args.at[i+1])->type.type) { + Ground.Log.Error("incorrect type of argument for native function in Ground.Bytecode.Instruction.execute"); + Ground.Flags.error = true; + return CONTINUE; + } + argTypes[i] = ffiTypeFromGroundType(&function->args.at[i].as.type); + switch (HEAP_GET(heap, instruction->args.at[i+1])->type.type) { + case GroundType_Int: { + args[i] = &HEAP_GET(heap, instruction->args.at[i+1])->as.Int; + break; + } + case GroundType_Double: { + args[i] = &HEAP_GET(heap, instruction->args.at[i+1])->as.Double; + break; + } + case GroundType_Char: { + args[i] = &HEAP_GET(heap, instruction->args.at[i+1])->as.Char; + break; + } + case GroundType_Bool: { + args[i] = &HEAP_GET(heap, instruction->args.at[i+1])->as.Bool; + break; + } + case GroundType_String: { + args[i] = &HEAP_GET(heap, instruction->args.at[i+1])->as.String.cstr; + break; + } + default: { + // FIXME implement non-basic types + args[i] = HEAP_GET(heap, instruction->args.at[i+1]); + break; + } + } + } + + ffi_cif cif; + ffi_status status = ffi_prep_cif( + &cif, FFI_DEFAULT_ABI, function->args.count, ffiTypeFromGroundType(function->returnType), argTypes + ); + + if (status != FFI_OK) { + Ground.Log.Error("ffi CIF preperation failed in Ground.Bytecode.Instruction.execute"); + Ground.Flags.error = true; + return CONTINUE; + } + + union { + GroundInt Int; + GroundDouble Double; + GroundChar Char; + GroundBool Bool; + char* String; + // TODO more stuff + } result; + + ffi_call(&cif, function->program.native, &result, args); + + // Put return value into the scope + switch (function->returnType->type) { + case GroundType_Int: { + HEAP_SET(heap, instruction->args.at[instruction->args.len - 1], Ground.New.BytecodeValue(Ground.New.Value.Int(result.Int))); + break; + } + case GroundType_Char: { + HEAP_SET(heap, instruction->args.at[instruction->args.len - 1], Ground.New.BytecodeValue(Ground.New.Value.Char(result.Char))); + break; + } + case GroundType_Double: { + HEAP_SET(heap, instruction->args.at[instruction->args.len - 1], Ground.New.BytecodeValue(Ground.New.Value.Double(result.Double))); + break; + } + case GroundType_Bool: { + HEAP_SET(heap, instruction->args.at[instruction->args.len - 1], Ground.New.BytecodeValue(Ground.New.Value.Bool(result.Bool))); + break; + } + case GroundType_String: { + HEAP_SET(heap, instruction->args.at[instruction->args.len - 1], Ground.New.BytecodeValue(Ground.New.Value.String(Ground.New.String(result.String)))); + break; + } + default: break; // TODO more types + } + return CONTINUE; } @@ -833,7 +938,7 @@ struct GroundExecutionResult _GroundBytecodeInstructionExecute(GroundBytecodeIns if (Ground.Flags.error) { return CONTINUE; } - void* function = Ground.FFI.getFunction(handle, HEAP_GET(heap, instruction->args.at[0])->as.String.cstr); + void* function = Ground.FFI.getFunction(handle, HEAP_GET(heap, instruction->args.at[1])->as.String.cstr); if (Ground.Flags.error) { return CONTINUE; } @@ -882,7 +987,7 @@ struct GroundExecutionResult _GroundBytecodeInstructionExecute(GroundBytecodeIns break; } case GroundType_CoreType: { - bf.args.at[i].as.type.type = HEAP_GET(heap, instruction->args.at[3])->as.CoreType; + bf.args.at[i].as.type.type = HEAP_GET(heap, instruction->args.at[i + 4])->as.CoreType; break; } default: { @@ -897,7 +1002,7 @@ struct GroundExecutionResult _GroundBytecodeInstructionExecute(GroundBytecodeIns .as.Function = bf }; - HEAP_SET(heap, instruction->args.at[3], val); + HEAP_SET(heap, instruction->args.at[2], val); return CONTINUE; }