embedding

eseguire istruzioni scritte in un linguaggio (es. Lua)
da un programma scritto in un altro (es. C o C++)


browser web

esempio: Edge, Firefox, Safari, etc.


esempio: reazione a un pulsante

all'interno della pagina:

<input type="button"
       value="pulsante"
       onClick="alert('ok');" />

esempio: estensioni Firefox

sono programmi scritti in JavaScript,
eseguiti da Firefox, scritto in C


esempio: estensioni debugger

sono programmi scritti in GNU Guile e/o Python
eseguiti da gdb, scritto in C


esempio: file di configurazione

user_pref("browser.download.panel.shown", true);
user_pref("browser.download.save_converter_index", 0);
user_pref("browser.tabs.closeWindowWithLastTab", false);
user_pref("browser.tabs.warnOnClose", true);

opzioni di Firefox
sempre in JavaScript

esempio: l'ultima linea dice di aprire una finestra di avvertimento quando si chiude il browser


esempio: instruzioni assembler nel kernel di Linux

char *strcpy(char *dest, const char *src)
{
	int d0, d1, d2;
	asm volatile("1:\tlodsb\n\t"
		"stosb\n\t"
		"testb %%al,%%al\n\t"
		"jne 1b"
		: "=&S" (d0), "=&D"  (d1), "=&a" (d2)
		: "0" (src), "1"  (dest) : "memory");
	return dest;
}

quasi tutto il kernel è scritto in C
esegue alcune istruzioni in linguaggio macchina
linux/arch/x86/lib/string_32.c

istruzioni:
1:	lodsb
	stosb
	testb %%al,%%al
	jne 1b
dati di uscita:
	: "=&S" (d0), "=&D"  (d1), "=&a" (d2)
dati di entrata:
	: "0" (src), "1"  (dest) : "memory"

esempi di immersione


caratteristiche delle immersioni

esempio: istruzioni lua eseguite un programma C

deve essere possibile:

ultima cosa: spiegata dopo


esempio di immersione di un linguaggio in un altro

#include <stdlib.h>
…

int main() {
	…
	char *hello="print(\"hello, this is the lua snippet\")";
	…
	luaL_loadbuffer(ls, hello, strlen(hello), "name");
	…
	lua_pcall(ls, 0, 0, 0);
	…
}

esecuzione istruzioni lua da C


scambio dati

avviene spesso attraverso una pila

struttura dati in cui è possibile inserire più dati

sono l'uno sopra l'altro

generalmente:


C → lua

	lua_pushnumber(ls, 2);
	lua_pushnumber(ls, -5);
	lua_pushnumber(ls, 23);

il programma C inserisce 2, -5 e 23 nella pila

il due è il primo
quindi va in fondo
i successivi sopra

       
       
       
       
|  2 | 
+----+ 
      →      
      
      
| -5 |
+----+
|  2 |
+----+
      →      
| 23 |
+----+
| -5 |
+----+
|  2 |
+----+

rimozione dati dalla pila

	lua_remove(ls, -1);
	lua_remove(ls, -1);
	lua_pushnumber(ls, 9);

rimuove i due elementi in cima alla pila
ne aggiunge uno nuovo:

| 23 |
+----+
| -5 |
+----+
|  2 |
+----+
      →      
      
      
      
      
|  2 |
+----+
      →      
      
      
|  9 |
+----+
|  2 |
+----+

lua → C

val = lua_tonumber(ls, -1);

legge il dato in cima alla pila
allo stato attuale è il 9

      
      
|  9 |
+----+
|  2 |
+----+


variabili lua in C


C → funzione lua

  1. caricare la definizione della funzione
  2. eseguire la definizione della funzione
  3. caricare la funzione sulla pila
  4. caricare i dati nella pila
  5. eseguire la funzione sulla pila, con due argomenti
  6. leggere il valore in cima alla pila

C → funzione lua, passo 1

	char *function = "			\
		function xxx(x,y)		\
			print(x,y)		\
			return x+y+2		\
		end				\
	";
	…
	luaL_loadbuffer(ls, function, strlen(function), "function");

carica la stringa che contiene definizione della funzione


C → funzione lua, passo 2

	lua_pcall(ls, 0, 0, 0);

esegue la definizione della funzione

è lo stesso di function xxx(x,y) ... in lua
crea la funzione, ancora non la esegue

analogo a xxx = function(x,y) … end
crea la variabile xxx e ci mette la funzione


C → funzione lua, passo 3

	lua_getglobal(ls, "xxx");

carica la funzione sulla pila

in lua le funzioni sono valori
come i numeri, come le stringhe

in questo caso, è il valore memorizzato nella variabile xxx
si carica il valore della variabile xxx nella pila

| function(x,y) ... end |
+-----------------------+


C → funzione lua, passo 4

	lua_pushnumber(ls, 9);
	lua_pushnumber(ls, 4);

carica i dati nella pila

|           4           |
+-----------------------+
|           9           |
+-----------------------+
| function(x,y) ... end |
+-----------------------+


C → funzione lua, passo 5

|           4           |
+-----------------------+
|           9           |
+-----------------------+
| function(x,y) ... end |
+-----------------------+

	lua_pcall(ls, 2, 1, 0);

esegue la funzione sulla pila, con due argomenti

la pila ora contiene il risultato

|          15           |
+-----------------------+


C → funzione lua, passo 6

|          15           |
+-----------------------+

val = lua_tonumber(ls, -1);

legge il valore in cima alla pila
solito sistema


dati opachi

esempio (JavaScript):


finestre e script

        pagina web
        visualizzata da Firefox, programma C
+---------------------+
| titolo              |
|                     |
| pulsante      testo |
+----|------------|---+
     |            |
     |            |  script.js
     |            |  programma JavaScript
+----|------------|------+
|    V            V      |
| premuto()   cambiato() |
|    |                   |
+----|-------------------+
     |             
     |             pagina dei dati
     V             visualizzata da Firefox, programma c
+---------------------+
| dati                |
|                     |
| a    y    r         |
| 31.3 45.3 9.0       |
| 32.2 45.2 13.2      |
| -9.9 12.0 -4.1      |
+---------------------+


sequenza

[opaco.fig]

  1. l'utente preme il pulsante
  2. il browser esegue le istruzioni JavaScript associate al pulsante
  3. le istruzioni dicono di aprire una finestra che contiene i dati
  4. aprire una finestra è una funzione C
  5. ma ha bisogno di sapere i dati
  6. sono dati del programma C
  7. ma la funzione viene chiamata da JavaScript

dati opachi

[opaco.fig]

non sono dati di interesse all'interno del programma JavaScript
a JavaScript interessa solo che va eseguita una funzione C

non è nemmeno detto che i dati che siano di un tipo che lua riconosce

vengono passati C → lua → C
senza che lua li debba o voglia sapere di che tipo sono

sono come un pacco che un corriere consegna
non vede il contenuto
ma nemmeno gli interessa sapere cosa c'è dentro
pacco "opaco"


programma lua

char *program = "					\
	print(\"start\")				\
	x,y = lua_aprifinestra(3,v)			\
	print(\"first return value: \",x)		\
	print(\"second return value: \",y)		\
";

chiama la funzione lua_aprifinesta()

verrè definita come una funzione C


funzione C da chiamare

int aprifinestra(lua_State *s) {
	…
}

nomina la funzione C in lua

	lua_register(ls, "lua_aprifinestra", aprifinestra);

dice che la funzione C aprifinestra si chiama lua_aprifinestra in lua


passaggio dato generico C a lua

	lua_pushlightuserdata(ls, &dato);
	lua_setglobal(ls, "v");

va nella variabile lua v


cosa fa il programma lua?

	…
	x,y = lua_aprifinestra(3,v)
	…

chiama la funzione lua lua_aprifinestra
è associata alla funzione C aprifinestra

due argomenti
il primo è il numero 3
il secondo è il dato opaco proveniente dal C


la funzione C riceve il dato opaco

int aprifinestra(lua_State *s) {

	…

	n = lua_gettop(s);		// numero argomenti
	x = lua_tonumber(s, 1);		// dato lua, generato da lua
	y = lua_touserdata(s, 2);	// dato opaco, proveniente dal C

	…
}

embedding di altri linguaggi

ogni linguaggio ha le sue specifiche funzioni
per interagire con istruzioni in altri linguaggi
es. lua, JavaScript, Python, Guile

ogni interprete JavaScript ha un suo meccanismo
diverso da quello degli altri
es. duktape, mujs, SpiderMonkey


caratteristiche comuni agli embedding


differenza negli embedding