diff --git a/src/cffi.h b/src/cffi.h index 1fd0f371..a9939502 100644 --- a/src/cffi.h +++ b/src/cffi.h @@ -9,13 +9,16 @@ namespace pkpy { template struct NativeProxyFunc { - using T = Ret(*)(Params...); + //using T = Ret(*)(Params...); + using T = std::function; static constexpr int N = sizeof...(Params); T func; NativeProxyFunc(T func) : func(func) {} PyVar operator()(VM* vm, Args& args) { - if (args.size() != N) vm->TypeError("invalid number of arguments"); + if (args.size() != N) { + vm->TypeError("expected " + std::to_string(N) + " arguments, but got " + std::to_string(args.size())); + } return call(vm, args, std::make_index_sequence()); } @@ -99,31 +102,27 @@ auto _ = [](){ return 0; }(); - struct Pointer{ PY_CLASS(Pointer, c, ptr_) + const TypeInfo* ctype; // this is immutable + int level; // level of pointer char* ptr; - TypeInfo* ctype; - int level; // level of pointer i64 unit_size() const { return level == 1 ? ctype->size : sizeof(void*); } - bool type_equal(const Pointer& other) const { - return level == other.level && ctype == other.ctype; - } - - Pointer() : ptr(nullptr), ctype(&_type_infos["void"]), level(1) {} - Pointer(char* ptr, TypeInfo* ctype, int level=1) : ptr(ptr), ctype(ctype), level(level) {} + Pointer() : ctype(&_type_infos["void"]), level(1), ptr(nullptr) {} + Pointer(const TypeInfo* ctype, int level, char* ptr): ctype(ctype), level(level), ptr(ptr) {} + Pointer(const TypeInfo* ctype, char* ptr): ctype(ctype), level(1), ptr(ptr) {} Pointer operator+(i64 offset) const { - return Pointer(ptr + offset * unit_size(), ctype, level); + return Pointer(ctype, level, ptr+offset*unit_size()); } Pointer operator-(i64 offset) const { - return Pointer(ptr - offset * unit_size(), ctype, level); + return Pointer(ctype, level, ptr-offset*unit_size()); } static void _register(VM* vm, PyVar mod, PyVar type){ @@ -173,6 +172,12 @@ struct Pointer{ return vm->None; }); + vm->bind_method<1>(type, "__getattr__", [](VM* vm, Args& args) { + Pointer& self = CAST(Pointer&, args[0]); + const Str& name = CAST(Str&, args[1]); + return VAR_T(Pointer, self._to(vm, name)); + }); + vm->bind_method<0>(type, "get", [](VM* vm, Args& args) { Pointer& self = CAST(Pointer&, args[0]); return self.get(vm); @@ -183,13 +188,28 @@ struct Pointer{ self.set(vm, args[1]); return vm->None; }); + + vm->bind_method<1>(type, "cast", [](VM* vm, Args& args) { + Pointer& self = CAST(Pointer&, args[0]); + const Str& name = CAST(Str&, args[1]); + int level = 0; + for(int i=name.size()-1; i>=0; i--){ + if(name[i] == '*') level++; + else break; + } + if(level == 0) vm->TypeError("expect a pointer type, such as 'int*'"); + Str type = name.substr(0, name.size()-level); + auto it = _type_infos.find(type); + if(it == _type_infos.end()) vm->TypeError("unknown type: " + type.escape(true)); + return VAR_T(Pointer, &it->second, level, self.ptr); + }); } template inline T& ref() noexcept { return *reinterpret_cast(ptr); } PyVar get(VM* vm){ - if(level > 1) return VAR_T(Pointer, ptr, ctype, level-1); + if(level > 1) return VAR_T(Pointer, ctype, level-1, ref()); switch(ctype->index){ #define CASE(T) case type_index(): return VAR(ref()) case type_index(): vm->ValueError("cannot get void*"); break; @@ -214,7 +234,7 @@ struct Pointer{ void set(VM* vm, const PyVar& val){ if(level > 1) { Pointer& p = CAST(Pointer&, val); - ref() = p.ptr; // We don't check the type, just copy the underlying address + ref() = p.ptr; // We don't check the type, just copy the underlying address return; } switch(ctype->index){ @@ -234,17 +254,17 @@ struct Pointer{ CASE(double, f64); CASE(bool, bool); #undef CASE + default: UNREACHABLE(); } - UNREACHABLE(); } - Pointer address(VM* vm, StrName name){ + Pointer _to(VM* vm, StrName name){ auto it = ctype->members.find(name); if(it == ctype->members.end()){ vm->AttributeError(Str("struct '") + ctype->name + "' has no member " + name.str().escape(true)); } - MemberInfo& info = it->second; - return {ptr+info.offset, info.type, level}; + const MemberInfo& info = it->second; + return {info.type, level, ptr+info.offset}; } }; @@ -255,12 +275,12 @@ struct Struct { char* data; Pointer head; - TypeInfo* ctype() const { return head.ctype; } + const TypeInfo* ctype() const { return head.ctype; } Struct(const Pointer& head) { data = new char[head.ctype->size]; memcpy(data, head.ptr, head.ctype->size); - this->head = Pointer(data, head.ctype, head.level); + this->head = Pointer(head.ctype, head.level, data); } static void _register(VM* vm, PyVar mod, PyVar type){ @@ -280,11 +300,11 @@ void add_module_c(VM* vm){ PyVar ptr_t = Pointer::register_class(vm, mod); Struct::register_class(vm, mod); - vm->setattr(mod, "nullptr", VAR_T(Pointer, nullptr, &_type_infos["void"])); + vm->setattr(mod, "nullptr", VAR_T(Pointer)); vm->bind_func<1>(mod, "malloc", [](VM* vm, Args& args) { i64 size = CAST(i64, args[0]); - return VAR_T(Pointer, (char*)malloc(size), &_type_infos["void"]); + return VAR_T(Pointer, &_type_infos["void"], (char*)malloc(size)); }); vm->bind_func<1>(mod, "free", [](VM* vm, Args& args) { @@ -301,6 +321,14 @@ void add_module_c(VM* vm){ return vm->None; }); + vm->bind_func<1>(mod, "sizeof", [](VM* vm, Args& args) { + const Str& name = CAST(Str&, args[0]); + if(name.find('*') != Str::npos) return VAR(sizeof(void*)); + auto it = _type_infos.find(name); + if(it == _type_infos.end()) vm->TypeError("unknown type: " + name.escape(true)); + return VAR(it->second.size); + }); + vm->bind_func<3>(mod, "memset", [](VM* vm, Args& args) { Pointer& dst = CAST(Pointer&, args[0]); i64 val = CAST(i64, args[1]); @@ -311,11 +339,11 @@ void add_module_c(VM* vm){ } PyVar py_var(VM* vm, void* p){ - return VAR_T(Pointer, (char*)p, &_type_infos["void"]); + return VAR_T(Pointer, &_type_infos["void"], (char*)p); } PyVar py_var(VM* vm, char* p){ - return VAR_T(Pointer, (char*)p, &_type_infos["char"]); + return VAR_T(Pointer, &_type_infos["char"], (char*)p); } } // namespace pkpy \ No newline at end of file diff --git a/src/common.h b/src/common.h index 6b8a8d2f..58e30017 100644 --- a/src/common.h +++ b/src/common.h @@ -28,7 +28,7 @@ #include #include -#define PK_VERSION "0.9.1" +#define PK_VERSION "0.9.2" #if defined(__EMSCRIPTEN__) || defined(__arm__) || defined(__i386__) typedef int32_t i64; diff --git a/src/str.h b/src/str.h index a750f425..89d5a494 100644 --- a/src/str.h +++ b/src/str.h @@ -20,6 +20,8 @@ class Str : public std::string { } } public: + uint16_t _cached_sn_index = 0; + Str() : std::string() {} Str(const char* s) : std::string(s) {} Str(const char* s, size_t n) : std::string(s, n) {} @@ -139,30 +141,36 @@ struct StrName { StrName(): index(0) {} StrName(uint16_t index): index(index) {} StrName(const char* s): index(get(s).index) {} - StrName(const Str& s): index(get(s).index) {} - inline const Str& str() const { return _r_interned[index-1]; } - inline bool empty() const { return index == 0; } + StrName(const Str& s){ + if(s._cached_sn_index != 0){ + index = s._cached_sn_index; + } else { + index = get(s).index; + } + } + const Str& str() const { return _r_interned[index-1]; } + bool empty() const { return index == 0; } - inline bool operator==(const StrName& other) const noexcept { + bool operator==(const StrName& other) const noexcept { return this->index == other.index; } - inline bool operator!=(const StrName& other) const noexcept { + bool operator!=(const StrName& other) const noexcept { return this->index != other.index; } - inline bool operator<(const StrName& other) const noexcept { + bool operator<(const StrName& other) const noexcept { return this->index < other.index; } - inline bool operator>(const StrName& other) const noexcept { + bool operator>(const StrName& other) const noexcept { return this->index > other.index; } static std::map> _interned; static std::vector _r_interned; - inline static StrName get(const Str& s){ + static StrName get(const Str& s){ return get(s.c_str()); } @@ -194,6 +202,8 @@ const StrName __json__ = StrName::get("__json__"); const StrName __name__ = StrName::get("__name__"); const StrName __len__ = StrName::get("__len__"); const StrName __get__ = StrName::get("__get__"); +const StrName __getattr__ = StrName::get("__getattr__"); +const StrName __setattr__ = StrName::get("__setattr__"); const StrName m_eval = StrName::get("eval"); const StrName m_self = StrName::get("self"); diff --git a/src/vm.h b/src/vm.h index c439d732..4124748c 100644 --- a/src/vm.h +++ b/src/vm.h @@ -359,6 +359,14 @@ void CodeObject::optimize(VM* vm){ codes[i-2].op = OP_NO_OP; } } + + // pre-compute sn in co_consts + for(int i=0; itp_str)){ + Str& s = OBJ_GET(Str, consts[i]); + s._cached_sn_index = StrName::get(s.c_str()).index; + } + } } DEF_NATIVE_2(Str, tp_str) @@ -765,7 +773,7 @@ PyVarOrNull VM::getattr(const PyVar& obj, StrName name, bool throw_err, bool cla if(!class_only){ val = (*root)->attr().try_get(name); - if(val != nullptr) return *val; + if(val != nullptr) return *val; } }else{ if(!class_only && !obj.is_tagged() && obj->is_attr_valid()){ @@ -785,6 +793,12 @@ PyVarOrNull VM::getattr(const PyVar& obj, StrName name, bool throw_err, bool cla }else{ return *val; } + }else{ + // this operation is expensive!!! + PyVar* interceptor = cls->attr().try_get(__getattr__); + if(interceptor != nullptr){ + return call(*interceptor, two_args(obj, VAR(name.str()))); + } } cls = cls->attr(__base__).get(); }