blob: 86aec71636945215fdd008e2c45ad5281b1b97de [file] [log] [blame]
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_ASMJS_ASM_PARSER_H_
#define V8_ASMJS_ASM_PARSER_H_
#include <list>
#include <string>
#include <vector>
#include "src/asmjs/asm-scanner.h"
#include "src/asmjs/asm-typer.h"
#include "src/asmjs/asm-types.h"
#include "src/wasm/signature-map.h"
#include "src/wasm/wasm-module-builder.h"
#include "src/zone/zone-containers.h"
namespace v8 {
namespace internal {
namespace wasm {
// A custom parser + validator + wasm converter for asm.js:
// http://asmjs.org/spec/latest/
// This parser intentionally avoids the portion of JavaScript parsing
// that are not required to determine if code is valid asm.js code.
// * It is mostly one pass.
// * It bails out on unexpected input.
// * It assumes strict ordering insofar as permitted by asm.js validation rules.
// * It relies on a custom scanner that provides de-duped identifiers in two
// scopes (local + module wide).
class AsmJsParser {
public:
explicit AsmJsParser(Isolate* isolate, Zone* zone, Handle<Script> script,
int start, int end);
bool Run();
const char* failure_message() const { return failure_message_.c_str(); }
int failure_location() const { return failure_location_; }
WasmModuleBuilder* module_builder() { return module_builder_; }
const AsmTyper::StdlibSet* stdlib_uses() const { return &stdlib_uses_; }
private:
// clang-format off
enum class VarKind {
kUnused,
kLocal,
kGlobal,
kSpecial,
kFunction,
kTable,
kImportedFunction,
#define V(_unused0, Name, _unused1, _unused2) kMath##Name,
STDLIB_MATH_FUNCTION_LIST(V)
#undef V
#define V(Name) kMath##Name,
STDLIB_MATH_VALUE_LIST(V)
#undef V
};
// clang-format on
struct FunctionImportInfo {
std::string name;
SignatureMap cache;
std::vector<uint32_t> cache_index;
};
struct VarInfo {
AsmType* type;
WasmFunctionBuilder* function_builder;
FunctionImportInfo* import;
int32_t mask;
uint32_t index;
VarKind kind;
bool mutable_variable;
bool function_defined;
VarInfo();
void DeclareGlobalImport(AsmType* type, uint32_t index);
void DeclareStdlibFunc(VarKind kind, AsmType* type);
};
struct GlobalImport {
std::string import_name;
uint32_t import_index;
uint32_t global_index;
bool needs_init;
};
enum class BlockKind { kRegular, kLoop, kOther };
struct BlockInfo {
BlockKind kind;
AsmJsScanner::token_t label;
};
Zone* zone_;
AsmJsScanner scanner_;
WasmModuleBuilder* module_builder_;
WasmFunctionBuilder* current_function_builder_;
AsmType* return_type_;
std::uintptr_t stack_limit_;
AsmTyper::StdlibSet stdlib_uses_;
std::list<FunctionImportInfo> function_import_info_;
ZoneVector<VarInfo> global_var_info_;
ZoneVector<VarInfo> local_var_info_;
int function_temp_locals_offset_;
int function_temp_locals_used_;
// Error Handling related
bool failed_;
std::string failure_message_;
int failure_location_;
// Module Related.
AsmJsScanner::token_t stdlib_name_;
AsmJsScanner::token_t foreign_name_;
AsmJsScanner::token_t heap_name_;
static const AsmJsScanner::token_t kTokenNone = 0;
// Track if parsing a heap assignment.
bool inside_heap_assignment_;
AsmType* heap_access_type_;
ZoneVector<BlockInfo> block_stack_;
// Types used for stdlib function and their set up.
AsmType* stdlib_dq2d_;
AsmType* stdlib_dqdq2d_;
AsmType* stdlib_fq2f_;
AsmType* stdlib_i2s_;
AsmType* stdlib_ii2s_;
AsmType* stdlib_minmax_;
AsmType* stdlib_abs_;
AsmType* stdlib_ceil_like_;
AsmType* stdlib_fround_;
// When making calls, the return type is needed to lookup signatures.
// For +callsite(..) or fround(callsite(..)) use this value to pass
// along the coercion.
AsmType* call_coercion_;
// Used to track the last label we've seen so it can be matched to later
// statements it's attached to.
AsmJsScanner::token_t pending_label_;
// Global imports.
// NOTE: Holds the strings referenced in wasm-module-builder for imports.
ZoneLinkedList<GlobalImport> global_imports_;
Zone* zone() { return zone_; }
inline bool Peek(AsmJsScanner::token_t token) {
return scanner_.Token() == token;
}
inline bool Check(AsmJsScanner::token_t token) {
if (scanner_.Token() == token) {
scanner_.Next();
return true;
} else {
return false;
}
}
inline bool CheckForZero() {
if (scanner_.IsUnsigned() && scanner_.AsUnsigned() == 0) {
scanner_.Next();
return true;
} else {
return false;
}
}
inline bool CheckForDouble(double* value) {
if (scanner_.IsDouble()) {
*value = scanner_.AsDouble();
scanner_.Next();
return true;
} else {
return false;
}
}
inline bool CheckForUnsigned(uint64_t* value) {
if (scanner_.IsUnsigned()) {
*value = scanner_.AsUnsigned();
scanner_.Next();
return true;
} else {
return false;
}
}
inline bool CheckForUnsignedBelow(uint64_t limit, uint64_t* value) {
if (scanner_.IsUnsigned() && scanner_.AsUnsigned() < limit) {
*value = scanner_.AsUnsigned();
scanner_.Next();
return true;
} else {
return false;
}
}
inline AsmJsScanner::token_t Consume() {
AsmJsScanner::token_t ret = scanner_.Token();
scanner_.Next();
return ret;
}
void SkipSemicolon();
VarInfo* GetVarInfo(AsmJsScanner::token_t token);
uint32_t VarIndex(VarInfo* info);
void DeclareGlobal(VarInfo* info, bool mutable_variable, AsmType* type,
ValueType vtype,
const WasmInitExpr& init = WasmInitExpr());
int32_t TempVariable(int i);
void AddGlobalImport(std::string name, AsmType* type, ValueType vtype,
bool mutable_variable, VarInfo* info);
// Use to set up block stack layers (including synthetic ones for if-else).
// Begin/Loop/End below are implemented with these plus code generation.
void BareBegin(BlockKind kind = BlockKind::kOther,
AsmJsScanner::token_t label = 0);
void BareEnd();
int FindContinueLabelDepth(AsmJsScanner::token_t label);
int FindBreakLabelDepth(AsmJsScanner::token_t label);
// Use to set up actual wasm blocks/loops.
void Begin(AsmJsScanner::token_t label = 0);
void Loop(AsmJsScanner::token_t label = 0);
void End();
void InitializeStdlibTypes();
FunctionSig* ConvertSignature(AsmType* return_type,
const std::vector<AsmType*>& params);
// 6.1 ValidateModule
void ValidateModule();
void ValidateModuleParameters();
void ValidateModuleVars();
void ValidateModuleVar(bool mutable_variable);
bool ValidateModuleVarImport(VarInfo* info, bool mutable_variable);
void ValidateModuleVarStdlib(VarInfo* info);
void ValidateModuleVarNewStdlib(VarInfo* info);
void ValidateModuleVarFloat(VarInfo* info, bool mutable_variable);
void ValidateExport(); // 6.2 ValidateExport
void ValidateFunctionTable(); // 6.3 ValidateFunctionTable
void ValidateFunction(); // 6.4 ValidateFunction
void ValidateFunctionParams(std::vector<AsmType*>* params);
void ValidateFunctionLocals(size_t param_count,
std::vector<ValueType>* locals);
void ValidateStatement(); // ValidateStatement
void Block(); // 6.5.1 Block
void ExpressionStatement(); // 6.5.2 ExpressionStatement
void EmptyStatement(); // 6.5.3 EmptyStatement
void IfStatement(); // 6.5.4 IfStatement
void ReturnStatement(); // 6.5.5 ReturnStatement
bool IterationStatement(); // 6.5.6 IterationStatement
void WhileStatement(); // 6.5.6 IterationStatement - while
void DoStatement(); // 6.5.6 IterationStatement - do
void ForStatement(); // 6.5.6 IterationStatement - for
void BreakStatement(); // 6.5.7 BreakStatement
void ContinueStatement(); // 6.5.8 ContinueStatement
void LabelledStatement(); // 6.5.9 LabelledStatement
void SwitchStatement(); // 6.5.10 SwitchStatement
void ValidateCase(); // 6.6. ValidateCase
void ValidateDefault(); // 6.7 ValidateDefault
AsmType* ValidateExpression(); // 6.8 ValidateExpression
AsmType* Expression(AsmType* expect); // 6.8.1 Expression
AsmType* NumericLiteral(); // 6.8.2 NumericLiteral
AsmType* Identifier(); // 6.8.3 Identifier
AsmType* CallExpression(); // 6.8.4 CallExpression
AsmType* MemberExpression(); // 6.8.5 MemberExpression
AsmType* AssignmentExpression(); // 6.8.6 AssignmentExpression
AsmType* UnaryExpression(); // 6.8.7 UnaryExpression
AsmType* MultiplicativeExpression(); // 6.8.8 MultaplicativeExpression
AsmType* AdditiveExpression(); // 6.8.9 AdditiveExpression
AsmType* ShiftExpression(); // 6.8.10 ShiftExpression
AsmType* RelationalExpression(); // 6.8.11 RelationalExpression
AsmType* EqualityExpression(); // 6.8.12 EqualityExpression
AsmType* BitwiseANDExpression(); // 6.8.13 BitwiseANDExpression
AsmType* BitwiseXORExpression(); // 6.8.14 BitwiseXORExpression
AsmType* BitwiseORExpression(); // 6.8.15 BitwiseORExpression
AsmType* ConditionalExpression(); // 6.8.16 ConditionalExpression
AsmType* ParenthesizedExpression(); // 6.8.17 ParenthesiedExpression
AsmType* ValidateCall(); // 6.9 ValidateCall
bool PeekCall(); // 6.9 ValidateCall - helper
void ValidateHeapAccess(); // 6.10 ValidateHeapAccess
void ValidateFloatCoercion(); // 6.11 ValidateFloatCoercion
void GatherCases(std::vector<int32_t>* cases);
};
} // namespace wasm
} // namespace internal
} // namespace v8
#endif