Просмотр исходного кода

test fastpath for `self.*` read (#535)

* test fastpath for `self.*` read

* bak
BLUELOVETH 3 недель назад
Родитель
Сommit
4e2b40db2d
4 измененных файлов с 67 добавлено и 11 удалено
  1. 2 0
      include/pocketpy/xmacros/opcodes.h
  2. 32 11
      src/compiler/compiler.c
  3. 31 0
      src/interpreter/ceval.c
  4. 2 0
      src/modules/dis.c

+ 2 - 0
include/pocketpy/xmacros/opcodes.h

@@ -27,6 +27,7 @@ OPCODE(LOAD_NAME)
 OPCODE(LOAD_NONLOCAL)
 OPCODE(LOAD_NONLOCAL)
 OPCODE(LOAD_GLOBAL)
 OPCODE(LOAD_GLOBAL)
 OPCODE(LOAD_ATTR)
 OPCODE(LOAD_ATTR)
+OPCODE(LOAD_SELF_ATTR)
 OPCODE(LOAD_CLASS_GLOBAL)
 OPCODE(LOAD_CLASS_GLOBAL)
 OPCODE(LOAD_METHOD)
 OPCODE(LOAD_METHOD)
 OPCODE(LOAD_SUBSCR)
 OPCODE(LOAD_SUBSCR)
@@ -35,6 +36,7 @@ OPCODE(STORE_FAST)
 OPCODE(STORE_NAME)
 OPCODE(STORE_NAME)
 OPCODE(STORE_GLOBAL)
 OPCODE(STORE_GLOBAL)
 OPCODE(STORE_ATTR)
 OPCODE(STORE_ATTR)
+OPCODE(STORE_SELF_ATTR)
 OPCODE(STORE_SUBSCR)
 OPCODE(STORE_SUBSCR)
 
 
 OPCODE(DELETE_FAST)
 OPCODE(DELETE_FAST)

+ 32 - 11
src/compiler/compiler.c

@@ -60,6 +60,7 @@ typedef struct Expr {
 typedef struct Ctx {
 typedef struct Ctx {
     CodeObject* co;  // 1 CodeEmitContext <=> 1 CodeObject*
     CodeObject* co;  // 1 CodeEmitContext <=> 1 CodeObject*
     FuncDecl* func;  // optional, weakref
     FuncDecl* func;  // optional, weakref
+    py_Name n_self;
     int level;
     int level;
     int curr_iblock;
     int curr_iblock;
     bool is_compiling_class;
     bool is_compiling_class;
@@ -70,7 +71,7 @@ typedef struct Ctx {
 
 
 typedef struct Expr Expr;
 typedef struct Expr Expr;
 
 
-static void Ctx__ctor(Ctx* self, CodeObject* co, FuncDecl* func, int level);
+static void Ctx__ctor(Ctx* self, CodeObject* co, FuncDecl* func, int level, py_Name n_self);
 static void Ctx__dtor(Ctx* self);
 static void Ctx__dtor(Ctx* self);
 static int Ctx__prepare_loop_divert(Ctx* self, int line, bool is_break);
 static int Ctx__prepare_loop_divert(Ctx* self, int line, bool is_break);
 static int Ctx__enter_block(Ctx* self, CodeBlockType type);
 static int Ctx__enter_block(Ctx* self, CodeBlockType type);
@@ -732,9 +733,9 @@ static void NamedExpr__dtor(Expr* self_) {
 
 
 static void NamedExpr__emit_(Expr* self_, Ctx* ctx) {
 static void NamedExpr__emit_(Expr* self_, Ctx* ctx) {
     NamedExpr* self = (NamedExpr*)self_;
     NamedExpr* self = (NamedExpr*)self_;
-    vtemit_(self->rhs, ctx);                              // [value]
-    Ctx__emit_(ctx, OP_DUP_TOP, BC_NOARG, self->line);   // [value, value]
-    vtemit_store((Expr*)self->name, ctx);                 // [value]
+    vtemit_(self->rhs, ctx);                            // [value]
+    Ctx__emit_(ctx, OP_DUP_TOP, BC_NOARG, self->line);  // [value, value]
+    vtemit_store((Expr*)self->name, ctx);               // [value]
 }
 }
 
 
 static NamedExpr* NamedExpr__new(int line, NameExpr* name, Expr* rhs) {
 static NamedExpr* NamedExpr__new(int line, NameExpr* name, Expr* rhs) {
@@ -997,8 +998,23 @@ void AttribExpr__dtor(Expr* self_) {
     vtdelete(self->child);
     vtdelete(self->child);
 }
 }
 
 
+static bool is_self_xxx(Expr* child, Ctx* ctx) {
+    if(child->vt->is_name) {
+        NameExpr* ne = (NameExpr*)child;
+        if(ne->scope == NAME_LOCAL && ne->name == ctx->n_self) {
+            int index = c11_smallmap_n2d__get(&ctx->co->varnames_inv, ne->name, -1);
+            if(index == 0) return true;
+        }
+    }
+    return false;
+}
+
 void AttribExpr__emit_(Expr* self_, Ctx* ctx) {
 void AttribExpr__emit_(Expr* self_, Ctx* ctx) {
     AttribExpr* self = (AttribExpr*)self_;
     AttribExpr* self = (AttribExpr*)self_;
+    if(is_self_xxx(self->child, ctx)) {
+        Ctx__emit_(ctx, OP_LOAD_SELF_ATTR, Ctx__add_name(ctx, self->name), self->line);
+        return;
+    }
     vtemit_(self->child, ctx);
     vtemit_(self->child, ctx);
     Ctx__emit_(ctx, OP_LOAD_ATTR, Ctx__add_name(ctx, self->name), self->line);
     Ctx__emit_(ctx, OP_LOAD_ATTR, Ctx__add_name(ctx, self->name), self->line);
 }
 }
@@ -1012,6 +1028,10 @@ bool AttribExpr__emit_del(Expr* self_, Ctx* ctx) {
 
 
 bool AttribExpr__emit_store(Expr* self_, Ctx* ctx) {
 bool AttribExpr__emit_store(Expr* self_, Ctx* ctx) {
     AttribExpr* self = (AttribExpr*)self_;
     AttribExpr* self = (AttribExpr*)self_;
+    if(is_self_xxx(self->child, ctx)) {
+        Ctx__emit_(ctx, OP_STORE_SELF_ATTR, Ctx__add_name(ctx, self->name), self->line);
+        return true;
+    }
     vtemit_(self->child, ctx);
     vtemit_(self->child, ctx);
     Ctx__emit_(ctx, OP_STORE_ATTR, Ctx__add_name(ctx, self->name), self->line);
     Ctx__emit_(ctx, OP_STORE_ATTR, Ctx__add_name(ctx, self->name), self->line);
     return true;
     return true;
@@ -1127,9 +1147,10 @@ CallExpr* CallExpr__new(int line, Expr* callable) {
 }
 }
 
 
 /* context.c */
 /* context.c */
-static void Ctx__ctor(Ctx* self, CodeObject* co, FuncDecl* func, int level) {
+static void Ctx__ctor(Ctx* self, CodeObject* co, FuncDecl* func, int level, py_Name n_self) {
     self->co = co;
     self->co = co;
     self->func = func;
     self->func = func;
+    self->n_self = n_self;
     self->level = level;
     self->level = level;
     self->curr_iblock = 0;
     self->curr_iblock = 0;
     self->is_compiling_class = false;
     self->is_compiling_class = false;
@@ -1361,6 +1382,7 @@ typedef struct Compiler {
 
 
     Token* tokens;
     Token* tokens;
     int tokens_length;
     int tokens_length;
+    py_Name n_self;
 
 
     int i;  // current token index
     int i;  // current token index
     c11_vector /*T=CodeEmitContext*/ contexts;
     c11_vector /*T=CodeEmitContext*/ contexts;
@@ -1370,6 +1392,7 @@ static void Compiler__ctor(Compiler* self, SourceData_ src, Token* tokens, int t
     self->src = src;
     self->src = src;
     self->tokens = tokens;
     self->tokens = tokens;
     self->tokens_length = tokens_length;
     self->tokens_length = tokens_length;
+    self->n_self = py_name("self");
     self->i = 0;
     self->i = 0;
     c11_vector__ctor(&self->contexts, sizeof(Ctx));
     c11_vector__ctor(&self->contexts, sizeof(Ctx));
 }
 }
@@ -1540,7 +1563,7 @@ static Error* EXPR_VARS(Compiler* self) {
 static void push_global_context(Compiler* self, CodeObject* co) {
 static void push_global_context(Compiler* self, CodeObject* co) {
     co->start_line = self->i == 0 ? 1 : prev()->line;
     co->start_line = self->i == 0 ? 1 : prev()->line;
     Ctx* ctx = c11_vector__emplace(&self->contexts);
     Ctx* ctx = c11_vector__emplace(&self->contexts);
-    Ctx__ctor(ctx, co, NULL, self->contexts.length);
+    Ctx__ctor(ctx, co, NULL, self->contexts.length, self->n_self);
 }
 }
 
 
 static Error* pop_context(Compiler* self) {
 static Error* pop_context(Compiler* self) {
@@ -1715,9 +1738,7 @@ static Error* exprWalrus(Compiler* self) {
     int line = prev()->line;
     int line = prev()->line;
     // LHS is on the stack; verify it's a simple name
     // LHS is on the stack; verify it's a simple name
     Expr* lhs = Ctx__s_top(ctx());
     Expr* lhs = Ctx__s_top(ctx());
-    if(!lhs->vt->is_name) {
-        return SyntaxError(self, "':=' target must be a simple name");
-    }
+    if(!lhs->vt->is_name) { return SyntaxError(self, "':=' target must be a simple name"); }
     check(parse_expression(self, PREC_NAMED_EXPR + 1, false));
     check(parse_expression(self, PREC_NAMED_EXPR + 1, false));
     Expr* rhs = Ctx__s_popx(ctx());
     Expr* rhs = Ctx__s_popx(ctx());
     NameExpr* name = (NameExpr*)Ctx__s_popx(ctx());
     NameExpr* name = (NameExpr*)Ctx__s_popx(ctx());
@@ -1940,7 +1961,7 @@ static Error* exprCall(Compiler* self) {
     Error* err;
     Error* err;
     Expr* callable = Ctx__s_popx(ctx());
     Expr* callable = Ctx__s_popx(ctx());
     int line = prev()->line;
     int line = prev()->line;
-    
+
     CallExpr* e = CallExpr__new(line, callable);
     CallExpr* e = CallExpr__new(line, callable);
     Ctx__s_push(ctx(), (Expr*)e);  // push onto the stack in advance
     Ctx__s_push(ctx(), (Expr*)e);  // push onto the stack in advance
     do {
     do {
@@ -2289,7 +2310,7 @@ static FuncDecl_ push_f_context(Compiler* self, c11_sv name, int* out_index) {
     *out_index = top_ctx->co->func_decls.length - 1;
     *out_index = top_ctx->co->func_decls.length - 1;
     // push new context
     // push new context
     top_ctx = c11_vector__emplace(&self->contexts);
     top_ctx = c11_vector__emplace(&self->contexts);
-    Ctx__ctor(top_ctx, &decl->code, decl, self->contexts.length);
+    Ctx__ctor(top_ctx, &decl->code, decl, self->contexts.length, self->n_self);
     return decl;
     return decl;
 }
 }
 
 

+ 31 - 0
src/interpreter/ceval.c

@@ -325,6 +325,23 @@ __NEXT_STEP:
             }
             }
             DISPATCH();
             DISPATCH();
         }
         }
+        case OP_LOAD_SELF_ATTR: {
+            assert(!frame->is_locals_special);
+            py_Ref val = &frame->locals[0];
+            if(!py_isnil(val)) {
+                // LOAD_ATTR
+                py_Name name = co_names[byte.arg];
+                if(py_getattr(val, name)) {
+                    PUSH(py_retval());
+                } else {
+                    goto __ERROR;
+                }
+                DISPATCH();
+            }
+            py_Name name = c11__getitem(py_Name, &frame->co->varnames, byte.arg);
+            UnboundLocalError(name);
+            goto __ERROR;
+        }
         case OP_LOAD_CLASS_GLOBAL: {
         case OP_LOAD_CLASS_GLOBAL: {
             assert(self->curr_class);
             assert(self->curr_class);
             py_Name name = co_names[byte.arg];
             py_Name name = co_names[byte.arg];
@@ -427,6 +444,20 @@ __NEXT_STEP:
             STACK_SHRINK(2);
             STACK_SHRINK(2);
             DISPATCH();
             DISPATCH();
         }
         }
+        case OP_STORE_SELF_ATTR: {
+            assert(!frame->is_locals_special);
+            py_Ref val = &frame->locals[0];
+            if(!py_isnil(val)) {
+                // [val, a] -> a.b = val
+                py_Name name = co_names[byte.arg];
+                if(!py_setattr(val, name, TOP())) goto __ERROR;
+                POP();
+                DISPATCH();
+            }
+            py_Name name = c11__getitem(py_Name, &frame->co->varnames, byte.arg);
+            UnboundLocalError(name);
+            goto __ERROR;
+        }
         case OP_STORE_SUBSCR: {
         case OP_STORE_SUBSCR: {
             // [val, a, b] -> a[b] = val
             // [val, a, b] -> a[b] = val
             py_Ref magic = py_tpfindmagic(SECOND()->type, __setitem__);
             py_Ref magic = py_tpfindmagic(SECOND()->type, __setitem__);

+ 2 - 0
src/modules/dis.c

@@ -77,8 +77,10 @@ static bool disassemble(CodeObject* co) {
                 case OP_LOAD_NONLOCAL:
                 case OP_LOAD_NONLOCAL:
                 case OP_STORE_GLOBAL:
                 case OP_STORE_GLOBAL:
                 case OP_LOAD_ATTR:
                 case OP_LOAD_ATTR:
+                case OP_LOAD_SELF_ATTR:
                 case OP_LOAD_METHOD:
                 case OP_LOAD_METHOD:
                 case OP_STORE_ATTR:
                 case OP_STORE_ATTR:
+                case OP_STORE_SELF_ATTR:
                 case OP_DELETE_ATTR:
                 case OP_DELETE_ATTR:
                 case OP_BEGIN_CLASS:
                 case OP_BEGIN_CLASS:
                 case OP_DELETE_GLOBAL:
                 case OP_DELETE_GLOBAL: