J'ai essayé de déplacer Hello World (+ α) écrit en langage C à partir de JavaScript [Web Assembly]

Que signifie exécuter du code C sur un navigateur? WebAssembly était l'une des technologies qui m'intéressait car je travaillais avec C dans mon travail précédent. Dans cet article, en plus de HelloWorld, j'ai résumé les résultats d'une petite expérience.


## Qu'est-ce que Web Assembly? *WebAssembly (abbreviated Wasm) is a binary instruction format for a stack-based virtual machine.* (Cité de [Officiel](https://webassembly.org/))
## Postscript (ce que j'ai fait) * Essayez de déplacer Hello World * Que se passe-t-il si j'exécute du code qui fuit de la mémoire? * Que se passe-t-il si vous utilisez de la mémoire? * Que se passe-t-il si j'exécute du code qui provoque une erreur d'exécution?
## Essayez de déplacer Hello World Référence: https://laboradian.com/tried-webassembly/ (Même procédure que [MDN](https://developer.mozilla.org/ja/docs/WebAssembly/C_to_wasm), mais plus facile à comprendre avec des explications supplémentaires)

** Installez Emscripten (compilateur) **

#La version installée cette fois
$ emcc -v
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 1.39.16
clang version 11.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 3774bcf9f84520a8c35bf765d9a528040d68a14b)
Target: x86_64-apple-darwin19.5.0
Thread model: posix
shared:INFO: (Emscripten: Running sanity checks)

** Créez hello.c **

hello.c


#include <stdio.h>

int main(int argc, char *argv[]) {
  printf("Hello World\n");
  return 0;
}

compiler

#Avant la compilation
$ ls
hello.c

#compiler
$ emcc hello.c -s WASM=1 -o hello.html

# wasm, js,html a été généré
$ ls -l
total 496
-rw-r--r--  1 arene  staff      95  5 19 21:55 hello.c
-rw-r--r--  1 arene  staff  102675  5 21 21:50 hello.html
-rw-r--r--  1 arene  staff  115917  5 21 21:50 hello.js    #2600 lignes(!)
-rw-r--r--  1 arene  staff   21727  5 21 21:50 hello.wasm

Le fichier js généré après la compilation contient 2600 lignes. Vous pouvez voir que c'est une technologie difficile. Bien sûr, le code qui ne pouvait pas être compilé en C ne pouvait pas non plus être compilé dans WASM.

↓   ** Activer l'assemblage Web expérimental sur chrome: // flags / **

↓   ** Configurez un serveur Web sur votre PC local **

#Emscripten fournit même un simple serveur Web
$ emrun --no_browser --port 8080 .
Web server root directory: /Users/arene/temporary/wasm
Now listening at http://0.0.0.0:8080/

↓   ** Ouvrez hello.html dans votre navigateur **

1.png

Le code généré automatiquement lors de la compilation de HelloWorld ressemblait à ceci. (Comme il n'a pas été correctement analysé et qu'il y en a beaucoup, seules les parties où il est facile de saisir l'atmosphère sont extraites)

hello.html


<!--Omettre les logos, les écrans de type terminal et autres éléments inutiles-->
<script async type="text/javascript" src="hello.js"></script>

hello.js


//Le code réel est de 2600 lignes
//Afin d'avoir un aperçu, je l'ai extrait comme ça
//L'ordre de définition des fonctions a également été modifié pour pouvoir être lu depuis le début.(Réellement`run();`Est à la fin du fichier)

var wasmBinaryFile = 'hello.wasm';
if (!isDataURI(wasmBinaryFile)) {
  wasmBinaryFile = locateFile(wasmBinaryFile);
}

run(); //Ce gars au bas du fichier est le point de départ de tout

function run(args) {
  //Des omissions très diverses
  callMain(args)
}
function callMain(args) {
  //Des omissions très diverses
  var entryFunction = Module['_main']; // Module['xxx']Il y a beaucoup de choses, y compris la fonction principale.
  var ret = entryFunction(argc, argv);
  exit(ret, true);
}

//Le module C fonctionne comme ceci["asm"]Lié à
var asm = createWasm();
Module["asm"] = asm;
var _main = Module["_main"] = function() {
  assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
  assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
  return Module["asm"]["main"].apply(null, arguments)
}; 
var _malloc = Module["_malloc"] = function() {
  assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
  assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
  return Module["asm"]["malloc"].apply(null, arguments)
}; 
var _free = Module["_free"] = function() {
  assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. waMBit for main() to be called)');
  assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
  return Module["asm"]["free"].apply(null, arguments)
};

## Que se passe-t-il si j'exécute du code qui fuit de la mémoire?

** Préparez du code qui fuit 100 Ko de mémoire pour chaque 1 s **

memoryLeak.c


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void memoryLeak(void) {
  int shouldLoop = 1;
  int loopCount = 0;
  while(shouldLoop) {
    loopCount++;
    if (loopCount > 10) {
      shouldLoop = 0;
    }
    char* p = malloc(1024 * 100); //Allouez dynamiquement de la mémoire. Puisqu'il n'est pas libéré, une fuite de mémoire se produit pour chaque boucle.
    printf("memory leak: leak 100KB!\n");
    usleep(1000 * 1000); // 1000msec
  }
  return;
}

int main(int argc, char *argv[]) {
  printf("memory leak: start\n");
  memoryLeak();
  printf("memory leak: end\n");
  return 0;
}

↓   ** Après la compilation, exécutez-le dans un navigateur et mesurez les performances avec devtool **

1.png

JS Heap n'a pas augmenté et aucune fuite de mémoire n'a été détectée sur la face avant. ...Qu'est-ce que ça veut dire? (Parce qu'il y a un GC dans liste de propositions, il semble que le GC n'a pas fonctionné)


## Que se passe-t-il si vous utilisez de la mémoire?

Je pensais que la raison pour laquelle je ne pouvais pas confirmer la fuite de mémoire dans la section précédente était que la largeur de la fuite était petite et difficile à comprendre, j'ai donc augmenté la largeur de la fuite. Je l'ai réécrit en un code qui fuit 1 Mo toutes les 100 ms, pour un total de 100 Mo, et lorsque je l'ai vérifié de la même manière, j'ai rencontré l'erreur suivante.

On ne sait pas quelle couche est limitée, navigateur, WASM, OS, mais il semble que la mémoire disponible soit limitée. (Bien sûr bien sûr)

console.log


 Cannot enlarge memory arrays to size 17534976 bytes (OOM). Either (1) compile with  -s INITIAL_MEMORY=X  with X higher than the current value 16777216, (2) compile with  -s ALLOW_MEMORY_GROWTH=1  which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with  -s ABORTING_MALLOC=0 
 
 memoryLeak.html:1246 Cannot enlarge memory arrays to size 17534976 bytes (OOM). Either (1) compile with  -s INITIAL_MEMORY=X  with X higher than the current value 16777216, (2) compile with  -s ALLOW_MEMORY_GROWTH=1  which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with  -s ABORTING_MALLOC=0 
 
 memoryLeak.html:1246 exception thrown: RuntimeError: abort(Cannot enlarge memory arrays to size 17534976 bytes (OOM). Either (1) compile with  -s INITIAL_MEMORY=X  with X higher than the current value 16777216, (2) compile with  -s ALLOW_MEMORY_GROWTH=1  which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with  -s ABORTING_MALLOC=0 ) at Error
     at jsStackTrace (http://0.0.0.0:8080/memoryLeak.js:1978:17)
     at stackTrace (http://0.0.0.0:8080/memoryLeak.js:1995:16)
     at abort (http://0.0.0.0:8080/memoryLeak.js:1735:44)
     at abortOnCannotGrowMemory (http://0.0.0.0:8080/memoryLeak.js:2018:7)
     at _emscripten_resize_heap (http://0.0.0.0:8080/memoryLeak.js:2021:7)
     at wasm-function[13]:0x237a
     at wasm-function[11]:0xd36
     at wasm-function[8]:0x337
     at wasm-function[9]:0x407
     at Module._main (http://0.0.0.0:8080/memoryLeak.js:2212:32),RuntimeError: abort(Cannot enlarge memory arrays to size 17534976 bytes (OOM). Either (1) compile with  -s INITIAL_MEMORY=X  with X higher than the current value 16777216, (2) compile with  -s ALLOW_MEMORY_GROWTH=1  which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with  -s ABORTING_MALLOC=0 ) at Error
     at jsStackTrace (http://0.0.0.0:8080/memoryLeak.js:1978:17)
     at stackTrace (http://0.0.0.0:8080/memoryLeak.js:1995:16)
     at abort (http://0.0.0.0:8080/memoryLeak.js:1735:44)
     at abortOnCannotGrowMemory (http://0.0.0.0:8080/memoryLeak.js:2018:7)
     at _emscripten_resize_heap (http://0.0.0.0:8080/memoryLeak.js:2021:7)
     at wasm-function[13]:0x237a
     at wasm-function[11]:0xd36
     at wasm-function[8]:0x337
     at wasm-function[9]:0x407
     at Module._main (http://0.0.0.0:8080/memoryLeak.js:2212:32)
     at abort (http://0.0.0.0:8080/memoryLeak.js:1741:9)
     at abortOnCannotGrowMemory (http://0.0.0.0:8080/memoryLeak.js:2018:7)
     at _emscripten_resize_heap (http://0.0.0.0:8080/memoryLeak.js:2021:7)
     at wasm-function[13]:0x237a
     at wasm-function[11]:0xd36
     at wasm-function[8]:0x337
     at wasm-function[9]:0x407
     at Module._main (http://0.0.0.0:8080/memoryLeak.js:2212:32)
     at callMain (http://0.0.0.0:8080/memoryLeak.js:2500:15)
     at doRun (http://0.0.0.0:8080/memoryLeak.js:2562:23)
 
 memoryLeak.js:1741 Uncaught RuntimeError: abort(Cannot enlarge memory arrays to size 17534976 bytes (OOM). Either (1) compile with  -s INITIAL_MEMORY=X  with X higher than the current value 16777216, (2) compile with  -s ALLOW_MEMORY_GROWTH=1  which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with  -s ABORTING_MALLOC=0 ) at Error
     at jsStackTrace (http://0.0.0.0:8080/memoryLeak.js:1978:17)
     at stackTrace (http://0.0.0.0:8080/memoryLeak.js:1995:16)
     at abort (http://0.0.0.0:8080/memoryLeak.js:1735:44)
     at abortOnCannotGrowMemory (http://0.0.0.0:8080/memoryLeak.js:2018:7)
     at _emscripten_resize_heap (http://0.0.0.0:8080/memoryLeak.js:2021:7)
     at wasm-function[13]:0x237a
     at wasm-function[11]:0xd36
     at wasm-function[8]:0x337
     at wasm-function[9]:0x407
     at Module._main (http://0.0.0.0:8080/memoryLeak.js:2212:32)
     at abort (http://0.0.0.0:8080/memoryLeak.js:1741:9)
     at abortOnCannotGrowMemory (http://0.0.0.0:8080/memoryLeak.js:2018:7)
     at _emscripten_resize_heap (http://0.0.0.0:8080/memoryLeak.js:2021:7)
     at wasm-function[13]:0x237a
     at wasm-function[11]:0xd36
     at wasm-function[8]:0x337
     at wasm-function[9]:0x407
     at Module._main (http://0.0.0.0:8080/memoryLeak.js:2212:32)
     at callMain (http://0.0.0.0:8080/memoryLeak.js:2500:15)
     at doRun (http://0.0.0.0:8080/memoryLeak.js:2562:23)

## Que se passe-t-il si j'exécute du code qui plante avec une erreur d'exécution?

Enfin, j'ai essayé d'exécuter le code qui a causé l'erreur d'exécution. Le résultat, bien sûr, était une erreur d'exécution sur le navigateur. Cependant, le code après la ligne qui a causé l'erreur d'exécution a également été exécuté. (Si vous l'exécutez en tant que C normalement, il tombera au point d'erreur, donc c'est légèrement différent. C'est un comportement assez effrayant.)

segfault.c


#include <stdio.h>

int main(void) {
  int i;
  char str[4];
  char* p;
  
  printf("Before Segmentation Fault\n");
  for(i = 0; i < 16; i++) {
    str[i] = 'a';
    *p = str[i];
  }
  printf("After Segmentation Fault\n");
  return 0;
}
#Lors de la compilation et de l'exécution en langage C normalement, cela échoue au niveau de la partie erreur
$ gcc segfault.c
$ ./a.out
Before Segmentation Fault
[1]    22777 segmentation fault  ./a.out

Lorsqu'il est exécuté à partir du navigateur, le traitement se poursuit même après la partie erreur 1.png

Erreur de connexion à la console

console.log


 segfault.html:1246 Runtime error: The application has corrupted its heap memory area (address zero)!
 segfault.js:1741 Uncaught RuntimeError: abort(Runtime error: The application has corrupted its heap memory area (address zero)!) at Error
     at jsStackTrace (http://0.0.0.0:8080/segfault.js:1978:17)
     at stackTrace (http://0.0.0.0:8080/segfault.js:1995:16)
     at abort (http://0.0.0.0:8080/segfault.js:1735:44)
     at checkStackCookie (http://0.0.0.0:8080/segfault.js:1446:46)
     at postRun (http://0.0.0.0:8080/segfault.js:1538:3)
     at doRun (http://0.0.0.0:8080/segfault.js:2545:5)
     at http://0.0.0.0:8080/segfault.js:2554:7
     at abort (http://0.0.0.0:8080/segfault.js:1741:9)
     at checkStackCookie (http://0.0.0.0:8080/segfault.js:1446:46)
     at postRun (http://0.0.0.0:8080/segfault.js:1538:3)
     at doRun (http://0.0.0.0:8080/segfault.js:2545:5)
     at http://0.0.0.0:8080/segfault.js:2554:7



## finalement Entrée standard, E / S de fichier, thread, sémaphore, mémoire partagée, signal, appel de la fonction js à partir de C, définition de plusieurs fonctions, division de fichier, appel récursif, comparaison de vitesse, etc. Il y a d'autres sujets de préoccupation, mais pour le moment, je vais terminer l'expérience ici.

Finalement, tout sera terminé sur le navigateur, et j'ai un rêve.

Recommended Posts

J'ai essayé de déplacer Hello World (+ α) écrit en langage C à partir de JavaScript [Web Assembly]
J'ai essayé de générer une source de programme en langage C à partir de cURL
J'ai essayé de faire une demande en 3 mois d'inexpérimenté
J'ai essayé de mâcher C # (indexeur)
C # (polymorphisme: polymorphisme)
"Professeur, je souhaite implémenter une fonction de connexion au printemps" ① Hello World
Convertir le langage C en JavaScript avec Emscripten
J'ai essayé de démarrer avec Web Assembly
J'ai essayé de toucher JavaScript Part.2 orienté objet
Dans l'application native Xamarin.Forms Gawa, effectuez la requête-réponse de C # vers JavaScript Task <T>
J'ai essayé d'implémenter des relations polymorphes à Nogizaka.
[Rails] J'ai essayé de faire passer la version de Rails de 5.0 à 5.2
J'ai essayé d'organiser la session en Rails
J'ai aussi essayé Web Assembly avec Nim et C
C # (base de l'encapsulation)
J'ai essayé de sortir quatre-vingt-dix-neuf en Java
J'ai essayé de développer une application en 2 langues
J'ai essayé de créer une compétence Alexa avec Java
J'ai essayé d'expliquer ce que vous pouvez faire dans un langage populaire pour le développement Web du point de vue d'un débutant.
Tokoro j'ai réécrit dans la migration de Wicket 7 à 8
J'ai essayé d'implémenter la notification push Firebase en Java
# 2 [Note] J'ai essayé de calculer quatre-vingt-dix-neuf avec Java.
J'ai essayé de créer une compétence Clova en Java
J'ai essayé de créer une fonction de connexion avec Java
J'ai essayé d'implémenter la méthode de division mutuelle d'Eugrid en Java
~ J'ai essayé d'apprendre la programmation fonctionnelle avec Java maintenant ~
J'ai essayé de mâcher C # (lire et écrire des fichiers)
J'ai essayé de découvrir ce qui avait changé dans Java 9