[code] Get rid of malloc: keep a buffer in Code::App to be used as python heap

This commit is contained in:
Émilie Feral
2018-09-19 18:20:30 +02:00
parent ac9b889a67
commit afce751eb7
12 changed files with 64 additions and 53 deletions

View File

@@ -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;
}
}
}

View File

@@ -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;

View File

@@ -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() {

View File

@@ -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

View File

@@ -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)
{

View File

@@ -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 */

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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,

View File

@@ -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; }