mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-18 21:30:38 +01:00
[code] Get rid of malloc: keep a buffer in Code::App to be used as python heap
This commit is contained in:
@@ -77,18 +77,24 @@ void App::Snapshot::setOpt(const char * name, char * value) {
|
||||
|
||||
App::App(Container * container, Snapshot * snapshot) :
|
||||
::App(container, snapshot, &m_codeStackViewController, I18n::Message::Warning),
|
||||
m_consoleController(nullptr, snapshot->scriptStore()
|
||||
m_pythonHeap{},
|
||||
m_pythonUser(nullptr),
|
||||
m_consoleController(nullptr, this, snapshot->scriptStore()
|
||||
#if EPSILON_GETOPT
|
||||
, snapshot->lockOnConsole()
|
||||
#endif
|
||||
),
|
||||
m_listFooter(&m_codeStackViewController, &m_menuController, &m_menuController, ButtonRowController::Position::Bottom, ButtonRowController::Style::EmbossedGrey, ButtonRowController::Size::Large),
|
||||
m_menuController(&m_listFooter, snapshot->scriptStore(), &m_listFooter),
|
||||
m_menuController(&m_listFooter, this, snapshot->scriptStore(), &m_listFooter),
|
||||
m_codeStackViewController(&m_modalViewController, &m_listFooter),
|
||||
m_variableBoxController(&m_menuController, snapshot->scriptStore())
|
||||
{
|
||||
}
|
||||
|
||||
App::~App() {
|
||||
deinitPython();
|
||||
}
|
||||
|
||||
bool App::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::Home && m_consoleController.inputRunLoopActive()) {
|
||||
// We need to return true here because we want to actually exit from the
|
||||
@@ -117,4 +123,17 @@ bool App::textInputDidReceiveEvent(TextInput * textInput, Ion::Events::Event eve
|
||||
return false;
|
||||
}
|
||||
|
||||
void App::initPythonWithUser(const void * pythonUser) {
|
||||
assert(m_pythonUser == nullptr);
|
||||
m_pythonUser = pythonUser;
|
||||
MicroPython::init(m_pythonHeap, m_pythonHeap + k_pythonHeapSize);
|
||||
}
|
||||
|
||||
void App::deinitPython() {
|
||||
if (m_pythonUser) {
|
||||
MicroPython::deinit();
|
||||
m_pythonUser = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,12 +36,26 @@ public:
|
||||
#endif
|
||||
ScriptStore m_scriptStore;
|
||||
};
|
||||
~App();
|
||||
StackViewController * stackViewController() { return &m_codeStackViewController; }
|
||||
ConsoleController * consoleController() { return &m_consoleController; }
|
||||
PythonToolbox * pythonToolbox() { return &m_toolbox; }
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
bool textInputDidReceiveEvent(TextInput * textInput, Ion::Events::Event event);
|
||||
// Python delegate
|
||||
bool isPythonUser(const void * pythonUser) { return m_pythonUser == pythonUser; }
|
||||
void initPythonWithUser(const void * pythonUser);
|
||||
void deinitPython();
|
||||
private:
|
||||
/* Python delegate:
|
||||
* MicroPython requires a heap. To avoid dynamic allocation, we keep a working
|
||||
* buffer here and we give to controllers that load Python environment. We
|
||||
* also memoize the last Python user to avoid re-initiating MicroPython when
|
||||
* unneeded. */
|
||||
static constexpr int k_pythonHeapSize = 16384;
|
||||
char m_pythonHeap[k_pythonHeapSize];
|
||||
const void * m_pythonUser;
|
||||
|
||||
App(Container * container, Snapshot * snapshot);
|
||||
ConsoleController m_consoleController;
|
||||
ButtonRowController m_listFooter;
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Code {
|
||||
|
||||
static const char * sStandardPromptText = ">>> ";
|
||||
|
||||
ConsoleController::ConsoleController(Responder * parentResponder, ScriptStore * scriptStore
|
||||
ConsoleController::ConsoleController(Responder * parentResponder, App * pythonDelegate, ScriptStore * scriptStore
|
||||
#if EPSILON_GETOPT
|
||||
, bool lockOnConsole
|
||||
#endif
|
||||
@@ -24,11 +24,11 @@ ConsoleController::ConsoleController(Responder * parentResponder, ScriptStore *
|
||||
SelectableTableViewDataSource(),
|
||||
TextFieldDelegate(),
|
||||
MicroPython::ExecutionEnvironment(),
|
||||
m_pythonDelegate(pythonDelegate),
|
||||
m_rowHeight(KDText::charSize(k_fontSize).height()),
|
||||
m_importScriptsWhenViewAppears(false),
|
||||
m_selectableTableView(this, this, this, this),
|
||||
m_editCell(this, this),
|
||||
m_pythonHeap(nullptr),
|
||||
m_scriptStore(scriptStore),
|
||||
m_sandboxController(this),
|
||||
m_inputRunLoopActive(false)
|
||||
@@ -44,22 +44,12 @@ ConsoleController::ConsoleController(Responder * parentResponder, ScriptStore *
|
||||
}
|
||||
}
|
||||
|
||||
ConsoleController::~ConsoleController() {
|
||||
unloadPythonEnvironment();
|
||||
}
|
||||
|
||||
bool ConsoleController::loadPythonEnvironment(bool autoImportScripts) {
|
||||
if(pythonEnvironmentIsLoaded()) {
|
||||
return true;
|
||||
}
|
||||
emptyOutputAccumulationBuffer();
|
||||
m_pythonHeap = (char *)malloc(k_pythonHeapSize);
|
||||
if (m_pythonHeap == nullptr) {
|
||||
// In DEBUG mode, the assert at the end of malloc would have already failed
|
||||
// and the program crashed.
|
||||
return false;
|
||||
}
|
||||
MicroPython::init(m_pythonHeap, m_pythonHeap + k_pythonHeapSize);
|
||||
m_pythonDelegate->initPythonWithUser(this);
|
||||
MicroPython::registerScriptProvider(m_scriptStore);
|
||||
m_importScriptsWhenViewAppears = autoImportScripts;
|
||||
return true;
|
||||
@@ -68,14 +58,12 @@ bool ConsoleController::loadPythonEnvironment(bool autoImportScripts) {
|
||||
void ConsoleController::unloadPythonEnvironment() {
|
||||
if (pythonEnvironmentIsLoaded()) {
|
||||
m_consoleStore.startNewSession();
|
||||
MicroPython::deinit();
|
||||
free(m_pythonHeap);
|
||||
m_pythonHeap = nullptr;
|
||||
m_pythonDelegate->deinitPython();
|
||||
}
|
||||
}
|
||||
|
||||
bool ConsoleController::pythonEnvironmentIsLoaded() {
|
||||
return (m_pythonHeap != nullptr);
|
||||
return m_pythonDelegate->isPythonUser(this);
|
||||
}
|
||||
|
||||
void ConsoleController::autoImport() {
|
||||
|
||||
@@ -12,20 +12,17 @@
|
||||
|
||||
namespace Code {
|
||||
|
||||
class App;
|
||||
|
||||
class ConsoleController : public ViewController, public ListViewDataSource, public SelectableTableViewDataSource, public SelectableTableViewDelegate, public TextFieldDelegate, public MicroPython::ExecutionEnvironment {
|
||||
public:
|
||||
static constexpr KDText::FontSize k_fontSize = KDText::FontSize::Large;
|
||||
|
||||
ConsoleController(Responder * parentResponder, ScriptStore * scriptStore
|
||||
ConsoleController(Responder * parentResponder, App * pythonDelegate, ScriptStore * scriptStore
|
||||
#if EPSILON_GETOPT
|
||||
, bool m_lockOnConsole
|
||||
#endif
|
||||
);
|
||||
~ConsoleController();
|
||||
ConsoleController(const ConsoleController& other) = delete;
|
||||
ConsoleController(ConsoleController&& other) = delete;
|
||||
ConsoleController operator=(const ConsoleController& other) = delete;
|
||||
ConsoleController& operator=(ConsoleController&& other) = delete;
|
||||
|
||||
bool loadPythonEnvironment(bool autoImportScripts = true);
|
||||
void unloadPythonEnvironment();
|
||||
@@ -81,20 +78,19 @@ private:
|
||||
static constexpr int LineCellType = 0;
|
||||
static constexpr int EditCellType = 1;
|
||||
static constexpr int k_numberOfLineCells = 15; // May change depending on the screen height
|
||||
static constexpr int k_pythonHeapSize = 16384;
|
||||
static constexpr int k_outputAccumulationBufferSize = 100;
|
||||
void flushOutputAccumulationBufferToStore();
|
||||
void appendTextToOutputAccumulationBuffer(const char * text, size_t length);
|
||||
void emptyOutputAccumulationBuffer();
|
||||
size_t firstNewLineCharIndex(const char * text, size_t length);
|
||||
StackViewController * stackViewController();
|
||||
App * m_pythonDelegate;
|
||||
int m_rowHeight;
|
||||
bool m_importScriptsWhenViewAppears;
|
||||
ConsoleStore m_consoleStore;
|
||||
SelectableTableView m_selectableTableView;
|
||||
ConsoleLineCell m_cells[k_numberOfLineCells];
|
||||
ConsoleEditCell m_editCell;
|
||||
char * m_pythonHeap;
|
||||
char m_outputAccumulationBuffer[k_outputAccumulationBufferSize];
|
||||
/* The Python machine might call printText several times to print a single
|
||||
* string. We thus use m_outputAccumulationBuffer to store and concatenate the
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
|
||||
namespace Code {
|
||||
|
||||
EditorController::EditorController(MenuController * menuController) :
|
||||
EditorController::EditorController(MenuController * menuController, App * pythonDelegate) :
|
||||
ViewController(nullptr),
|
||||
m_editorView(this),
|
||||
m_editorView(this, pythonDelegate),
|
||||
m_script(Ion::Storage::Record()),
|
||||
m_menuController(menuController)
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@ class ScriptParameterController;
|
||||
|
||||
class EditorController : public ViewController, public TextAreaDelegate {
|
||||
public:
|
||||
EditorController(MenuController * menuController);
|
||||
EditorController(MenuController * menuController, App * pythonDelegate);
|
||||
void setScript(Script script);
|
||||
|
||||
/* ViewController */
|
||||
|
||||
@@ -8,10 +8,10 @@ namespace Code {
|
||||
|
||||
constexpr KDText::FontSize editorFontSize = KDText::FontSize::Large;
|
||||
|
||||
EditorView::EditorView(Responder * parentResponder) :
|
||||
EditorView::EditorView(Responder * parentResponder, App * pythonDelegate) :
|
||||
Responder(parentResponder),
|
||||
View(),
|
||||
m_textArea(parentResponder, editorFontSize),
|
||||
m_textArea(parentResponder, pythonDelegate, editorFontSize),
|
||||
m_gutterView(editorFontSize)
|
||||
{
|
||||
m_textArea.setScrollViewDelegate(this);
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Code {
|
||||
|
||||
class EditorView : public Responder, public View, public ScrollViewDelegate {
|
||||
public:
|
||||
EditorView(Responder * parentResponder);
|
||||
EditorView(Responder * parentResponder, App * pythonDelegate);
|
||||
void setTextAreaDelegate(TextAreaDelegate * delegate) {
|
||||
m_textArea.setDelegate(delegate);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
namespace Code {
|
||||
|
||||
MenuController::MenuController(Responder * parentResponder, ScriptStore * scriptStore, ButtonRowController * footer) :
|
||||
MenuController::MenuController(Responder * parentResponder, App * pythonDelegate, ScriptStore * scriptStore, ButtonRowController * footer) :
|
||||
ViewController(parentResponder),
|
||||
ButtonRowDelegate(nullptr, footer),
|
||||
m_scriptStore(scriptStore),
|
||||
@@ -23,7 +23,7 @@ MenuController::MenuController(Responder * parentResponder, ScriptStore * script
|
||||
}, this), KDText::FontSize::Large),
|
||||
m_selectableTableView(this, this, this, this),
|
||||
m_scriptParameterController(nullptr, I18n::Message::ScriptOptions, this),
|
||||
m_editorController(this),
|
||||
m_editorController(this, pythonDelegate),
|
||||
m_reloadConsoleWhenBecomingFirstResponder(false),
|
||||
m_shouldDisplayAddScriptRow(true)
|
||||
{
|
||||
|
||||
@@ -13,7 +13,7 @@ class ScriptParameterController;
|
||||
|
||||
class MenuController : public ViewController, public TableViewDataSource, public SelectableTableViewDataSource, public SelectableTableViewDelegate, public TextFieldDelegate, public ButtonRowDelegate {
|
||||
public:
|
||||
MenuController(Responder * parentResponder, ScriptStore * scriptStore, ButtonRowController * footer);
|
||||
MenuController(Responder * parentResponder, App * pythonDelegate, ScriptStore * scriptStore, ButtonRowController * footer);
|
||||
ConsoleController * consoleController();
|
||||
StackViewController * stackViewController();
|
||||
void willExitResponderChain(Responder * nextFirstResponder) override;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "python_text_area.h"
|
||||
#include "app.h"
|
||||
|
||||
extern "C" {
|
||||
#include "py/nlr.h"
|
||||
@@ -75,19 +76,11 @@ static inline size_t TokenLength(mp_lexer_t * lex) {
|
||||
}
|
||||
|
||||
void PythonTextArea::ContentView::loadSyntaxHighlighter() {
|
||||
assert(m_pythonHeap == nullptr);
|
||||
m_pythonHeap = static_cast<char *>(malloc(k_pythonHeapSize));
|
||||
if (m_pythonHeap != nullptr) {
|
||||
MicroPython::init(m_pythonHeap, m_pythonHeap + k_pythonHeapSize);
|
||||
}
|
||||
m_pythonDelegate->initPythonWithUser(this);
|
||||
}
|
||||
|
||||
void PythonTextArea::ContentView::unloadSyntaxHighlighter() {
|
||||
if (m_pythonHeap != nullptr) {
|
||||
MicroPython::deinit();
|
||||
free(m_pythonHeap);
|
||||
m_pythonHeap = nullptr;
|
||||
}
|
||||
m_pythonDelegate->deinitPython();
|
||||
}
|
||||
|
||||
void PythonTextArea::ContentView::clearRect(KDContext * ctx, KDRect rect) const {
|
||||
@@ -105,7 +98,7 @@ void PythonTextArea::ContentView::clearRect(KDContext * ctx, KDRect rect) const
|
||||
void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char * text, size_t length, int fromColumn, int toColumn) const {
|
||||
LOG_DRAW("Drawing \"%.*s\"\n", length, text);
|
||||
|
||||
if (m_pythonHeap == nullptr) {
|
||||
if (!m_pythonDelegate->isPythonUser(this)) {
|
||||
drawStringAt(
|
||||
ctx,
|
||||
line,
|
||||
|
||||
@@ -5,11 +5,13 @@
|
||||
|
||||
namespace Code {
|
||||
|
||||
class App;
|
||||
|
||||
class PythonTextArea : public TextArea {
|
||||
public:
|
||||
PythonTextArea(Responder * parentResponder, KDText::FontSize fontSize) :
|
||||
PythonTextArea(Responder * parentResponder, App * pythonDelegate, KDText::FontSize fontSize) :
|
||||
TextArea(parentResponder, &m_contentView, fontSize),
|
||||
m_contentView(fontSize)
|
||||
m_contentView(pythonDelegate, fontSize)
|
||||
{
|
||||
}
|
||||
void loadSyntaxHighlighter() { m_contentView.loadSyntaxHighlighter(); }
|
||||
@@ -17,9 +19,9 @@ public:
|
||||
protected:
|
||||
class ContentView : public TextArea::ContentView {
|
||||
public:
|
||||
ContentView(KDText::FontSize fontSize) :
|
||||
ContentView(App * pythonDelegate, KDText::FontSize fontSize) :
|
||||
TextArea::ContentView(fontSize),
|
||||
m_pythonHeap(nullptr)
|
||||
m_pythonDelegate(pythonDelegate)
|
||||
{
|
||||
}
|
||||
void loadSyntaxHighlighter();
|
||||
@@ -28,8 +30,7 @@ protected:
|
||||
void drawLine(KDContext * ctx, int line, const char * text, size_t length, int fromColumn, int toColumn) const override;
|
||||
KDRect dirtyRectFromCursorPosition(size_t index, bool lineBreak) const override;
|
||||
private:
|
||||
static constexpr size_t k_pythonHeapSize = 4096;
|
||||
char * m_pythonHeap;
|
||||
App * m_pythonDelegate;
|
||||
};
|
||||
private:
|
||||
const ContentView * nonEditableContentView() const override { return &m_contentView; }
|
||||
|
||||
Reference in New Issue
Block a user