SlideShare ist ein Scribd-Unternehmen logo
1 von 24
Perlと出会い、Perlを作る

     株式会社ミクシィ
 Masaaki Goshima(@goccy54)
Perl作成を決意
• 「深く理解したいなら作る」という
  モットーのもと、学ぶなら作って学びた
  い!
 – どうせなら、スクリプト言語界最速のPerlを作りたい
gperl
• 世界一高速なPerl処理系を目指している

• 大目標はPerl5.16とある程度互換性を持
  ち, mixiのホーム画面を表示させるスクリプ
  ト(home.pl)を動かすこと

• C++でスクラッチから実装
 – 依存ライブラリは極力入れない方針
  • (readlineも自作)
アジェンダ
•   gperlの概要と性能評価
•   高速化技術あれこれ
•   高速化のために断念したPerlの仕様
•   まとめ
gperlの概要(Speed)
• 導入済みの高速化技術
 – asmベースの2番地コード命令
 – Register型VM
 – Direct Threaded Codeを用いた
   高速関数呼び出し
 – 引数オブジェクトの事前構築
 – NaN-boxingによる型検査
 – アノテーションによるStatic Typingの実現
 – JIT Compile
gperlの概要(Syntax)
• サポートされている文法やデータ構造
 – データ型 :
   int, double, String, Array(Ref), Hash(Ref), CodeRef, B
   lessedObject
 – ループ: for, while, foreach
 – 条件文: if-elsif-else
 – 関数呼び出し(再帰処理可)とクラス作成(package)
 – 演算子(一部) : +, -, *, /, +=, -=, ++, --
   , <<, >>, <, >, <=, >=, !=, ==
 – その他: ローカル変数, 複数変数の宣言と代入など
性能評価(1/3)
                      Fibonacci数列の計算
N=35
       Language          time(real)[sec]   X(倍率)
        gperl(JIT)            0.10         X91.2
                                                         測定環境
  LuaJIT(2.0.0-beta10)        0.12         X76.0

         v8(0.8.0)            0.18         X50.6      MacOSX(10.7.4)
                                                    2.2GHz Intel Core i7
   gperl(StaticTyping)        0.44         X20.7       Memory: 8GB
           gperl              0.46         X19.8   Darwin Kernel Version
                                                       11.4.0 x86_64
       Konoha(1.0)            0.52         X17.5

       PyPy(1.9.0)            0.53         X17.2

  SpiderMonkey(1.8.5)         2.17          X4.2

        Lua(5.2.1)            2.82          X3.2         測れるもの
       Ruby(1.9.3)            3.65          X2.5
                                                        数値演算速度
       Python(2.7.3)          4.32          X2.1      関数呼び出し速度
                                                      VM設計の良し悪し
       Perl(5.16.0)           9.12          X1.0
性能評価(2/3)
                  たらい回し関数の計算
(x,y,z) = (13, 6, 0)
       Language           time(real)[sec]   X(倍率)
        gperl(JIT)             0.29         X102.0
                                                           測定環境
        v8(0.8.0)              0.41         X72.1
   LuaJIT(2.0.0-beta10)                                 MacOSX(10.7.4)
                               0.46         X64.3
                                                      2.2GHz Intel Core i7
    gperl(StaticTyping)        1.24         X23.9        Memory: 8GB
                                                     Darwin Kernel Version
       Konoha(1.0)             1.38         X21.4        11.4.0 x86_64
          gperl                1.56         X19.0
       PyPy(1.9.0)
                               4.30          X6.9

   SpiderMonkey(1.8.5)         5.70          X5.2          測れるもの
        Lua(5.2.1)             5.97          X5.0
                                                         複数引数の処理
       Ruby(1.9.3)             7.63          X3.9         数値演算速度
                                                        関数呼び出し速度
      Python(2.7.3)            17.18         X1.7       VM設計の良し悪し
       Perl(5.16.0)            29.59         X1.0
性能評価(3/3)
                         binary-trees
N=15
       Language          time(real)[sec]   X(倍率)
         v8(0.8.0)
                              0.32         X35.8         測定環境

  LuaJIT(2.0.0-beta10)        1.29          X8.9      MacOSX(10.7.4)
       Konoha(1.0)            1.46          X7.9    2.2GHz Intel Core i7
                                                       Memory: 8GB
       PyPy(1.9.0)            1.98          X5.8   Darwin Kernel Version
       Python(2.7.3)          2.25          X5.1       11.4.0 x86_64
  gperl(Static Typing)        3.97          X2.9

           gperl              4.06          X2.8

       Ruby(1.9.3)            5.23          X2.2

  SpiderMonkey(5.7.3)         5.73          X2.0         測れるもの
        Lua(5.2.1)            7.56          X1.5          GCの速度
       Perl(5.16.0)           11.47         X1.0
高速化技術あれこれ
引数オブジェクトの事前構築(1/2)
• 引数格納用の配列を事前構築して高速化
 – Perlは, シンプルに実装すると関数呼び出しのた
   びに引数用の配列オブジェクトが作られる
  • 関数呼び出しの度に配列を生成すると遅い


 – 通常、引数の数は一定数以下に抑えられてコー
   ディングされるため、あらかじめ引数用の配列を
   確保しておくことで対処する
引数オブジェクトの事前構築(2/2)
                                        関数呼び出しスタックの一つ一つに対応して




                           ・・・・
関数呼び出しスタック                            引数用の配列を事前に作り、引数はそこに積まれる
スタックの伸びる方向




                   3
                       4
                                  5
                                            1 :subf {
                                            2 : my $a = $_[0];
                   2
                       3
                                  4
                       引数用の配列               3 : my$b= $_[1];
                                            4 : my$c= $_[2];
                   1
                       2
                                  3



                                            5 : if ($a > 10) {
                                            6 : return 1;
                                            7 : }
                                            8 : returnf(++$a, ++$b, ++$c);
                                            9 :}
       関数が呼ばれるとstack_topが一つ上がる              10 :f(1, 2, 3);
          関数から抜けると一つ下がる
             しかしPerlには、引数が一定数以下に抑えられるという常識が通じない
             仕様があるため、一筋縄ではいかない =>後述
NaN-boxingによる型検査(1/2)
• Perlのような動的型付け言語は、変数の型を保
  存する仕組みが必要
 – 通常は、値(int, double, boolean)であっても、オブ
   ジェクトとして扱い、型情報を持たせる(boxing)
 – しかしboxingしてあると、計算の時に毎回オブジェク
   トから値を取り出す操作(unboxing)が入るため遅い.
   また、全てオブジェクトにするためメモリ効率も悪
   くなる
                     case ADD:
 structIntObject {   Object *a = reg[0];
                     Object *b = reg[1];
 inttype; //型情報      if (a->type == TypeInt&&b->type == TypeInt) {
 intdata; //実際の値          ((IntObject *)a)->data += ((IntObject *)b)->data;
 };                    } else if (a->type == TypeString&&b->type == TypeString) {
                          ……
                       }
NaN-boxingによる型検査(2/2)
• NaN-boxingは、double型のNaN領域に型
  情報を埋め込む技術
  – unboxingと同じように扱えて、型情報も持た
    せられる               unboxingされている
                case ADD:                                 のに型検査できる
union{          switch (typecheck(reg[0], reg[1])) {
intidata;       caseInt_Int:
double ddata;        reg[0].idata += reg[1].idata;//データに直にアクセスできる
char *sdata;    break;
void *odata;      case String_String:
};                   …..
                  }

しかしPerlには、関数呼び出し時に渡される変数は全てリファレンス
として扱われるという仕様があるため、一筋縄ではいかない =>後述
アノテーションによる
  Static Typing/JIT Compileの実現
• 大規模開発を行う場合、型は静的に決定できる
  場合がほとんど
 – 型安全性が損なわれるとバグのもとに
 – そもそも、開発するときに型のイメージはあるはず


• 型を静的に決められるケースが多いなら、その
  恩恵を受けようじゃないか
 – アノテーションを付加することで、静的型付け用の命
   令を生成したり, JIT Compileできるようにする
アノテーションによる
   Static Typing/JIT Compileの実現
• 関数の宣言前に、”#@static_typing” or
  “#@jit_safe”と記述することで、静的型付け用の命
  令やJIT用の命令が生成される
 – #~とすることで、Perlとの互換性を保つ
                 1: #@static_typing
                 2: subfib {
型が決まらないと処理できない   3: if ($_[0] < 2) {
    命令において、      4: return 1;
初めて処理した時に分かった型   5: } else {
    を覚えておき、      6:         return fib($_[0] - 1) + fib($_[0] - 2);
 2回目からは分かった型用の   7: }
    命令で処理する      8:}
                 9:print(fib(35), "n");
高速化のために断念した(い)機能
高速化のために断念した(い)機能
1. 関数引数にあるリストの展開
2. デフォルトでのスカラー変数の参照渡し
1.関数引数にあるリストの展開
• Perlでは, 関数の引数にリストがあるときは, 中
  身を展開して一つの配列にしてから関数に渡す
 – 配列結合のSyntax SugarがPerlでは(@a, @b)で表現
   でき、引数では常に有効になる
      subf{
      my@args= @_;
      print $args[0], "n"; # $args[0] == 1
      print $args[1], "n"; # $args[1] == 2
      }
      my@a = (1, 2, 3);
      my @b= (4, 5, 6);
      f(@a, @b);
1.関数引数にあるリストの展開
• gperlではあらかじめ引数の数を想定して引数ス
  タックのサイズを決めているため、引数の数が
  多いとスタックを拡張しなければならない
                                          gperl内部では@aも一つの
subf{                                    配列オブジェクトとして扱わ
my@args= @_;                             れているため、そのままだと
print $args[0], "n"; # $args[0] == @a   $args[0]の値は@aになり、
print $args[1], "n"; # $args[1] == @b   $args[1]の値は@bになって
}                                                 しまう
my@a = (1, 2, 3);
my @b= (4, 5, 6);
                                         これを簡単に避けるために、
f(@a, @b);
                                         リストを展開・結合したい場
                                         合は、f((@a, @b))のように呼
                                          び出すルールを決めている
2.デフォルトでのスカラー変数の
        参照渡し
• Perlでは、関数の引数は全て参照渡しになるの
  で、明示的にリファレンスにしなくとも、値の
  書き変えが可能

subf{                           NaN-boxingではこの挙動を
    $_[0] = 3;                  再現できないため、
}                  $_[0]には$aの   スカラー変数のデフォルトでの
                  リファレンスが入っ     参照渡しは未サポート
my $a = 1;        ているので、値を書
f($a);            き変えると元の値も     $aを使ってリファレンスを
print $a, "n”;     書き変わる       渡すことを明示すれば、
                                そのときにboxingを行って対処する
まとめ
• VM、GCやJITなど、ベースとなる技術の
  設計や実装はできてきた
• 今後の予定 (文法や機能の充実)
 – 後置文, 三項演算子, format, 正規表現 ,
   map/grep, eval, use/FFI, 継承, 括弧の省略など
 – ドキュメントの整備

• 研修時に書いたPerlスクリプトがやっと動く
  ように・・
 – 本当の意味で研修内容を理解できた・・・!?
https://github.com/goccy/gperl
Perlと出会い、Perlを作る

Weitere ähnliche Inhalte

Was ist angesagt?

ラムダと invokedynamic の蜜月
ラムダと invokedynamic の蜜月ラムダと invokedynamic の蜜月
ラムダと invokedynamic の蜜月
Taku Miyakawa
 
Node-v0.12の新機能について
Node-v0.12の新機能についてNode-v0.12の新機能について
Node-v0.12の新機能について
shigeki_ohtsu
 
How to debug a perl script using gdb
How to debug a perl script using gdbHow to debug a perl script using gdb
How to debug a perl script using gdb
akirahiguchi
 
はじめてのRuby拡張ライブラリ
はじめてのRuby拡張ライブラリはじめてのRuby拡張ライブラリ
はじめてのRuby拡張ライブラリ
Masahiro Tomita
 
"Programming Hive" Reading #1
"Programming Hive" Reading #1"Programming Hive" Reading #1
"Programming Hive" Reading #1
moai kids
 
Javaで簡単にgpgpu aparapi
Javaで簡単にgpgpu aparapiJavaで簡単にgpgpu aparapi
Javaで簡単にgpgpu aparapi
Ken'ichi Sakiyama
 
第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」
yoshiaki iwanaga
 

Was ist angesagt? (20)

ラムダと invokedynamic の蜜月
ラムダと invokedynamic の蜜月ラムダと invokedynamic の蜜月
ラムダと invokedynamic の蜜月
 
Node-v0.12の新機能について
Node-v0.12の新機能についてNode-v0.12の新機能について
Node-v0.12の新機能について
 
続・SECDマシン
続・SECDマシン続・SECDマシン
続・SECDマシン
 
How to debug a perl script using gdb
How to debug a perl script using gdbHow to debug a perl script using gdb
How to debug a perl script using gdb
 
はじめてのRuby拡張ライブラリ
はじめてのRuby拡張ライブラリはじめてのRuby拡張ライブラリ
はじめてのRuby拡張ライブラリ
 
"Programming Hive" Reading #1
"Programming Hive" Reading #1"Programming Hive" Reading #1
"Programming Hive" Reading #1
 
SystemV IPC
SystemV IPCSystemV IPC
SystemV IPC
 
Lisp Tutorial for Pythonista : Day 4
Lisp Tutorial for Pythonista : Day 4Lisp Tutorial for Pythonista : Day 4
Lisp Tutorial for Pythonista : Day 4
 
Java 9で進化する診断ツール
Java 9で進化する診断ツールJava 9で進化する診断ツール
Java 9で進化する診断ツール
 
JEP280: Java 9 で文字列結合の処理が変わるぞ!準備はいいか!? #jjug_ccc
JEP280: Java 9 で文字列結合の処理が変わるぞ!準備はいいか!? #jjug_cccJEP280: Java 9 で文字列結合の処理が変わるぞ!準備はいいか!? #jjug_ccc
JEP280: Java 9 で文字列結合の処理が変わるぞ!準備はいいか!? #jjug_ccc
 
Improvement future api
Improvement future apiImprovement future api
Improvement future api
 
about Perl5.10
about Perl5.10about Perl5.10
about Perl5.10
 
Javaで簡単にgpgpu aparapi
Javaで簡単にgpgpu aparapiJavaで簡単にgpgpu aparapi
Javaで簡単にgpgpu aparapi
 
第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」
 
Heliumエンジンの設計と実装
Heliumエンジンの設計と実装Heliumエンジンの設計と実装
Heliumエンジンの設計と実装
 
PHP AST 徹底解説(補遺)
PHP AST 徹底解説(補遺)PHP AST 徹底解説(補遺)
PHP AST 徹底解説(補遺)
 
20160730 fluentd meetup in matsue slide
20160730 fluentd meetup in matsue slide20160730 fluentd meetup in matsue slide
20160730 fluentd meetup in matsue slide
 
Introduction to cython
Introduction to cythonIntroduction to cython
Introduction to cython
 
コンピューティングとJava~なにわTECH道
コンピューティングとJava~なにわTECH道コンピューティングとJava~なにわTECH道
コンピューティングとJava~なにわTECH道
 
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するCEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
 

Ähnlich wie Perlと出会い、Perlを作る

東京Node学園#3 Domains & Isolates
東京Node学園#3 Domains & Isolates東京Node学園#3 Domains & Isolates
東京Node学園#3 Domains & Isolates
koichik
 
Python Kyoto study
Python Kyoto studyPython Kyoto study
Python Kyoto study
Naoya Inada
 
Kai = (Dynamo + memcache API) / Erlang
Kai = (Dynamo + memcache API) / ErlangKai = (Dynamo + memcache API) / Erlang
Kai = (Dynamo + memcache API) / Erlang
Takeru INOUE
 
関ジャバ JavaOne Tokyo 2012報告会
関ジャバ JavaOne Tokyo 2012報告会関ジャバ JavaOne Tokyo 2012報告会
関ジャバ JavaOne Tokyo 2012報告会
Koichi Sakata
 
MySQLのプロトコル解説
MySQLのプロトコル解説MySQLのプロトコル解説
MySQLのプロトコル解説
Masahiro Tomita
 
今さら聞けないHadoop勉強会第3回 セントラルソフト株式会社(20120327)
今さら聞けないHadoop勉強会第3回 セントラルソフト株式会社(20120327)今さら聞けないHadoop勉強会第3回 セントラルソフト株式会社(20120327)
今さら聞けないHadoop勉強会第3回 セントラルソフト株式会社(20120327)
YoheiOkuyama
 

Ähnlich wie Perlと出会い、Perlを作る (20)

Prosym2012
Prosym2012Prosym2012
Prosym2012
 
x86とコンテキストスイッチ
x86とコンテキストスイッチx86とコンテキストスイッチ
x86とコンテキストスイッチ
 
ATN No.2 Scala事始め
ATN No.2 Scala事始めATN No.2 Scala事始め
ATN No.2 Scala事始め
 
Rの高速化
Rの高速化Rの高速化
Rの高速化
 
Apache Spark チュートリアル
Apache Spark チュートリアルApache Spark チュートリアル
Apache Spark チュートリアル
 
ROP Illmatic: Exploring Universal ROP on glibc x86-64 (ja)
ROP Illmatic: Exploring Universal ROP on glibc x86-64 (ja)ROP Illmatic: Exploring Universal ROP on glibc x86-64 (ja)
ROP Illmatic: Exploring Universal ROP on glibc x86-64 (ja)
 
東京Node学園#3 Domains & Isolates
東京Node学園#3 Domains & Isolates東京Node学園#3 Domains & Isolates
東京Node学園#3 Domains & Isolates
 
Python Kyoto study
Python Kyoto studyPython Kyoto study
Python Kyoto study
 
Kai = (Dynamo + memcache API) / Erlang
Kai = (Dynamo + memcache API) / ErlangKai = (Dynamo + memcache API) / Erlang
Kai = (Dynamo + memcache API) / Erlang
 
Lispmeetup #53 PythonベースのLisp方言、 Hyのすすめ
Lispmeetup #53 PythonベースのLisp方言、 HyのすすめLispmeetup #53 PythonベースのLisp方言、 Hyのすすめ
Lispmeetup #53 PythonベースのLisp方言、 Hyのすすめ
 
関ジャバ JavaOne Tokyo 2012報告会
関ジャバ JavaOne Tokyo 2012報告会関ジャバ JavaOne Tokyo 2012報告会
関ジャバ JavaOne Tokyo 2012報告会
 
講座Java入門
講座Java入門講座Java入門
講座Java入門
 
Python physicalcomputing
Python physicalcomputingPython physicalcomputing
Python physicalcomputing
 
Boost Tour 1.50.0 All
Boost Tour 1.50.0 AllBoost Tour 1.50.0 All
Boost Tour 1.50.0 All
 
MySQLのプロトコル解説
MySQLのプロトコル解説MySQLのプロトコル解説
MySQLのプロトコル解説
 
Spmv9forpublic
Spmv9forpublicSpmv9forpublic
Spmv9forpublic
 
DTraceによるMySQL解析ことはじめ
DTraceによるMySQL解析ことはじめDTraceによるMySQL解析ことはじめ
DTraceによるMySQL解析ことはじめ
 
Introduction of Python
Introduction of PythonIntroduction of Python
Introduction of Python
 
PHP AST 徹底解説
PHP AST 徹底解説PHP AST 徹底解説
PHP AST 徹底解説
 
今さら聞けないHadoop勉強会第3回 セントラルソフト株式会社(20120327)
今さら聞けないHadoop勉強会第3回 セントラルソフト株式会社(20120327)今さら聞けないHadoop勉強会第3回 セントラルソフト株式会社(20120327)
今さら聞けないHadoop勉強会第3回 セントラルソフト株式会社(20120327)
 

Perlと出会い、Perlを作る

  • 1. Perlと出会い、Perlを作る 株式会社ミクシィ Masaaki Goshima(@goccy54)
  • 2. Perl作成を決意 • 「深く理解したいなら作る」という モットーのもと、学ぶなら作って学びた い! – どうせなら、スクリプト言語界最速のPerlを作りたい
  • 3. gperl • 世界一高速なPerl処理系を目指している • 大目標はPerl5.16とある程度互換性を持 ち, mixiのホーム画面を表示させるスクリプ ト(home.pl)を動かすこと • C++でスクラッチから実装 – 依存ライブラリは極力入れない方針 • (readlineも自作)
  • 4. アジェンダ • gperlの概要と性能評価 • 高速化技術あれこれ • 高速化のために断念したPerlの仕様 • まとめ
  • 5. gperlの概要(Speed) • 導入済みの高速化技術 – asmベースの2番地コード命令 – Register型VM – Direct Threaded Codeを用いた 高速関数呼び出し – 引数オブジェクトの事前構築 – NaN-boxingによる型検査 – アノテーションによるStatic Typingの実現 – JIT Compile
  • 6. gperlの概要(Syntax) • サポートされている文法やデータ構造 – データ型 : int, double, String, Array(Ref), Hash(Ref), CodeRef, B lessedObject – ループ: for, while, foreach – 条件文: if-elsif-else – 関数呼び出し(再帰処理可)とクラス作成(package) – 演算子(一部) : +, -, *, /, +=, -=, ++, -- , <<, >>, <, >, <=, >=, !=, == – その他: ローカル変数, 複数変数の宣言と代入など
  • 7. 性能評価(1/3) Fibonacci数列の計算 N=35 Language time(real)[sec] X(倍率) gperl(JIT) 0.10 X91.2 測定環境 LuaJIT(2.0.0-beta10) 0.12 X76.0 v8(0.8.0) 0.18 X50.6 MacOSX(10.7.4) 2.2GHz Intel Core i7 gperl(StaticTyping) 0.44 X20.7 Memory: 8GB gperl 0.46 X19.8 Darwin Kernel Version 11.4.0 x86_64 Konoha(1.0) 0.52 X17.5 PyPy(1.9.0) 0.53 X17.2 SpiderMonkey(1.8.5) 2.17 X4.2 Lua(5.2.1) 2.82 X3.2 測れるもの Ruby(1.9.3) 3.65 X2.5 数値演算速度 Python(2.7.3) 4.32 X2.1 関数呼び出し速度 VM設計の良し悪し Perl(5.16.0) 9.12 X1.0
  • 8. 性能評価(2/3) たらい回し関数の計算 (x,y,z) = (13, 6, 0) Language time(real)[sec] X(倍率) gperl(JIT) 0.29 X102.0 測定環境 v8(0.8.0) 0.41 X72.1 LuaJIT(2.0.0-beta10) MacOSX(10.7.4) 0.46 X64.3 2.2GHz Intel Core i7 gperl(StaticTyping) 1.24 X23.9 Memory: 8GB Darwin Kernel Version Konoha(1.0) 1.38 X21.4 11.4.0 x86_64 gperl 1.56 X19.0 PyPy(1.9.0) 4.30 X6.9 SpiderMonkey(1.8.5) 5.70 X5.2 測れるもの Lua(5.2.1) 5.97 X5.0 複数引数の処理 Ruby(1.9.3) 7.63 X3.9 数値演算速度 関数呼び出し速度 Python(2.7.3) 17.18 X1.7 VM設計の良し悪し Perl(5.16.0) 29.59 X1.0
  • 9. 性能評価(3/3) binary-trees N=15 Language time(real)[sec] X(倍率) v8(0.8.0) 0.32 X35.8 測定環境 LuaJIT(2.0.0-beta10) 1.29 X8.9 MacOSX(10.7.4) Konoha(1.0) 1.46 X7.9 2.2GHz Intel Core i7 Memory: 8GB PyPy(1.9.0) 1.98 X5.8 Darwin Kernel Version Python(2.7.3) 2.25 X5.1 11.4.0 x86_64 gperl(Static Typing) 3.97 X2.9 gperl 4.06 X2.8 Ruby(1.9.3) 5.23 X2.2 SpiderMonkey(5.7.3) 5.73 X2.0 測れるもの Lua(5.2.1) 7.56 X1.5 GCの速度 Perl(5.16.0) 11.47 X1.0
  • 11. 引数オブジェクトの事前構築(1/2) • 引数格納用の配列を事前構築して高速化 – Perlは, シンプルに実装すると関数呼び出しのた びに引数用の配列オブジェクトが作られる • 関数呼び出しの度に配列を生成すると遅い – 通常、引数の数は一定数以下に抑えられてコー ディングされるため、あらかじめ引数用の配列を 確保しておくことで対処する
  • 12. 引数オブジェクトの事前構築(2/2) 関数呼び出しスタックの一つ一つに対応して ・・・・ 関数呼び出しスタック 引数用の配列を事前に作り、引数はそこに積まれる スタックの伸びる方向 3 4 5 1 :subf { 2 : my $a = $_[0]; 2 3 4 引数用の配列 3 : my$b= $_[1]; 4 : my$c= $_[2]; 1 2 3 5 : if ($a > 10) { 6 : return 1; 7 : } 8 : returnf(++$a, ++$b, ++$c); 9 :} 関数が呼ばれるとstack_topが一つ上がる 10 :f(1, 2, 3); 関数から抜けると一つ下がる しかしPerlには、引数が一定数以下に抑えられるという常識が通じない 仕様があるため、一筋縄ではいかない =>後述
  • 13. NaN-boxingによる型検査(1/2) • Perlのような動的型付け言語は、変数の型を保 存する仕組みが必要 – 通常は、値(int, double, boolean)であっても、オブ ジェクトとして扱い、型情報を持たせる(boxing) – しかしboxingしてあると、計算の時に毎回オブジェク トから値を取り出す操作(unboxing)が入るため遅い. また、全てオブジェクトにするためメモリ効率も悪 くなる case ADD: structIntObject { Object *a = reg[0]; Object *b = reg[1]; inttype; //型情報 if (a->type == TypeInt&&b->type == TypeInt) { intdata; //実際の値 ((IntObject *)a)->data += ((IntObject *)b)->data; }; } else if (a->type == TypeString&&b->type == TypeString) { …… }
  • 14. NaN-boxingによる型検査(2/2) • NaN-boxingは、double型のNaN領域に型 情報を埋め込む技術 – unboxingと同じように扱えて、型情報も持た せられる unboxingされている case ADD: のに型検査できる union{ switch (typecheck(reg[0], reg[1])) { intidata; caseInt_Int: double ddata; reg[0].idata += reg[1].idata;//データに直にアクセスできる char *sdata; break; void *odata; case String_String: }; ….. } しかしPerlには、関数呼び出し時に渡される変数は全てリファレンス として扱われるという仕様があるため、一筋縄ではいかない =>後述
  • 15. アノテーションによる Static Typing/JIT Compileの実現 • 大規模開発を行う場合、型は静的に決定できる 場合がほとんど – 型安全性が損なわれるとバグのもとに – そもそも、開発するときに型のイメージはあるはず • 型を静的に決められるケースが多いなら、その 恩恵を受けようじゃないか – アノテーションを付加することで、静的型付け用の命 令を生成したり, JIT Compileできるようにする
  • 16. アノテーションによる Static Typing/JIT Compileの実現 • 関数の宣言前に、”#@static_typing” or “#@jit_safe”と記述することで、静的型付け用の命 令やJIT用の命令が生成される – #~とすることで、Perlとの互換性を保つ 1: #@static_typing 2: subfib { 型が決まらないと処理できない 3: if ($_[0] < 2) { 命令において、 4: return 1; 初めて処理した時に分かった型 5: } else { を覚えておき、 6: return fib($_[0] - 1) + fib($_[0] - 2); 2回目からは分かった型用の 7: } 命令で処理する 8:} 9:print(fib(35), "n");
  • 19. 1.関数引数にあるリストの展開 • Perlでは, 関数の引数にリストがあるときは, 中 身を展開して一つの配列にしてから関数に渡す – 配列結合のSyntax SugarがPerlでは(@a, @b)で表現 でき、引数では常に有効になる subf{ my@args= @_; print $args[0], "n"; # $args[0] == 1 print $args[1], "n"; # $args[1] == 2 } my@a = (1, 2, 3); my @b= (4, 5, 6); f(@a, @b);
  • 20. 1.関数引数にあるリストの展開 • gperlではあらかじめ引数の数を想定して引数ス タックのサイズを決めているため、引数の数が 多いとスタックを拡張しなければならない gperl内部では@aも一つの subf{ 配列オブジェクトとして扱わ my@args= @_; れているため、そのままだと print $args[0], "n"; # $args[0] == @a $args[0]の値は@aになり、 print $args[1], "n"; # $args[1] == @b $args[1]の値は@bになって } しまう my@a = (1, 2, 3); my @b= (4, 5, 6); これを簡単に避けるために、 f(@a, @b); リストを展開・結合したい場 合は、f((@a, @b))のように呼 び出すルールを決めている
  • 21. 2.デフォルトでのスカラー変数の 参照渡し • Perlでは、関数の引数は全て参照渡しになるの で、明示的にリファレンスにしなくとも、値の 書き変えが可能 subf{ NaN-boxingではこの挙動を $_[0] = 3; 再現できないため、 } $_[0]には$aの スカラー変数のデフォルトでの リファレンスが入っ 参照渡しは未サポート my $a = 1; ているので、値を書 f($a); き変えると元の値も $aを使ってリファレンスを print $a, "n”; 書き変わる 渡すことを明示すれば、 そのときにboxingを行って対処する
  • 22. まとめ • VM、GCやJITなど、ベースとなる技術の 設計や実装はできてきた • 今後の予定 (文法や機能の充実) – 後置文, 三項演算子, format, 正規表現 , map/grep, eval, use/FFI, 継承, 括弧の省略など – ドキュメントの整備 • 研修時に書いたPerlスクリプトがやっと動く ように・・ – 本当の意味で研修内容を理解できた・・・!?