Index: src/asmjs/asm-parser.cc |
diff --git a/src/asmjs/asm-parser.cc b/src/asmjs/asm-parser.cc |
index 59745c191de58d175f74820421d266403568142e..d3c6f1a18a36ac96d4e0ebd36eb3c79fa3b1872a 100644 |
--- a/src/asmjs/asm-parser.cc |
+++ b/src/asmjs/asm-parser.cc |
@@ -71,12 +71,11 @@ namespace wasm { |
#define RECURSE_OR_RETURN(ret, call) \ |
do { \ |
- DCHECK(GetCurrentStackPosition() >= stack_limit_); \ |
DCHECK(!failed_); \ |
- call; \ |
if (GetCurrentStackPosition() < stack_limit_) { \ |
FAIL_AND_RETURN(ret, "Stack overflow while parsing asm.js module."); \ |
} \ |
+ call; \ |
if (failed_) return ret; \ |
} while (false); |
@@ -238,21 +237,25 @@ uint32_t AsmJsParser::VarIndex(VarInfo* info) { |
void AsmJsParser::AddGlobalImport(std::string name, AsmType* type, |
ValueType vtype, bool mutable_variable, |
VarInfo* info) { |
+ // TODO(bradnelson): Refactor memory management here. |
+ // AsmModuleBuilder should really own import names. |
+ char* name_data = zone()->NewArray<char>(name.size()); |
+ memcpy(name_data, name.data(), name.size()); |
if (mutable_variable) { |
// Allocate a separate variable for the import. |
DeclareGlobal(info, true, type, vtype); |
// Record the need to initialize the global from the import. |
- global_imports_.push_back({name, 0, info->index, true}); |
+ global_imports_.push_back({name_data, name.size(), 0, info->index, true}); |
} else { |
// Just use the import directly. |
- global_imports_.push_back({name, 0, info->index, false}); |
+ global_imports_.push_back({name_data, name.size(), 0, info->index, false}); |
} |
GlobalImport& gi = global_imports_.back(); |
// TODO(bradnelson): Reuse parse buffer memory / make wasm-module-builder |
// managed the memory for the import name (currently have to keep our |
// own memory for it). |
gi.import_index = module_builder_->AddGlobalImport( |
- name.data(), static_cast<int>(name.size()), vtype); |
+ name_data, static_cast<int>(name.size()), vtype); |
if (!mutable_variable) { |
info->DeclareGlobalImport(type, gi.import_index); |
} |
@@ -362,6 +365,16 @@ void AsmJsParser::ValidateModule() { |
} |
RECURSE(ValidateExport()); |
+ // Check that all functions were eventually defined. |
+ for (auto info : global_var_info_) { |
+ if (info.kind != VarKind::kFunction) { |
+ continue; |
+ } |
+ if (!info.function_defined) { |
+ FAIL("Undefined function"); |
+ } |
+ } |
+ |
// Add start function to init things. |
WasmFunctionBuilder* start = module_builder_->AddFunction(); |
module_builder_->MarkStartFunction(start); |
@@ -447,8 +460,9 @@ void AsmJsParser::ValidateModuleVar(bool mutable_variable) { |
if (uvalue > 0x7fffffff) { |
FAIL("Numeric literal out of range"); |
} |
- DeclareGlobal(info, mutable_variable, AsmType::Int(), kWasmI32, |
- WasmInitExpr(static_cast<int32_t>(uvalue))); |
+ DeclareGlobal(info, mutable_variable, |
+ mutable_variable ? AsmType::Int() : AsmType::Signed(), |
+ kWasmI32, WasmInitExpr(static_cast<int32_t>(uvalue))); |
} else if (Check('-')) { |
if (CheckForDouble(&dvalue)) { |
DeclareGlobal(info, mutable_variable, AsmType::Double(), kWasmF64, |
@@ -457,8 +471,9 @@ void AsmJsParser::ValidateModuleVar(bool mutable_variable) { |
if (uvalue > 0x7fffffff) { |
FAIL("Numeric literal out of range"); |
} |
- DeclareGlobal(info, mutable_variable, AsmType::Int(), kWasmI32, |
- WasmInitExpr(-static_cast<int32_t>(uvalue))); |
+ DeclareGlobal(info, mutable_variable, |
+ mutable_variable ? AsmType::Int() : AsmType::Signed(), |
+ kWasmI32, WasmInitExpr(-static_cast<int32_t>(uvalue))); |
} else { |
FAIL("Expected numeric literal"); |
} |
@@ -470,16 +485,33 @@ void AsmJsParser::ValidateModuleVar(bool mutable_variable) { |
} else if (ValidateModuleVarImport(info, mutable_variable)) { |
// Handled inside. |
} else if (scanner_.IsGlobal()) { |
- RECURSE(ValidateModuleVarFloat(info, mutable_variable)); |
+ RECURSE(ValidateModuleVarFromGlobal(info, mutable_variable)); |
} else { |
FAIL("Bad variable declaration"); |
} |
} |
// 6.1 ValidateModule - global float declaration |
-void AsmJsParser::ValidateModuleVarFloat(VarInfo* info, bool mutable_variable) { |
- if (!GetVarInfo(Consume())->type->IsA(stdlib_fround_)) { |
- FAIL("Expected fround"); |
+void AsmJsParser::ValidateModuleVarFromGlobal(VarInfo* info, |
+ bool mutable_variable) { |
+ VarInfo* src_info = GetVarInfo(Consume()); |
+ if (!src_info->type->IsA(stdlib_fround_)) { |
+ if (src_info->mutable_variable) { |
+ FAIL("Can only use immutable variables in global definition"); |
+ } |
+ if (mutable_variable) { |
+ FAIL("Can only define immutable variables with other immutables"); |
+ } |
+ if (!src_info->type->IsA(AsmType::Int()) && |
+ !src_info->type->IsA(AsmType::Float()) && |
+ !src_info->type->IsA(AsmType::Double())) { |
+ FAIL("Expected int, float, double, or fround for global definition"); |
+ } |
+ info->kind = VarKind::kGlobal; |
+ info->type = src_info->type; |
+ info->index = src_info->index; |
+ info->mutable_variable = false; |
+ return; |
} |
EXPECT_TOKEN('('); |
bool negate = false; |
@@ -532,7 +564,11 @@ bool AsmJsParser::ValidateModuleVarImport(VarInfo* info, |
info->kind = VarKind::kImportedFunction; |
function_import_info_.resize(function_import_info_.size() + 1); |
info->import = &function_import_info_.back(); |
- info->import->name = import_name; |
+ // TODO(bradnelson): Refactor memory management here. |
+ // AsmModuleBuilder should really own import names. |
+ info->import->function_name = zone()->NewArray<char>(import_name.size()); |
+ memcpy(info->import->function_name, import_name.data(), import_name.size()); |
+ info->import->function_name_size = import_name.size(); |
return true; |
} |
return false; |
@@ -569,6 +605,7 @@ void AsmJsParser::ValidateModuleVarStdlib(VarInfo* info) { |
case TOK(name): \ |
DeclareGlobal(info, false, AsmType::Double(), kWasmF64, \ |
WasmInitExpr(M_##name)); \ |
+ stdlib_uses_.insert(AsmTyper::kMath##name); \ |
break; |
STDLIB_MATH_VALUE_LIST(V) |
#undef V |
@@ -585,9 +622,11 @@ void AsmJsParser::ValidateModuleVarStdlib(VarInfo* info) { |
} else if (Check(TOK(Infinity))) { |
DeclareGlobal(info, false, AsmType::Double(), kWasmF64, |
WasmInitExpr(std::numeric_limits<double>::infinity())); |
+ stdlib_uses_.insert(AsmTyper::kInfinity); |
} else if (Check(TOK(NaN))) { |
DeclareGlobal(info, false, AsmType::Double(), kWasmF64, |
WasmInitExpr(std::numeric_limits<double>::quiet_NaN())); |
+ stdlib_uses_.insert(AsmTyper::kNaN); |
} else { |
FAIL("Invalid member of stdlib"); |
} |
@@ -695,13 +734,18 @@ void AsmJsParser::ValidateFunction() { |
if (function_info->kind == VarKind::kUnused) { |
function_info->kind = VarKind::kFunction; |
function_info->function_builder = module_builder_->AddFunction(); |
+ // TODO(bradnelson): Cleanup memory management here. |
+ // WasmModuleBuilder should own these. |
+ char* function_name = zone()->NewArray<char>(function_name_raw.size()); |
+ memcpy(function_name, function_name_raw.data(), function_name_raw.size()); |
function_info->function_builder->SetName( |
- {function_name_raw.c_str(), |
- static_cast<int>(function_name_raw.size())}); |
+ {function_name, static_cast<int>(function_name_raw.size())}); |
function_info->index = function_info->function_builder->func_index(); |
function_info->function_defined = true; |
} else if (function_info->function_defined) { |
FAIL("Function redefined"); |
+ } else { |
+ function_info->function_defined = true; |
} |
current_function_builder_ = function_info->function_builder; |
return_type_ = nullptr; |
@@ -855,7 +899,7 @@ void AsmJsParser::ValidateFunctionLocals( |
info->type = AsmType::Double(); |
info->index = static_cast<uint32_t>(param_count + locals->size()); |
locals->push_back(kWasmF64); |
- byte code[] = {WASM_F64(dvalue)}; |
+ byte code[] = {WASM_F64(-dvalue)}; |
current_function_builder_->EmitCode(code, sizeof(code)); |
current_function_builder_->EmitSetLocal(info->index); |
} else if (CheckForUnsigned(&uvalue)) { |
@@ -2063,8 +2107,9 @@ AsmType* AsmJsParser::ValidateCall() { |
uint32_t index; |
if (cache_index >= function_info->import->cache_index.size()) { |
index = module_builder_->AddImport( |
- function_info->import->name.data(), |
- static_cast<uint32_t>(function_info->import->name.size()), sig); |
+ function_info->import->function_name, |
+ static_cast<uint32_t>(function_info->import->function_name_size), |
+ sig); |
function_info->import->cache_index.push_back(index); |
} else { |
index = function_info->import->cache_index[cache_index]; |