This commit is contained in:
blueloveTH 2023-02-22 18:11:26 +08:00
parent d9c04e6da6
commit 88b6b8066b
7 changed files with 58 additions and 37 deletions

View File

@ -210,7 +210,7 @@ list.__new__ = lambda obj: [i for i in obj]
# https://github.com/python/cpython/blob/main/Objects/dictobject.c # https://github.com/python/cpython/blob/main/Objects/dictobject.c
class dict: class dict:
def __init__(self, capacity=16): def __init__(self, capacity=12):
self._capacity = capacity self._capacity = capacity
self._a = [None] * self._capacity self._a = [None] * self._capacity
self._len = 0 self._len = 0
@ -243,7 +243,7 @@ class dict:
else: else:
self._a[i] = [key, value] self._a[i] = [key, value]
self._len += 1 self._len += 1
if self._len > self._capacity * 0.8: if self._len > self._capacity * 0.67:
self._capacity *= 2 self._capacity *= 2
self.__rehash() self.__rehash()

View File

@ -64,8 +64,8 @@ struct CodeObject {
std::map<StrName, int> global_names; std::map<StrName, int> global_names;
std::vector<CodeBlock> blocks = { CodeBlock{NO_BLOCK, -1} }; std::vector<CodeBlock> blocks = { CodeBlock{NO_BLOCK, -1} };
std::map<StrName, int> labels; std::map<StrName, int> labels;
int recommended_hashmap_capacity = 8; int ideal_locals_capacity = 4;
void optimize(VM* vm); void optimize(VM* vm);

View File

@ -47,7 +47,9 @@ typedef int64_t i64;
typedef double f64; typedef double f64;
#endif #endif
struct Dummy { char _; }; struct Dummy { };
struct DummyInstance { };
struct DummyModule { };
#define DUMMY_VAL Dummy() #define DUMMY_VAL Dummy()
struct Type { struct Type {
@ -67,4 +69,6 @@ struct Type {
#define RAW(T) std::remove_const_t<std::remove_reference_t<T>> #define RAW(T) std::remove_const_t<std::remove_reference_t<T>>
const float kNameDictLoadFactor = 0.8; const float kLocalsLoadFactor = 0.8;
const float kInstAttrLoadFactor = 0.67;
const float kTypeAttrLoadFactor = 0.34;

View File

@ -11,9 +11,11 @@ struct NameDictNode{
struct NameDict { struct NameDict {
int _capacity; int _capacity;
int _size; int _size;
float _load_factor;
NameDictNode* _a; NameDictNode* _a;
NameDict(int capacity=2): _capacity(capacity), _size(0) { NameDict(int capacity=4, float load_factor=0.67):
_capacity(capacity), _size(0), _load_factor(load_factor) {
_a = new NameDictNode[_capacity]; _a = new NameDictNode[_capacity];
} }
@ -38,12 +40,13 @@ struct NameDict {
int size() const { return _size; } int size() const { return _size; }
//https://github.com/python/cpython/blob/main/Objects/dictobject.c#L175
#define HASH_PROBE(key, ok, i) \ #define HASH_PROBE(key, ok, i) \
int i = (key).index % _capacity; \ int i = (key).index % _capacity; \
bool ok = false; \ bool ok = false; \
while(!_a[i].empty()) { \ while(!_a[i].empty()) { \
if(_a[i].first == (key)) { ok = true; break; } \ if(_a[i].first == (key)) { ok = true; break; } \
i = (i + 1) % _capacity; \ i = (5*i + 1) % _capacity; \
} }
#define HASH_PROBE_OVERRIDE(key, ok, i) \ #define HASH_PROBE_OVERRIDE(key, ok, i) \
@ -51,7 +54,7 @@ struct NameDict {
ok = false; \ ok = false; \
while(!_a[i].empty()) { \ while(!_a[i].empty()) { \
if(_a[i].first == (key)) { ok = true; break; } \ if(_a[i].first == (key)) { ok = true; break; } \
i = (i + 1) % _capacity; \ i = (5*i + 1) % _capacity; \
} }
const PyVar& operator[](StrName key) const { const PyVar& operator[](StrName key) const {
@ -65,15 +68,15 @@ struct NameDict {
if(!ok) { if(!ok) {
_a[i].first = key; _a[i].first = key;
_size++; _size++;
if(_size > _capacity * kNameDictLoadFactor){ if(_size > _capacity * _load_factor){
__rehash_2x(); _rehash_2x();
HASH_PROBE_OVERRIDE(key, ok, i); HASH_PROBE_OVERRIDE(key, ok, i);
} }
} }
return _a[i].second; return _a[i].second;
} }
void __rehash_2x(){ void _rehash_2x(){
NameDictNode* old_a = _a; NameDictNode* old_a = _a;
int old_capacity = _capacity; int old_capacity = _capacity;
_capacity *= 2; _capacity *= 2;
@ -122,8 +125,8 @@ struct NameDict {
if(!ok) { if(!ok) {
_a[i].first = key; _a[i].first = key;
_size++; _size++;
if(_size > _capacity * kNameDictLoadFactor){ if(_size > _capacity * _load_factor){
__rehash_2x(); _rehash_2x();
HASH_PROBE_OVERRIDE(key, ok, i); HASH_PROBE_OVERRIDE(key, ok, i);
} }
} }
@ -151,4 +154,7 @@ struct NameDict {
inline iterator begin() const { return iterator(this, 0); } inline iterator begin() const { return iterator(this, 0); }
inline iterator end() const { return iterator(this, _capacity); } inline iterator end() const { return iterator(this, _capacity); }
#undef HASH_PROBE
#undef HASH_PROBE_OVERRIDE
}; };

View File

@ -25,7 +25,7 @@ struct Function {
CodeObject_ code; CodeObject_ code;
std::vector<StrName> args; std::vector<StrName> args;
StrName starred_arg; // empty if no *arg StrName starred_arg; // empty if no *arg
pkpy::NameDict kwargs; // empty if no k=v pkpy::NameDict kwargs; // empty if no k=v
std::vector<StrName> kwargs_order; std::vector<StrName> kwargs_order;
// runtime settings // runtime settings
@ -97,8 +97,10 @@ struct Py_ : PyObject {
Py_(Type type, T&& val): PyObject(type), _value(std::move(val)) { _init(); } Py_(Type type, T&& val): PyObject(type), _value(std::move(val)) { _init(); }
inline void _init() noexcept { inline void _init() noexcept {
if constexpr (std::is_same_v<T, Dummy> || std::is_same_v<T, Type>) { if constexpr (std::is_same_v<T, Type> || std::is_same_v<T, DummyModule>) {
_attr = new pkpy::NameDict(); _attr = new pkpy::NameDict(8, kTypeAttrLoadFactor);
}else if constexpr(std::is_same_v<T, DummyInstance>){
_attr = new pkpy::NameDict(4, kInstAttrLoadFactor);
}else{ }else{
_attr = nullptr; _attr = nullptr;
} }

View File

@ -774,6 +774,22 @@ void add_module_random(VM* vm){
vm->_exec(code, mod); vm->_exec(code, mod);
} }
void VM::post_init(){
init_builtins(this);
add_module_sys(this);
add_module_time(this);
add_module_json(this);
add_module_math(this);
add_module_re(this);
add_module_dis(this);
add_module_random(this);
add_module_io(this);
add_module_os(this);
CodeObject_ code = compile(kBuiltinsCode, "<builtins>", EXEC_MODE);
this->_exec(code, this->builtins);
}
class _PkExported{ class _PkExported{
public: public:
@ -879,21 +895,7 @@ extern "C" {
__EXPORT __EXPORT
/// Create a virtual machine. /// Create a virtual machine.
VM* pkpy_new_vm(bool use_stdio){ VM* pkpy_new_vm(bool use_stdio){
VM* vm = PKPY_ALLOCATE(VM, use_stdio); return PKPY_ALLOCATE(VM, use_stdio);
init_builtins(vm);
add_module_sys(vm);
add_module_time(vm);
add_module_json(vm);
add_module_math(vm);
add_module_re(vm);
add_module_dis(vm);
add_module_random(vm);
add_module_io(vm);
add_module_os(vm);
CodeObject_ code = vm->compile(kBuiltinsCode, "<builtins>", EXEC_MODE);
vm->_exec(code, vm->builtins);
return vm;
} }
__EXPORT __EXPORT

View File

@ -131,7 +131,7 @@ public:
if(new_f != nullptr){ if(new_f != nullptr){
obj = call(*new_f, args, kwargs, false); obj = call(*new_f, args, kwargs, false);
}else{ }else{
obj = new_object(_callable, DUMMY_VAL); obj = new_object(_callable, DummyInstance());
PyVarOrNull init_f = getattr(obj, __init__, false); PyVarOrNull init_f = getattr(obj, __init__, false);
if (init_f != nullptr) call(init_f, args, kwargs, false); if (init_f != nullptr) call(init_f, args, kwargs, false);
} }
@ -151,7 +151,9 @@ public:
return f(this, args); return f(this, args);
} else if(is_type(*callable, tp_function)){ } else if(is_type(*callable, tp_function)){
const pkpy::Function& fn = PyFunction_AS_C(*callable); const pkpy::Function& fn = PyFunction_AS_C(*callable);
auto _locals = pkpy::make_shared<pkpy::NameDict>(fn.code->recommended_hashmap_capacity); auto _locals = pkpy::make_shared<pkpy::NameDict>(
fn.code->ideal_locals_capacity, kLocalsLoadFactor
);
pkpy::NameDict& locals = *_locals; pkpy::NameDict& locals = *_locals;
int i = 0; int i = 0;
@ -323,7 +325,7 @@ public:
} }
PyVar new_module(StrName name) { PyVar new_module(StrName name) {
PyVar obj = new_object(tp_module, DUMMY_VAL); PyVar obj = new_object(tp_module, DummyModule());
setattr(obj, __name__, PyStr(name.str())); setattr(obj, __name__, PyStr(name.str()));
_modules[name] = obj; _modules[name] = obj;
return obj; return obj;
@ -635,8 +637,12 @@ public:
for (auto& name : pb_types) { for (auto& name : pb_types) {
setattr(builtins, name, _types[name]); setattr(builtins, name, _types[name]);
} }
post_init();
} }
void post_init();
i64 hash(const PyVar& obj){ i64 hash(const PyVar& obj){
if (is_type(obj, tp_str)) return PyStr_AS_C(obj).hash(); if (is_type(obj, tp_str)) return PyStr_AS_C(obj).hash();
if (is_int(obj)) return PyInt_AS_C(obj); if (is_int(obj)) return PyInt_AS_C(obj);
@ -860,8 +866,9 @@ PyVar pkpy::NativeFunc::operator()(VM* vm, pkpy::Args& args) const{
void CodeObject::optimize(VM* vm){ void CodeObject::optimize(VM* vm){
int n = 0; int n = 0;
for(auto& p: names) if(p.second == NAME_LOCAL) n++; for(auto& p: names) if(p.second == NAME_LOCAL) n++;
recommended_hashmap_capacity = (int)(n / kNameDictLoadFactor + 1.5); int base_n = (int)(n / kLocalsLoadFactor + 1.5);
if(recommended_hashmap_capacity < 2) recommended_hashmap_capacity = 2; ideal_locals_capacity = 2;
while(ideal_locals_capacity < base_n) ideal_locals_capacity *= 2;
for(int i=1; i<codes.size(); i++){ for(int i=1; i<codes.size(); i++){
if(codes[i].op == OP_UNARY_NEGATIVE && codes[i-1].op == OP_LOAD_CONST){ if(codes[i].op == OP_UNARY_NEGATIVE && codes[i-1].op == OP_LOAD_CONST){