mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 11:30:18 +00:00
Make py_Name
opaque pointer (#370)
* backup * backup * backup * backup * backup * backup * Update codeobject.c * backup * Update ceval.c * backup * backup * fix all * revert ci * fix all * fix all * fix pybind * add `PK_ENABLE_CUSTOM_SNAME`
This commit is contained in:
parent
a0bd1a3f3b
commit
a53af18ee8
@ -4,6 +4,8 @@
|
||||
#include "http/HttpMessage.h"
|
||||
#include "base/hplatform.h"
|
||||
|
||||
#include "pocketpy/common/name.h"
|
||||
|
||||
extern "C" void pk__add_module_libhv();
|
||||
|
||||
void libhv_HttpRequest_create(py_OutRef out, HttpRequestPtr ptr);
|
||||
|
@ -53,6 +53,11 @@ if(PK_ENABLE_WATCHDOG)
|
||||
add_definitions(-DPK_ENABLE_WATCHDOG=1)
|
||||
endif()
|
||||
|
||||
if(PK_ENABLE_CUSTOM_SNAME)
|
||||
add_definitions(-DPK_ENABLE_CUSTOM_SNAME=1)
|
||||
endif()
|
||||
|
||||
|
||||
if(PK_BUILD_MODULE_LZ4)
|
||||
add_subdirectory(3rd/lz4)
|
||||
add_definitions(-DPK_BUILD_MODULE_LZ4)
|
||||
|
@ -9,6 +9,7 @@ endif()
|
||||
option(PK_ENABLE_OS "" OFF)
|
||||
option(PK_ENABLE_DETERMINISM "" OFF)
|
||||
option(PK_ENABLE_WATCHDOG "" OFF)
|
||||
option(PK_ENABLE_CUSTOM_SNAME "" OFF)
|
||||
|
||||
# modules
|
||||
option(PK_BUILD_MODULE_LZ4 "" OFF)
|
||||
|
15
include/pocketpy/common/name.h
Normal file
15
include/pocketpy/common/name.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
void pk_names_initialize();
|
||||
void pk_names_finalize();
|
||||
|
||||
#define MAGIC_METHOD(x) extern py_Name x;
|
||||
#include "pocketpy/xmacros/magics.h"
|
||||
#undef MAGIC_METHOD
|
||||
|
||||
py_Name py_namev(c11_sv name);
|
||||
c11_sv py_name2sv(py_Name index);
|
||||
py_Name py_name(const char* name);
|
||||
const char* py_name2str(py_Name index);
|
@ -5,17 +5,23 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#define SMALLMAP_T__HEADER
|
||||
#define K uint16_t
|
||||
#define K py_Name
|
||||
#define V int
|
||||
#define NAME c11_smallmap_n2i
|
||||
#define NAME c11_smallmap_n2d
|
||||
#include "pocketpy/xmacros/smallmap.h"
|
||||
#undef SMALLMAP_T__HEADER
|
||||
|
||||
#define SMALLMAP_T__HEADER
|
||||
#define K int
|
||||
#define V int
|
||||
#define NAME c11_smallmap_d2d
|
||||
#include "pocketpy/xmacros/smallmap.h"
|
||||
#undef SMALLMAP_T__HEADER
|
||||
|
||||
#define SMALLMAP_T__HEADER
|
||||
#define K c11_sv
|
||||
#define V uint16_t
|
||||
#define NAME c11_smallmap_s2n
|
||||
#define V int
|
||||
#define NAME c11_smallmap_v2d
|
||||
#define less(a, b) (c11_sv__cmp((a), (b)) < 0)
|
||||
#define equal(a, b) (c11_sv__cmp((a), (b)) == 0)
|
||||
#include "pocketpy/xmacros/smallmap.h"
|
||||
|
@ -60,6 +60,7 @@ int c11_sv__index2(c11_sv self, c11_sv sub, int start);
|
||||
int c11_sv__count(c11_sv self, c11_sv sub);
|
||||
bool c11_sv__startswith(c11_sv self, c11_sv prefix);
|
||||
bool c11_sv__endswith(c11_sv self, c11_sv suffix);
|
||||
uint64_t c11_sv__hash(c11_sv self);
|
||||
|
||||
c11_string* c11_sv__replace(c11_sv self, char old, char new_);
|
||||
c11_string* c11_sv__replace2(c11_sv self, c11_sv old, c11_sv new_);
|
||||
|
@ -23,6 +23,9 @@
|
||||
abort(); \
|
||||
} while(0)
|
||||
|
||||
#define c11__rtassert(cond) \
|
||||
if(!(cond)) c11__abort("assertion failed: %s", #cond)
|
||||
|
||||
#define c11__min(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define c11__max(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
@ -42,4 +45,3 @@ typedef struct RefCounted {
|
||||
PK_FREE(obj); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
|
@ -20,6 +20,10 @@
|
||||
#define PK_ENABLE_WATCHDOG 0
|
||||
#endif
|
||||
|
||||
#ifndef PK_ENABLE_CUSTOM_SNAME // can be overridden by cmake
|
||||
#define PK_ENABLE_CUSTOM_SNAME 0
|
||||
#endif
|
||||
|
||||
// GC min threshold
|
||||
#ifndef PK_GC_MIN_THRESHOLD // can be overridden by cmake
|
||||
#define PK_GC_MIN_THRESHOLD 32768
|
||||
@ -60,6 +64,12 @@
|
||||
#define PK_M_DEG2RAD 0.017453292519943295
|
||||
#define PK_M_RAD2DEG 57.29577951308232
|
||||
|
||||
// Hash table load factor (smaller ones mean less collision but more memory)
|
||||
// For class instance
|
||||
#define PK_INST_ATTR_LOAD_FACTOR 0.67f
|
||||
// For class itself
|
||||
#define PK_TYPE_ATTR_LOAD_FACTOR 0.5f
|
||||
|
||||
#ifdef _WIN32
|
||||
#define PK_PLATFORM_SEP '\\'
|
||||
#else
|
||||
|
@ -55,3 +55,9 @@
|
||||
#else
|
||||
#define PK_IS_DESKTOP_PLATFORM 0
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define PK_DEPRECATED __attribute__((deprecated))
|
||||
#else
|
||||
#define PK_DEPRECATED
|
||||
#endif
|
@ -1,9 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/memorypool.h"
|
||||
#include "pocketpy/objects/codeobject.h"
|
||||
#include "pocketpy/objects/namedict.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
void FastLocals__to_dict(py_TValue* locals, const CodeObject* co) PY_RETURN;
|
||||
|
@ -1,18 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/objects/base.h"
|
||||
#include "pocketpy/common/smallmap.h"
|
||||
|
||||
typedef struct {
|
||||
char* data; // null-terminated data
|
||||
int size; // size of the data excluding the null-terminator
|
||||
py_TValue obj; // cached `str` object (lazy initialized)
|
||||
} RInternedEntry;
|
||||
|
||||
typedef struct {
|
||||
c11_smallmap_s2n interned;
|
||||
c11_vector /* T=RInternedEntry */ r_interned;
|
||||
} InternedNames;
|
||||
|
||||
void InternedNames__ctor(InternedNames* self);
|
||||
void InternedNames__dtor(InternedNames* self);
|
@ -3,8 +3,6 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
|
||||
#define PK_MAGIC_SLOTS_COMMON_LENGTH (__missing__ - __xor__)
|
||||
#define PK_MAGIC_SLOTS_UNCOMMON_LENGTH (__xor__ + 1)
|
||||
#define PK_MAX_CHUNK_LENGTH 256
|
||||
|
||||
typedef struct py_TypeInfo {
|
||||
@ -25,8 +23,7 @@ typedef struct py_TypeInfo {
|
||||
void (*on_end_subclass)(struct py_TypeInfo*); // backdoor for enum module
|
||||
|
||||
/* Magic Slots */
|
||||
py_TValue magic_0[PK_MAGIC_SLOTS_COMMON_LENGTH]; // common magic slots
|
||||
py_TValue* magic_1; // uncommon magic slots
|
||||
// (deleted)
|
||||
} py_TypeInfo;
|
||||
|
||||
typedef struct TypeList {
|
||||
@ -39,7 +36,4 @@ void TypeList__dtor(TypeList* self);
|
||||
py_TypeInfo* TypeList__get(TypeList* self, py_Type index);
|
||||
py_TypeInfo* TypeList__emplace(TypeList* self);
|
||||
void TypeList__apply(TypeList* self, void (*f)(py_TypeInfo*, void*), void* ctx);
|
||||
py_TValue* TypeList__magic(py_TypeInfo* self, unsigned index);
|
||||
py_TValue* TypeList__magic_readonly(py_TypeInfo* self, unsigned index);
|
||||
|
||||
#define TypeList__magic_common(ti, index) ((ti)->magic_0 + ((index)-PK_MAGIC_SLOTS_UNCOMMON_LENGTH))
|
||||
|
@ -1,12 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/memorypool.h"
|
||||
#include "pocketpy/common/name.h"
|
||||
#include "pocketpy/objects/codeobject.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include "pocketpy/interpreter/heap.h"
|
||||
#include "pocketpy/interpreter/frame.h"
|
||||
#include "pocketpy/interpreter/typeinfo.h"
|
||||
#include "pocketpy/interpreter/name.h"
|
||||
#include "pocketpy/interpreter/line_profiler.h"
|
||||
#include <time.h>
|
||||
|
||||
@ -49,6 +49,8 @@ typedef struct VM {
|
||||
py_TValue reg[8]; // users' registers
|
||||
void* ctx; // user-defined context
|
||||
|
||||
NameDict cached_names;
|
||||
|
||||
py_StackRef curr_class;
|
||||
py_StackRef curr_decl_based_function;
|
||||
TraceInfo trace_info;
|
||||
@ -56,7 +58,6 @@ typedef struct VM {
|
||||
LineProfiler line_profiler;
|
||||
py_TValue vectorcall_buffer[PK_MAX_CO_VARNAMES];
|
||||
|
||||
InternedNames names;
|
||||
FixedMemoryPool pool_frame;
|
||||
ManagedHeap heap;
|
||||
ValueStack stack; // put `stack` at the end for better cache locality
|
||||
|
@ -75,9 +75,11 @@ typedef struct CodeObject {
|
||||
|
||||
c11_vector /*T=py_TValue*/ consts; // constants
|
||||
c11_vector /*T=py_Name*/ varnames; // local variables
|
||||
int nlocals; // cached varnames.size()
|
||||
c11_vector /*T=py_Name*/ names;
|
||||
int nlocals;
|
||||
|
||||
c11_smallmap_n2i varnames_inv;
|
||||
c11_smallmap_n2d varnames_inv;
|
||||
c11_smallmap_n2d names_inv;
|
||||
|
||||
c11_vector /*T=CodeBlock*/ blocks;
|
||||
c11_vector /*T=FuncDecl_*/ func_decls;
|
||||
@ -89,11 +91,12 @@ typedef struct CodeObject {
|
||||
void CodeObject__ctor(CodeObject* self, SourceData_ src, c11_sv name);
|
||||
void CodeObject__dtor(CodeObject* self);
|
||||
int CodeObject__add_varname(CodeObject* self, py_Name name);
|
||||
int CodeObject__add_name(CodeObject* self, py_Name name);
|
||||
void CodeObject__gc_mark(const CodeObject* self, c11_vector* p_stack);
|
||||
|
||||
typedef struct FuncDeclKwArg {
|
||||
int index; // index in co->varnames
|
||||
uint16_t key; // name of this argument
|
||||
py_Name key; // name of this argument
|
||||
py_TValue value; // default value
|
||||
} FuncDeclKwArg;
|
||||
|
||||
@ -111,7 +114,7 @@ typedef struct FuncDecl {
|
||||
const char* docstring; // docstring of this function (weak ref)
|
||||
|
||||
FuncType type;
|
||||
c11_smallmap_n2i kw_to_index;
|
||||
c11_smallmap_n2d kw_to_index;
|
||||
} FuncDecl;
|
||||
|
||||
typedef FuncDecl* FuncDecl_;
|
||||
|
@ -1,16 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/vector.h"
|
||||
#include "pocketpy/common/str.h"
|
||||
#include "pocketpy/objects/base.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#define SMALLMAP_T__HEADER
|
||||
#define K uint16_t
|
||||
#define V py_TValue
|
||||
#define NAME NameDict
|
||||
#include "pocketpy/xmacros/smallmap.h"
|
||||
#undef SMALLMAP_T__HEADER
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
/* A simple binary tree for storing modules. */
|
||||
typedef struct ModuleDict {
|
||||
@ -26,3 +18,30 @@ void ModuleDict__set(ModuleDict* self, const char* key, py_TValue val);
|
||||
py_TValue* ModuleDict__try_get(ModuleDict* self, const char* path);
|
||||
bool ModuleDict__contains(ModuleDict* self, const char* path);
|
||||
void ModuleDict__apply_mark(ModuleDict* self, c11_vector* p_stack);
|
||||
|
||||
/////////////////// NameDict ///////////////////
|
||||
|
||||
typedef struct NameDict_KV {
|
||||
py_Name key;
|
||||
py_TValue value;
|
||||
} NameDict_KV;
|
||||
|
||||
// https://github.com/pocketpy/pocketpy/blob/v1.x/include/pocketpy/namedict.h
|
||||
typedef struct NameDict {
|
||||
int length;
|
||||
float load_factor;
|
||||
int capacity;
|
||||
int critical_size;
|
||||
uintptr_t mask;
|
||||
NameDict_KV* items;
|
||||
} NameDict;
|
||||
|
||||
NameDict* NameDict__new(float load_factor);
|
||||
void NameDict__delete(NameDict* self);
|
||||
void NameDict__ctor(NameDict* self, float load_factor);
|
||||
void NameDict__dtor(NameDict* self);
|
||||
py_TValue* NameDict__try_get(NameDict* self, py_Name key);
|
||||
bool NameDict__contains(NameDict* self, py_Name key);
|
||||
void NameDict__set(NameDict* self, py_Name key, py_TValue* value);
|
||||
bool NameDict__del(NameDict* self, py_Name key);
|
||||
void NameDict__clear(NameDict* self);
|
@ -13,12 +13,12 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/************* Public Types *************/
|
||||
|
||||
/// A helper struct for `py_Name`.
|
||||
typedef struct py_OpaqueName py_OpaqueName;
|
||||
/// A pointer that represents a python identifier. For fast name resolution.
|
||||
typedef py_OpaqueName* py_Name;
|
||||
/// A opaque type that represents a python object. You cannot access its members directly.
|
||||
typedef struct py_TValue py_TValue;
|
||||
/// An integer that represents a python identifier. This is to achieve string pooling and fast name
|
||||
/// resolution.
|
||||
typedef uint16_t py_Name;
|
||||
/// An integer that represents a python type. `0` is invalid.
|
||||
typedef int16_t py_Type;
|
||||
/// A 64-bit integer type. Corresponds to `int` in python.
|
||||
@ -237,13 +237,13 @@ PK_API py_Name py_name(const char*);
|
||||
/// Convert a name to a null-terminated string.
|
||||
PK_API const char* py_name2str(py_Name);
|
||||
/// Convert a name to a python `str` object with cache.
|
||||
PK_API py_GlobalRef py_name2ref(py_Name);
|
||||
PK_API py_ItemRef py_name2ref(py_Name);
|
||||
/// Convert a `c11_sv` to a name.
|
||||
PK_API py_Name py_namev(c11_sv);
|
||||
/// Convert a name to a `c11_sv`.
|
||||
PK_API c11_sv py_name2sv(py_Name);
|
||||
|
||||
#define py_ismagicname(name) (name <= __missing__)
|
||||
#define py_ismagicname(name) (true)
|
||||
|
||||
/************* Meta Operations *************/
|
||||
|
||||
@ -318,7 +318,7 @@ PK_API bool py_issubclass(py_Type derived, py_Type base);
|
||||
|
||||
/// Get the magic method from the given type only.
|
||||
/// The returned reference is always valid. However, its value may be `nil`.
|
||||
PK_API py_GlobalRef py_tpgetmagic(py_Type type, py_Name name);
|
||||
PK_API PK_DEPRECATED py_GlobalRef py_tpgetmagic(py_Type type, py_Name name);
|
||||
/// Search the magic method from the given type to the base type.
|
||||
/// Return `NULL` if not found.
|
||||
PK_API py_GlobalRef py_tpfindmagic(py_Type, py_Name name);
|
||||
@ -438,8 +438,8 @@ PK_API void py_bindfunc(py_Ref obj, const char* name, py_CFunction f);
|
||||
/// @param setter setter function. Use `NULL` if not needed.
|
||||
PK_API void
|
||||
py_bindproperty(py_Type type, const char* name, py_CFunction getter, py_CFunction setter);
|
||||
|
||||
#define py_bindmagic(type, __magic__, f) py_newnativefunc(py_tpgetmagic((type), __magic__), (f))
|
||||
/// Bind a magic method to type.
|
||||
PK_API void py_bindmagic(py_Type type, py_Name name, py_CFunction f);
|
||||
|
||||
#define PY_CHECK_ARGC(n) \
|
||||
if(argc != n) return TypeError("expected %d arguments, got %d", n, argc)
|
||||
@ -469,21 +469,32 @@ PK_API bool py_delitem(py_Ref self, py_Ref key) PY_RAISE;
|
||||
/// The result will be set to `py_retval()`.
|
||||
/// The stack remains unchanged after the operation.
|
||||
PK_API bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop) PY_RAISE PY_RETURN;
|
||||
|
||||
#define py_binaryadd(lhs, rhs) py_binaryop(lhs, rhs, __add__, __radd__)
|
||||
#define py_binarysub(lhs, rhs) py_binaryop(lhs, rhs, __sub__, __rsub__)
|
||||
#define py_binarymul(lhs, rhs) py_binaryop(lhs, rhs, __mul__, __rmul__)
|
||||
#define py_binarytruediv(lhs, rhs) py_binaryop(lhs, rhs, __truediv__, __rtruediv__)
|
||||
#define py_binaryfloordiv(lhs, rhs) py_binaryop(lhs, rhs, __floordiv__, __rfloordiv__)
|
||||
#define py_binarymod(lhs, rhs) py_binaryop(lhs, rhs, __mod__, __rmod__)
|
||||
#define py_binarypow(lhs, rhs) py_binaryop(lhs, rhs, __pow__, __rpow__)
|
||||
|
||||
#define py_binarylshift(lhs, rhs) py_binaryop(lhs, rhs, __lshift__, 0)
|
||||
#define py_binaryrshift(lhs, rhs) py_binaryop(lhs, rhs, __rshift__, 0)
|
||||
#define py_binaryand(lhs, rhs) py_binaryop(lhs, rhs, __and__, 0)
|
||||
#define py_binaryor(lhs, rhs) py_binaryop(lhs, rhs, __or__, 0)
|
||||
#define py_binaryxor(lhs, rhs) py_binaryop(lhs, rhs, __xor__, 0)
|
||||
#define py_binarymatmul(lhs, rhs) py_binaryop(lhs, rhs, __matmul__, 0)
|
||||
/// lhs + rhs
|
||||
PK_API bool py_binaryadd(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
/// lhs - rhs
|
||||
PK_API bool py_binarysub(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
/// lhs * rhs
|
||||
PK_API bool py_binarymul(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
/// lhs / rhs
|
||||
PK_API bool py_binarytruediv(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
/// lhs // rhs
|
||||
PK_API bool py_binaryfloordiv(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
/// lhs % rhs
|
||||
PK_API bool py_binarymod(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
/// lhs ** rhs
|
||||
PK_API bool py_binarypow(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
/// lhs << rhs
|
||||
PK_API bool py_binarylshift(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
/// lhs >> rhs
|
||||
PK_API bool py_binaryrshift(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
/// lhs & rhs
|
||||
PK_API bool py_binaryand(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
/// lhs | rhs
|
||||
PK_API bool py_binaryor(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
/// lhs ^ rhs
|
||||
PK_API bool py_binaryxor(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
/// lhs @ rhs
|
||||
PK_API bool py_binarymatmul(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
|
||||
/************* Stack Operations *************/
|
||||
|
||||
@ -710,14 +721,6 @@ PK_API int py_replinput(char* buf, int max_size);
|
||||
/// %t: py_Type
|
||||
/// %n: py_Name
|
||||
|
||||
enum py_MagicName {
|
||||
py_MagicName__NULL, // 0 is reserved
|
||||
|
||||
#define MAGIC_METHOD(x) x,
|
||||
#include "pocketpy/xmacros/magics.h"
|
||||
#undef MAGIC_METHOD
|
||||
};
|
||||
|
||||
enum py_PredefinedType {
|
||||
tp_nil = 0,
|
||||
tp_object = 1,
|
||||
|
@ -51,7 +51,25 @@ OPCODE(BUILD_SET)
|
||||
OPCODE(BUILD_SLICE)
|
||||
OPCODE(BUILD_STRING)
|
||||
/**************************/
|
||||
OPCODE(BINARY_OP)
|
||||
OPCODE(BINARY_ADD)
|
||||
OPCODE(BINARY_SUB)
|
||||
OPCODE(BINARY_MUL)
|
||||
OPCODE(BINARY_TRUEDIV)
|
||||
OPCODE(BINARY_FLOORDIV)
|
||||
OPCODE(BINARY_MOD)
|
||||
OPCODE(BINARY_POW)
|
||||
OPCODE(BINARY_LSHIFT)
|
||||
OPCODE(BINARY_RSHIFT)
|
||||
OPCODE(BINARY_AND)
|
||||
OPCODE(BINARY_OR)
|
||||
OPCODE(BINARY_XOR)
|
||||
OPCODE(BINARY_MATMUL)
|
||||
OPCODE(COMPARE_LT)
|
||||
OPCODE(COMPARE_LE)
|
||||
OPCODE(COMPARE_EQ)
|
||||
OPCODE(COMPARE_NE)
|
||||
OPCODE(COMPARE_GT)
|
||||
OPCODE(COMPARE_GE)
|
||||
OPCODE(IS_OP)
|
||||
OPCODE(CONTAINS_OP)
|
||||
/**************************/
|
||||
|
@ -6,7 +6,7 @@
|
||||
/* Input */
|
||||
#define K int
|
||||
#define V float
|
||||
#define NAME c11_smallmap_i2f
|
||||
#define NAME c11_smallmap_d2f
|
||||
#endif
|
||||
|
||||
/* Optional Input */
|
||||
|
@ -30,8 +30,8 @@ public:
|
||||
auto& info = type_info::of<T>();
|
||||
info.name = name;
|
||||
|
||||
py_newfunction(
|
||||
py_tpgetmagic(this->index(), __new__),
|
||||
py_bind(
|
||||
py_tpobject(this->index()),
|
||||
"__new__(type, *args, **kwargs)",
|
||||
[](int, py_Ref stack) {
|
||||
auto cls = py_offset(stack, 0);
|
||||
@ -44,9 +44,7 @@ public:
|
||||
py_newobject(py_retval(), steal<type>(cls).index(), slot, sizeof(instance));
|
||||
new (data) instance{instance::Flag::Own, operator new (info->size), info};
|
||||
return true;
|
||||
},
|
||||
nullptr,
|
||||
0);
|
||||
});
|
||||
}
|
||||
|
||||
/// bind constructor
|
||||
|
@ -101,25 +101,25 @@ inline object::operator bool () const { return raise_call<py_bool>(m_ptr); }
|
||||
return object::from_ret(); \
|
||||
}
|
||||
|
||||
PKBIND_BINARY_OPERATOR(==, __eq__, __eq__)
|
||||
PKBIND_BINARY_OPERATOR(!=, __ne__, __ne__)
|
||||
PKBIND_BINARY_OPERATOR(<, __lt__, __gt__)
|
||||
PKBIND_BINARY_OPERATOR(<=, __le__, __ge__)
|
||||
PKBIND_BINARY_OPERATOR(>, __gt__, __lt__)
|
||||
PKBIND_BINARY_OPERATOR(>=, __ge__, __le__)
|
||||
PKBIND_BINARY_OPERATOR(==, py_name("__eq__"), py_name("__eq__"))
|
||||
PKBIND_BINARY_OPERATOR(!=, py_name("__ne__"), py_name("__ne__"))
|
||||
PKBIND_BINARY_OPERATOR(<, py_name("__lt__"), py_name("__gt__"))
|
||||
PKBIND_BINARY_OPERATOR(<=, py_name("__le__"), py_name("__ge__"))
|
||||
PKBIND_BINARY_OPERATOR(>, py_name("__gt__"), py_name("__lt__"))
|
||||
PKBIND_BINARY_OPERATOR(>=, py_name("__ge__"), py_name("__le__"))
|
||||
|
||||
PKBIND_BINARY_OPERATOR(+, __add__, __radd__)
|
||||
PKBIND_BINARY_OPERATOR(-, __sub__, __rsub__)
|
||||
PKBIND_BINARY_OPERATOR(*, __mul__, __rmul__)
|
||||
PKBIND_BINARY_OPERATOR(/, __truediv__, __rtruediv__)
|
||||
PKBIND_BINARY_OPERATOR(%, __mod__, __rmod__)
|
||||
PKBIND_BINARY_OPERATOR(+, py_name("__add__"), py_name("__radd__"))
|
||||
PKBIND_BINARY_OPERATOR(-, py_name("__sub__"), py_name("__rsub__"))
|
||||
PKBIND_BINARY_OPERATOR(*, py_name("__mul__"), py_name("__rmul__"))
|
||||
PKBIND_BINARY_OPERATOR(/, py_name("__truediv__"), py_name("__rtruediv__"))
|
||||
PKBIND_BINARY_OPERATOR(%, py_name("__mod__"), py_name("__rmod__"))
|
||||
|
||||
// FIXME: support __rand__ ...
|
||||
PKBIND_BINARY_OPERATOR(&, __and__, 0)
|
||||
PKBIND_BINARY_OPERATOR(|, __or__, 0)
|
||||
PKBIND_BINARY_OPERATOR(^, __xor__, 0)
|
||||
PKBIND_BINARY_OPERATOR(<<, __lshift__, 0)
|
||||
PKBIND_BINARY_OPERATOR(>>, __rshift__, 0)
|
||||
PKBIND_BINARY_OPERATOR(&, py_name("__and__"), nullptr)
|
||||
PKBIND_BINARY_OPERATOR(|, py_name("__or__"), nullptr)
|
||||
PKBIND_BINARY_OPERATOR(^, py_name("__xor__"), nullptr)
|
||||
PKBIND_BINARY_OPERATOR(<<, py_name("__lshift__"), nullptr)
|
||||
PKBIND_BINARY_OPERATOR(>>, py_name("__rshift__"), nullptr)
|
||||
|
||||
#undef PKBIND_BINARY_OPERATOR
|
||||
|
||||
|
101
src/common/name.c
Normal file
101
src/common/name.c
Normal file
@ -0,0 +1,101 @@
|
||||
#if PK_ENABLE_CUSTOM_SNAME == 0
|
||||
|
||||
#include "pocketpy/common/name.h"
|
||||
#include "pocketpy/common/str.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include <stdatomic.h>
|
||||
|
||||
typedef struct NameBucket NameBucket;
|
||||
|
||||
typedef struct NameBucket {
|
||||
NameBucket* next;
|
||||
uint64_t hash;
|
||||
int size; // size of the data excluding the null-terminator
|
||||
char data[]; // null-terminated data
|
||||
} NameBucket;
|
||||
|
||||
static struct {
|
||||
NameBucket* table[0x10000];
|
||||
atomic_flag lock;
|
||||
} pk_string_table;
|
||||
|
||||
#define MAGIC_METHOD(x) py_Name x;
|
||||
#include "pocketpy/xmacros/magics.h"
|
||||
#undef MAGIC_METHOD
|
||||
|
||||
void pk_names_initialize() {
|
||||
#define MAGIC_METHOD(x) x = py_name(#x);
|
||||
#include "pocketpy/xmacros/magics.h"
|
||||
#undef MAGIC_METHOD
|
||||
}
|
||||
|
||||
void pk_names_finalize() {
|
||||
for(int i = 0; i < 0x10000; i++) {
|
||||
NameBucket* p = pk_string_table.table[i];
|
||||
while(p) {
|
||||
NameBucket* next = p->next;
|
||||
PK_FREE(p);
|
||||
p = next;
|
||||
}
|
||||
pk_string_table.table[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
py_Name py_namev(c11_sv name) {
|
||||
while(atomic_flag_test_and_set(&pk_string_table.lock)) {
|
||||
// busy-wait until the lock is released
|
||||
}
|
||||
uint64_t hash = c11_sv__hash(name);
|
||||
int index = hash & 0xFFFF;
|
||||
NameBucket* p = pk_string_table.table[index];
|
||||
NameBucket* prev = NULL;
|
||||
bool found = false;
|
||||
while(p) {
|
||||
c11_sv p_sv = {p->data, p->size};
|
||||
if(p->hash == hash && c11__sveq(p_sv, name)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
prev = p;
|
||||
p = p->next;
|
||||
}
|
||||
if(found) {
|
||||
atomic_flag_clear(&pk_string_table.lock);
|
||||
return (py_Name)p;
|
||||
}
|
||||
|
||||
// generate new index
|
||||
NameBucket* bucket = PK_MALLOC(sizeof(NameBucket) + name.size + 1);
|
||||
bucket->next = NULL;
|
||||
bucket->hash = hash;
|
||||
bucket->size = name.size;
|
||||
memcpy(bucket->data, name.data, name.size);
|
||||
bucket->data[name.size] = '\0';
|
||||
if(prev == NULL) {
|
||||
pk_string_table.table[index] = bucket;
|
||||
} else {
|
||||
assert(prev->next == NULL);
|
||||
prev->next = bucket;
|
||||
}
|
||||
atomic_flag_clear(&pk_string_table.lock);
|
||||
return (py_Name)bucket;
|
||||
}
|
||||
|
||||
c11_sv py_name2sv(py_Name index) {
|
||||
NameBucket* p = (NameBucket*)index;
|
||||
return (c11_sv){p->data, p->size};
|
||||
}
|
||||
|
||||
py_Name py_name(const char* name) {
|
||||
c11_sv sv;
|
||||
sv.data = name;
|
||||
sv.size = strlen(name);
|
||||
return py_namev(sv);
|
||||
}
|
||||
|
||||
const char* py_name2str(py_Name index) {
|
||||
NameBucket* p = (NameBucket*)index;
|
||||
return p->data;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,17 +1,23 @@
|
||||
#include "pocketpy/common/smallmap.h"
|
||||
|
||||
#define SMALLMAP_T__SOURCE
|
||||
#define K uint16_t
|
||||
#define K py_Name
|
||||
#define V int
|
||||
#define NAME c11_smallmap_n2i
|
||||
#define NAME c11_smallmap_n2d
|
||||
#include "pocketpy/xmacros/smallmap.h"
|
||||
#undef SMALLMAP_T__SOURCE
|
||||
|
||||
#define SMALLMAP_T__SOURCE
|
||||
#define K int
|
||||
#define V int
|
||||
#define NAME c11_smallmap_d2d
|
||||
#include "pocketpy/xmacros/smallmap.h"
|
||||
#undef SMALLMAP_T__SOURCE
|
||||
|
||||
#define SMALLMAP_T__SOURCE
|
||||
#define K c11_sv
|
||||
#define V uint16_t
|
||||
#define NAME c11_smallmap_s2n
|
||||
#define V int
|
||||
#define NAME c11_smallmap_v2d
|
||||
#define less(a, b) (c11_sv__cmp((a), (b)) < 0)
|
||||
#define equal(a, b) (c11_sv__cmp((a), (b)) == 0)
|
||||
#include "pocketpy/xmacros/smallmap.h"
|
||||
|
@ -224,7 +224,7 @@ void pk_vsprintf(c11_sbuf* ss, const char* fmt, va_list args) {
|
||||
break;
|
||||
}
|
||||
case 'n': {
|
||||
py_Name n = va_arg(args, int);
|
||||
py_Name n = va_arg(args, void*);
|
||||
c11_sbuf__write_cstr(ss, py_name2str(n));
|
||||
break;
|
||||
}
|
||||
|
@ -181,6 +181,15 @@ bool c11_sv__endswith(c11_sv self, c11_sv suffix) {
|
||||
return memcmp(self.data + self.size - suffix.size, suffix.data, suffix.size) == 0;
|
||||
}
|
||||
|
||||
uint64_t c11_sv__hash(c11_sv self) {
|
||||
uint64_t hash = 5381;
|
||||
for(int i = 0; i < self.size; i++) {
|
||||
// hash * 33 + c
|
||||
hash = ((hash << 5) + hash) + (unsigned char)self.data[i];
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
c11_vector /* T=c11_sv */ c11_sv__split(c11_sv self, char sep) {
|
||||
c11_vector retval;
|
||||
c11_vector__ctor(&retval, sizeof(c11_sv));
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "pocketpy/compiler/compiler.h"
|
||||
#include "pocketpy/common/vector.h"
|
||||
#include "pocketpy/common/name.h"
|
||||
#include "pocketpy/compiler/lexer.h"
|
||||
#include "pocketpy/objects/base.h"
|
||||
#include "pocketpy/objects/codeobject.h"
|
||||
@ -61,9 +62,9 @@ typedef struct Ctx {
|
||||
int level;
|
||||
int curr_iblock;
|
||||
bool is_compiling_class;
|
||||
c11_vector /*T=Expr* */ s_expr;
|
||||
c11_smallmap_n2i global_names;
|
||||
c11_smallmap_s2n co_consts_string_dedup_map;
|
||||
c11_vector /*T=Expr_p*/ s_expr;
|
||||
c11_smallmap_n2d global_names;
|
||||
c11_smallmap_v2d co_consts_string_dedup_map; // this stores 0-based index instead of pointer
|
||||
} Ctx;
|
||||
|
||||
typedef struct Expr Expr;
|
||||
@ -75,11 +76,12 @@ static int Ctx__enter_block(Ctx* self, CodeBlockType type);
|
||||
static void Ctx__exit_block(Ctx* self);
|
||||
static int Ctx__emit_(Ctx* self, Opcode opcode, uint16_t arg, int line);
|
||||
static int Ctx__emit_virtual(Ctx* self, Opcode opcode, uint16_t arg, int line, bool virtual);
|
||||
static void Ctx__revert_last_emit_(Ctx* self);
|
||||
// static void Ctx__revert_last_emit_(Ctx* self);
|
||||
static int Ctx__emit_int(Ctx* self, int64_t value, int line);
|
||||
static void Ctx__patch_jump(Ctx* self, int index);
|
||||
static void Ctx__emit_jump(Ctx* self, int target, int line);
|
||||
static int Ctx__add_varname(Ctx* self, py_Name name);
|
||||
static int Ctx__add_name(Ctx* self, py_Name name);
|
||||
static int Ctx__add_const(Ctx* self, py_Ref);
|
||||
static int Ctx__add_const_string(Ctx* self, c11_sv);
|
||||
static void Ctx__emit_store_name(Ctx* self, NameScope scope, py_Name name, int line);
|
||||
@ -100,7 +102,7 @@ typedef struct NameExpr {
|
||||
|
||||
void NameExpr__emit_(Expr* self_, Ctx* ctx) {
|
||||
NameExpr* self = (NameExpr*)self_;
|
||||
int index = c11_smallmap_n2i__get(&ctx->co->varnames_inv, self->name, -1);
|
||||
int index = c11_smallmap_n2d__get(&ctx->co->varnames_inv, self->name, -1);
|
||||
if(self->scope == NAME_LOCAL && index >= 0) {
|
||||
// we know this is a local variable
|
||||
Ctx__emit_(ctx, OP_LOAD_FAST, index, self->line);
|
||||
@ -117,7 +119,7 @@ void NameExpr__emit_(Expr* self_, Ctx* ctx) {
|
||||
}
|
||||
}
|
||||
}
|
||||
Ctx__emit_(ctx, op, self->name, self->line);
|
||||
Ctx__emit_(ctx, op, Ctx__add_name(ctx, self->name), self->line);
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,7 +131,7 @@ bool NameExpr__emit_del(Expr* self_, Ctx* ctx) {
|
||||
break;
|
||||
case NAME_GLOBAL: {
|
||||
Opcode op = ctx->co->src->is_dynamic ? OP_DELETE_NAME : OP_DELETE_GLOBAL;
|
||||
Ctx__emit_(ctx, op, self->name, self->line);
|
||||
Ctx__emit_(ctx, op, Ctx__add_name(ctx, self->name), self->line);
|
||||
break;
|
||||
}
|
||||
default: c11__unreachable();
|
||||
@ -140,7 +142,7 @@ bool NameExpr__emit_del(Expr* self_, Ctx* ctx) {
|
||||
bool NameExpr__emit_store(Expr* self_, Ctx* ctx) {
|
||||
NameExpr* self = (NameExpr*)self_;
|
||||
if(ctx->is_compiling_class) {
|
||||
Ctx__emit_(ctx, OP_STORE_CLASS_ATTR, self->name, self->line);
|
||||
Ctx__emit_(ctx, OP_STORE_CLASS_ATTR, Ctx__add_name(ctx, self->name), self->line);
|
||||
return true;
|
||||
}
|
||||
Ctx__emit_store_name(ctx, self->scope, self->name, self->line);
|
||||
@ -710,19 +712,19 @@ static void BinaryExpr__dtor(Expr* self_) {
|
||||
vtdelete(self->rhs);
|
||||
}
|
||||
|
||||
static py_Name cmp_token2name(TokenIndex token) {
|
||||
static Opcode cmp_token2op(TokenIndex token) {
|
||||
switch(token) {
|
||||
case TK_LT: return __lt__;
|
||||
case TK_LE: return __le__;
|
||||
case TK_EQ: return __eq__;
|
||||
case TK_NE: return __ne__;
|
||||
case TK_GT: return __gt__;
|
||||
case TK_GE: return __ge__;
|
||||
case TK_LT: return OP_COMPARE_LT;
|
||||
case TK_LE: return OP_COMPARE_LE;
|
||||
case TK_EQ: return OP_COMPARE_EQ;
|
||||
case TK_NE: return OP_COMPARE_NE;
|
||||
case TK_GT: return OP_COMPARE_GT;
|
||||
case TK_GE: return OP_COMPARE_GE;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#define is_compare_expr(e) ((e)->vt->is_binary && cmp_token2name(((BinaryExpr*)(e))->op))
|
||||
#define is_compare_expr(e) ((e)->vt->is_binary && cmp_token2op(((BinaryExpr*)(e))->op))
|
||||
|
||||
static void _emit_compare(BinaryExpr* self, Ctx* ctx, c11_vector* jmps) {
|
||||
if(is_compare_expr(self->lhs)) {
|
||||
@ -733,7 +735,7 @@ static void _emit_compare(BinaryExpr* self, Ctx* ctx, c11_vector* jmps) {
|
||||
vtemit_(self->rhs, ctx); // [a, b]
|
||||
Ctx__emit_(ctx, OP_DUP_TOP, BC_NOARG, self->line); // [a, b, b]
|
||||
Ctx__emit_(ctx, OP_ROT_THREE, BC_NOARG, self->line); // [b, a, b]
|
||||
Ctx__emit_(ctx, OP_BINARY_OP, cmp_token2name(self->op), self->line);
|
||||
Ctx__emit_(ctx, cmp_token2op(self->op), BC_NOARG, self->line);
|
||||
// [b, RES]
|
||||
int index = Ctx__emit_(ctx, OP_SHORTCUT_IF_FALSE_OR_POP, BC_NOARG, self->line);
|
||||
c11_vector__push(int, jmps, index);
|
||||
@ -743,7 +745,7 @@ static void BinaryExpr__emit_(Expr* self_, Ctx* ctx) {
|
||||
BinaryExpr* self = (BinaryExpr*)self_;
|
||||
c11_vector /*T=int*/ jmps;
|
||||
c11_vector__ctor(&jmps, sizeof(int));
|
||||
if(cmp_token2name(self->op) && is_compare_expr(self->lhs)) {
|
||||
if(cmp_token2op(self->op) && is_compare_expr(self->lhs)) {
|
||||
// (a < b) < c
|
||||
BinaryExpr* e = (BinaryExpr*)self->lhs;
|
||||
_emit_compare(e, ctx, &jmps);
|
||||
@ -759,24 +761,24 @@ static void BinaryExpr__emit_(Expr* self_, Ctx* ctx) {
|
||||
|
||||
vtemit_(self->rhs, ctx);
|
||||
|
||||
Opcode opcode = OP_BINARY_OP;
|
||||
Opcode opcode;
|
||||
uint16_t arg = BC_NOARG;
|
||||
|
||||
switch(self->op) {
|
||||
case TK_ADD: arg = __add__ | (__radd__ << 8); break;
|
||||
case TK_SUB: arg = __sub__ | (__rsub__ << 8); break;
|
||||
case TK_MUL: arg = __mul__ | (__rmul__ << 8); break;
|
||||
case TK_DIV: arg = __truediv__ | (__rtruediv__ << 8); break;
|
||||
case TK_FLOORDIV: arg = __floordiv__ | (__rfloordiv__ << 8); break;
|
||||
case TK_MOD: arg = __mod__ | (__rmod__ << 8); break;
|
||||
case TK_POW: arg = __pow__ | (__rpow__ << 8); break;
|
||||
case TK_ADD: opcode = OP_BINARY_ADD; break;
|
||||
case TK_SUB: opcode = OP_BINARY_SUB; break;
|
||||
case TK_MUL: opcode = OP_BINARY_MUL; break;
|
||||
case TK_DIV: opcode = OP_BINARY_TRUEDIV; break;
|
||||
case TK_FLOORDIV: opcode = OP_BINARY_FLOORDIV; break;
|
||||
case TK_MOD: opcode = OP_BINARY_MOD; break;
|
||||
case TK_POW: opcode = OP_BINARY_POW; break;
|
||||
|
||||
case TK_LT: arg = __lt__ | (__gt__ << 8); break;
|
||||
case TK_LE: arg = __le__ | (__ge__ << 8); break;
|
||||
case TK_EQ: arg = __eq__ | (__eq__ << 8); break;
|
||||
case TK_NE: arg = __ne__ | (__ne__ << 8); break;
|
||||
case TK_GT: arg = __gt__ | (__lt__ << 8); break;
|
||||
case TK_GE: arg = __ge__ | (__le__ << 8); break;
|
||||
case TK_LT: opcode = OP_COMPARE_LT; break;
|
||||
case TK_LE: opcode = OP_COMPARE_LE; break;
|
||||
case TK_EQ: opcode = OP_COMPARE_EQ; break;
|
||||
case TK_NE: opcode = OP_COMPARE_NE; break;
|
||||
case TK_GT: opcode = OP_COMPARE_GT; break;
|
||||
case TK_GE: opcode = OP_COMPARE_GE; break;
|
||||
|
||||
case TK_IN:
|
||||
opcode = OP_CONTAINS_OP;
|
||||
@ -795,13 +797,13 @@ static void BinaryExpr__emit_(Expr* self_, Ctx* ctx) {
|
||||
arg = 1;
|
||||
break;
|
||||
|
||||
case TK_LSHIFT: arg = __lshift__; break;
|
||||
case TK_RSHIFT: arg = __rshift__; break;
|
||||
case TK_AND: arg = __and__; break;
|
||||
case TK_OR: arg = __or__; break;
|
||||
case TK_XOR: arg = __xor__; break;
|
||||
case TK_DECORATOR: arg = __matmul__; break;
|
||||
default: assert(false);
|
||||
case TK_LSHIFT: opcode = OP_BINARY_LSHIFT; break;
|
||||
case TK_RSHIFT: opcode = OP_BINARY_RSHIFT; break;
|
||||
case TK_AND: opcode = OP_BINARY_AND; break;
|
||||
case TK_OR: opcode = OP_BINARY_OR; break;
|
||||
case TK_XOR: opcode = OP_BINARY_XOR; break;
|
||||
case TK_DECORATOR: opcode = OP_BINARY_MATMUL; break;
|
||||
default: c11__unreachable();
|
||||
}
|
||||
|
||||
Ctx__emit_(ctx, opcode, arg, self->line);
|
||||
@ -945,20 +947,20 @@ void AttribExpr__dtor(Expr* self_) {
|
||||
void AttribExpr__emit_(Expr* self_, Ctx* ctx) {
|
||||
AttribExpr* self = (AttribExpr*)self_;
|
||||
vtemit_(self->child, ctx);
|
||||
Ctx__emit_(ctx, OP_LOAD_ATTR, self->name, self->line);
|
||||
Ctx__emit_(ctx, OP_LOAD_ATTR, Ctx__add_name(ctx, self->name), self->line);
|
||||
}
|
||||
|
||||
bool AttribExpr__emit_del(Expr* self_, Ctx* ctx) {
|
||||
AttribExpr* self = (AttribExpr*)self_;
|
||||
vtemit_(self->child, ctx);
|
||||
Ctx__emit_(ctx, OP_DELETE_ATTR, self->name, self->line);
|
||||
Ctx__emit_(ctx, OP_DELETE_ATTR, Ctx__add_name(ctx, self->name), self->line);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AttribExpr__emit_store(Expr* self_, Ctx* ctx) {
|
||||
AttribExpr* self = (AttribExpr*)self_;
|
||||
vtemit_(self->child, ctx);
|
||||
Ctx__emit_(ctx, OP_STORE_ATTR, self->name, self->line);
|
||||
Ctx__emit_(ctx, OP_STORE_ATTR, Ctx__add_name(ctx, self->name), self->line);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -966,14 +968,14 @@ void AttribExpr__emit_inplace(Expr* self_, Ctx* ctx) {
|
||||
AttribExpr* self = (AttribExpr*)self_;
|
||||
vtemit_(self->child, ctx);
|
||||
Ctx__emit_(ctx, OP_DUP_TOP, BC_NOARG, self->line);
|
||||
Ctx__emit_(ctx, OP_LOAD_ATTR, self->name, self->line);
|
||||
Ctx__emit_(ctx, OP_LOAD_ATTR, Ctx__add_name(ctx, self->name), self->line);
|
||||
}
|
||||
|
||||
bool AttribExpr__emit_istore(Expr* self_, Ctx* ctx) {
|
||||
// [a, val] -> [val, a]
|
||||
AttribExpr* self = (AttribExpr*)self_;
|
||||
Ctx__emit_(ctx, OP_ROT_TWO, BC_NOARG, self->line);
|
||||
Ctx__emit_(ctx, OP_STORE_ATTR, self->name, self->line);
|
||||
Ctx__emit_(ctx, OP_STORE_ATTR, Ctx__add_name(ctx, self->name), self->line);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1031,7 +1033,7 @@ void CallExpr__emit_(Expr* self_, Ctx* ctx) {
|
||||
if(self->callable->vt->is_attrib) {
|
||||
AttribExpr* p = (AttribExpr*)self->callable;
|
||||
vtemit_(p->child, ctx);
|
||||
Ctx__emit_(ctx, OP_LOAD_METHOD, p->name, p->line);
|
||||
Ctx__emit_(ctx, OP_LOAD_METHOD, Ctx__add_name(ctx, p->name), p->line);
|
||||
} else {
|
||||
vtemit_(self->callable, ctx);
|
||||
Ctx__emit_(ctx, OP_LOAD_NULL, BC_NOARG, BC_KEEPLINE);
|
||||
@ -1046,7 +1048,7 @@ void CallExpr__emit_(Expr* self_, Ctx* ctx) {
|
||||
|
||||
c11__foreach(Expr*, &self->args, e) { vtemit_(*e, ctx); }
|
||||
c11__foreach(CallExprKwArg, &self->kwargs, e) {
|
||||
Ctx__emit_int(ctx, e->key, self->line);
|
||||
Ctx__emit_int(ctx, (uintptr_t)e->key, self->line);
|
||||
vtemit_(e->val, ctx);
|
||||
}
|
||||
int KWARGC = self->kwargs.length;
|
||||
@ -1074,8 +1076,8 @@ static void Ctx__ctor(Ctx* self, CodeObject* co, FuncDecl* func, int level) {
|
||||
self->curr_iblock = 0;
|
||||
self->is_compiling_class = false;
|
||||
c11_vector__ctor(&self->s_expr, sizeof(Expr*));
|
||||
c11_smallmap_n2i__ctor(&self->global_names);
|
||||
c11_smallmap_s2n__ctor(&self->co_consts_string_dedup_map);
|
||||
c11_smallmap_n2d__ctor(&self->global_names);
|
||||
c11_smallmap_v2d__ctor(&self->co_consts_string_dedup_map);
|
||||
}
|
||||
|
||||
static void Ctx__dtor(Ctx* self) {
|
||||
@ -1084,13 +1086,13 @@ static void Ctx__dtor(Ctx* self) {
|
||||
vtdelete(c11__getitem(Expr*, &self->s_expr, i));
|
||||
}
|
||||
c11_vector__dtor(&self->s_expr);
|
||||
c11_smallmap_n2i__dtor(&self->global_names);
|
||||
c11_smallmap_n2d__dtor(&self->global_names);
|
||||
// free the dedup map
|
||||
c11__foreach(c11_smallmap_s2n_KV, &self->co_consts_string_dedup_map, p_kv) {
|
||||
c11__foreach(c11_smallmap_v2d_KV, &self->co_consts_string_dedup_map, p_kv) {
|
||||
const char* p = p_kv->key.data;
|
||||
PK_FREE((void*)p);
|
||||
}
|
||||
c11_smallmap_s2n__dtor(&self->co_consts_string_dedup_map);
|
||||
c11_smallmap_v2d__dtor(&self->co_consts_string_dedup_map);
|
||||
}
|
||||
|
||||
static int Ctx__prepare_loop_divert(Ctx* self, int line, bool is_break) {
|
||||
@ -1166,10 +1168,10 @@ static int Ctx__emit_(Ctx* self, Opcode opcode, uint16_t arg, int line) {
|
||||
return Ctx__emit_virtual(self, opcode, arg, line, false);
|
||||
}
|
||||
|
||||
static void Ctx__revert_last_emit_(Ctx* self) {
|
||||
c11_vector__pop(&self->co->codes);
|
||||
c11_vector__pop(&self->co->codes_ex);
|
||||
}
|
||||
// static void Ctx__revert_last_emit_(Ctx* self) {
|
||||
// c11_vector__pop(&self->co->codes);
|
||||
// c11_vector__pop(&self->co->codes_ex);
|
||||
// }
|
||||
|
||||
static int Ctx__emit_int(Ctx* self, int64_t value, int line) {
|
||||
if(INT16_MIN <= value && value <= INT16_MAX) {
|
||||
@ -1199,6 +1201,8 @@ static int Ctx__add_varname(Ctx* self, py_Name name) {
|
||||
return CodeObject__add_varname(self->co, name);
|
||||
}
|
||||
|
||||
static int Ctx__add_name(Ctx* self, py_Name name) { return CodeObject__add_name(self->co, name); }
|
||||
|
||||
static int Ctx__add_const_string(Ctx* self, c11_sv key) {
|
||||
if(key.size > 100) {
|
||||
py_Ref tmp = c11_vector__emplace(&self->co->consts);
|
||||
@ -1206,7 +1210,7 @@ static int Ctx__add_const_string(Ctx* self, c11_sv key) {
|
||||
int index = self->co->consts.length - 1;
|
||||
return index;
|
||||
}
|
||||
uint16_t* val = c11_smallmap_s2n__try_get(&self->co_consts_string_dedup_map, key);
|
||||
int* val = c11_smallmap_v2d__try_get(&self->co_consts_string_dedup_map, key);
|
||||
if(val) {
|
||||
return *val;
|
||||
} else {
|
||||
@ -1217,7 +1221,7 @@ static int Ctx__add_const_string(Ctx* self, c11_sv key) {
|
||||
char* new_buf = PK_MALLOC(key.size + 1);
|
||||
memcpy(new_buf, key.data, key.size);
|
||||
new_buf[key.size] = 0;
|
||||
c11_smallmap_s2n__set(&self->co_consts_string_dedup_map,
|
||||
c11_smallmap_v2d__set(&self->co_consts_string_dedup_map,
|
||||
(c11_sv){new_buf, key.size},
|
||||
index);
|
||||
return index;
|
||||
@ -1235,7 +1239,7 @@ static void Ctx__emit_store_name(Ctx* self, NameScope scope, py_Name name, int l
|
||||
case NAME_LOCAL: Ctx__emit_(self, OP_STORE_FAST, Ctx__add_varname(self, name), line); break;
|
||||
case NAME_GLOBAL: {
|
||||
Opcode op = self->co->src->is_dynamic ? OP_STORE_NAME : OP_STORE_GLOBAL;
|
||||
Ctx__emit_(self, op, name, line);
|
||||
Ctx__emit_(self, op, Ctx__add_name(self, name), line);
|
||||
} break;
|
||||
default: c11__unreachable();
|
||||
}
|
||||
@ -1742,7 +1746,7 @@ static Error* exprName(Compiler* self) {
|
||||
py_Name name = py_namev(Token__sv(prev()));
|
||||
NameScope scope = name_scope(self);
|
||||
// promote this name to global scope if needed
|
||||
if(c11_smallmap_n2i__contains(&ctx()->global_names, name)) {
|
||||
if(c11_smallmap_n2d__contains(&ctx()->global_names, name)) {
|
||||
if(self->src->is_dynamic) return SyntaxError(self, "cannot use global keyword here");
|
||||
scope = NAME_GLOBAL;
|
||||
}
|
||||
@ -2371,7 +2375,7 @@ static Error* compile_function(Compiler* self, int decorators) {
|
||||
}
|
||||
}
|
||||
|
||||
Ctx__emit_(ctx(), OP_STORE_CLASS_ATTR, decl_name, prev()->line);
|
||||
Ctx__emit_(ctx(), OP_STORE_CLASS_ATTR, Ctx__add_name(ctx(), decl_name), prev()->line);
|
||||
} else {
|
||||
NameExpr* e = NameExpr__new(prev()->line, decl_name, name_scope(self));
|
||||
vtemit_store((Expr*)e, ctx());
|
||||
@ -2399,7 +2403,7 @@ static Error* compile_class(Compiler* self, int decorators) {
|
||||
} else {
|
||||
Ctx__s_emit_top(ctx()); // []
|
||||
}
|
||||
Ctx__emit_(ctx(), OP_BEGIN_CLASS, name, BC_KEEPLINE);
|
||||
Ctx__emit_(ctx(), OP_BEGIN_CLASS, Ctx__add_name(ctx(), name), BC_KEEPLINE);
|
||||
|
||||
c11__foreach(Ctx, &self->contexts, it) {
|
||||
if(it->is_compiling_class) return SyntaxError(self, "nested class is not allowed");
|
||||
@ -2409,7 +2413,7 @@ static Error* compile_class(Compiler* self, int decorators) {
|
||||
ctx()->is_compiling_class = false;
|
||||
|
||||
Ctx__s_emit_decorators(ctx(), decorators);
|
||||
Ctx__emit_(ctx(), OP_END_CLASS, name, BC_KEEPLINE);
|
||||
Ctx__emit_(ctx(), OP_END_CLASS, Ctx__add_name(ctx(), name), BC_KEEPLINE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -2517,7 +2521,7 @@ __EAT_DOTS_END:
|
||||
Ctx__emit_(ctx(), OP_DUP_TOP, BC_NOARG, BC_KEEPLINE);
|
||||
consume(TK_ID);
|
||||
c11_sv name = Token__sv(prev());
|
||||
Ctx__emit_(ctx(), OP_LOAD_ATTR, py_namev(name), prev()->line);
|
||||
Ctx__emit_(ctx(), OP_LOAD_ATTR, Ctx__add_name(ctx(), py_namev(name)), prev()->line);
|
||||
if(match(TK_AS)) {
|
||||
consume(TK_ID);
|
||||
name = Token__sv(prev());
|
||||
@ -2722,7 +2726,7 @@ static Error* compile_stmt(Compiler* self) {
|
||||
do {
|
||||
consume(TK_ID);
|
||||
py_Name name = py_namev(Token__sv(prev()));
|
||||
c11_smallmap_n2i__set(&ctx()->global_names, name, 0);
|
||||
c11_smallmap_n2d__set(&ctx()->global_names, name, 0);
|
||||
} while(match(TK_COMMA));
|
||||
consume_end_stmt();
|
||||
break;
|
||||
@ -2783,7 +2787,10 @@ static Error* compile_stmt(Compiler* self) {
|
||||
NameExpr* ne = (NameExpr*)Ctx__s_top(ctx());
|
||||
int index = Ctx__add_const_string(ctx(), type_hint);
|
||||
Ctx__emit_(ctx(), OP_LOAD_CONST, index, BC_KEEPLINE);
|
||||
Ctx__emit_(ctx(), OP_ADD_CLASS_ANNOTATION, ne->name, BC_KEEPLINE);
|
||||
Ctx__emit_(ctx(),
|
||||
OP_ADD_CLASS_ANNOTATION,
|
||||
Ctx__add_name(ctx(), ne->name),
|
||||
BC_KEEPLINE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ static bool unpack_dict_to_buffer(py_Ref key, py_Ref val, void* ctx) {
|
||||
py_TValue** p = ctx;
|
||||
if(py_isstr(key)) {
|
||||
py_Name name = py_namev(py_tosv(key));
|
||||
py_newint(*p, name);
|
||||
py_newint(*p, (uintptr_t)name);
|
||||
py_assign(*p + 1, val);
|
||||
(*p) += 2;
|
||||
return true;
|
||||
@ -80,7 +80,8 @@ static bool unpack_dict_to_buffer(py_Ref key, py_Ref val, void* ctx) {
|
||||
|
||||
FrameResult VM__run_top_frame(VM* self) {
|
||||
py_Frame* frame = self->top_frame;
|
||||
Bytecode* codes;
|
||||
Bytecode* co_codes;
|
||||
py_Name* co_names;
|
||||
|
||||
const py_Frame* base_frame = frame;
|
||||
|
||||
@ -91,11 +92,13 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
py_exception(tp_RecursionError, "maximum recursion depth exceeded");
|
||||
goto __ERROR;
|
||||
}
|
||||
codes = frame->co->codes.data;
|
||||
// NOTE: remember to change another occurrence after __ERROR_RE_RAISE:
|
||||
co_codes = frame->co->codes.data;
|
||||
co_names = frame->co->names.data;
|
||||
frame->ip++;
|
||||
|
||||
__NEXT_STEP:
|
||||
byte = codes[frame->ip];
|
||||
byte = co_codes[frame->ip];
|
||||
|
||||
if(self->trace_info.func) {
|
||||
SourceLocation loc = Frame__source_location(frame);
|
||||
@ -195,7 +198,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
ud->closure = FastLocals__to_namedict(frame->locals, frame->co);
|
||||
py_Name name = py_name(decl->code.name->data);
|
||||
// capture itself to allow recursion
|
||||
NameDict__set(ud->closure, name, *SP());
|
||||
NameDict__set(ud->closure, name, SP());
|
||||
}
|
||||
SP()++;
|
||||
DISPATCH();
|
||||
@ -211,13 +214,13 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
PUSH(val);
|
||||
DISPATCH();
|
||||
}
|
||||
py_Name name = c11__getitem(uint16_t, &frame->co->varnames, byte.arg);
|
||||
py_Name name = c11__getitem(py_Name, &frame->co->varnames, byte.arg);
|
||||
UnboundLocalError(name);
|
||||
goto __ERROR;
|
||||
}
|
||||
case OP_LOAD_NAME: {
|
||||
assert(frame->is_locals_special);
|
||||
py_Name name = byte.arg;
|
||||
py_Name name = co_names[byte.arg];
|
||||
// locals
|
||||
switch(frame->locals->type) {
|
||||
case tp_locals: {
|
||||
@ -261,7 +264,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
goto __ERROR;
|
||||
}
|
||||
case OP_LOAD_NONLOCAL: {
|
||||
py_Name name = byte.arg;
|
||||
py_Name name = co_names[byte.arg];
|
||||
py_Ref tmp = Frame__getclosure(frame, name);
|
||||
if(tmp != NULL) {
|
||||
PUSH(tmp);
|
||||
@ -283,7 +286,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
goto __ERROR;
|
||||
}
|
||||
case OP_LOAD_GLOBAL: {
|
||||
py_Name name = byte.arg;
|
||||
py_Name name = co_names[byte.arg];
|
||||
int res = Frame__getglobal(frame, name);
|
||||
if(res == 1) {
|
||||
PUSH(&self->last_retval);
|
||||
@ -299,7 +302,8 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
goto __ERROR;
|
||||
}
|
||||
case OP_LOAD_ATTR: {
|
||||
if(py_getattr(TOP(), byte.arg)) {
|
||||
py_Name name = co_names[byte.arg];
|
||||
if(py_getattr(TOP(), name)) {
|
||||
py_assign(TOP(), py_retval());
|
||||
} else {
|
||||
goto __ERROR;
|
||||
@ -308,7 +312,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
}
|
||||
case OP_LOAD_CLASS_GLOBAL: {
|
||||
assert(self->curr_class);
|
||||
py_Name name = byte.arg;
|
||||
py_Name name = co_names[byte.arg];
|
||||
py_Ref tmp = py_getdict(self->curr_class, name);
|
||||
if(tmp) {
|
||||
PUSH(tmp);
|
||||
@ -331,10 +335,11 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
}
|
||||
case OP_LOAD_METHOD: {
|
||||
// [self] -> [unbound, self]
|
||||
bool ok = py_pushmethod(byte.arg);
|
||||
py_Name name = co_names[byte.arg];
|
||||
bool ok = py_pushmethod(name);
|
||||
if(!ok) {
|
||||
// fallback to getattr
|
||||
if(py_getattr(TOP(), byte.arg)) {
|
||||
if(py_getattr(TOP(), name)) {
|
||||
py_assign(TOP(), py_retval());
|
||||
py_newnil(SP()++);
|
||||
} else {
|
||||
@ -368,7 +373,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
}
|
||||
case OP_STORE_NAME: {
|
||||
assert(frame->is_locals_special);
|
||||
py_Name name = byte.arg;
|
||||
py_Name name = co_names[byte.arg];
|
||||
switch(frame->locals->type) {
|
||||
case tp_locals: {
|
||||
py_Frame* noproxy = frame->locals->_ptr;
|
||||
@ -395,13 +400,15 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
}
|
||||
}
|
||||
case OP_STORE_GLOBAL: {
|
||||
if(!Frame__setglobal(frame, byte.arg, TOP())) goto __ERROR;
|
||||
py_Name name = co_names[byte.arg];
|
||||
if(!Frame__setglobal(frame, name, TOP())) goto __ERROR;
|
||||
POP();
|
||||
DISPATCH();
|
||||
}
|
||||
case OP_STORE_ATTR: {
|
||||
// [val, a] -> a.b = val
|
||||
if(!py_setattr(TOP(), byte.arg, SECOND())) goto __ERROR;
|
||||
py_Name name = co_names[byte.arg];
|
||||
if(!py_setattr(TOP(), name, SECOND())) goto __ERROR;
|
||||
STACK_SHRINK(2);
|
||||
DISPATCH();
|
||||
}
|
||||
@ -435,7 +442,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
}
|
||||
case OP_DELETE_NAME: {
|
||||
assert(frame->is_locals_special);
|
||||
py_Name name = byte.arg;
|
||||
py_Name name = co_names[byte.arg];
|
||||
switch(frame->locals->type) {
|
||||
case tp_locals: {
|
||||
py_Frame* noproxy = frame->locals->_ptr;
|
||||
@ -464,7 +471,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
}
|
||||
}
|
||||
case OP_DELETE_GLOBAL: {
|
||||
py_Name name = byte.arg;
|
||||
py_Name name = co_names[byte.arg];
|
||||
int res = Frame__delglobal(frame, name);
|
||||
if(res == 1) DISPATCH();
|
||||
if(res == -1) goto __ERROR;
|
||||
@ -473,7 +480,8 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
}
|
||||
|
||||
case OP_DELETE_ATTR: {
|
||||
if(!py_delattr(TOP(), byte.arg)) goto __ERROR;
|
||||
py_Name name = co_names[byte.arg];
|
||||
if(!py_delattr(TOP(), name)) goto __ERROR;
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
@ -594,14 +602,33 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
DISPATCH();
|
||||
}
|
||||
/*****************************/
|
||||
case OP_BINARY_OP: {
|
||||
py_Name op = byte.arg & 0xFF;
|
||||
py_Name rop = byte.arg >> 8;
|
||||
if(!pk_stack_binaryop(self, op, rop)) goto __ERROR;
|
||||
POP();
|
||||
*TOP() = self->last_retval;
|
||||
DISPATCH();
|
||||
#define CASE_BINARY_OP(label, op, rop)\
|
||||
case label: {\
|
||||
if(!pk_stack_binaryop(self, op, rop)) goto __ERROR;\
|
||||
POP();\
|
||||
*TOP() = self->last_retval;\
|
||||
DISPATCH();\
|
||||
}
|
||||
CASE_BINARY_OP(OP_BINARY_ADD, __add__, __radd__)
|
||||
CASE_BINARY_OP(OP_BINARY_SUB, __sub__, __rsub__)
|
||||
CASE_BINARY_OP(OP_BINARY_MUL, __mul__, __rmul__)
|
||||
CASE_BINARY_OP(OP_BINARY_TRUEDIV, __truediv__, __rtruediv__)
|
||||
CASE_BINARY_OP(OP_BINARY_FLOORDIV, __floordiv__, __rfloordiv__)
|
||||
CASE_BINARY_OP(OP_BINARY_MOD, __mod__, __rmod__)
|
||||
CASE_BINARY_OP(OP_BINARY_POW, __pow__, __rpow__)
|
||||
CASE_BINARY_OP(OP_BINARY_LSHIFT, __lshift__, 0)
|
||||
CASE_BINARY_OP(OP_BINARY_RSHIFT, __rshift__, 0)
|
||||
CASE_BINARY_OP(OP_BINARY_AND, __and__, 0)
|
||||
CASE_BINARY_OP(OP_BINARY_OR, __or__, 0)
|
||||
CASE_BINARY_OP(OP_BINARY_XOR, __xor__, 0)
|
||||
CASE_BINARY_OP(OP_BINARY_MATMUL, __matmul__, 0)
|
||||
CASE_BINARY_OP(OP_COMPARE_LT, __lt__, __gt__)
|
||||
CASE_BINARY_OP(OP_COMPARE_LE, __le__, __ge__)
|
||||
CASE_BINARY_OP(OP_COMPARE_EQ, __eq__, __eq__)
|
||||
CASE_BINARY_OP(OP_COMPARE_NE, __ne__, __ne__)
|
||||
CASE_BINARY_OP(OP_COMPARE_GT, __gt__, __lt__)
|
||||
CASE_BINARY_OP(OP_COMPARE_GE, __ge__, __le__)
|
||||
#undef CASE_BINARY_OP
|
||||
case OP_IS_OP: {
|
||||
bool res = py_isidentical(SECOND(), TOP());
|
||||
POP();
|
||||
@ -875,7 +902,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
case OP_POP_IMPORT_STAR: {
|
||||
// [module]
|
||||
NameDict* dict = PyObject__dict(TOP()->_obj);
|
||||
py_Ref all = NameDict__try_get(dict, __all__);
|
||||
py_ItemRef all = NameDict__try_get(dict, __all__);
|
||||
if(all) {
|
||||
py_TValue* p;
|
||||
int length = pk_arrayview(all, &p);
|
||||
@ -885,7 +912,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
}
|
||||
for(int i = 0; i < length; i++) {
|
||||
py_Name name = py_namev(py_tosv(p + i));
|
||||
py_Ref value = NameDict__try_get(dict, name);
|
||||
py_ItemRef value = NameDict__try_get(dict, name);
|
||||
if(value == NULL) {
|
||||
ImportError("cannot import name '%n'", name);
|
||||
goto __ERROR;
|
||||
@ -894,9 +921,9 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(int i = 0; i < dict->length; i++) {
|
||||
NameDict_KV* kv = c11__at(NameDict_KV, dict, i);
|
||||
if(!kv->key) continue;
|
||||
for(int i = 0; i < dict->capacity; i++) {
|
||||
NameDict_KV* kv = &dict->items[i];
|
||||
if(kv->key == NULL) continue;
|
||||
c11_sv name = py_name2sv(kv->key);
|
||||
if(name.size == 0 || name.data[0] == '_') continue;
|
||||
if(!Frame__setglobal(frame, kv->key, &kv->value)) goto __ERROR;
|
||||
@ -999,7 +1026,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
///////////
|
||||
case OP_BEGIN_CLASS: {
|
||||
// [base]
|
||||
py_Name name = byte.arg;
|
||||
py_Name name = co_names[byte.arg];
|
||||
py_Type base;
|
||||
if(py_isnone(TOP())) {
|
||||
base = tp_object;
|
||||
@ -1027,7 +1054,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
}
|
||||
case OP_END_CLASS: {
|
||||
// [cls or decorated]
|
||||
py_Name name = byte.arg;
|
||||
py_Name name = co_names[byte.arg];
|
||||
if(!Frame__setglobal(frame, name, TOP())) goto __ERROR;
|
||||
|
||||
if(py_istype(TOP(), tp_type)) {
|
||||
@ -1037,9 +1064,9 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
py_TypeInfo* base_ti = ti->base_ti;
|
||||
if(base_ti->on_end_subclass) base_ti->on_end_subclass(ti);
|
||||
}
|
||||
py_TValue* slot_eq = TypeList__magic_common(ti, __eq__);
|
||||
py_TValue* slot_ne = TypeList__magic_common(ti, __ne__);
|
||||
if(!py_isnil(slot_eq) && py_isnil(slot_ne)) {
|
||||
py_TValue* slot_eq = py_getdict(&ti->self, __eq__);
|
||||
py_TValue* slot_ne = py_getdict(&ti->self, __ne__);
|
||||
if(slot_eq && !slot_ne) {
|
||||
TypeError("'%n' implements '__eq__' but not '__ne__'", ti->name);
|
||||
goto __ERROR;
|
||||
}
|
||||
@ -1052,7 +1079,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
}
|
||||
case OP_STORE_CLASS_ATTR: {
|
||||
assert(self->curr_class);
|
||||
py_Name name = byte.arg;
|
||||
py_Name name = co_names[byte.arg];
|
||||
// TOP() can be a function, classmethod or custom decorator
|
||||
py_Ref actual_func = TOP();
|
||||
if(actual_func->type == tp_classmethod) {
|
||||
@ -1072,7 +1099,8 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
py_Type type = py_totype(self->curr_class);
|
||||
py_TypeInfo* ti = TypeList__get(&self->types, type);
|
||||
if(py_isnil(&ti->annotations)) py_newdict(&ti->annotations);
|
||||
bool ok = py_dict_setitem_by_str(&ti->annotations, py_name2str(byte.arg), TOP());
|
||||
py_Name name = co_names[byte.arg];
|
||||
bool ok = py_dict_setitem_by_str(&ti->annotations, py_name2str(name), TOP());
|
||||
if(!ok) goto __ERROR;
|
||||
POP();
|
||||
DISPATCH();
|
||||
@ -1211,7 +1239,8 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
return RES_ERROR;
|
||||
}
|
||||
frame = self->top_frame;
|
||||
codes = frame->co->codes.data;
|
||||
co_codes = frame->co->codes.data;
|
||||
co_names = frame->co->names.data;
|
||||
goto __ERROR;
|
||||
}
|
||||
}
|
||||
@ -1220,30 +1249,28 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
}
|
||||
|
||||
const char* pk_op2str(py_Name op) {
|
||||
switch(op) {
|
||||
case __eq__: return "==";
|
||||
case __ne__: return "!=";
|
||||
case __lt__: return "<";
|
||||
case __le__: return "<=";
|
||||
case __gt__: return ">";
|
||||
case __ge__: return ">=";
|
||||
case __add__: return "+";
|
||||
case __sub__: return "-";
|
||||
case __mul__: return "*";
|
||||
case __truediv__: return "/";
|
||||
case __floordiv__: return "//";
|
||||
case __mod__: return "%";
|
||||
case __pow__: return "**";
|
||||
case __lshift__: return "<<";
|
||||
case __rshift__: return ">>";
|
||||
case __and__: return "&";
|
||||
case __or__: return "|";
|
||||
case __xor__: return "^";
|
||||
case __neg__: return "-";
|
||||
case __invert__: return "~";
|
||||
case __matmul__: return "@";
|
||||
default: return py_name2str(op);
|
||||
}
|
||||
if(__eq__ == op) return "==";
|
||||
if(__ne__ == op) return "!=";
|
||||
if(__lt__ == op) return "<";
|
||||
if(__le__ == op) return "<=";
|
||||
if(__gt__ == op) return ">";
|
||||
if(__ge__ == op) return ">=";
|
||||
if(__add__ == op) return "+";
|
||||
if(__sub__ == op) return "-";
|
||||
if(__mul__ == op) return "*";
|
||||
if(__truediv__ == op) return "/";
|
||||
if(__floordiv__ == op) return "//";
|
||||
if(__mod__ == op) return "%";
|
||||
if(__pow__ == op) return "**";
|
||||
if(__lshift__ == op) return "<<";
|
||||
if(__rshift__ == op) return ">>";
|
||||
if(__and__ == op) return "&";
|
||||
if(__or__ == op) return "|";
|
||||
if(__xor__ == op) return "^";
|
||||
if(__neg__ == op) return "-";
|
||||
if(__invert__ == op) return "~";
|
||||
if(__matmul__ == op) return "@";
|
||||
return py_name2str(op);
|
||||
}
|
||||
|
||||
bool pk_stack_binaryop(VM* self, py_Name op, py_Name rop) {
|
||||
@ -1289,6 +1316,58 @@ bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop) {
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool py_binaryadd(py_Ref lhs, py_Ref rhs) {
|
||||
return py_binaryop(lhs, rhs, __add__, __radd__);
|
||||
}
|
||||
|
||||
bool py_binarysub(py_Ref lhs, py_Ref rhs) {
|
||||
return py_binaryop(lhs, rhs, __sub__, __rsub__);
|
||||
}
|
||||
|
||||
bool py_binarymul(py_Ref lhs, py_Ref rhs) {
|
||||
return py_binaryop(lhs, rhs, __mul__, __rmul__);
|
||||
}
|
||||
|
||||
bool py_binarytruediv(py_Ref lhs, py_Ref rhs) {
|
||||
return py_binaryop(lhs, rhs, __truediv__, __rtruediv__);
|
||||
}
|
||||
|
||||
bool py_binaryfloordiv(py_Ref lhs, py_Ref rhs) {
|
||||
return py_binaryop(lhs, rhs, __floordiv__, __rfloordiv__);
|
||||
}
|
||||
|
||||
bool py_binarymod(py_Ref lhs, py_Ref rhs) {
|
||||
return py_binaryop(lhs, rhs, __mod__, __rmod__);
|
||||
}
|
||||
|
||||
bool py_binarypow(py_Ref lhs, py_Ref rhs) {
|
||||
return py_binaryop(lhs, rhs, __pow__, __rpow__);
|
||||
}
|
||||
|
||||
bool py_binarylshift(py_Ref lhs, py_Ref rhs) {
|
||||
return py_binaryop(lhs, rhs, __lshift__, 0);
|
||||
}
|
||||
|
||||
bool py_binaryrshift(py_Ref lhs, py_Ref rhs) {
|
||||
return py_binaryop(lhs, rhs, __rshift__, 0);
|
||||
}
|
||||
|
||||
bool py_binaryand(py_Ref lhs, py_Ref rhs) {
|
||||
return py_binaryop(lhs, rhs, __and__, 0);
|
||||
}
|
||||
|
||||
bool py_binaryor(py_Ref lhs, py_Ref rhs) {
|
||||
return py_binaryop(lhs, rhs, __or__, 0);
|
||||
}
|
||||
|
||||
bool py_binaryxor(py_Ref lhs, py_Ref rhs) {
|
||||
return py_binaryop(lhs, rhs, __xor__, 0);
|
||||
}
|
||||
|
||||
bool py_binarymatmul(py_Ref lhs, py_Ref rhs) {
|
||||
return py_binaryop(lhs, rhs, __matmul__, 0);
|
||||
}
|
||||
|
||||
static bool stack_format_object(VM* self, c11_sv spec) {
|
||||
// format TOS via `spec` inplace
|
||||
// spec: '!r:.2f', '.2f'
|
||||
|
@ -16,7 +16,7 @@ void ValueStack__dtor(ValueStack* self) { self->sp = self->begin; }
|
||||
void FastLocals__to_dict(py_TValue* locals, const CodeObject* co) {
|
||||
py_StackRef dict = py_pushtmp();
|
||||
py_newdict(dict);
|
||||
c11__foreach(c11_smallmap_n2i_KV, &co->varnames_inv, entry) {
|
||||
c11__foreach(c11_smallmap_n2d_KV, &co->varnames_inv, entry) {
|
||||
py_TValue* value = &locals[entry->value];
|
||||
if(!py_isnil(value)) {
|
||||
bool ok = py_dict_setitem(dict, py_name2ref(entry->key), value);
|
||||
@ -29,10 +29,10 @@ void FastLocals__to_dict(py_TValue* locals, const CodeObject* co) {
|
||||
}
|
||||
|
||||
NameDict* FastLocals__to_namedict(py_TValue* locals, const CodeObject* co) {
|
||||
NameDict* dict = NameDict__new();
|
||||
c11__foreach(c11_smallmap_n2i_KV, &co->varnames_inv, entry) {
|
||||
py_TValue value = locals[entry->value];
|
||||
if(!py_isnil(&value)) NameDict__set(dict, entry->key, value);
|
||||
NameDict* dict = NameDict__new(PK_INST_ATTR_LOAD_FACTOR);
|
||||
c11__foreach(c11_smallmap_n2d_KV, &co->varnames_inv, entry) {
|
||||
py_Ref val = &locals[entry->value];
|
||||
if(!py_isnil(val)) NameDict__set(dict, entry->key, val);
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
@ -166,7 +166,7 @@ int Frame__delglobal(py_Frame* self, py_Name name) {
|
||||
|
||||
py_StackRef Frame__getlocal_noproxy(py_Frame* self, py_Name name) {
|
||||
assert(!self->is_locals_special);
|
||||
int index = c11_smallmap_n2i__get(&self->co->varnames_inv, name, -1);
|
||||
int index = c11_smallmap_n2d__get(&self->co->varnames_inv, name, -1);
|
||||
if(index == -1) return NULL;
|
||||
return &self->locals[index];
|
||||
}
|
||||
|
@ -44,7 +44,8 @@ void ManagedHeap__collect_if_needed(ManagedHeap* self) {
|
||||
const int lower = PK_GC_MIN_THRESHOLD / 2;
|
||||
float free_ratio = (float)avg_freed / self->gc_threshold;
|
||||
int new_threshold = self->gc_threshold * (1 / free_ratio);
|
||||
// printf("gc_threshold=%d, avg_freed=%d, new_threshold=%d\n", self->gc_threshold, avg_freed, new_threshold);
|
||||
// printf("gc_threshold=%d, avg_freed=%d, new_threshold=%d\n", self->gc_threshold, avg_freed,
|
||||
// new_threshold);
|
||||
self->gc_threshold = c11__min(c11__max(new_threshold, lower), upper);
|
||||
}
|
||||
|
||||
@ -98,7 +99,9 @@ PyObject* ManagedHeap__gcnew(ManagedHeap* self, py_Type type, int slots, int uds
|
||||
if(slots >= 0) {
|
||||
memset(obj->flex, 0, slots * sizeof(py_TValue));
|
||||
} else {
|
||||
NameDict__ctor((void*)obj->flex);
|
||||
float load_factor = (type == tp_type || type == tp_module) ? PK_TYPE_ATTR_LOAD_FACTOR
|
||||
: PK_INST_ATTR_LOAD_FACTOR;
|
||||
NameDict__ctor((void*)obj->flex, load_factor);
|
||||
}
|
||||
|
||||
self->gc_counter++;
|
||||
|
@ -1,75 +0,0 @@
|
||||
#include "pocketpy/interpreter/name.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
void InternedNames__ctor(InternedNames* self) {
|
||||
c11_smallmap_s2n__ctor(&self->interned);
|
||||
c11_vector__ctor(&self->r_interned, sizeof(RInternedEntry));
|
||||
|
||||
// initialize all magic names
|
||||
#define MAGIC_METHOD(x) \
|
||||
if(x != py_name(#x)) abort();
|
||||
#include "pocketpy/xmacros/magics.h"
|
||||
#undef MAGIC_METHOD
|
||||
}
|
||||
|
||||
void InternedNames__dtor(InternedNames* self) {
|
||||
for(int i = 0; i < self->r_interned.length; i++) {
|
||||
PK_FREE(c11__getitem(RInternedEntry, &self->r_interned, i).data);
|
||||
}
|
||||
c11_smallmap_s2n__dtor(&self->interned);
|
||||
c11_vector__dtor(&self->r_interned);
|
||||
}
|
||||
|
||||
py_Name py_name(const char* name) {
|
||||
c11_sv sv;
|
||||
sv.data = name;
|
||||
sv.size = strlen(name);
|
||||
return py_namev(sv);
|
||||
}
|
||||
|
||||
py_Name py_namev(c11_sv name) {
|
||||
InternedNames* self = &pk_current_vm->names;
|
||||
uint16_t index = c11_smallmap_s2n__get(&self->interned, name, 0);
|
||||
if(index != 0) return index;
|
||||
// generate new index
|
||||
if(self->interned.length > 65530) c11__abort("py_Name index overflow");
|
||||
// NOTE: we must allocate the string in the heap so iterators are not invalidated
|
||||
char* p = PK_MALLOC(name.size + 1);
|
||||
memcpy(p, name.data, name.size);
|
||||
p[name.size] = '\0';
|
||||
RInternedEntry* entry = c11_vector__emplace(&self->r_interned);
|
||||
entry->data = p;
|
||||
entry->size = name.size;
|
||||
memset(&entry->obj, 0, sizeof(py_TValue));
|
||||
index = self->r_interned.length; // 1-based
|
||||
// save to _interned
|
||||
c11_smallmap_s2n__set(&self->interned, (c11_sv){p, name.size}, index);
|
||||
assert(self->interned.length == self->r_interned.length);
|
||||
return index;
|
||||
}
|
||||
|
||||
const char* py_name2str(py_Name index) {
|
||||
InternedNames* self = &pk_current_vm->names;
|
||||
assert(index > 0 && index <= self->interned.length);
|
||||
return c11__getitem(RInternedEntry, &self->r_interned, index - 1).data;
|
||||
}
|
||||
|
||||
c11_sv py_name2sv(py_Name index) {
|
||||
InternedNames* self = &pk_current_vm->names;
|
||||
assert(index > 0 && index <= self->interned.length);
|
||||
RInternedEntry entry = c11__getitem(RInternedEntry, &self->r_interned, index - 1);
|
||||
return (c11_sv){entry.data, entry.size};
|
||||
}
|
||||
|
||||
py_GlobalRef py_name2ref(py_Name index) {
|
||||
InternedNames* self = &pk_current_vm->names;
|
||||
assert(index > 0 && index <= self->interned.length);
|
||||
RInternedEntry* entry = c11__at(RInternedEntry, &self->r_interned, index - 1);
|
||||
if(entry->obj.type == tp_nil) {
|
||||
c11_sv sv;
|
||||
sv.data = entry->data;
|
||||
sv.size = entry->size;
|
||||
py_newstrv(&entry->obj, sv);
|
||||
}
|
||||
return &entry->obj;
|
||||
}
|
@ -12,7 +12,7 @@ void TypeList__ctor(TypeList* self) {
|
||||
void TypeList__dtor(TypeList* self) {
|
||||
for(py_Type t = 0; t < self->length; t++) {
|
||||
py_TypeInfo* info = TypeList__get(self, t);
|
||||
if(info->magic_1) PK_FREE(info->magic_1);
|
||||
(void)info;
|
||||
}
|
||||
for(int i = 0; i < PK_MAX_CHUNK_LENGTH; i++) {
|
||||
if(self->chunks[i]) PK_FREE(self->chunks[i]);
|
||||
@ -47,28 +47,5 @@ void TypeList__apply(TypeList* self, void (*f)(py_TypeInfo*, void*), void* ctx)
|
||||
}
|
||||
}
|
||||
|
||||
py_TValue* TypeList__magic(py_TypeInfo* self, unsigned index) {
|
||||
if(index > __xor__) {
|
||||
// common magic slots
|
||||
return TypeList__magic_common(self, index);
|
||||
}
|
||||
// uncommon magic slots
|
||||
if(self->magic_1 == NULL) {
|
||||
self->magic_1 = PK_MALLOC(sizeof(py_TValue) * PK_MAGIC_SLOTS_UNCOMMON_LENGTH);
|
||||
memset(self->magic_1, 0, sizeof(py_TValue) * PK_MAGIC_SLOTS_UNCOMMON_LENGTH);
|
||||
}
|
||||
return self->magic_1 + index;
|
||||
}
|
||||
|
||||
py_TValue* TypeList__magic_readonly(py_TypeInfo* self, unsigned index) {
|
||||
if(index > __xor__) {
|
||||
// common magic slots
|
||||
return TypeList__magic_common(self, index);
|
||||
}
|
||||
// uncommon magic slots
|
||||
if(self->magic_1 == NULL) return py_NIL();
|
||||
return self->magic_1 + index;
|
||||
}
|
||||
|
||||
#undef CHUNK_SIZE
|
||||
#undef LOG2_CHUNK_SIZE
|
@ -65,7 +65,6 @@ static void py_TypeInfo__ctor(py_TypeInfo* self,
|
||||
|
||||
void VM__ctor(VM* self) {
|
||||
self->top_frame = NULL;
|
||||
InternedNames__ctor(&self->names);
|
||||
|
||||
ModuleDict__ctor(&self->modules, "", *py_NIL());
|
||||
TypeList__ctor(&self->types);
|
||||
@ -97,6 +96,7 @@ void VM__ctor(VM* self) {
|
||||
|
||||
ManagedHeap__ctor(&self->heap);
|
||||
ValueStack__ctor(&self->stack);
|
||||
NameDict__ctor(&self->cached_names, PK_INST_ATTR_LOAD_FACTOR);
|
||||
|
||||
/* Init Builtin Types */
|
||||
// 0: unused
|
||||
@ -274,7 +274,7 @@ void VM__dtor(VM* self) {
|
||||
TypeList__dtor(&self->types);
|
||||
FixedMemoryPool__dtor(&self->pool_frame);
|
||||
ValueStack__dtor(&self->stack);
|
||||
InternedNames__dtor(&self->names);
|
||||
NameDict__dtor(&self->cached_names);
|
||||
}
|
||||
|
||||
void VM__push_frame(VM* self, py_Frame* frame) {
|
||||
@ -442,8 +442,8 @@ static bool
|
||||
if(decl->starred_kwarg != -1) py_newdict(&buffer[decl->starred_kwarg]);
|
||||
|
||||
for(int j = 0; j < kwargc; j++) {
|
||||
py_Name key = py_toint(&p1[2 * j]);
|
||||
int index = c11_smallmap_n2i__get(&decl->kw_to_index, key, -1);
|
||||
py_Name key = (py_Name)py_toint(&p1[2 * j]);
|
||||
int index = c11_smallmap_n2d__get(&decl->kw_to_index, key, -1);
|
||||
// if key is an explicit key, set as local variable
|
||||
if(index >= 0) {
|
||||
buffer[index] = p1[2 * j + 1];
|
||||
@ -653,20 +653,6 @@ void ManagedHeap__mark(ManagedHeap* self) {
|
||||
py_TypeInfo* ti = TypeList__get(&vm->types, i);
|
||||
// mark type object
|
||||
pk__mark_value(&ti->self);
|
||||
// mark common magic slots
|
||||
for(int j = 0; j < PK_MAGIC_SLOTS_COMMON_LENGTH; j++) {
|
||||
py_TValue* slot = ti->magic_0 + j;
|
||||
if(py_isnil(slot)) continue;
|
||||
pk__mark_value(slot);
|
||||
}
|
||||
// mark uncommon magic slots
|
||||
if(ti->magic_1) {
|
||||
for(int j = 0; j < PK_MAGIC_SLOTS_UNCOMMON_LENGTH; j++) {
|
||||
py_TValue* slot = ti->magic_1 + j;
|
||||
if(py_isnil(slot)) continue;
|
||||
pk__mark_value(slot);
|
||||
}
|
||||
}
|
||||
// mark type annotations
|
||||
pk__mark_value(&ti->annotations);
|
||||
}
|
||||
@ -680,12 +666,6 @@ void ManagedHeap__mark(ManagedHeap* self) {
|
||||
for(int i = 0; i < c11__count_array(vm->reg); i++) {
|
||||
pk__mark_value(&vm->reg[i]);
|
||||
}
|
||||
// mark interned names
|
||||
for(int i = 0; i < vm->names.r_interned.length; i++) {
|
||||
RInternedEntry* entry = c11__at(RInternedEntry, &vm->names.r_interned, i);
|
||||
pk__mark_value(&entry->obj);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
while(p_stack->length > 0) {
|
||||
PyObject* obj = c11_vector__back(PyObject*, p_stack);
|
||||
@ -698,9 +678,10 @@ void ManagedHeap__mark(ManagedHeap* self) {
|
||||
for(int i = 0; i < obj->slots; i++)
|
||||
pk__mark_value(p + i);
|
||||
} else if(obj->slots == -1) {
|
||||
NameDict* namedict = PyObject__dict(obj);
|
||||
for(int i = 0; i < namedict->length; i++) {
|
||||
NameDict_KV* kv = c11__at(NameDict_KV, namedict, i);
|
||||
NameDict* dict = PyObject__dict(obj);
|
||||
for(int i = 0; i < dict->capacity; i++) {
|
||||
NameDict_KV* kv = &dict->items[i];
|
||||
if(kv->key == NULL) continue;
|
||||
pk__mark_value(&kv->value);
|
||||
}
|
||||
}
|
||||
@ -855,3 +836,15 @@ int py_replinput(char* buf, int max_size) {
|
||||
buf[size] = '\0';
|
||||
return size;
|
||||
}
|
||||
|
||||
py_Ref py_name2ref(py_Name name) {
|
||||
assert(name != NULL);
|
||||
NameDict* d = &pk_current_vm->cached_names;
|
||||
py_Ref res = NameDict__try_get(d, name);
|
||||
if(res != NULL) return res;
|
||||
// not found, create a new one
|
||||
py_TValue tmp;
|
||||
py_newstrv(&tmp, py_name2sv(name));
|
||||
NameDict__set(d, name, &tmp);
|
||||
return NameDict__try_get(d, name);
|
||||
}
|
@ -84,7 +84,8 @@ static bool disassemble(CodeObject* co) {
|
||||
case OP_BEGIN_CLASS:
|
||||
case OP_DELETE_GLOBAL:
|
||||
case OP_STORE_CLASS_ATTR: {
|
||||
pk_sprintf(&ss, " (%n)", byte.arg);
|
||||
py_Name name = c11__getitem(py_Name, &co->names, byte.arg);
|
||||
pk_sprintf(&ss, " (%n)", name);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_FAST:
|
||||
@ -99,11 +100,31 @@ static bool disassemble(CodeObject* co) {
|
||||
pk_sprintf(&ss, " (%s)", decl->code.name->data);
|
||||
break;
|
||||
}
|
||||
case OP_BINARY_OP: {
|
||||
py_Name name = byte.arg & 0xFF;
|
||||
pk_sprintf(&ss, " (%s)", pk_op2str(name));
|
||||
break;
|
||||
#define CASE_BINARY_OP(label, op, rop) \
|
||||
case label: { \
|
||||
pk_sprintf(&ss, " (%s)", pk_op2str(op)); \
|
||||
break; \
|
||||
}
|
||||
CASE_BINARY_OP(OP_BINARY_ADD, __add__, __radd__)
|
||||
CASE_BINARY_OP(OP_BINARY_SUB, __sub__, __rsub__)
|
||||
CASE_BINARY_OP(OP_BINARY_MUL, __mul__, __rmul__)
|
||||
CASE_BINARY_OP(OP_BINARY_TRUEDIV, __truediv__, __rtruediv__)
|
||||
CASE_BINARY_OP(OP_BINARY_FLOORDIV, __floordiv__, __rfloordiv__)
|
||||
CASE_BINARY_OP(OP_BINARY_MOD, __mod__, __rmod__)
|
||||
CASE_BINARY_OP(OP_BINARY_POW, __pow__, __rpow__)
|
||||
CASE_BINARY_OP(OP_BINARY_LSHIFT, __lshift__, 0)
|
||||
CASE_BINARY_OP(OP_BINARY_RSHIFT, __rshift__, 0)
|
||||
CASE_BINARY_OP(OP_BINARY_AND, __and__, 0)
|
||||
CASE_BINARY_OP(OP_BINARY_OR, __or__, 0)
|
||||
CASE_BINARY_OP(OP_BINARY_XOR, __xor__, 0)
|
||||
CASE_BINARY_OP(OP_BINARY_MATMUL, __matmul__, 0)
|
||||
CASE_BINARY_OP(OP_COMPARE_LT, __lt__, __gt__)
|
||||
CASE_BINARY_OP(OP_COMPARE_LE, __le__, __ge__)
|
||||
CASE_BINARY_OP(OP_COMPARE_EQ, __eq__, __eq__)
|
||||
CASE_BINARY_OP(OP_COMPARE_NE, __ne__, __ne__)
|
||||
CASE_BINARY_OP(OP_COMPARE_GT, __gt__, __lt__)
|
||||
CASE_BINARY_OP(OP_COMPARE_GE, __ge__, __le__)
|
||||
#undef CASE_BINARY_OP
|
||||
}
|
||||
} while(0);
|
||||
|
||||
|
@ -374,16 +374,18 @@ static bool pkl__write_object(PickleObject* buf, py_TValue* obj) {
|
||||
}
|
||||
if(ti->is_python) {
|
||||
NameDict* dict = PyObject__dict(obj->_obj);
|
||||
for(int i = dict->length - 1; i >= 0; i--) {
|
||||
NameDict_KV* kv = c11__at(NameDict_KV, dict, i);
|
||||
for(int i = dict->capacity - 1; i >= 0; i--) {
|
||||
NameDict_KV* kv = &dict->items[i];
|
||||
if(kv->key == NULL) continue;
|
||||
if(!pkl__write_object(buf, &kv->value)) return false;
|
||||
}
|
||||
pkl__emit_op(buf, PKL_OBJECT);
|
||||
pkl__emit_int(buf, obj->type);
|
||||
buf->used_types[obj->type] = true;
|
||||
pkl__emit_int(buf, dict->length);
|
||||
for(int i = 0; i < dict->length; i++) {
|
||||
NameDict_KV* kv = c11__at(NameDict_KV, dict, i);
|
||||
for(int i = 0; i < dict->capacity; i++) {
|
||||
NameDict_KV* kv = &dict->items[i];
|
||||
if(kv->key == NULL) continue;
|
||||
c11_sv field = py_name2sv(kv->key);
|
||||
// include '\0'
|
||||
PickleObject__write_bytes(buf, field.data, field.size + 1);
|
||||
@ -440,7 +442,7 @@ static py_i64 pkl__header_read_int(const unsigned char** p, char sep) {
|
||||
return out;
|
||||
}
|
||||
|
||||
bool py_pickle_loads_body(const unsigned char* p, int memo_length, c11_smallmap_n2i* type_mapping);
|
||||
bool py_pickle_loads_body(const unsigned char* p, int memo_length, c11_smallmap_d2d* type_mapping);
|
||||
|
||||
bool py_pickle_loads(const unsigned char* data, int size) {
|
||||
const unsigned char* p = data;
|
||||
@ -450,8 +452,8 @@ bool py_pickle_loads(const unsigned char* data, int size) {
|
||||
return ValueError("invalid pickle data");
|
||||
p += 4;
|
||||
|
||||
c11_smallmap_n2i type_mapping;
|
||||
c11_smallmap_n2i__ctor(&type_mapping);
|
||||
c11_smallmap_d2d type_mapping;
|
||||
c11_smallmap_d2d__ctor(&type_mapping);
|
||||
|
||||
while(true) {
|
||||
if(*p == '\n') {
|
||||
@ -462,25 +464,25 @@ bool py_pickle_loads(const unsigned char* data, int size) {
|
||||
c11_sv path = pkl__header_read_sv(&p, ')');
|
||||
py_Type new_type = pkl__header_find_type(path);
|
||||
if(new_type == 0) {
|
||||
c11_smallmap_n2i__dtor(&type_mapping);
|
||||
c11_smallmap_d2d__dtor(&type_mapping);
|
||||
return ImportError("cannot find type '%v'", path);
|
||||
}
|
||||
if(type != new_type) c11_smallmap_n2i__set(&type_mapping, type, new_type);
|
||||
if(type != new_type) c11_smallmap_d2d__set(&type_mapping, type, new_type);
|
||||
}
|
||||
|
||||
int memo_length = pkl__header_read_int(&p, '\n');
|
||||
bool ok = py_pickle_loads_body(p, memo_length, &type_mapping);
|
||||
c11_smallmap_n2i__dtor(&type_mapping);
|
||||
c11_smallmap_d2d__dtor(&type_mapping);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static py_Type pkl__fix_type(py_Type type, c11_smallmap_n2i* type_mapping) {
|
||||
int new_type = c11_smallmap_n2i__get(type_mapping, type, -1);
|
||||
static py_Type pkl__fix_type(py_Type type, c11_smallmap_d2d* type_mapping) {
|
||||
int new_type = c11_smallmap_d2d__get(type_mapping, type, -1);
|
||||
if(new_type != -1) return (py_Type)new_type;
|
||||
return type;
|
||||
}
|
||||
|
||||
bool py_pickle_loads_body(const unsigned char* p, int memo_length, c11_smallmap_n2i* type_mapping) {
|
||||
bool py_pickle_loads_body(const unsigned char* p, int memo_length, c11_smallmap_d2d* type_mapping) {
|
||||
py_StackRef p0 = py_peek(0);
|
||||
py_Ref p_memo = py_newtuple(py_pushtmp(), memo_length);
|
||||
while(true) {
|
||||
@ -685,7 +687,7 @@ bool py_pickle_loads_body(const unsigned char* p, int memo_length, c11_smallmap_
|
||||
for(int i = 0; i < dict_length; i++) {
|
||||
py_StackRef value = py_peek(-1);
|
||||
c11_sv field = {(const char*)p, strlen((const char*)p)};
|
||||
NameDict__set(dict, py_namev(field), *value);
|
||||
NameDict__set(dict, py_namev(field), value);
|
||||
py_pop();
|
||||
p += field.size + 1;
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ static void
|
||||
static bool _pk_compute_thread_flags[16];
|
||||
|
||||
static void c11_ComputeThread__dtor(c11_ComputeThread* self) {
|
||||
if(!self->is_done) {
|
||||
if(!atomic_load(&self->is_done)) {
|
||||
c11__abort("ComputeThread(%d) is not done yet!! But the object was deleted.",
|
||||
self->vm_index);
|
||||
}
|
||||
@ -187,7 +187,7 @@ static bool ComputeThread__new__(int argc, py_Ref argv) {
|
||||
c11_ComputeThread* self =
|
||||
py_newobject(py_retval(), py_totype(argv), 0, sizeof(c11_ComputeThread));
|
||||
self->vm_index = 0;
|
||||
self->is_done = true;
|
||||
atomic_store(&self->is_done, true);
|
||||
self->last_retval_data = NULL;
|
||||
self->last_retval_size = 0;
|
||||
self->last_error = NULL;
|
||||
@ -217,15 +217,17 @@ static bool ComputeThread__init__(int argc, py_Ref argv) {
|
||||
static bool ComputeThread_is_done(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
c11_ComputeThread* self = py_touserdata(argv);
|
||||
py_newbool(py_retval(), self->is_done);
|
||||
bool value = atomic_load(&self->is_done);
|
||||
py_newbool(py_retval(), value);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ComputeThread_wait_for_done(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
c11_ComputeThread* self = py_touserdata(argv);
|
||||
while(!self->is_done)
|
||||
while(!atomic_load(&self->is_done)) {
|
||||
c11_thrd_yield();
|
||||
}
|
||||
py_newnone(py_retval());
|
||||
return true;
|
||||
}
|
||||
@ -233,7 +235,7 @@ static bool ComputeThread_wait_for_done(int argc, py_Ref argv) {
|
||||
static bool ComputeThread_last_error(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
c11_ComputeThread* self = py_touserdata(argv);
|
||||
if(!self->is_done) return OSError("thread is not done yet");
|
||||
if(!atomic_load(&self->is_done)) return OSError("thread is not done yet");
|
||||
if(self->last_error) {
|
||||
py_newstr(py_retval(), self->last_error);
|
||||
} else {
|
||||
@ -245,7 +247,7 @@ static bool ComputeThread_last_error(int argc, py_Ref argv) {
|
||||
static bool ComputeThread_last_retval(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
c11_ComputeThread* self = py_touserdata(argv);
|
||||
if(!self->is_done) return OSError("thread is not done yet");
|
||||
if(!atomic_load(&self->is_done)) return OSError("thread is not done yet");
|
||||
if(self->last_retval_data == NULL) return ValueError("no retval available");
|
||||
return py_pickle_loads(self->last_retval_data, self->last_retval_size);
|
||||
}
|
||||
@ -273,12 +275,12 @@ static c11_thrd_retval_t ComputeThreadJob_call(void* arg) {
|
||||
unsigned char* retval_data = py_tobytes(py_retval(), &retval_size);
|
||||
self->last_retval_data = c11_memdup(retval_data, retval_size);
|
||||
self->last_retval_size = retval_size;
|
||||
self->is_done = true;
|
||||
atomic_store(&self->is_done, true);
|
||||
return (c11_thrd_retval_t)0;
|
||||
|
||||
__ERROR:
|
||||
self->last_error = py_formatexc();
|
||||
self->is_done = true;
|
||||
atomic_store(&self->is_done, true);
|
||||
py_clearexc(p0);
|
||||
py_newnone(py_retval());
|
||||
return (c11_thrd_retval_t)0;
|
||||
@ -296,12 +298,12 @@ static c11_thrd_retval_t ComputeThreadJob_exec(void* arg) {
|
||||
unsigned char* retval_data = py_tobytes(py_retval(), &retval_size);
|
||||
self->last_retval_data = c11_memdup(retval_data, retval_size);
|
||||
self->last_retval_size = retval_size;
|
||||
self->is_done = true;
|
||||
atomic_store(&self->is_done, true);
|
||||
return (c11_thrd_retval_t)0;
|
||||
|
||||
__ERROR:
|
||||
self->last_error = py_formatexc();
|
||||
self->is_done = true;
|
||||
atomic_store(&self->is_done, true);
|
||||
py_clearexc(p0);
|
||||
return (c11_thrd_retval_t)0;
|
||||
}
|
||||
@ -309,7 +311,7 @@ __ERROR:
|
||||
static bool ComputeThread_submit_exec(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(2);
|
||||
c11_ComputeThread* self = py_touserdata(py_arg(0));
|
||||
if(!self->is_done) return OSError("thread is not done yet");
|
||||
if(!atomic_load(&self->is_done)) return OSError("thread is not done yet");
|
||||
PY_CHECK_ARG_TYPE(1, tp_str);
|
||||
const char* source = py_tostr(py_arg(1));
|
||||
/**************************/
|
||||
@ -319,10 +321,10 @@ static bool ComputeThread_submit_exec(int argc, py_Ref argv) {
|
||||
job->mode = EXEC_MODE;
|
||||
c11_ComputeThread__reset_job(self, job, ComputeThreadJobExec__dtor);
|
||||
/**************************/
|
||||
self->is_done = false;
|
||||
atomic_store(&self->is_done, false);
|
||||
bool ok = c11_thrd_create(&self->thread, ComputeThreadJob_exec, job);
|
||||
if(!ok) {
|
||||
self->is_done = true;
|
||||
atomic_store(&self->is_done, true);
|
||||
return OSError("thrd_create() failed");
|
||||
}
|
||||
py_newnone(py_retval());
|
||||
@ -332,7 +334,7 @@ static bool ComputeThread_submit_exec(int argc, py_Ref argv) {
|
||||
static bool ComputeThread_submit_eval(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(2);
|
||||
c11_ComputeThread* self = py_touserdata(py_arg(0));
|
||||
if(!self->is_done) return OSError("thread is not done yet");
|
||||
if(!atomic_load(&self->is_done)) return OSError("thread is not done yet");
|
||||
PY_CHECK_ARG_TYPE(1, tp_str);
|
||||
const char* source = py_tostr(py_arg(1));
|
||||
/**************************/
|
||||
@ -342,10 +344,10 @@ static bool ComputeThread_submit_eval(int argc, py_Ref argv) {
|
||||
job->mode = EVAL_MODE;
|
||||
c11_ComputeThread__reset_job(self, job, ComputeThreadJobExec__dtor);
|
||||
/**************************/
|
||||
self->is_done = false;
|
||||
atomic_store(&self->is_done, false);
|
||||
bool ok = c11_thrd_create(&self->thread, ComputeThreadJob_exec, job);
|
||||
if(!ok) {
|
||||
self->is_done = true;
|
||||
atomic_store(&self->is_done, true);
|
||||
return OSError("thrd_create() failed");
|
||||
}
|
||||
py_newnone(py_retval());
|
||||
@ -355,7 +357,7 @@ static bool ComputeThread_submit_eval(int argc, py_Ref argv) {
|
||||
static bool ComputeThread_submit_call(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(4);
|
||||
c11_ComputeThread* self = py_touserdata(py_arg(0));
|
||||
if(!self->is_done) return OSError("thread is not done yet");
|
||||
if(!atomic_load(&self->is_done)) return OSError("thread is not done yet");
|
||||
PY_CHECK_ARG_TYPE(1, tp_str);
|
||||
PY_CHECK_ARG_TYPE(2, tp_tuple);
|
||||
PY_CHECK_ARG_TYPE(3, tp_dict);
|
||||
@ -379,10 +381,10 @@ static bool ComputeThread_submit_call(int argc, py_Ref argv) {
|
||||
job->kwargs_size = kwargs_size;
|
||||
c11_ComputeThread__reset_job(self, job, ComputeThreadJobCall__dtor);
|
||||
/**************************/
|
||||
self->is_done = false;
|
||||
atomic_store(&self->is_done, false);
|
||||
bool ok = c11_thrd_create(&self->thread, ComputeThreadJob_call, job);
|
||||
if(!ok) {
|
||||
self->is_done = true;
|
||||
atomic_store(&self->is_done, true);
|
||||
return OSError("thrd_create() failed");
|
||||
}
|
||||
py_newnone(py_retval());
|
||||
@ -392,8 +394,8 @@ static bool ComputeThread_submit_call(int argc, py_Ref argv) {
|
||||
static bool c11_ComputeThread__exec_blocked(c11_ComputeThread* self,
|
||||
const char* source,
|
||||
enum py_CompileMode mode) {
|
||||
if(!self->is_done) return OSError("thread is not done yet");
|
||||
self->is_done = false;
|
||||
if(!atomic_load(&self->is_done)) return OSError("thread is not done yet");
|
||||
atomic_store(&self->is_done, false);
|
||||
char* err = NULL;
|
||||
int old_vm_index = py_currentvm();
|
||||
py_switchvm(self->vm_index);
|
||||
@ -405,14 +407,14 @@ static bool c11_ComputeThread__exec_blocked(c11_ComputeThread* self,
|
||||
unsigned char* retval_data = py_tobytes(py_retval(), &retval_size);
|
||||
py_switchvm(old_vm_index);
|
||||
bool ok = py_pickle_loads(retval_data, retval_size);
|
||||
self->is_done = true;
|
||||
atomic_store(&self->is_done, true);
|
||||
return ok;
|
||||
|
||||
__ERROR:
|
||||
err = py_formatexc();
|
||||
py_clearexc(p0);
|
||||
py_switchvm(old_vm_index);
|
||||
self->is_done = true;
|
||||
atomic_store(&self->is_done, true);
|
||||
RuntimeError("c11_ComputeThread__exec_blocked() failed:\n%s", err);
|
||||
PK_FREE(err);
|
||||
return false;
|
||||
@ -454,7 +456,7 @@ static void pk_ComputeThread__register(py_Ref mod) {
|
||||
py_bindmethod(type, "eval", ComputeThread_eval);
|
||||
}
|
||||
|
||||
static void pkpy_configmacros_add(py_Ref dict, const char* key, int val){
|
||||
static void pkpy_configmacros_add(py_Ref dict, const char* key, int val) {
|
||||
assert(dict->type == tp_dict);
|
||||
py_TValue tmp;
|
||||
py_newint(&tmp, val);
|
||||
|
@ -20,7 +20,7 @@ static void FuncDecl__dtor(FuncDecl* self) {
|
||||
CodeObject__dtor(&self->code);
|
||||
c11_vector__dtor(&self->args);
|
||||
c11_vector__dtor(&self->kwargs);
|
||||
c11_smallmap_n2i__dtor(&self->kw_to_index);
|
||||
c11_smallmap_n2d__dtor(&self->kw_to_index);
|
||||
}
|
||||
|
||||
FuncDecl_ FuncDecl__rcnew(SourceData_ src, c11_sv name) {
|
||||
@ -39,14 +39,14 @@ FuncDecl_ FuncDecl__rcnew(SourceData_ src, c11_sv name) {
|
||||
self->docstring = NULL;
|
||||
self->type = FuncType_UNSET;
|
||||
|
||||
c11_smallmap_n2i__ctor(&self->kw_to_index);
|
||||
c11_smallmap_n2d__ctor(&self->kw_to_index);
|
||||
return self;
|
||||
}
|
||||
|
||||
bool FuncDecl__is_duplicated_arg(const FuncDecl* decl, py_Name name) {
|
||||
py_Name tmp_name;
|
||||
c11__foreach(int, &decl->args, j) {
|
||||
tmp_name = c11__getitem(py_Name, &decl->args, *j);
|
||||
tmp_name = c11__getitem(py_Name, &decl->code.varnames, *j);
|
||||
if(tmp_name == name) return true;
|
||||
}
|
||||
c11__foreach(FuncDeclKwArg, &decl->kwargs, kv) {
|
||||
@ -71,7 +71,7 @@ void FuncDecl__add_arg(FuncDecl* self, py_Name name) {
|
||||
|
||||
void FuncDecl__add_kwarg(FuncDecl* self, py_Name name, const py_TValue* value) {
|
||||
int index = CodeObject__add_varname(&self->code, name);
|
||||
c11_smallmap_n2i__set(&self->kw_to_index, name, index);
|
||||
c11_smallmap_n2d__set(&self->kw_to_index, name, index);
|
||||
FuncDeclKwArg* item = c11_vector__emplace(&self->kwargs);
|
||||
item->index = index;
|
||||
item->key = name;
|
||||
@ -123,10 +123,12 @@ void CodeObject__ctor(CodeObject* self, SourceData_ src, c11_sv name) {
|
||||
c11_vector__ctor(&self->codes_ex, sizeof(BytecodeEx));
|
||||
|
||||
c11_vector__ctor(&self->consts, sizeof(py_TValue));
|
||||
c11_vector__ctor(&self->varnames, sizeof(uint16_t));
|
||||
c11_vector__ctor(&self->varnames, sizeof(py_Name));
|
||||
c11_vector__ctor(&self->names, sizeof(py_Name));
|
||||
self->nlocals = 0;
|
||||
|
||||
c11_smallmap_n2i__ctor(&self->varnames_inv);
|
||||
c11_smallmap_n2d__ctor(&self->varnames_inv);
|
||||
c11_smallmap_n2d__ctor(&self->names_inv);
|
||||
|
||||
c11_vector__ctor(&self->blocks, sizeof(CodeBlock));
|
||||
c11_vector__ctor(&self->func_decls, sizeof(FuncDecl_));
|
||||
@ -147,8 +149,10 @@ void CodeObject__dtor(CodeObject* self) {
|
||||
|
||||
c11_vector__dtor(&self->consts);
|
||||
c11_vector__dtor(&self->varnames);
|
||||
c11_vector__dtor(&self->names);
|
||||
|
||||
c11_smallmap_n2i__dtor(&self->varnames_inv);
|
||||
c11_smallmap_n2d__dtor(&self->varnames_inv);
|
||||
c11_smallmap_n2d__dtor(&self->names_inv);
|
||||
|
||||
c11_vector__dtor(&self->blocks);
|
||||
|
||||
@ -170,12 +174,21 @@ void Function__ctor(Function* self, FuncDecl_ decl, py_GlobalRef module, py_Ref
|
||||
}
|
||||
|
||||
int CodeObject__add_varname(CodeObject* self, py_Name name) {
|
||||
int index = c11_smallmap_n2i__get(&self->varnames_inv, name, -1);
|
||||
int index = c11_smallmap_n2d__get(&self->varnames_inv, name, -1);
|
||||
if(index >= 0) return index;
|
||||
c11_vector__push(uint16_t, &self->varnames, name);
|
||||
c11_vector__push(py_Name, &self->varnames, name);
|
||||
self->nlocals++;
|
||||
index = self->varnames.length - 1;
|
||||
c11_smallmap_n2i__set(&self->varnames_inv, name, index);
|
||||
c11_smallmap_n2d__set(&self->varnames_inv, name, index);
|
||||
return index;
|
||||
}
|
||||
|
||||
int CodeObject__add_name(CodeObject* self, py_Name name) {
|
||||
int index = c11_smallmap_n2d__get(&self->names_inv, name, -1);
|
||||
if(index >= 0) return index;
|
||||
c11_vector__push(py_Name, &self->names, name);
|
||||
index = self->names.length - 1;
|
||||
c11_smallmap_n2d__set(&self->names_inv, name, index);
|
||||
return index;
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,8 @@
|
||||
#include "pocketpy/objects/namedict.h"
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
|
||||
#define SMALLMAP_T__SOURCE
|
||||
#define K uint16_t
|
||||
#define V py_TValue
|
||||
#define NAME NameDict
|
||||
#include "pocketpy/xmacros/smallmap.h"
|
||||
#undef SMALLMAP_T__SOURCE
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include <stdint.h>
|
||||
|
||||
void ModuleDict__ctor(ModuleDict* self, const char* path, py_TValue module) {
|
||||
assert(path != NULL);
|
||||
@ -90,3 +86,127 @@ void ModuleDict__apply_mark(ModuleDict* self, c11_vector* p_stack) {
|
||||
if(self->left) ModuleDict__apply_mark(self->left, p_stack);
|
||||
if(self->right) ModuleDict__apply_mark(self->right, p_stack);
|
||||
}
|
||||
|
||||
/////////////////// NameDict ///////////////////
|
||||
|
||||
#define HASH_PROBE_1(__k, ok, i) \
|
||||
ok = false; \
|
||||
i = (uintptr_t)(__k) & self->mask; \
|
||||
while(self->items[i].key != NULL) { \
|
||||
if(self->items[i].key == (__k)) { \
|
||||
ok = true; \
|
||||
break; \
|
||||
} \
|
||||
i = (i + 1) & self->mask; \
|
||||
}
|
||||
|
||||
#define HASH_PROBE_0 HASH_PROBE_1
|
||||
|
||||
static void NameDict__set_capacity_and_alloc_items(NameDict* self, int val) {
|
||||
self->capacity = val;
|
||||
self->critical_size = val * self->load_factor;
|
||||
self->mask = (uintptr_t)val - 1;
|
||||
|
||||
self->items = PK_MALLOC(self->capacity * sizeof(NameDict_KV));
|
||||
memset(self->items, 0, self->capacity * sizeof(NameDict_KV));
|
||||
}
|
||||
|
||||
static void NameDict__rehash_2x(NameDict* self) {
|
||||
NameDict_KV* old_items = self->items;
|
||||
int old_capacity = self->capacity;
|
||||
NameDict__set_capacity_and_alloc_items(self, self->capacity * 2);
|
||||
for(int i = 0; i < old_capacity; i++) {
|
||||
if(old_items[i].key == NULL) continue;
|
||||
bool ok;
|
||||
uintptr_t j;
|
||||
HASH_PROBE_1(old_items[i].key, ok, j);
|
||||
c11__rtassert(!ok);
|
||||
self->items[j] = old_items[i];
|
||||
}
|
||||
PK_FREE(old_items);
|
||||
}
|
||||
|
||||
NameDict* NameDict__new(float load_factor) {
|
||||
NameDict* p = PK_MALLOC(sizeof(NameDict));
|
||||
NameDict__ctor(p, load_factor);
|
||||
return p;
|
||||
}
|
||||
|
||||
void NameDict__delete(NameDict* self) {
|
||||
NameDict__dtor(self);
|
||||
PK_FREE(self);
|
||||
}
|
||||
|
||||
void NameDict__ctor(NameDict* self, float load_factor) {
|
||||
assert(load_factor > 0.0f && load_factor < 1.0f);
|
||||
self->length = 0;
|
||||
self->load_factor = load_factor;
|
||||
NameDict__set_capacity_and_alloc_items(self, 4);
|
||||
}
|
||||
|
||||
void NameDict__dtor(NameDict* self) { PK_FREE(self->items); }
|
||||
|
||||
py_TValue* NameDict__try_get(NameDict* self, py_Name key) {
|
||||
bool ok;
|
||||
uintptr_t i;
|
||||
HASH_PROBE_0(key, ok, i);
|
||||
if(!ok) return NULL;
|
||||
return &self->items[i].value;
|
||||
}
|
||||
|
||||
bool NameDict__contains(NameDict* self, py_Name key) {
|
||||
bool ok;
|
||||
uintptr_t i;
|
||||
HASH_PROBE_0(key, ok, i);
|
||||
return ok;
|
||||
}
|
||||
|
||||
void NameDict__set(NameDict* self, py_Name key, py_TValue* val) {
|
||||
bool ok;
|
||||
uintptr_t i;
|
||||
HASH_PROBE_1(key, ok, i);
|
||||
if(!ok) {
|
||||
self->length++;
|
||||
if(self->length > self->critical_size) {
|
||||
NameDict__rehash_2x(self);
|
||||
HASH_PROBE_1(key, ok, i);
|
||||
}
|
||||
self->items[i].key = key;
|
||||
}
|
||||
self->items[i].value = *val;
|
||||
}
|
||||
|
||||
bool NameDict__del(NameDict* self, py_Name key) {
|
||||
bool ok;
|
||||
uintptr_t i;
|
||||
HASH_PROBE_0(key, ok, i);
|
||||
if(!ok) return false;
|
||||
self->items[i].key = NULL;
|
||||
self->items[i].value = *py_NIL();
|
||||
self->length--;
|
||||
// tidy
|
||||
uintptr_t pre_z = i;
|
||||
uintptr_t z = (i + 1) & self->mask;
|
||||
while(self->items[z].key != NULL) {
|
||||
uintptr_t h = (uintptr_t)self->items[z].key & self->mask;
|
||||
if(h != i) break;
|
||||
// std::swap(_items[pre_z], _items[z]);
|
||||
NameDict_KV tmp = self->items[pre_z];
|
||||
self->items[pre_z] = self->items[z];
|
||||
self->items[z] = tmp;
|
||||
pre_z = z;
|
||||
z = (z + 1) & self->mask;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void NameDict__clear(NameDict* self) {
|
||||
for(int i = 0; i < self->capacity; i++) {
|
||||
self->items[i].key = NULL;
|
||||
self->items[i].value = *py_NIL();
|
||||
}
|
||||
self->length = 0;
|
||||
}
|
||||
|
||||
#undef HASH_PROBE_0
|
||||
#undef HASH_PROBE_1
|
@ -3,6 +3,7 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/common/name.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
_Thread_local VM* pk_current_vm;
|
||||
@ -18,6 +19,8 @@ void py_initialize() {
|
||||
return;
|
||||
}
|
||||
|
||||
pk_names_initialize();
|
||||
|
||||
// check endianness
|
||||
int x = 1;
|
||||
bool is_little_endian = *(char*)&x == 1;
|
||||
@ -62,6 +65,8 @@ void py_finalize() {
|
||||
pk_current_vm = &pk_default_vm;
|
||||
VM__dtor(&pk_default_vm);
|
||||
pk_current_vm = NULL;
|
||||
|
||||
pk_names_finalize();
|
||||
}
|
||||
|
||||
void py_switchvm(int index) {
|
||||
@ -229,14 +234,7 @@ bool pk_loadmethod(py_StackRef self, py_Name name) {
|
||||
|
||||
py_Ref py_tpfindmagic(py_Type t, py_Name name) {
|
||||
assert(py_ismagicname(name));
|
||||
py_TypeInfo* ti = pk__type_info(t);
|
||||
do {
|
||||
py_Ref f = TypeList__magic_readonly(ti, name);
|
||||
assert(f != NULL);
|
||||
if(!py_isnil(f)) return f;
|
||||
ti = ti->base_ti;
|
||||
} while(ti);
|
||||
return NULL;
|
||||
return py_tpfindname(t, name);
|
||||
}
|
||||
|
||||
py_Ref py_tpfindname(py_Type t, py_Name name) {
|
||||
@ -249,10 +247,11 @@ py_Ref py_tpfindname(py_Type t, py_Name name) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
py_Ref py_tpgetmagic(py_Type type, py_Name name) {
|
||||
PK_DEPRECATED py_Ref py_tpgetmagic(py_Type type, py_Name name) {
|
||||
assert(py_ismagicname(name));
|
||||
py_TypeInfo* ti = pk__type_info(type);
|
||||
return TypeList__magic(ti, name);
|
||||
py_Ref retval = py_getdict(&ti->self, name);
|
||||
return retval != NULL ? retval : py_NIL();
|
||||
}
|
||||
|
||||
py_Ref py_tpobject(py_Type type) {
|
||||
|
@ -617,7 +617,7 @@ static bool
|
||||
int max_index = -1;
|
||||
c11__foreach(Bytecode, &co->codes, bc) {
|
||||
if(bc->op == OP_LOAD_NAME) {
|
||||
c11_sv name = py_name2sv(bc->arg);
|
||||
c11_sv name = py_name2sv(c11__getitem(py_Name, &co->names, bc->arg));
|
||||
if(name.data[0] != '_') continue;
|
||||
int index;
|
||||
if(name.size == 1) {
|
||||
@ -752,11 +752,11 @@ py_TValue pk_builtins__register() {
|
||||
|
||||
// some patches
|
||||
py_bindmagic(tp_NoneType, __repr__, NoneType__repr__);
|
||||
*py_tpgetmagic(tp_NoneType, __hash__) = *py_None();
|
||||
py_setdict(py_tpobject(tp_NoneType), __hash__, py_None());
|
||||
py_bindmagic(tp_ellipsis, __repr__, ellipsis__repr__);
|
||||
*py_tpgetmagic(tp_ellipsis, __hash__) = *py_None();
|
||||
py_setdict(py_tpobject(tp_ellipsis), __hash__, py_None());
|
||||
py_bindmagic(tp_NotImplementedType, __repr__, NotImplementedType__repr__);
|
||||
*py_tpgetmagic(tp_NotImplementedType, __hash__) = *py_None();
|
||||
py_setdict(py_tpobject(tp_NotImplementedType), __hash__, py_None());
|
||||
return *builtins;
|
||||
}
|
||||
|
||||
@ -764,9 +764,10 @@ void function__gc_mark(void* ud, c11_vector* p_stack) {
|
||||
Function* func = ud;
|
||||
if(func->globals) pk__mark_value(func->globals);
|
||||
if(func->closure) {
|
||||
NameDict* namedict = func->closure;
|
||||
for(int i = 0; i < namedict->length; i++) {
|
||||
NameDict_KV* kv = c11__at(NameDict_KV, namedict, i);
|
||||
NameDict* dict = func->closure;
|
||||
for(int i = 0; i < dict->capacity; i++) {
|
||||
NameDict_KV* kv = &dict->items[i];
|
||||
if(kv->key == NULL) continue;
|
||||
pk__mark_value(&kv->value);
|
||||
}
|
||||
}
|
||||
|
@ -225,6 +225,13 @@ char* py_formatexc() {
|
||||
}
|
||||
|
||||
bool py_exception(py_Type type, const char* fmt, ...) {
|
||||
#ifndef NDEBUG
|
||||
if(py_checkexc(true)) {
|
||||
const char* name = py_tpname(pk_current_vm->curr_exception.type);
|
||||
c11__abort("py_exception(): `%s` was already set!", name);
|
||||
}
|
||||
#endif
|
||||
|
||||
c11_sbuf buf;
|
||||
c11_sbuf__ctor(&buf);
|
||||
va_list args;
|
||||
|
@ -52,29 +52,11 @@ static bool namedict_items(int argc, py_Ref argv) {
|
||||
py_Ref object = py_getslot(argv, 0);
|
||||
NameDict* dict = PyObject__dict(object->_obj);
|
||||
py_newlist(py_retval());
|
||||
if(object->type == tp_type) {
|
||||
py_TypeInfo* ti = pk__type_info(py_totype(object));
|
||||
for(int j = 0; j < PK_MAGIC_SLOTS_COMMON_LENGTH; j++) {
|
||||
if(py_isnil(ti->magic_0 + j)) continue;
|
||||
for(int i = 0; i < dict->capacity; i++) {
|
||||
NameDict_KV* kv = &dict->items[i];
|
||||
if(kv->key == NULL) continue;
|
||||
py_Ref slot = py_list_emplace(py_retval());
|
||||
py_Ref p = py_newtuple(slot, 2);
|
||||
p[0] = *py_name2ref(j + PK_MAGIC_SLOTS_UNCOMMON_LENGTH);
|
||||
p[1] = ti->magic_0[j];
|
||||
}
|
||||
if(ti->magic_1) {
|
||||
for(int j = 0; j < PK_MAGIC_SLOTS_UNCOMMON_LENGTH; j++) {
|
||||
if(py_isnil(ti->magic_1 + j)) continue;
|
||||
py_Ref slot = py_list_emplace(py_retval());
|
||||
py_Ref p = py_newtuple(slot, 2);
|
||||
p[0] = *py_name2ref(j);
|
||||
p[1] = ti->magic_1[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < dict->length; i++) {
|
||||
py_Ref slot = py_list_emplace(py_retval());
|
||||
py_Ref p = py_newtuple(slot, 2);
|
||||
NameDict_KV* kv = c11__at(NameDict_KV, dict, i);
|
||||
p[0] = *py_name2ref(kv->key);
|
||||
p[1] = kv->value;
|
||||
}
|
||||
@ -97,7 +79,7 @@ py_Type pk_namedict__register() {
|
||||
py_bindmagic(type, __setitem__, namedict__setitem__);
|
||||
py_bindmagic(type, __delitem__, namedict__delitem__);
|
||||
py_bindmagic(type, __contains__, namedict__contains__);
|
||||
py_newnone(py_tpgetmagic(type, __hash__));
|
||||
py_setdict(py_tpobject(type), __hash__, py_None());
|
||||
py_bindmethod(type, "items", namedict_items);
|
||||
py_bindmethod(type, "clear", namedict_clear);
|
||||
return type;
|
||||
|
@ -54,11 +54,11 @@ int py_bool(py_Ref val) {
|
||||
bool py_hash(py_Ref val, int64_t* out) {
|
||||
py_TypeInfo* ti = pk__type_info(val->type);
|
||||
do {
|
||||
py_Ref slot_hash = TypeList__magic_common(ti, __hash__);
|
||||
if(py_isnone(slot_hash)) break;
|
||||
py_Ref slot_eq = TypeList__magic_common(ti, __eq__);
|
||||
if(!py_isnil(slot_eq)) {
|
||||
if(py_isnil(slot_hash)) break;
|
||||
py_Ref slot_hash = py_getdict(&ti->self, __hash__);
|
||||
if(slot_hash && py_isnone(slot_hash)) break;
|
||||
py_Ref slot_eq = py_getdict(&ti->self, __eq__);
|
||||
if(slot_eq) {
|
||||
if(!slot_hash) break;
|
||||
if(!py_call(slot_hash, 1, val)) return false;
|
||||
if(!py_checkint(py_retval())) return false;
|
||||
*out = py_toint(py_retval());
|
||||
|
@ -103,13 +103,8 @@ static bool str__new__(int argc, py_Ref argv) {
|
||||
|
||||
static bool str__hash__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
int size;
|
||||
const char* data = py_tostrn(&argv[0], &size);
|
||||
uint64_t res = 0;
|
||||
for(int i = 0; i < size; i++) {
|
||||
res = res * 31 + data[i];
|
||||
}
|
||||
py_newint(py_retval(), res);
|
||||
uint64_t res = c11_sv__hash(py_tosv(argv));
|
||||
py_newint(py_retval(), (py_i64)res);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -10,23 +10,12 @@ void py_setreg(int i, py_Ref val) { pk_current_vm->reg[i] = *val; }
|
||||
|
||||
py_Ref py_getdict(py_Ref self, py_Name name) {
|
||||
assert(self && self->is_ptr);
|
||||
if(!py_ismagicname(name) || self->type != tp_type) {
|
||||
return NameDict__try_get(PyObject__dict(self->_obj), name);
|
||||
} else {
|
||||
py_Type* ud = py_touserdata(self);
|
||||
py_Ref slot = py_tpgetmagic(*ud, name);
|
||||
return py_isnil(slot) ? NULL : slot;
|
||||
}
|
||||
}
|
||||
|
||||
void py_setdict(py_Ref self, py_Name name, py_Ref val) {
|
||||
assert(self && self->is_ptr);
|
||||
if(!py_ismagicname(name) || self->type != tp_type) {
|
||||
NameDict__set(PyObject__dict(self->_obj), name, *val);
|
||||
} else {
|
||||
py_Type* ud = py_touserdata(self);
|
||||
*py_tpgetmagic(*ud, name) = *val;
|
||||
}
|
||||
NameDict__set(PyObject__dict(self->_obj), name, val);
|
||||
}
|
||||
|
||||
py_ItemRef py_emplacedict(py_Ref self, py_Name name) {
|
||||
@ -37,8 +26,9 @@ py_ItemRef py_emplacedict(py_Ref self, py_Name name) {
|
||||
bool py_applydict(py_Ref self, bool (*f)(py_Name, py_Ref, void*), void* ctx) {
|
||||
assert(self && self->is_ptr);
|
||||
NameDict* dict = PyObject__dict(self->_obj);
|
||||
for(int i = 0; i < dict->length; i++) {
|
||||
NameDict_KV* kv = c11__at(NameDict_KV, dict, i);
|
||||
for(int i = 0; i < dict->capacity; i++) {
|
||||
NameDict_KV* kv = &dict->items[i];
|
||||
if(kv->key == NULL) continue;
|
||||
bool ok = f(kv->key, &kv->value, ctx);
|
||||
if(!ok) return false;
|
||||
}
|
||||
@ -47,13 +37,7 @@ bool py_applydict(py_Ref self, bool (*f)(py_Name, py_Ref, void*), void* ctx) {
|
||||
|
||||
bool py_deldict(py_Ref self, py_Name name) {
|
||||
assert(self && self->is_ptr);
|
||||
if(!py_ismagicname(name) || self->type != tp_type) {
|
||||
return NameDict__del(PyObject__dict(self->_obj), name);
|
||||
} else {
|
||||
py_Type* ud = py_touserdata(self);
|
||||
py_newnil(py_tpgetmagic(*ud, name));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
py_Ref py_getslot(py_Ref self, int i) {
|
||||
@ -119,7 +103,7 @@ void py_pushnone() {
|
||||
|
||||
void py_pushname(py_Name name) {
|
||||
VM* vm = pk_current_vm;
|
||||
py_newint(vm->stack.sp++, name);
|
||||
py_newint(vm->stack.sp++, (uintptr_t)name);
|
||||
}
|
||||
|
||||
py_Ref py_pushtmp() {
|
||||
|
@ -83,14 +83,22 @@ void py_bindproperty(py_Type type, const char* name, py_CFunction getter, py_CFu
|
||||
py_setdict(py_tpobject(type), py_name(name), &tmp);
|
||||
}
|
||||
|
||||
void py_bindmagic(py_Type type, py_Name name, py_CFunction f) {
|
||||
py_Ref tmp = py_emplacedict(py_tpobject(type), name);
|
||||
py_newnativefunc(tmp, f);
|
||||
}
|
||||
|
||||
void py_bind(py_Ref obj, const char* sig, py_CFunction f) {
|
||||
py_TValue tmp;
|
||||
py_Name name = py_newfunction(&tmp, sig, f, NULL, 0);
|
||||
py_setdict(obj, name, &tmp);
|
||||
}
|
||||
|
||||
py_Name
|
||||
py_newfunction(py_OutRef out, const char* sig, py_CFunction f, const char* docstring, int slots) {
|
||||
py_Name py_newfunction(py_OutRef out,
|
||||
const char* sig,
|
||||
py_CFunction f,
|
||||
const char* docstring,
|
||||
int slots) {
|
||||
char buffer[256];
|
||||
snprintf(buffer, sizeof(buffer), "def %s: pass", sig);
|
||||
// fn(a, b, *c, d=1) -> None
|
||||
|
Loading…
x
Reference in New Issue
Block a user