読者です 読者をやめる 読者になる 読者になる

言語のしくみを読む

2-6キャッシュとシンボル

stringを生成するためのstruct sym_keyが新たに定義されている。
渡された文字列の特徴からハッシュ値を取り出している。
これがシンボル検索の高速化に寄与しているのかな?
khash.hが新規に追加,string.cが大幅な書き換えとなっている。

言語のしくみを読む

2-5マルチスレッドとオブジェクト

core.cのstrm_loop関数を中心にマルチスレッド対応になっている。
queue.cにpush_high_task,push_low_task関数が追加などの変更がある。
ncpu.c,string.c,value.cが新規で入っている
srcフォルダにも新規ファイルが入っているがコンパイルの方法がわからないので
パス。
libフォルダでコンパイルすると-lgcが見つからないとのエラー
sudo apt-get install libgc-dev
コンパイル成功a.outができる

<メモ>
GitKrakenのFullScreenを戻す方法:shift+ctrl+F (ubuntu)

pythonのソースコードを調べる

Objectsフォルダの中身を調べる
それっぽい名前としては

boolobject.c
bytearrayobject.c
bytesobject.c
cellobject.c
classobject.c
codeobject.c
complexobject.c
descrobject.c
dictobject.c
enumobject.c
fileobject.c
floatobject.c
frameobject.c
funcobject.c
genobject.c
iterobject.c
listobject.c
longobject.c
memoryobject.c
methodobject.c
moduleobject.c
namespaceobject.c
object.c
odictobject

object.cの主な関数(?)

void _Py_AddToAllObjects(PyObject op, int force) void Py_IncRef(PyObject o)
void Py_DecRef(PyObject *o)
PyObject * PyObject_Init(PyObject op, PyTypeObject tp)
PyVarObject * PyObject_InitVar(PyVarObject op, PyTypeObject tp, Py_ssize_t size)
PyObject * _PyObject_New(PyTypeObject *tp)
PyVarObject * _PyObject_NewVar(PyTypeObject *tp, Py_ssize_t nitems)
void PyObject_CallFinalizer(PyObject *self)
int PyObject_CallFinalizerFromDealloc(PyObject *self)
int PyObject_Print(PyObject op, FILE fp, int flags)
void _PyObject_Dump(PyObject* op)
PyObject * PyObject_Repr(PyObject *v)
PyObject * PyObject_Str(PyObject *v)
PyObject * PyObject_ASCII(PyObject *v)
PyObject * PyObject_Bytes(PyObject *v)
int _Py_SwappedOp = {Py_GT, Py_GE, Py_EQ, Py_NE, Py_LT, Py_LE};
static char *opstrings = {“<”, “<=”, “==”, “!=”, “>”, “>=”};
static PyObject * do_richcompare(PyObject v, PyObject w, int op)
PyObject * PyObject_RichCompare(PyObject v, PyObject w, int op)
int PyObject_RichCompareBool(PyObject v, PyObject w, int op)
Py_hash_t PyObject_HashNotImplemented(PyObject *v)
Py_hash_t PyObject_Hash(PyObject *v)
PyObject * PyObject_GetAttrString(PyObject v, const char name)
int PyObject_HasAttrString(PyObject v, const char name)
int PyObject_SetAttrString(PyObject v, const char name, PyObject *w)
int _PyObject_IsAbstract(PyObject *obj)
PyObject * PyObject_GetAttrId(PyObject *v, Py_Identifier *name)
int PyObject_HasAttrId(PyObject *v, Py_Identifier *name)
int PyObject_SetAttrId(PyObject *v, Py_Identifier name, PyObject w)
PyObject * PyObject_GetAttr(PyObject v, PyObject name)
int PyObject_HasAttr(PyObject v, PyObject name)
int PyObject_SetAttr(PyObject v, PyObject name, PyObject *value)
PyObject * _PyObject_GetDictPtr(PyObject obj)
PyObject * PyObject_SelfIter(PyObject *obj)
PyObject * _PyObject_GetBuiltin(const char *name)
PyObject * _PyObject_NextNotImplemented(PyObject *self)
PyObject * _PyObject_GenericGetAttrWithDict(PyObject obj, PyObject name, PyObject *dict)
PyObject * PyObject_GenericGetAttr(PyObject obj, PyObject name)
int _PyObject_GenericSetAttrWithDict(PyObject obj, PyObject name, PyObject value, PyObject dict)
int PyObject_GenericSetAttr(PyObject obj, PyObject name, PyObject *value)
int PyObject_GenericSetDict(PyObject obj, PyObject value, void *context)
int PyObject_IsTrue(PyObject *v)
int PyObject_Not(PyObject *v)
int PyCallable_Check(PyObject *x)
static PyObject * _dir_locals(void)
static PyObject * _dir_object(PyObject *obj)
PyObject * PyObject_Dir(PyObject *obj)
static PyObject * none_repr(PyObject *op)
static void none_dealloc(PyObject* ignore)
static PyObject * none_new(PyTypeObject type, PyObject args, PyObject *kwargs)
static int none_bool(PyObject *v)
static PyNumberMethods none_as_number = { 0, / nb_add / 0, / nb_subtract / 0, / nb_multiply / 0, / nb_remainder / 0, / nb_divmod / 0, / nb_power / 0, / nb_negative / 0, / nb_positive / 0, / nb_absolute / (inquiry)none_bool, / nb_bool / 0, / nb_invert / 0, / nb_lshift / 0, / nb_rshift / 0, / nb_and / 0, / nb_xor / 0, / nb_or / 0, / nb_int / 0, / nb_reserved / 0, / nb_float / 0, / nb_inplace_add / 0, / nb_inplace_subtract / 0, / nb_inplace_multiply / 0, / nb_inplace_remainder / 0, / nb_inplace_power / 0, / nb_inplace_lshift / 0, / nb_inplace_rshift / 0, / nb_inplace_and / 0, / nb_inplace_xor / 0, / nb_inplace_or / 0, / nb_floor_divide / 0, / nb_true_divide / 0, / nb_inplace_floor_divide / 0, / nb_inplace_true_divide / 0, / nb_index / };
PyTypeObject _PyNone_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) “NoneType”, 0, 0, none_dealloc, /tp_dealloc/ /never called/ 0, /tp_print/ 0, /tp_getattr/ 0, /tp_setattr/ 0, /tp_reserved/ none_repr, /tp_repr/ &none_as_number, /tp_as_number/ 0, /tp_as_sequence/ 0, /tp_as_mapping/ 0, /tp_hash / 0, /tp_call / 0, /tp_str / 0, /tp_getattro / 0, /tp_setattro / 0, /tp_as_buffer / Py_TPFLAGS_DEFAULT, /tp_flags / 0, /tp_doc / 0, /tp_traverse / 0, /tp_clear / 0, /tp_richcompare / 0, /tp_weaklistoffset / 0, /tp_iter / 0, /tp_iternext / 0, /tp_methods / 0, /tp_members / 0, /tp_getset / 0, /tp_base / 0, /tp_dict / 0, /tp_descr_get / 0, /tp_descr_set / 0, /tp_dictoffset / 0, /tp_init / 0, /tp_alloc / none_new, /tp_new / };
PyObject Py_NoneStruct = { PyObject_EXTRA_INIT 1, &_PyNone_Type };
static PyObject * NotImplemented_repr(PyObject *op)
static PyObject * NotImplemented_reduce(PyObject *op) static PyMethodDef notimplemented_methods[] = { {“reduce”, (PyCFunction)NotImplemented_reduce, METH_NOARGS, NULL}, {NULL, NULL} };
static PyObject * notimplemented_new(PyTypeObject type, PyObject args, PyObject *kwargs)
static void notimplemented_dealloc(PyObject* ignore)
PyTypeObject _PyNotImplemented_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) “NotImplementedType”, 0, 0, notimplemented_dealloc, /tp_dealloc/ /never called/ 0, /tp_print/ 0, /tp_getattr/ 0, /tp_setattr/ 0, /tp_reserved/ NotImplemented_repr, /tp_repr/ 0, /tp_as_number/ 0, /tp_as_sequence/ 0, /tp_as_mapping/ 0, /tp_hash / 0, /tp_call / 0, /tp_str / 0, /tp_getattro / 0, /tp_setattro / 0, /tp_as_buffer / Py_TPFLAGS_DEFAULT, /tp_flags / 0, /tp_doc / 0, /tp_traverse / 0, /tp_clear / 0, /tp_richcompare / 0, /tp_weaklistoffset / 0, /tp_iter / 0, /tp_iternext / notimplemented_methods, /tp_methods / 0, /tp_members / 0, /tp_getset / 0, /tp_base / 0, /tp_dict / 0, /tp_descr_get / 0, /tp_descr_set / 0, /tp_dictoffset / 0, /tp_init / 0, /tp_alloc / notimplemented_new, /tp_new / };
PyObject Py_NotImplementedStruct = { PyObject_EXTRA_INIT 1, &_PyNotImplemented_Type };
void _Py_ReadyTypes(void)
void _Py_NewReference(PyObject *op)
void _Py_ForgetReference(PyObject *op)
void _Py_Dealloc(PyObject *op)
void _Py_PrintReferences(FILE *fp)
void _Py_PrintReferenceAddresses(FILE *fp)
PyObject * _Py_GetObjects(PyObject self, PyObject args)
Py_ssize_t (_Py_abstract_hack)(PyObject ) = PyObject_Size;
void _PyObject_DebugTypeStats(FILE *out)
int Py_ReprEnter(PyObject *obj)
void Py_ReprLeave(PyObject *obj)
int _PyTrash_delete_nesting = 0;
PyObject *_PyTrash_delete_later = NULL;
void _PyTrash_deposit_object(PyObject *op)
void _PyTrash_thread_deposit_object(PyObject *op)
void _PyTrash_destroy_chain(void)
void _PyTrash_thread_destroy_chain(void)
PyAPI_FUNC(void) Py_Dealloc(PyObject *); void Py_Dealloc(PyObject *op)

言語のしくみを読む

2-4イベントループ

Gitkrakenのタグを201503に移動させてlibフォルダを見ると
main.c core.c io.c queue.cがはいており
$ makeでa.outファイルができた。
$ ./a.outで入力待機状態になったようなのでstreemと
入力するとSTREEMと標準出力に表示された。
停止方法はないようなのでCTLR+Cで停止

main.cが全体の初期化と実行
core.cがメインループの制御(strm_loop関数)
io.cが標準入力、出力の制御、I/Oループの制御(io_loop関数)
queue.cがキューの制御(strm_queue_push関数がイベントを積み strm_queue_exec関数がイベントを降ろして実行)

言語のしくみを読む

2-3文法チエッカーをまず作る

Ubuntu16.04LTS(64bit)にGitクライアントのGitKrakenをinstallした。
GitKrakenに https://github.com/matz/streemをクローンさせて手元にリポジトリを作る
最初のタグ201502に移動してResr master to this commit>Hard-discard all changesを実行させると リポジトリ内フォルダ(streem/src)に「Makefile lex.l parse.y」ができている。
$ sudo apt install flexflexをインストールしてmakeとコマンドを入力すると

yacc parse.y
flex lex.l
gcc -g - c y.tab.c -o parse.o
gcc parse.o -o streem

と実行され、新たにlex.yy.c parse.o y.tab.c streemファイルが作成されていた。  

tracpath.com

pythonのソースコードを調べる

この構造体のメンバーには接頭子tp_が付けられている。
typeobjectの頭文字と予想される。

typedef struct _typeobject {
    PyObject_VAR_HEAD
    const char *tp_name; /* For printing, in format "<module>.<name>" */ #この構造体の名前を要求されたときのフォーマット?
    Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */ #メモリの上限値?
    /* Methods to implement standard operations */
    destructor tp_dealloc;  #デストラクタ?
    printfunc tp_print;        #プリントファンクション?
    getattrfunc tp_getattr; #この構造体のゲッター?
    setattrfunc tp_setattr; #この構造体のセッタ?
    PyAsyncMethods *tp_as_async; /* formerly known as tp_compare (Python 2)
                                    or tp_reserved (Python 3) */ #?
    reprfunc tp_repr; #?

    /* Method suites for standard classes */

    PyNumberMethods *tp_as_number; #PyObjectが数値だった場合のメソッド(nb_add,nb_subtract,nb_multiply,nb_divmodなどへの関数へのポインタが並んで知る接頭子のnbは?
    PySequenceMethods *tp_as_sequence; #PyObjectがシーケンスタイプのオブジエクトだった場合の構造体。接頭子のsqはシーケンス(sequence)由来と思われる。おそらくリスト、タプルに適用されるのだろう
    PyMappingMethods *tp_as_mapping; #PyObjectがマッピングタイプのオブジエクトだった場合の構造体  辞書に適用されるのだろう。
    /* More standard operations (here for binary compatibility) */
    hashfunc tp_hash; #?
    ternaryfunc tp_call; #?
    reprfunc tp_str; #?
    getattrofunc tp_getattro; #?
    setattrofunc tp_setattro; #?

    /* Functions to access object as input/output buffer */
    PyBufferProcs *tp_as_buffer; #何かのバッフア?

    /* Flags to define presence of optional/expanded features */
    unsigned long tp_flags; #オプション機能/拡張機能の有無を定義するフラグ?

    const char *tp_doc; /* Documentation string */ #ドキュメント文字列へのポインタ?

    /* Assigned meaning in release 2.0 */
    /* call function for all accessible objects */
    traverseproc tp_traverse; #?

    /* delete references to contained objects */
    inquiry tp_clear; #?

    /* Assigned meaning in release 2.1 */
    /* rich comparisons */
    richcmpfunc tp_richcompare; #?

    /* weak reference enabler */
    Py_ssize_t tp_weaklistoffset; #弱い参照?

    /* Iterators */
    getiterfunc tp_iter;
    iternextfunc tp_iternext;

    /* Attribute descriptor and subclassing stuff */
    struct PyMethodDef *tp_methods; #Pythonビルトイン関数/メソッドへのポインタ
    struct PyMemberDef *tp_members; #?
    struct PyGetSetDef *tp_getset; #?
    struct _typeobject *tp_base; #?
    PyObject *tp_dict; #?
    descrgetfunc tp_descr_get; #?
    descrsetfunc tp_descr_set; #?
    Py_ssize_t tp_dictoffset; #?
    initproc tp_init; #?
    allocfunc tp_alloc; #?
    newfunc tp_new; #?
    freefunc tp_free; /* Low-level free-memory routine */ #?
    inquiry tp_is_gc; /* For PyObject_IS_GC */ #ガ-ベージコレクション?
    PyObject *tp_bases; #?
    PyObject *tp_mro; /* method resolution order */ #?
    PyObject *tp_cache; #?
    PyObject *tp_subclasses; #?
    PyObject *tp_weaklist; #?
    destructor tp_del; #?

    /* Type attribute cache version tag. Added in version 2.6 */
    unsigned int tp_version_tag; #?

    destructor tp_finalize; #?
#ifdef COUNT_ALLOCS #なし
    /* these must be last and never explicitly initialized */
    Py_ssize_t tp_allocs;
    Py_ssize_t tp_frees;
    Py_ssize_t tp_maxalloc;
    struct _typeobject *tp_prev;
    struct _typeobject *tp_next;
#endif
} PyTypeObject;

構造体の先頭にあるPyObject_VAR_HEADはPyVarObjectを表すマクロ
PyVarObjectはPyObjectにPy_ssize_t ob_sizeを追加して拡張したもののようである。

pythonのソースコードを調べる

もっとも頻度の高いキーワードPyObjectは Includeフォルダのobject.h内に定義してある
構造体でした。

postd.cc

Pythonの全てのオブジエクトの元になっている構造体である。

マクロを展開すると
typedef struct _object {
    struct _object *_ob_next;
    struct _object *_ob_prev;
    Py_ssize_t ob_refcnt;   #longかintの別定義 
    struct _typeobject *ob_type; typestruct.hに定義してある構造体
} PyObject;

_typeobject の定義
typedef struct _typeobject {
    PyObject_VAR_HEAD
    const char *tp_name; /* For printing, in format "<module>.<name>" */
    Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */

    /* Methods to implement standard operations */

    destructor tp_dealloc;
    printfunc tp_print;
    getattrfunc tp_getattr;
    setattrfunc tp_setattr;
    PyAsyncMethods *tp_as_async; /* formerly known as tp_compare (Python 2)
                                    or tp_reserved (Python 3) */
    reprfunc tp_repr;

    /* Method suites for standard classes */

    PyNumberMethods *tp_as_number;
    PySequenceMethods *tp_as_sequence;
    PyMappingMethods *tp_as_mapping;

    /* More standard operations (here for binary compatibility) */

    hashfunc tp_hash;
    ternaryfunc tp_call;
    reprfunc tp_str;
    getattrofunc tp_getattro;
    setattrofunc tp_setattro;

    /* Functions to access object as input/output buffer */
    PyBufferProcs *tp_as_buffer;

    /* Flags to define presence of optional/expanded features */
    unsigned long tp_flags;

    const char *tp_doc; /* Documentation string */

    /* call function for all accessible objects */
    traverseproc tp_traverse;

    /* delete references to contained objects */
    inquiry tp_clear;

    /* rich comparisons */
    richcmpfunc tp_richcompare;

    /* weak reference enabler */
    Py_ssize_t tp_weaklistoffset;

    /* Iterators */
    getiterfunc tp_iter;
    iternextfunc tp_iternext;

    /* Attribute descriptor and subclassing stuff */
    struct PyMethodDef *tp_methods;
    struct PyMemberDef *tp_members;
    struct PyGetSetDef *tp_getset;
    struct _typeobject *tp_base;
    PyObject *tp_dict;
    descrgetfunc tp_descr_get;
    descrsetfunc tp_descr_set;
    Py_ssize_t tp_dictoffset;
    initproc tp_init;
    allocfunc tp_alloc;
    newfunc tp_new;
    freefunc tp_free; /* Low-level free-memory routine */
    inquiry tp_is_gc; /* For PyObject_IS_GC */
    PyObject *tp_bases;
    PyObject *tp_mro; /* method resolution order */
    PyObject *tp_cache;
    PyObject *tp_subclasses;
    PyObject *tp_weaklist;
    destructor tp_del;

    /* Type attribute cache version tag. Added in version 2.6 */
    unsigned int tp_version_tag;

    destructor tp_finalize;

} PyTypeObject;

次はPyTypeObjectを調べよう