This commit is contained in:
blueloveTH 2023-02-22 16:32:14 +08:00
parent 6854128bac
commit d9c04e6da6
6 changed files with 194 additions and 39 deletions

View File

@ -64,6 +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;
void optimize(VM* vm); void optimize(VM* vm);

View File

@ -24,6 +24,7 @@
#include <functional> #include <functional>
#include <iostream> #include <iostream>
#include <map> #include <map>
#include <algorithm>
// #include <filesystem> // #include <filesystem>
// namespace fs = std::filesystem; // namespace fs = std::filesystem;
@ -64,4 +65,6 @@ struct Type {
//#define THREAD_LOCAL thread_local //#define THREAD_LOCAL thread_local
#define THREAD_LOCAL #define THREAD_LOCAL
#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;

154
src/namedict.h Normal file
View File

@ -0,0 +1,154 @@
#pragma once
#include "safestl.h"
struct NameDictNode{
StrName first;
PyVar second;
inline bool empty() const { return first.empty(); }
};
struct NameDict {
int _capacity;
int _size;
NameDictNode* _a;
NameDict(int capacity=2): _capacity(capacity), _size(0) {
_a = new NameDictNode[_capacity];
}
NameDict(const NameDict& other) {
this->_capacity = other._capacity;
this->_size = other._size;
this->_a = new NameDictNode[_capacity];
for(int i=0; i<_capacity; i++) _a[i] = other._a[i];
}
NameDict& operator=(const NameDict& other){
delete[] _a;
this->_capacity = other._capacity;
this->_size = other._size;
this->_a = new NameDictNode[_capacity];
for(int i=0; i<_capacity; i++) _a[i] = other._a[i];
return *this;
}
NameDict(NameDict&&) = delete;
NameDict& operator=(NameDict&&) = delete;
int size() const { return _size; }
#define HASH_PROBE(key, ok, i) \
int i = (key).index % _capacity; \
bool ok = false; \
while(!_a[i].empty()) { \
if(_a[i].first == (key)) { ok = true; break; } \
i = (i + 1) % _capacity; \
}
#define HASH_PROBE_OVERRIDE(key, ok, i) \
i = (key).index % _capacity; \
ok = false; \
while(!_a[i].empty()) { \
if(_a[i].first == (key)) { ok = true; break; } \
i = (i + 1) % _capacity; \
}
const PyVar& operator[](StrName key) const {
HASH_PROBE(key, ok, i);
if(!ok) throw std::out_of_range("NameDict key not found");
return _a[i].second;
}
[[nodiscard]] PyVar& operator[](StrName key){
HASH_PROBE(key, ok, i);
if(!ok) {
_a[i].first = key;
_size++;
if(_size > _capacity * kNameDictLoadFactor){
__rehash_2x();
HASH_PROBE_OVERRIDE(key, ok, i);
}
}
return _a[i].second;
}
void __rehash_2x(){
NameDictNode* old_a = _a;
int old_capacity = _capacity;
_capacity *= 2;
_size = 0;
_a = new NameDictNode[_capacity];
for(int i=0; i<old_capacity; i++){
if(old_a[i].empty()) continue;
HASH_PROBE(old_a[i].first, ok, j);
_a[j].first = old_a[i].first;
_a[j].second = std::move(old_a[i].second);
_size++;
}
delete[] old_a;
}
inline PyVar* try_get(StrName key){
HASH_PROBE(key, ok, i);
if(!ok) return nullptr;
return &_a[i].second;
}
inline bool contains(StrName key) const {
HASH_PROBE(key, ok, i);
return ok;
}
~NameDict(){ delete[] _a;}
struct iterator {
const NameDict* _dict;
int i;
iterator() = default;
iterator(const NameDict* dict, int i): _dict(dict), i(i) { _skip_empty(); }
inline void _skip_empty(){ while(i < _dict->_capacity && _dict->_a[i].empty()) i++;}
inline iterator& operator++(){ i++; _skip_empty(); return *this;}
inline bool operator!=(const iterator& other) const { return i != other.i; }
inline bool operator==(const iterator& other) const { return i == other.i; }
inline NameDictNode* operator->() const { return &_dict->_a[i]; }
};
template<typename T>
void emplace(StrName key, T&& value){
HASH_PROBE(key, ok, i);
if(!ok) {
_a[i].first = key;
_size++;
if(_size > _capacity * kNameDictLoadFactor){
__rehash_2x();
HASH_PROBE_OVERRIDE(key, ok, i);
}
}
_a[i].second = std::forward<T>(value);
}
void insert(iterator begin, iterator end){
for(auto it = begin; it != end; ++it){
emplace(it->first, it->second);
}
}
iterator find(StrName key) const{
HASH_PROBE(key, ok, i);
if(!ok) return end();
return iterator(this, i);
}
void erase(StrName key){
HASH_PROBE(key, ok, i);
if(!ok) throw std::out_of_range("NameDict key not found");
_a[i] = NameDictNode();
_size--;
}
inline iterator begin() const { return iterator(this, 0); }
inline iterator end() const { return iterator(this, _capacity); }
};

View File

@ -11,39 +11,33 @@ typedef PyVar PyVarRef;
#include "hash_table5.hpp" #include "hash_table5.hpp"
namespace pkpy { namespace pkpy {
template<typename... Args> #include "namedict.h"
using HashMap = emhash5::HashMap<Args...>; // template<typename... Args>
} // using HashMap = emhash5::HashMap<Args...>;
// typedef HashMap<StrName, PyVar> NameDict;
class List: public std::vector<PyVar> {
PyVar& at(size_t) = delete;
namespace pkpy{ inline void _check_index(size_t i) const {
class List: public std::vector<PyVar> { if (i >= size()){
PyVar& at(size_t) = delete; auto msg = "std::vector index out of range, " + std::to_string(i) + " not in [0, " + std::to_string(size()) + ")";
throw std::out_of_range(msg);
inline void _check_index(size_t i) const { }
if (i >= size()){ }
auto msg = "std::vector index out of range, " + std::to_string(i) + " not in [0, " + std::to_string(size()) + ")"; public:
throw std::out_of_range(msg); PyVar& operator[](size_t i) {
_check_index(i);
return std::vector<PyVar>::operator[](i);
} }
}
public:
PyVar& operator[](size_t i) {
_check_index(i);
return std::vector<PyVar>::operator[](i);
}
const PyVar& operator[](size_t i) const { const PyVar& operator[](size_t i) const {
_check_index(i); _check_index(i);
return std::vector<PyVar>::operator[](i); return std::vector<PyVar>::operator[](i);
} }
using std::vector<PyVar>::vector; using std::vector<PyVar>::vector;
}; };
}
namespace pkpy {
typedef HashMap<StrName, PyVar> NameDict;
class Args { class Args {
static THREAD_LOCAL SmallArrayPool<PyVar, 10> _pool; static THREAD_LOCAL SmallArrayPool<PyVar, 10> _pool;
@ -140,8 +134,5 @@ namespace pkpy {
} }
typedef Args Tuple; typedef Args Tuple;
// declare static members
THREAD_LOCAL SmallArrayPool<PyVar, 10> Args::_pool; THREAD_LOCAL SmallArrayPool<PyVar, 10> Args::_pool;
// THREAD_LOCAL SmallArrayPool<NameDictNode, 1> NameDict::_pool;
} // namespace pkpy } // namespace pkpy

View File

@ -140,7 +140,6 @@ struct StrName {
StrName(const Str& s): index(get(s).index) {} StrName(const Str& s): index(get(s).index) {}
inline const Str& str() const { return _r_interned[index]; } inline const Str& str() const { return _r_interned[index]; }
inline bool empty() const { return index == -1; } inline bool empty() const { return index == -1; }
inline void reset() { index = -1; }
inline bool operator==(const StrName& other) const noexcept { inline bool operator==(const StrName& other) const noexcept {
return this->index == other.index; return this->index == other.index;

View File

@ -25,7 +25,7 @@ public:
pkpy::NameDict _types; pkpy::NameDict _types;
pkpy::NameDict _modules; // loaded modules pkpy::NameDict _modules; // loaded modules
pkpy::HashMap<StrName, Str> _lazy_modules; // lazy loaded modules std::map<StrName, Str> _lazy_modules; // lazy loaded modules
PyVar None, True, False, Ellipsis; PyVar None, True, False, Ellipsis;
bool use_stdio; bool use_stdio;
@ -151,7 +151,7 @@ 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);
pkpy::shared_ptr<pkpy::NameDict> _locals = pkpy::make_shared<pkpy::NameDict>(); auto _locals = pkpy::make_shared<pkpy::NameDict>(fn.code->recommended_hashmap_capacity);
pkpy::NameDict& locals = *_locals; pkpy::NameDict& locals = *_locals;
int i = 0; int i = 0;
@ -172,7 +172,7 @@ public:
}else{ }else{
for(StrName key : fn.kwargs_order){ for(StrName key : fn.kwargs_order){
if(i < args.size()){ if(i < args.size()){
locals[key] = args[i++]; locals.emplace(key, args[i++]);
}else{ }else{
break; break;
} }
@ -185,8 +185,7 @@ public:
if(!fn.kwargs.contains(key)){ if(!fn.kwargs.contains(key)){
TypeError(key.escape(true) + " is an invalid keyword argument for " + fn.name + "()"); TypeError(key.escape(true) + " is an invalid keyword argument for " + fn.name + "()");
} }
const PyVar& val = kwargs[i+1]; locals.emplace(key, kwargs[i+1]);
locals[key] = val;
} }
PyVar _module = fn._module != nullptr ? fn._module : top_frame()->_module; PyVar _module = fn._module != nullptr ? fn._module : top_frame()->_module;
auto _frame = _new_frame(fn.code, _module, _locals, fn._closure); auto _frame = _new_frame(fn.code, _module, _locals, fn._closure);
@ -212,10 +211,12 @@ public:
}catch (const pkpy::Exception& e){ }catch (const pkpy::Exception& e){
*_stderr << e.summary() << '\n'; *_stderr << e.summary() << '\n';
} }
#ifdef _NDEBUG
catch (const std::exception& e) { catch (const std::exception& e) {
*_stderr << "An std::exception occurred! It could be a bug.\n"; *_stderr << "An std::exception occurred! It could be a bug.\n";
*_stderr << e.what() << '\n'; *_stderr << e.what() << '\n';
} }
#endif
callstack = {}; callstack = {};
return nullptr; return nullptr;
} }
@ -857,6 +858,11 @@ PyVar pkpy::NativeFunc::operator()(VM* vm, pkpy::Args& args) const{
} }
void CodeObject::optimize(VM* vm){ void CodeObject::optimize(VM* vm){
int n = 0;
for(auto& p: names) if(p.second == NAME_LOCAL) n++;
recommended_hashmap_capacity = (int)(n / kNameDictLoadFactor + 1.5);
if(recommended_hashmap_capacity < 2) recommended_hashmap_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){
codes[i].op = OP_NO_OP; codes[i].op = OP_NO_OP;