MicroPythonin merkkijonojen sisäistäminen¶
MicroPython käyttää merkkijonojen sisäistämistä säästääkseen sekä RAM- että ROM-muistia. Tämä välttää saman merkkijonon kaksoiskappaleiden tallentamisen. Ensisijaisesti tämä koskee koodisi tunnisteita, sillä esimerkiksi funktion tai muuttujan nimi esiintyy hyvin todennäköisesti koodissa useassa paikassa. MicroPythonissa sisäistettyä merkkijonoa kutsutaan nimellä QSTR (uniQue STRing).
QSTR-arvo (jonka tyyppi on qstr) on indeksi QSTR-altaiden linkitettyyn listaan. QSTR:t tallentavat pituutensa ja sisältönsä tiivisteen nopeaa vertailua varten kaksoiskappaleiden poistoprosessin aikana. Kaikki merkkijonojen kanssa toimivat tavukoodioperaatiot käyttävät QSTR-argumenttia.
QSTR:ien generointi käännösaikana¶
MicroPythonin C-koodissa kaikki merkkijonot, jotka tulisi sisäistää lopulliseen laiteohjelmistoon, kirjoitetaan muodossa MP_QSTR_Foo. Käännösaikana tämä muuntuu qstr-arvoksi, joka osoittaa merkkijonon "Foo" indeksiin QSTR-altaassa.
Monivaiheinen prosessi Makefile-tiedostossa saa tämän toimimaan. Tiivistettynä tässä prosessissa on kolme osaa:
Etsi kaikki
MP_QSTR_Foo-tokenit koodista.Generoi staattinen QSTR-allas, joka sisältää kaiken merkkijonodatan (mukaan lukien pituudet ja tiivisteet).
Korvaa kaikki
MP_QSTR_Foo(esikäsittelijän avulla) niitä vastaavalla indeksillä.
MP_QSTR_Foo-tokeneita etsitään kahdesta lähteestä:
Kaikki tiedostot, joihin viitataan muuttujassa
$(SRC_QSTR). Tämä on kaikki C-koodi (elipy,extmod,ports/stm32), mutta ei kolmannen osapuolen koodia, kutenlib.Lisäksi
$(QSTR_GLOBAL_DEPENDENCIES)(joka sisältäämpconfig*.h).
Huomaa: frozen_mpy.c (jonka mpy-tool.py generoi) sisältää oman QSTR-generointinsa ja -altaansa.
Jotkin lisämerkkijonot, joita ei voida ilmaista MP_QSTR_Foo-syntaksilla (esimerkiksi koska ne sisältävät ei-aakkosnumeerisia merkkejä), määritellään eksplisiittisesti tiedostoissa qstrdefs.h ja qstrdefsport.h muuttujan $(QSTR_DEFS) kautta.
Käsittely tapahtuu seuraavissa vaiheissa:
qstr.i.laston tulos, joka saadaan ajamalla jokainen yksittäinen syötetiedosto C-esikäsittelijän läpi. Tämä tarkoittaa, että kaikki ehdollisesti pois kytketty koodi poistetaan ja makrot laajennetaan. Näin emme lisää altaaseen merkkijonoja, joita ei käytetä lopullisessa laiteohjelmistossa. Koska tässä vaiheessa (QSTR_GEN_CFLAGS-asetuksen lisäämänNO_QSTR-makron ansiosta)MP_QSTR_Foo:lla ei ole määritelmää, se kulkee tämän vaiheen läpi muuttumattomana. Tämä tiedosto sisältää myös esikäsittelijän kommentit, jotka sisältävät rivinumerotiedot. Huomaa, että tämä vaihe käyttää vain muuttuneita tiedostoja, mikä tarkoittaa, ettäqstr.i.lastsisältää dataa vain niistä tiedostoista, jotka ovat muuttuneet edellisen käännöksen jälkeen.qstr.spliton tyhjä tiedosto, joka luodaan komennonmakeqstrdefs.py splitajamisen jälkeen tiedostolle qstr.i.last. Sitä käytetään vain riippuvuutena osoittamaan, että vaihe ajettiin. Tämä skripti tuottaa yhden tiedoston jokaista syöte-C-tiedostoa kohti,genhdr/qstr/...file.c.qstr, joka sisältää vain löydetyt QSTR:t. Jokainen QSTR tulostetaan muodossaQ(Foo). Tämä vaihe on välttämätön, jotta olemassa olevat tiedostot voidaan yhdistää inkrementaalisesta päivityksestä tiedostossaqstr.i.lastsyntyneeseen uuteen dataan.qstrdefs.collected.hon tulos, joka saadaan yhdistämällägenhdr/qstr/*komennollamakeqstrdefs.py cat. Tämä on nyt koko joukko koodista löydettyjäMP_QSTR_Foo:ja, nyt muotoiltuna muotoonQ(Foo), yksi per rivi, kaksoiskappaleiden kanssa. Tämä tiedosto päivitetään vain, jos qstr-joukko on muuttunut. QSTR-datan tiiviste kirjoitetaan toiseen tiedostoon (qstrdefs.collected.h.hash), mikä mahdollistaa muutosten seurannan käännösten välillä.Generoi luettelo (enum), jonka jokainen merkintä yhdistää
MP_QSTR_Foo:n sitä vastaavaan indeksiin. Se yhdistää tiedostonqstrdefs.collected.htiedostoihinqstrdefs*.hja muuntaa sitten jokaisen rivin muodostaQ(Foo)muotoon"Q(Foo)", jotta ne kulkevat esikäsittelijän läpi muuttumattomina. Sen jälkeen esikäsittelijää käytetään käsittelemään mahdollinen ehdollinen kääntäminen tiedostoissaqstrdefs*.h. Sitten muunnos perutaan takaisin muotoonQ(Foo)ja tallennetaan tiedostonaqstrdefs.preprocessed.h.qstrdefs.generated.hon komennonmakeqstrdata.pytulos. JokaiselleQ(Foo):lle tiedostossa qstrdefs.preprocessed.h (sekä joillekin ylimääräisille kovakoodatuille) se tulostaaQDEF(MP_QSTR_Foo, (const byte*)"hash" "Foo").
Sitten pääkäännöksessä tiedostolle qstrdefs.generated.h tapahtuu kaksi asiaa:
Tiedostossa qstr.h jokaisesta QDEF:stä tulee merkintä luettelossa (enum), mikä tekee
MP_QSTR_Foo:sta koodin saatavilla olevan ja yhtä suuren kuin kyseisen merkkijonon indeksi QSTR-taulukossa.Tiedostossa qstr.c varsinainen QSTR-datataulukko generoidaan
mp_qstr_const_pool->qstrs:n elementteinä.
QSTR:ien generointi ajon aikana¶
Lisää QSTR-altaita voidaan luoda ajon aikana, jotta niihin voidaan lisätä merkkijonoja. Esimerkiksi koodi:
foo[x] = 3
Joutuu luomaan QSTR:n arvolle x, jotta sitä voidaan käyttää ”load attr” -tavukoodissa.
Lisäksi Python-koodia käännettäessä tunnisteille ja literaaleille on luotava QSTR:t. Huomaa: vain alle 10 merkkiä pitkistä literaaleista tulee QSTR:iä. Tämä johtuu siitä, että tavallinen merkkijono keossa vie aina vähintään 16 tavua (yksi GC-lohko), kun taas QSTR:t mahdollistavat niiden tehokkaamman pakkaamisen altaaseen.
QSTR-altaat (ja niiden taustalla olevat ”lohkot”, jotka tallentavat merkkijonodatan) varataan tarpeen mukaan keosta vähimmäiskoolla.