diff options
author | Michaël Zasso <targos@protonmail.com> | 2017-03-21 10:16:54 +0100 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2017-03-25 09:44:10 +0100 |
commit | c459d8ea5d402c702948c860d9497b2230ff7e8a (patch) | |
tree | 56c282fc4d40e5cb613b47cf7be3ea0526ed5b6f /deps/v8/src/asmjs | |
parent | e0bc5a7361b1d29c3ed034155fd779ce6f44fb13 (diff) | |
download | android-node-v8-c459d8ea5d402c702948c860d9497b2230ff7e8a.tar.gz android-node-v8-c459d8ea5d402c702948c860d9497b2230ff7e8a.tar.bz2 android-node-v8-c459d8ea5d402c702948c860d9497b2230ff7e8a.zip |
deps: update V8 to 5.7.492.69
PR-URL: https://github.com/nodejs/node/pull/11752
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com>
Diffstat (limited to 'deps/v8/src/asmjs')
-rw-r--r-- | deps/v8/src/asmjs/OWNERS | 1 | ||||
-rw-r--r-- | deps/v8/src/asmjs/asm-js.cc | 129 | ||||
-rw-r--r-- | deps/v8/src/asmjs/asm-js.h | 4 | ||||
-rw-r--r-- | deps/v8/src/asmjs/asm-typer.cc | 407 | ||||
-rw-r--r-- | deps/v8/src/asmjs/asm-typer.h | 80 | ||||
-rw-r--r-- | deps/v8/src/asmjs/asm-types.cc | 1 | ||||
-rw-r--r-- | deps/v8/src/asmjs/asm-wasm-builder.cc | 465 | ||||
-rw-r--r-- | deps/v8/src/asmjs/asm-wasm-builder.h | 14 |
8 files changed, 735 insertions, 366 deletions
diff --git a/deps/v8/src/asmjs/OWNERS b/deps/v8/src/asmjs/OWNERS index 78e688d86e..b994be3e17 100644 --- a/deps/v8/src/asmjs/OWNERS +++ b/deps/v8/src/asmjs/OWNERS @@ -4,6 +4,7 @@ set noparent ahaas@chromium.org bradnelson@chromium.org +clemensh@chromium.org jpp@chromium.org mtrofin@chromium.org rossberg@chromium.org diff --git a/deps/v8/src/asmjs/asm-js.cc b/deps/v8/src/asmjs/asm-js.cc index 13f936d0b5..b4026b0b19 100644 --- a/deps/v8/src/asmjs/asm-js.cc +++ b/deps/v8/src/asmjs/asm-js.cc @@ -9,6 +9,7 @@ #include "src/asmjs/asm-typer.h" #include "src/asmjs/asm-wasm-builder.h" #include "src/assert-scope.h" +#include "src/compilation-info.h" #include "src/execution.h" #include "src/factory.h" #include "src/handles.h" @@ -31,6 +32,15 @@ namespace v8 { namespace internal { namespace { +enum WasmDataEntries { + kWasmDataCompiledModule, + kWasmDataForeignGlobals, + kWasmDataUsesArray, + kWasmDataScript, + kWasmDataScriptPosition, + kWasmDataEntryCount, +}; + Handle<i::Object> StdlibMathMember(i::Isolate* isolate, Handle<JSReceiver> stdlib, Handle<Name> name) { @@ -151,29 +161,38 @@ bool IsStdlibMemberValid(i::Isolate* isolate, Handle<JSReceiver> stdlib, } // namespace -MaybeHandle<FixedArray> AsmJs::ConvertAsmToWasm(ParseInfo* info) { +MaybeHandle<FixedArray> AsmJs::CompileAsmViaWasm(CompilationInfo* info) { ErrorThrower thrower(info->isolate(), "Asm.js -> WebAssembly conversion"); - wasm::AsmTyper typer(info->isolate(), info->zone(), *(info->script()), - info->literal()); - if (!typer.Validate()) { + base::ElapsedTimer asm_wasm_timer; + asm_wasm_timer.Start(); + wasm::AsmWasmBuilder builder(info); + Handle<FixedArray> foreign_globals; + auto asm_wasm_result = builder.Run(&foreign_globals); + if (!asm_wasm_result.success) { DCHECK(!info->isolate()->has_pending_exception()); - PrintF("Validation of asm.js module failed: %s", typer.error_message()); + if (!FLAG_suppress_asm_messages) { + MessageHandler::ReportMessage(info->isolate(), + builder.typer()->message_location(), + builder.typer()->error_message()); + } return MaybeHandle<FixedArray>(); } - v8::internal::wasm::AsmWasmBuilder builder(info->isolate(), info->zone(), - info->literal(), &typer); - i::Handle<i::FixedArray> foreign_globals; - auto asm_wasm_result = builder.Run(&foreign_globals); + double asm_wasm_time = asm_wasm_timer.Elapsed().InMillisecondsF(); + wasm::ZoneBuffer* module = asm_wasm_result.module_bytes; wasm::ZoneBuffer* asm_offsets = asm_wasm_result.asm_offset_table; + Vector<const byte> asm_offsets_vec(asm_offsets->begin(), + static_cast<int>(asm_offsets->size())); - i::MaybeHandle<i::JSObject> compiled = wasm::CreateModuleObjectFromBytes( + base::ElapsedTimer compile_timer; + compile_timer.Start(); + MaybeHandle<JSObject> compiled = wasm::CreateModuleObjectFromBytes( info->isolate(), module->begin(), module->end(), &thrower, - internal::wasm::kAsmJsOrigin, info->script(), asm_offsets->begin(), - asm_offsets->end()); + internal::wasm::kAsmJsOrigin, info->script(), asm_offsets_vec); DCHECK(!compiled.is_null()); + double compile_time = compile_timer.Elapsed().InMillisecondsF(); - wasm::AsmTyper::StdlibSet uses = typer.StdlibUses(); + wasm::AsmTyper::StdlibSet uses = builder.typer()->StdlibUses(); Handle<FixedArray> uses_array = info->isolate()->factory()->NewFixedArray(static_cast<int>(uses.size())); int count = 0; @@ -181,16 +200,45 @@ MaybeHandle<FixedArray> AsmJs::ConvertAsmToWasm(ParseInfo* info) { uses_array->set(count++, Smi::FromInt(i)); } - Handle<FixedArray> result = info->isolate()->factory()->NewFixedArray(3); - result->set(0, *compiled.ToHandleChecked()); - result->set(1, *foreign_globals); - result->set(2, *uses_array); + Handle<FixedArray> result = + info->isolate()->factory()->NewFixedArray(kWasmDataEntryCount); + result->set(kWasmDataCompiledModule, *compiled.ToHandleChecked()); + result->set(kWasmDataForeignGlobals, *foreign_globals); + result->set(kWasmDataUsesArray, *uses_array); + result->set(kWasmDataScript, *info->script()); + result->set(kWasmDataScriptPosition, + Smi::FromInt(info->literal()->position())); + + MessageLocation location(info->script(), info->literal()->position(), + info->literal()->position()); + char text[100]; + int length; + if (FLAG_predictable) { + length = base::OS::SNPrintF(text, arraysize(text), "success"); + } else { + length = + base::OS::SNPrintF(text, arraysize(text), + "success, asm->wasm: %0.3f ms, compile: %0.3f ms", + asm_wasm_time, compile_time); + } + DCHECK_NE(-1, length); + USE(length); + Handle<String> stext(info->isolate()->factory()->InternalizeUtf8String(text)); + Handle<JSMessageObject> message = MessageHandler::MakeMessageObject( + info->isolate(), MessageTemplate::kAsmJsCompiled, &location, stext, + Handle<JSArray>::null()); + message->set_error_level(v8::Isolate::kMessageInfo); + if (!FLAG_suppress_asm_messages && FLAG_trace_asm_time) { + MessageHandler::ReportMessage(info->isolate(), &location, message); + } + return result; } bool AsmJs::IsStdlibValid(i::Isolate* isolate, Handle<FixedArray> wasm_data, Handle<JSReceiver> stdlib) { - i::Handle<i::FixedArray> uses(i::FixedArray::cast(wasm_data->get(2))); + i::Handle<i::FixedArray> uses( + i::FixedArray::cast(wasm_data->get(kWasmDataUsesArray))); for (int i = 0; i < uses->length(); ++i) { if (!IsStdlibMemberValid(isolate, stdlib, uses->GetValueChecked<i::Object>(isolate, i))) { @@ -204,14 +252,27 @@ MaybeHandle<Object> AsmJs::InstantiateAsmWasm(i::Isolate* isolate, Handle<FixedArray> wasm_data, Handle<JSArrayBuffer> memory, Handle<JSReceiver> foreign) { - i::Handle<i::JSObject> module(i::JSObject::cast(wasm_data->get(0))); + base::ElapsedTimer instantiate_timer; + instantiate_timer.Start(); + i::Handle<i::WasmModuleObject> module( + i::WasmModuleObject::cast(wasm_data->get(kWasmDataCompiledModule))); i::Handle<i::FixedArray> foreign_globals( - i::FixedArray::cast(wasm_data->get(1))); + i::FixedArray::cast(wasm_data->get(kWasmDataForeignGlobals))); ErrorThrower thrower(isolate, "Asm.js -> WebAssembly instantiation"); + // Create the ffi object for foreign functions {"": foreign}. + Handle<JSObject> ffi_object; + if (!foreign.is_null()) { + Handle<JSFunction> object_function = Handle<JSFunction>( + isolate->native_context()->object_function(), isolate); + ffi_object = isolate->factory()->NewJSObject(object_function); + JSObject::AddProperty(ffi_object, isolate->factory()->empty_string(), + foreign, NONE); + } + i::MaybeHandle<i::JSObject> maybe_module_object = - i::wasm::WasmModule::Instantiate(isolate, &thrower, module, foreign, + i::wasm::WasmModule::Instantiate(isolate, &thrower, module, ffi_object, memory); if (maybe_module_object.is_null()) { return MaybeHandle<Object>(); @@ -258,6 +319,32 @@ MaybeHandle<Object> AsmJs::InstantiateAsmWasm(i::Isolate* isolate, !single_function.ToHandleChecked()->IsUndefined(isolate)) { return single_function; } + + i::Handle<i::Script> script(i::Script::cast(wasm_data->get(kWasmDataScript))); + int32_t position = 0; + if (!wasm_data->get(kWasmDataScriptPosition)->ToInt32(&position)) { + UNREACHABLE(); + } + MessageLocation location(script, position, position); + char text[50]; + int length; + if (FLAG_predictable) { + length = base::OS::SNPrintF(text, arraysize(text), "success"); + } else { + length = base::OS::SNPrintF(text, arraysize(text), "success, %0.3f ms", + instantiate_timer.Elapsed().InMillisecondsF()); + } + DCHECK_NE(-1, length); + USE(length); + Handle<String> stext(isolate->factory()->InternalizeUtf8String(text)); + Handle<JSMessageObject> message = MessageHandler::MakeMessageObject( + isolate, MessageTemplate::kAsmJsInstantiated, &location, stext, + Handle<JSArray>::null()); + message->set_error_level(v8::Isolate::kMessageInfo); + if (!FLAG_suppress_asm_messages && FLAG_trace_asm_time) { + MessageHandler::ReportMessage(isolate, &location, message); + } + return module_object; } diff --git a/deps/v8/src/asmjs/asm-js.h b/deps/v8/src/asmjs/asm-js.h index a2c5cec280..a7795dc541 100644 --- a/deps/v8/src/asmjs/asm-js.h +++ b/deps/v8/src/asmjs/asm-js.h @@ -10,13 +10,13 @@ namespace v8 { namespace internal { +class CompilationInfo; class JSArrayBuffer; -class ParseInfo; // Interface to compile and instantiate for asmjs. class AsmJs { public: - static MaybeHandle<FixedArray> ConvertAsmToWasm(ParseInfo* info); + static MaybeHandle<FixedArray> CompileAsmViaWasm(CompilationInfo* info); static bool IsStdlibValid(Isolate* isolate, Handle<FixedArray> wasm_data, Handle<JSReceiver> stdlib); static MaybeHandle<Object> InstantiateAsmWasm(Isolate* isolate, diff --git a/deps/v8/src/asmjs/asm-typer.cc b/deps/v8/src/asmjs/asm-typer.cc index 55b5fc70d8..2389551872 100644 --- a/deps/v8/src/asmjs/asm-typer.cc +++ b/deps/v8/src/asmjs/asm-typer.cc @@ -9,6 +9,7 @@ #include <memory> #include <string> +#include "include/v8.h" #include "src/v8.h" #include "src/asmjs/asm-types.h" @@ -17,18 +18,33 @@ #include "src/base/bits.h" #include "src/codegen.h" #include "src/globals.h" +#include "src/messages.h" #include "src/utils.h" +#include "src/vector.h" + +#define FAIL_LOCATION_RAW(location, msg) \ + do { \ + Handle<String> message( \ + isolate_->factory()->InternalizeOneByteString(msg)); \ + error_message_ = MessageHandler::MakeMessageObject( \ + isolate_, MessageTemplate::kAsmJsInvalid, (location), message, \ + Handle<JSArray>::null()); \ + error_message_->set_error_level(v8::Isolate::kMessageWarning); \ + message_location_ = *(location); \ + return AsmType::None(); \ + } while (false) -#define FAIL(node, msg) \ - do { \ - int line = node->position() == kNoSourcePosition \ - ? -1 \ - : script_->GetLineNumber(node->position()); \ - base::OS::SNPrintF(error_message_, sizeof(error_message_), \ - "asm: line %d: %s\n", line + 1, msg); \ - return AsmType::None(); \ +#define FAIL_RAW(node, msg) \ + do { \ + MessageLocation location(script_, node->position(), node->position()); \ + FAIL_LOCATION_RAW(&location, msg); \ } while (false) +#define FAIL_LOCATION(location, msg) \ + FAIL_LOCATION_RAW(location, STATIC_CHAR_VECTOR(msg)) + +#define FAIL(node, msg) FAIL_RAW(node, STATIC_CHAR_VECTOR(msg)) + #define RECURSE(call) \ do { \ if (GetCurrentStackPosition() < stack_limit_) { \ @@ -91,6 +107,53 @@ Statement* AsmTyper::FlattenedStatements::Next() { } // ---------------------------------------------------------------------------- +// Implementation of AsmTyper::SourceLayoutTracker + +bool AsmTyper::SourceLayoutTracker::IsValid() const { + const Section* kAllSections[] = {&use_asm_, &globals_, &functions_, &tables_, + &exports_}; + for (size_t ii = 0; ii < arraysize(kAllSections); ++ii) { + const auto& curr_section = *kAllSections[ii]; + for (size_t jj = ii + 1; jj < arraysize(kAllSections); ++jj) { + if (curr_section.IsPrecededBy(*kAllSections[jj])) { + return false; + } + } + } + return true; +} + +void AsmTyper::SourceLayoutTracker::Section::AddNewElement( + const AstNode& node) { + const int node_pos = node.position(); + if (start_ == kNoSourcePosition) { + start_ = node_pos; + } else { + start_ = std::min(start_, node_pos); + } + if (end_ == kNoSourcePosition) { + end_ = node_pos; + } else { + end_ = std::max(end_, node_pos); + } +} + +bool AsmTyper::SourceLayoutTracker::Section::IsPrecededBy( + const Section& other) const { + if (start_ == kNoSourcePosition) { + DCHECK_EQ(end_, kNoSourcePosition); + return false; + } + if (other.start_ == kNoSourcePosition) { + DCHECK_EQ(other.end_, kNoSourcePosition); + return false; + } + DCHECK_LE(start_, end_); + DCHECK_LE(other.start_, other.end_); + return other.start_ <= end_; +} + +// ---------------------------------------------------------------------------- // Implementation of AsmTyper::VariableInfo AsmTyper::VariableInfo* AsmTyper::VariableInfo::ForSpecialSymbol( @@ -112,16 +175,16 @@ AsmTyper::VariableInfo* AsmTyper::VariableInfo::Clone(Zone* zone) const { return new_var_info; } -void AsmTyper::VariableInfo::FirstForwardUseIs(VariableProxy* var) { - DCHECK(first_forward_use_ == nullptr); +void AsmTyper::VariableInfo::SetFirstForwardUse( + const MessageLocation& source_location) { missing_definition_ = true; - first_forward_use_ = var; + source_location_ = source_location; } // ---------------------------------------------------------------------------- // Implementation of AsmTyper -AsmTyper::AsmTyper(Isolate* isolate, Zone* zone, Script* script, +AsmTyper::AsmTyper(Isolate* isolate, Zone* zone, Handle<Script> script, FunctionLiteral* root) : isolate_(isolate), zone_(zone), @@ -137,9 +200,9 @@ AsmTyper::AsmTyper(Isolate* isolate, Zone* zone, Script* script, local_scope_(ZoneHashMap::kDefaultHashMapCapacity, ZoneAllocationPolicy(zone)), stack_limit_(isolate->stack_guard()->real_climit()), - node_types_(zone_), fround_type_(AsmType::FroundType(zone_)), - ffi_type_(AsmType::FFIType(zone_)) { + ffi_type_(AsmType::FFIType(zone_)), + function_pointer_tables_(zone_) { InitializeStdlib(); } @@ -283,6 +346,9 @@ void AsmTyper::InitializeStdlib() { AsmTyper::VariableInfo* AsmTyper::ImportLookup(Property* import) { auto* obj = import->obj(); auto* key = import->key()->AsLiteral(); + if (key == nullptr) { + return nullptr; + } ObjectTypeMap* stdlib = &stdlib_types_; if (auto* obj_as_property = obj->AsProperty()) { @@ -345,7 +411,8 @@ AsmTyper::VariableInfo* AsmTyper::Lookup(Variable* variable) const { } void AsmTyper::AddForwardReference(VariableProxy* proxy, VariableInfo* info) { - info->FirstForwardUseIs(proxy); + MessageLocation location(script_, proxy->position(), proxy->position()); + info->SetFirstForwardUse(location); forward_definitions_.push_back(info); } @@ -390,22 +457,58 @@ bool AsmTyper::AddLocal(Variable* variable, VariableInfo* info) { void AsmTyper::SetTypeOf(AstNode* node, AsmType* type) { DCHECK_NE(type, AsmType::None()); - DCHECK(node_types_.find(node) == node_types_.end()); - node_types_.insert(std::make_pair(node, type)); + if (in_function_) { + DCHECK(function_node_types_.find(node) == function_node_types_.end()); + function_node_types_.insert(std::make_pair(node, type)); + } else { + DCHECK(module_node_types_.find(node) == module_node_types_.end()); + module_node_types_.insert(std::make_pair(node, type)); + } +} + +namespace { +bool IsLiteralDouble(Literal* literal) { + return literal->raw_value()->IsNumber() && + literal->raw_value()->ContainsDot(); +} + +bool IsLiteralInt(Literal* literal) { + return literal->raw_value()->IsNumber() && + !literal->raw_value()->ContainsDot(); +} + +bool IsLiteralMinus1(Literal* literal) { + return IsLiteralInt(literal) && literal->raw_value()->AsNumber() == -1.0; +} + +bool IsLiteral1Dot0(Literal* literal) { + return IsLiteralDouble(literal) && literal->raw_value()->AsNumber() == 1.0; } +bool IsLiteral0(Literal* literal) { + return IsLiteralInt(literal) && literal->raw_value()->AsNumber() == 0.0; +} +} // namespace + AsmType* AsmTyper::TypeOf(AstNode* node) const { - auto node_type_iter = node_types_.find(node); - if (node_type_iter != node_types_.end()) { + auto node_type_iter = function_node_types_.find(node); + if (node_type_iter != function_node_types_.end()) { + return node_type_iter->second; + } + node_type_iter = module_node_types_.find(node); + if (node_type_iter != module_node_types_.end()) { return node_type_iter->second; } // Sometimes literal nodes are not added to the node_type_ map simply because // their are not visited with ValidateExpression(). if (auto* literal = node->AsLiteral()) { - if (literal->raw_value()->ContainsDot()) { + if (IsLiteralDouble(literal)) { return AsmType::Double(); } + if (!IsLiteralInt(literal)) { + return AsmType::None(); + } uint32_t u; if (literal->value()->ToUint32(&u)) { if (u > LargestFixNum) { @@ -433,13 +536,39 @@ AsmTyper::StandardMember AsmTyper::VariableAsStandardMember(Variable* var) { return member; } +AsmType* AsmTyper::FailWithMessage(const char* text) { + FAIL_RAW(root_, OneByteVector(text)); +} + bool AsmTyper::Validate() { - if (!AsmType::None()->IsExactly(ValidateModule(root_))) { + return ValidateBeforeFunctionsPhase() && + !AsmType::None()->IsExactly(ValidateModuleFunctions(root_)) && + ValidateAfterFunctionsPhase(); +} + +bool AsmTyper::ValidateBeforeFunctionsPhase() { + if (!AsmType::None()->IsExactly(ValidateModuleBeforeFunctionsPhase(root_))) { return true; } return false; } +bool AsmTyper::ValidateInnerFunction(FunctionDeclaration* fun_decl) { + if (!AsmType::None()->IsExactly(ValidateModuleFunction(fun_decl))) { + return true; + } + return false; +} + +bool AsmTyper::ValidateAfterFunctionsPhase() { + if (!AsmType::None()->IsExactly(ValidateModuleAfterFunctionsPhase(root_))) { + return true; + } + return false; +} + +void AsmTyper::ClearFunctionNodeTypes() { function_node_types_.clear(); } + namespace { bool IsUseAsmDirective(Statement* first_statement) { ExpressionStatement* use_asm = first_statement->AsExpressionStatement(); @@ -477,91 +606,12 @@ Assignment* ExtractInitializerExpression(Statement* statement) { } // namespace // 6.1 ValidateModule -namespace { -// SourceLayoutTracker keeps track of the start and end positions of each -// section in the asm.js source. The sections should not overlap, otherwise the -// asm.js source is invalid. -class SourceLayoutTracker { - public: - SourceLayoutTracker() = default; - - bool IsValid() const { - const Section* kAllSections[] = {&use_asm_, &globals_, &functions_, - &tables_, &exports_}; - for (size_t ii = 0; ii < arraysize(kAllSections); ++ii) { - const auto& curr_section = *kAllSections[ii]; - for (size_t jj = ii + 1; jj < arraysize(kAllSections); ++jj) { - if (curr_section.OverlapsWith(*kAllSections[jj])) { - return false; - } - } - } - return true; - } - - void AddUseAsm(const AstNode& node) { use_asm_.AddNewElement(node); } - - void AddGlobal(const AstNode& node) { globals_.AddNewElement(node); } - - void AddFunction(const AstNode& node) { functions_.AddNewElement(node); } - - void AddTable(const AstNode& node) { tables_.AddNewElement(node); } - - void AddExport(const AstNode& node) { exports_.AddNewElement(node); } - - private: - class Section { - public: - Section() = default; - Section(const Section&) = default; - Section& operator=(const Section&) = default; - - void AddNewElement(const AstNode& node) { - const int node_pos = node.position(); - if (start_ == kNoSourcePosition) { - start_ = node_pos; - } else { - start_ = std::max(start_, node_pos); - } - if (end_ == kNoSourcePosition) { - end_ = node_pos; - } else { - end_ = std::max(end_, node_pos); - } - } - - bool OverlapsWith(const Section& other) const { - if (start_ == kNoSourcePosition) { - DCHECK_EQ(end_, kNoSourcePosition); - return false; - } - if (other.start_ == kNoSourcePosition) { - DCHECK_EQ(other.end_, kNoSourcePosition); - return false; - } - return other.start_ < end_ || other.end_ < start_; - } - - private: - int start_ = kNoSourcePosition; - int end_ = kNoSourcePosition; - }; - - Section use_asm_; - Section globals_; - Section functions_; - Section tables_; - Section exports_; - - DISALLOW_COPY_AND_ASSIGN(SourceLayoutTracker); -}; -} // namespace - -AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) { - SourceLayoutTracker source_layout; - +AsmType* AsmTyper::ValidateModuleBeforeFunctionsPhase(FunctionLiteral* fun) { DeclarationScope* scope = fun->scope(); if (!scope->is_function_scope()) FAIL(fun, "Not at function scope."); + if (scope->inner_scope_calls_eval()) { + FAIL(fun, "Invalid asm.js module using eval."); + } if (!ValidAsmIdentifier(fun->name())) FAIL(fun, "Invalid asm.js identifier in module name."); module_name_ = fun->name(); @@ -594,7 +644,6 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) { } } - ZoneVector<Assignment*> function_pointer_tables(zone_); FlattenedStatements iter(zone_, fun->body()); auto* use_asm_directive = iter.Next(); if (use_asm_directive == nullptr) { @@ -616,8 +665,8 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) { if (!IsUseAsmDirective(use_asm_directive)) { FAIL(fun, "Missing \"use asm\"."); } - source_layout.AddUseAsm(*use_asm_directive); - ReturnStatement* module_return = nullptr; + source_layout_.AddUseAsm(*use_asm_directive); + module_return_ = nullptr; // *VIOLATION* The spec states that globals should be followed by function // declarations, which should be followed by function pointer tables, followed @@ -627,40 +676,57 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) { if (auto* assign = ExtractInitializerExpression(current)) { if (assign->value()->IsArrayLiteral()) { // Save function tables for later validation. - function_pointer_tables.push_back(assign); + function_pointer_tables_.push_back(assign); } else { RECURSE(ValidateGlobalDeclaration(assign)); - source_layout.AddGlobal(*assign); + source_layout_.AddGlobal(*assign); } continue; } if (auto* current_as_return = current->AsReturnStatement()) { - if (module_return != nullptr) { + if (module_return_ != nullptr) { FAIL(fun, "Multiple export statements."); } - module_return = current_as_return; - source_layout.AddExport(*module_return); + module_return_ = current_as_return; + source_layout_.AddExport(*module_return_); continue; } FAIL(current, "Invalid top-level statement in asm.js module."); } + return AsmType::Int(); // Any type that is not AsmType::None(); +} + +AsmType* AsmTyper::ValidateModuleFunction(FunctionDeclaration* fun_decl) { + RECURSE(ValidateFunction(fun_decl)); + source_layout_.AddFunction(*fun_decl); + + return AsmType::Int(); // Any type that is not AsmType::None(); +} + +AsmType* AsmTyper::ValidateModuleFunctions(FunctionLiteral* fun) { + DeclarationScope* scope = fun->scope(); Declaration::List* decls = scope->declarations(); for (Declaration* decl : *decls) { if (FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration()) { - RECURSE(ValidateFunction(fun_decl)); - source_layout.AddFunction(*fun_decl); + RECURSE(ValidateModuleFunction(fun_decl)); continue; } } - for (auto* function_table : function_pointer_tables) { + return AsmType::Int(); // Any type that is not AsmType::None(); +} + +AsmType* AsmTyper::ValidateModuleAfterFunctionsPhase(FunctionLiteral* fun) { + for (auto* function_table : function_pointer_tables_) { RECURSE(ValidateFunctionTable(function_table)); - source_layout.AddTable(*function_table); + source_layout_.AddTable(*function_table); } + DeclarationScope* scope = fun->scope(); + Declaration::List* decls = scope->declarations(); for (Declaration* decl : *decls) { if (decl->IsFunctionDeclaration()) { continue; @@ -682,20 +748,20 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) { } // 6.2 ValidateExport - if (module_return == nullptr) { + if (module_return_ == nullptr) { FAIL(fun, "Missing asm.js module export."); } for (auto* forward_def : forward_definitions_) { if (forward_def->missing_definition()) { - FAIL(forward_def->first_forward_use(), - "Missing definition for forward declared identifier."); + FAIL_LOCATION(forward_def->source_location(), + "Missing definition for forward declared identifier."); } } - RECURSE(ValidateExport(module_return)); + RECURSE(ValidateExport(module_return_)); - if (!source_layout.IsValid()) { + if (!source_layout_.IsValid()) { FAIL(fun, "Invalid asm.js source code layout."); } @@ -714,8 +780,7 @@ bool IsDoubleAnnotation(BinaryOperation* binop) { return false; } - return right_as_literal->raw_value()->ContainsDot() && - right_as_literal->raw_value()->AsNumber() == 1.0; + return IsLiteral1Dot0(right_as_literal); } bool IsIntAnnotation(BinaryOperation* binop) { @@ -728,8 +793,7 @@ bool IsIntAnnotation(BinaryOperation* binop) { return false; } - return !right_as_literal->raw_value()->ContainsDot() && - right_as_literal->raw_value()->AsNumber() == 0.0; + return IsLiteral0(right_as_literal); } } // namespace @@ -894,6 +958,10 @@ AsmType* AsmTyper::ExportType(VariableProxy* fun_export) { FAIL(fun_export, "Module export is not an asm.js function."); } + if (!fun_export->var()->is_function()) { + FAIL(fun_export, "Module exports must be function declarations."); + } + return type; } @@ -915,6 +983,10 @@ AsmType* AsmTyper::ValidateExport(ReturnStatement* exports) { "Only normal object properties may be used in the export object " "literal."); } + if (!prop->key()->AsLiteral()->IsPropertyName()) { + FAIL(prop->key(), + "Exported functions must have valid identifier names."); + } auto* export_obj = prop->value()->AsVariableProxy(); if (export_obj == nullptr) { @@ -1091,6 +1163,7 @@ AsmType* AsmTyper::ValidateFunction(FunctionDeclaration* fun_decl) { parameter_types.push_back(type); SetTypeOf(proxy, type); SetTypeOf(expr, type); + SetTypeOf(expr->value(), type); } if (static_cast<int>(annotated_parameters) != fun->parameter_count()) { @@ -1442,7 +1515,7 @@ bool ExtractInt32CaseLabel(CaseClause* clause, int32_t* lbl) { return false; } - if (lbl_expr->raw_value()->ContainsDot()) { + if (!IsLiteralInt(lbl_expr)) { return false; } @@ -1539,8 +1612,7 @@ bool IsInvert(BinaryOperation* binop) { return false; } - return !right_as_literal->raw_value()->ContainsDot() && - right_as_literal->raw_value()->AsNumber() == -1.0; + return IsLiteralMinus1(right_as_literal); } bool IsUnaryMinus(BinaryOperation* binop) { @@ -1554,8 +1626,7 @@ bool IsUnaryMinus(BinaryOperation* binop) { return false; } - return !right_as_literal->raw_value()->ContainsDot() && - right_as_literal->raw_value()->AsNumber() == -1.0; + return IsLiteralMinus1(right_as_literal); } } // namespace @@ -1684,7 +1755,7 @@ AsmType* AsmTyper::ValidateNumericLiteral(Literal* literal) { return AsmType::Void(); } - if (literal->raw_value()->ContainsDot()) { + if (IsLiteralDouble(literal)) { return AsmType::Double(); } @@ -1864,7 +1935,7 @@ bool IsIntishLiteralFactor(Expression* expr, int32_t* factor) { return false; } - if (literal->raw_value()->ContainsDot()) { + if (!IsLiteralInt(literal)) { return false; } @@ -2204,12 +2275,12 @@ AsmType* AsmTyper::ValidateBitwiseORExpression(BinaryOperation* binop) { RECURSE(type = ValidateCall(AsmType::Signed(), left_as_call)); return type; } - - // TODO(jpp): at this point we know that binop is expr|0. We could sinply - // - // RECURSE(t = ValidateExpression(left)); - // FAIL_IF(t->IsNotA(Intish)); - // return Signed; + AsmType* left_type; + RECURSE(left_type = ValidateExpression(left)); + if (!left_type->IsA(AsmType::Intish())) { + FAIL(left, "Left side of |0 annotation must be intish."); + } + return AsmType::Signed(); } auto* right = binop->right(); @@ -2273,7 +2344,7 @@ bool ExtractIndirectCallMask(Expression* expr, uint32_t* value) { return false; } - if (as_literal->raw_value()->ContainsDot()) { + if (!IsLiteralInt(as_literal)) { return false; } @@ -2329,6 +2400,9 @@ AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) { DCHECK(false); FAIL(call, "Redeclared global identifier."); } + if (call->GetCallType() != Call::OTHER_CALL) { + FAIL(call, "Invalid call of existing global function."); + } SetTypeOf(call_var_proxy, reinterpret_cast<AsmType*>(call_type)); SetTypeOf(call, return_type); return return_type; @@ -2359,6 +2433,10 @@ AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) { FAIL(call, "Function invocation does not match function type."); } + if (call->GetCallType() != Call::OTHER_CALL) { + FAIL(call, "Invalid forward call of global function."); + } + SetTypeOf(call_var_proxy, call_var_info->type()); SetTypeOf(call, return_type); return return_type; @@ -2417,6 +2495,9 @@ AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) { DCHECK(false); FAIL(call, "Redeclared global identifier."); } + if (call->GetCallType() != Call::KEYED_PROPERTY_CALL) { + FAIL(call, "Invalid call of existing function table."); + } SetTypeOf(call_property, reinterpret_cast<AsmType*>(call_type)); SetTypeOf(call, return_type); return return_type; @@ -2441,6 +2522,9 @@ AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) { "signature."); } + if (call->GetCallType() != Call::KEYED_PROPERTY_CALL) { + FAIL(call, "Invalid forward call of function table."); + } SetTypeOf(call_property, previous_type->signature()); SetTypeOf(call, return_type); return return_type; @@ -2457,7 +2541,7 @@ bool ExtractHeapAccessShift(Expression* expr, uint32_t* value) { return false; } - if (as_literal->raw_value()->ContainsDot()) { + if (!IsLiteralInt(as_literal)) { return false; } @@ -2501,7 +2585,7 @@ AsmType* AsmTyper::ValidateHeapAccess(Property* heap, SetTypeOf(obj, obj_type); if (auto* key_as_literal = heap->key()->AsLiteral()) { - if (key_as_literal->raw_value()->ContainsDot()) { + if (!IsLiteralInt(key_as_literal)) { FAIL(key_as_literal, "Heap access index must be int."); } @@ -2685,9 +2769,9 @@ AsmType* AsmTyper::ReturnTypeAnnotations(ReturnStatement* statement) { if (auto* literal = ret_expr->AsLiteral()) { int32_t _; - if (literal->raw_value()->ContainsDot()) { + if (IsLiteralDouble(literal)) { return AsmType::Double(); - } else if (literal->value()->ToInt32(&_)) { + } else if (IsLiteralInt(literal) && literal->value()->ToInt32(&_)) { return AsmType::Signed(); } else if (literal->IsUndefinedLiteral()) { // *VIOLATION* The parser changes @@ -2728,13 +2812,15 @@ AsmType* AsmTyper::ReturnTypeAnnotations(ReturnStatement* statement) { AsmType* AsmTyper::VariableTypeAnnotations( Expression* initializer, VariableInfo::Mutability mutability_type) { if (auto* literal = initializer->AsLiteral()) { - if (literal->raw_value()->ContainsDot()) { + if (IsLiteralDouble(literal)) { SetTypeOf(initializer, AsmType::Double()); return AsmType::Double(); } + if (!IsLiteralInt(literal)) { + FAIL(initializer, "Invalid type annotation - forbidden literal."); + } int32_t i32; uint32_t u32; - AsmType* initializer_type = nullptr; if (literal->value()->ToUint32(&u32)) { if (u32 > LargestFixNum) { @@ -2793,13 +2879,17 @@ AsmType* AsmTyper::VariableTypeAnnotations( "to fround."); } - // Float constants must contain dots in local, but not in globals. - if (mutability_type == VariableInfo::kLocal) { - if (!src_expr->raw_value()->ContainsDot()) { - FAIL(initializer, - "Invalid float type annotation - expected literal argument to be a " - "floating point literal."); - } + // ERRATA: 5.4 + // According to the spec: float constants must contain dots in local, + // but not in globals. + // However, the errata doc (and actual programs), use integer values + // with fround(..). + // Skipping the check that would go here to enforce this. + // Checking instead the literal expression is at least a number. + if (!src_expr->raw_value()->IsNumber()) { + FAIL(initializer, + "Invalid float type annotation - expected numeric literal for call " + "to fround."); } return AsmType::Float(); @@ -2848,19 +2938,6 @@ AsmType* AsmTyper::NewHeapView(CallNew* new_heap_view) { return heap_view_info->type(); } -bool IsValidAsm(Isolate* isolate, Zone* zone, Script* script, - FunctionLiteral* root, std::string* error_message) { - error_message->clear(); - - AsmTyper typer(isolate, zone, script, root); - if (typer.Validate()) { - return true; - } - - *error_message = typer.error_message(); - return false; -} - } // namespace wasm } // namespace internal } // namespace v8 diff --git a/deps/v8/src/asmjs/asm-typer.h b/deps/v8/src/asmjs/asm-typer.h index 2c66948d56..8ddcb34b0f 100644 --- a/deps/v8/src/asmjs/asm-typer.h +++ b/deps/v8/src/asmjs/asm-typer.h @@ -7,6 +7,7 @@ #include <cstdint> #include <string> +#include <unordered_map> #include <unordered_set> #include "src/allocation.h" @@ -15,6 +16,7 @@ #include "src/ast/ast-types.h" #include "src/ast/ast.h" #include "src/effects.h" +#include "src/messages.h" #include "src/type-info.h" #include "src/zone/zone-containers.h" #include "src/zone/zone.h" @@ -25,6 +27,7 @@ namespace wasm { class AsmType; class AsmTyperHarnessBuilder; +class SourceLayoutTracker; class AsmTyper final { public: @@ -66,16 +69,27 @@ class AsmTyper final { }; ~AsmTyper() = default; - AsmTyper(Isolate* isolate, Zone* zone, Script* script, FunctionLiteral* root); + AsmTyper(Isolate* isolate, Zone* zone, Handle<Script> script, + FunctionLiteral* root); bool Validate(); + // Do asm.js validation in phases (to interleave with conversion to wasm). + bool ValidateBeforeFunctionsPhase(); + bool ValidateInnerFunction(FunctionDeclaration* decl); + bool ValidateAfterFunctionsPhase(); + void ClearFunctionNodeTypes(); - const char* error_message() const { return error_message_; } + Handle<JSMessageObject> error_message() const { return error_message_; } + const MessageLocation* message_location() const { return &message_location_; } AsmType* TypeOf(AstNode* node) const; AsmType* TypeOf(Variable* v) const; StandardMember VariableAsStandardMember(Variable* var); + // Allow the asm-wasm-builder to trigger failures (for interleaved + // validating). + AsmType* FailWithMessage(const char* text); + typedef std::unordered_set<StandardMember, std::hash<int> > StdlibSet; StdlibSet StdlibUses() const { return stdlib_uses_; } @@ -130,7 +144,7 @@ class AsmTyper final { bool IsHeap() const { return standard_member_ == kHeap; } void MarkDefined() { missing_definition_ = false; } - void FirstForwardUseIs(VariableProxy* var); + void SetFirstForwardUse(const MessageLocation& source_location); StandardMember standard_member() const { return standard_member_; } void set_standard_member(StandardMember standard_member) { @@ -145,7 +159,7 @@ class AsmTyper final { bool missing_definition() const { return missing_definition_; } - VariableProxy* first_forward_use() const { return first_forward_use_; } + const MessageLocation* source_location() { return &source_location_; } static VariableInfo* ForSpecialSymbol(Zone* zone, StandardMember standard_member); @@ -157,9 +171,8 @@ class AsmTyper final { // missing_definition_ is set to true for forward definition - i.e., use // before definition. bool missing_definition_ = false; - // first_forward_use_ holds the AST node that first referenced this - // VariableInfo. Used for error messages. - VariableProxy* first_forward_use_ = nullptr; + // Used for error messages. + MessageLocation source_location_; }; // RAII-style manager for the in_function_ member variable. @@ -199,6 +212,40 @@ class AsmTyper final { DISALLOW_IMPLICIT_CONSTRUCTORS(FlattenedStatements); }; + class SourceLayoutTracker { + public: + SourceLayoutTracker() = default; + bool IsValid() const; + void AddUseAsm(const AstNode& node) { use_asm_.AddNewElement(node); } + void AddGlobal(const AstNode& node) { globals_.AddNewElement(node); } + void AddFunction(const AstNode& node) { functions_.AddNewElement(node); } + void AddTable(const AstNode& node) { tables_.AddNewElement(node); } + void AddExport(const AstNode& node) { exports_.AddNewElement(node); } + + private: + class Section { + public: + Section() = default; + Section(const Section&) = default; + Section& operator=(const Section&) = default; + + void AddNewElement(const AstNode& node); + bool IsPrecededBy(const Section& other) const; + + private: + int start_ = kNoSourcePosition; + int end_ = kNoSourcePosition; + }; + + Section use_asm_; + Section globals_; + Section functions_; + Section tables_; + Section exports_; + + DISALLOW_COPY_AND_ASSIGN(SourceLayoutTracker); + }; + using ObjectTypeMap = ZoneMap<std::string, VariableInfo*>; void InitializeStdlib(); void SetTypeOf(AstNode* node, AsmType* type); @@ -220,7 +267,10 @@ class AsmTyper final { // validation failure. // 6.1 ValidateModule - AsmType* ValidateModule(FunctionLiteral* fun); + AsmType* ValidateModuleBeforeFunctionsPhase(FunctionLiteral* fun); + AsmType* ValidateModuleFunction(FunctionDeclaration* fun_decl); + AsmType* ValidateModuleFunctions(FunctionLiteral* fun); + AsmType* ValidateModuleAfterFunctionsPhase(FunctionLiteral* fun); AsmType* ValidateGlobalDeclaration(Assignment* assign); // 6.2 ValidateExport AsmType* ExportType(VariableProxy* fun_export); @@ -323,7 +373,7 @@ class AsmTyper final { Isolate* isolate_; Zone* zone_; - Script* script_; + Handle<Script> script_; FunctionLiteral* root_; bool in_function_ = false; @@ -345,13 +395,19 @@ class AsmTyper final { std::uintptr_t stack_limit_; bool stack_overflow_ = false; - ZoneMap<AstNode*, AsmType*> node_types_; - static const int kErrorMessageLimit = 100; + std::unordered_map<AstNode*, AsmType*> module_node_types_; + std::unordered_map<AstNode*, AsmType*> function_node_types_; + static const int kErrorMessageLimit = 128; AsmType* fround_type_; AsmType* ffi_type_; - char error_message_[kErrorMessageLimit]; + Handle<JSMessageObject> error_message_; + MessageLocation message_location_; StdlibSet stdlib_uses_; + SourceLayoutTracker source_layout_; + ReturnStatement* module_return_; + ZoneVector<Assignment*> function_pointer_tables_; + DISALLOW_IMPLICIT_CONSTRUCTORS(AsmTyper); }; diff --git a/deps/v8/src/asmjs/asm-types.cc b/deps/v8/src/asmjs/asm-types.cc index 8f3c9a51e6..79c43a370b 100644 --- a/deps/v8/src/asmjs/asm-types.cc +++ b/deps/v8/src/asmjs/asm-types.cc @@ -6,6 +6,7 @@ #include <cinttypes> +#include "src/utils.h" #include "src/v8.h" namespace v8 { diff --git a/deps/v8/src/asmjs/asm-wasm-builder.cc b/deps/v8/src/asmjs/asm-wasm-builder.cc index cac6fbd8b3..907e80fe4b 100644 --- a/deps/v8/src/asmjs/asm-wasm-builder.cc +++ b/deps/v8/src/asmjs/asm-wasm-builder.cc @@ -19,6 +19,11 @@ #include "src/ast/ast.h" #include "src/ast/scopes.h" +#include "src/codegen.h" +#include "src/compilation-info.h" +#include "src/compiler.h" +#include "src/isolate.h" +#include "src/parsing/parse-info.h" namespace v8 { namespace internal { @@ -37,13 +42,14 @@ enum ValueFate { kDrop, kLeaveOnStack }; struct ForeignVariable { Handle<Name> name; Variable* var; - LocalType type; + ValueType type; }; class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { public: - AsmWasmBuilderImpl(Isolate* isolate, Zone* zone, FunctionLiteral* literal, - AsmTyper* typer) + AsmWasmBuilderImpl(Isolate* isolate, Zone* zone, CompilationInfo* info, + AstValueFactory* ast_value_factory, Handle<Script> script, + FunctionLiteral* literal, AsmTyper* typer) : local_variables_(ZoneHashMap::kDefaultHashMapCapacity, ZoneAllocationPolicy(zone)), functions_(ZoneHashMap::kDefaultHashMapCapacity, @@ -56,15 +62,20 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { literal_(literal), isolate_(isolate), zone_(zone), + info_(info), + ast_value_factory_(ast_value_factory), + script_(script), typer_(typer), + typer_failed_(false), + typer_finished_(false), breakable_blocks_(zone), foreign_variables_(zone), init_function_(nullptr), foreign_init_function_(nullptr), - next_table_index_(0), function_tables_(ZoneHashMap::kDefaultHashMapCapacity, ZoneAllocationPolicy(zone)), - imported_function_table_(this) { + imported_function_table_(this), + parent_binop_(nullptr) { InitializeAstVisitor(isolate); } @@ -90,10 +101,11 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { uint32_t index = LookupOrInsertGlobal(fv->var, fv->type); foreign_init_function_->EmitWithVarInt(kExprSetGlobal, index); } + foreign_init_function_->Emit(kExprEnd); } - i::Handle<i::FixedArray> GetForeignArgs() { - i::Handle<FixedArray> ret = isolate_->factory()->NewFixedArray( + Handle<FixedArray> GetForeignArgs() { + Handle<FixedArray> ret = isolate_->factory()->NewFixedArray( static_cast<int>(foreign_variables_.size())); for (size_t i = 0; i < foreign_variables_.size(); ++i) { ForeignVariable* fv = &foreign_variables_[i]; @@ -102,10 +114,26 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { return ret; } - void Build() { + bool Build() { InitializeInitFunction(); - RECURSE(VisitFunctionLiteral(literal_)); + if (!typer_->ValidateBeforeFunctionsPhase()) { + return false; + } + DCHECK(!HasStackOverflow()); + VisitFunctionLiteral(literal_); + if (HasStackOverflow()) { + return false; + } + if (!typer_finished_ && !typer_failed_) { + typer_->FailWithMessage("Module missing export section."); + typer_failed_ = true; + } + if (typer_failed_) { + return false; + } BuildForeignInitFunction(); + init_function_->Emit(kExprEnd); // finish init function. + return true; } void VisitVariableDeclaration(VariableDeclaration* decl) {} @@ -113,12 +141,65 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { void VisitFunctionDeclaration(FunctionDeclaration* decl) { DCHECK_EQ(kModuleScope, scope_); DCHECK_NULL(current_function_builder_); + FunctionLiteral* old_func = decl->fun(); + Zone zone(isolate_->allocator(), ZONE_NAME); + DeclarationScope* new_func_scope = nullptr; + if (decl->fun()->body() == nullptr) { + // TODO(titzer/bradnelson): Reuse SharedFunctionInfos used here when + // compiling the wasm module. + Handle<SharedFunctionInfo> shared = + Compiler::GetSharedFunctionInfo(decl->fun(), script_, info_); + shared->set_is_toplevel(false); + ParseInfo info(&zone, script_); + info.set_shared_info(shared); + info.set_toplevel(false); + info.set_language_mode(decl->fun()->scope()->language_mode()); + info.set_allow_lazy_parsing(false); + info.set_function_literal_id(shared->function_literal_id()); + info.set_ast_value_factory(ast_value_factory_); + info.set_ast_value_factory_owned(false); + // Create fresh function scope to use to parse the function in. + new_func_scope = new (info.zone()) DeclarationScope( + info.zone(), decl->fun()->scope()->outer_scope(), FUNCTION_SCOPE); + info.set_asm_function_scope(new_func_scope); + if (!Compiler::ParseAndAnalyze(&info)) { + typer_failed_ = true; + return; + } + FunctionLiteral* func = info.literal(); + DCHECK_NOT_NULL(func); + decl->set_fun(func); + } + if (!typer_->ValidateInnerFunction(decl)) { + typer_failed_ = true; + decl->set_fun(old_func); + if (new_func_scope != nullptr) { + DCHECK_EQ(new_func_scope, decl->scope()->inner_scope()); + if (!decl->scope()->RemoveInnerScope(new_func_scope)) { + UNREACHABLE(); + } + } + return; + } current_function_builder_ = LookupOrInsertFunction(decl->proxy()->var()); scope_ = kFuncScope; + + // Record start of the function, used as position for the stack check. + current_function_builder_->SetAsmFunctionStartPosition( + decl->fun()->start_position()); + RECURSE(Visit(decl->fun())); + decl->set_fun(old_func); + if (new_func_scope != nullptr) { + DCHECK_EQ(new_func_scope, decl->scope()->inner_scope()); + if (!decl->scope()->RemoveInnerScope(new_func_scope)) { + UNREACHABLE(); + } + } scope_ = kModuleScope; current_function_builder_ = nullptr; local_variables_.Clear(); + typer_->ClearFunctionNodeTypes(); } void VisitStatements(ZoneList<Statement*>* stmts) { @@ -129,7 +210,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { continue; } RECURSE(Visit(stmt)); - if (stmt->IsJump()) break; + if (typer_failed_) break; } } @@ -204,6 +285,8 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { void VisitEmptyParentheses(EmptyParentheses* paren) { UNREACHABLE(); } + void VisitGetIterator(GetIterator* expr) { UNREACHABLE(); } + void VisitIfStatement(IfStatement* stmt) { DCHECK_EQ(kFuncScope, scope_); RECURSE(Visit(stmt->condition())); @@ -245,6 +328,16 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { void VisitReturnStatement(ReturnStatement* stmt) { if (scope_ == kModuleScope) { + if (typer_finished_) { + typer_->FailWithMessage("Module has multiple returns."); + typer_failed_ = true; + return; + } + if (!typer_->ValidateAfterFunctionsPhase()) { + typer_failed_ = true; + return; + } + typer_finished_ = true; scope_ = kExportScope; RECURSE(Visit(stmt->expression())); scope_ = kModuleScope; @@ -440,16 +533,21 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { // Add the parameters for the function. const auto& arguments = func_type->Arguments(); for (int i = 0; i < expr->parameter_count(); ++i) { - LocalType type = TypeFrom(arguments[i]); - DCHECK_NE(kAstStmt, type); + ValueType type = TypeFrom(arguments[i]); + DCHECK_NE(kWasmStmt, type); InsertParameter(scope->parameter(i), type, i); } } else { UNREACHABLE(); } } - RECURSE(VisitStatements(expr->body())); RECURSE(VisitDeclarations(scope->declarations())); + if (typer_failed_) return; + RECURSE(VisitStatements(expr->body())); + if (scope_ == kFuncScope) { + // Finish the function-body scope block. + current_function_builder_->Emit(kExprEnd); + } } void VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) { @@ -461,18 +559,18 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { RECURSE(Visit(expr->condition())); // WASM ifs come with implicit blocks for both arms. breakable_blocks_.push_back(std::make_pair(nullptr, false)); - LocalTypeCode type; + ValueTypeCode type; switch (TypeOf(expr)) { - case kAstI32: + case kWasmI32: type = kLocalI32; break; - case kAstI64: + case kWasmI64: type = kLocalI64; break; - case kAstF32: + case kWasmF32: type = kLocalF32; break; - case kAstF64: + case kWasmF64: type = kLocalF64; break; default: @@ -544,8 +642,8 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { if (VisitStdlibConstant(var)) { return; } - LocalType var_type = TypeOf(expr); - DCHECK_NE(kAstStmt, var_type); + ValueType var_type = TypeOf(expr); + DCHECK_NE(kWasmStmt, var_type); if (var->IsContextSlot()) { current_function_builder_->EmitWithVarInt( kExprGetGlobal, LookupOrInsertGlobal(var, var_type)); @@ -638,12 +736,13 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { Literal* name = prop->key()->AsLiteral(); DCHECK_NOT_NULL(name); DCHECK(name->IsPropertyName()); - const AstRawString* raw_name = name->AsRawPropertyName(); + Handle<String> function_name = name->AsPropertyName(); + int length; + std::unique_ptr<char[]> utf8 = function_name->ToCString( + DISALLOW_NULLS, FAST_STRING_TRAVERSAL, &length); if (var->is_function()) { WasmFunctionBuilder* function = LookupOrInsertFunction(var); - function->Export(); - function->SetName({reinterpret_cast<const char*>(raw_name->raw_data()), - raw_name->length()}); + function->ExportAs({utf8.get(), length}); } } } @@ -660,53 +759,67 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { current_function_builder_ = nullptr; } - void AddFunctionTable(VariableProxy* table, ArrayLiteral* funcs) { - auto* func_tbl_type = typer_->TypeOf(funcs)->AsFunctionTableType(); - DCHECK_NOT_NULL(func_tbl_type); - auto* func_type = func_tbl_type->signature()->AsFunctionType(); + struct FunctionTableIndices : public ZoneObject { + uint32_t start_index; + uint32_t signature_index; + }; + + FunctionTableIndices* LookupOrAddFunctionTable(VariableProxy* table, + Property* p) { + FunctionTableIndices* indices = LookupFunctionTable(table->var()); + if (indices != nullptr) { + // Already setup. + return indices; + } + indices = new (zone()) FunctionTableIndices(); + auto* func_type = typer_->TypeOf(p)->AsFunctionType(); + auto* func_table_type = typer_->TypeOf(p->obj()->AsVariableProxy()->var()) + ->AsFunctionTableType(); const auto& arguments = func_type->Arguments(); - LocalType return_type = TypeFrom(func_type->ReturnType()); - FunctionSig::Builder sig(zone(), return_type == kAstStmt ? 0 : 1, + ValueType return_type = TypeFrom(func_type->ReturnType()); + FunctionSig::Builder sig(zone(), return_type == kWasmStmt ? 0 : 1, arguments.size()); - if (return_type != kAstStmt) { + if (return_type != kWasmStmt) { sig.AddReturn(return_type); } for (auto* arg : arguments) { sig.AddParam(TypeFrom(arg)); } uint32_t signature_index = builder_->AddSignature(sig.Build()); - InsertFunctionTable(table->var(), next_table_index_, signature_index); - next_table_index_ += funcs->values()->length(); - for (int i = 0; i < funcs->values()->length(); ++i) { - VariableProxy* func = funcs->values()->at(i)->AsVariableProxy(); - DCHECK_NOT_NULL(func); - builder_->AddIndirectFunction( - LookupOrInsertFunction(func->var())->func_index()); - } - } - - struct FunctionTableIndices : public ZoneObject { - uint32_t start_index; - uint32_t signature_index; - }; - - void InsertFunctionTable(Variable* v, uint32_t start_index, - uint32_t signature_index) { - FunctionTableIndices* container = new (zone()) FunctionTableIndices(); - container->start_index = start_index; - container->signature_index = signature_index; + indices->start_index = builder_->AllocateIndirectFunctions( + static_cast<uint32_t>(func_table_type->length())); + indices->signature_index = signature_index; ZoneHashMap::Entry* entry = function_tables_.LookupOrInsert( - v, ComputePointerHash(v), ZoneAllocationPolicy(zone())); - entry->value = container; + table->var(), ComputePointerHash(table->var()), + ZoneAllocationPolicy(zone())); + entry->value = indices; + return indices; } FunctionTableIndices* LookupFunctionTable(Variable* v) { ZoneHashMap::Entry* entry = function_tables_.Lookup(v, ComputePointerHash(v)); - DCHECK_NOT_NULL(entry); + if (entry == nullptr) { + return nullptr; + } return reinterpret_cast<FunctionTableIndices*>(entry->value); } + void PopulateFunctionTable(VariableProxy* table, ArrayLiteral* funcs) { + FunctionTableIndices* indices = LookupFunctionTable(table->var()); + // Ignore unused function tables. + if (indices == nullptr) { + return; + } + for (int i = 0; i < funcs->values()->length(); ++i) { + VariableProxy* func = funcs->values()->at(i)->AsVariableProxy(); + DCHECK_NOT_NULL(func); + builder_->SetIndirectFunction( + indices->start_index + i, + LookupOrInsertFunction(func->var())->func_index()); + } + } + class ImportedFunctionTable { private: class ImportedFunctionIndices : public ZoneObject { @@ -727,20 +840,33 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { ZoneAllocationPolicy(builder->zone())), builder_(builder) {} - void AddImport(Variable* v, const char* name, int name_length) { - ImportedFunctionIndices* indices = new (builder_->zone()) - ImportedFunctionIndices(name, name_length, builder_->zone()); + ImportedFunctionIndices* LookupOrInsertImport(Variable* v) { auto* entry = table_.LookupOrInsert( v, ComputePointerHash(v), ZoneAllocationPolicy(builder_->zone())); - entry->value = indices; + ImportedFunctionIndices* indices; + if (entry->value == nullptr) { + indices = new (builder_->zone()) + ImportedFunctionIndices(nullptr, 0, builder_->zone()); + entry->value = indices; + } else { + indices = reinterpret_cast<ImportedFunctionIndices*>(entry->value); + } + return indices; + } + + void SetImportName(Variable* v, const char* name, int name_length) { + auto* indices = LookupOrInsertImport(v); + indices->name_ = name; + indices->name_length_ = name_length; + for (auto i : indices->signature_to_index_) { + builder_->builder_->SetImportName(i.second, indices->name_, + indices->name_length_); + } } // Get a function's index (or allocate if new). - uint32_t LookupOrInsertImport(Variable* v, FunctionSig* sig) { - ZoneHashMap::Entry* entry = table_.Lookup(v, ComputePointerHash(v)); - DCHECK_NOT_NULL(entry); - ImportedFunctionIndices* indices = - reinterpret_cast<ImportedFunctionIndices*>(entry->value); + uint32_t LookupOrInsertImportUse(Variable* v, FunctionSig* sig) { + auto* indices = LookupOrInsertImport(v); WasmModuleBuilder::SignatureMap::iterator pos = indices->signature_to_index_.find(sig); if (pos != indices->signature_to_index_.end()) { @@ -819,8 +945,8 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { if (target_var != nullptr) { // Left hand side is a local or a global variable. Variable* var = target_var->var(); - LocalType var_type = TypeOf(expr); - DCHECK_NE(kAstStmt, var_type); + ValueType var_type = TypeOf(expr); + DCHECK_NE(kWasmStmt, var_type); if (var->IsContextSlot()) { uint32_t index = LookupOrInsertGlobal(var, var_type); current_function_builder_->EmitWithVarInt(kExprSetGlobal, index); @@ -841,7 +967,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { Property* target_prop = expr->target()->AsProperty(); if (target_prop != nullptr) { // Left hand side is a property access, i.e. the asm.js heap. - if (TypeOf(expr->value()) == kAstF64 && expr->target()->IsProperty() && + if (TypeOf(expr->value()) == kWasmF64 && expr->target()->IsProperty() && typer_->TypeOf(expr->target()->AsProperty()->obj()) ->IsA(AsmType::Float32Array())) { current_function_builder_->Emit(kExprF32ConvertF64); @@ -901,7 +1027,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { if (typer_->TypeOf(target)->AsFFIType() != nullptr) { const AstRawString* name = prop->key()->AsLiteral()->AsRawPropertyName(); - imported_function_table_.AddImport( + imported_function_table_.SetImportName( target->var(), reinterpret_cast<const char*>(name->raw_data()), name->length()); } @@ -910,14 +1036,10 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { return; } ArrayLiteral* funcs = expr->value()->AsArrayLiteral(); - if (funcs != nullptr && - typer_->TypeOf(funcs) - ->AsFunctionTableType() - ->signature() - ->AsFunctionType()) { + if (funcs != nullptr) { VariableProxy* target = expr->target()->AsVariableProxy(); DCHECK_NOT_NULL(target); - AddFunctionTable(target, funcs); + PopulateFunctionTable(target, funcs); // Only add to the function table. No init needed. return; } @@ -952,8 +1074,8 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { DCHECK_NOT_NULL(key_literal); if (!key_literal->value().is_null()) { Handle<Name> name = - i::Object::ToName(isolate_, key_literal->value()).ToHandleChecked(); - LocalType type = is_float ? kAstF64 : kAstI32; + Object::ToName(isolate_, key_literal->value()).ToHandleChecked(); + ValueType type = is_float ? kWasmF64 : kWasmI32; foreign_variables_.push_back({name, var, type}); } } @@ -961,7 +1083,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { void VisitPropertyAndEmitIndex(Property* expr, AsmType** atype) { Expression* obj = expr->obj(); *atype = typer_->TypeOf(obj); - int size = (*atype)->ElementSizeInBytes(); + int32_t size = (*atype)->ElementSizeInBytes(); if (size == 1) { // Allow more general expression in byte arrays than the spec // strictly permits. @@ -974,7 +1096,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { Literal* value = expr->key()->AsLiteral(); if (value) { DCHECK(value->raw_value()->IsNumber()); - DCHECK_EQ(kAstI32, TypeOf(value)); + DCHECK_EQ(kWasmI32, TypeOf(value)); int32_t val = static_cast<int32_t>(value->raw_value()->AsNumber()); // TODO(titzer): handle overflow here. current_function_builder_->EmitI32Const(val * size); @@ -984,14 +1106,13 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { if (binop) { DCHECK_EQ(Token::SAR, binop->op()); DCHECK(binop->right()->AsLiteral()->raw_value()->IsNumber()); - DCHECK(kAstI32 == TypeOf(binop->right()->AsLiteral())); + DCHECK(kWasmI32 == TypeOf(binop->right()->AsLiteral())); DCHECK_EQ(size, 1 << static_cast<int>( binop->right()->AsLiteral()->raw_value()->AsNumber())); // Mask bottom bits to match asm.js behavior. - byte mask = static_cast<byte>(~(size - 1)); RECURSE(Visit(binop->left())); - current_function_builder_->EmitWithU8(kExprI8Const, mask); + current_function_builder_->EmitI32Const(~(size - 1)); current_function_builder_->Emit(kExprI32And); return; } @@ -1030,7 +1151,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { AsmTyper::StandardMember standard_object = typer_->VariableAsStandardMember(var); ZoneList<Expression*>* args = call->arguments(); - LocalType call_type = TypeOf(call); + ValueType call_type = TypeOf(call); switch (standard_object) { case AsmTyper::kNone: { @@ -1038,57 +1159,57 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { } case AsmTyper::kMathAcos: { VisitCallArgs(call); - DCHECK_EQ(kAstF64, call_type); + DCHECK_EQ(kWasmF64, call_type); current_function_builder_->Emit(kExprF64Acos); break; } case AsmTyper::kMathAsin: { VisitCallArgs(call); - DCHECK_EQ(kAstF64, call_type); + DCHECK_EQ(kWasmF64, call_type); current_function_builder_->Emit(kExprF64Asin); break; } case AsmTyper::kMathAtan: { VisitCallArgs(call); - DCHECK_EQ(kAstF64, call_type); + DCHECK_EQ(kWasmF64, call_type); current_function_builder_->Emit(kExprF64Atan); break; } case AsmTyper::kMathCos: { VisitCallArgs(call); - DCHECK_EQ(kAstF64, call_type); + DCHECK_EQ(kWasmF64, call_type); current_function_builder_->Emit(kExprF64Cos); break; } case AsmTyper::kMathSin: { VisitCallArgs(call); - DCHECK_EQ(kAstF64, call_type); + DCHECK_EQ(kWasmF64, call_type); current_function_builder_->Emit(kExprF64Sin); break; } case AsmTyper::kMathTan: { VisitCallArgs(call); - DCHECK_EQ(kAstF64, call_type); + DCHECK_EQ(kWasmF64, call_type); current_function_builder_->Emit(kExprF64Tan); break; } case AsmTyper::kMathExp: { VisitCallArgs(call); - DCHECK_EQ(kAstF64, call_type); + DCHECK_EQ(kWasmF64, call_type); current_function_builder_->Emit(kExprF64Exp); break; } case AsmTyper::kMathLog: { VisitCallArgs(call); - DCHECK_EQ(kAstF64, call_type); + DCHECK_EQ(kWasmF64, call_type); current_function_builder_->Emit(kExprF64Log); break; } case AsmTyper::kMathCeil: { VisitCallArgs(call); - if (call_type == kAstF32) { + if (call_type == kWasmF32) { current_function_builder_->Emit(kExprF32Ceil); - } else if (call_type == kAstF64) { + } else if (call_type == kWasmF64) { current_function_builder_->Emit(kExprF64Ceil); } else { UNREACHABLE(); @@ -1097,9 +1218,9 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { } case AsmTyper::kMathFloor: { VisitCallArgs(call); - if (call_type == kAstF32) { + if (call_type == kWasmF32) { current_function_builder_->Emit(kExprF32Floor); - } else if (call_type == kAstF64) { + } else if (call_type == kWasmF64) { current_function_builder_->Emit(kExprF64Floor); } else { UNREACHABLE(); @@ -1108,9 +1229,9 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { } case AsmTyper::kMathSqrt: { VisitCallArgs(call); - if (call_type == kAstF32) { + if (call_type == kWasmF32) { current_function_builder_->Emit(kExprF32Sqrt); - } else if (call_type == kAstF64) { + } else if (call_type == kWasmF64) { current_function_builder_->Emit(kExprF64Sqrt); } else { UNREACHABLE(); @@ -1119,18 +1240,18 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { } case AsmTyper::kMathClz32: { VisitCallArgs(call); - DCHECK(call_type == kAstI32); + DCHECK(call_type == kWasmI32); current_function_builder_->Emit(kExprI32Clz); break; } case AsmTyper::kMathAbs: { - if (call_type == kAstI32) { - WasmTemporary tmp(current_function_builder_, kAstI32); + if (call_type == kWasmI32) { + WasmTemporary tmp(current_function_builder_, kWasmI32); // if set_local(tmp, x) < 0 Visit(call->arguments()->at(0)); current_function_builder_->EmitTeeLocal(tmp.index()); - byte code[] = {WASM_I8(0)}; + byte code[] = {WASM_ZERO}; current_function_builder_->EmitCode(code, sizeof(code)); current_function_builder_->Emit(kExprI32LtS); current_function_builder_->EmitWithU8(kExprIf, kLocalI32); @@ -1146,10 +1267,10 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { // end current_function_builder_->Emit(kExprEnd); - } else if (call_type == kAstF32) { + } else if (call_type == kWasmF32) { VisitCallArgs(call); current_function_builder_->Emit(kExprF32Abs); - } else if (call_type == kAstF64) { + } else if (call_type == kWasmF64) { VisitCallArgs(call); current_function_builder_->Emit(kExprF64Abs); } else { @@ -1159,9 +1280,9 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { } case AsmTyper::kMathMin: { // TODO(bradnelson): Change wasm to match Math.min in asm.js mode. - if (call_type == kAstI32) { - WasmTemporary tmp_x(current_function_builder_, kAstI32); - WasmTemporary tmp_y(current_function_builder_, kAstI32); + if (call_type == kWasmI32) { + WasmTemporary tmp_x(current_function_builder_, kWasmI32); + WasmTemporary tmp_y(current_function_builder_, kWasmI32); // if set_local(tmp_x, x) < set_local(tmp_y, y) Visit(call->arguments()->at(0)); @@ -1181,10 +1302,10 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { current_function_builder_->EmitGetLocal(tmp_y.index()); current_function_builder_->Emit(kExprEnd); - } else if (call_type == kAstF32) { + } else if (call_type == kWasmF32) { VisitCallArgs(call); current_function_builder_->Emit(kExprF32Min); - } else if (call_type == kAstF64) { + } else if (call_type == kWasmF64) { VisitCallArgs(call); current_function_builder_->Emit(kExprF64Min); } else { @@ -1194,9 +1315,9 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { } case AsmTyper::kMathMax: { // TODO(bradnelson): Change wasm to match Math.max in asm.js mode. - if (call_type == kAstI32) { - WasmTemporary tmp_x(current_function_builder_, kAstI32); - WasmTemporary tmp_y(current_function_builder_, kAstI32); + if (call_type == kWasmI32) { + WasmTemporary tmp_x(current_function_builder_, kWasmI32); + WasmTemporary tmp_y(current_function_builder_, kWasmI32); // if set_local(tmp_x, x) < set_local(tmp_y, y) Visit(call->arguments()->at(0)); @@ -1217,10 +1338,10 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { current_function_builder_->EmitGetLocal(tmp_x.index()); current_function_builder_->Emit(kExprEnd); - } else if (call_type == kAstF32) { + } else if (call_type == kWasmF32) { VisitCallArgs(call); current_function_builder_->Emit(kExprF32Max); - } else if (call_type == kAstF64) { + } else if (call_type == kWasmF64) { VisitCallArgs(call); current_function_builder_->Emit(kExprF64Max); } else { @@ -1230,13 +1351,13 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { } case AsmTyper::kMathAtan2: { VisitCallArgs(call); - DCHECK_EQ(kAstF64, call_type); + DCHECK_EQ(kWasmF64, call_type); current_function_builder_->Emit(kExprF64Atan2); break; } case AsmTyper::kMathPow: { VisitCallArgs(call); - DCHECK_EQ(kAstF64, call_type); + DCHECK_EQ(kWasmF64, call_type); current_function_builder_->Emit(kExprF64Pow); break; } @@ -1298,6 +1419,10 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { bool VisitCallExpression(Call* expr) { Call::CallType call_type = expr->GetCallType(); bool returns_value = true; + + // Save the parent now, it might be overwritten in VisitCallArgs. + BinaryOperation* parent_binop = parent_binop_; + switch (call_type) { case Call::OTHER_CALL: { VariableProxy* proxy = expr->expression()->AsVariableProxy(); @@ -1313,11 +1438,11 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { VariableProxy* vp = expr->expression()->AsVariableProxy(); DCHECK_NOT_NULL(vp); if (typer_->TypeOf(vp)->AsFFIType() != nullptr) { - LocalType return_type = TypeOf(expr); + ValueType return_type = TypeOf(expr); ZoneList<Expression*>* args = expr->arguments(); - FunctionSig::Builder sig(zone(), return_type == kAstStmt ? 0 : 1, + FunctionSig::Builder sig(zone(), return_type == kWasmStmt ? 0 : 1, args->length()); - if (return_type != kAstStmt) { + if (return_type != kWasmStmt) { sig.AddReturn(return_type); } else { returns_value = false; @@ -1325,16 +1450,23 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { for (int i = 0; i < args->length(); ++i) { sig.AddParam(TypeOf(args->at(i))); } - uint32_t index = imported_function_table_.LookupOrInsertImport( + uint32_t index = imported_function_table_.LookupOrInsertImportUse( vp->var(), sig.Build()); VisitCallArgs(expr); - current_function_builder_->AddAsmWasmOffset(expr->position()); + // For non-void functions, we must know the parent node. + DCHECK_IMPLIES(returns_value, parent_binop != nullptr); + DCHECK_IMPLIES(returns_value, parent_binop->left() == expr || + parent_binop->right() == expr); + int pos = expr->position(); + int parent_pos = returns_value ? parent_binop->position() : pos; + current_function_builder_->AddAsmWasmOffset(pos, parent_pos); current_function_builder_->Emit(kExprCallFunction); current_function_builder_->EmitVarInt(index); } else { WasmFunctionBuilder* function = LookupOrInsertFunction(vp->var()); VisitCallArgs(expr); - current_function_builder_->AddAsmWasmOffset(expr->position()); + current_function_builder_->AddAsmWasmOffset(expr->position(), + expr->position()); current_function_builder_->Emit(kExprCallFunction); current_function_builder_->EmitDirectCallIndex( function->func_index()); @@ -1348,19 +1480,20 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { DCHECK_NOT_NULL(p); VariableProxy* var = p->obj()->AsVariableProxy(); DCHECK_NOT_NULL(var); - FunctionTableIndices* indices = LookupFunctionTable(var->var()); + FunctionTableIndices* indices = LookupOrAddFunctionTable(var, p); Visit(p->key()); // TODO(titzer): should use RECURSE() // We have to use a temporary for the correct order of evaluation. current_function_builder_->EmitI32Const(indices->start_index); current_function_builder_->Emit(kExprI32Add); - WasmTemporary tmp(current_function_builder_, kAstI32); + WasmTemporary tmp(current_function_builder_, kWasmI32); current_function_builder_->EmitSetLocal(tmp.index()); VisitCallArgs(expr); current_function_builder_->EmitGetLocal(tmp.index()); - current_function_builder_->AddAsmWasmOffset(expr->position()); + current_function_builder_->AddAsmWasmOffset(expr->position(), + expr->position()); current_function_builder_->Emit(kExprCallIndirect); current_function_builder_->EmitVarInt(indices->signature_index); current_function_builder_->EmitVarInt(0); // table index @@ -1383,7 +1516,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { RECURSE(Visit(expr->expression())); switch (expr->op()) { case Token::NOT: { - DCHECK_EQ(kAstI32, TypeOf(expr->expression())); + DCHECK_EQ(kWasmI32, TypeOf(expr->expression())); current_function_builder_->Emit(kExprI32Eqz); break; } @@ -1398,10 +1531,10 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { int32_t val) { DCHECK_NOT_NULL(expr->right()); if (expr->op() == op && expr->right()->IsLiteral() && - TypeOf(expr) == kAstI32) { + TypeOf(expr) == kWasmI32) { Literal* right = expr->right()->AsLiteral(); - DCHECK(right->raw_value()->IsNumber()); - if (static_cast<int32_t>(right->raw_value()->AsNumber()) == val) { + if (right->raw_value()->IsNumber() && + static_cast<int32_t>(right->raw_value()->AsNumber()) == val) { return true; } } @@ -1412,7 +1545,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { double val) { DCHECK_NOT_NULL(expr->right()); if (expr->op() == op && expr->right()->IsLiteral() && - TypeOf(expr) == kAstF64) { + TypeOf(expr) == kWasmF64) { Literal* right = expr->right()->AsLiteral(); DCHECK(right->raw_value()->IsNumber()); if (right->raw_value()->AsNumber() == val) { @@ -1426,7 +1559,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { ConvertOperation MatchOr(BinaryOperation* expr) { if (MatchIntBinaryOperation(expr, Token::BIT_OR, 0) && - (TypeOf(expr->left()) == kAstI32)) { + (TypeOf(expr->left()) == kWasmI32)) { return kAsIs; } else { return kNone; @@ -1436,7 +1569,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { ConvertOperation MatchShr(BinaryOperation* expr) { if (MatchIntBinaryOperation(expr, Token::SHR, 0)) { // TODO(titzer): this probably needs to be kToUint - return (TypeOf(expr->left()) == kAstI32) ? kAsIs : kToInt; + return (TypeOf(expr->left()) == kWasmI32) ? kAsIs : kToInt; } else { return kNone; } @@ -1444,13 +1577,13 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { ConvertOperation MatchXor(BinaryOperation* expr) { if (MatchIntBinaryOperation(expr, Token::BIT_XOR, 0xffffffff)) { - DCHECK_EQ(kAstI32, TypeOf(expr->left())); - DCHECK_EQ(kAstI32, TypeOf(expr->right())); + DCHECK_EQ(kWasmI32, TypeOf(expr->left())); + DCHECK_EQ(kWasmI32, TypeOf(expr->right())); BinaryOperation* op = expr->left()->AsBinaryOperation(); if (op != nullptr) { if (MatchIntBinaryOperation(op, Token::BIT_XOR, 0xffffffff)) { - DCHECK_EQ(kAstI32, TypeOf(op->right())); - if (TypeOf(op->left()) != kAstI32) { + DCHECK_EQ(kWasmI32, TypeOf(op->right())); + if (TypeOf(op->left()) != kWasmI32) { return kToInt; } else { return kAsIs; @@ -1463,8 +1596,8 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { ConvertOperation MatchMul(BinaryOperation* expr) { if (MatchDoubleBinaryOperation(expr, Token::MUL, 1.0)) { - DCHECK_EQ(kAstF64, TypeOf(expr->right())); - if (TypeOf(expr->left()) != kAstF64) { + DCHECK_EQ(kWasmF64, TypeOf(expr->right())); + if (TypeOf(expr->left()) != kWasmF64) { return kToDouble; } else { return kAsIs; @@ -1532,6 +1665,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { void VisitBinaryOperation(BinaryOperation* expr) { ConvertOperation convertOperation = MatchBinaryOperation(expr); static const bool kDontIgnoreSign = false; + parent_binop_ = expr; if (convertOperation == kToDouble) { RECURSE(Visit(expr->left())); TypeIndex type = TypeIndexOf(expr->left(), kDontIgnoreSign); @@ -1694,6 +1828,9 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { void VisitDeclarations(Declaration::List* decls) { for (Declaration* decl : *decls) { RECURSE(Visit(decl)); + if (typer_failed_) { + return; + } } } @@ -1719,7 +1856,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { uint32_t index; }; - uint32_t LookupOrInsertLocal(Variable* v, LocalType type) { + uint32_t LookupOrInsertLocal(Variable* v, ValueType type) { DCHECK_NOT_NULL(current_function_builder_); ZoneHashMap::Entry* entry = local_variables_.Lookup(v, ComputePointerHash(v)); @@ -1736,7 +1873,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { return (reinterpret_cast<IndexContainer*>(entry->value))->index; } - void InsertParameter(Variable* v, LocalType type, uint32_t index) { + void InsertParameter(Variable* v, ValueType type, uint32_t index) { DCHECK(v->IsParameter()); DCHECK_NOT_NULL(current_function_builder_); ZoneHashMap::Entry* entry = @@ -1749,7 +1886,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { entry->value = container; } - uint32_t LookupOrInsertGlobal(Variable* v, LocalType type) { + uint32_t LookupOrInsertGlobal(Variable* v, ValueType type) { ZoneHashMap::Entry* entry = global_variables_.Lookup(v, ComputePointerHash(v)); if (entry == nullptr) { @@ -1770,14 +1907,14 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { auto* func_type = typer_->TypeOf(v)->AsFunctionType(); DCHECK_NOT_NULL(func_type); // Build the signature for the function. - LocalType return_type = TypeFrom(func_type->ReturnType()); + ValueType return_type = TypeFrom(func_type->ReturnType()); const auto& arguments = func_type->Arguments(); - FunctionSig::Builder b(zone(), return_type == kAstStmt ? 0 : 1, + FunctionSig::Builder b(zone(), return_type == kWasmStmt ? 0 : 1, arguments.size()); - if (return_type != kAstStmt) b.AddReturn(return_type); + if (return_type != kWasmStmt) b.AddReturn(return_type); for (int i = 0; i < static_cast<int>(arguments.size()); ++i) { - LocalType type = TypeFrom(arguments[i]); - DCHECK_NE(kAstStmt, type); + ValueType type = TypeFrom(arguments[i]); + DCHECK_NE(kWasmStmt, type); b.AddParam(type); } @@ -1792,22 +1929,22 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { return (reinterpret_cast<WasmFunctionBuilder*>(entry->value)); } - LocalType TypeOf(Expression* expr) { return TypeFrom(typer_->TypeOf(expr)); } + ValueType TypeOf(Expression* expr) { return TypeFrom(typer_->TypeOf(expr)); } - LocalType TypeFrom(AsmType* type) { + ValueType TypeFrom(AsmType* type) { if (type->IsA(AsmType::Intish())) { - return kAstI32; + return kWasmI32; } if (type->IsA(AsmType::Floatish())) { - return kAstF32; + return kWasmF32; } if (type->IsA(AsmType::DoubleQ())) { - return kAstF64; + return kWasmF64; } - return kAstStmt; + return kWasmStmt; } Zone* zone() { return zone_; } @@ -1821,7 +1958,12 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { FunctionLiteral* literal_; Isolate* isolate_; Zone* zone_; + CompilationInfo* info_; + AstValueFactory* ast_value_factory_; + Handle<Script> script_; AsmTyper* typer_; + bool typer_failed_; + bool typer_finished_; ZoneVector<std::pair<BreakableStatement*, bool>> breakable_blocks_; ZoneVector<ForeignVariable> foreign_variables_; WasmFunctionBuilder* init_function_; @@ -1829,6 +1971,9 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { uint32_t next_table_index_; ZoneHashMap function_tables_; ImportedFunctionTable imported_function_table_; + // Remember the parent node for reporting the correct location for ToNumber + // conversions after calls. + BinaryOperation* parent_binop_; DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); @@ -1836,22 +1981,24 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { DISALLOW_COPY_AND_ASSIGN(AsmWasmBuilderImpl); }; -AsmWasmBuilder::AsmWasmBuilder(Isolate* isolate, Zone* zone, - FunctionLiteral* literal, AsmTyper* typer) - : isolate_(isolate), zone_(zone), literal_(literal), typer_(typer) {} +AsmWasmBuilder::AsmWasmBuilder(CompilationInfo* info) + : info_(info), + typer_(info->isolate(), info->zone(), info->script(), info->literal()) {} // TODO(aseemgarg): probably should take zone (to write wasm to) as input so // that zone in constructor may be thrown away once wasm module is written. -AsmWasmBuilder::Result AsmWasmBuilder::Run( - i::Handle<i::FixedArray>* foreign_args) { - AsmWasmBuilderImpl impl(isolate_, zone_, literal_, typer_); - impl.Build(); +AsmWasmBuilder::Result AsmWasmBuilder::Run(Handle<FixedArray>* foreign_args) { + Zone* zone = info_->zone(); + AsmWasmBuilderImpl impl(info_->isolate(), zone, info_, + info_->parse_info()->ast_value_factory(), + info_->script(), info_->literal(), &typer_); + bool success = impl.Build(); *foreign_args = impl.GetForeignArgs(); - ZoneBuffer* module_buffer = new (zone_) ZoneBuffer(zone_); + ZoneBuffer* module_buffer = new (zone) ZoneBuffer(zone); impl.builder_->WriteTo(*module_buffer); - ZoneBuffer* asm_offsets_buffer = new (zone_) ZoneBuffer(zone_); + ZoneBuffer* asm_offsets_buffer = new (zone) ZoneBuffer(zone); impl.builder_->WriteAsmJsOffsetTable(*asm_offsets_buffer); - return {module_buffer, asm_offsets_buffer}; + return {module_buffer, asm_offsets_buffer, success}; } const char* AsmWasmBuilder::foreign_init_name = "__foreign_init__"; diff --git a/deps/v8/src/asmjs/asm-wasm-builder.h b/deps/v8/src/asmjs/asm-wasm-builder.h index f234abde8a..a5db096683 100644 --- a/deps/v8/src/asmjs/asm-wasm-builder.h +++ b/deps/v8/src/asmjs/asm-wasm-builder.h @@ -14,7 +14,7 @@ namespace v8 { namespace internal { -class FunctionLiteral; +class CompilationInfo; namespace wasm { @@ -23,20 +23,20 @@ class AsmWasmBuilder { struct Result { ZoneBuffer* module_bytes; ZoneBuffer* asm_offset_table; + bool success; }; - explicit AsmWasmBuilder(Isolate* isolate, Zone* zone, FunctionLiteral* root, - AsmTyper* typer); + explicit AsmWasmBuilder(CompilationInfo* info); Result Run(Handle<FixedArray>* foreign_args); static const char* foreign_init_name; static const char* single_function_name; + const AsmTyper* typer() { return &typer_; } + private: - Isolate* isolate_; - Zone* zone_; - FunctionLiteral* literal_; - AsmTyper* typer_; + CompilationInfo* info_; + AsmTyper typer_; }; } // namespace wasm } // namespace internal |