2005/5/10

     
 

AAL OpCode

artefaktur

| Intentional Programming | ACI Concept | AAL definition | AAL syntax | AAL parser | Object Representation | OpCode | Reference Links |

Intermediate OpCode for AAL.

Sub chapter pages:

Intermediate OpCode for AAL.

Intermediate OpCode for AAL.

Intermediate OpCode for AAL.

Intermediate OpCode for AAL.

Content of this chapter:

   Basics
   Aspects
     Integrate in the ParseTree
     Stack based Byte Code
       ByteCode as Sub-Nodes
     Basic Types
       Local Variables
     DMI mapping
       Static Resolution
         Function Call
         Build-In-Functions
         Named parameter
         Member Access
     Type definitions
     Persistence
       String Ressource
       Codes
       SymbolTables
       Script
     ActivationFrame
       General
         Function ActivationFrame
         Exceptions
         Script
       ClazzInfo Ressource
       OpStatements
     Optimizations
       Elimination of local temp vars
   Op Codes
     Stack
     Arithmetik and Logical Ops
     Branches
     Invokation

 Basics

Using an OpCode for execution and maybe transpile to Java ByteCode or .NET CIL. For both languages an assembler language should be used.

 Aspects

 Integrate in the ParseTree

OpCodes are nodes below the Code nodes. Code::executes() delegates the call to OpCodes. Maybe translation can be done on the fly.

 Stack based Byte Code

 ByteCode as Sub-Nodes

On each CodeNode the Byte Code of the construct will be attached. The ByteCode contains an ObjectArray. The Elements can be either a OpCode statement (like 'push 1') or a Link to another ByteCode.

 Basic Types

Use ScriptVar as basic type. All OpCodes operates on ScriptVar, so they don't make a difference to i2, i4, r4, Object etc.

 Local Variables

  • Use Instance variable name in Byte-Code?
  • Use .data section (StackFrame)?
int i = 1 + 2;

// will be: 
.data i int
push 1
push 2
add
pushlval .data[0]
assign

i = 1;
// maybe also
push 1
assign i

 DMI mapping

 Static Resolution

 Function Call
 Build-In-Functions
// Minimal sample

void foo() { }
// Callee
push Nil
ret

foo();

// Caller
push "foo" // class name
push "operator_popc"
push 0 // argcount | flags
invoke_static
pop
 Named parameter
void foo(int i = 0, String s = Nil);
foo(s: "AAL", i: 2);

push 2
push "i"
push "AAL"
push "s"
push 2 // number of named params
push 0  // number of unnamed params
push "foo"
callnp
 Member Access
Write access
class AClass
{
public: int foo;
};

// AClass cls
acls.foo = 2;

push acls
push 2
poke 'foo'

// or
push 2
push acdk
push 'foo'
getmemberlval
assign

// or
push acls
push 'foo'
push 2
invoke 
// or implement operator=() on the object reference. which may be most general approach.
acdk.lang.System.out.println("asdf");
push "acdk/lang/System"
push "out"
peek_static   // top on stack is out
push "println" 
push "asdf"
push 1
invoke

 Type definitions

To define Types, special Opcodes should be used.
  1. Don't use OpCodes for Class Definition but use the Code nodes and the Environment to define classes. Pro: Easy to implement.
  2. Use structured declarative statement (.defclass) in the opcode. Con: Has to established a Parser for OpCode.
  3. Use basic stack based op codes to create type. Con: Hard to understand, not portable to other ByteCode languages.
  4. Use serialized ClazzInfo to define Classes. The classes can be loaded via a ClassLoader Pro: easy to implement. Pro: Fast execution
class AClass
{
  public void foo(int i);
};
// Case 1 has no OpCode

// Case 2 
.defclass AClass extends BClass
  .defmethod void foo (int i) 
.endclass

// Case 3
push "AClass"
clsdef // class AClass is on top
push "BClass"
clsextends
push "void" // return type
push "foo" // method name
push "int"
push "i"
push 1 // argument count, method flags
defmethod
pop // removes the class defintion

// Case 4

 Persistence

The a compiled unit should be stored into a binary file:

 String Ressource

Maybe a string dictionary similar to the Java Class format.

 Codes

For debugging purpose may also include the original AST with all Codes.

 SymbolTables

Symboltable holds defined ClazzInfo ressources and tries to resolves external type definitions. After postParse() the SymbolTable is build. The SymbolTable is a mapping from String (VarName) to Type.

 Script

class AalClassFile
{
   short magic; // 0xaacf
   int version_mayor;
   int version_minor;
   SymbolTableArray symbols;
   OpCodeArray symbols;
   CodeArray codes; // debug information
};

 ActivationFrame

 General

For runtime the names should be resolved to simple index into an ActivationFrame. The ActivationFrame holds all local variables of the current block. The ActivationFrame creates two OpCodes blocks: Push all local variables on the stack before emitting the childCodes of the ActivateFrame. After emmitting the the childCodes, save last value on the stack if needed, pop all local variables.
// AFS = ActivationFrameStack
int foo(int i) // AFS[0]
{
  int j; // AFS[1]
  {
    // // AFS[2]
    return i;
  }
}

AFS[1]: pop ScriptVar(int(0));
ret AFS[0][0]. // save AFS[0][0] value and unwind AFS until function will be leaved.
To enable returning from everywhere in the ActivationFrame Stack (and exceptions too) the ret operation has to call a method unwind to pop all local variables. The ret value must not saved on the local variable stack, otherwise it will be also discarged at the unwind operation. Positive index values address the values from the bottom (0) Negativ values (beginning with -1, which is the last pushed value) addresses the values from top of the stack. Variable declarations in a ActivationFrame
void foo()
{
  int i = 42;
  i = i + 1;
  if (i == 42)
    return;
  int j = i;
  return j;
}
The example defines a variable i, uses this variable and than defines another variable j. In C both variables i and j will be created at beginning of the function block. In C++ only the first variable i will be created. If using the C++ creation manner of local variables, the AF must be managed dynamically:
lvar int
push 42
store 0
...
lval int
load 0
store 1
load 1
ret
 Function ActivationFrame
Parameter passing Functions ActivationFrame are specialized ActivationFrame. Question: Caller should push arguments on stack. But should also the caller pop the arguments to avoid stack under/overflow? The advantage of the case, that the callee pops the arguments is, that less OpCodes are generated (a function normally calls many functions).
foo(42, 41);
push 41
push 42
push 2 // 2 arguments, 0 unnamed, standard call
call foo

int foo(int i, int j)
{
  //Stack:  i, j, Number of arguments (2)
  return i + j;
  pop AFS[0][2]
  pop AFS[0][1]
  add 
  ret AFS[0][0]
} // 
invokation flags = number of arguments (byte) |
                   number of named arguments (byte) << 8
                   unused << 16
                   flags << 24 
flags:
enum InvokationFlags
{
  StandardFrame = 0x00,
  
};
Parameter attributes in attributes In case a parameter will be passed with the 'in' attribute it will be possible just to reuse parents AF slot. An flag of the ScriptVar has to ensure, that the value must not be changed. out/inout attributes In case a parameter will be passed with the 'out' or 'inout' attribute it will be possible just to reuse parents AF slot. Otherwise the ScriptVar must be a reference type.
 Exceptions
Exceptions has to be hold by the ActivationFrame and delegate to parent ActivationFrame. Java handles this with ExceptionsTables, which markes an OpCodeBlock internally and the target PC in case of an active Exception.
 Script

// function and global ActivationFrame
class ActivationFrame
: implements OpCode

  ScriptVar _returnValue;
  RThrowable _activeException;
  ActivationFrame(ActivationFrame* parent = 0);
  void execute();
  void unwind();
}

// a block
class ActivationFrameScope
{
  ActivationFrame& _af;
  int _top;
  void unwind();
}
  createaf
  clvar int
void foo(int i)
{
    // createafscope
  int j = 1;
    // clval int
    // push 1
    // store AF[1]
  { // createafscope
    int j = i;
    // clval int
    // load AF[0]
    // store AF[2] 
  } // destroyafscope
  
  j = 2;
  // push 2
  // store AF[1]
  int k = 1;
   // clval int
   // push 1
   // store AF[2]
   
} // destroyafscope
// destroyaf
int i;
while (i < 3)
  i = i + 1;

  clval int // asume on AF[1]
loopentry:
  load 1
  push 3
  lt
  brnull loopexit
  
  load 1
  push 1
  add
  store 1
  
  br loopentry
loopexit:

Same now with block:

while (i < 3)
{
  i = i + 1;
}

 clval int // asume on AF[1]
loopentry:
  oopentry:
  load 1
  push 3
  lt
  brnull loopexit
  
  createafscope
  load 1
  push 1
  add
  store 1
  destroyafscope
  br loopentry
  
loopexit:
  
  

 ClazzInfo Ressource

Store the DClazzInfo as binary, compatible with ClazzInfo C-structures to make loading an ClazzInfo a simple task. Maybe use a type of memory mapped file. Link from a ClazzMethodInfo to the starting OPStatement of these function.

 OpStatements

Binary, as stream.

 Optimizations

 Elimination of local temp vars

0: clvr 0
1: push ""Hello ""
2: push "acdk/lang/StringBuffer"
3: push 1
4: new
5: store 0                        lvar 0 will only used in next line (pop stack and store at 0)
6: load 0                         (load 0 and push on stack
7: clvr 1
8: store 1
9: push ""ACDK""
10: push "append"
11: load 1
12: push 1
13: invoke
14: pop

Can be:

0: <deleted>
1: push ""Hello ""
2: push "acdk/lang/StringBuffer"
3: push 1
4: new
5: <deleted>
6: <deleted>
7: clvr 0
8: store 0
9: push ""ACDK""
10: push "append"
11: load 0
12: push 1
13: invoke
14: pop

 Op Codes

 Stack

AAL JVM CIL Explenation
nop ? nop No operation
ldc loadx ldc Load constant on stack
dup ? dup Duplicates the top most element

 Arithmetik and Logical Ops

AAL JVM CIL Explenation
add ? add Add both values on top

 Branches

AAL JVM CIL Explenation
br ? br Branch (goto) to label
brtrue ? brtrue Branch (goto) to label if true
brfalse ? brtrue Branch (goto) to label if false

 Invokation

AAL JVM CIL Explenation
inv ? callvirt Call the virtual method
invs ? ? Invoke Static
inve ? ? Invoke with extended Invokation Frame
invse ? ? Invoke static with extended Invokation Frame
new ? ? create new Object.
Also pass allocator
newe ? ? create new Object with extended Invokation Frame