Avoid extra allocations

This commit is contained in:
Kampfkarren 2022-07-27 17:13:44 -07:00
parent dadbd4cd47
commit 2a41dca9d4
3 changed files with 3443 additions and 3442 deletions

View file

@ -1,386 +1,386 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once #pragma once
#include "Luau/Ast.h" #include "Luau/Ast.h"
#include "Luau/Lexer.h" #include "Luau/Lexer.h"
#include "Luau/ParseOptions.h" #include "Luau/ParseOptions.h"
#include "Luau/ParseResult.h" #include "Luau/ParseResult.h"
#include "Luau/StringUtils.h" #include "Luau/StringUtils.h"
#include "Luau/DenseHash.h" #include "Luau/DenseHash.h"
#include "Luau/Common.h" #include "Luau/Common.h"
#include <initializer_list> #include <initializer_list>
#include <optional> #include <optional>
namespace Luau namespace Luau
{ {
template<typename T> template<typename T>
class TempVector class TempVector
{ {
public: public:
explicit TempVector(std::vector<T>& storage); explicit TempVector(std::vector<T>& storage);
~TempVector(); ~TempVector();
const T& operator[](std::size_t index) const; const T& operator[](std::size_t index) const;
const T& front() const; const T& front() const;
const T& back() const; const T& back() const;
bool empty() const; bool empty() const;
std::size_t size() const; std::size_t size() const;
void push_back(const T& item); void push_back(const T& item);
typename std::vector<T>::const_iterator begin() const typename std::vector<T>::const_iterator begin() const
{ {
return storage.begin() + offset; return storage.begin() + offset;
} }
typename std::vector<T>::const_iterator end() const typename std::vector<T>::const_iterator end() const
{ {
return storage.begin() + offset + size_; return storage.begin() + offset + size_;
} }
private: private:
std::vector<T>& storage; std::vector<T>& storage;
size_t offset; size_t offset;
size_t size_; size_t size_;
}; };
class Parser class Parser
{ {
public: public:
static ParseResult parse( static ParseResult parse(
const char* buffer, std::size_t bufferSize, AstNameTable& names, Allocator& allocator, ParseOptions options = ParseOptions()); const char* buffer, std::size_t bufferSize, AstNameTable& names, Allocator& allocator, ParseOptions options = ParseOptions());
private: private:
struct Name; struct Name;
struct Binding; struct Binding;
Parser(const char* buffer, std::size_t bufferSize, AstNameTable& names, Allocator& allocator, const ParseOptions& options); Parser(const char* buffer, std::size_t bufferSize, AstNameTable& names, Allocator& allocator, const ParseOptions& options);
bool blockFollow(const Lexeme& l); bool blockFollow(const Lexeme& l);
AstStatBlock* parseChunk(); AstStatBlock* parseChunk();
// chunk ::= {stat [`;']} [laststat [`;']] // chunk ::= {stat [`;']} [laststat [`;']]
// block ::= chunk // block ::= chunk
AstStatBlock* parseBlock(); AstStatBlock* parseBlock();
AstStatBlock* parseBlockNoScope(); AstStatBlock* parseBlockNoScope();
// stat ::= // stat ::=
// varlist `=' explist | // varlist `=' explist |
// functioncall | // functioncall |
// do block end | // do block end |
// while exp do block end | // while exp do block end |
// repeat block until exp | // repeat block until exp |
// if exp then block {elseif exp then block} [else block] end | // if exp then block {elseif exp then block} [else block] end |
// for Name `=' exp `,' exp [`,' exp] do block end | // for Name `=' exp `,' exp [`,' exp] do block end |
// for namelist in explist do block end | // for namelist in explist do block end |
// function funcname funcbody | // function funcname funcbody |
// local function Name funcbody | // local function Name funcbody |
// local namelist [`=' explist] // local namelist [`=' explist]
// laststat ::= return [explist] | break // laststat ::= return [explist] | break
AstStat* parseStat(); AstStat* parseStat();
// if exp then block {elseif exp then block} [else block] end // if exp then block {elseif exp then block} [else block] end
AstStat* parseIf(); AstStat* parseIf();
// while exp do block end // while exp do block end
AstStat* parseWhile(); AstStat* parseWhile();
// repeat block until exp // repeat block until exp
AstStat* parseRepeat(); AstStat* parseRepeat();
// do block end // do block end
AstStat* parseDo(); AstStat* parseDo();
// break // break
AstStat* parseBreak(); AstStat* parseBreak();
// continue // continue
AstStat* parseContinue(const Location& start); AstStat* parseContinue(const Location& start);
// for Name `=' exp `,' exp [`,' exp] do block end | // for Name `=' exp `,' exp [`,' exp] do block end |
// for namelist in explist do block end | // for namelist in explist do block end |
AstStat* parseFor(); AstStat* parseFor();
// function funcname funcbody | // function funcname funcbody |
// funcname ::= Name {`.' Name} [`:' Name] // funcname ::= Name {`.' Name} [`:' Name]
AstStat* parseFunctionStat(); AstStat* parseFunctionStat();
// local function Name funcbody | // local function Name funcbody |
// local namelist [`=' explist] // local namelist [`=' explist]
AstStat* parseLocal(); AstStat* parseLocal();
// return [explist] // return [explist]
AstStat* parseReturn(); AstStat* parseReturn();
// type Name `=' typeannotation // type Name `=' typeannotation
AstStat* parseTypeAlias(const Location& start, bool exported); AstStat* parseTypeAlias(const Location& start, bool exported);
AstDeclaredClassProp parseDeclaredClassMethod(); AstDeclaredClassProp parseDeclaredClassMethod();
// `declare global' Name: typeannotation | // `declare global' Name: typeannotation |
// `declare function' Name`(' [parlist] `)' [`:` TypeAnnotation] // `declare function' Name`(' [parlist] `)' [`:` TypeAnnotation]
AstStat* parseDeclaration(const Location& start); AstStat* parseDeclaration(const Location& start);
// varlist `=' explist // varlist `=' explist
AstStat* parseAssignment(AstExpr* initial); AstStat* parseAssignment(AstExpr* initial);
// var [`+=' | `-=' | `*=' | `/=' | `%=' | `^=' | `..='] exp // var [`+=' | `-=' | `*=' | `/=' | `%=' | `^=' | `..='] exp
AstStat* parseCompoundAssignment(AstExpr* initial, AstExprBinary::Op op); AstStat* parseCompoundAssignment(AstExpr* initial, AstExprBinary::Op op);
// funcbody ::= `(' [parlist] `)' block end // funcbody ::= `(' [parlist] `)' block end
// parlist ::= namelist [`,' `...'] | `...' // parlist ::= namelist [`,' `...'] | `...'
std::pair<AstExprFunction*, AstLocal*> parseFunctionBody( std::pair<AstExprFunction*, AstLocal*> parseFunctionBody(
bool hasself, const Lexeme& matchFunction, const AstName& debugname, std::optional<Name> localName); bool hasself, const Lexeme& matchFunction, const AstName& debugname, std::optional<Name> localName);
// explist ::= {exp `,'} exp // explist ::= {exp `,'} exp
void parseExprList(TempVector<AstExpr*>& result); void parseExprList(TempVector<AstExpr*>& result);
// binding ::= Name [`:` TypeAnnotation] // binding ::= Name [`:` TypeAnnotation]
Binding parseBinding(); Binding parseBinding();
// bindinglist ::= (binding | `...') {`,' bindinglist} // bindinglist ::= (binding | `...') {`,' bindinglist}
// Returns the location of the vararg ..., or std::nullopt if the function is not vararg. // Returns the location of the vararg ..., or std::nullopt if the function is not vararg.
std::pair<std::optional<Location>, AstTypePack*> parseBindingList(TempVector<Binding>& result, bool allowDot3 = false); std::pair<std::optional<Location>, AstTypePack*> parseBindingList(TempVector<Binding>& result, bool allowDot3 = false);
AstType* parseOptionalTypeAnnotation(); AstType* parseOptionalTypeAnnotation();
// TypeList ::= TypeAnnotation [`,' TypeList] // TypeList ::= TypeAnnotation [`,' TypeList]
// ReturnType ::= TypeAnnotation | `(' TypeList `)' // ReturnType ::= TypeAnnotation | `(' TypeList `)'
// TableProp ::= Name `:' TypeAnnotation // TableProp ::= Name `:' TypeAnnotation
// TableIndexer ::= `[' TypeAnnotation `]' `:' TypeAnnotation // TableIndexer ::= `[' TypeAnnotation `]' `:' TypeAnnotation
// PropList ::= (TableProp | TableIndexer) [`,' PropList] // PropList ::= (TableProp | TableIndexer) [`,' PropList]
// TypeAnnotation // TypeAnnotation
// ::= Name // ::= Name
// | `nil` // | `nil`
// | `{' [PropList] `}' // | `{' [PropList] `}'
// | `(' [TypeList] `)' `->` ReturnType // | `(' [TypeList] `)' `->` ReturnType
// Returns the variadic annotation, if it exists. // Returns the variadic annotation, if it exists.
AstTypePack* parseTypeList(TempVector<AstType*>& result, TempVector<std::optional<AstArgumentName>>& resultNames); AstTypePack* parseTypeList(TempVector<AstType*>& result, TempVector<std::optional<AstArgumentName>>& resultNames);
std::optional<AstTypeList> parseOptionalReturnTypeAnnotation(); std::optional<AstTypeList> parseOptionalReturnTypeAnnotation();
std::pair<Location, AstTypeList> parseReturnTypeAnnotation(); std::pair<Location, AstTypeList> parseReturnTypeAnnotation();
AstTableIndexer* parseTableIndexerAnnotation(); AstTableIndexer* parseTableIndexerAnnotation();
AstTypeOrPack parseFunctionTypeAnnotation(bool allowPack); AstTypeOrPack parseFunctionTypeAnnotation(bool allowPack);
AstType* parseFunctionTypeAnnotationTail(const Lexeme& begin, AstArray<AstGenericType> generics, AstArray<AstGenericTypePack> genericPacks, AstType* parseFunctionTypeAnnotationTail(const Lexeme& begin, AstArray<AstGenericType> generics, AstArray<AstGenericTypePack> genericPacks,
AstArray<AstType*>& params, AstArray<std::optional<AstArgumentName>>& paramNames, AstTypePack* varargAnnotation); AstArray<AstType*>& params, AstArray<std::optional<AstArgumentName>>& paramNames, AstTypePack* varargAnnotation);
AstType* parseTableTypeAnnotation(); AstType* parseTableTypeAnnotation();
AstTypeOrPack parseSimpleTypeAnnotation(bool allowPack); AstTypeOrPack parseSimpleTypeAnnotation(bool allowPack);
AstTypeOrPack parseTypeOrPackAnnotation(); AstTypeOrPack parseTypeOrPackAnnotation();
AstType* parseTypeAnnotation(TempVector<AstType*>& parts, const Location& begin); AstType* parseTypeAnnotation(TempVector<AstType*>& parts, const Location& begin);
AstType* parseTypeAnnotation(); AstType* parseTypeAnnotation();
AstTypePack* parseTypePackAnnotation(); AstTypePack* parseTypePackAnnotation();
AstTypePack* parseVariadicArgumentAnnotation(); AstTypePack* parseVariadicArgumentAnnotation();
static std::optional<AstExprUnary::Op> parseUnaryOp(const Lexeme& l); static std::optional<AstExprUnary::Op> parseUnaryOp(const Lexeme& l);
static std::optional<AstExprBinary::Op> parseBinaryOp(const Lexeme& l); static std::optional<AstExprBinary::Op> parseBinaryOp(const Lexeme& l);
static std::optional<AstExprBinary::Op> parseCompoundOp(const Lexeme& l); static std::optional<AstExprBinary::Op> parseCompoundOp(const Lexeme& l);
struct BinaryOpPriority struct BinaryOpPriority
{ {
unsigned char left, right; unsigned char left, right;
}; };
std::optional<AstExprUnary::Op> checkUnaryConfusables(); std::optional<AstExprUnary::Op> checkUnaryConfusables();
std::optional<AstExprBinary::Op> checkBinaryConfusables(const BinaryOpPriority binaryPriority[], unsigned int limit); std::optional<AstExprBinary::Op> checkBinaryConfusables(const BinaryOpPriority binaryPriority[], unsigned int limit);
// subexpr -> (asexp | unop subexpr) { binop subexpr } // subexpr -> (asexp | unop subexpr) { binop subexpr }
// where `binop' is any binary operator with a priority higher than `limit' // where `binop' is any binary operator with a priority higher than `limit'
AstExpr* parseExpr(unsigned int limit = 0); AstExpr* parseExpr(unsigned int limit = 0);
// NAME // NAME
AstExpr* parseNameExpr(const char* context = nullptr); AstExpr* parseNameExpr(const char* context = nullptr);
// prefixexp -> NAME | '(' expr ')' // prefixexp -> NAME | '(' expr ')'
AstExpr* parsePrefixExpr(); AstExpr* parsePrefixExpr();
// primaryexp -> prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } // primaryexp -> prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs }
AstExpr* parsePrimaryExpr(bool asStatement); AstExpr* parsePrimaryExpr(bool asStatement);
// asexp -> simpleexp [`::' typeAnnotation] // asexp -> simpleexp [`::' typeAnnotation]
AstExpr* parseAssertionExpr(); AstExpr* parseAssertionExpr();
// simpleexp -> NUMBER | STRING | NIL | true | false | ... | constructor | FUNCTION body | primaryexp // simpleexp -> NUMBER | STRING | NIL | true | false | ... | constructor | FUNCTION body | primaryexp
AstExpr* parseSimpleExpr(); AstExpr* parseSimpleExpr();
// args ::= `(' [explist] `)' | tableconstructor | String // args ::= `(' [explist] `)' | tableconstructor | String
AstExpr* parseFunctionArgs(AstExpr* func, bool self, const Location& selfLocation); AstExpr* parseFunctionArgs(AstExpr* func, bool self, const Location& selfLocation);
// tableconstructor ::= `{' [fieldlist] `}' // tableconstructor ::= `{' [fieldlist] `}'
// fieldlist ::= field {fieldsep field} [fieldsep] // fieldlist ::= field {fieldsep field} [fieldsep]
// field ::= `[' exp `]' `=' exp | Name `=' exp | exp // field ::= `[' exp `]' `=' exp | Name `=' exp | exp
// fieldsep ::= `,' | `;' // fieldsep ::= `,' | `;'
AstExpr* parseTableConstructor(); AstExpr* parseTableConstructor();
// TODO: Add grammar rules here? // TODO: Add grammar rules here?
AstExpr* parseIfElseExpr(); AstExpr* parseIfElseExpr();
// stringinterp ::= <INTERP_BEGIN> exp {<INTERP_MID> exp} <INTERP_END> // stringinterp ::= <INTERP_BEGIN> exp {<INTERP_MID> exp} <INTERP_END>
AstExpr* parseInterpString(); AstExpr* parseInterpString();
// Name // Name
std::optional<Name> parseNameOpt(const char* context = nullptr); std::optional<Name> parseNameOpt(const char* context = nullptr);
Name parseName(const char* context = nullptr); Name parseName(const char* context = nullptr);
Name parseIndexName(const char* context, const Position& previous); Name parseIndexName(const char* context, const Position& previous);
// `<' namelist `>' // `<' namelist `>'
std::pair<AstArray<AstGenericType>, AstArray<AstGenericTypePack>> parseGenericTypeList(bool withDefaultValues); std::pair<AstArray<AstGenericType>, AstArray<AstGenericTypePack>> parseGenericTypeList(bool withDefaultValues);
// `<' typeAnnotation[, ...] `>' // `<' typeAnnotation[, ...] `>'
AstArray<AstTypeOrPack> parseTypeParams(); AstArray<AstTypeOrPack> parseTypeParams();
std::optional<AstArray<char>> parseCharArray(); std::optional<AstArray<char>> parseCharArray();
AstExpr* parseString(); AstExpr* parseString();
AstLocal* pushLocal(const Binding& binding); AstLocal* pushLocal(const Binding& binding);
unsigned int saveLocals(); unsigned int saveLocals();
void restoreLocals(unsigned int offset); void restoreLocals(unsigned int offset);
// check that parser is at lexeme/symbol, move to next lexeme/symbol on success, report failure and continue on failure // check that parser is at lexeme/symbol, move to next lexeme/symbol on success, report failure and continue on failure
bool expectAndConsume(char value, const char* context = nullptr); bool expectAndConsume(char value, const char* context = nullptr);
bool expectAndConsume(Lexeme::Type type, const char* context = nullptr); bool expectAndConsume(Lexeme::Type type, const char* context = nullptr);
void expectAndConsumeFail(Lexeme::Type type, const char* context); void expectAndConsumeFail(Lexeme::Type type, const char* context);
bool expectMatchAndConsume(char value, const Lexeme& begin, bool searchForMissing = false); bool expectMatchAndConsume(char value, const Lexeme& begin, bool searchForMissing = false);
void expectMatchAndConsumeFail(Lexeme::Type type, const Lexeme& begin, const char* extra = nullptr); void expectMatchAndConsumeFail(Lexeme::Type type, const Lexeme& begin, const char* extra = nullptr);
bool expectMatchEndAndConsume(Lexeme::Type type, const Lexeme& begin); bool expectMatchEndAndConsume(Lexeme::Type type, const Lexeme& begin);
void expectMatchEndAndConsumeFail(Lexeme::Type type, const Lexeme& begin); void expectMatchEndAndConsumeFail(Lexeme::Type type, const Lexeme& begin);
template<typename T> template<typename T>
AstArray<T> copy(const T* data, std::size_t size); AstArray<T> copy(const T* data, std::size_t size);
template<typename T> template<typename T>
AstArray<T> copy(const TempVector<T>& data); AstArray<T> copy(const TempVector<T>& data);
template<typename T> template<typename T>
AstArray<T> copy(std::initializer_list<T> data); AstArray<T> copy(std::initializer_list<T> data);
AstArray<char> copy(const std::string& data); AstArray<char> copy(const std::string& data);
void incrementRecursionCounter(const char* context); void incrementRecursionCounter(const char* context);
void report(const Location& location, const char* format, va_list args); void report(const Location& location, const char* format, va_list args);
void report(const Location& location, const char* format, ...) LUAU_PRINTF_ATTR(3, 4); void report(const Location& location, const char* format, ...) LUAU_PRINTF_ATTR(3, 4);
void reportNameError(const char* context); void reportNameError(const char* context);
AstStatError* reportStatError(const Location& location, const AstArray<AstExpr*>& expressions, const AstArray<AstStat*>& statements, AstStatError* reportStatError(const Location& location, const AstArray<AstExpr*>& expressions, const AstArray<AstStat*>& statements,
const char* format, ...) LUAU_PRINTF_ATTR(5, 6); const char* format, ...) LUAU_PRINTF_ATTR(5, 6);
AstExprError* reportExprError(const Location& location, const AstArray<AstExpr*>& expressions, const char* format, ...) LUAU_PRINTF_ATTR(4, 5); AstExprError* reportExprError(const Location& location, const AstArray<AstExpr*>& expressions, const char* format, ...) LUAU_PRINTF_ATTR(4, 5);
AstTypeError* reportTypeAnnotationError(const Location& location, const AstArray<AstType*>& types, bool isMissing, const char* format, ...) AstTypeError* reportTypeAnnotationError(const Location& location, const AstArray<AstType*>& types, bool isMissing, const char* format, ...)
LUAU_PRINTF_ATTR(5, 6); LUAU_PRINTF_ATTR(5, 6);
void nextLexeme(); void nextLexeme();
struct Function struct Function
{ {
bool vararg; bool vararg;
unsigned int loopDepth; unsigned int loopDepth;
Function() Function()
: vararg(false) : vararg(false)
, loopDepth(0) , loopDepth(0)
{ {
} }
}; };
struct Local struct Local
{ {
AstLocal* local; AstLocal* local;
unsigned int offset; unsigned int offset;
Local() Local()
: local(nullptr) : local(nullptr)
, offset(0) , offset(0)
{ {
} }
}; };
struct Name struct Name
{ {
AstName name; AstName name;
Location location; Location location;
Name(const AstName& name, const Location& location) Name(const AstName& name, const Location& location)
: name(name) : name(name)
, location(location) , location(location)
{ {
} }
}; };
struct Binding struct Binding
{ {
Name name; Name name;
AstType* annotation; AstType* annotation;
explicit Binding(const Name& name, AstType* annotation = nullptr) explicit Binding(const Name& name, AstType* annotation = nullptr)
: name(name) : name(name)
, annotation(annotation) , annotation(annotation)
{ {
} }
}; };
ParseOptions options; ParseOptions options;
Lexer lexer; Lexer lexer;
Allocator& allocator; Allocator& allocator;
std::vector<Comment> commentLocations; std::vector<Comment> commentLocations;
std::vector<HotComment> hotcomments; std::vector<HotComment> hotcomments;
bool hotcommentHeader = true; bool hotcommentHeader = true;
unsigned int recursionCounter; unsigned int recursionCounter;
AstName nameSelf; AstName nameSelf;
AstName nameNumber; AstName nameNumber;
AstName nameError; AstName nameError;
AstName nameNil; AstName nameNil;
Lexeme endMismatchSuspect; Lexeme endMismatchSuspect;
std::vector<Function> functionStack; std::vector<Function> functionStack;
DenseHashMap<AstName, AstLocal*> localMap; DenseHashMap<AstName, AstLocal*> localMap;
std::vector<AstLocal*> localStack; std::vector<AstLocal*> localStack;
std::vector<ParseError> parseErrors; std::vector<ParseError> parseErrors;
std::vector<unsigned int> matchRecoveryStopOnToken; std::vector<unsigned int> matchRecoveryStopOnToken;
std::vector<AstStat*> scratchStat; std::vector<AstStat*> scratchStat;
std::vector<AstExpr*> scratchExpr; std::vector<AstExpr*> scratchExpr;
std::vector<AstExpr*> scratchExprAux; std::vector<AstExpr*> scratchExprAux;
std::vector<AstName> scratchName; std::vector<AstName> scratchName;
std::vector<AstName> scratchPackName; std::vector<AstName> scratchPackName;
std::vector<Binding> scratchBinding; std::vector<Binding> scratchBinding;
std::vector<AstLocal*> scratchLocal; std::vector<AstLocal*> scratchLocal;
std::vector<AstTableProp> scratchTableTypeProps; std::vector<AstTableProp> scratchTableTypeProps;
std::vector<AstType*> scratchAnnotation; std::vector<AstType*> scratchAnnotation;
std::vector<AstTypeOrPack> scratchTypeOrPackAnnotation; std::vector<AstTypeOrPack> scratchTypeOrPackAnnotation;
std::vector<AstDeclaredClassProp> scratchDeclaredClassProps; std::vector<AstDeclaredClassProp> scratchDeclaredClassProps;
std::vector<AstExprTable::Item> scratchItem; std::vector<AstExprTable::Item> scratchItem;
std::vector<AstArgumentName> scratchArgName; std::vector<AstArgumentName> scratchArgName;
std::vector<AstGenericType> scratchGenericTypes; std::vector<AstGenericType> scratchGenericTypes;
std::vector<AstGenericTypePack> scratchGenericTypePacks; std::vector<AstGenericTypePack> scratchGenericTypePacks;
std::vector<std::optional<AstArgumentName>> scratchOptArgName; std::vector<std::optional<AstArgumentName>> scratchOptArgName;
std::string scratchData; std::string scratchData;
}; };
} // namespace Luau } // namespace Luau

File diff suppressed because it is too large Load diff

View file

@ -1488,18 +1488,19 @@ struct Compiler
for (AstArray<char> const& string : expr->strings) for (AstArray<char> const& string : expr->strings)
{ {
std::string stringEscaped(string.data); if (memchr(string.data, '%', string.size))
for (size_t characterIndex = 0; characterIndex < stringEscaped.size(); ++characterIndex)
{ {
if (stringEscaped[characterIndex] == '%') for (size_t characterIndex = 0; characterIndex < string.size; ++characterIndex)
{ {
stringEscaped.insert(characterIndex, 1, '%'); char character = string.data[characterIndex];
characterIndex++; formatString.push_back(character);
if (character == '%')
formatString.push_back('%');
} }
} }
else
formatString += stringEscaped; formatString += std::string(string.data, string.size);
stringsLeft--; stringsLeft--;