Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

More of my philosophy about setjmp() and longjmp() and generators and coroutines..

1 view
Skip to first unread message

Amine Moulay Ramdane

unread,
Nov 23, 2021, 3:24:15 PM11/23/21
to
Hello,


More of my philosophy about setjmp() and longjmp() and generators and coroutines..

I am a white arab from Morocco, and i think i am smart since i have also
invented many scalable algorithms and algorithms..

I have just quickly implemented setjmp() and longjmp() in x64 assembler,
and after that i have just implemented quickly a good example of a generator with my setjmp() and longjmp(), look at it below, and in computer science, a generator is a routine that can be used to control the iteration behaviour of a loop. All generators are also iterators. A generator is very similar to a function that returns an array, in that a generator has parameters, can be called, and generates a sequence of values. However, instead of building an array containing all the values and returning them all at once, a generator yields the values one at a time, which requires less memory and allows the caller to get started processing the first few values immediately. In short, a generator looks like a function but behaves like an iterator. So here is my implementations in freepascal and delphi and they are working perfectly:

Here is my first unit that implement longjmp() and setjmp() and notice
how i am saving the non-volatile registers and how i am coding it in
x64 assembler:

======


{ Volatile registers: The calling program assumes registers
RAX, RCX, RDX, and R8 through R11 are volatile.
The contents of registers RBX, RSI, RDI, RBP, RSP, and
R12 through R15 are considered non-volatile. Functions return
values in RAX. }



unit JmpLib64;

{$IFDEF FPC}
{$ASMMODE intel}
{$ENDIF}
interface

type
jmp_buf = record
RBX,
RSI,
RDI,
RSP,
RBP,
RIP,
R12,
R13,
R14,
R15: UInt64;
end;

{ setjmp captures the complete task state which can later be used to perform a non-local goto using longjmp. setjmp returns 0 when it is initially called, and a non-zero value when it is returning from a call to longjmp. setjmp must be called before longjmp. }

function setjmp(out jmpb: jmp_buf): UInt64;

{ longjmp restores the task state captured by setjmp (and passed in jmpb). It then returns in such a way that setjmp appears to have returned with the value retval. setjmp must be called before longjmp. }

procedure longjmp(const jmpb: jmp_buf; retval: UInt64);
implementation

function setjmp(out jmpb: jmp_buf): UInt64; assembler;{$IFDEF FPC} nostackframe; {$ENDIF}register;
asm
{ -> RCX jmpb }
{ <- RAX Result }
MOV RDX, [RSP] // Fetch return address (RIP)
// Save task state
MOV [RCX+jmp_buf.&RBX], RBX
MOV [RCX+jmp_buf.&RSI], RSI
MOV [RCX+jmp_buf.&RDI], RDI
MOV [RCX+jmp_buf.&RSP], RSP
MOV [RCX+jmp_buf.&RBP], RBP
MOV [RCX+jmp_buf.&RIP], RDX
MOV [RCX+jmp_buf.&R12], R12
MOV [RCX+jmp_buf.&R13], R13
MOV [RCX+jmp_buf.&R14], R14
MOV [RCX+jmp_buf.&R15], R15


SUB RAX, RAX
@@1:
end;

procedure longjmp(const jmpb: jmp_buf; retval: UInt64);assembler;{$IFDEF FPC} nostackframe; {$ENDIF}register;
asm
{ -> RCX jmpb }
{ RDX retval }
{ <- RAX Result }
XCHG RDX, RCX
MOV RAX,RCX
MOV RCX, [RDX+jmp_buf.&RIP]
// Restore task state
MOV RBX, [RDX+jmp_buf.&RBX]
MOV RSI, [RDX+jmp_buf.&RSI]
MOV RDI, [RDX+jmp_buf.&RDI]
MOV RSP, [RDX+jmp_buf.&RSP]
MOV RBP, [RDX+jmp_buf.&RBP]
MOV R12, [RDX+jmp_buf.&R12]
MOV R13, [RDX+jmp_buf.&R13]
MOV R14, [RDX+jmp_buf.&R14]
MOV R15, [RDX+jmp_buf.&R15]
MOV [RSP], RCX // Restore return address (RIP)

TEST RAX, RAX // Ensure retval is <> 0
JNZ @@1
MOV RAX, 1
@@1:
end;

end.

================

And here is my example of a generator with my longjmp() and setjmp():


{ In computer science, a generator is a routine that can be used to control the iteration behaviour of a loop. All generators are also iterators. A generator is very similar to a function that returns an array, in that a generator has parameters, can be called, and generates a sequence of values. However, instead of building an array containing all the values and returning them all at once, a generator yields the values one at a time, which requires less memory and allows the caller to get started processing the first few values immediately. In short, a generator looks like a function but behaves like an iterator. }

program test_generator;

{$APPTYPE CONSOLE}

uses
JmpLib64;

type PtrInt = ^Integer;

var
childtask,maintask: jmp_buf;
myarr1: array of integer;
i,a:integer;
Ptr1:PtrInt;

function generator(var myarr:array of integer):integer;

var i1:integer;
val:integer;
ptr:PtrInt;
begin


i1:=0;

val:= setjmp(childtask);

i1:=val-1;

if val=0 then
begin
new(ptr);
ptr^:=myarr1[i1];
longjmp(maintask,uint64(ptr));
end;

if val=10
then
begin
writeln('Exiting child..');
exit;
end;

inc(i1);
new(ptr);
ptr^:=myarr1[i1];
longjmp(maintask,uint64(ptr));
end;

begin

setlength(myarr1,10);

for i:=0 to 9
do myarr1[i]:=i;

uint64(ptr1):=setjmp(maintask);

if ptr1=nil then generator(myarr1);

a:=ptr1^;
dispose(ptr1);

if (a<=length(myarr1))
then
begin
if a=length(myarr1)
then longjmp(childtask,a+1)
else
begin
writeln('Value retuned by generator is: ',a);
longjmp(childtask,a+1);
end;
end;

setlength(myarr1,0);

end.

====


Thank you,
Amine Moulay Ramdane.


0 new messages