Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any way to declare a const reference to a method at compile-time?

Tags:

delphi

I'm working on a script interpreter, that I've managed to get to a working state. It has a compiler that parses the script and generates bytecode, and a VM that executes the bytecode.

At the heart of the interpreter is a loop with a giant case statement that looks something like this:

case CurrentOpcode.Operation of
  OP_1: DoOp1(CurrentOpcode);
  OP_2: DoOp2(CurrentOpcode);
  ...
  OP_N: DoOpN(CurrentOpcode);
end;

Profiling tells me that, for whatever reason, my script execution is spending a significant amount of time inside that case statement, which seems strange to me, so I'm looking for a way to optimize it. The obvious solution, since all the operation functions basically have the same signature, is to create an array of method pointers indexed by the opcode's Operation value. But Operation is declared as an enum, and it would be nice to be able to declare this as a const array so that if I add more opcodes in the future, the compiler can remind me to update the array.

Since a method pointer stores runtime state, (the Self reference to the object it's running against,) I can't create a const array of method pointers. (Nor would this be a good idea anyway, as it's quite likely that I'll end up with more than one script running at the same time.) But methods are just syntactic sugar anyway. Something like:

procedure TMyObject.DoSomething(x, y: integer);

really means:

procedure TMyObject_DoSomething(Self: TMyObject; x, y: integer);

So I should be able to declare a function pointer type in the latter form and assign it that way, and then I'd just have to explicitly pass Self as the first parameter when I invoke it. But the compiler doesn't like that.

type TOpcodeProc = procedure (Self: TScriptVM; Opcode: TOpcode);
const OPCODE: TOpcodeProc = TScriptVM.DoOp1;

[DCC Error]: E2009 Incompatible types: 'regular procedure and method pointer'

I've tried different variations on this to try to get it to compile, but they all give errors. Is there any way to get this to compile?

like image 746
Mason Wheeler Avatar asked Feb 05 '13 23:02

Mason Wheeler


1 Answers

Declaration:

const
  OPCODE: array[TOperation] of Pointer = (
    @TScriptVM.DoOp1, 
    @TScriptVM.DoOp2, 
    ... 
    @TScriptVM.DoOpN
  );

Call:

TOpcodeProc(OPCODE[CurrentOpcode.Operation])(Self, CurrentOpcode);

More cool stuff:

var
  OpCodeProcs: array[TOperation] of TOpCodeProc absolute OPCODE;

Much nicer syntax to call the method:

OpCodeProcs[CurrentOpcode.Operation](Self, CurrentOpcode);

Good thing is because of the absolute to the constant the compiler prevents you from assigning something to the OpCodeProcs variable!

like image 197
Stefan Glienke Avatar answered Sep 29 '22 12:09

Stefan Glienke