浏览代码

add `PK_LOW_MEMORY_MODE`

blueloveTH 1 年之前
父节点
当前提交
93ca8d88f3
共有 5 个文件被更改,包括 67 次插入16 次删除
  1. 16 3
      include/pocketpy/config.h
  2. 2 3
      include/pocketpy/interpreter/frame.h
  3. 1 0
      src/common/sstream.c
  4. 46 9
      src/interpreter/ceval.c
  5. 2 1
      src/interpreter/heap.c

+ 16 - 3
include/pocketpy/config.h

@@ -8,6 +8,11 @@
 
 /*************** feature settings ***************/
 
+// Reduce the startup memory usage for embedded systems
+#ifndef PK_LOW_MEMORY_MODE          // can be overridden by cmake
+#define PK_LOW_MEMORY_MODE          0
+#endif
+
 // Whether to compile os-related modules or not
 #ifndef PK_ENABLE_OS                // can be overridden by cmake
 #define PK_ENABLE_OS                1
@@ -15,7 +20,11 @@
 
 // GC min threshold
 #ifndef PK_GC_MIN_THRESHOLD         // can be overridden by cmake
-#define PK_GC_MIN_THRESHOLD         16384
+    #if PK_LOW_MEMORY_MODE
+        #define PK_GC_MIN_THRESHOLD     2048
+    #else
+        #define PK_GC_MIN_THRESHOLD     16384
+    #endif
 #endif
 
 // Memory allocation functions
@@ -28,7 +37,11 @@
 // This is the maximum size of the value stack in py_TValue units
 // The actual size in bytes equals `sizeof(py_TValue) * PK_VM_STACK_SIZE`
 #ifndef PK_VM_STACK_SIZE            // can be overridden by cmake
-#define PK_VM_STACK_SIZE            16384
+    #if PK_LOW_MEMORY_MODE
+        #define PK_VM_STACK_SIZE    2048
+    #else
+        #define PK_VM_STACK_SIZE    16384
+    #endif
 #endif
 
 // This is the maximum number of local variables in a function
@@ -51,4 +64,4 @@
     #define PK_PLATFORM_SEP '\\'
 #else
     #define PK_PLATFORM_SEP '/'
-#endif
+#endif

+ 2 - 3
include/pocketpy/interpreter/frame.h

@@ -11,11 +11,10 @@ py_TValue* FastLocals__try_get_by_name(py_TValue* locals, const CodeObject* co,
 NameDict* FastLocals__to_namedict(py_TValue* locals, const CodeObject* co);
 
 typedef struct ValueStack {
-    // We allocate extra PK_VM_STACK_SIZE/128 places to keep `_sp` valid when `is_overflow() ==
-    // true`.
     py_TValue* sp;
     py_TValue* end;
-    py_TValue begin[PK_VM_STACK_SIZE + PK_VM_STACK_SIZE / 128];
+    // We allocate extra places to keep `_sp` valid to detect stack overflow
+    py_TValue begin[PK_VM_STACK_SIZE + PK_MAX_CO_VARNAMES * 2];
 } ValueStack;
 
 void ValueStack__ctor(ValueStack* self);

+ 1 - 0
src/common/sstream.c

@@ -100,6 +100,7 @@ void c11_sbuf__write_quoted(c11_sbuf* self, c11_sv sv, char quote) {
             case '\b': c11_sbuf__write_cstrn(self, "\\b", 2); break;
             default: {
                 int u8bytes = c11__u8_header(c, true);
+                if(i + u8bytes > sv.size) u8bytes = 0;  // invalid utf8
                 if(u8bytes <= 1) {
                     // not a valid utf8 char, or ascii
                     if(!isprint(c)) {

+ 46 - 9
src/interpreter/ceval.c

@@ -13,6 +13,14 @@ static bool stack_format_object(VM* self, c11_sv spec);
 #define CHECK_RETURN_FROM_EXCEPT_OR_FINALLY()                                                      \
     if(self->is_curr_exc_handled) py_clearexc(NULL)
 
+#define CHECK_STACK_OVERFLOW()                                                                     \
+    do {                                                                                           \
+        if(self->stack.sp > self->stack.end) {                                                     \
+            py_exception(tp_StackOverflowError, "");                                               \
+            goto __ERROR;                                                                          \
+        }                                                                                          \
+    } while(0)
+
 #define DISPATCH()                                                                                 \
     do {                                                                                           \
         frame->ip++;                                                                               \
@@ -92,7 +100,7 @@ FrameResult VM__run_top_frame(VM* self) {
         pk_print_stack(self, frame, byte);
 #endif
 
-        if(self->is_signal_interrupted){
+        if(self->is_signal_interrupted) {
             self->is_signal_interrupted = false;
             py_exception(tp_KeyboardInterrupt, "");
             goto __ERROR;
@@ -132,15 +140,40 @@ FrameResult VM__run_top_frame(VM* self) {
                 POP();
                 DISPATCH();
             /*****************************************/
-            case OP_LOAD_CONST: PUSH(c11__at(py_TValue, &frame->co->consts, byte.arg)); DISPATCH();
-            case OP_LOAD_NONE: py_newnone(SP()++); DISPATCH();
-            case OP_LOAD_TRUE: py_newbool(SP()++, true); DISPATCH();
-            case OP_LOAD_FALSE: py_newbool(SP()++, false); DISPATCH();
+            case OP_LOAD_CONST: {
+                CHECK_STACK_OVERFLOW();
+                PUSH(c11__at(py_TValue, &frame->co->consts, byte.arg));
+                DISPATCH();
+            }
+            case OP_LOAD_NONE: {
+                CHECK_STACK_OVERFLOW();
+                py_newnone(SP()++);
+                DISPATCH();
+            }
+            case OP_LOAD_TRUE: {
+                CHECK_STACK_OVERFLOW();
+                py_newbool(SP()++, true);
+                DISPATCH();
+            }
+            case OP_LOAD_FALSE: {
+                CHECK_STACK_OVERFLOW();
+                py_newbool(SP()++, false);
+                DISPATCH();
+            }
             /*****************************************/
-            case OP_LOAD_SMALL_INT: py_newint(SP()++, (int16_t)byte.arg); DISPATCH();
+            case OP_LOAD_SMALL_INT: {
+                CHECK_STACK_OVERFLOW();
+                py_newint(SP()++, (int16_t)byte.arg);
+                DISPATCH();
+            }
             /*****************************************/
-            case OP_LOAD_ELLIPSIS: py_newellipsis(SP()++); DISPATCH();
+            case OP_LOAD_ELLIPSIS: {
+                CHECK_STACK_OVERFLOW();
+                py_newellipsis(SP()++);
+                DISPATCH();
+            }
             case OP_LOAD_FUNCTION: {
+                CHECK_STACK_OVERFLOW();
                 FuncDecl_ decl = c11__getitem(FuncDecl_, &frame->co->func_decls, byte.arg);
                 Function* ud = py_newobject(SP(), tp_function, 0, sizeof(Function));
                 Function__ctor(ud, decl, frame->module);
@@ -952,8 +985,12 @@ FrameResult VM__run_top_frame(VM* self) {
                     goto __ERROR;
                 }
 
-                py_Type type =
-                    pk_newtype(py_name2str(name), base, frame->module, NULL, base_ti->is_python, false);
+                py_Type type = pk_newtype(py_name2str(name),
+                                          base,
+                                          frame->module,
+                                          NULL,
+                                          base_ti->is_python,
+                                          false);
                 PUSH(py_tpobject(type));
                 self->__curr_class = TOP();
                 DISPATCH();

+ 2 - 1
src/interpreter/heap.c

@@ -1,5 +1,6 @@
 #include "pocketpy/interpreter/heap.h"
 #include "pocketpy/common/memorypool.h"
+#include "pocketpy/config.h"
 #include "pocketpy/objects/base.h"
 
 void ManagedHeap__ctor(ManagedHeap* self, VM* vm) {
@@ -94,7 +95,7 @@ PyObject* PyObject__new(py_Type type, int slots, int size) {
     PyObject* self;
     // header + slots + udsize
     size = sizeof(PyObject) + PK_OBJ_SLOTS_SIZE(slots) + size;
-    if(size <= kPoolObjectBlockSize) {
+    if(!PK_LOW_MEMORY_MODE && size <= kPoolObjectBlockSize) {
         self = PoolObject_alloc();
         self->gc_is_large = false;
     } else {