Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.programming > #14233

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

Newsgroups comp.programming
Date 2021-11-23 12:44 -0800
Message-ID <51bda776-99cb-41af-a952-790955412b2dn@googlegroups.com> (permalink)
Subject More of my philosophy about coroutines and about setjmp() and longjmp()..
From Amine Moulay Ramdane <aminer68@gmail.com>

Show all headers | View raw


Hello,



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

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

I think i am smart, and i will say that with setjmp() and longjmp() 
you can implement a generator or the like, but you can not implement coroutines with just setjmp() and longjmp(), and so that to understand it, i invite you to read the following article that shows how when you yield from a first function with a longjmp() to the main body of a program and when you call another functions with longjmp(), it can make the stack frames not work correctly, and when you understand it you will not use setjmp() and longjmp() alone so that to implement coroutines, so read the following article so that to understand the problem with 
the stack frames, and i am understanding it easily:

https://www.csl.mtu.edu/cs4411.ck/www/NOTES/non-local-goto/coroutine.html

So this is why i have also implemented my sophisticated stackful coroutines library so that to solve this problem, and here is my sophisticated coroutines library and read about it and download it from here:

https://sites.google.com/site/scalable68/object-oriented-stackful-coroutines-library-for-delphi-and-freepascal

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

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 implements 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.

Back to comp.programming | Previous | Next | Find similar | Unroll thread


Thread

More of my philosophy about coroutines and about setjmp() and longjmp().. Amine Moulay Ramdane <aminer68@gmail.com> - 2021-11-23 12:44 -0800

csiph-web