summaryrefslogtreecommitdiff
path: root/deps/v8/src/asmjs
diff options
context:
space:
mode:
authorMichaël Zasso <targos@protonmail.com>2017-03-21 10:16:54 +0100
committerMichaël Zasso <targos@protonmail.com>2017-03-25 09:44:10 +0100
commitc459d8ea5d402c702948c860d9497b2230ff7e8a (patch)
tree56c282fc4d40e5cb613b47cf7be3ea0526ed5b6f /deps/v8/src/asmjs
parente0bc5a7361b1d29c3ed034155fd779ce6f44fb13 (diff)
downloadandroid-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/OWNERS1
-rw-r--r--deps/v8/src/asmjs/asm-js.cc129
-rw-r--r--deps/v8/src/asmjs/asm-js.h4
-rw-r--r--deps/v8/src/asmjs/asm-typer.cc407
-rw-r--r--deps/v8/src/asmjs/asm-typer.h80
-rw-r--r--deps/v8/src/asmjs/asm-types.cc1
-rw-r--r--deps/v8/src/asmjs/asm-wasm-builder.cc465
-rw-r--r--deps/v8/src/asmjs/asm-wasm-builder.h14
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