kakts-log

programming について調べたことを整理していきます

wordle用にmacのターミナルでwordle用の辞書ヘルパーをワンライナーで

やりたいこと

wordle 用に、指定した文字を含んだ5文字の単語の一覧を表示させて、wordleを解きやすくしたい

前提

MacOS 12.3

英単語をどうやって取得するか

今回はMacOSで用意されている英単語辞書を利用する

MacOS内での英単語辞書について

/usr/share/dict/wordsに英単語の辞書が用意されている。 単語数は23万以上と、十分にある。

cat /usr/share/dict/words | wc -l
  235886

英単語は改行区切りになっています。 grepして条件に一致する単語を抽出します。

awkをつかって指定した文字数のものを表示させる

awkで length($0)を使って、ヒットした対象の文字数をチェックできます。 これで5文字だった場合にprintさせるようにする

cat /usr/share/dict/words | grep ber | awk '{ if(length($0) == 5) print $0 }'
amber
awber
berat

あとはgrepの条件でよしなに絞れば一通りの候補を出すことができます。

systemd systemctlでデーモン起動しない場合のログ確認方法

systemd により、os上でsystemctl start hoge のようにデーモンプロセスを起動する際、 プロセスが立ち上がらず、原因がわからなくて困ることがある

$ systemctl start hoge.service


# うまく起動せず、ステータス確認
$ systemctl status hoge -l
● hoge.service 
   Loaded: loaded (/usr/lib/systemd/system/hoge.service; disabled; vendor preset: disabled)
   Active: active (exited) (Result: exit-code) since Wed 2022-03-09 11:11:11:
  Process: 12345 ExecStop=/bin/kill -s QUIT $MAINPID (code=exited, status=1/FAILURE)
  Process: 12345 ExecStart=/bin/sh -c ${JAVA_EXEC} ${JAVA_OPTS} /opt/app/${APP_NAME}.jar ${APP_OPTS} (code=exited, status=127)
 Main PID: 12345 (code=exited, status=127)

Mar 09 11:11:11    host systemd[1]: Started Host Service
Mar 09 11:11:12 host systemd[1]: hoge.service: main process exited, code=exited, status=127/n/a

ここでsystemctl status で-lオプションを実行する。 systemctlによるデーモンプロセス起動時に、bashのstatus終了コード127で落ちているのがわかる。
127番はコマンドが見つからなかったときに返るエラーというのはわかりますが、エラーの詳細がこれだけではわからない状況です。

journalctlによるデーモンプロセスのエラーログ調査

ここで、 上記のsystemctl statusの出力結果にMain PID: ${PID}が表示されており、これが起動しようとしたプロセスIDになります。
journalctlコマンドを使うことで、systemctlによって起動するプロセスのエラーなどのログを確認することができます。

journalctl _PID=12345
-- Logs begin at ..... --
Mar 09 11:11:12 host sh[23467]: /bin/sh: /usr/java/default/bin/java: No such file or directory

こういう感じで実際のエラーの原因を知ることができました。

Apple Silicon macで公式のDocker MySQLイメージを利用する

MySQL公式が Apple Silicon用のMySQLイメージをサポート

Apple Silicon (ARM 64) Macが出てから、DockerではARM64用の公式MySQLイメージが用意されておらず、 --platform linux/amd64 を指定してIntel用イメージをエミュレーションするか、代わりにmariadb イメージを利用する必要がありました。

docs.docker.com

最近、ようやくMySQL8.0において、MySQL公式でARM64版のMySQLイメージが利用可能になりました。 www.emmanuelgautier.com

利用方法

Apple silicon対応のMySQLイメージを利用するには、上記のページで紹介してあるように2通りあります。

  • arm64v8/mysqlを利用する。
  • mysql/mysql-serverイメージで、Oracleによってメンテナンスされているタグを指定する

確認したところだと、8.0系のみ対応しているようです。

arm64v8/mysqlイメージを利用する

https://hub.docker.com/r/arm64v8/mysql/ arm64v8は、arm64用に作成されたイメージをまとめたリポジトリで、MySQL以外にもあります。 現時点では、MySQL8系をサポートしています。

mysql/mysql-serverイメージで、Oracleによってメンテナンスされているタグを指定する

従来通り、MySQL公式のmysql/mysql-serverイメージで、Oracleによってサポートされているタグを指定します。 arm64v8/mysqlと同様のタグ名で、OS/ARCHの項目が linux/arm64/v8になっているものを指定します。

以上となります。

起動したイメージのアーキテクチャ確認

ためしに、linux/arm64/v8に対応しているmysql/mysql-server:8.0.27 イメージタグを指定してみます。 https://hub.docker.com/layers/mysql/mysql-server/8.0.27/images/sha256-f9c95e7df7a8514e0d1b8d24375d2b952387e3293e225f2ba3beb2dc5d456e04?context=explore

docker-compose.yamlの抜粋ですが、下記のような感じで指定します。 platform項目は指定しません。

services:
  # MySQL db
  db:
    image: mysql/mysql-server:8.0.27

これでイメージをpullした後、イメージの情報を確認すると、Architectureの項目がarm64になっていることを確認できます。

$ docker image inspect mysql/mysql-server:8.0.27 | jq '.[0].Architecture'
"arm64"

以上となります。

vscode: Goのコードで定義元にジャンプさせる

概要

vscodeでGoのコードを書く際に、関数などの定義元にジャンプさせたい時の設定。

手順

Go公式のvscode拡張機能を有効にする

まず、Go公式のvscode拡張機能が有効になっているか確認します。 github.com

f:id:kakts:20220303014031p:plain
Goの公式の拡張機能が有効になっているか確認する

上記のvscode拡張機能で、goplsというGo公式のLanguage Serverもバンドルされています。

memo Language Server Protocolというプロトコルについて

https://microsoft.github.io/language-server-protocol/ Language Server Protocolは、IDEとLanguage Serverの間で使われるプロトコルです。
自動補完や、関数などの定義へのジャンプ、関数などの呼び出し元を探したりなど、言語ごとの機能を提供するものです。 Go Language Serverは、このプロトコルに準拠しており、Goに関する上記の機能を提供するものです。 Go Language Serverの1つとして、現在Go公式でサポートしているgoplsがよく使われているようです。

VSCODEでGo Language Serverを有効にする

vscodeにおいてgoplsのセットアップが済んでいますが、vscodeのデフォルトだと、goのLanguageServerが無効になっています。
これが有効になっていないとコード補完やコードの定義元へのジャンプが使えません。
そのため、vscodeの設定でこれを有効にしてあげるhつ用があります。

github.com Goの拡張機能のドキュメントに記載してある通り、 go.useLanguageServerをtrueにしてあげると有効になります。

この記事では解説しませんが、Linterの設定もできるようです。

https://github.com/microsoft/vscode-go/tree/0.13.0#linter

手順

  • Command + Shift + Pでコマンドパレット表示
  • open settingを入力し、設定画面を出す。 f:id:kakts:20220303015437p:plain
  • jsonで設定を追加する
{
...
    "go.useLanguageServer": true,
...
}

これにより、特にエディタ再起動しなくてもジャンプできるようになります。

この設定を入れても定義元ジャンプが利用できない場合は、原因の1つとしてプロジェクトルートにgo.modが存在していないことが挙げられるようです。

bmf-tech - vscodeでgoのLanguage Serverを有効にしたらコード定義元ジャンプができなくなった

参考

VSCode で Go の Language Server である gopls を有効にする - Qiita

C: ディレクトリストリームによるディレクトリエントリ情報の取得

UNIX/linuxベースのOSにおいて、C標準ライブラリを使って、ファイルシステムにおける指定したディレクトリの情報を取得する方法をまとめます。

環境

m1 mac OS(11.6)

ファイルシステムにおけるディレクトリについて

ディレクトリはデータ領域にディレクトリに関する情報を保持しています。 ディレクトリに関する情報は、主に下記になります。

ディレクトリ配下のファイル情報

  • ファイル名
  • ファイル名に対応するiノード番号

iノードはここでは詳しく説明しませんが、ファイルシステムにおいて、ファイルの属性情報を管理するためのデータとなります。 そのiノードごとに番号が割り振られていて、この番号のことをiノード番号と呼びます。

ディレクトリ配下に存在するファイルごとに、それを特定するファイル名と、ファイル名に紐づいたiノード番号が対応づけられ、これによってファイル名と対応したファイルデータをiノード番号から取得できます。

ディレクトリストリームを使ったディレクトリ情報の取得

ここで、C言語にて、ファイルシステムディレクトリ情報をとるための標準ライブラリ関数が用意されています。 C言語において、dirent.hをincludeすることで利用できます。

dirent.h(0p) - Linux manual page

ファイル操作でストリームを使うのと同様に、ディレクトリに対してもディレクトリストリームの仕組みが用意されていて、そのストリームをもとにディレクトリの操作をします。

ディレクトリの操作について

ディレクトリストリームを使ったディレクトリの操作は、主に以下の手順でおこないます。

  1. opendir(3)で指定したパスのディレクトリストリームを取得する
  2. readdir(3)で、1で取得したストリームから、ディレクトリ配下のファイル情報を取得する。 (readdir(3)は一度の呼び出しで1ファイルの情報を取得する。
  3. closedir(3)で、ディレクトリストリームを閉じる

ここで、2のreaddir(3)でディレクトリエントリ(ディレクトリ内の項目)の情報を読み取ります。 readdir(3)の戻り値の型はstruct direntで、POSIXで定義されているフィールドは下記のような構成になっています。

struct dirent {
  ino_t d_fileno; // iノード番号
  char d_name[]; // ファイル名
}

ディレクトリストリームを使った簡単なlsを作る

ここで、ディレクトリストリームを使って、カレンとディレクトリに対するディレクトリエントリの情報を表示する簡易lsコマンドを実装してみます。

/** 
 * ディレクトリストリームを使った簡単なls
 */
#include <errno.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>

int main(void)
{
    DIR *dirp; // ディレクトリストリーム
    struct dirent *p; // ディレクトリ項目用の構造体 readdirで取得する

    // カレントディレクトリのディレクトリストリームを取得
    if ((dirp = opendir(".")) == NULL) {
        perror("opendir");
        exit(1);
    }
    errno = 0;
    // ディレクトリ項目がなくなるまでreaddirする
    while((p = readdir(dirp)) != NULL) {
        // ファイル名とiノード番号を表示する。
        printf("filename: %s, inode: %llu\n", p->d_name, p->d_ino);
    }

    if (errno != 0) {
        perror("readdir");
        exit(1);
    }

    // ディレクトリストリームを閉じる
    if (closedir(dirp) != 0) {
        perror("closedir");
        exit(1);
    }
    return 0;
}

カレントディレクトリに対するストリームを開き、そのストリームに対して、ディレクトリエントリを全部たどりきるまでreaddirを実行して、ディレクトリエントリ(ファイル)の情報を取得します。 そこでファイル名:d_name、iノード番号:d_inoを表示させます。

上記のコードをコンパイルして実行すると、下記の結果となります。

./a.out         
filename: ., inode: 4323177
filename: .., inode: 81985
filename: ch06, inode: 6747507
filename: ch01, inode: 4378311
filename: test022, inode: 4743777
filename: LICENSE, inode: 4323246
filename: test, inode: 4743763
filename: ch04, inode: 4956826
filename: ch03, inode: 4616053
filename: README.md, inode: 4323247
filename: sub, inode: 4684166
filename: ch02, inode: 4516118
filename: a.out, inode: 6748530
filename: ch05, inode: 5625378
filename: foo.txt, inode: 4527223
filename: .gitignore, inode: 4323245
filename: test.txt, inode: 4743184
filename: phone1.dat, inode: 4706419
filename: .git, inode: 4323178
filename: .vscode, inode: 4392160

こんな感じで、カレントディレクトリのディレクトリエントリ情報を表示することができました。

v8によって生成されるbytecodeを確認してみる

Qiita Node.js アドベントカレンダー2021の20日目の記事です
qiita.com

v8のbytecodeについて、自分で書いたコードでどうやって確認するか気になったので調べてみました。

v8によるバイトコード生成

v8がどうやってバイトコード機械語を生成するかざっくりと整理します。
v8がJavaScriptコンパイルするとき、パーサはASTを生成します。
ASTはJavascriptコードの文法構造を表現したツリーです。 v8のインタプリタであるIgnitionはこのASTからバイトコードを生成します。
一方で、最適化コンパイラであるTurboFanは最終的にバイトコードを取得し、そのバイトコードから最適化された機械語を生成します。 なぜv8がこの2つの実行モードを持っているかについては、下記の動画で説明されています。

youtu.be

JavaScriptコードからバイトコードを確認する

ここで、実際に書いたコードから、v8によって生成されるバイトコードを確認します。

nodeコマンドのv8オプションにバイトコードを表示するオプションがあります。nodeコマンド実行時にそのオプションを指定し、該当のjsコードを指定するとバイトコードを確認することができます。

v8オプションの調べ方

まずnodeコマンドでv8に関するオプションを確認するには、--v8-optionsオプションを使用して確認できます。 公式のドキュメントにも記載があります。 Command-line API | Node.js v21.0.0 Documentation

実行するコードのbytecodeを表示するオプションは --print-bytecodeになります

  --print-bytecode (print bytecode generated by ignition interpreter)
        type: bool  default: false

--print-bytecodeのみだと、実行しているコードに関する全情報が表示されてしまいます。
実行する関数のみの情報を表示したい場合は --print-bytecode-filter=${funcName} を追加で指定します。

  --print-bytecode-filter (filter for selecting which functions to print bytecode)
        type: string  default: *

実装した関数をバイトコードで見てみる

早速、簡単な関数をいくつか実装し、それぞれの関数のバイトコードを確認してみます。

function add(a, b) {
    return a + b;
}

add(10, 20)

function sub(a, b) {
    return a - b;
}

sub(20, 10)

function constAdd(a) {
    const v = 100;
    return a + v;
}
constAdd(1);

function constAddLarge(a) {
    const v = 100000;
    return a + v;
}

constAddLarge(1);

ポイントとして、v8は遅延評価をするので、上に記載したように関数を定義したあとに実行しないと--print-bytecodeでもバイトコードが表示されないので気をつけてください。

下記に具体的なバイトコードを載せますが、各バイトコードの説明は、下記のinterpreter-generator.ccで確認可能です。
github.com

addの場合

➜  node --print-bytecode --print-bytecode-filter=add app.js
[generated bytecode for function: add (0x045a03077c09 <SharedFunctionInfo add>)]
Bytecode length: 6
Parameter count 3
Register count 0
Frame size 0
OSR nesting level: 0
Bytecode Age: 0
   25 S> 0x45a0307878e @    0 : 0b 04             Ldar a1
   34 E> 0x45a03078790 @    2 : 38 03 00          Add a0, [0]
   38 S> 0x45a03078793 @    5 : a8                Return 
Constant pool (size = 0)
Handler Table (size = 0)
Source Position Table (size = 8)
0x045a03078799 <ByteArray[8]>

こういう感じで Bytecodeが表示されます。 add関数ではシンプルに変数aとbを加算します。

// Ldar <src>
//  
// Load accumulator with value from register <src>.
IGNITION_HANDLER(Ldar, InterpreterAssembler) {  
  TNode<Object> value = LoadRegisterAtOperandIndex(0);
  SetAccumulator(value);
  Dispatch();
}
  • Add a0, [0] Addは、アキュムレータに対して a0レジスタの値を加算します。

https://github.com/v8/v8/blob/9.5.173/src/interpreter/interpreter-generator.cc#L872-L877

// Add <src>
//
// Add register <src> to accumulator.
IGNITION_HANDLER(Add, InterpreterBinaryOpAssembler) {
  BinaryOpWithFeedback(&BinaryOpAssembler::Generate_AddWithFeedback);
}

このBinaryOpWithFeedbackは、共通化された関数のため、さまざまなところで使われているものです。
バイトコードごとに特定の操作を表すBinaryOpGeneratorの値を引数に渡し、その値によってレジスターとアキュムレータの値を操作します。
BinaryOpGeneratorの値は下記のコードでまとまっています。 github.com

BinaryOpWithFeedbackの実装を見てみます。
https://github.com/v8/v8/blob/9.5.173/src/interpreter/interpreter-generator.cc#L839-L853

  1. 1番目のオペランドの値を取得する
  2. generatorのタイプによって、オペランドの値を加算したり源さんなどしたりして、その結果をアキュムレータにセットする
  void BinaryOpWithFeedback(BinaryOpGenerator generator) {
    TNode<Object> lhs = LoadRegisterAtOperandIndex(0);
    TNode<Object> rhs = GetAccumulator();
    TNode<Context> context = GetContext();
    TNode<UintPtrT> slot_index = BytecodeOperandIdx(1);
    TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();

    BinaryOpAssembler binop_asm(state());
    TNode<Object> result =
        (binop_asm.*generator)([=] { return context; }, lhs, rhs, slot_index,
                               [=] { return maybe_feedback_vector; },
                               UpdateFeedbackMode::kOptionalFeedback, false);
    SetAccumulator(result);
    Dispatch();
  }

これによって、2つの引数を加算してアキュムレータに書き込まれました。 - Return
最後にReturnとなります。 Returnは、アキュムレータにある値を返します。 https://github.com/v8/v8/blob/9.5.173/src/interpreter/interpreter-generator.cc#L2658-L2665

// Return
//
// Return the value in the accumulator.
IGNITION_HANDLER(Return, InterpreterAssembler) {
  UpdateInterruptBudgetOnReturn();
  TNode<Object> accumulator = GetAccumulator();
  Return(accumulator);
}

subの場合

subの場合は、先程のaddと違うのが、2番目のバイトコードSub a0, [0] になっているのが異なります。 それ以外は、基本的にレジスターの値を操作してアキュムレータに結果を書き込み、最後にその値をReturnして返すという大まかな構造は変わりません。

➜  node-sandbox node --print-bytecode --print-bytecode-filter=sub app.js
[generated bytecode for function: sub (0x0a9837e37c59 <SharedFunctionInfo sub>)]
Bytecode length: 6
Parameter count 3
Register count 0
Frame size 0
OSR nesting level: 0
Bytecode Age: 0
   80 S> 0xa9837e38846 @    0 : 0b 04             Ldar a1
   89 E> 0xa9837e38848 @    2 : 39 03 00          Sub a0, [0]
   93 S> 0xa9837e3884b @    5 : a8                Return 
Constant pool (size = 0)
Handler Table (size = 0)
Source Position Table (size = 9)
0x0a9837e38851 <ByteArray[9]>

constAddの場合

constAddは、受け取った引数の値と、関数内で宣言している定数を加算して返します。 こちらも、基本的な処理は変わらず、引数をレジスターに読み込み、定数を加算してアキュムレータに書き込み、それを最後にReturnします。

 node --print-bytecode --print-bytecode-filter=constAdd app.js
[generated bytecode for function: constAdd (0x18deb9bf7d41 <SharedFunctionInfo constAdd>)]
Bytecode length: 9
Parameter count 2
Register count 1
Frame size 8
OSR nesting level: 0
Bytecode Age: 0
  159 S> 0x18deb9bf8aae @    0 : 0d 64             LdaSmi [100]
         0x18deb9bf8ab0 @    2 : c3                Star0 
  168 S> 0x18deb9bf8ab1 @    3 : 0b fa             Ldar r0
  177 E> 0x18deb9bf8ab3 @    5 : 38 03 00          Add a0, [0]
  181 S> 0x18deb9bf8ab6 @    8 : a8                Return 
Constant pool (size = 0)
Handler Table (size = 0)
Source Position Table (size = 11)
0x18deb9bf8ab9 <ByteArray[11]>

add, subと異なるのは、定数の読み込みにLdaSmi を使用しています。 これも紹介していきます。

  • LdaSmi [100] で定数100をアキュムレータに読み込む 定数を読み込む場合の専用のバイトコードが用意されていて、LdaSmiとなります。 SmiはSmall Integerの略で、ある程度小さい値の整数を扱うものとなります。

下記の実装の通り、オペランドに指定されている数を読み込んで、それをアキュムレータにセットしています。 https://github.com/v8/v8/blob/9.5.173/src/interpreter/interpreter-generator.cc#L72-L80

// LdaSmi <imm>
//
// Load an integer literal into the accumulator as a Smi.
IGNITION_HANDLER(LdaSmi, InterpreterAssembler) {
  TNode<Smi> smi_int = BytecodeOperandImmSmi(0);
  SetAccumulator(smi_int);
  Dispatch();
}
  • Star0 でアキュムレータの値を r0レジスターに書き込む ここで 0という数字を使っていますが、この数字は下記の実装でわかるように、レジスターの番号を表します。 この値は、つまりアキュムレータにある値をr0のレジスターに書き込むこととなります。

https://github.com/v8/v8/blob/9.5.173/src/interpreter/interpreter-generator.cc#L148-L160

// Star0 - StarN
//
// Store accumulator to one of a special batch of registers, without using a
// second byte to specify the destination.
//
// Even though this handler is declared as Star0, multiple entries in
// the jump table point to this handler.
IGNITION_HANDLER(Star0, InterpreterAssembler) {
  TNode<Object> accumulator = GetAccumulator();
  TNode<WordT> opcode = LoadBytecode(BytecodeOffset());
  StoreRegisterForShortStar(accumulator, opcode);
  Dispatch();
}

これにより、 r0レジスターに定数1000が書き込まれました。

  • Ldar r0 r0レジスターの値をアキュムレータに読み込みます。 値の操作は、アキュムレータにある値をもとに行います。 このあと、引数で指定した値をアキュムレータにある値に加算していきます。 Ldarは、addで前述したように、 オペランドで指定したレジスターの値をアキュムレータに読み込むためのバイトコードです これによって定数1000がアキュムレータに読み込まれました

残りの下記2つについてはaddと同じです。
- Add r0, [0] r0の値をアキュムレータに加算する 
- Return アキュムレータの値を関数呼び出しもとに返す。

if文を使ったコードの場合

ここで、長くなるため軽く説明しますが、下記のようにif文を使った場合は、JumpIfToBooleanFalse などを使って、指定した値が条件に一致する場合に特定のコードのアドレスにジャンプするなどの処理が走ります。

function iftest(flg) {
    if (flg) {
        console.log(1);
    } else {
        console.log(2)
    }
}
iftest(true);
➜  node-sandbox node --print-bytecode --print-bytecode-filter=iftest app.js
[generated bytecode for function: iftest (0x3b78e6677ca9 <SharedFunctionInfo iftest>)]
Bytecode length: 42
Parameter count 2
Register count 3
Frame size 24
OSR nesting level: 0
Bytecode Age: 0
  150 S> 0x3b78e6678926 @    0 : 0b 03             Ldar a0
         0x3b78e6678928 @    2 : 96 15             JumpIfToBooleanFalse [21] (0x3b78e667893d @ 23)
  169 S> 0x3b78e667892a @    4 : 21 00 00          LdaGlobal [0], [0]
         0x3b78e667892d @    7 : c2                Star1 
  177 E> 0x3b78e667892e @    8 : 2d f9 01 02       LdaNamedProperty r1, [1], [2]
         0x3b78e6678932 @   12 : c3                Star0 
         0x3b78e6678933 @   13 : 0d 01             LdaSmi [1]
         0x3b78e6678935 @   15 : c1                Star2 
  177 E> 0x3b78e6678936 @   16 : 5d fa f9 f8 04    CallProperty1 r0, r1, r2, [4]
         0x3b78e667893b @   21 : 89 13             Jump [19] (0x3b78e667894e @ 40)
  206 S> 0x3b78e667893d @   23 : 21 00 00          LdaGlobal [0], [0]
         0x3b78e6678940 @   26 : c2                Star1 
  214 E> 0x3b78e6678941 @   27 : 2d f9 01 02       LdaNamedProperty r1, [1], [2]
         0x3b78e6678945 @   31 : c3                Star0 
         0x3b78e6678946 @   32 : 0d 02             LdaSmi [2]
         0x3b78e6678948 @   34 : c1                Star2 
  214 E> 0x3b78e6678949 @   35 : 5d fa f9 f8 06    CallProperty1 r0, r1, r2, [6]
         0x3b78e667894e @   40 : 0e                LdaUndefined 
  227 S> 0x3b78e667894f @   41 : a8                Return 
Constant pool (size = 2)
0x3b78e66788d1: [FixedArray] in OldSpace
 - map: 0x0d95fcb412c1 <Map>
 - length: 2
           0: 0x3523f1b390b9 <String[7]: #console>
           1: 0x3523f1b0c0b1 <String[3]: #log>
Handler Table (size = 0)
Source Position Table (size = 19)
0x3b78e6678951 <ByteArray[19]>
  • JumpIfToBooleanFalse [21] もしアキュムレータのオブジェクトがBooleanに変換した結果Falseになる場合、 オペランドに指定したアドレスにジャンプします。 この場合、Falseだったら 21番目のアドレスにジャンプします。
// Jump by the number of bytes represented by the immediate operand |imm|.
IGNITION_HANDLER(Jump, InterpreterAssembler) {
  TNode<IntPtrT> relative_jump = Signed(BytecodeOperandUImmWord(0));
  Jump(relative_jump);
}

おわりに

v8では、コードの最適化のために、Ignition, TurboFanによってバイトコードの生成や、機械語の最適化などいろいろ内部でやっているようで奥が深いので、今後も深く調べてみようと思います。

今回紹介したバイトコードの確認は比較的簡単にできるので、関数の実装で色々パターンを試してどういうバイトコードに変換されるかをみても面白いかもしれません。

m1 macでpip使用時にModuleNotFoundError: No module named '_ctypes' エラーが出る

前提 - python 3.7.12
- m1 mac
- mac OS Big Sur 11.6


m1 macでpython3系を利用し、pip installを実行すると下記のエラーがでた。

ModuleNotFoundError: No module named '_ctypes'

対処法

自分はpythonのバージョンを3.8.12にあげたら対応ができた。 いろいろ調べたところ3.7系でも対応方法があるようです。

Python build fails on M1 Apple Silicon with arm64 homebrew · Issue #1768 · pyenv/pyenv · GitHub