Start working on CALLMETHOD
This commit is contained in:
@@ -888,6 +888,137 @@ struct GroundExecutionResult _GroundBytecodeInstructionExecute(GroundBytecodeIns
|
||||
return CONTINUE;
|
||||
}
|
||||
CALLMETHOD: {
|
||||
// bytecode: object_offset, field0_offset, ..., fieldN_offset, method_offset, arg0_offset, ..., argM_offset, output_offset
|
||||
GroundSize len = instruction->args.len;
|
||||
|
||||
// Navigate the object through field path to find the containing object and method
|
||||
GroundBytecodeValue* current = HEAP_GET(heap, instruction->args.at[0]);
|
||||
|
||||
// Walk the field path to find the containing object
|
||||
GroundSize fieldPairsCount = 0;
|
||||
for (GroundSize fi = 1; fi < len - 1; fi++) {
|
||||
if (current->type.type != GroundType_Object) break;
|
||||
GroundBytecodeValue* next = ¤t->as.Object.values[instruction->args.at[fi]];
|
||||
if (next->type.type == GroundType_Function) {
|
||||
// This is the method
|
||||
break;
|
||||
}
|
||||
current = next;
|
||||
fieldPairsCount++;
|
||||
}
|
||||
|
||||
// The method is at index 1 + fieldPairsCount
|
||||
GroundSize methodFieldIdx = 1 + fieldPairsCount;
|
||||
GroundSize methodArgCount = len - methodFieldIdx - 2; // subtract method and output
|
||||
|
||||
if (current->type.type != GroundType_Object) {
|
||||
Ground.Log.Error("CALLMETHOD on non-object value in Ground.Bytecode.Instruction.execute");
|
||||
Ground.Flags.error = true;
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
GroundBytecodeFunction* method = ¤t->as.Object.values[instruction->args.at[methodFieldIdx]].as.Function;
|
||||
|
||||
if (method->isNativeFunction) {
|
||||
// Native method handling (same as CALL native path but with self appended)
|
||||
ffi_type* argTypes[methodArgCount + 1];
|
||||
void* args[methodArgCount + 1];
|
||||
|
||||
// Self is the first arg for native methods
|
||||
argTypes[0] = ffiTypeFromGroundType(&(GroundType){.type = GroundType_Object});
|
||||
args[0] = current;
|
||||
|
||||
for (GroundSize i = 0; i < methodArgCount; i++) {
|
||||
GroundBytecodeValue* val = HEAP_GET(heap, instruction->args.at[methodFieldIdx + 1 + i]);
|
||||
argTypes[i + 1] = ffiTypeFromGroundType(&val->type);
|
||||
switch (val->type.type) {
|
||||
case GroundType_Int: args[i + 1] = &val->as.Int; break;
|
||||
case GroundType_Double: args[i + 1] = &val->as.Double; break;
|
||||
case GroundType_Char: args[i + 1] = &val->as.Char; break;
|
||||
case GroundType_Bool: args[i + 1] = &val->as.Bool; break;
|
||||
case GroundType_String: args[i + 1] = &val->as.String.cstr; break;
|
||||
default: args[i + 1] = val; break;
|
||||
}
|
||||
}
|
||||
|
||||
ffi_cif cif;
|
||||
ffi_status status = ffi_prep_cif(
|
||||
&cif, FFI_DEFAULT_ABI, methodArgCount + 1,
|
||||
ffiTypeFromGroundType(method->returnType), argTypes
|
||||
);
|
||||
|
||||
if (status != FFI_OK) {
|
||||
Ground.Log.Error("ffi CIF preparation failed in Ground.Bytecode.Instruction.execute");
|
||||
Ground.Flags.error = true;
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
union {
|
||||
GroundInt Int;
|
||||
GroundDouble Double;
|
||||
GroundChar Char;
|
||||
GroundBool Bool;
|
||||
char* String;
|
||||
} result;
|
||||
|
||||
ffi_call(&cif, method->program.native, &result, args);
|
||||
|
||||
switch (method->returnType->type) {
|
||||
case GroundType_Int: HEAP_SET(heap, instruction->args.at[len - 1], Ground.New.BytecodeValue(Ground.New.Value.Int(result.Int))); break;
|
||||
case GroundType_Char: HEAP_SET(heap, instruction->args.at[len - 1], Ground.New.BytecodeValue(Ground.New.Value.Char(result.Char))); break;
|
||||
case GroundType_Double: HEAP_SET(heap, instruction->args.at[len - 1], Ground.New.BytecodeValue(Ground.New.Value.Double(result.Double))); break;
|
||||
case GroundType_Bool: HEAP_SET(heap, instruction->args.at[len - 1], Ground.New.BytecodeValue(Ground.New.Value.Bool(result.Bool))); break;
|
||||
case GroundType_String: HEAP_SET(heap, instruction->args.at[len - 1], Ground.New.BytecodeValue(Ground.New.Value.String(Ground.New.String(result.String)))); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
if (method->closure == NULL) {
|
||||
Ground.Log.Error("unexpected NULL closure in Ground.Bytecode.Instruction.execute");
|
||||
Ground.Flags.error = true;
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
// Total args for method: methodArgCount explicit + 1 self
|
||||
GroundSize totalArgs = methodArgCount + 1;
|
||||
GroundSize heapSize = totalArgs + method->closure->len;
|
||||
|
||||
GroundBytecodeHeap newHeap = { malloc(sizeof(GroundBytecodeValue) * heapSize), heapSize, heapSize };
|
||||
if (newHeap.heap == NULL) {
|
||||
Ground.Log.Error("malloc failed in Ground.Bytecode.Instruction.execute");
|
||||
Ground.Flags.error = true;
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
// Load explicit method arguments into the heap
|
||||
for (GroundSize i = 0; i < methodArgCount; i++) {
|
||||
newHeap.heap[i] = Ground.Copy.BytecodeValue(HEAP_GET(heap, instruction->args.at[methodFieldIdx + 1 + i]));
|
||||
}
|
||||
|
||||
// Self (the containing object) is the last argument
|
||||
newHeap.heap[methodArgCount] = Ground.Copy.BytecodeValue(current);
|
||||
|
||||
// Copy closure variables after arguments
|
||||
for (GroundSize i = totalArgs; i < newHeap.len; i++) {
|
||||
newHeap.heap[i] = Ground.Copy.BytecodeValue(&method->closure->heap[i - totalArgs]);
|
||||
}
|
||||
|
||||
// Execute the method
|
||||
GroundBytecodeValue result = Ground.Bytecode.Program.execute(method->program.ground, &newHeap);
|
||||
|
||||
GroundBytecodeValue resultCopy = Ground.Copy.BytecodeValue(&result);
|
||||
|
||||
// Clean up
|
||||
for (GroundSize i = 0; i < newHeap.len; i++) {
|
||||
Ground.Free.BytecodeValue(&newHeap.heap[i]);
|
||||
}
|
||||
free(newHeap.heap);
|
||||
|
||||
// Store the result
|
||||
HEAP_SET(heap, instruction->args.at[len - 1], resultCopy);
|
||||
|
||||
return CONTINUE;
|
||||
}
|
||||
STRUCT: {
|
||||
|
||||
Reference in New Issue
Block a user