Bug 1713735 part 1 - Vendored files for wasm2c for use in rlbox r=glandium

Differential Revision: https://phabricator.services.mozilla.com/D116441
This commit is contained in:
shravanrn@gmail.com
2021-07-16 02:38:40 +00:00
parent 819f1b4168
commit 48a5ecdc61
144 changed files with 52759 additions and 0 deletions

202
third_party/wasm2c/LICENSE vendored Normal file
View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

510
third_party/wasm2c/src/apply-names.cc vendored Normal file
View File

@@ -0,0 +1,510 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/apply-names.h"
#include <cassert>
#include <cstdio>
#include <vector>
#include "src/expr-visitor.h"
#include "src/ir.h"
#include "src/string-view.h"
namespace wabt {
namespace {
class NameApplier : public ExprVisitor::DelegateNop {
public:
NameApplier();
Result VisitModule(Module* module);
// Implementation of ExprVisitor::DelegateNop.
Result BeginBlockExpr(BlockExpr*) override;
Result EndBlockExpr(BlockExpr*) override;
Result OnBrExpr(BrExpr*) override;
Result OnBrIfExpr(BrIfExpr*) override;
Result OnBrTableExpr(BrTableExpr*) override;
Result OnCallExpr(CallExpr*) override;
Result OnRefFuncExpr(RefFuncExpr*) override;
Result OnCallIndirectExpr(CallIndirectExpr*) override;
Result OnReturnCallExpr(ReturnCallExpr*) override;
Result OnReturnCallIndirectExpr(ReturnCallIndirectExpr*) override;
Result OnGlobalGetExpr(GlobalGetExpr*) override;
Result OnGlobalSetExpr(GlobalSetExpr*) override;
Result BeginIfExpr(IfExpr*) override;
Result EndIfExpr(IfExpr*) override;
Result OnLocalGetExpr(LocalGetExpr*) override;
Result OnLocalSetExpr(LocalSetExpr*) override;
Result OnLocalTeeExpr(LocalTeeExpr*) override;
Result BeginLoopExpr(LoopExpr*) override;
Result EndLoopExpr(LoopExpr*) override;
Result OnDataDropExpr(DataDropExpr*) override;
Result OnMemoryInitExpr(MemoryInitExpr*) override;
Result OnElemDropExpr(ElemDropExpr*) override;
Result OnTableCopyExpr(TableCopyExpr*) override;
Result OnTableInitExpr(TableInitExpr*) override;
Result OnTableGetExpr(TableGetExpr*) override;
Result OnTableSetExpr(TableSetExpr*) override;
Result OnTableGrowExpr(TableGrowExpr*) override;
Result OnTableSizeExpr(TableSizeExpr*) override;
Result OnTableFillExpr(TableFillExpr*) override;
Result BeginTryExpr(TryExpr*) override;
Result EndTryExpr(TryExpr*) override;
Result OnCatchExpr(TryExpr*, Catch*) override;
Result OnDelegateExpr(TryExpr*) override;
Result OnThrowExpr(ThrowExpr*) override;
Result OnRethrowExpr(RethrowExpr*) override;
private:
void PushLabel(const std::string& label);
void PopLabel();
string_view FindLabelByVar(Var* var);
void UseNameForVar(string_view name, Var* var);
Result UseNameForFuncTypeVar(Var* var);
Result UseNameForFuncVar(Var* var);
Result UseNameForGlobalVar(Var* var);
Result UseNameForTableVar(Var* var);
Result UseNameForMemoryVar(Var* var);
Result UseNameForEventVar(Var* var);
Result UseNameForDataSegmentVar(Var* var);
Result UseNameForElemSegmentVar(Var* var);
Result UseNameForParamAndLocalVar(Func* func, Var* var);
Result VisitFunc(Index func_index, Func* func);
Result VisitGlobal(Global* global);
Result VisitEvent(Event* event);
Result VisitExport(Index export_index, Export* export_);
Result VisitElemSegment(Index elem_segment_index, ElemSegment* segment);
Result VisitDataSegment(Index data_segment_index, DataSegment* segment);
Result VisitStart(Var* start_var);
Module* module_ = nullptr;
Func* current_func_ = nullptr;
ExprVisitor visitor_;
std::vector<std::string> param_and_local_index_to_name_;
std::vector<std::string> labels_;
};
NameApplier::NameApplier() : visitor_(this) {}
void NameApplier::PushLabel(const std::string& label) {
labels_.push_back(label);
}
void NameApplier::PopLabel() {
labels_.pop_back();
}
string_view NameApplier::FindLabelByVar(Var* var) {
if (var->is_name()) {
for (int i = labels_.size() - 1; i >= 0; --i) {
const std::string& label = labels_[i];
if (label == var->name()) {
return label;
}
}
return string_view();
} else {
if (var->index() >= labels_.size()) {
return string_view();
}
return labels_[labels_.size() - 1 - var->index()];
}
}
void NameApplier::UseNameForVar(string_view name, Var* var) {
if (var->is_name()) {
assert(name == var->name());
return;
}
if (!name.empty()) {
var->set_name(name);
}
}
Result NameApplier::UseNameForFuncTypeVar(Var* var) {
FuncType* func_type = module_->GetFuncType(*var);
if (!func_type) {
return Result::Error;
}
UseNameForVar(func_type->name, var);
return Result::Ok;
}
Result NameApplier::UseNameForFuncVar(Var* var) {
Func* func = module_->GetFunc(*var);
if (!func) {
return Result::Error;
}
UseNameForVar(func->name, var);
return Result::Ok;
}
Result NameApplier::UseNameForGlobalVar(Var* var) {
Global* global = module_->GetGlobal(*var);
if (!global) {
return Result::Error;
}
UseNameForVar(global->name, var);
return Result::Ok;
}
Result NameApplier::UseNameForTableVar(Var* var) {
Table* table = module_->GetTable(*var);
if (!table) {
return Result::Error;
}
UseNameForVar(table->name, var);
return Result::Ok;
}
Result NameApplier::UseNameForMemoryVar(Var* var) {
Memory* memory = module_->GetMemory(*var);
if (!memory) {
return Result::Error;
}
UseNameForVar(memory->name, var);
return Result::Ok;
}
Result NameApplier::UseNameForEventVar(Var* var) {
Event* event = module_->GetEvent(*var);
if (!event) {
return Result::Error;
}
UseNameForVar(event->name, var);
return Result::Ok;
}
Result NameApplier::UseNameForDataSegmentVar(Var* var) {
DataSegment* data_segment = module_->GetDataSegment(*var);
if (!data_segment) {
return Result::Error;
}
UseNameForVar(data_segment->name, var);
return Result::Ok;
}
Result NameApplier::UseNameForElemSegmentVar(Var* var) {
ElemSegment* elem_segment = module_->GetElemSegment(*var);
if (!elem_segment) {
return Result::Error;
}
UseNameForVar(elem_segment->name, var);
return Result::Ok;
}
Result NameApplier::UseNameForParamAndLocalVar(Func* func, Var* var) {
Index local_index = func->GetLocalIndex(*var);
if (local_index >= func->GetNumParamsAndLocals()) {
return Result::Error;
}
std::string name = param_and_local_index_to_name_[local_index];
if (var->is_name()) {
assert(name == var->name());
return Result::Ok;
}
if (!name.empty()) {
var->set_name(name);
}
return Result::Ok;
}
Result NameApplier::BeginBlockExpr(BlockExpr* expr) {
PushLabel(expr->block.label);
return Result::Ok;
}
Result NameApplier::EndBlockExpr(BlockExpr* expr) {
PopLabel();
return Result::Ok;
}
Result NameApplier::BeginLoopExpr(LoopExpr* expr) {
PushLabel(expr->block.label);
return Result::Ok;
}
Result NameApplier::EndLoopExpr(LoopExpr* expr) {
PopLabel();
return Result::Ok;
}
Result NameApplier::OnDataDropExpr(DataDropExpr* expr) {
CHECK_RESULT(UseNameForDataSegmentVar(&expr->var));
return Result::Ok;
}
Result NameApplier::OnMemoryInitExpr(MemoryInitExpr* expr) {
CHECK_RESULT(UseNameForDataSegmentVar(&expr->var));
return Result::Ok;
}
Result NameApplier::OnElemDropExpr(ElemDropExpr* expr) {
CHECK_RESULT(UseNameForElemSegmentVar(&expr->var));
return Result::Ok;
}
Result NameApplier::OnTableCopyExpr(TableCopyExpr* expr) {
CHECK_RESULT(UseNameForTableVar(&expr->dst_table));
CHECK_RESULT(UseNameForTableVar(&expr->src_table));
return Result::Ok;
}
Result NameApplier::OnTableInitExpr(TableInitExpr* expr) {
CHECK_RESULT(UseNameForElemSegmentVar(&expr->segment_index));
CHECK_RESULT(UseNameForTableVar(&expr->table_index));
return Result::Ok;
}
Result NameApplier::OnTableGetExpr(TableGetExpr* expr) {
CHECK_RESULT(UseNameForTableVar(&expr->var));
return Result::Ok;
}
Result NameApplier::OnTableSetExpr(TableSetExpr* expr) {
CHECK_RESULT(UseNameForTableVar(&expr->var));
return Result::Ok;
}
Result NameApplier::OnTableGrowExpr(TableGrowExpr* expr) {
CHECK_RESULT(UseNameForTableVar(&expr->var));
return Result::Ok;
}
Result NameApplier::OnTableSizeExpr(TableSizeExpr* expr) {
CHECK_RESULT(UseNameForTableVar(&expr->var));
return Result::Ok;
}
Result NameApplier::OnTableFillExpr(TableFillExpr* expr) {
CHECK_RESULT(UseNameForTableVar(&expr->var));
return Result::Ok;
}
Result NameApplier::OnBrExpr(BrExpr* expr) {
string_view label = FindLabelByVar(&expr->var);
UseNameForVar(label, &expr->var);
return Result::Ok;
}
Result NameApplier::OnBrIfExpr(BrIfExpr* expr) {
string_view label = FindLabelByVar(&expr->var);
UseNameForVar(label, &expr->var);
return Result::Ok;
}
Result NameApplier::OnBrTableExpr(BrTableExpr* expr) {
for (Var& target : expr->targets) {
string_view label = FindLabelByVar(&target);
UseNameForVar(label, &target);
}
string_view label = FindLabelByVar(&expr->default_target);
UseNameForVar(label, &expr->default_target);
return Result::Ok;
}
Result NameApplier::BeginTryExpr(TryExpr* expr) {
PushLabel(expr->block.label);
return Result::Ok;
}
Result NameApplier::EndTryExpr(TryExpr*) {
PopLabel();
return Result::Ok;
}
Result NameApplier::OnCatchExpr(TryExpr*, Catch* expr) {
if (!expr->IsCatchAll()) {
CHECK_RESULT(UseNameForEventVar(&expr->var));
}
return Result::Ok;
}
Result NameApplier::OnDelegateExpr(TryExpr* expr) {
string_view label = FindLabelByVar(&expr->delegate_target);
UseNameForVar(label, &expr->delegate_target);
return Result::Ok;
}
Result NameApplier::OnThrowExpr(ThrowExpr* expr) {
CHECK_RESULT(UseNameForEventVar(&expr->var));
return Result::Ok;
}
Result NameApplier::OnRethrowExpr(RethrowExpr* expr) {
string_view label = FindLabelByVar(&expr->var);
UseNameForVar(label, &expr->var);
return Result::Ok;
}
Result NameApplier::OnCallExpr(CallExpr* expr) {
CHECK_RESULT(UseNameForFuncVar(&expr->var));
return Result::Ok;
}
Result NameApplier::OnRefFuncExpr(RefFuncExpr* expr) {
CHECK_RESULT(UseNameForFuncVar(&expr->var));
return Result::Ok;
}
Result NameApplier::OnCallIndirectExpr(CallIndirectExpr* expr) {
if (expr->decl.has_func_type) {
CHECK_RESULT(UseNameForFuncTypeVar(&expr->decl.type_var));
}
CHECK_RESULT(UseNameForTableVar(&expr->table));
return Result::Ok;
}
Result NameApplier::OnReturnCallExpr(ReturnCallExpr* expr) {
CHECK_RESULT(UseNameForFuncVar(&expr->var));
return Result::Ok;
}
Result NameApplier::OnReturnCallIndirectExpr(ReturnCallIndirectExpr* expr) {
if (expr->decl.has_func_type) {
CHECK_RESULT(UseNameForFuncTypeVar(&expr->decl.type_var));
}
CHECK_RESULT(UseNameForTableVar(&expr->table));
return Result::Ok;
}
Result NameApplier::OnGlobalGetExpr(GlobalGetExpr* expr) {
CHECK_RESULT(UseNameForGlobalVar(&expr->var));
return Result::Ok;
}
Result NameApplier::OnLocalGetExpr(LocalGetExpr* expr) {
CHECK_RESULT(UseNameForParamAndLocalVar(current_func_, &expr->var));
return Result::Ok;
}
Result NameApplier::BeginIfExpr(IfExpr* expr) {
PushLabel(expr->true_.label);
return Result::Ok;
}
Result NameApplier::EndIfExpr(IfExpr* expr) {
PopLabel();
return Result::Ok;
}
Result NameApplier::OnGlobalSetExpr(GlobalSetExpr* expr) {
CHECK_RESULT(UseNameForGlobalVar(&expr->var));
return Result::Ok;
}
Result NameApplier::OnLocalSetExpr(LocalSetExpr* expr) {
CHECK_RESULT(UseNameForParamAndLocalVar(current_func_, &expr->var));
return Result::Ok;
}
Result NameApplier::OnLocalTeeExpr(LocalTeeExpr* expr) {
CHECK_RESULT(UseNameForParamAndLocalVar(current_func_, &expr->var));
return Result::Ok;
}
Result NameApplier::VisitFunc(Index func_index, Func* func) {
current_func_ = func;
if (func->decl.has_func_type) {
CHECK_RESULT(UseNameForFuncTypeVar(&func->decl.type_var));
}
MakeTypeBindingReverseMapping(func->GetNumParamsAndLocals(), func->bindings,
&param_and_local_index_to_name_);
CHECK_RESULT(visitor_.VisitFunc(func));
current_func_ = nullptr;
return Result::Ok;
}
Result NameApplier::VisitGlobal(Global* global) {
CHECK_RESULT(visitor_.VisitExprList(global->init_expr));
return Result::Ok;
}
Result NameApplier::VisitEvent(Event* event) {
if (event->decl.has_func_type) {
CHECK_RESULT(UseNameForFuncTypeVar(&event->decl.type_var));
}
return Result::Ok;
}
Result NameApplier::VisitExport(Index export_index, Export* export_) {
if (export_->kind == ExternalKind::Func) {
UseNameForFuncVar(&export_->var);
}
return Result::Ok;
}
Result NameApplier::VisitElemSegment(Index elem_segment_index,
ElemSegment* segment) {
CHECK_RESULT(UseNameForTableVar(&segment->table_var));
CHECK_RESULT(visitor_.VisitExprList(segment->offset));
for (ElemExpr& elem_expr : segment->elem_exprs) {
if (elem_expr.kind == ElemExprKind::RefFunc) {
CHECK_RESULT(UseNameForFuncVar(&elem_expr.var));
}
}
return Result::Ok;
}
Result NameApplier::VisitDataSegment(Index data_segment_index,
DataSegment* segment) {
CHECK_RESULT(UseNameForMemoryVar(&segment->memory_var));
CHECK_RESULT(visitor_.VisitExprList(segment->offset));
return Result::Ok;
}
Result NameApplier::VisitStart(Var* start_var) {
CHECK_RESULT(UseNameForFuncVar(start_var));
return Result::Ok;
}
Result NameApplier::VisitModule(Module* module) {
module_ = module;
for (size_t i = 0; i < module->funcs.size(); ++i)
CHECK_RESULT(VisitFunc(i, module->funcs[i]));
for (size_t i = 0; i < module->globals.size(); ++i)
CHECK_RESULT(VisitGlobal(module->globals[i]));
for (size_t i = 0; i < module->events.size(); ++i)
CHECK_RESULT(VisitEvent(module->events[i]));
for (size_t i = 0; i < module->exports.size(); ++i)
CHECK_RESULT(VisitExport(i, module->exports[i]));
for (size_t i = 0; i < module->elem_segments.size(); ++i)
CHECK_RESULT(VisitElemSegment(i, module->elem_segments[i]));
for (size_t i = 0; i < module->data_segments.size(); ++i)
CHECK_RESULT(VisitDataSegment(i, module->data_segments[i]));
for (size_t i = 0; i < module->starts.size(); ++i)
CHECK_RESULT(VisitStart(module->starts[i]));
module_ = nullptr;
return Result::Ok;
}
} // end anonymous namespace
Result ApplyNames(Module* module) {
NameApplier applier;
return applier.VisitModule(module);
}
} // namespace wabt

45
third_party/wasm2c/src/apply-names.h vendored Normal file
View File

@@ -0,0 +1,45 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_APPLY_NAMES_H_
#define WABT_APPLY_NAMES_H_
#include "src/common.h"
namespace wabt {
struct Module;
/* Use function, import, function type, parameter and local names in Vars
* that reference them.
*
* e.g. transform this:
*
* (func $foo ...)
* ...
* (call 0 ...)
*
* to this:
*
* (func $foo ...)
* ...
* (call $foo ...)
*/
Result ApplyNames(struct Module*);
} // namespace wabt
#endif /* WABT_APPLY_NAMES_H_ */

1585
third_party/wasm2c/src/binary-reader-ir.cc vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_BINARY_READER_IR_H_
#define WABT_BINARY_READER_IR_H_
#include "src/common.h"
#include "src/error.h"
namespace wabt {
struct Module;
struct ReadBinaryOptions;
Result ReadBinaryIr(const char* filename,
const void* data,
size_t size,
const ReadBinaryOptions& options,
Errors*,
Module* out_module);
} // namespace wabt
#endif /* WABT_BINARY_READER_IR_H_ */

View File

@@ -0,0 +1,967 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/binary-reader-logging.h"
#include <cinttypes>
#include "src/stream.h"
namespace wabt {
#define INDENT_SIZE 2
#define LOGF_NOINDENT(...) stream_->Writef(__VA_ARGS__)
#define LOGF(...) \
do { \
WriteIndent(); \
LOGF_NOINDENT(__VA_ARGS__); \
} while (0)
namespace {
void SPrintLimits(char* dst, size_t size, const Limits* limits) {
int result;
if (limits->has_max) {
result = wabt_snprintf(dst, size, "initial: %" PRIu64 ", max: %" PRIu64,
limits->initial, limits->max);
} else {
result = wabt_snprintf(dst, size, "initial: %" PRIu64, limits->initial);
}
WABT_USE(result);
assert(static_cast<size_t>(result) < size);
}
} // end anonymous namespace
BinaryReaderLogging::BinaryReaderLogging(Stream* stream,
BinaryReaderDelegate* forward)
: stream_(stream), reader_(forward), indent_(0) {}
void BinaryReaderLogging::Indent() {
indent_ += INDENT_SIZE;
}
void BinaryReaderLogging::Dedent() {
indent_ -= INDENT_SIZE;
assert(indent_ >= 0);
}
void BinaryReaderLogging::WriteIndent() {
static char s_indent[] =
" "
" ";
static const size_t s_indent_len = sizeof(s_indent) - 1;
size_t i = indent_;
while (i > s_indent_len) {
stream_->WriteData(s_indent, s_indent_len);
i -= s_indent_len;
}
if (i > 0) {
stream_->WriteData(s_indent, indent_);
}
}
void BinaryReaderLogging::LogType(Type type) {
if (type.IsIndex()) {
LOGF_NOINDENT("typeidx[%d]", type.GetIndex());
} else {
LOGF_NOINDENT("%s", type.GetName());
}
}
void BinaryReaderLogging::LogTypes(Index type_count, Type* types) {
LOGF_NOINDENT("[");
for (Index i = 0; i < type_count; ++i) {
LogType(types[i]);
if (i != type_count - 1) {
LOGF_NOINDENT(", ");
}
}
LOGF_NOINDENT("]");
}
void BinaryReaderLogging::LogTypes(TypeVector& types) {
LogTypes(types.size(), types.data());
}
void BinaryReaderLogging::LogField(TypeMut field) {
if (field.mutable_) {
LOGF_NOINDENT("(mut ");
}
LogType(field.type);
if (field.mutable_) {
LOGF_NOINDENT(")");
}
}
bool BinaryReaderLogging::OnError(const Error& error) {
return reader_->OnError(error);
}
void BinaryReaderLogging::OnSetState(const State* s) {
BinaryReaderDelegate::OnSetState(s);
reader_->OnSetState(s);
}
Result BinaryReaderLogging::BeginModule(uint32_t version) {
LOGF("BeginModule(version: %u)\n", version);
Indent();
return reader_->BeginModule(version);
}
Result BinaryReaderLogging::BeginSection(Index section_index,
BinarySection section_type,
Offset size) {
return reader_->BeginSection(section_index, section_type, size);
}
Result BinaryReaderLogging::BeginCustomSection(Index section_index,
Offset size,
string_view section_name) {
LOGF("BeginCustomSection('" PRIstringview "', size: %" PRIzd ")\n",
WABT_PRINTF_STRING_VIEW_ARG(section_name), size);
Indent();
return reader_->BeginCustomSection(section_index, size, section_name);
}
Result BinaryReaderLogging::OnFuncType(Index index,
Index param_count,
Type* param_types,
Index result_count,
Type* result_types) {
LOGF("OnFuncType(index: %" PRIindex ", params: ", index);
LogTypes(param_count, param_types);
LOGF_NOINDENT(", results: ");
LogTypes(result_count, result_types);
LOGF_NOINDENT(")\n");
return reader_->OnFuncType(index, param_count, param_types, result_count,
result_types);
}
Result BinaryReaderLogging::OnStructType(Index index,
Index field_count,
TypeMut* fields) {
LOGF("OnStructType(index: %" PRIindex ", fields: ", index);
LOGF_NOINDENT("[");
for (Index i = 0; i < field_count; ++i) {
LogField(fields[i]);
if (i != field_count - 1) {
LOGF_NOINDENT(", ");
}
}
LOGF_NOINDENT("])\n");
return reader_->OnStructType(index, field_count, fields);
}
Result BinaryReaderLogging::OnArrayType(Index index, TypeMut field) {
LOGF("OnArrayType(index: %" PRIindex ", field: ", index);
LogField(field);
LOGF_NOINDENT(")\n");
return reader_->OnArrayType(index, field);
}
Result BinaryReaderLogging::OnImport(Index index,
ExternalKind kind,
string_view module_name,
string_view field_name) {
LOGF("OnImport(index: %" PRIindex ", kind: %s, module: \"" PRIstringview
"\", field: \"" PRIstringview "\")\n",
index, GetKindName(kind), WABT_PRINTF_STRING_VIEW_ARG(module_name),
WABT_PRINTF_STRING_VIEW_ARG(field_name));
return reader_->OnImport(index, kind, module_name, field_name);
}
Result BinaryReaderLogging::OnImportFunc(Index import_index,
string_view module_name,
string_view field_name,
Index func_index,
Index sig_index) {
LOGF("OnImportFunc(import_index: %" PRIindex ", func_index: %" PRIindex
", sig_index: %" PRIindex ")\n",
import_index, func_index, sig_index);
return reader_->OnImportFunc(import_index, module_name, field_name,
func_index, sig_index);
}
Result BinaryReaderLogging::OnImportTable(Index import_index,
string_view module_name,
string_view field_name,
Index table_index,
Type elem_type,
const Limits* elem_limits) {
char buf[100];
SPrintLimits(buf, sizeof(buf), elem_limits);
LOGF("OnImportTable(import_index: %" PRIindex ", table_index: %" PRIindex
", elem_type: %s, %s)\n",
import_index, table_index, elem_type.GetName(), buf);
return reader_->OnImportTable(import_index, module_name, field_name,
table_index, elem_type, elem_limits);
}
Result BinaryReaderLogging::OnImportMemory(Index import_index,
string_view module_name,
string_view field_name,
Index memory_index,
const Limits* page_limits) {
char buf[100];
SPrintLimits(buf, sizeof(buf), page_limits);
LOGF("OnImportMemory(import_index: %" PRIindex ", memory_index: %" PRIindex
", %s)\n",
import_index, memory_index, buf);
return reader_->OnImportMemory(import_index, module_name, field_name,
memory_index, page_limits);
}
Result BinaryReaderLogging::OnImportGlobal(Index import_index,
string_view module_name,
string_view field_name,
Index global_index,
Type type,
bool mutable_) {
LOGF("OnImportGlobal(import_index: %" PRIindex ", global_index: %" PRIindex
", type: %s, mutable: "
"%s)\n",
import_index, global_index, type.GetName(), mutable_ ? "true" : "false");
return reader_->OnImportGlobal(import_index, module_name, field_name,
global_index, type, mutable_);
}
Result BinaryReaderLogging::OnImportEvent(Index import_index,
string_view module_name,
string_view field_name,
Index event_index,
Index sig_index) {
LOGF("OnImportEvent(import_index: %" PRIindex ", event_index: %" PRIindex
", sig_index: %" PRIindex ")\n",
import_index, event_index, sig_index);
return reader_->OnImportEvent(import_index, module_name, field_name,
event_index, sig_index);
}
Result BinaryReaderLogging::OnTable(Index index,
Type elem_type,
const Limits* elem_limits) {
char buf[100];
SPrintLimits(buf, sizeof(buf), elem_limits);
LOGF("OnTable(index: %" PRIindex ", elem_type: %s, %s)\n", index,
elem_type.GetName(), buf);
return reader_->OnTable(index, elem_type, elem_limits);
}
Result BinaryReaderLogging::OnMemory(Index index, const Limits* page_limits) {
char buf[100];
SPrintLimits(buf, sizeof(buf), page_limits);
LOGF("OnMemory(index: %" PRIindex ", %s)\n", index, buf);
return reader_->OnMemory(index, page_limits);
}
Result BinaryReaderLogging::BeginGlobal(Index index, Type type, bool mutable_) {
LOGF("BeginGlobal(index: %" PRIindex ", type: %s, mutable: %s)\n", index,
type.GetName(), mutable_ ? "true" : "false");
return reader_->BeginGlobal(index, type, mutable_);
}
Result BinaryReaderLogging::OnExport(Index index,
ExternalKind kind,
Index item_index,
string_view name) {
LOGF("OnExport(index: %" PRIindex ", kind: %s, item_index: %" PRIindex
", name: \"" PRIstringview "\")\n",
index, GetKindName(kind), item_index, WABT_PRINTF_STRING_VIEW_ARG(name));
return reader_->OnExport(index, kind, item_index, name);
}
Result BinaryReaderLogging::BeginFunctionBody(Index value, Offset size) {
LOGF("BeginFunctionBody(%" PRIindex ", size:%" PRIzd ")\n", value, size);
return reader_->BeginFunctionBody(value, size);
}
Result BinaryReaderLogging::OnLocalDecl(Index decl_index,
Index count,
Type type) {
LOGF("OnLocalDecl(index: %" PRIindex ", count: %" PRIindex ", type: %s)\n",
decl_index, count, type.GetName());
return reader_->OnLocalDecl(decl_index, count, type);
}
Result BinaryReaderLogging::OnBlockExpr(Type sig_type) {
LOGF("OnBlockExpr(sig: ");
LogType(sig_type);
LOGF_NOINDENT(")\n");
return reader_->OnBlockExpr(sig_type);
}
Result BinaryReaderLogging::OnBrExpr(Index depth) {
LOGF("OnBrExpr(depth: %" PRIindex ")\n", depth);
return reader_->OnBrExpr(depth);
}
Result BinaryReaderLogging::OnBrIfExpr(Index depth) {
LOGF("OnBrIfExpr(depth: %" PRIindex ")\n", depth);
return reader_->OnBrIfExpr(depth);
}
Result BinaryReaderLogging::OnBrTableExpr(Index num_targets,
Index* target_depths,
Index default_target_depth) {
LOGF("OnBrTableExpr(num_targets: %" PRIindex ", depths: [", num_targets);
for (Index i = 0; i < num_targets; ++i) {
LOGF_NOINDENT("%" PRIindex, target_depths[i]);
if (i != num_targets - 1) {
LOGF_NOINDENT(", ");
}
}
LOGF_NOINDENT("], default: %" PRIindex ")\n", default_target_depth);
return reader_->OnBrTableExpr(num_targets, target_depths,
default_target_depth);
}
Result BinaryReaderLogging::OnF32ConstExpr(uint32_t value_bits) {
float value;
memcpy(&value, &value_bits, sizeof(value));
LOGF("OnF32ConstExpr(%g (0x%08x))\n", value, value_bits);
return reader_->OnF32ConstExpr(value_bits);
}
Result BinaryReaderLogging::OnF64ConstExpr(uint64_t value_bits) {
double value;
memcpy(&value, &value_bits, sizeof(value));
LOGF("OnF64ConstExpr(%g (0x%016" PRIx64 "))\n", value, value_bits);
return reader_->OnF64ConstExpr(value_bits);
}
Result BinaryReaderLogging::OnV128ConstExpr(v128 value_bits) {
LOGF("OnV128ConstExpr(0x%08x 0x%08x 0x%08x 0x%08x)\n", value_bits.u32(0),
value_bits.u32(1), value_bits.u32(2), value_bits.u32(3));
return reader_->OnV128ConstExpr(value_bits);
}
Result BinaryReaderLogging::OnI32ConstExpr(uint32_t value) {
LOGF("OnI32ConstExpr(%u (0x%x))\n", value, value);
return reader_->OnI32ConstExpr(value);
}
Result BinaryReaderLogging::OnI64ConstExpr(uint64_t value) {
LOGF("OnI64ConstExpr(%" PRIu64 " (0x%" PRIx64 "))\n", value, value);
return reader_->OnI64ConstExpr(value);
}
Result BinaryReaderLogging::OnIfExpr(Type sig_type) {
LOGF("OnIfExpr(sig: ");
LogType(sig_type);
LOGF_NOINDENT(")\n");
return reader_->OnIfExpr(sig_type);
}
Result BinaryReaderLogging::OnLoopExpr(Type sig_type) {
LOGF("OnLoopExpr(sig: ");
LogType(sig_type);
LOGF_NOINDENT(")\n");
return reader_->OnLoopExpr(sig_type);
}
Result BinaryReaderLogging::OnSelectExpr(Index result_count,
Type* result_types) {
LOGF("OnSelectExpr(return_type: ");
LogTypes(result_count, result_types);
LOGF_NOINDENT(")\n");
return reader_->OnSelectExpr(result_count, result_types);
}
Result BinaryReaderLogging::OnTryExpr(Type sig_type) {
LOGF("OnTryExpr(sig: ");
LogType(sig_type);
LOGF_NOINDENT(")\n");
return reader_->OnTryExpr(sig_type);
}
Result BinaryReaderLogging::OnSimdLaneOpExpr(Opcode opcode, uint64_t value) {
LOGF("OnSimdLaneOpExpr (lane: %" PRIu64 ")\n", value);
return reader_->OnSimdLaneOpExpr(opcode, value);
}
Result BinaryReaderLogging::OnSimdShuffleOpExpr(Opcode opcode, v128 value) {
LOGF("OnSimdShuffleOpExpr (lane: 0x%08x %08x %08x %08x)\n", value.u32(0),
value.u32(1), value.u32(2), value.u32(3));
return reader_->OnSimdShuffleOpExpr(opcode, value);
}
Result BinaryReaderLogging::BeginElemSegment(Index index,
Index table_index,
uint8_t flags) {
LOGF("BeginElemSegment(index: %" PRIindex ", table_index: %" PRIindex
", flags: %d)\n",
index, table_index, flags);
return reader_->BeginElemSegment(index, table_index, flags);
}
Result BinaryReaderLogging::OnElemSegmentElemType(Index index, Type elem_type) {
LOGF("OnElemSegmentElemType(index: %" PRIindex ", type: %s)\n", index,
elem_type.GetName());
return reader_->OnElemSegmentElemType(index, elem_type);
}
Result BinaryReaderLogging::OnDataSegmentData(Index index,
const void* data,
Address size) {
LOGF("OnDataSegmentData(index:%" PRIindex ", size:%" PRIaddress ")\n", index,
size);
return reader_->OnDataSegmentData(index, data, size);
}
Result BinaryReaderLogging::OnModuleNameSubsection(Index index,
uint32_t name_type,
Offset subsection_size) {
LOGF("OnModuleNameSubsection(index:%" PRIindex ", nametype:%u, size:%" PRIzd
")\n",
index, name_type, subsection_size);
return reader_->OnModuleNameSubsection(index, name_type, subsection_size);
}
Result BinaryReaderLogging::OnModuleName(string_view name) {
LOGF("OnModuleName(name: \"" PRIstringview "\")\n",
WABT_PRINTF_STRING_VIEW_ARG(name));
return reader_->OnModuleName(name);
}
Result BinaryReaderLogging::OnFunctionNameSubsection(Index index,
uint32_t name_type,
Offset subsection_size) {
LOGF("OnFunctionNameSubsection(index:%" PRIindex ", nametype:%u, size:%" PRIzd
")\n",
index, name_type, subsection_size);
return reader_->OnFunctionNameSubsection(index, name_type, subsection_size);
}
Result BinaryReaderLogging::OnFunctionName(Index index, string_view name) {
LOGF("OnFunctionName(index: %" PRIindex ", name: \"" PRIstringview "\")\n",
index, WABT_PRINTF_STRING_VIEW_ARG(name));
return reader_->OnFunctionName(index, name);
}
Result BinaryReaderLogging::OnLocalNameSubsection(Index index,
uint32_t name_type,
Offset subsection_size) {
LOGF("OnLocalNameSubsection(index:%" PRIindex ", nametype:%u, size:%" PRIzd
")\n",
index, name_type, subsection_size);
return reader_->OnLocalNameSubsection(index, name_type, subsection_size);
}
Result BinaryReaderLogging::OnLocalName(Index func_index,
Index local_index,
string_view name) {
LOGF("OnLocalName(func_index: %" PRIindex ", local_index: %" PRIindex
", name: \"" PRIstringview "\")\n",
func_index, local_index, WABT_PRINTF_STRING_VIEW_ARG(name));
return reader_->OnLocalName(func_index, local_index, name);
}
Result BinaryReaderLogging::OnNameSubsection(
Index index,
NameSectionSubsection subsection_type,
Offset subsection_size) {
LOGF("OnNameSubsection(index: %" PRIindex ", type: %s, size:%" PRIzd ")\n",
index, GetNameSectionSubsectionName(subsection_type), subsection_size);
return reader_->OnNameSubsection(index, subsection_type, subsection_size);
}
Result BinaryReaderLogging::OnNameEntry(NameSectionSubsection type,
Index index,
string_view name) {
LOGF("OnNameEntry(type: %s, index: %" PRIindex ", name: \"" PRIstringview
"\")\n",
GetNameSectionSubsectionName(type), index,
WABT_PRINTF_STRING_VIEW_ARG(name));
return reader_->OnNameEntry(type, index, name);
}
Result BinaryReaderLogging::OnInitExprF32ConstExpr(Index index,
uint32_t value_bits) {
float value;
memcpy(&value, &value_bits, sizeof(value));
LOGF("OnInitExprF32ConstExpr(index: %" PRIindex ", value: %g (0x04%x))\n",
index, value, value_bits);
return reader_->OnInitExprF32ConstExpr(index, value_bits);
}
Result BinaryReaderLogging::OnInitExprF64ConstExpr(Index index,
uint64_t value_bits) {
double value;
memcpy(&value, &value_bits, sizeof(value));
LOGF("OnInitExprF64ConstExpr(index: %" PRIindex " value: %g (0x08%" PRIx64
"))\n",
index, value, value_bits);
return reader_->OnInitExprF64ConstExpr(index, value_bits);
}
Result BinaryReaderLogging::OnInitExprV128ConstExpr(Index index,
v128 value_bits) {
LOGF("OnInitExprV128ConstExpr(index: %" PRIindex
" value: ( 0x%08x 0x%08x 0x%08x 0x%08x))\n",
index, value_bits.u32(0), value_bits.u32(1), value_bits.u32(2),
value_bits.u32(3));
return reader_->OnInitExprV128ConstExpr(index, value_bits);
}
Result BinaryReaderLogging::OnInitExprI32ConstExpr(Index index,
uint32_t value) {
LOGF("OnInitExprI32ConstExpr(index: %" PRIindex ", value: %u)\n", index,
value);
return reader_->OnInitExprI32ConstExpr(index, value);
}
Result BinaryReaderLogging::OnInitExprI64ConstExpr(Index index,
uint64_t value) {
LOGF("OnInitExprI64ConstExpr(index: %" PRIindex ", value: %" PRIu64 ")\n",
index, value);
return reader_->OnInitExprI64ConstExpr(index, value);
}
Result BinaryReaderLogging::OnDylinkInfo(uint32_t mem_size,
uint32_t mem_align,
uint32_t table_size,
uint32_t table_align) {
LOGF(
"OnDylinkInfo(mem_size: %u, mem_align: %u, table_size: %u, table_align: "
"%u)\n",
mem_size, mem_align, table_size, table_align);
return reader_->OnDylinkInfo(mem_size, mem_align, table_size, table_align);
}
Result BinaryReaderLogging::OnDylinkNeeded(string_view so_name) {
LOGF("OnDylinkNeeded(name: " PRIstringview ")\n",
WABT_PRINTF_STRING_VIEW_ARG(so_name));
return reader_->OnDylinkNeeded(so_name);
}
Result BinaryReaderLogging::OnRelocCount(Index count,
Index section_index) {
LOGF("OnRelocCount(count: %" PRIindex ", section: %" PRIindex ")\n", count,
section_index);
return reader_->OnRelocCount(count, section_index);
}
Result BinaryReaderLogging::OnReloc(RelocType type,
Offset offset,
Index index,
uint32_t addend) {
int32_t signed_addend = static_cast<int32_t>(addend);
LOGF("OnReloc(type: %s, offset: %" PRIzd ", index: %" PRIindex
", addend: %d)\n",
GetRelocTypeName(type), offset, index, signed_addend);
return reader_->OnReloc(type, offset, index, addend);
}
Result BinaryReaderLogging::OnSymbol(Index symbol_index,
SymbolType type,
uint32_t flags) {
LOGF("OnSymbol(type: %s flags: 0x%x)\n", GetSymbolTypeName(type), flags);
return reader_->OnSymbol(symbol_index, type, flags);
}
Result BinaryReaderLogging::OnDataSymbol(Index index,
uint32_t flags,
string_view name,
Index segment,
uint32_t offset,
uint32_t size) {
LOGF("OnDataSymbol(name: " PRIstringview " flags: 0x%x)\n",
WABT_PRINTF_STRING_VIEW_ARG(name), flags);
return reader_->OnDataSymbol(index, flags, name, segment, offset, size);
}
Result BinaryReaderLogging::OnFunctionSymbol(Index index,
uint32_t flags,
string_view name,
Index func_index) {
LOGF("OnFunctionSymbol(name: " PRIstringview " flags: 0x%x index: %" PRIindex
")\n",
WABT_PRINTF_STRING_VIEW_ARG(name), flags, func_index);
return reader_->OnFunctionSymbol(index, flags, name, func_index);
}
Result BinaryReaderLogging::OnGlobalSymbol(Index index,
uint32_t flags,
string_view name,
Index global_index) {
LOGF("OnGlobalSymbol(name: " PRIstringview " flags: 0x%x index: %" PRIindex
")\n",
WABT_PRINTF_STRING_VIEW_ARG(name), flags, global_index);
return reader_->OnGlobalSymbol(index, flags, name, global_index);
}
Result BinaryReaderLogging::OnSectionSymbol(Index index,
uint32_t flags,
Index section_index) {
LOGF("OnSectionSymbol(flags: 0x%x index: %" PRIindex ")\n", flags,
section_index);
return reader_->OnSectionSymbol(index, flags, section_index);
}
Result BinaryReaderLogging::OnEventSymbol(Index index,
uint32_t flags,
string_view name,
Index event_index) {
LOGF("OnEventSymbol(name: " PRIstringview " flags: 0x%x index: %" PRIindex
")\n",
WABT_PRINTF_STRING_VIEW_ARG(name), flags, event_index);
return reader_->OnEventSymbol(index, flags, name, event_index);
}
Result BinaryReaderLogging::OnTableSymbol(Index index,
uint32_t flags,
string_view name,
Index table_index) {
LOGF("OnTableSymbol(name: " PRIstringview " flags: 0x%x index: %" PRIindex
")\n",
WABT_PRINTF_STRING_VIEW_ARG(name), flags, table_index);
return reader_->OnTableSymbol(index, flags, name, table_index);
}
Result BinaryReaderLogging::OnSegmentInfo(Index index,
string_view name,
Address alignment,
uint32_t flags) {
LOGF("OnSegmentInfo(%d name: " PRIstringview ", alignment: %" PRIaddress
", flags: 0x%x)\n",
index, WABT_PRINTF_STRING_VIEW_ARG(name), alignment, flags);
return reader_->OnSegmentInfo(index, name, alignment, flags);
}
Result BinaryReaderLogging::OnInitFunction(uint32_t priority,
Index func_index) {
LOGF("OnInitFunction(%d priority: %d)\n", func_index, priority);
return reader_->OnInitFunction(priority, func_index);
}
Result BinaryReaderLogging::OnComdatBegin(string_view name,
uint32_t flags,
Index count) {
LOGF("OnComdatBegin(" PRIstringview ", flags: %d, count: %" PRIindex ")\n",
WABT_PRINTF_STRING_VIEW_ARG(name), flags, count);
return reader_->OnComdatBegin(name, flags, count);
}
Result BinaryReaderLogging::OnComdatEntry(ComdatType kind, Index index) {
LOGF("OnComdatEntry(kind: %d, index: %" PRIindex ")\n",
static_cast<int>(kind), index);
return reader_->OnComdatEntry(kind, index);
}
#define DEFINE_BEGIN(name) \
Result BinaryReaderLogging::name(Offset size) { \
LOGF(#name "(%" PRIzd ")\n", size); \
Indent(); \
return reader_->name(size); \
}
#define DEFINE_END(name) \
Result BinaryReaderLogging::name() { \
Dedent(); \
LOGF(#name "\n"); \
return reader_->name(); \
}
#define DEFINE_INDEX(name) \
Result BinaryReaderLogging::name(Index value) { \
LOGF(#name "(%" PRIindex ")\n", value); \
return reader_->name(value); \
}
#define DEFINE_TYPE(name) \
Result BinaryReaderLogging::name(Type type) { \
LOGF(#name "(%s)\n", type.GetName()); \
return reader_->name(type); \
}
#define DEFINE_INDEX_DESC(name, desc) \
Result BinaryReaderLogging::name(Index value) { \
LOGF(#name "(" desc ": %" PRIindex ")\n", value); \
return reader_->name(value); \
}
#define DEFINE_INDEX_TYPE(name) \
Result BinaryReaderLogging::name(Index value, Type type) { \
LOGF(#name "(index: %" PRIindex ", type: %s)\n", value, type.GetName()); \
return reader_->name(value, type); \
}
#define DEFINE_INDEX_INDEX(name, desc0, desc1) \
Result BinaryReaderLogging::name(Index value0, Index value1) { \
LOGF(#name "(" desc0 ": %" PRIindex ", " desc1 ": %" PRIindex ")\n", \
value0, value1); \
return reader_->name(value0, value1); \
}
#define DEFINE_INDEX_INDEX_U8(name, desc0, desc1, desc2) \
Result BinaryReaderLogging::name(Index value0, Index value1, \
uint8_t value2) { \
LOGF(#name "(" desc0 ": %" PRIindex ", " desc1 ": %" PRIindex ", " desc2 \
": %d)\n", \
value0, value1, value2); \
return reader_->name(value0, value1, value2); \
}
#define DEFINE_OPCODE(name) \
Result BinaryReaderLogging::name(Opcode opcode) { \
LOGF(#name "(\"%s\" (%u))\n", opcode.GetName(), opcode.GetCode()); \
return reader_->name(opcode); \
}
#define DEFINE_LOAD_STORE_OPCODE(name) \
Result BinaryReaderLogging::name(Opcode opcode, Address alignment_log2, \
Address offset) { \
LOGF(#name "(opcode: \"%s\" (%u), align log2: %" PRIaddress \
", offset: %" PRIaddress ")\n", \
opcode.GetName(), opcode.GetCode(), alignment_log2, offset); \
return reader_->name(opcode, alignment_log2, offset); \
}
#define DEFINE_SIMD_LOAD_STORE_LANE_OPCODE(name) \
Result BinaryReaderLogging::name(Opcode opcode, Address alignment_log2, \
Address offset, uint64_t value) { \
LOGF(#name "(opcode: \"%s\" (%u), align log2: %" PRIaddress \
", offset: %" PRIaddress ", lane: %" PRIu64 ")\n", \
opcode.GetName(), opcode.GetCode(), alignment_log2, offset, value); \
return reader_->name(opcode, alignment_log2, offset, value); \
}
#define DEFINE0(name) \
Result BinaryReaderLogging::name() { \
LOGF(#name "\n"); \
return reader_->name(); \
}
DEFINE_END(EndModule)
DEFINE_END(EndCustomSection)
DEFINE_BEGIN(BeginTypeSection)
DEFINE_INDEX(OnTypeCount)
DEFINE_END(EndTypeSection)
DEFINE_BEGIN(BeginImportSection)
DEFINE_INDEX(OnImportCount)
DEFINE_END(EndImportSection)
DEFINE_BEGIN(BeginFunctionSection)
DEFINE_INDEX(OnFunctionCount)
DEFINE_INDEX_INDEX(OnFunction, "index", "sig_index")
DEFINE_END(EndFunctionSection)
DEFINE_BEGIN(BeginTableSection)
DEFINE_INDEX(OnTableCount)
DEFINE_END(EndTableSection)
DEFINE_BEGIN(BeginMemorySection)
DEFINE_INDEX(OnMemoryCount)
DEFINE_END(EndMemorySection)
DEFINE_BEGIN(BeginGlobalSection)
DEFINE_INDEX(OnGlobalCount)
DEFINE_INDEX(BeginGlobalInitExpr)
DEFINE_INDEX(EndGlobalInitExpr)
DEFINE_INDEX(EndGlobal)
DEFINE_END(EndGlobalSection)
DEFINE_BEGIN(BeginExportSection)
DEFINE_INDEX(OnExportCount)
DEFINE_END(EndExportSection)
DEFINE_BEGIN(BeginStartSection)
DEFINE_INDEX(OnStartFunction)
DEFINE_END(EndStartSection)
DEFINE_BEGIN(BeginCodeSection)
DEFINE_INDEX(OnFunctionBodyCount)
DEFINE_INDEX(EndFunctionBody)
DEFINE_INDEX(OnLocalDeclCount)
DEFINE_LOAD_STORE_OPCODE(OnAtomicLoadExpr);
DEFINE_LOAD_STORE_OPCODE(OnAtomicRmwExpr);
DEFINE_LOAD_STORE_OPCODE(OnAtomicRmwCmpxchgExpr);
DEFINE_LOAD_STORE_OPCODE(OnAtomicStoreExpr);
DEFINE_LOAD_STORE_OPCODE(OnAtomicWaitExpr);
DEFINE_INDEX_DESC(OnAtomicFenceExpr, "consistency_model");
DEFINE_LOAD_STORE_OPCODE(OnAtomicNotifyExpr);
DEFINE_OPCODE(OnBinaryExpr)
DEFINE_INDEX_DESC(OnCallExpr, "func_index")
DEFINE_INDEX_INDEX(OnCallIndirectExpr, "sig_index", "table_index")
DEFINE_INDEX_DESC(OnCatchExpr, "event_index");
DEFINE0(OnCatchAllExpr);
DEFINE_OPCODE(OnCompareExpr)
DEFINE_OPCODE(OnConvertExpr)
DEFINE_INDEX_DESC(OnDelegateExpr, "depth");
DEFINE0(OnDropExpr)
DEFINE0(OnElseExpr)
DEFINE0(OnEndExpr)
DEFINE_INDEX_DESC(OnGlobalGetExpr, "index")
DEFINE_INDEX_DESC(OnGlobalSetExpr, "index")
DEFINE_LOAD_STORE_OPCODE(OnLoadExpr);
DEFINE_INDEX_DESC(OnLocalGetExpr, "index")
DEFINE_INDEX_DESC(OnLocalSetExpr, "index")
DEFINE_INDEX_DESC(OnLocalTeeExpr, "index")
DEFINE0(OnMemoryCopyExpr)
DEFINE_INDEX(OnDataDropExpr)
DEFINE0(OnMemoryFillExpr)
DEFINE0(OnMemoryGrowExpr)
DEFINE_INDEX(OnMemoryInitExpr)
DEFINE0(OnMemorySizeExpr)
DEFINE_INDEX_INDEX(OnTableCopyExpr, "dst_index", "src_index")
DEFINE_INDEX(OnElemDropExpr)
DEFINE_INDEX_INDEX(OnTableInitExpr, "segment_index", "table_index")
DEFINE_INDEX(OnTableSetExpr)
DEFINE_INDEX(OnTableGetExpr)
DEFINE_INDEX(OnTableGrowExpr)
DEFINE_INDEX(OnTableSizeExpr)
DEFINE_INDEX_DESC(OnTableFillExpr, "table index")
DEFINE_INDEX(OnRefFuncExpr)
DEFINE_TYPE(OnRefNullExpr)
DEFINE0(OnRefIsNullExpr)
DEFINE0(OnNopExpr)
DEFINE_INDEX_DESC(OnRethrowExpr, "depth");
DEFINE_INDEX_DESC(OnReturnCallExpr, "func_index")
DEFINE_INDEX_INDEX(OnReturnCallIndirectExpr, "sig_index", "table_index")
DEFINE0(OnReturnExpr)
DEFINE_LOAD_STORE_OPCODE(OnLoadSplatExpr);
DEFINE_LOAD_STORE_OPCODE(OnLoadZeroExpr);
DEFINE_LOAD_STORE_OPCODE(OnStoreExpr);
DEFINE_INDEX_DESC(OnThrowExpr, "event_index")
DEFINE0(OnUnreachableExpr)
DEFINE0(OnUnwindExpr)
DEFINE_OPCODE(OnUnaryExpr)
DEFINE_OPCODE(OnTernaryExpr)
DEFINE_SIMD_LOAD_STORE_LANE_OPCODE(OnSimdLoadLaneExpr);
DEFINE_SIMD_LOAD_STORE_LANE_OPCODE(OnSimdStoreLaneExpr);
DEFINE_END(EndCodeSection)
DEFINE_BEGIN(BeginElemSection)
DEFINE_INDEX(OnElemSegmentCount)
DEFINE_INDEX(BeginElemSegmentInitExpr)
DEFINE_INDEX(EndElemSegmentInitExpr)
DEFINE_INDEX_INDEX(OnElemSegmentElemExprCount, "index", "count")
DEFINE_INDEX_TYPE(OnElemSegmentElemExpr_RefNull)
DEFINE_INDEX_INDEX(OnElemSegmentElemExpr_RefFunc, "index", "func_index")
DEFINE_INDEX(EndElemSegment)
DEFINE_END(EndElemSection)
DEFINE_BEGIN(BeginDataSection)
DEFINE_INDEX(OnDataSegmentCount)
DEFINE_INDEX_INDEX_U8(BeginDataSegment, "index", "memory_index", "flags")
DEFINE_INDEX(BeginDataSegmentInitExpr)
DEFINE_INDEX(EndDataSegmentInitExpr)
DEFINE_INDEX(EndDataSegment)
DEFINE_END(EndDataSection)
DEFINE_BEGIN(BeginDataCountSection)
DEFINE_INDEX(OnDataCount)
DEFINE_END(EndDataCountSection)
DEFINE_BEGIN(BeginNamesSection)
DEFINE_INDEX(OnFunctionNamesCount)
DEFINE_INDEX(OnLocalNameFunctionCount)
DEFINE_INDEX_INDEX(OnLocalNameLocalCount, "index", "count")
DEFINE_INDEX(OnNameCount);
DEFINE_END(EndNamesSection)
DEFINE_BEGIN(BeginRelocSection)
DEFINE_END(EndRelocSection)
DEFINE_INDEX_INDEX(OnInitExprGlobalGetExpr, "index", "global_index")
DEFINE_INDEX_TYPE(OnInitExprRefNull)
DEFINE_INDEX_INDEX(OnInitExprRefFunc, "index", "func_index")
DEFINE_BEGIN(BeginDylinkSection)
DEFINE_INDEX(OnDylinkNeededCount)
DEFINE_END(EndDylinkSection)
DEFINE_BEGIN(BeginLinkingSection)
DEFINE_INDEX(OnSymbolCount)
DEFINE_INDEX(OnSegmentInfoCount)
DEFINE_INDEX(OnInitFunctionCount)
DEFINE_INDEX(OnComdatCount)
DEFINE_END(EndLinkingSection)
DEFINE_BEGIN(BeginEventSection);
DEFINE_INDEX(OnEventCount);
DEFINE_INDEX_INDEX(OnEventType, "index", "sig_index")
DEFINE_END(EndEventSection);
// We don't need to log these (the individual opcodes are logged instead), but
// we still need to forward the calls.
Result BinaryReaderLogging::OnOpcode(Opcode opcode) {
return reader_->OnOpcode(opcode);
}
Result BinaryReaderLogging::OnOpcodeBare() {
return reader_->OnOpcodeBare();
}
Result BinaryReaderLogging::OnOpcodeIndex(Index value) {
return reader_->OnOpcodeIndex(value);
}
Result BinaryReaderLogging::OnOpcodeIndexIndex(Index value, Index value2) {
return reader_->OnOpcodeIndexIndex(value, value2);
}
Result BinaryReaderLogging::OnOpcodeUint32(uint32_t value) {
return reader_->OnOpcodeUint32(value);
}
Result BinaryReaderLogging::OnOpcodeUint32Uint32(uint32_t value,
uint32_t value2) {
return reader_->OnOpcodeUint32Uint32(value, value2);
}
Result BinaryReaderLogging::OnOpcodeUint32Uint32Uint32(uint32_t value,
uint32_t value2,
uint32_t value3) {
return reader_->OnOpcodeUint32Uint32Uint32(value, value2, value3);
}
Result BinaryReaderLogging::OnOpcodeUint64(uint64_t value) {
return reader_->OnOpcodeUint64(value);
}
Result BinaryReaderLogging::OnOpcodeF32(uint32_t value) {
return reader_->OnOpcodeF32(value);
}
Result BinaryReaderLogging::OnOpcodeF64(uint64_t value) {
return reader_->OnOpcodeF64(value);
}
Result BinaryReaderLogging::OnOpcodeV128(v128 value) {
return reader_->OnOpcodeV128(value);
}
Result BinaryReaderLogging::OnOpcodeBlockSig(Type sig_type) {
return reader_->OnOpcodeBlockSig(sig_type);
}
Result BinaryReaderLogging::OnOpcodeType(Type type) {
return reader_->OnOpcodeType(type);
}
Result BinaryReaderLogging::OnEndFunc() {
return reader_->OnEndFunc();
}
} // namespace wabt

View File

@@ -0,0 +1,399 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_BINARY_READER_LOGGING_H_
#define WABT_BINARY_READER_LOGGING_H_
#include "src/binary-reader.h"
namespace wabt {
class Stream;
class BinaryReaderLogging : public BinaryReaderDelegate {
public:
BinaryReaderLogging(Stream*, BinaryReaderDelegate* forward);
bool OnError(const Error&) override;
void OnSetState(const State* s) override;
Result BeginModule(uint32_t version) override;
Result EndModule() override;
Result BeginSection(Index section_index,
BinarySection section_type,
Offset size) override;
Result BeginCustomSection(Index section_index,
Offset size,
string_view section_name) override;
Result EndCustomSection() override;
Result BeginTypeSection(Offset size) override;
Result OnTypeCount(Index count) override;
Result OnFuncType(Index index,
Index param_count,
Type* param_types,
Index result_count,
Type* result_types) override;
Result OnStructType(Index index, Index field_count, TypeMut* fields) override;
Result OnArrayType(Index index, TypeMut field) override;
Result EndTypeSection() override;
Result BeginImportSection(Offset size) override;
Result OnImportCount(Index count) override;
Result OnImport(Index index,
ExternalKind kind,
string_view module_name,
string_view field_name) override;
Result OnImportFunc(Index import_index,
string_view module_name,
string_view field_name,
Index func_index,
Index sig_index) override;
Result OnImportTable(Index import_index,
string_view module_name,
string_view field_name,
Index table_index,
Type elem_type,
const Limits* elem_limits) override;
Result OnImportMemory(Index import_index,
string_view module_name,
string_view field_name,
Index memory_index,
const Limits* page_limits) override;
Result OnImportGlobal(Index import_index,
string_view module_name,
string_view field_name,
Index global_index,
Type type,
bool mutable_) override;
Result OnImportEvent(Index import_index,
string_view module_name,
string_view field_name,
Index event_index,
Index sig_index) override;
Result EndImportSection() override;
Result BeginFunctionSection(Offset size) override;
Result OnFunctionCount(Index count) override;
Result OnFunction(Index index, Index sig_index) override;
Result EndFunctionSection() override;
Result BeginTableSection(Offset size) override;
Result OnTableCount(Index count) override;
Result OnTable(Index index,
Type elem_type,
const Limits* elem_limits) override;
Result EndTableSection() override;
Result BeginMemorySection(Offset size) override;
Result OnMemoryCount(Index count) override;
Result OnMemory(Index index, const Limits* limits) override;
Result EndMemorySection() override;
Result BeginGlobalSection(Offset size) override;
Result OnGlobalCount(Index count) override;
Result BeginGlobal(Index index, Type type, bool mutable_) override;
Result BeginGlobalInitExpr(Index index) override;
Result EndGlobalInitExpr(Index index) override;
Result EndGlobal(Index index) override;
Result EndGlobalSection() override;
Result BeginExportSection(Offset size) override;
Result OnExportCount(Index count) override;
Result OnExport(Index index,
ExternalKind kind,
Index item_index,
string_view name) override;
Result EndExportSection() override;
Result BeginStartSection(Offset size) override;
Result OnStartFunction(Index func_index) override;
Result EndStartSection() override;
Result BeginCodeSection(Offset size) override;
Result OnFunctionBodyCount(Index count) override;
Result BeginFunctionBody(Index index, Offset size) override;
Result OnLocalDeclCount(Index count) override;
Result OnLocalDecl(Index decl_index, Index count, Type type) override;
Result OnOpcode(Opcode opcode) override;
Result OnOpcodeBare() override;
Result OnOpcodeIndex(Index value) override;
Result OnOpcodeIndexIndex(Index value, Index value2) override;
Result OnOpcodeUint32(uint32_t value) override;
Result OnOpcodeUint32Uint32(uint32_t value, uint32_t value2) override;
Result OnOpcodeUint32Uint32Uint32(uint32_t value,
uint32_t value2,
uint32_t value3) override;
Result OnOpcodeUint64(uint64_t value) override;
Result OnOpcodeF32(uint32_t value) override;
Result OnOpcodeF64(uint64_t value) override;
Result OnOpcodeV128(v128 value) override;
Result OnOpcodeBlockSig(Type sig_type) override;
Result OnOpcodeType(Type type) override;
Result OnAtomicLoadExpr(Opcode opcode,
Address alignment_log2,
Address offset) override;
Result OnAtomicStoreExpr(Opcode opcode,
Address alignment_log2,
Address offset) override;
Result OnAtomicRmwExpr(Opcode opcode,
Address alignment_log2,
Address offset) override;
Result OnAtomicRmwCmpxchgExpr(Opcode opcode,
Address alignment_log2,
Address offset) override;
Result OnBinaryExpr(Opcode opcode) override;
Result OnBlockExpr(Type sig_type) override;
Result OnBrExpr(Index depth) override;
Result OnBrIfExpr(Index depth) override;
Result OnBrTableExpr(Index num_targets,
Index* target_depths,
Index default_target_depth) override;
Result OnCallExpr(Index func_index) override;
Result OnCatchExpr(Index event_index) override;
Result OnCatchAllExpr() override;
Result OnCallIndirectExpr(Index sig_index, Index table_index) override;
Result OnCompareExpr(Opcode opcode) override;
Result OnConvertExpr(Opcode opcode) override;
Result OnDelegateExpr(Index depth) override;
Result OnDropExpr() override;
Result OnElseExpr() override;
Result OnEndExpr() override;
Result OnEndFunc() override;
Result OnF32ConstExpr(uint32_t value_bits) override;
Result OnF64ConstExpr(uint64_t value_bits) override;
Result OnV128ConstExpr(v128 value_bits) override;
Result OnGlobalGetExpr(Index global_index) override;
Result OnGlobalSetExpr(Index global_index) override;
Result OnI32ConstExpr(uint32_t value) override;
Result OnI64ConstExpr(uint64_t value) override;
Result OnIfExpr(Type sig_type) override;
Result OnLoadExpr(Opcode opcode,
Address alignment_log2,
Address offset) override;
Result OnLocalGetExpr(Index local_index) override;
Result OnLocalSetExpr(Index local_index) override;
Result OnLocalTeeExpr(Index local_index) override;
Result OnLoopExpr(Type sig_type) override;
Result OnMemoryCopyExpr() override;
Result OnDataDropExpr(Index segment_index) override;
Result OnMemoryFillExpr() override;
Result OnMemoryGrowExpr() override;
Result OnMemoryInitExpr(Index segment_index) override;
Result OnMemorySizeExpr() override;
Result OnTableCopyExpr(Index dst_index, Index src_index) override;
Result OnElemDropExpr(Index segment_index) override;
Result OnTableInitExpr(Index segment_index, Index table_index) override;
Result OnTableGetExpr(Index table) override;
Result OnTableSetExpr(Index table) override;
Result OnTableGrowExpr(Index table) override;
Result OnTableSizeExpr(Index table) override;
Result OnTableFillExpr(Index table) override;
Result OnRefFuncExpr(Index index) override;
Result OnRefNullExpr(Type type) override;
Result OnRefIsNullExpr() override;
Result OnNopExpr() override;
Result OnRethrowExpr(Index depth) override;
Result OnReturnCallExpr(Index func_index) override;
Result OnReturnCallIndirectExpr(Index sig_index, Index table_index) override;
Result OnReturnExpr() override;
Result OnSelectExpr(Index result_count, Type* result_types) override;
Result OnStoreExpr(Opcode opcode,
Address alignment_log2,
Address offset) override;
Result OnThrowExpr(Index event_index) override;
Result OnTryExpr(Type sig_type) override;
Result OnUnaryExpr(Opcode opcode) override;
Result OnTernaryExpr(Opcode opcode) override;
Result OnUnreachableExpr() override;
Result OnUnwindExpr() override;
Result OnAtomicWaitExpr(Opcode opcode,
Address alignment_log2,
Address offset) override;
Result OnAtomicFenceExpr(uint32_t consistency_model) override;
Result OnAtomicNotifyExpr(Opcode opcode,
Address alignment_log2,
Address offset) override;
Result EndFunctionBody(Index index) override;
Result EndCodeSection() override;
Result OnSimdLaneOpExpr(Opcode opcode, uint64_t value) override;
Result OnSimdLoadLaneExpr(Opcode opcode,
Address alignment_log2,
Address offset,
uint64_t value) override;
Result OnSimdStoreLaneExpr(Opcode opcode,
Address alignment_log2,
Address offset,
uint64_t value) override;
Result OnSimdShuffleOpExpr(Opcode opcode, v128 value) override;
Result OnLoadSplatExpr(Opcode opcode,
Address alignment_log2,
Address offset) override;
Result OnLoadZeroExpr(Opcode opcode,
Address alignment_log2,
Address offset) override;
Result BeginElemSection(Offset size) override;
Result OnElemSegmentCount(Index count) override;
Result BeginElemSegment(Index index,
Index table_index,
uint8_t flags) override;
Result BeginElemSegmentInitExpr(Index index) override;
Result EndElemSegmentInitExpr(Index index) override;
Result OnElemSegmentElemType(Index index, Type elem_type) override;
Result OnElemSegmentElemExprCount(Index index, Index count) override;
Result OnElemSegmentElemExpr_RefNull(Index segment_index, Type type) override;
Result OnElemSegmentElemExpr_RefFunc(Index segment_index,
Index func_index) override;
Result EndElemSegment(Index index) override;
Result EndElemSection() override;
Result BeginDataSection(Offset size) override;
Result OnDataSegmentCount(Index count) override;
Result BeginDataSegment(Index index,
Index memory_index,
uint8_t flags) override;
Result BeginDataSegmentInitExpr(Index index) override;
Result EndDataSegmentInitExpr(Index index) override;
Result OnDataSegmentData(Index index,
const void* data,
Address size) override;
Result EndDataSegment(Index index) override;
Result EndDataSection() override;
Result BeginDataCountSection(Offset size) override;
Result OnDataCount(Index count) override;
Result EndDataCountSection() override;
Result BeginNamesSection(Offset size) override;
Result OnModuleNameSubsection(Index index,
uint32_t name_type,
Offset subsection_size) override;
Result OnModuleName(string_view name) override;
Result OnFunctionNameSubsection(Index index,
uint32_t name_type,
Offset subsection_size) override;
Result OnFunctionNamesCount(Index num_functions) override;
Result OnFunctionName(Index function_index,
string_view function_name) override;
Result OnLocalNameSubsection(Index index,
uint32_t name_type,
Offset subsection_size) override;
Result OnLocalNameFunctionCount(Index num_functions) override;
Result OnLocalNameLocalCount(Index function_index, Index num_locals) override;
Result OnLocalName(Index function_index,
Index local_index,
string_view local_name) override;
Result OnNameSubsection(Index index,
NameSectionSubsection subsection_type,
Offset subsection_size) override;
Result OnNameEntry(NameSectionSubsection type,
Index index,
string_view name) override;
Result OnNameCount(Index num_names) override;
Result EndNamesSection() override;
Result BeginRelocSection(Offset size) override;
Result OnRelocCount(Index count, Index section_index) override;
Result OnReloc(RelocType type,
Offset offset,
Index index,
uint32_t addend) override;
Result EndRelocSection() override;
Result BeginDylinkSection(Offset size) override;
Result OnDylinkInfo(uint32_t mem_size,
uint32_t mem_align,
uint32_t table_size,
uint32_t table_align) override;
Result OnDylinkNeededCount(Index count) override;
Result OnDylinkNeeded(string_view needed) override;
Result EndDylinkSection() override;
Result BeginLinkingSection(Offset size) override;
Result OnSymbolCount(Index count) override;
Result OnSymbol(Index sybmol_index, SymbolType type, uint32_t flags) override;
Result OnDataSymbol(Index index,
uint32_t flags,
string_view name,
Index segment,
uint32_t offset,
uint32_t size) override;
Result OnFunctionSymbol(Index index,
uint32_t flags,
string_view name,
Index func_index) override;
Result OnGlobalSymbol(Index index,
uint32_t flags,
string_view name,
Index global_index) override;
Result OnSectionSymbol(Index index,
uint32_t flags,
Index section_index) override;
Result OnEventSymbol(Index index,
uint32_t flags,
string_view name,
Index event_index) override;
Result OnTableSymbol(Index index,
uint32_t flags,
string_view name,
Index event_index) override;
Result OnSegmentInfoCount(Index count) override;
Result OnSegmentInfo(Index index,
string_view name,
Address alignment,
uint32_t flags) override;
Result OnInitFunctionCount(Index count) override;
Result OnInitFunction(uint32_t priority, Index function_index) override;
Result OnComdatCount(Index count) override;
Result OnComdatBegin(string_view name, uint32_t flags, Index count) override;
Result OnComdatEntry(ComdatType kind, Index index) override;
Result EndLinkingSection() override;
Result BeginEventSection(Offset size) override;
Result OnEventCount(Index count) override;
Result OnEventType(Index index, Index sig_index) override;
Result EndEventSection() override;
Result OnInitExprF32ConstExpr(Index index, uint32_t value) override;
Result OnInitExprF64ConstExpr(Index index, uint64_t value) override;
Result OnInitExprV128ConstExpr(Index index, v128 value) override;
Result OnInitExprGlobalGetExpr(Index index, Index global_index) override;
Result OnInitExprI32ConstExpr(Index index, uint32_t value) override;
Result OnInitExprI64ConstExpr(Index index, uint64_t value) override;
Result OnInitExprRefNull(Index index, Type type) override;
Result OnInitExprRefFunc(Index index, Index func_index) override;
private:
void Indent();
void Dedent();
void WriteIndent();
void LogType(Type type);
void LogTypes(Index type_count, Type* types);
void LogTypes(TypeVector& types);
void LogField(TypeMut field);
Stream* stream_;
BinaryReaderDelegate* reader_;
int indent_;
};
} // namespace wabt
#endif // WABT_BINARY_READER_LOGGING_H_

View File

@@ -0,0 +1,567 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_BINARY_READER_NOP_H_
#define WABT_BINARY_READER_NOP_H_
#include "src/binary-reader.h"
namespace wabt {
class BinaryReaderNop : public BinaryReaderDelegate {
public:
bool OnError(const Error&) override { return false; }
/* Module */
Result BeginModule(uint32_t version) override { return Result::Ok; }
Result EndModule() override { return Result::Ok; }
Result BeginSection(Index section_index,
BinarySection section_type,
Offset size) override {
return Result::Ok;
}
/* Custom section */
Result BeginCustomSection(Index section_index,
Offset size,
string_view section_name) override {
return Result::Ok;
}
Result EndCustomSection() override { return Result::Ok; }
/* Type section */
Result BeginTypeSection(Offset size) override { return Result::Ok; }
Result OnTypeCount(Index count) override { return Result::Ok; }
Result OnFuncType(Index index,
Index param_count,
Type* param_types,
Index result_count,
Type* result_types) override {
return Result::Ok;
}
Result OnStructType(Index index,
Index field_count,
TypeMut* fields) override {
return Result::Ok;
}
Result OnArrayType(Index index, TypeMut field) override {
return Result::Ok;
}
Result EndTypeSection() override { return Result::Ok; }
/* Import section */
Result BeginImportSection(Offset size) override { return Result::Ok; }
Result OnImportCount(Index count) override { return Result::Ok; }
Result OnImport(Index index,
ExternalKind kind,
string_view module_name,
string_view field_name) override {
return Result::Ok;
}
Result OnImportFunc(Index import_index,
string_view module_name,
string_view field_name,
Index func_index,
Index sig_index) override {
return Result::Ok;
}
Result OnImportTable(Index import_index,
string_view module_name,
string_view field_name,
Index table_index,
Type elem_type,
const Limits* elem_limits) override {
return Result::Ok;
}
Result OnImportMemory(Index import_index,
string_view module_name,
string_view field_name,
Index memory_index,
const Limits* page_limits) override {
return Result::Ok;
}
Result OnImportGlobal(Index import_index,
string_view module_name,
string_view field_name,
Index global_index,
Type type,
bool mutable_) override {
return Result::Ok;
}
Result OnImportEvent(Index import_index,
string_view module_name,
string_view field_name,
Index event_index,
Index sig_index) override {
return Result::Ok;
}
Result EndImportSection() override { return Result::Ok; }
/* Function section */
Result BeginFunctionSection(Offset size) override { return Result::Ok; }
Result OnFunctionCount(Index count) override { return Result::Ok; }
Result OnFunction(Index index, Index sig_index) override {
return Result::Ok;
}
Result EndFunctionSection() override { return Result::Ok; }
/* Table section */
Result BeginTableSection(Offset size) override { return Result::Ok; }
Result OnTableCount(Index count) override { return Result::Ok; }
Result OnTable(Index index,
Type elem_type,
const Limits* elem_limits) override {
return Result::Ok;
}
Result EndTableSection() override { return Result::Ok; }
/* Memory section */
Result BeginMemorySection(Offset size) override { return Result::Ok; }
Result OnMemoryCount(Index count) override { return Result::Ok; }
Result OnMemory(Index index, const Limits* limits) override {
return Result::Ok;
}
Result EndMemorySection() override { return Result::Ok; }
/* Global section */
Result BeginGlobalSection(Offset size) override { return Result::Ok; }
Result OnGlobalCount(Index count) override { return Result::Ok; }
Result BeginGlobal(Index index, Type type, bool mutable_) override {
return Result::Ok;
}
Result BeginGlobalInitExpr(Index index) override { return Result::Ok; }
Result EndGlobalInitExpr(Index index) override { return Result::Ok; }
Result EndGlobal(Index index) override { return Result::Ok; }
Result EndGlobalSection() override { return Result::Ok; }
/* Exports section */
Result BeginExportSection(Offset size) override { return Result::Ok; }
Result OnExportCount(Index count) override { return Result::Ok; }
Result OnExport(Index index,
ExternalKind kind,
Index item_index,
string_view name) override {
return Result::Ok;
}
Result EndExportSection() override { return Result::Ok; }
/* Start section */
Result BeginStartSection(Offset size) override { return Result::Ok; }
Result OnStartFunction(Index func_index) override { return Result::Ok; }
Result EndStartSection() override { return Result::Ok; }
/* Code section */
Result BeginCodeSection(Offset size) override { return Result::Ok; }
Result OnFunctionBodyCount(Index count) override { return Result::Ok; }
Result BeginFunctionBody(Index index, Offset size) override {
return Result::Ok;
}
Result OnLocalDeclCount(Index count) override { return Result::Ok; }
Result OnLocalDecl(Index decl_index, Index count, Type type) override {
return Result::Ok;
}
/* Function expressions; called between BeginFunctionBody and
EndFunctionBody */
Result OnOpcode(Opcode Opcode) override { return Result::Ok; }
Result OnOpcodeBare() override { return Result::Ok; }
Result OnOpcodeIndex(Index value) override { return Result::Ok; }
Result OnOpcodeIndexIndex(Index value, Index value2) override {
return Result::Ok;
}
Result OnOpcodeUint32(uint32_t value) override { return Result::Ok; }
Result OnOpcodeUint32Uint32(uint32_t value, uint32_t value2) override {
return Result::Ok;
}
Result OnOpcodeUint32Uint32Uint32(uint32_t value,
uint32_t value2,
uint32_t value3) override {
return Result::Ok;
}
Result OnOpcodeUint64(uint64_t value) override { return Result::Ok; }
Result OnOpcodeF32(uint32_t value) override { return Result::Ok; }
Result OnOpcodeF64(uint64_t value) override { return Result::Ok; }
Result OnOpcodeV128(v128 value) override { return Result::Ok; }
Result OnOpcodeBlockSig(Type sig_type) override { return Result::Ok; }
Result OnOpcodeType(Type type) override { return Result::Ok; }
Result OnAtomicLoadExpr(Opcode opcode,
Address alignment_log2,
Address offset) override {
return Result::Ok;
}
Result OnAtomicStoreExpr(Opcode opcode,
Address alignment_log2,
Address offset) override {
return Result::Ok;
}
Result OnAtomicRmwExpr(Opcode opcode,
Address alignment_log2,
Address offset) override {
return Result::Ok;
}
Result OnAtomicRmwCmpxchgExpr(Opcode opcode,
Address alignment_log2,
Address offset) override {
return Result::Ok;
}
Result OnAtomicWaitExpr(Opcode, Address, Address) override {
return Result::Ok;
}
Result OnAtomicFenceExpr(uint32_t) override {
return Result::Ok;
}
Result OnAtomicNotifyExpr(Opcode, Address, Address) override {
return Result::Ok;
}
Result OnBinaryExpr(Opcode opcode) override { return Result::Ok; }
Result OnBlockExpr(Type sig_type) override { return Result::Ok; }
Result OnBrExpr(Index depth) override { return Result::Ok; }
Result OnBrIfExpr(Index depth) override { return Result::Ok; }
Result OnBrTableExpr(Index num_targets,
Index* target_depths,
Index default_target_depth) override {
return Result::Ok;
}
Result OnCallExpr(Index func_index) override { return Result::Ok; }
Result OnCallIndirectExpr(Index sig_index, Index table_index) override { return Result::Ok; }
Result OnCatchExpr(Index event_index) override { return Result::Ok; }
Result OnCatchAllExpr() override { return Result::Ok; }
Result OnCompareExpr(Opcode opcode) override { return Result::Ok; }
Result OnConvertExpr(Opcode opcode) override { return Result::Ok; }
Result OnDelegateExpr(Index depth) override { return Result::Ok; }
Result OnDropExpr() override { return Result::Ok; }
Result OnElseExpr() override { return Result::Ok; }
Result OnEndExpr() override { return Result::Ok; }
Result OnEndFunc() override { return Result::Ok; }
Result OnF32ConstExpr(uint32_t value_bits) override { return Result::Ok; }
Result OnF64ConstExpr(uint64_t value_bits) override { return Result::Ok; }
Result OnV128ConstExpr(v128 value_bits) override { return Result::Ok; }
Result OnGlobalGetExpr(Index global_index) override { return Result::Ok; }
Result OnGlobalSetExpr(Index global_index) override { return Result::Ok; }
Result OnI32ConstExpr(uint32_t value) override { return Result::Ok; }
Result OnI64ConstExpr(uint64_t value) override { return Result::Ok; }
Result OnIfExpr(Type sig_type) override { return Result::Ok; }
Result OnLoadExpr(Opcode opcode,
Address alignment_log2,
Address offset) override {
return Result::Ok;
}
Result OnLocalGetExpr(Index local_index) override { return Result::Ok; }
Result OnLocalSetExpr(Index local_index) override { return Result::Ok; }
Result OnLocalTeeExpr(Index local_index) override { return Result::Ok; }
Result OnLoopExpr(Type sig_type) override { return Result::Ok; }
Result OnMemoryCopyExpr() override { return Result::Ok; }
Result OnDataDropExpr(Index segment_index) override { return Result::Ok; }
Result OnMemoryFillExpr() override { return Result::Ok; }
Result OnMemoryGrowExpr() override { return Result::Ok; }
Result OnMemoryInitExpr(Index segment_index) override { return Result::Ok; }
Result OnMemorySizeExpr() override { return Result::Ok; }
Result OnTableCopyExpr(Index dst_index, Index src_index) override {
return Result::Ok;
}
Result OnElemDropExpr(Index segment_index) override { return Result::Ok; }
Result OnTableInitExpr(Index segment_index, Index table_index) override {
return Result::Ok;
}
Result OnTableGetExpr(Index table_index) override { return Result::Ok; }
Result OnTableSetExpr(Index table_index) override { return Result::Ok; }
Result OnTableGrowExpr(Index table_index) override { return Result::Ok; }
Result OnTableSizeExpr(Index table_index) override { return Result::Ok; }
Result OnTableFillExpr(Index table_index) override { return Result::Ok; }
Result OnRefFuncExpr(Index func_index) override { return Result::Ok; }
Result OnRefNullExpr(Type type) override { return Result::Ok; }
Result OnRefIsNullExpr() override { return Result::Ok; }
Result OnNopExpr() override { return Result::Ok; }
Result OnRethrowExpr(Index depth) override { return Result::Ok; }
Result OnReturnCallExpr(Index sig_index) override { return Result::Ok; }
Result OnReturnCallIndirectExpr(Index sig_index, Index table_index) override { return Result::Ok; }
Result OnReturnExpr() override { return Result::Ok; }
Result OnSelectExpr(Index result_count, Type* result_types) override {
return Result::Ok;
}
Result OnStoreExpr(Opcode opcode,
Address alignment_log2,
Address offset) override {
return Result::Ok;
}
Result OnThrowExpr(Index depth) override { return Result::Ok; }
Result OnTryExpr(Type sig_type) override { return Result::Ok; }
Result OnUnaryExpr(Opcode opcode) override { return Result::Ok; }
Result OnTernaryExpr(Opcode opcode) override { return Result::Ok; }
Result OnUnreachableExpr() override { return Result::Ok; }
Result OnUnwindExpr() override { return Result::Ok; }
Result EndFunctionBody(Index index) override { return Result::Ok; }
Result EndCodeSection() override { return Result::Ok; }
Result OnSimdLaneOpExpr(Opcode opcode, uint64_t value) override {
return Result::Ok;
}
Result OnSimdLoadLaneExpr(Opcode opcode,
Address alignment_log2,
Address offset,
uint64_t value) override {
return Result::Ok;
}
Result OnSimdStoreLaneExpr(Opcode opcode,
Address alignment_log2,
Address offset,
uint64_t value) override {
return Result::Ok;
}
Result OnSimdShuffleOpExpr(Opcode opcode, v128 value) override {
return Result::Ok;
}
Result OnLoadSplatExpr(Opcode opcode,
Address alignment_log2,
Address offset) override {
return Result::Ok;
}
Result OnLoadZeroExpr(Opcode opcode,
Address alignment_log2,
Address offset) override {
return Result::Ok;
}
/* Elem section */
Result BeginElemSection(Offset size) override { return Result::Ok; }
Result OnElemSegmentCount(Index count) override { return Result::Ok; }
Result BeginElemSegment(Index index,
Index table_index,
uint8_t flags) override {
return Result::Ok;
}
Result BeginElemSegmentInitExpr(Index index) override { return Result::Ok; }
Result EndElemSegmentInitExpr(Index index) override { return Result::Ok; }
Result OnElemSegmentElemType(Index index, Type elem_type) override {
return Result::Ok;
}
Result OnElemSegmentElemExprCount(Index index, Index count) override {
return Result::Ok;
}
Result OnElemSegmentElemExpr_RefNull(Index segment_index,
Type type) override {
return Result::Ok;
}
Result OnElemSegmentElemExpr_RefFunc(Index segment_index,
Index func_index) override {
return Result::Ok;
}
Result EndElemSegment(Index index) override { return Result::Ok; }
Result EndElemSection() override { return Result::Ok; }
/* Data section */
Result BeginDataSection(Offset size) override { return Result::Ok; }
Result OnDataSegmentCount(Index count) override { return Result::Ok; }
Result BeginDataSegment(Index index,
Index memory_index,
uint8_t flags) override {
return Result::Ok;
}
Result BeginDataSegmentInitExpr(Index index) override { return Result::Ok; }
Result EndDataSegmentInitExpr(Index index) override { return Result::Ok; }
Result OnDataSegmentData(Index index,
const void* data,
Address size) override {
return Result::Ok;
}
Result EndDataSegment(Index index) override { return Result::Ok; }
Result EndDataSection() override { return Result::Ok; }
/* DataCount section */
Result BeginDataCountSection(Offset size) override { return Result::Ok; }
Result OnDataCount(Index count) override { return Result::Ok; }
Result EndDataCountSection() override { return Result::Ok; }
/* Names section */
Result BeginNamesSection(Offset size) override { return Result::Ok; }
Result OnModuleNameSubsection(Index index,
uint32_t name_type,
Offset subsection_size) override {
return Result::Ok;
}
Result OnModuleName(string_view name) override { return Result::Ok; }
Result OnFunctionNameSubsection(Index index,
uint32_t name_type,
Offset subsection_size) override {
return Result::Ok;
}
Result OnFunctionNamesCount(Index num_functions) override {
return Result::Ok;
}
Result OnFunctionName(Index function_index,
string_view function_name) override {
return Result::Ok;
}
Result OnLocalNameSubsection(Index index,
uint32_t name_type,
Offset subsection_size) override {
return Result::Ok;
}
Result OnLocalNameFunctionCount(Index num_functions) override {
return Result::Ok;
}
Result OnLocalNameLocalCount(Index function_index,
Index num_locals) override {
return Result::Ok;
}
Result OnLocalName(Index function_index,
Index local_index,
string_view local_name) override {
return Result::Ok;
}
Result EndNamesSection() override { return Result::Ok; }
Result OnNameSubsection(Index index,
NameSectionSubsection subsection_type,
Offset subsection_size) override {
return Result::Ok;
}
Result OnNameCount(Index num_names) override { return Result::Ok; }
Result OnNameEntry(NameSectionSubsection type,
Index index,
string_view name) override {
return Result::Ok;
}
/* Reloc section */
Result BeginRelocSection(Offset size) override { return Result::Ok; }
Result OnRelocCount(Index count, Index section_code) override {
return Result::Ok;
}
Result OnReloc(RelocType type,
Offset offset,
Index index,
uint32_t addend) override {
return Result::Ok;
}
Result EndRelocSection() override { return Result::Ok; }
/* Event section */
Result BeginEventSection(Offset size) override { return Result::Ok; }
Result OnEventCount(Index count) override { return Result::Ok; }
Result OnEventType(Index index, Index sig_index) override {
return Result::Ok;
}
Result EndEventSection() override { return Result::Ok; }
/* Dylink section */
Result BeginDylinkSection(Offset size) override { return Result::Ok; }
Result OnDylinkInfo(uint32_t mem_size,
uint32_t mem_align,
uint32_t table_size,
uint32_t table_align) override {
return Result::Ok;
}
Result OnDylinkNeededCount(Index count) override { return Result::Ok; }
Result OnDylinkNeeded(string_view so_name) override { return Result::Ok; }
Result EndDylinkSection() override { return Result::Ok; }
/* Linking section */
Result BeginLinkingSection(Offset size) override { return Result::Ok; }
Result OnSymbolCount(Index count) override { return Result::Ok; }
Result OnSymbol(Index sybmol_index,
SymbolType type,
uint32_t flags) override {
return Result::Ok;
}
Result OnDataSymbol(Index index,
uint32_t flags,
string_view name,
Index segment,
uint32_t offset,
uint32_t size) override {
return Result::Ok;
}
Result OnFunctionSymbol(Index index,
uint32_t flags,
string_view name,
Index func_index) override {
return Result::Ok;
}
Result OnGlobalSymbol(Index index,
uint32_t flags,
string_view name,
Index global_index) override {
return Result::Ok;
}
Result OnSectionSymbol(Index index,
uint32_t flags,
Index section_index) override {
return Result::Ok;
}
Result OnEventSymbol(Index index,
uint32_t flags,
string_view name,
Index event_index) override {
return Result::Ok;
}
Result OnTableSymbol(Index index,
uint32_t flags,
string_view name,
Index table_index) override {
return Result::Ok;
}
Result OnSegmentInfoCount(Index count) override { return Result::Ok; }
Result OnSegmentInfo(Index index,
string_view name,
Address alignment,
uint32_t flags) override {
return Result::Ok;
}
Result OnInitFunctionCount(Index count) override { return Result::Ok; }
Result OnInitFunction(uint32_t priority, Index function_index) override {
return Result::Ok;
}
Result OnComdatCount(Index count) override { return Result::Ok; }
Result OnComdatBegin(string_view name, uint32_t flags, Index count) override {
return Result::Ok;
}
Result OnComdatEntry(ComdatType kind, Index index) override {
return Result::Ok;
}
Result EndLinkingSection() override { return Result::Ok; }
/* InitExpr - used by elem, data and global sections; these functions are
* only called between calls to Begin*InitExpr and End*InitExpr */
Result OnInitExprF32ConstExpr(Index index, uint32_t value) override {
return Result::Ok;
}
Result OnInitExprF64ConstExpr(Index index, uint64_t value) override {
return Result::Ok;
}
Result OnInitExprV128ConstExpr(Index index, v128 value) override {
return Result::Ok;
}
Result OnInitExprGlobalGetExpr(Index index, Index global_index) override {
return Result::Ok;
}
Result OnInitExprI32ConstExpr(Index index, uint32_t value) override {
return Result::Ok;
}
Result OnInitExprI64ConstExpr(Index index, uint64_t value) override {
return Result::Ok;
}
Result OnInitExprRefNull(Index index, Type type) override {
return Result::Ok;
}
Result OnInitExprRefFunc(Index index, Index func_index) override {
return Result::Ok;
}
};
} // namespace wabt
#endif /* WABT_BINARY_READER_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,87 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_BINARY_READER_OBJDUMP_H_
#define WABT_BINARY_READER_OBJDUMP_H_
#include <map>
#include <string>
#include "src/common.h"
#include "src/feature.h"
#include "src/stream.h"
namespace wabt {
struct Module;
struct ReadBinaryOptions;
enum class ObjdumpMode {
Prepass,
Headers,
Details,
Disassemble,
RawData,
};
struct ObjdumpOptions {
Stream* log_stream;
bool headers;
bool details;
bool raw;
bool disassemble;
bool debug;
bool relocs;
ObjdumpMode mode;
const char* filename;
const char* section_name;
};
struct ObjdumpSymbol {
wabt::SymbolType kind;
std::string name;
Index index;
};
struct ObjdumpNames {
string_view Get(Index index) const;
void Set(Index index, string_view name);
std::map<Index, std::string> names;
};
// read_binary_objdump uses this state to store information from previous runs
// and use it to display more useful information.
struct ObjdumpState {
std::vector<Reloc> code_relocations;
std::vector<Reloc> data_relocations;
ObjdumpNames function_names;
ObjdumpNames global_names;
ObjdumpNames section_names;
ObjdumpNames event_names;
ObjdumpNames segment_names;
ObjdumpNames table_names;
std::vector<ObjdumpSymbol> symtab;
};
Result ReadBinaryObjdump(const uint8_t* data,
size_t size,
ObjdumpOptions* options,
ObjdumpState* state);
} // namespace wabt
#endif /* WABT_BINARY_READER_OBJDUMP_H_ */

View File

@@ -0,0 +1,290 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/binary-reader-opcnt.h"
#include <cassert>
#include <cinttypes>
#include <cstdarg>
#include <cstdint>
#include <cstdio>
#include "src/binary-reader-nop.h"
#include "src/common.h"
#include "src/literal.h"
#include "src/stream.h"
namespace wabt {
OpcodeInfo::OpcodeInfo(Opcode opcode, Kind kind)
: opcode_(opcode), kind_(kind) {}
template <typename T>
OpcodeInfo::OpcodeInfo(Opcode opcode, Kind kind, T* data, size_t count)
: OpcodeInfo(opcode, kind) {
if (count > 0) {
data_.resize(sizeof(T) * count);
memcpy(data_.data(), data, data_.size());
}
}
template <typename T>
OpcodeInfo::OpcodeInfo(Opcode opcode, Kind kind, T* data, size_t count, T extra)
: OpcodeInfo(opcode, kind, data, count) {
data_.resize(data_.size() + sizeof(T));
memcpy(data_.data() + data_.size() - sizeof(T), &extra, sizeof(T));
}
template <typename T>
std::pair<const T*, size_t> OpcodeInfo::GetDataArray() const {
if (data_.empty()) {
return std::pair<const T*, size_t>(nullptr, 0);
}
assert(data_.size() % sizeof(T) == 0);
return std::make_pair(reinterpret_cast<const T*>(data_.data()),
data_.size() / sizeof(T));
}
template <typename T>
const T* OpcodeInfo::GetData(size_t expected_size) const {
auto pair = GetDataArray<T>();
assert(pair.second == expected_size);
return pair.first;
}
template <typename T, typename F>
void OpcodeInfo::WriteArray(Stream& stream, F&& write_func) {
auto pair = GetDataArray<T>();
for (size_t i = 0; i < pair.second; ++i) {
// Write an initial space (to separate from the opcode name) first, then
// comma-separate.
stream.Writef("%s", i == 0 ? " " : ", ");
write_func(pair.first[i]);
}
}
void OpcodeInfo::Write(Stream& stream) {
stream.Writef("%s", opcode_.GetName());
switch (kind_) {
case Kind::Bare:
break;
case Kind::Uint32:
stream.Writef(" %u (0x%x)", *GetData<uint32_t>(), *GetData<uint32_t>());
break;
case Kind::Uint64:
stream.Writef(" %" PRIu64 " (0x%" PRIx64 ")", *GetData<uint64_t>(),
*GetData<uint64_t>());
break;
case Kind::Index:
stream.Writef(" %" PRIindex, *GetData<Index>());
break;
case Kind::Float32: {
stream.Writef(" %g", *GetData<float>());
char buffer[WABT_MAX_FLOAT_HEX + 1];
WriteFloatHex(buffer, sizeof(buffer), *GetData<uint32_t>());
stream.Writef(" (%s)", buffer);
break;
}
case Kind::Float64: {
stream.Writef(" %g", *GetData<double>());
char buffer[WABT_MAX_DOUBLE_HEX + 1];
WriteDoubleHex(buffer, sizeof(buffer), *GetData<uint64_t>());
stream.Writef(" (%s)", buffer);
break;
}
case Kind::Uint32Uint32:
WriteArray<uint32_t>(
stream, [&stream](uint32_t value) { stream.Writef("%u", value); });
break;
case Kind::BlockSig: {
auto type = *GetData<Type>();
if (type.IsIndex()) {
stream.Writef(" type:%d", type.GetIndex());
} else if (type != Type::Void) {
stream.Writef(" %s", type.GetName());
}
break;
}
case Kind::BrTable: {
WriteArray<Index>(stream, [&stream](Index index) {
stream.Writef("%" PRIindex, index);
});
break;
}
}
}
bool operator==(const OpcodeInfo& lhs, const OpcodeInfo& rhs) {
return lhs.opcode_ == rhs.opcode_ && lhs.kind_ == rhs.kind_ &&
lhs.data_ == rhs.data_;
}
bool operator!=(const OpcodeInfo& lhs, const OpcodeInfo& rhs) {
return !(lhs == rhs);
}
bool operator<(const OpcodeInfo& lhs, const OpcodeInfo& rhs) {
if (lhs.opcode_ < rhs.opcode_) {
return true;
}
if (lhs.opcode_ > rhs.opcode_) {
return false;
}
if (lhs.kind_ < rhs.kind_) {
return true;
}
if (lhs.kind_ > rhs.kind_) {
return false;
}
if (lhs.data_ < rhs.data_) {
return true;
}
if (lhs.data_ > rhs.data_) {
return false;
}
return false;
}
bool operator<=(const OpcodeInfo& lhs, const OpcodeInfo& rhs) {
return lhs < rhs || lhs == rhs;
}
bool operator>(const OpcodeInfo& lhs, const OpcodeInfo& rhs) {
return !(lhs <= rhs);
}
bool operator>=(const OpcodeInfo& lhs, const OpcodeInfo& rhs) {
return !(lhs < rhs);
}
namespace {
class BinaryReaderOpcnt : public BinaryReaderNop {
public:
explicit BinaryReaderOpcnt(OpcodeInfoCounts* counts);
Result OnOpcode(Opcode opcode) override;
Result OnOpcodeBare() override;
Result OnOpcodeUint32(uint32_t value) override;
Result OnOpcodeIndex(Index value) override;
Result OnOpcodeUint32Uint32(uint32_t value, uint32_t value2) override;
Result OnOpcodeUint64(uint64_t value) override;
Result OnOpcodeF32(uint32_t value) override;
Result OnOpcodeF64(uint64_t value) override;
Result OnOpcodeBlockSig(Type sig_type) override;
Result OnBrTableExpr(Index num_targets,
Index* target_depths,
Index default_target_depth) override;
Result OnEndExpr() override;
Result OnEndFunc() override;
private:
template <typename... Args>
Result Emplace(Args&&... args);
OpcodeInfoCounts* opcode_counts_;
Opcode current_opcode_;
};
template <typename... Args>
Result BinaryReaderOpcnt::Emplace(Args&&... args) {
auto pair = opcode_counts_->emplace(
std::piecewise_construct, std::make_tuple(std::forward<Args>(args)...),
std::make_tuple(0));
auto& count = pair.first->second;
count++;
return Result::Ok;
}
BinaryReaderOpcnt::BinaryReaderOpcnt(OpcodeInfoCounts* counts)
: opcode_counts_(counts) {}
Result BinaryReaderOpcnt::OnOpcode(Opcode opcode) {
current_opcode_ = opcode;
return Result::Ok;
}
Result BinaryReaderOpcnt::OnOpcodeBare() {
return Emplace(current_opcode_, OpcodeInfo::Kind::Bare);
}
Result BinaryReaderOpcnt::OnOpcodeUint32(uint32_t value) {
return Emplace(current_opcode_, OpcodeInfo::Kind::Uint32, &value);
}
Result BinaryReaderOpcnt::OnOpcodeIndex(Index value) {
return Emplace(current_opcode_, OpcodeInfo::Kind::Index, &value);
}
Result BinaryReaderOpcnt::OnOpcodeUint32Uint32(uint32_t value0,
uint32_t value1) {
uint32_t array[2] = {value0, value1};
return Emplace(current_opcode_, OpcodeInfo::Kind::Uint32Uint32, array, 2);
}
Result BinaryReaderOpcnt::OnOpcodeUint64(uint64_t value) {
return Emplace(current_opcode_, OpcodeInfo::Kind::Uint64, &value);
}
Result BinaryReaderOpcnt::OnOpcodeF32(uint32_t value) {
return Emplace(current_opcode_, OpcodeInfo::Kind::Float32, &value);
}
Result BinaryReaderOpcnt::OnOpcodeF64(uint64_t value) {
return Emplace(current_opcode_, OpcodeInfo::Kind::Float64, &value);
}
Result BinaryReaderOpcnt::OnOpcodeBlockSig(Type sig_type) {
return Emplace(current_opcode_, OpcodeInfo::Kind::BlockSig, &sig_type);
}
Result BinaryReaderOpcnt::OnBrTableExpr(Index num_targets,
Index* target_depths,
Index default_target_depth) {
return Emplace(current_opcode_, OpcodeInfo::Kind::BrTable, target_depths,
num_targets, default_target_depth);
}
Result BinaryReaderOpcnt::OnEndExpr() {
return Emplace(Opcode::End, OpcodeInfo::Kind::Bare);
}
Result BinaryReaderOpcnt::OnEndFunc() {
return Emplace(Opcode::End, OpcodeInfo::Kind::Bare);
}
} // end anonymous namespace
Result ReadBinaryOpcnt(const void* data,
size_t size,
const ReadBinaryOptions& options,
OpcodeInfoCounts* counts) {
BinaryReaderOpcnt reader(counts);
return ReadBinary(data, size, &reader, options);
}
} // namespace wabt

View File

@@ -0,0 +1,93 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_BINARY_READER_OPCNT_H_
#define WABT_BINARY_READER_OPCNT_H_
#include <map>
#include <vector>
#include "src/common.h"
#include "src/opcode.h"
namespace wabt {
struct Module;
struct ReadBinaryOptions;
class Stream;
class OpcodeInfo {
public:
enum class Kind {
Bare,
Uint32,
Uint64,
Index,
Float32,
Float64,
Uint32Uint32,
BlockSig,
BrTable,
};
explicit OpcodeInfo(Opcode, Kind);
template <typename T>
OpcodeInfo(Opcode, Kind, T* data, size_t count = 1);
template <typename T>
OpcodeInfo(Opcode, Kind, T* data, size_t count, T extra);
Opcode opcode() const { return opcode_; }
void Write(Stream&);
private:
template <typename T>
std::pair<const T*, size_t> GetDataArray() const;
template <typename T>
const T* GetData(size_t expected_size = 1) const;
template <typename T, typename F>
void WriteArray(Stream& stream, F&& write_func);
Opcode opcode_;
Kind kind_;
std::vector<uint8_t> data_;
friend bool operator==(const OpcodeInfo&, const OpcodeInfo&);
friend bool operator!=(const OpcodeInfo&, const OpcodeInfo&);
friend bool operator<(const OpcodeInfo&, const OpcodeInfo&);
friend bool operator<=(const OpcodeInfo&, const OpcodeInfo&);
friend bool operator>(const OpcodeInfo&, const OpcodeInfo&);
friend bool operator>=(const OpcodeInfo&, const OpcodeInfo&);
};
bool operator==(const OpcodeInfo&, const OpcodeInfo&);
bool operator!=(const OpcodeInfo&, const OpcodeInfo&);
bool operator<(const OpcodeInfo&, const OpcodeInfo&);
bool operator<=(const OpcodeInfo&, const OpcodeInfo&);
bool operator>(const OpcodeInfo&, const OpcodeInfo&);
bool operator>=(const OpcodeInfo&, const OpcodeInfo&);
typedef std::map<OpcodeInfo, size_t> OpcodeInfoCounts;
Result ReadBinaryOpcnt(const void* data,
size_t size,
const ReadBinaryOptions& options,
OpcodeInfoCounts* opcode_counts);
} // namespace wabt
#endif /* WABT_BINARY_READER_OPCNT_H_ */

2756
third_party/wasm2c/src/binary-reader.cc vendored Normal file

File diff suppressed because it is too large Load Diff

480
third_party/wasm2c/src/binary-reader.h vendored Normal file
View File

@@ -0,0 +1,480 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_BINARY_READER_H_
#define WABT_BINARY_READER_H_
#include <stddef.h>
#include <stdint.h>
#include "src/binary.h"
#include "src/common.h"
#include "src/error.h"
#include "src/feature.h"
#include "src/opcode.h"
#include "src/string-view.h"
namespace wabt {
class Stream;
struct ReadBinaryOptions {
ReadBinaryOptions() = default;
ReadBinaryOptions(const Features& features,
Stream* log_stream,
bool read_debug_names,
bool stop_on_first_error,
bool fail_on_custom_section_error)
: features(features),
log_stream(log_stream),
read_debug_names(read_debug_names),
stop_on_first_error(stop_on_first_error),
fail_on_custom_section_error(fail_on_custom_section_error) {}
Features features;
Stream* log_stream = nullptr;
bool read_debug_names = false;
bool stop_on_first_error = true;
bool fail_on_custom_section_error = true;
};
// TODO: Move somewhere else?
struct TypeMut {
Type type;
bool mutable_;
};
using TypeMutVector = std::vector<TypeMut>;
class BinaryReaderDelegate {
public:
struct State {
State(const uint8_t* data, Offset size)
: data(data), size(size), offset(0) {}
const uint8_t* data;
Offset size;
Offset offset;
};
virtual ~BinaryReaderDelegate() {}
virtual bool OnError(const Error&) = 0;
virtual void OnSetState(const State* s) { state = s; }
/* Module */
virtual Result BeginModule(uint32_t version) = 0;
virtual Result EndModule() = 0;
virtual Result BeginSection(Index section_index,
BinarySection section_type,
Offset size) = 0;
/* Custom section */
virtual Result BeginCustomSection(Index section_index,
Offset size,
string_view section_name) = 0;
virtual Result EndCustomSection() = 0;
/* Type section */
virtual Result BeginTypeSection(Offset size) = 0;
virtual Result OnTypeCount(Index count) = 0;
virtual Result OnFuncType(Index index,
Index param_count,
Type* param_types,
Index result_count,
Type* result_types) = 0;
virtual Result OnStructType(Index index,
Index field_count,
TypeMut* fields) = 0;
virtual Result OnArrayType(Index index, TypeMut field) = 0;
virtual Result EndTypeSection() = 0;
/* Import section */
virtual Result BeginImportSection(Offset size) = 0;
virtual Result OnImportCount(Index count) = 0;
virtual Result OnImport(Index index,
ExternalKind kind,
string_view module_name,
string_view field_name) = 0;
virtual Result OnImportFunc(Index import_index,
string_view module_name,
string_view field_name,
Index func_index,
Index sig_index) = 0;
virtual Result OnImportTable(Index import_index,
string_view module_name,
string_view field_name,
Index table_index,
Type elem_type,
const Limits* elem_limits) = 0;
virtual Result OnImportMemory(Index import_index,
string_view module_name,
string_view field_name,
Index memory_index,
const Limits* page_limits) = 0;
virtual Result OnImportGlobal(Index import_index,
string_view module_name,
string_view field_name,
Index global_index,
Type type,
bool mutable_) = 0;
virtual Result OnImportEvent(Index import_index,
string_view module_name,
string_view field_name,
Index event_index,
Index sig_index) = 0;
virtual Result EndImportSection() = 0;
/* Function section */
virtual Result BeginFunctionSection(Offset size) = 0;
virtual Result OnFunctionCount(Index count) = 0;
virtual Result OnFunction(Index index, Index sig_index) = 0;
virtual Result EndFunctionSection() = 0;
/* Table section */
virtual Result BeginTableSection(Offset size) = 0;
virtual Result OnTableCount(Index count) = 0;
virtual Result OnTable(Index index,
Type elem_type,
const Limits* elem_limits) = 0;
virtual Result EndTableSection() = 0;
/* Memory section */
virtual Result BeginMemorySection(Offset size) = 0;
virtual Result OnMemoryCount(Index count) = 0;
virtual Result OnMemory(Index index, const Limits* limits) = 0;
virtual Result EndMemorySection() = 0;
/* Global section */
virtual Result BeginGlobalSection(Offset size) = 0;
virtual Result OnGlobalCount(Index count) = 0;
virtual Result BeginGlobal(Index index, Type type, bool mutable_) = 0;
virtual Result BeginGlobalInitExpr(Index index) = 0;
virtual Result EndGlobalInitExpr(Index index) = 0;
virtual Result EndGlobal(Index index) = 0;
virtual Result EndGlobalSection() = 0;
/* Exports section */
virtual Result BeginExportSection(Offset size) = 0;
virtual Result OnExportCount(Index count) = 0;
virtual Result OnExport(Index index,
ExternalKind kind,
Index item_index,
string_view name) = 0;
virtual Result EndExportSection() = 0;
/* Start section */
virtual Result BeginStartSection(Offset size) = 0;
virtual Result OnStartFunction(Index func_index) = 0;
virtual Result EndStartSection() = 0;
/* Code section */
virtual Result BeginCodeSection(Offset size) = 0;
virtual Result OnFunctionBodyCount(Index count) = 0;
virtual Result BeginFunctionBody(Index index, Offset size) = 0;
virtual Result OnLocalDeclCount(Index count) = 0;
virtual Result OnLocalDecl(Index decl_index, Index count, Type type) = 0;
/* Function expressions; called between BeginFunctionBody and
EndFunctionBody */
virtual Result OnOpcode(Opcode Opcode) = 0;
virtual Result OnOpcodeBare() = 0;
virtual Result OnOpcodeUint32(uint32_t value) = 0;
virtual Result OnOpcodeIndex(Index value) = 0;
virtual Result OnOpcodeIndexIndex(Index value, Index value2) = 0;
virtual Result OnOpcodeUint32Uint32(uint32_t value, uint32_t value2) = 0;
virtual Result OnOpcodeUint32Uint32Uint32(uint32_t value,
uint32_t value2,
uint32_t value3) = 0;
virtual Result OnOpcodeUint64(uint64_t value) = 0;
virtual Result OnOpcodeF32(uint32_t value) = 0;
virtual Result OnOpcodeF64(uint64_t value) = 0;
virtual Result OnOpcodeV128(v128 value) = 0;
virtual Result OnOpcodeBlockSig(Type sig_type) = 0;
virtual Result OnOpcodeType(Type type) = 0;
virtual Result OnAtomicLoadExpr(Opcode opcode,
Address alignment_log2,
Address offset) = 0;
virtual Result OnAtomicStoreExpr(Opcode opcode,
Address alignment_log2,
Address offset) = 0;
virtual Result OnAtomicRmwExpr(Opcode opcode,
Address alignment_log2,
Address offset) = 0;
virtual Result OnAtomicRmwCmpxchgExpr(Opcode opcode,
Address alignment_log2,
Address offset) = 0;
virtual Result OnAtomicWaitExpr(Opcode opcode,
Address alignment_log2,
Address offset) = 0;
virtual Result OnAtomicFenceExpr(uint32_t consistency_model) = 0;
virtual Result OnAtomicNotifyExpr(Opcode opcode,
Address alignment_log2,
Address offset) = 0;
virtual Result OnBinaryExpr(Opcode opcode) = 0;
virtual Result OnBlockExpr(Type sig_type) = 0;
virtual Result OnBrExpr(Index depth) = 0;
virtual Result OnBrIfExpr(Index depth) = 0;
virtual Result OnBrTableExpr(Index num_targets,
Index* target_depths,
Index default_target_depth) = 0;
virtual Result OnCallExpr(Index func_index) = 0;
virtual Result OnCallIndirectExpr(Index sig_index, Index table_index) = 0;
virtual Result OnCatchExpr(Index event_index) = 0;
virtual Result OnCatchAllExpr() = 0;
virtual Result OnCompareExpr(Opcode opcode) = 0;
virtual Result OnConvertExpr(Opcode opcode) = 0;
virtual Result OnDelegateExpr(Index depth) = 0;
virtual Result OnDropExpr() = 0;
virtual Result OnElseExpr() = 0;
virtual Result OnEndExpr() = 0;
virtual Result OnEndFunc() = 0;
virtual Result OnF32ConstExpr(uint32_t value_bits) = 0;
virtual Result OnF64ConstExpr(uint64_t value_bits) = 0;
virtual Result OnV128ConstExpr(v128 value_bits) = 0;
virtual Result OnGlobalGetExpr(Index global_index) = 0;
virtual Result OnGlobalSetExpr(Index global_index) = 0;
virtual Result OnI32ConstExpr(uint32_t value) = 0;
virtual Result OnI64ConstExpr(uint64_t value) = 0;
virtual Result OnIfExpr(Type sig_type) = 0;
virtual Result OnLoadExpr(Opcode opcode,
Address alignment_log2,
Address offset) = 0;
virtual Result OnLocalGetExpr(Index local_index) = 0;
virtual Result OnLocalSetExpr(Index local_index) = 0;
virtual Result OnLocalTeeExpr(Index local_index) = 0;
virtual Result OnLoopExpr(Type sig_type) = 0;
virtual Result OnMemoryCopyExpr() = 0;
virtual Result OnDataDropExpr(Index segment_index) = 0;
virtual Result OnMemoryFillExpr() = 0;
virtual Result OnMemoryGrowExpr() = 0;
virtual Result OnMemoryInitExpr(Index segment_index) = 0;
virtual Result OnMemorySizeExpr() = 0;
virtual Result OnTableCopyExpr(Index dst_index, Index src_index) = 0;
virtual Result OnElemDropExpr(Index segment_index) = 0;
virtual Result OnTableInitExpr(Index segment_index, Index table_index) = 0;
virtual Result OnTableGetExpr(Index table_index) = 0;
virtual Result OnTableSetExpr(Index table_index) = 0;
virtual Result OnTableGrowExpr(Index table_index) = 0;
virtual Result OnTableSizeExpr(Index table_index) = 0;
virtual Result OnTableFillExpr(Index table_index) = 0;
virtual Result OnRefFuncExpr(Index func_index) = 0;
virtual Result OnRefNullExpr(Type type) = 0;
virtual Result OnRefIsNullExpr() = 0;
virtual Result OnNopExpr() = 0;
virtual Result OnRethrowExpr(Index depth) = 0;
virtual Result OnReturnExpr() = 0;
virtual Result OnReturnCallExpr(Index func_index) = 0;
virtual Result OnReturnCallIndirectExpr(Index sig_index,
Index table_index) = 0;
virtual Result OnSelectExpr(Index result_count, Type* result_types) = 0;
virtual Result OnStoreExpr(Opcode opcode,
Address alignment_log2,
Address offset) = 0;
virtual Result OnThrowExpr(Index event_index) = 0;
virtual Result OnTryExpr(Type sig_type) = 0;
virtual Result OnUnaryExpr(Opcode opcode) = 0;
virtual Result OnTernaryExpr(Opcode opcode) = 0;
virtual Result OnUnreachableExpr() = 0;
virtual Result OnUnwindExpr() = 0;
virtual Result EndFunctionBody(Index index) = 0;
virtual Result EndCodeSection() = 0;
/* Simd instructions with Lane Imm operand*/
virtual Result OnSimdLaneOpExpr(Opcode opcode, uint64_t value) = 0;
virtual Result OnSimdShuffleOpExpr(Opcode opcode, v128 value) = 0;
virtual Result OnSimdLoadLaneExpr(Opcode opcode,
Address alignment_log2,
Address offset,
uint64_t value) = 0;
virtual Result OnSimdStoreLaneExpr(Opcode opcode,
Address alignment_log2,
Address offset,
uint64_t value) = 0;
virtual Result OnLoadSplatExpr(Opcode opcode,
Address alignment_log2,
Address offset) = 0;
virtual Result OnLoadZeroExpr(Opcode opcode,
Address alignment_log2,
Address offset) = 0;
/* Elem section */
virtual Result BeginElemSection(Offset size) = 0;
virtual Result OnElemSegmentCount(Index count) = 0;
virtual Result BeginElemSegment(Index index,
Index table_index,
uint8_t flags) = 0;
virtual Result BeginElemSegmentInitExpr(Index index) = 0;
virtual Result EndElemSegmentInitExpr(Index index) = 0;
virtual Result OnElemSegmentElemType(Index index, Type elem_type) = 0;
virtual Result OnElemSegmentElemExprCount(Index index, Index count) = 0;
virtual Result OnElemSegmentElemExpr_RefNull(Index segment_index,
Type type) = 0;
virtual Result OnElemSegmentElemExpr_RefFunc(Index segment_index,
Index func_index) = 0;
virtual Result EndElemSegment(Index index) = 0;
virtual Result EndElemSection() = 0;
/* Data section */
virtual Result BeginDataSection(Offset size) = 0;
virtual Result OnDataSegmentCount(Index count) = 0;
virtual Result BeginDataSegment(Index index,
Index memory_index,
uint8_t flags) = 0;
virtual Result BeginDataSegmentInitExpr(Index index) = 0;
virtual Result EndDataSegmentInitExpr(Index index) = 0;
virtual Result OnDataSegmentData(Index index,
const void* data,
Address size) = 0;
virtual Result EndDataSegment(Index index) = 0;
virtual Result EndDataSection() = 0;
/* DataCount section */
virtual Result BeginDataCountSection(Offset size) = 0;
virtual Result OnDataCount(Index count) = 0;
virtual Result EndDataCountSection() = 0;
/* Names section */
virtual Result BeginNamesSection(Offset size) = 0;
virtual Result OnModuleNameSubsection(Index index,
uint32_t name_type,
Offset subsection_size) = 0;
virtual Result OnModuleName(string_view name) = 0;
virtual Result OnFunctionNameSubsection(Index index,
uint32_t name_type,
Offset subsection_size) = 0;
virtual Result OnFunctionNamesCount(Index num_functions) = 0;
virtual Result OnFunctionName(Index function_index,
string_view function_name) = 0;
virtual Result OnLocalNameSubsection(Index index,
uint32_t name_type,
Offset subsection_size) = 0;
virtual Result OnLocalNameFunctionCount(Index num_functions) = 0;
virtual Result OnLocalNameLocalCount(Index function_index,
Index num_locals) = 0;
virtual Result OnLocalName(Index function_index,
Index local_index,
string_view local_name) = 0;
virtual Result OnNameSubsection(Index index,
NameSectionSubsection subsection_type,
Offset subsection_size) = 0;
virtual Result OnNameCount(Index num_names) = 0;
virtual Result OnNameEntry(NameSectionSubsection type,
Index index,
string_view name) = 0;
virtual Result EndNamesSection() = 0;
/* Reloc section */
virtual Result BeginRelocSection(Offset size) = 0;
virtual Result OnRelocCount(Index count,
Index section_index) = 0;
virtual Result OnReloc(RelocType type,
Offset offset,
Index index,
uint32_t addend) = 0;
virtual Result EndRelocSection() = 0;
/* Dylink section */
virtual Result BeginDylinkSection(Offset size) = 0;
virtual Result OnDylinkInfo(uint32_t mem_size,
uint32_t mem_align_log2,
uint32_t table_size,
uint32_t table_align_log2) = 0;
virtual Result OnDylinkNeededCount(Index count) = 0;
virtual Result OnDylinkNeeded(string_view so_name) = 0;
virtual Result EndDylinkSection() = 0;
/* Linking section */
virtual Result BeginLinkingSection(Offset size) = 0;
virtual Result OnSymbolCount(Index count) = 0;
virtual Result OnSymbol(Index index, SymbolType type, uint32_t flags) = 0;
virtual Result OnDataSymbol(Index index,
uint32_t flags,
string_view name,
Index segment,
uint32_t offset,
uint32_t size) = 0;
virtual Result OnFunctionSymbol(Index index,
uint32_t flags,
string_view name,
Index function_index) = 0;
virtual Result OnGlobalSymbol(Index index,
uint32_t flags,
string_view name,
Index global_index) = 0;
virtual Result OnSectionSymbol(Index index,
uint32_t flags,
Index section_index) = 0;
virtual Result OnEventSymbol(Index index,
uint32_t flags,
string_view name,
Index event_index) = 0;
virtual Result OnTableSymbol(Index index,
uint32_t flags,
string_view name,
Index table_index) = 0;
virtual Result OnSegmentInfoCount(Index count) = 0;
virtual Result OnSegmentInfo(Index index,
string_view name,
Address alignment_log2,
uint32_t flags) = 0;
virtual Result OnInitFunctionCount(Index count) = 0;
virtual Result OnInitFunction(uint32_t priority, Index function_index) = 0;
virtual Result OnComdatCount(Index count) = 0;
virtual Result OnComdatBegin(string_view name,
uint32_t flags,
Index count) = 0;
virtual Result OnComdatEntry(ComdatType kind, Index index) = 0;
virtual Result EndLinkingSection() = 0;
/* Event section */
virtual Result BeginEventSection(Offset size) = 0;
virtual Result OnEventCount(Index count) = 0;
virtual Result OnEventType(Index index, Index sig_index) = 0;
virtual Result EndEventSection() = 0;
/* InitExpr - used by elem, data and global sections; these functions are
* only called between calls to Begin*InitExpr and End*InitExpr */
virtual Result OnInitExprF32ConstExpr(Index index, uint32_t value) = 0;
virtual Result OnInitExprF64ConstExpr(Index index, uint64_t value) = 0;
virtual Result OnInitExprV128ConstExpr(Index index, v128 value) = 0;
virtual Result OnInitExprGlobalGetExpr(Index index, Index global_index) = 0;
virtual Result OnInitExprI32ConstExpr(Index index, uint32_t value) = 0;
virtual Result OnInitExprI64ConstExpr(Index index, uint64_t value) = 0;
virtual Result OnInitExprRefNull(Index index, Type type) = 0;
virtual Result OnInitExprRefFunc(Index index, Index func_index) = 0;
const State* state = nullptr;
};
Result ReadBinary(const void* data,
size_t size,
BinaryReaderDelegate* reader,
const ReadBinaryOptions& options);
size_t ReadU32Leb128(const uint8_t* ptr,
const uint8_t* end,
uint32_t* out_value);
size_t ReadI32Leb128(const uint8_t* ptr,
const uint8_t* end,
uint32_t* out_value);
} // namespace wabt
#endif /* WABT_BINARY_READER_H_ */

View File

@@ -0,0 +1,630 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/binary-writer-spec.h"
#include <cassert>
#include <cinttypes>
#include "config.h"
#include "src/binary-writer.h"
#include "src/binary.h"
#include "src/cast.h"
#include "src/filenames.h"
#include "src/ir.h"
#include "src/literal.h"
#include "src/stream.h"
#include "src/string-view.h"
namespace wabt {
namespace {
class BinaryWriterSpec {
public:
BinaryWriterSpec(Stream* json_stream,
WriteBinarySpecStreamFactory module_stream_factory,
string_view source_filename,
string_view module_filename_noext,
const WriteBinaryOptions& options);
Result WriteScript(const Script& script);
private:
std::string GetModuleFilename(const char* extension);
void WriteString(const char* s);
void WriteKey(const char* key);
void WriteSeparator();
void WriteEscapedString(string_view);
void WriteCommandType(const Command& command);
void WriteLocation(const Location& loc);
void WriteVar(const Var& var);
void WriteTypeObject(Type type);
void WriteF32(uint32_t, ExpectedNan);
void WriteF64(uint64_t, ExpectedNan);
void WriteRefBits(uintptr_t ref_bits);
void WriteConst(const Const& const_);
void WriteConstVector(const ConstVector& consts);
void WriteAction(const Action& action);
void WriteActionResultType(const Action& action);
void WriteModule(string_view filename, const Module& module);
void WriteScriptModule(string_view filename,
const ScriptModule& script_module);
void WriteInvalidModule(const ScriptModule& module, string_view text);
void WriteCommands();
const Script* script_ = nullptr;
Stream* json_stream_ = nullptr;
WriteBinarySpecStreamFactory module_stream_factory_;
std::string source_filename_;
std::string module_filename_noext_;
const WriteBinaryOptions& options_;
Result result_ = Result::Ok;
size_t num_modules_ = 0;
};
BinaryWriterSpec::BinaryWriterSpec(
Stream* json_stream,
WriteBinarySpecStreamFactory module_stream_factory,
string_view source_filename,
string_view module_filename_noext,
const WriteBinaryOptions& options)
: json_stream_(json_stream),
module_stream_factory_(module_stream_factory),
source_filename_(source_filename),
module_filename_noext_(module_filename_noext),
options_(options) {}
std::string BinaryWriterSpec::GetModuleFilename(const char* extension) {
std::string result = module_filename_noext_;
result += '.';
result += std::to_string(num_modules_);
result += extension;
ConvertBackslashToSlash(&result);
return result;
}
void BinaryWriterSpec::WriteString(const char* s) {
json_stream_->Writef("\"%s\"", s);
}
void BinaryWriterSpec::WriteKey(const char* key) {
json_stream_->Writef("\"%s\": ", key);
}
void BinaryWriterSpec::WriteSeparator() {
json_stream_->Writef(", ");
}
void BinaryWriterSpec::WriteEscapedString(string_view s) {
json_stream_->WriteChar('"');
for (size_t i = 0; i < s.length(); ++i) {
uint8_t c = s[i];
if (c < 0x20 || c == '\\' || c == '"') {
json_stream_->Writef("\\u%04x", c);
} else {
json_stream_->WriteChar(c);
}
}
json_stream_->WriteChar('"');
}
void BinaryWriterSpec::WriteCommandType(const Command& command) {
static const char* s_command_names[] = {
"module",
"action",
"register",
"assert_malformed",
"assert_invalid",
"assert_unlinkable",
"assert_uninstantiable",
"assert_return",
"assert_trap",
"assert_exhaustion",
};
WABT_STATIC_ASSERT(WABT_ARRAY_SIZE(s_command_names) == kCommandTypeCount);
WriteKey("type");
assert(s_command_names[static_cast<size_t>(command.type)]);
WriteString(s_command_names[static_cast<size_t>(command.type)]);
}
void BinaryWriterSpec::WriteLocation(const Location& loc) {
WriteKey("line");
json_stream_->Writef("%d", loc.line);
}
void BinaryWriterSpec::WriteVar(const Var& var) {
if (var.is_index()) {
json_stream_->Writef("\"%" PRIindex "\"", var.index());
} else {
WriteEscapedString(var.name());
}
}
void BinaryWriterSpec::WriteTypeObject(Type type) {
json_stream_->Writef("{");
WriteKey("type");
WriteString(type.GetName());
json_stream_->Writef("}");
}
void BinaryWriterSpec::WriteF32(uint32_t f32_bits, ExpectedNan expected) {
switch (expected) {
case ExpectedNan::None:
json_stream_->Writef("\"%u\"", f32_bits);
break;
case ExpectedNan::Arithmetic:
WriteString("nan:arithmetic");
break;
case ExpectedNan::Canonical:
WriteString("nan:canonical");
break;
}
}
void BinaryWriterSpec::WriteF64(uint64_t f64_bits, ExpectedNan expected) {
switch (expected) {
case ExpectedNan::None:
json_stream_->Writef("\"%" PRIu64 "\"", f64_bits);
break;
case ExpectedNan::Arithmetic:
WriteString("nan:arithmetic");
break;
case ExpectedNan::Canonical:
WriteString("nan:canonical");
break;
}
}
void BinaryWriterSpec::WriteRefBits(uintptr_t ref_bits) {
if (ref_bits == Const::kRefNullBits) {
json_stream_->Writef("\"null\"");
} else {
json_stream_->Writef("\"%" PRIuPTR "\"", ref_bits);
}
}
void BinaryWriterSpec::WriteConst(const Const& const_) {
json_stream_->Writef("{");
WriteKey("type");
/* Always write the values as strings, even though they may be representable
* as JSON numbers. This way the formatting is consistent. */
switch (const_.type()) {
case Type::I32:
WriteString("i32");
WriteSeparator();
WriteKey("value");
json_stream_->Writef("\"%u\"", const_.u32());
break;
case Type::I64:
WriteString("i64");
WriteSeparator();
WriteKey("value");
json_stream_->Writef("\"%" PRIu64 "\"", const_.u64());
break;
case Type::F32:
WriteString("f32");
WriteSeparator();
WriteKey("value");
WriteF32(const_.f32_bits(), const_.expected_nan());
break;
case Type::F64:
WriteString("f64");
WriteSeparator();
WriteKey("value");
WriteF64(const_.f64_bits(), const_.expected_nan());
break;
case Type::FuncRef: {
WriteString("funcref");
WriteSeparator();
WriteKey("value");
WriteRefBits(const_.ref_bits());
break;
}
case Type::ExternRef: {
WriteString("externref");
WriteSeparator();
WriteKey("value");
WriteRefBits(const_.ref_bits());
break;
}
case Type::V128: {
WriteString("v128");
WriteSeparator();
WriteKey("lane_type");
WriteString(const_.lane_type().GetName());
WriteSeparator();
WriteKey("value");
json_stream_->Writef("[");
for (int lane = 0; lane < const_.lane_count(); ++lane) {
switch (const_.lane_type()) {
case Type::I8:
json_stream_->Writef("\"%u\"", const_.v128_lane<uint8_t>(lane));
break;
case Type::I16:
json_stream_->Writef("\"%u\"", const_.v128_lane<uint16_t>(lane));
break;
case Type::I32:
json_stream_->Writef("\"%u\"", const_.v128_lane<uint32_t>(lane));
break;
case Type::I64:
json_stream_->Writef("\"%" PRIu64 "\"",
const_.v128_lane<uint64_t>(lane));
break;
case Type::F32:
WriteF32(const_.v128_lane<uint32_t>(lane),
const_.expected_nan(lane));
break;
case Type::F64:
WriteF64(const_.v128_lane<uint64_t>(lane),
const_.expected_nan(lane));
break;
default:
WABT_UNREACHABLE;
}
if (lane != const_.lane_count() - 1) {
WriteSeparator();
}
}
json_stream_->Writef("]");
break;
}
default:
WABT_UNREACHABLE;
}
json_stream_->Writef("}");
}
void BinaryWriterSpec::WriteConstVector(const ConstVector& consts) {
json_stream_->Writef("[");
for (size_t i = 0; i < consts.size(); ++i) {
const Const& const_ = consts[i];
WriteConst(const_);
if (i != consts.size() - 1) {
WriteSeparator();
}
}
json_stream_->Writef("]");
}
void BinaryWriterSpec::WriteAction(const Action& action) {
WriteKey("action");
json_stream_->Writef("{");
WriteKey("type");
if (action.type() == ActionType::Invoke) {
WriteString("invoke");
} else {
assert(action.type() == ActionType::Get);
WriteString("get");
}
WriteSeparator();
if (action.module_var.is_name()) {
WriteKey("module");
WriteVar(action.module_var);
WriteSeparator();
}
if (action.type() == ActionType::Invoke) {
WriteKey("field");
WriteEscapedString(action.name);
WriteSeparator();
WriteKey("args");
WriteConstVector(cast<InvokeAction>(&action)->args);
} else {
WriteKey("field");
WriteEscapedString(action.name);
}
json_stream_->Writef("}");
}
void BinaryWriterSpec::WriteActionResultType(const Action& action) {
const Module* module = script_->GetModule(action.module_var);
const Export* export_;
json_stream_->Writef("[");
switch (action.type()) {
case ActionType::Invoke: {
export_ = module->GetExport(action.name);
assert(export_->kind == ExternalKind::Func);
const Func* func = module->GetFunc(export_->var);
Index num_results = func->GetNumResults();
for (Index i = 0; i < num_results; ++i)
WriteTypeObject(func->GetResultType(i));
break;
}
case ActionType::Get: {
export_ = module->GetExport(action.name);
assert(export_->kind == ExternalKind::Global);
const Global* global = module->GetGlobal(export_->var);
WriteTypeObject(global->type);
break;
}
}
json_stream_->Writef("]");
}
void BinaryWriterSpec::WriteModule(string_view filename, const Module& module) {
result_ |=
WriteBinaryModule(module_stream_factory_(filename), &module, options_);
}
void BinaryWriterSpec::WriteScriptModule(string_view filename,
const ScriptModule& script_module) {
switch (script_module.type()) {
case ScriptModuleType::Text:
WriteModule(filename, cast<TextScriptModule>(&script_module)->module);
break;
case ScriptModuleType::Binary:
module_stream_factory_(filename)->WriteData(
cast<BinaryScriptModule>(&script_module)->data, "");
break;
case ScriptModuleType::Quoted:
module_stream_factory_(filename)->WriteData(
cast<QuotedScriptModule>(&script_module)->data, "");
break;
}
}
void BinaryWriterSpec::WriteInvalidModule(const ScriptModule& module,
string_view text) {
const char* extension = "";
const char* module_type = "";
switch (module.type()) {
case ScriptModuleType::Text:
extension = kWasmExtension;
module_type = "binary";
break;
case ScriptModuleType::Binary:
extension = kWasmExtension;
module_type = "binary";
break;
case ScriptModuleType::Quoted:
extension = kWatExtension;
module_type = "text";
break;
}
WriteLocation(module.location());
WriteSeparator();
std::string filename = GetModuleFilename(extension);
WriteKey("filename");
WriteEscapedString(GetBasename(filename));
WriteSeparator();
WriteKey("text");
WriteEscapedString(text);
WriteSeparator();
WriteKey("module_type");
WriteString(module_type);
WriteScriptModule(filename, module);
}
void BinaryWriterSpec::WriteCommands() {
json_stream_->Writef("{\"source_filename\": ");
WriteEscapedString(source_filename_);
json_stream_->Writef(",\n \"commands\": [\n");
Index last_module_index = kInvalidIndex;
for (size_t i = 0; i < script_->commands.size(); ++i) {
const Command* command = script_->commands[i].get();
if (i != 0) {
WriteSeparator();
json_stream_->Writef("\n");
}
json_stream_->Writef(" {");
WriteCommandType(*command);
WriteSeparator();
switch (command->type) {
case CommandType::Module: {
const Module& module = cast<ModuleCommand>(command)->module;
std::string filename = GetModuleFilename(kWasmExtension);
WriteLocation(module.loc);
WriteSeparator();
if (!module.name.empty()) {
WriteKey("name");
WriteEscapedString(module.name);
WriteSeparator();
}
WriteKey("filename");
WriteEscapedString(GetBasename(filename));
WriteModule(filename, module);
num_modules_++;
last_module_index = i;
break;
}
case CommandType::Action: {
const Action& action = *cast<ActionCommand>(command)->action;
WriteLocation(action.loc);
WriteSeparator();
WriteAction(action);
WriteSeparator();
WriteKey("expected");
WriteActionResultType(action);
break;
}
case CommandType::Register: {
auto* register_command = cast<RegisterCommand>(command);
const Var& var = register_command->var;
WriteLocation(var.loc);
WriteSeparator();
if (var.is_name()) {
WriteKey("name");
WriteVar(var);
WriteSeparator();
} else {
/* If we're not registering by name, then we should only be
* registering the last module. */
WABT_USE(last_module_index);
assert(var.index() == last_module_index);
}
WriteKey("as");
WriteEscapedString(register_command->module_name);
break;
}
case CommandType::AssertMalformed: {
auto* assert_malformed_command = cast<AssertMalformedCommand>(command);
WriteInvalidModule(*assert_malformed_command->module,
assert_malformed_command->text);
num_modules_++;
break;
}
case CommandType::AssertInvalid: {
auto* assert_invalid_command = cast<AssertInvalidCommand>(command);
WriteInvalidModule(*assert_invalid_command->module,
assert_invalid_command->text);
num_modules_++;
break;
}
case CommandType::AssertUnlinkable: {
auto* assert_unlinkable_command =
cast<AssertUnlinkableCommand>(command);
WriteInvalidModule(*assert_unlinkable_command->module,
assert_unlinkable_command->text);
num_modules_++;
break;
}
case CommandType::AssertUninstantiable: {
auto* assert_uninstantiable_command =
cast<AssertUninstantiableCommand>(command);
WriteInvalidModule(*assert_uninstantiable_command->module,
assert_uninstantiable_command->text);
num_modules_++;
break;
}
case CommandType::AssertReturn: {
auto* assert_return_command = cast<AssertReturnCommand>(command);
WriteLocation(assert_return_command->action->loc);
WriteSeparator();
WriteAction(*assert_return_command->action);
WriteSeparator();
WriteKey("expected");
WriteConstVector(assert_return_command->expected);
break;
}
case CommandType::AssertTrap: {
auto* assert_trap_command = cast<AssertTrapCommand>(command);
WriteLocation(assert_trap_command->action->loc);
WriteSeparator();
WriteAction(*assert_trap_command->action);
WriteSeparator();
WriteKey("text");
WriteEscapedString(assert_trap_command->text);
WriteSeparator();
WriteKey("expected");
WriteActionResultType(*assert_trap_command->action);
break;
}
case CommandType::AssertExhaustion: {
auto* assert_exhaustion_command =
cast<AssertExhaustionCommand>(command);
WriteLocation(assert_exhaustion_command->action->loc);
WriteSeparator();
WriteAction(*assert_exhaustion_command->action);
WriteSeparator();
WriteKey("text");
WriteEscapedString(assert_exhaustion_command->text);
WriteSeparator();
WriteKey("expected");
WriteActionResultType(*assert_exhaustion_command->action);
break;
}
}
json_stream_->Writef("}");
}
json_stream_->Writef("]}\n");
}
Result BinaryWriterSpec::WriteScript(const Script& script) {
script_ = &script;
WriteCommands();
return result_;
}
} // end anonymous namespace
Result WriteBinarySpecScript(Stream* json_stream,
WriteBinarySpecStreamFactory module_stream_factory,
Script* script,
string_view source_filename,
string_view module_filename_noext,
const WriteBinaryOptions& options) {
BinaryWriterSpec binary_writer_spec(json_stream, module_stream_factory,
source_filename, module_filename_noext,
options);
return binary_writer_spec.WriteScript(*script);
}
Result WriteBinarySpecScript(
Stream* json_stream,
Script* script,
string_view source_filename,
string_view module_filename_noext,
const WriteBinaryOptions& options,
std::vector<FilenameMemoryStreamPair>* out_module_streams,
Stream* log_stream) {
WriteBinarySpecStreamFactory module_stream_factory =
[&](string_view filename) {
out_module_streams->emplace_back(filename,
MakeUnique<MemoryStream>(log_stream));
return out_module_streams->back().stream.get();
};
BinaryWriterSpec binary_writer_spec(json_stream, module_stream_factory,
source_filename, module_filename_noext,
options);
return binary_writer_spec.WriteScript(*script);
}
} // namespace wabt

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_BINARY_WRITER_SPEC_H_
#define WABT_BINARY_WRITER_SPEC_H_
#include <functional>
#include <utility>
#include <vector>
#include "src/binary-writer.h"
#include "src/common.h"
#include "src/ir.h"
namespace wabt {
struct FilenameMemoryStreamPair {
FilenameMemoryStreamPair(string_view filename,
std::unique_ptr<MemoryStream> stream)
: filename(filename), stream(std::move(stream)) {}
std::string filename;
std::unique_ptr<MemoryStream> stream;
};
typedef std::function<Stream*(string_view filename)>
WriteBinarySpecStreamFactory;
Result WriteBinarySpecScript(Stream* json_stream,
WriteBinarySpecStreamFactory module_stream_factory,
Script*,
string_view source_filename,
string_view module_filename_noext,
const WriteBinaryOptions&);
// Convenience function for producing MemoryStream outputs all modules.
Result WriteBinarySpecScript(
Stream* json_stream,
Script*,
string_view source_filename,
string_view module_filename_noext,
const WriteBinaryOptions&,
std::vector<FilenameMemoryStreamPair>* out_module_streams,
Stream* log_stream = nullptr);
} // namespace wabt
#endif /* WABT_BINARY_WRITER_SPEC_H_ */

1670
third_party/wasm2c/src/binary-writer.cc vendored Normal file

File diff suppressed because it is too large Load Diff

62
third_party/wasm2c/src/binary-writer.h vendored Normal file
View File

@@ -0,0 +1,62 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_BINARY_WRITER_H_
#define WABT_BINARY_WRITER_H_
#include "src/common.h"
#include "src/feature.h"
#include "src/opcode.h"
#include "src/stream.h"
namespace wabt {
struct Module;
struct Script;
struct WriteBinaryOptions {
WriteBinaryOptions() = default;
WriteBinaryOptions(const Features& features,
bool canonicalize_lebs,
bool relocatable,
bool write_debug_names)
: features(features),
canonicalize_lebs(canonicalize_lebs),
relocatable(relocatable),
write_debug_names(write_debug_names) {}
Features features;
bool canonicalize_lebs = true;
bool relocatable = false;
bool write_debug_names = false;
};
Result WriteBinaryModule(Stream*, const Module*, const WriteBinaryOptions&);
void WriteType(Stream* stream, Type type, const char* desc = nullptr);
void WriteStr(Stream* stream,
string_view s,
const char* desc,
PrintChars print_chars = PrintChars::No);
void WriteOpcode(Stream* stream, Opcode opcode);
void WriteLimits(Stream* stream, const Limits* limits);
} // namespace wabt
#endif /* WABT_BINARY_WRITER_H_ */

62
third_party/wasm2c/src/binary.cc vendored Normal file
View File

@@ -0,0 +1,62 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/binary.h"
namespace wabt {
BinarySectionOrder GetSectionOrder(BinarySection sec) {
switch (sec) {
#define V(Name, name, code) \
case BinarySection::Name: \
return BinarySectionOrder::Name;
WABT_FOREACH_BINARY_SECTION(V)
#undef V
default:
WABT_UNREACHABLE;
}
}
const char* GetSectionName(BinarySection sec) {
switch (sec) {
#define V(Name, name, code) \
case BinarySection::Name: \
return #Name;
WABT_FOREACH_BINARY_SECTION(V)
#undef V
default:
WABT_UNREACHABLE;
}
}
const char* NameSubsectionName[] = {
"module",
"function",
"local",
"label",
"type",
"table",
"memory",
"global",
"elemseg",
"dataseg",
};
const char* GetNameSectionSubsectionName(NameSectionSubsection subsec) {
return NameSubsectionName[size_t(subsec)];
}
} // namespace wabt

93
third_party/wasm2c/src/binary.h vendored Normal file
View File

@@ -0,0 +1,93 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_BINARY_H_
#define WABT_BINARY_H_
#include "src/common.h"
#define WABT_BINARY_MAGIC 0x6d736100
#define WABT_BINARY_VERSION 1
#define WABT_BINARY_LIMITS_HAS_MAX_FLAG 0x1
#define WABT_BINARY_LIMITS_IS_SHARED_FLAG 0x2
#define WABT_BINARY_LIMITS_IS_64_FLAG 0x4
#define WABT_BINARY_LIMITS_ALL_FLAGS \
(WABT_BINARY_LIMITS_HAS_MAX_FLAG | WABT_BINARY_LIMITS_IS_SHARED_FLAG | \
WABT_BINARY_LIMITS_IS_64_FLAG)
#define WABT_BINARY_SECTION_NAME "name"
#define WABT_BINARY_SECTION_RELOC "reloc"
#define WABT_BINARY_SECTION_LINKING "linking"
#define WABT_BINARY_SECTION_DYLINK "dylink"
#define WABT_FOREACH_BINARY_SECTION(V) \
V(Custom, custom, 0) \
V(Type, type, 1) \
V(Import, import, 2) \
V(Function, function, 3) \
V(Table, table, 4) \
V(Memory, memory, 5) \
V(Event, event, 13) \
V(Global, global, 6) \
V(Export, export, 7) \
V(Start, start, 8) \
V(Elem, elem, 9) \
V(DataCount, data_count, 12) \
V(Code, code, 10) \
V(Data, data, 11)
namespace wabt {
/* clang-format off */
enum class BinarySection {
#define V(Name, name, code) Name = code,
WABT_FOREACH_BINARY_SECTION(V)
#undef V
Invalid = ~0,
First = Custom,
Last = Event,
};
/* clang-format on */
static const int kBinarySectionCount = WABT_ENUM_COUNT(BinarySection);
enum class BinarySectionOrder {
#define V(Name, name, code) Name,
WABT_FOREACH_BINARY_SECTION(V)
#undef V
};
BinarySectionOrder GetSectionOrder(BinarySection);
const char* GetSectionName(BinarySection);
enum class NameSectionSubsection {
Module = 0,
Function = 1,
Local = 2,
Label = 3,
Type = 4,
Table = 5,
Memory = 6,
Global = 7,
ElemSegment = 8,
DataSegment = 9,
Last = DataSegment,
};
const char* GetNameSectionSubsectionName(NameSectionSubsection subsec);
} // namespace wabt
#endif /* WABT_BINARY_H_ */

91
third_party/wasm2c/src/binding-hash.cc vendored Normal file
View File

@@ -0,0 +1,91 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/binding-hash.h"
#include <algorithm>
#include <vector>
#include "src/ir.h"
namespace wabt {
void BindingHash::FindDuplicates(DuplicateCallback callback) const {
if (size() > 0) {
ValueTypeVector duplicates;
CreateDuplicatesVector(&duplicates);
SortDuplicatesVectorByLocation(&duplicates);
CallCallbacks(duplicates, callback);
}
}
Index BindingHash::FindIndex(const Var& var) const {
if (var.is_name()) {
return FindIndex(var.name());
}
return var.index();
}
void BindingHash::CreateDuplicatesVector(
ValueTypeVector* out_duplicates) const {
// This relies on the fact that in an unordered_multimap, all values with the
// same key are adjacent in iteration order.
auto first = begin();
bool is_first = true;
for (auto iter = std::next(first); iter != end(); ++iter) {
if (first->first == iter->first) {
if (is_first) {
out_duplicates->push_back(&*first);
}
out_duplicates->push_back(&*iter);
is_first = false;
} else {
is_first = true;
first = iter;
}
}
}
void BindingHash::SortDuplicatesVectorByLocation(
ValueTypeVector* duplicates) const {
std::sort(
duplicates->begin(), duplicates->end(),
[](const value_type* lhs, const value_type* rhs) -> bool {
return lhs->second.loc.line < rhs->second.loc.line ||
(lhs->second.loc.line == rhs->second.loc.line &&
lhs->second.loc.first_column < rhs->second.loc.first_column);
});
}
void BindingHash::CallCallbacks(const ValueTypeVector& duplicates,
DuplicateCallback callback) const {
// Loop through all duplicates in order, and call callback with first
// occurrence.
for (auto iter = duplicates.begin(), end = duplicates.end(); iter != end;
++iter) {
auto first = std::find_if(duplicates.begin(), duplicates.end(),
[iter](const value_type* x) -> bool {
return x->first == (*iter)->first;
});
if (first == iter) {
continue;
}
assert(first != duplicates.end());
callback(**first, **iter);
}
}
} // namespace wabt

72
third_party/wasm2c/src/binding-hash.h vendored Normal file
View File

@@ -0,0 +1,72 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_BINDING_HASH_H_
#define WABT_BINDING_HASH_H_
#include <functional>
#include <string>
#include <unordered_map>
#include <vector>
#include "src/common.h"
#include "src/string-view.h"
namespace wabt {
struct Var;
struct Binding {
explicit Binding(Index index) : index(index) {}
Binding(const Location& loc, Index index) : loc(loc), index(index) {}
Location loc;
Index index;
};
// This class derives from a C++ container, which is usually not advisable
// because they don't have virtual destructors. So don't delete a BindingHash
// object through a pointer to std::unordered_multimap.
class BindingHash : public std::unordered_multimap<std::string, Binding> {
public:
typedef std::function<void(const value_type&, const value_type&)>
DuplicateCallback;
void FindDuplicates(DuplicateCallback callback) const;
Index FindIndex(const Var&) const;
Index FindIndex(const std::string& name) const {
auto iter = find(name);
return iter != end() ? iter->second.index : kInvalidIndex;
}
Index FindIndex(string_view name) const {
return FindIndex(name.to_string());
}
private:
typedef std::vector<const value_type*> ValueTypeVector;
void CreateDuplicatesVector(ValueTypeVector* out_duplicates) const;
void SortDuplicatesVectorByLocation(ValueTypeVector* duplicates) const;
void CallCallbacks(const ValueTypeVector& duplicates,
DuplicateCallback callback) const;
};
} // namespace wabt
#endif /* WABT_BINDING_HASH_H_ */

2361
third_party/wasm2c/src/c-writer.cc vendored Normal file

File diff suppressed because it is too large Load Diff

41
third_party/wasm2c/src/c-writer.h vendored Normal file
View File

@@ -0,0 +1,41 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_C_WRITER_H_
#define WABT_C_WRITER_H_
#include "src/common.h"
#include <string>
namespace wabt {
struct Module;
class Stream;
struct WriteCOptions {
std::string mod_name;
};
Result WriteC(Stream* c_stream,
Stream* h_stream,
const char* header_name,
const Module*,
const WriteCOptions&);
} // namespace wabt
#endif /* WABT_C_WRITER_H_ */

109
third_party/wasm2c/src/cast.h vendored Normal file
View File

@@ -0,0 +1,109 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_CAST_H_
#define WABT_CAST_H_
#include <memory>
#include <type_traits>
#include "src/common.h"
// Modeled after LLVM's dynamic casts:
// http://llvm.org/docs/ProgrammersManual.html#the-isa-cast-and-dyn-cast-templates
//
// Use isa<T>(foo) to check whether foo is a T*:
//
// if (isa<Minivan>(car)) {
// ...
// }
//
// Use cast<T>(foo) when you know that foo is a T* -- it will assert that the
// type matches:
//
// switch (car.type) {
// case CarType::Minivan: {
// auto minivan = cast<Minivan>(car);
// ...
// }
// }
//
// Use dyn_cast<T>(foo) as a combination if isa and cast, it will return
// nullptr if the type doesn't match:
//
// if (auto minivan = dyn_cast<Minivan>(car)) {
// ...
// }
//
//
// To use these classes in a type hierarchy, you must implement classof:
//
// enum CarType { Minivan, ... };
// struct Car { CarType type; ... };
// struct Minivan : Car {
// static bool classof(const Car* car) { return car->type == Minivan; }
// ...
// };
//
namespace wabt {
template <typename Derived, typename Base>
bool isa(const Base* base) {
WABT_STATIC_ASSERT((std::is_base_of<Base, Derived>::value));
return Derived::classof(base);
}
template <typename Derived, typename Base>
const Derived* cast(const Base* base) {
assert(isa<Derived>(base));
return static_cast<const Derived*>(base);
};
template <typename Derived, typename Base>
Derived* cast(Base* base) {
assert(isa<Derived>(base));
return static_cast<Derived*>(base);
};
template <typename Derived, typename Base>
const Derived* dyn_cast(const Base* base) {
return isa<Derived>(base) ? static_cast<const Derived*>(base) : nullptr;
};
template <typename Derived, typename Base>
Derived* dyn_cast(Base* base) {
return isa<Derived>(base) ? static_cast<Derived*>(base) : nullptr;
};
// Cast functionality for unique_ptr. isa and dyn_cast are not included because
// they won't always pass ownership back to the caller.
template <typename Derived, typename Base>
std::unique_ptr<const Derived> cast(std::unique_ptr<const Base>&& base) {
assert(isa<Derived>(base.get()));
return std::unique_ptr<Derived>(static_cast<const Derived*>(base.release()));
};
template <typename Derived, typename Base>
std::unique_ptr<Derived> cast(std::unique_ptr<Base>&& base) {
assert(isa<Derived>(base.get()));
return std::unique_ptr<Derived>(static_cast<Derived*>(base.release()));
};
} // namespace wabt
#endif // WABT_CAST_H_

123
third_party/wasm2c/src/circular-array.h vendored Normal file
View File

@@ -0,0 +1,123 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_CIRCULAR_ARRAY_H_
#define WABT_CIRCULAR_ARRAY_H_
#include <array>
#include <cassert>
#include <cstddef>
#include <type_traits>
namespace wabt {
// TODO(karlschimpf) Complete the API
// Note: Capacity must be a power of 2.
template <class T, size_t kCapacity>
class CircularArray {
public:
typedef T value_type;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
CircularArray() {
static_assert(kCapacity && ((kCapacity & (kCapacity - 1)) == 0),
"Capacity must be a power of 2.");
}
CircularArray(const CircularArray&) = default;
CircularArray& operator=(const CircularArray&) = default;
CircularArray(CircularArray&&) = default;
CircularArray& operator=(CircularArray&&) = default;
~CircularArray() { clear(); }
reference at(size_type index) {
assert(index < size_);
return (*this)[index];
}
const_reference at(size_type index) const {
assert(index < size_);
return (*this)[index];
}
reference operator[](size_type index) { return contents_[position(index)]; }
const_reference operator[](size_type index) const {
return contents_[position(index)];
}
reference back() { return at(size_ - 1); }
const_reference back() const { return at(size_ - 1); }
bool empty() const { return size_ == 0; }
reference front() { return at(0); }
const_reference front() const { return at(0); }
size_type max_size() const { return kCapacity; }
void pop_back() {
assert(size_ > 0);
SetElement(back());
--size_;
}
void pop_front() {
assert(size_ > 0);
SetElement(front());
front_ = (front_ + 1) & kMask;
--size_;
}
void push_back(const value_type& value) {
assert(size_ < kCapacity);
SetElement(at(size_++), value);
}
size_type size() const { return size_; }
void clear() {
while (!empty()) {
pop_back();
}
}
private:
static const size_type kMask = kCapacity - 1;
size_t position(size_t index) const { return (front_ + index) & kMask; }
template <typename... Args>
void SetElement(reference element, Args&&... args) {
element.~T();
new (&element) T(std::forward<Args>(args)...);
}
std::array<T, kCapacity> contents_;
size_type size_ = 0;
size_type front_ = 0;
};
} // namespace wabt
#endif // WABT_CIRCULAR_ARRAY_H_

84
third_party/wasm2c/src/color.cc vendored Normal file
View File

@@ -0,0 +1,84 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/color.h"
#include <cstdlib>
#include "src/common.h"
#if _WIN32
#include <io.h>
#include <windows.h>
#elif HAVE_UNISTD_H
#include <unistd.h>
#endif
namespace wabt {
Color::Color(FILE* file, bool enabled) : file_(file) {
enabled_ = enabled && SupportsColor(file_);
}
// static
bool Color::SupportsColor(FILE* file) {
char* force = getenv("FORCE_COLOR");
if (force) {
return atoi(force) != 0;
}
#if _WIN32
{
#if HAVE_WIN32_VT100
HANDLE handle;
if (file == stdout) {
handle = GetStdHandle(STD_OUTPUT_HANDLE);
} else if (file == stderr) {
handle = GetStdHandle(STD_ERROR_HANDLE);
} else {
return false;
}
DWORD mode;
if (!_isatty(_fileno(file)) || !GetConsoleMode(handle, &mode) ||
!SetConsoleMode(handle, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) {
return false;
}
return true;
#else
// TODO(binji): Support older Windows by using SetConsoleTextAttribute?
return false;
#endif
}
#elif HAVE_UNISTD_H
return isatty(fileno(file));
#else
return false;
#endif
}
void Color::WriteCode(const char* code) const {
if (enabled_) {
fputs(code, file_);
}
}
} // namespace wabt

72
third_party/wasm2c/src/color.h vendored Normal file
View File

@@ -0,0 +1,72 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_COLOR_H_
#define WABT_COLOR_H_
#include <cstdio>
namespace wabt {
#define WABT_FOREACH_COLOR_CODE(V) \
V(Default, "\x1b[0m") \
V(Bold, "\x1b[1m") \
V(NoBold, "\x1b[22m") \
V(Black, "\x1b[30m") \
V(Red, "\x1b[31m") \
V(Green, "\x1b[32m") \
V(Yellow, "\x1b[33m") \
V(Blue, "\x1b[34m") \
V(Magenta, "\x1b[35m") \
V(Cyan, "\x1b[36m") \
V(White, "\x1b[37m")
class Color {
public:
Color() : file_(nullptr), enabled_(false) {}
Color(FILE*, bool enabled = true);
// Write the given color to the file, if enabled.
#define WABT_COLOR(Name, code) \
void Name() const { WriteCode(Name##Code()); }
WABT_FOREACH_COLOR_CODE(WABT_COLOR)
#undef WABT_COLOR
// Get the color code as a string, if enabled.
#define WABT_COLOR(Name, code) \
const char* Maybe##Name##Code() const { return enabled_ ? Name##Code() : ""; }
WABT_FOREACH_COLOR_CODE(WABT_COLOR)
#undef WABT_COLOR
// Get the color code as a string.
#define WABT_COLOR(Name, code) \
static const char* Name##Code() { return code; }
WABT_FOREACH_COLOR_CODE(WABT_COLOR)
#undef WABT_COLOR
private:
static bool SupportsColor(FILE*);
void WriteCode(const char*) const;
FILE* file_;
bool enabled_;
};
#undef WABT_FOREACH_COLOR_CODE
} // namespace wabt
#endif // WABT_COLOR_H_

147
third_party/wasm2c/src/common.cc vendored Normal file
View File

@@ -0,0 +1,147 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/common.h"
#include <cassert>
#include <climits>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <sys/types.h>
#include <sys/stat.h>
#if COMPILER_IS_MSVC
#include <fcntl.h>
#include <io.h>
#include <stdlib.h>
#define PATH_MAX _MAX_PATH
#define stat _stat
#define S_IFREG _S_IFREG
#endif
namespace wabt {
Reloc::Reloc(RelocType type, Offset offset, Index index, int32_t addend)
: type(type), offset(offset), index(index), addend(addend) {}
const char* g_kind_name[] = {"func", "table", "memory", "global", "event"};
WABT_STATIC_ASSERT(WABT_ARRAY_SIZE(g_kind_name) == kExternalKindCount);
const char* g_reloc_type_name[] = {
"R_WASM_FUNCTION_INDEX_LEB", "R_WASM_TABLE_INDEX_SLEB",
"R_WASM_TABLE_INDEX_I32", "R_WASM_MEMORY_ADDR_LEB",
"R_WASM_MEMORY_ADDR_SLEB", "R_WASM_MEMORY_ADDR_I32",
"R_WASM_TYPE_INDEX_LEB", "R_WASM_GLOBAL_INDEX_LEB",
"R_WASM_FUNCTION_OFFSET_I32", "R_WASM_SECTION_OFFSET_I32",
"R_WASM_EVENT_INDEX_LEB", "R_WASM_MEMORY_ADDR_REL_SLEB",
"R_WASM_TABLE_INDEX_REL_SLEB", "R_WASM_GLOBAL_INDEX_I32",
"R_WASM_MEMORY_ADDR_LEB64", "R_WASM_MEMORY_ADDR_SLEB64",
"R_WASM_MEMORY_ADDR_I64", "R_WASM_MEMORY_ADDR_REL_SLEB64",
"R_WASM_TABLE_INDEX_SLEB64", "R_WASM_TABLE_INDEX_I64",
"R_WASM_TABLE_NUMBER_LEB", "R_WASM_MEMORY_ADDR_TLS_SLEB",
"R_WASM_MEMORY_ADDR_TLS_I32",
};
WABT_STATIC_ASSERT(WABT_ARRAY_SIZE(g_reloc_type_name) == kRelocTypeCount);
static Result ReadStdin(std::vector<uint8_t>* out_data) {
out_data->resize(0);
uint8_t buffer[4096];
while (true) {
size_t bytes_read = fread(buffer, 1, sizeof(buffer), stdin);
if (bytes_read == 0) {
if (ferror(stdin)) {
fprintf(stderr, "error reading from stdin: %s\n", strerror(errno));
return Result::Error;
}
return Result::Ok;
}
size_t old_size = out_data->size();
out_data->resize(old_size + bytes_read);
memcpy(out_data->data() + old_size, buffer, bytes_read);
}
}
Result ReadFile(string_view filename, std::vector<uint8_t>* out_data) {
std::string filename_str = filename.to_string();
const char* filename_cstr = filename_str.c_str();
if (filename == "-") {
return ReadStdin(out_data);
}
struct stat statbuf;
if (stat(filename_cstr, &statbuf) < 0) {
fprintf(stderr, "%s: %s\n", filename_cstr, strerror(errno));
return Result::Error;
}
if (!(statbuf.st_mode & S_IFREG)) {
fprintf(stderr, "%s: not a regular file\n", filename_cstr);
return Result::Error;
}
FILE* infile = fopen(filename_cstr, "rb");
if (!infile) {
fprintf(stderr, "%s: %s\n", filename_cstr, strerror(errno));
return Result::Error;
}
if (fseek(infile, 0, SEEK_END) < 0) {
perror("fseek to end failed");
fclose(infile);
return Result::Error;
}
long size = ftell(infile);
if (size < 0) {
perror("ftell failed");
fclose(infile);
return Result::Error;
}
if (fseek(infile, 0, SEEK_SET) < 0) {
perror("fseek to beginning failed");
fclose(infile);
return Result::Error;
}
out_data->resize(size);
if (size != 0 && fread(out_data->data(), size, 1, infile) != 1) {
fprintf(stderr, "%s: fread failed: %s\n", filename_cstr, strerror(errno));
fclose(infile);
return Result::Error;
}
fclose(infile);
return Result::Ok;
}
void InitStdio() {
#if COMPILER_IS_MSVC
int result = _setmode(_fileno(stdout), _O_BINARY);
if (result == -1) {
perror("Cannot set mode binary to stdout");
}
result = _setmode(_fileno(stderr), _O_BINARY);
if (result == -1) {
perror("Cannot set mode binary to stderr");
}
#endif
}
} // namespace wabt

479
third_party/wasm2c/src/common.h vendored Normal file
View File

@@ -0,0 +1,479 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_COMMON_H_
#define WABT_COMMON_H_
#include <algorithm>
#include <cassert>
#include <cstdarg>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <memory>
#include <string>
#include <type_traits>
#include <vector>
#include "config.h"
#include "src/make-unique.h"
#include "src/result.h"
#include "src/string-view.h"
#include "src/type.h"
#define WABT_FATAL(...) fprintf(stderr, __VA_ARGS__), exit(1)
#define WABT_ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#define WABT_USE(x) static_cast<void>(x)
#define WABT_PAGE_SIZE 0x10000 /* 64k */
#define WABT_MAX_PAGES 0x10000 /* # of pages that fit in 32-bit address space \
*/
#define WABT_BYTES_TO_PAGES(x) ((x) >> 16)
#define WABT_ALIGN_UP_TO_PAGE(x) \
(((x) + WABT_PAGE_SIZE - 1) & ~(WABT_PAGE_SIZE - 1))
#define PRIstringview "%.*s"
#define WABT_PRINTF_STRING_VIEW_ARG(x) \
static_cast<int>((x).length()), (x).data()
#define PRItypecode "%s%#x"
#define WABT_PRINTF_TYPE_CODE(x) \
(static_cast<int32_t>(x) < 0 ? "-" : ""), std::abs(static_cast<int32_t>(x))
#define WABT_DEFAULT_SNPRINTF_ALLOCA_BUFSIZE 128
#define WABT_SNPRINTF_ALLOCA(buffer, len, format) \
va_list args; \
va_list args_copy; \
va_start(args, format); \
va_copy(args_copy, args); \
char fixed_buf[WABT_DEFAULT_SNPRINTF_ALLOCA_BUFSIZE]; \
char* buffer = fixed_buf; \
size_t len = wabt_vsnprintf(fixed_buf, sizeof(fixed_buf), format, args); \
va_end(args); \
if (len + 1 > sizeof(fixed_buf)) { \
buffer = static_cast<char*>(alloca(len + 1)); \
len = wabt_vsnprintf(buffer, len + 1, format, args_copy); \
} \
va_end(args_copy)
#define WABT_ENUM_COUNT(name) \
(static_cast<int>(name::Last) - static_cast<int>(name::First) + 1)
#define WABT_DISALLOW_COPY_AND_ASSIGN(type) \
type(const type&) = delete; \
type& operator=(const type&) = delete;
#if WITH_EXCEPTIONS
#define WABT_TRY try {
#define WABT_CATCH_BAD_ALLOC \
} \
catch (std::bad_alloc&) { \
}
#define WABT_CATCH_BAD_ALLOC_AND_EXIT \
} \
catch (std::bad_alloc&) { \
WABT_FATAL("Memory allocation failure.\n"); \
}
#else
#define WABT_TRY
#define WABT_CATCH_BAD_ALLOC
#define WABT_CATCH_BAD_ALLOC_AND_EXIT
#endif
#define PRIindex "u"
#define PRIaddress PRIu64
#define PRIoffset PRIzx
namespace wabt {
#if WABT_BIG_ENDIAN
inline void MemcpyEndianAware(void *dst, const void *src, size_t dsize, size_t ssize, size_t doff, size_t soff, size_t len) {
memcpy(static_cast<char*>(dst) + (dsize) - (len) - (doff),
static_cast<const char*>(src) + (ssize) - (len) - (soff),
(len));
}
#else
inline void MemcpyEndianAware(void *dst, const void *src, size_t dsize, size_t ssize, size_t doff, size_t soff, size_t len) {
memcpy(static_cast<char*>(dst) + (doff),
static_cast<const char*>(src) + (soff),
(len));
}
#endif
}
struct v128 {
v128() = default;
v128(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3) {
set_u32(0, x0);
set_u32(1, x1);
set_u32(2, x2);
set_u32(3, x3);
}
bool operator==(const v128& other) const {
return std::equal(std::begin(v), std::end(v), std::begin(other.v));
}
bool operator!=(const v128& other) const { return !(*this == other); }
uint8_t u8(int lane) const { return To<uint8_t>(lane); }
uint16_t u16(int lane) const { return To<uint16_t>(lane); }
uint32_t u32(int lane) const { return To<uint32_t>(lane); }
uint64_t u64(int lane) const { return To<uint64_t>(lane); }
uint32_t f32_bits(int lane) const { return To<uint32_t>(lane); }
uint64_t f64_bits(int lane) const { return To<uint64_t>(lane); }
void set_u8(int lane, uint8_t x) { return From<uint8_t>(lane, x); }
void set_u16(int lane, uint16_t x) { return From<uint16_t>(lane, x); }
void set_u32(int lane, uint32_t x) { return From<uint32_t>(lane, x); }
void set_u64(int lane, uint64_t x) { return From<uint64_t>(lane, x); }
void set_f32_bits(int lane, uint32_t x) { return From<uint32_t>(lane, x); }
void set_f64_bits(int lane, uint64_t x) { return From<uint64_t>(lane, x); }
bool is_zero() const {
return std::all_of(std::begin(v), std::end(v),
[](uint8_t x) { return x == 0; });
}
void set_zero() { std::fill(std::begin(v), std::end(v), 0); }
template <typename T>
T To(int lane) const {
static_assert(sizeof(T) <= sizeof(v), "Invalid cast!");
assert((lane + 1) * sizeof(T) <= sizeof(v));
T result;
wabt::MemcpyEndianAware(&result, v, sizeof(result), sizeof(v), 0, lane * sizeof(T), sizeof(result));
return result;
}
template <typename T>
void From(int lane, T data) {
static_assert(sizeof(T) <= sizeof(v), "Invalid cast!");
assert((lane + 1) * sizeof(T) <= sizeof(v));
wabt::MemcpyEndianAware(v, &data, sizeof(v), sizeof(data), lane * sizeof(T), 0, sizeof(data));
}
uint8_t v[16];
};
namespace wabt {
typedef uint32_t Index; // An index into one of the many index spaces.
typedef uint64_t Address; // An address or size in linear memory.
typedef size_t Offset; // An offset into a host's file or memory buffer.
static const Address kInvalidAddress = ~0;
static const Index kInvalidIndex = ~0;
static const Offset kInvalidOffset = ~0;
template <typename Dst, typename Src>
Dst WABT_VECTORCALL Bitcast(Src&& value) {
static_assert(sizeof(Src) == sizeof(Dst), "Bitcast sizes must match.");
Dst result;
memcpy(&result, &value, sizeof(result));
return result;
}
template <typename T>
void ZeroMemory(T& v) {
WABT_STATIC_ASSERT(std::is_pod<T>::value);
memset(&v, 0, sizeof(v));
}
// Placement construct
template <typename T, typename... Args>
void Construct(T& placement, Args&&... args) {
new (&placement) T(std::forward<Args>(args)...);
}
// Placement destruct
template <typename T>
void Destruct(T& placement) {
placement.~T();
}
inline std::string WABT_PRINTF_FORMAT(1, 2)
StringPrintf(const char* format, ...) {
va_list args;
va_list args_copy;
va_start(args, format);
va_copy(args_copy, args);
size_t len = wabt_vsnprintf(nullptr, 0, format, args) + 1; // For \0.
std::vector<char> buffer(len);
va_end(args);
wabt_vsnprintf(buffer.data(), len, format, args_copy);
va_end(args_copy);
return std::string(buffer.data(), len - 1);
}
enum class LabelType {
Func,
Block,
Loop,
If,
Else,
Try,
Catch,
Unwind,
First = Func,
Last = Unwind,
};
static const int kLabelTypeCount = WABT_ENUM_COUNT(LabelType);
struct Location {
enum class Type {
Text,
Binary,
};
Location() : line(0), first_column(0), last_column(0) {}
Location(string_view filename, int line, int first_column, int last_column)
: filename(filename),
line(line),
first_column(first_column),
last_column(last_column) {}
explicit Location(size_t offset) : offset(offset) {}
string_view filename;
union {
// For text files.
struct {
int line;
int first_column;
int last_column;
};
// For binary files.
struct {
size_t offset;
};
};
};
enum class SegmentKind {
Active,
Passive,
Declared,
};
// Used in test asserts for special expected values "nan:canonical" and
// "nan:arithmetic"
enum class ExpectedNan {
None,
Canonical,
Arithmetic,
};
// Matches binary format, do not change.
enum SegmentFlags : uint8_t {
SegFlagsNone = 0,
SegPassive = 1, // bit 0: Is passive
SegExplicitIndex = 2, // bit 1: Has explict index (Implies table 0 if absent)
SegDeclared = 3, // Only used for declared segments
SegUseElemExprs = 4, // bit 2: Is elemexpr (Or else index sequence)
SegFlagMax = (SegUseElemExprs << 1) - 1, // All bits set.
};
enum class RelocType {
FuncIndexLEB = 0, // e.g. Immediate of call instruction
TableIndexSLEB = 1, // e.g. Loading address of function
TableIndexI32 = 2, // e.g. Function address in DATA
MemoryAddressLEB = 3, // e.g. Memory address in load/store offset immediate
MemoryAddressSLEB = 4, // e.g. Memory address in i32.const
MemoryAddressI32 = 5, // e.g. Memory address in DATA
TypeIndexLEB = 6, // e.g. Immediate type in call_indirect
GlobalIndexLEB = 7, // e.g. Immediate of get_global inst
FunctionOffsetI32 = 8, // e.g. Code offset in DWARF metadata
SectionOffsetI32 = 9, // e.g. Section offset in DWARF metadata
EventIndexLEB = 10, // Used in throw instructions
MemoryAddressRelSLEB = 11, // In PIC code, addr relative to __memory_base
TableIndexRelSLEB = 12, // In PIC code, table index relative to __table_base
GlobalIndexI32 = 13, // e.g. Global index in data (e.g. DWARF)
MemoryAddressLEB64 = 14, // Memory64: Like MemoryAddressLEB
MemoryAddressSLEB64 = 15, // Memory64: Like MemoryAddressSLEB
MemoryAddressI64 = 16, // Memory64: Like MemoryAddressI32
MemoryAddressRelSLEB64 = 17, // Memory64: Like MemoryAddressRelSLEB
TableIndexSLEB64 = 18, // Memory64: Like TableIndexSLEB
TableIndexI64 = 19, // Memory64: Like TableIndexI32
TableNumberLEB = 20, // e.g. Immediate of table.get
MemoryAddressTLSSLEB = 21, // Address relative to __tls_base
MemoryAddressTLSI32 = 22, // Address relative to __tls_base
First = FuncIndexLEB,
Last = MemoryAddressTLSI32,
};
static const int kRelocTypeCount = WABT_ENUM_COUNT(RelocType);
struct Reloc {
Reloc(RelocType, size_t offset, Index index, int32_t addend = 0);
RelocType type;
size_t offset;
Index index;
int32_t addend;
};
enum class LinkingEntryType {
SegmentInfo = 5,
InitFunctions = 6,
ComdatInfo = 7,
SymbolTable = 8,
};
enum class SymbolType {
Function = 0,
Data = 1,
Global = 2,
Section = 3,
Event = 4,
Table = 5,
};
enum class ComdatType {
Data = 0x0,
Function = 0x1,
};
#define WABT_SYMBOL_MASK_VISIBILITY 0x4
#define WABT_SYMBOL_MASK_BINDING 0x3
#define WABT_SYMBOL_FLAG_UNDEFINED 0x10
#define WABT_SYMBOL_FLAG_EXPORTED 0x20
#define WABT_SYMBOL_FLAG_EXPLICIT_NAME 0x40
#define WABT_SYMBOL_FLAG_NO_STRIP 0x80
#define WABT_SYMBOL_FLAG_MAX 0xff
enum class SymbolVisibility {
Default = 0,
Hidden = 4,
};
enum class SymbolBinding {
Global = 0,
Weak = 1,
Local = 2,
};
/* matches binary format, do not change */
enum class ExternalKind {
Func = 0,
Table = 1,
Memory = 2,
Global = 3,
Event = 4,
First = Func,
Last = Event,
};
static const int kExternalKindCount = WABT_ENUM_COUNT(ExternalKind);
struct Limits {
Limits() = default;
explicit Limits(uint64_t initial) : initial(initial) {}
Limits(uint64_t initial, uint64_t max)
: initial(initial), max(max), has_max(true) {}
Limits(uint64_t initial, uint64_t max, bool is_shared)
: initial(initial), max(max), has_max(true), is_shared(is_shared) {}
Limits(uint64_t initial, uint64_t max, bool is_shared, bool is_64)
: initial(initial),
max(max),
has_max(true),
is_shared(is_shared),
is_64(is_64) {}
Type IndexType() const { return is_64 ? Type::I64 : Type::I32; }
uint64_t initial = 0;
uint64_t max = 0;
bool has_max = false;
bool is_shared = false;
bool is_64 = false;
};
enum { WABT_USE_NATURAL_ALIGNMENT = 0xFFFFFFFFFFFFFFFF };
Result ReadFile(string_view filename, std::vector<uint8_t>* out_data);
void InitStdio();
/* external kind */
extern const char* g_kind_name[];
static WABT_INLINE const char* GetKindName(ExternalKind kind) {
return static_cast<int>(kind) < kExternalKindCount
? g_kind_name[static_cast<size_t>(kind)]
: "<error_kind>";
}
/* reloc */
extern const char* g_reloc_type_name[];
static WABT_INLINE const char* GetRelocTypeName(RelocType reloc) {
return static_cast<int>(reloc) < kRelocTypeCount
? g_reloc_type_name[static_cast<size_t>(reloc)]
: "<error_reloc_type>";
}
/* symbol */
static WABT_INLINE const char* GetSymbolTypeName(SymbolType type) {
switch (type) {
case SymbolType::Function:
return "func";
case SymbolType::Global:
return "global";
case SymbolType::Data:
return "data";
case SymbolType::Section:
return "section";
case SymbolType::Event:
return "event";
case SymbolType::Table:
return "table";
default:
return "<error_symbol_type>";
}
}
template <typename T>
void ConvertBackslashToSlash(T begin, T end) {
std::replace(begin, end, '\\', '/');
}
inline void ConvertBackslashToSlash(char* s, size_t length) {
ConvertBackslashToSlash(s, s + length);
}
inline void ConvertBackslashToSlash(char* s) {
ConvertBackslashToSlash(s, strlen(s));
}
inline void ConvertBackslashToSlash(std::string* s) {
ConvertBackslashToSlash(s->begin(), s->end());
}
inline void SwapBytesSized(void *addr, size_t size) {
auto bytes = static_cast<uint8_t*>(addr);
for (size_t i = 0; i < size / 2; i++) {
std::swap(bytes[i], bytes[size-1-i]);
}
}
} // namespace wabt
#endif // WABT_COMMON_H_

162
third_party/wasm2c/src/config.cc vendored Normal file
View File

@@ -0,0 +1,162 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "config.h"
#include <cstdarg>
#include <cstdio>
#if COMPILER_IS_MSVC && _M_X64
#include <emmintrin.h>
#elif COMPILER_IS_MSVC && _M_IX86
#include <float.h>
#endif
/* c99-style vsnprintf for MSVC < 2015. See http://stackoverflow.com/a/8712996
using _snprintf or vsnprintf will not-properly null-terminate, and will return
-1 instead of the number of characters needed on overflow. */
#if COMPILER_IS_MSVC
int wabt_vsnprintf(char* str, size_t size, const char* format, va_list ap) {
int result = -1;
if (size != 0) {
result = _vsnprintf_s(str, size, _TRUNCATE, format, ap);
}
if (result == -1) {
result = _vscprintf(format, ap);
}
return result;
}
#if !HAVE_SNPRINTF
int wabt_snprintf(char* str, size_t size, const char* format, ...) {
va_list args;
va_start(args, format);
int result = wabt_vsnprintf(str, size, format, args);
va_end(args);
return result;
}
#endif
#endif
#if COMPILER_IS_MSVC && _M_IX86
// Allow the following functions to change the floating-point environment (e.g.
// update to 64-bit precision in the mantissa). This is only needed for x87
// floats, which are only used on MSVC 32-bit.
#pragma fenv_access (on)
namespace {
typedef unsigned int FPControl;
FPControl Set64BitPrecisionControl() {
FPControl old_ctrl = _control87(0, 0);
_control87(_PC_64, _MCW_PC);
return old_ctrl;
}
void ResetPrecisionControl(FPControl old_ctrl) {
_control87(old_ctrl, _MCW_PC);
}
} // end of anonymous namespace
#endif
double wabt_convert_uint64_to_double(uint64_t x) {
#if COMPILER_IS_MSVC && _M_X64
// MSVC on x64 generates uint64 -> float conversions but doesn't do
// round-to-nearest-ties-to-even, which is required by WebAssembly.
__m128d result = _mm_setzero_pd();
if (x & 0x8000000000000000ULL) {
result = _mm_cvtsi64_sd(result, (x >> 1) | (x & 1));
result = _mm_add_sd(result, result);
} else {
result = _mm_cvtsi64_sd(result, x);
}
return _mm_cvtsd_f64(result);
#elif COMPILER_IS_MSVC && _M_IX86
// MSVC on x86 converts from i64 -> double -> float, which causes incorrect
// rounding. Using the x87 float stack instead preserves the correct
// rounding.
FPControl old_ctrl = Set64BitPrecisionControl();
static const double c = 18446744073709551616.0;
double result;
__asm fild x;
if (x & 0x8000000000000000ULL) {
__asm fadd c;
}
__asm fstp result;
ResetPrecisionControl(old_ctrl);
return result;
#else
return static_cast<double>(x);
#endif
}
float wabt_convert_uint64_to_float(uint64_t x) {
#if COMPILER_IS_MSVC && _M_X64
// MSVC on x64 generates uint64 -> float conversions but doesn't do
// round-to-nearest-ties-to-even, which is required by WebAssembly.
__m128 result = _mm_setzero_ps();
if (x & 0x8000000000000000ULL) {
result = _mm_cvtsi64_ss(result, (x >> 1) | (x & 1));
result = _mm_add_ss(result, result);
} else {
result = _mm_cvtsi64_ss(result, x);
}
return _mm_cvtss_f32(result);
#elif COMPILER_IS_MSVC && _M_IX86
// MSVC on x86 converts from i64 -> double -> float, which causes incorrect
// rounding. Using the x87 float stack instead preserves the correct
// rounding.
FPControl old_ctrl = Set64BitPrecisionControl();
static const float c = 18446744073709551616.0f;
float result;
__asm fild x;
if (x & 0x8000000000000000ULL) {
__asm fadd c;
}
__asm fstp result;
ResetPrecisionControl(old_ctrl);
return result;
#else
return static_cast<float>(x);
#endif
}
double wabt_convert_int64_to_double(int64_t x) {
#if COMPILER_IS_MSVC && _M_IX86
double result;
__asm fild x;
__asm fstp result;
return result;
#else
return static_cast<double>(x);
#endif
}
float wabt_convert_int64_to_float(int64_t x) {
#if COMPILER_IS_MSVC && _M_IX86
float result;
__asm fild x;
__asm fstp result;
return result;
#else
return static_cast<float>(x);
#endif
}
#if COMPILER_IS_MSVC && _M_IX86
#pragma fenv_access (off)
#endif

316
third_party/wasm2c/src/config.h.in vendored Normal file
View File

@@ -0,0 +1,316 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_CONFIG_H_
#define WABT_CONFIG_H_
#include <stdint.h>
#include <stdlib.h>
#cmakedefine CMAKE_PROJECT_VERSION "${CMAKE_PROJECT_VERSION}"
/* TODO(binji): nice way to define these with WABT_ prefix? */
/* Whether <alloca.h> is available */
#cmakedefine01 HAVE_ALLOCA_H
/* Whether <unistd.h> is available */
#cmakedefine01 HAVE_UNISTD_H
/* Whether snprintf is defined by stdio.h */
#cmakedefine01 HAVE_SNPRINTF
/* Whether ssize_t is defined by stddef.h */
#cmakedefine01 HAVE_SSIZE_T
/* Whether strcasecmp is defined by strings.h */
#cmakedefine01 HAVE_STRCASECMP
/* Whether ENABLE_VIRTUAL_TERMINAL_PROCESSING is defined by windows.h */
#cmakedefine01 HAVE_WIN32_VT100
#cmakedefine01 COMPILER_IS_CLANG
#cmakedefine01 COMPILER_IS_GNU
#cmakedefine01 COMPILER_IS_MSVC
#cmakedefine01 WITH_EXCEPTIONS
#define SIZEOF_SIZE_T @SIZEOF_SIZE_T@
#if HAVE_ALLOCA_H
#include <alloca.h>
#elif COMPILER_IS_MSVC
#include <malloc.h>
#define alloca _alloca
#elif defined(__MINGW32__)
#include <malloc.h>
#endif
#if COMPILER_IS_CLANG || COMPILER_IS_GNU
#define WABT_UNUSED __attribute__((unused))
#define WABT_WARN_UNUSED __attribute__((warn_unused_result))
#define WABT_INLINE inline
#define WABT_UNLIKELY(x) __builtin_expect(!!(x), 0)
#define WABT_LIKELY(x) __builtin_expect(!!(x), 1)
#define WABT_VECTORCALL
#if __MINGW32__
// mingw defaults to printf format specifier being ms_printf (which doesn't
// understand 'llu', etc.) We always want gnu_printf, and force mingw to always
// use mingw_printf, mingw_vprintf, etc.
#define WABT_PRINTF_FORMAT(format_arg, first_arg) \
__attribute__((format(gnu_printf, (format_arg), (first_arg))))
#else
#define WABT_PRINTF_FORMAT(format_arg, first_arg) \
__attribute__((format(printf, (format_arg), (first_arg))))
#endif
#ifdef __cplusplus
#if __cplusplus >= 201103L
#define WABT_STATIC_ASSERT(x) static_assert((x), #x)
#else
#define WABT_STATIC_ASSERT__(x, c) \
static int static_assert_##c[(x ? 0 : -1)] WABT_UNUSED
#define WABT_STATIC_ASSERT_(x, c) WABT_STATIC_ASSERT__(x, c)
#define WABT_STATIC_ASSERT(x) WABT_STATIC_ASSERT_(x, __COUNTER__)
#endif
#else
#define WABT_STATIC_ASSERT(x) _Static_assert((x), #x)
#endif
#elif COMPILER_IS_MSVC
#include <intrin.h>
#include <string.h>
#define WABT_UNUSED
#define WABT_WARN_UNUSED
#define WABT_INLINE __inline
#define WABT_STATIC_ASSERT(x) _STATIC_ASSERT(x)
#define WABT_UNLIKELY(x) (x)
#define WABT_LIKELY(x) (x)
#define WABT_PRINTF_FORMAT(format_arg, first_arg)
#define WABT_VECTORCALL __vectorcall
#else
#error unknown compiler
#endif
#define WABT_UNREACHABLE abort()
#ifdef __cplusplus
namespace wabt {
#if COMPILER_IS_CLANG || COMPILER_IS_GNU
inline int Clz(unsigned x) { return x ? __builtin_clz(x) : sizeof(x) * 8; }
inline int Clz(unsigned long x) { return x ? __builtin_clzl(x) : sizeof(x) * 8; }
inline int Clz(unsigned long long x) { return x ? __builtin_clzll(x) : sizeof(x) * 8; }
inline int Ctz(unsigned x) { return x ? __builtin_ctz(x) : sizeof(x) * 8; }
inline int Ctz(unsigned long x) { return x ? __builtin_ctzl(x) : sizeof(x) * 8; }
inline int Ctz(unsigned long long x) { return x ? __builtin_ctzll(x) : sizeof(x) * 8; }
inline int Popcount(uint8_t x) { return __builtin_popcount(x); }
inline int Popcount(unsigned x) { return __builtin_popcount(x); }
inline int Popcount(unsigned long x) { return __builtin_popcountl(x); }
inline int Popcount(unsigned long long x) { return __builtin_popcountll(x); }
#elif COMPILER_IS_MSVC
#if _M_IX86
inline unsigned long LowDword(unsigned __int64 value) {
return (unsigned long)value;
}
inline unsigned long HighDword(unsigned __int64 value) {
unsigned long high;
memcpy(&high, (unsigned char*)&value + sizeof(high), sizeof(high));
return high;
}
#endif
inline int Clz(unsigned long mask) {
if (mask == 0)
return 32;
unsigned long index;
_BitScanReverse(&index, mask);
return sizeof(unsigned long) * 8 - (index + 1);
}
inline int Clz(unsigned int mask) {
return Clz((unsigned long)mask);
}
inline int Clz(unsigned __int64 mask) {
#if _M_X64
if (mask == 0)
return 64;
unsigned long index;
_BitScanReverse64(&index, mask);
return sizeof(unsigned __int64) * 8 - (index + 1);
#elif _M_IX86
int result = Clz(HighDword(mask));
if (result == 32)
result += Clz(LowDword(mask));
return result;
#else
#error unexpected architecture
#endif
}
inline int Ctz(unsigned long mask) {
if (mask == 0)
return 32;
unsigned long index;
_BitScanForward(&index, mask);
return index;
}
inline int Ctz(unsigned int mask) {
return Ctz((unsigned long)mask);
}
inline int Ctz(unsigned __int64 mask) {
#if _M_X64
if (mask == 0)
return 64;
unsigned long index;
_BitScanForward64(&index, mask);
return index;
#elif _M_IX86
int result = Ctz(LowDword(mask));
if (result == 32)
result += Ctz(HighDword(mask));
return result;
#else
#error unexpected architecture
#endif
}
inline int Popcount(uint8_t value) {
return __popcnt(value);
}
inline int Popcount(unsigned long value) {
return __popcnt(value);
}
inline int Popcount(unsigned int value) {
return Popcount((unsigned long)value);
}
inline int Popcount(unsigned __int64 value) {
#if _M_X64
return __popcnt64(value);
#elif _M_IX86
return Popcount(HighDword(value)) + Popcount(LowDword(value));
#else
#error unexpected architecture
#endif
}
#else
#error unknown compiler
#endif
} // namespace wabt
#if COMPILER_IS_MSVC
/* print format specifier for size_t */
#if SIZEOF_SIZE_T == 4
#define PRIzd "d"
#define PRIzx "x"
#elif SIZEOF_SIZE_T == 8
#define PRIzd "I64d"
#define PRIzx "I64x"
#else
#error "weird sizeof size_t"
#endif
#elif COMPILER_IS_CLANG || COMPILER_IS_GNU
/* print format specifier for size_t */
#define PRIzd "zd"
#define PRIzx "zx"
#else
#error unknown compiler
#endif
#if HAVE_SNPRINTF
#define wabt_snprintf snprintf
#elif COMPILER_IS_MSVC
/* can't just use _snprintf because it doesn't always null terminate */
#include <cstdarg>
int wabt_snprintf(char* str, size_t size, const char* format, ...);
#else
#error no snprintf
#endif
#if COMPILER_IS_MSVC
/* can't just use vsnprintf because it doesn't always null terminate */
int wabt_vsnprintf(char* str, size_t size, const char* format, va_list ap);
#else
#define wabt_vsnprintf vsnprintf
#endif
#if !HAVE_SSIZE_T
#if COMPILER_IS_MSVC
/* define ssize_t identically to how LLVM does, to avoid conflicts if including both */
#if defined(_WIN64)
typedef signed __int64 ssize_t;
#else
typedef signed int ssize_t;
#endif /* _WIN64 */
#else
typedef long ssize_t;
#endif
#endif
#if !HAVE_STRCASECMP
#if COMPILER_IS_MSVC
#define strcasecmp _stricmp
#else
#error no strcasecmp
#endif
#endif
double wabt_convert_uint64_to_double(uint64_t x);
float wabt_convert_uint64_to_float(uint64_t x);
double wabt_convert_int64_to_double(int64_t x);
float wabt_convert_int64_to_float(int64_t x);
#endif // __cplusplus
#endif /* WABT_CONFIG_H_ */

378
third_party/wasm2c/src/decompiler-ast.h vendored Normal file
View File

@@ -0,0 +1,378 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_DECOMPILER_AST_H_
#define WABT_DECOMPILER_AST_H_
#include "src/cast.h"
#include "src/generate-names.h"
#include "src/ir.h"
#include "src/ir-util.h"
#include <map>
namespace wabt {
enum class NodeType {
Uninitialized,
FlushToVars,
FlushedVar,
Statements,
EndReturn,
Decl,
DeclInit,
Expr
};
// The AST we're going to convert the standard IR into.
struct Node {
NodeType ntype;
ExprType etype; // Only if ntype == Expr.
const Expr* e;
std::vector<Node> children;
// Node specific annotations.
union {
struct { Index var_start, var_count; }; // FlushedVar/FlushToVars
const Var* var; // Decl/DeclInit.
LabelType lt; // br/br_if target.
} u;
Node() : ntype(NodeType::Uninitialized), etype(ExprType::Nop), e(nullptr) {
}
Node(NodeType ntype, ExprType etype, const Expr* e, const Var* v)
: ntype(ntype), etype(etype), e(e) {
u.var = v;
}
// This value should really never be copied, only moved.
Node(const Node& rhs) = delete;
Node& operator=(const Node& rhs) = delete;
Node(Node&& rhs) { *this = std::move(rhs); }
Node& operator=(Node&& rhs) {
ntype = rhs.ntype;
// Reset ntype to avoid moved from values still being used.
rhs.ntype = NodeType::Uninitialized;
etype = rhs.etype;
rhs.etype = ExprType::Nop;
e = rhs.e;
std::swap(children, rhs.children);
u = rhs.u;
return *this;
}
};
struct AST {
AST(ModuleContext& mc, const Func *f) : mc(mc), f(f) {
if (f) {
mc.BeginFunc(*f);
for (Index i = 0; i < f->GetNumParams(); i++) {
auto name = "$" + IndexToAlphaName(i);
vars_defined.insert({ name, { 0, false }});
}
}
}
~AST() {
if (f) mc.EndFunc();
}
// Create a new node, take nargs existing nodes on the exp stack as children.
Node& InsertNode(NodeType ntype, ExprType etype, const Expr* e, Index nargs) {
assert(exp_stack.size() >= nargs);
Node n { ntype, etype, e, nullptr };
n.children.reserve(nargs);
std::move(exp_stack.end() - nargs, exp_stack.end(),
std::back_inserter(n.children));
exp_stack.erase(exp_stack.end() - nargs, exp_stack.end());
exp_stack.push_back(std::move(n));
return exp_stack.back();
}
template<ExprType T> void PreDecl(const VarExpr<T>& ve) {
predecls.emplace_back(NodeType::Decl, ExprType::Nop, nullptr, &ve.var);
}
template<ExprType T> void Get(const VarExpr<T>& ve, bool local) {
if (local) {
auto ret = vars_defined.insert({ ve.var.name(), { cur_block_id, false }});
if (ret.second) {
// Use before def, may happen since locals are guaranteed 0.
PreDecl(ve);
} else if (blocks_closed[ret.first->second.block_id]) {
// This is a use of a variable that was defined in a block that has
// already ended. This happens rarely, but we should cater for this
// case by lifting it to the top scope.
PreDecl(ve);
}
}
InsertNode(NodeType::Expr, T, &ve, 0);
}
template<ExprType T> void Set(const VarExpr<T>& ve, bool local) {
// Seen this var before?
if (local &&
vars_defined.insert({ ve.var.name(), { cur_block_id, false }}).second) {
if (value_stack_depth == 1) {
// Top level, declare it here.
InsertNode(NodeType::DeclInit, ExprType::Nop, nullptr, 1).u.var =
&ve.var;
return;
} else {
// Inside exp, better leave it as assignment exp and lift the decl out.
PreDecl(ve);
}
}
InsertNode(NodeType::Expr, T, &ve, 1);
}
template<ExprType T> void Block(const BlockExprBase<T>& be, LabelType label) {
mc.BeginBlock(label, be.block);
Construct(be.block.exprs, be.block.decl.GetNumResults(), be.block.decl.GetNumParams(), false);
mc.EndBlock();
InsertNode(NodeType::Expr, T, &be, 1);
}
void Construct(const Expr& e) {
auto arity = mc.GetExprArity(e);
switch (e.type()) {
case ExprType::LocalGet: {
Get(*cast<LocalGetExpr>(&e), true);
return;
}
case ExprType::GlobalGet: {
Get(*cast<GlobalGetExpr>(&e), false);
return;
}
case ExprType::LocalSet: {
Set(*cast<LocalSetExpr>(&e), true);
return;
}
case ExprType::GlobalSet: {
Set(*cast<GlobalSetExpr>(&e), false);
return;
}
case ExprType::LocalTee: {
auto& lt = *cast<LocalTeeExpr>(&e);
Set(lt, true);
if (value_stack_depth == 1) { // Tee is the only thing on there.
Get(lt, true); // Now Set + Get instead.
} else {
// Things are above us on the stack so the Tee can't be eliminated.
// The Set makes this work as a Tee when consumed by a parent.
}
return;
}
case ExprType::If: {
auto ife = cast<IfExpr>(&e);
value_stack_depth--; // Condition.
mc.BeginBlock(LabelType::Block, ife->true_);
Construct(ife->true_.exprs, ife->true_.decl.GetNumResults(), ife->true_.decl.GetNumParams(), false);
if (!ife->false_.empty()) {
Construct(ife->false_, ife->true_.decl.GetNumResults(), ife->true_.decl.GetNumParams(), false);
}
mc.EndBlock();
value_stack_depth++; // Put Condition back.
InsertNode(NodeType::Expr, ExprType::If, &e, ife->false_.empty() ? 2 : 3);
return;
}
case ExprType::Block: {
Block(*cast<BlockExpr>(&e), LabelType::Block);
return;
}
case ExprType::Loop: {
Block(*cast<LoopExpr>(&e), LabelType::Loop);
return;
}
case ExprType::Br: {
InsertNode(NodeType::Expr, ExprType::Br, &e, 0).u.lt =
mc.GetLabel(cast<BrExpr>(&e)->var)->label_type;
return;
}
case ExprType::BrIf: {
InsertNode(NodeType::Expr, ExprType::BrIf, &e, 1).u.lt =
mc.GetLabel(cast<BrIfExpr>(&e)->var)->label_type;
return;
}
default: {
InsertNode(NodeType::Expr, e.type(), &e, arity.nargs);
return;
}
}
}
void Construct(const ExprList& es, Index nresults, Index nparams, bool is_function_body) {
block_stack.push_back(cur_block_id);
cur_block_id = blocks_closed.size();
blocks_closed.push_back(false);
auto start = exp_stack.size();
int value_stack_depth_start = value_stack_depth - nparams;
auto value_stack_in_variables = value_stack_depth;
bool unreachable = false;
for (auto& e : es) {
Construct(e);
auto arity = mc.GetExprArity(e);
value_stack_depth -= arity.nargs;
value_stack_in_variables = std::min(value_stack_in_variables,
value_stack_depth);
unreachable = unreachable || arity.unreachable;
assert(unreachable || value_stack_depth >= value_stack_depth_start);
value_stack_depth += arity.nreturns;
// We maintain the invariant that a value_stack_depth of N is represented
// by the last N exp_stack items (each of which returning exactly 1
// value), all exp_stack items before it return void ("statements").
// In particular for the wasm stack:
// - The values between 0 and value_stack_depth_start are part of the
// parent block, and not touched here.
// - The values from there up to value_stack_in_variables are variables
// to be used, representing previous statements that flushed the
// stack into variables.
// - Values on top of that up to value_stack_depth are exps returning
// a single value.
// The code below maintains the above invariants. With this in place
// code "falls into place" the way you expect it.
if (arity.nreturns != 1) {
auto num_vars = value_stack_in_variables - value_stack_depth_start;
auto num_vals = value_stack_depth - value_stack_in_variables;
auto GenFlushVars = [&](int nargs) {
auto& ftv = InsertNode(NodeType::FlushToVars, ExprType::Nop, nullptr,
nargs);
ftv.u.var_start = flushed_vars;
ftv.u.var_count = num_vals;
};
auto MoveStatementsBelowVars = [&](size_t amount) {
std::rotate(exp_stack.end() - num_vars - amount,
exp_stack.end() - amount,
exp_stack.end());
};
auto GenFlushedVars = [&]() {
// Re-generate these values as vars.
for (int i = 0; i < num_vals; i++) {
auto& fv = InsertNode(NodeType::FlushedVar, ExprType::Nop, nullptr,
0);
fv.u.var_start = flushed_vars++;
fv.u.var_count = 1;
}
};
if (arity.nreturns == 0 &&
value_stack_depth > value_stack_depth_start) {
// We have a void item on top of the exp_stack, so we must "lift" the
// previous values around it.
// We track what part of the stack is in variables to avoid doing
// this unnecessarily.
if (num_vals > 0) {
// We have actual new values that need lifting.
// This puts the part of the stack that wasn't already a variable
// (before the current void exp) into a FlushToVars.
auto void_exp = std::move(exp_stack.back());
exp_stack.pop_back();
GenFlushVars(num_vals);
exp_stack.push_back(std::move(void_exp));
// Put this flush statement + void statement before any
// existing variables.
MoveStatementsBelowVars(2);
// Now re-generate these values after the void exp as vars.
GenFlushedVars();
} else {
// We have existing variables that need lifting, but no need to
// create them anew.
std::rotate(exp_stack.end() - num_vars - 1, exp_stack.end() - 1,
exp_stack.end());
}
value_stack_in_variables = value_stack_depth;
} else if (arity.nreturns > 1) {
// Multivalue: we flush the stack also.
// Number of other non-variable values that may be present:
assert(num_vals >= static_cast<int>(arity.nreturns));
// Flush multi-value exp + others.
GenFlushVars(num_vals - arity.nreturns + 1);
// Put this flush statement before any existing variables.
MoveStatementsBelowVars(1);
GenFlushedVars();
value_stack_in_variables = value_stack_depth;
}
} else {
// Special optimisation: for constant instructions, we can mark these
// as if they were variables, so they can be re-ordered for free with
// the above code, without needing new variables!
// TODO: this would be nice to also do for get_local and maybe others,
// though that needs a way to ensure there's no set_local in between
// when they get lifted, so complicates matters a bit.
if (e.type() == ExprType::Const &&
value_stack_in_variables == value_stack_depth - 1) {
value_stack_in_variables++;
}
}
}
assert(unreachable ||
value_stack_depth - value_stack_depth_start ==
static_cast<int>(nresults));
// Undo any changes to value_stack_depth, since parent takes care of arity
// changes.
value_stack_depth = value_stack_depth_start;
auto end = exp_stack.size();
assert(end >= start);
if (is_function_body) {
if (!exp_stack.empty()) {
if (exp_stack.back().etype == ExprType::Return) {
if (exp_stack.back().children.empty()) {
// Return statement at the end of a void function.
exp_stack.pop_back();
}
} else if (nresults) {
// Combine nresults into a return statement, for when this is used as
// a function body.
// TODO: if this is some other kind of block and >1 value is being
// returned, probably need some kind of syntax to make that clearer.
InsertNode(NodeType::EndReturn, ExprType::Nop, nullptr, nresults);
}
}
// TODO: these predecls are always at top level, but in the case of
// use inside an exp, it be nice to do it in the current block. Can't
// do that for predecls that are "out if scope" however.
std::move(predecls.begin(), predecls.end(),
std::back_inserter(exp_stack));
std::rotate(exp_stack.begin(), exp_stack.end() - predecls.size(),
exp_stack.end());
predecls.clear();
}
end = exp_stack.size();
assert(end >= start);
auto size = end - start;
if (size != 1) {
InsertNode(NodeType::Statements, ExprType::Nop, nullptr, size);
}
blocks_closed[cur_block_id] = true;
cur_block_id = block_stack.back();
block_stack.pop_back();
}
ModuleContext& mc;
std::vector<Node> exp_stack;
std::vector<Node> predecls;
const Func *f;
int value_stack_depth = 0;
struct Variable { size_t block_id; bool defined; };
std::map<std::string, Variable> vars_defined;
Index flushed_vars = 0;
size_t cur_block_id = 0;
std::vector<size_t> block_stack;
std::vector<bool> blocks_closed;
};
} // namespace wabt
#endif // WABT_DECOMPILER_AST_H_

265
third_party/wasm2c/src/decompiler-ls.h vendored Normal file
View File

@@ -0,0 +1,265 @@
/*
* Copyright 2019 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_DECOMPILER_LS_H_
#define WABT_DECOMPILER_LS_H_
#include "src/decompiler-ast.h"
#include <map>
namespace wabt {
// Names starting with "u" are unsigned, the rest are "signed or doesn't matter"
inline const char *GetDecompTypeName(Type t) {
switch (t) {
case Type::I8: return "byte";
case Type::I8U: return "ubyte";
case Type::I16: return "short";
case Type::I16U: return "ushort";
case Type::I32: return "int";
case Type::I32U: return "uint";
case Type::I64: return "long";
case Type::F32: return "float";
case Type::F64: return "double";
case Type::V128: return "simd";
case Type::Func: return "func";
case Type::FuncRef: return "funcref";
case Type::ExternRef: return "externref";
case Type::Void: return "void";
default: return "ILLEGAL";
}
}
inline Type GetMemoryType(Type operand_type, Opcode opc) {
// TODO: something something SIMD.
// TODO: this loses information of the type it is read into.
// That may well not be the biggest deal since that is usually obvious
// from context, if not, we should probably represent that as a cast around
// the access, since it should not be part of the field type.
if (operand_type == Type::I32 || operand_type == Type::I64) {
auto name = string_view(opc.GetName());
// FIXME: change into a new column in opcode.def instead?
auto is_unsigned = name.substr(name.size() - 2) == "_u";
switch (opc.GetMemorySize()) {
case 1: return is_unsigned ? Type::I8U : Type::I8;
case 2: return is_unsigned ? Type::I16U : Type::I16;
case 4: return is_unsigned ? Type::I32U : Type::I32;
}
}
return operand_type;
}
// Track all loads and stores inside a single function, to be able to detect
// struct layouts we can use to annotate variables with, to make code more
// readable.
struct LoadStoreTracking {
struct LSAccess {
Address byte_size = 0;
Type type = Type::Any;
Address align = 0;
uint32_t idx = 0;
bool is_uniform = true;
};
struct LSVar {
std::map<uint64_t, LSAccess> accesses;
bool struct_layout = true;
Type same_type = Type::Any;
Address same_align = kInvalidAddress;
Opcode last_opc;
};
void Track(const Node& n) {
for (auto& c : n.children) Track(c);
switch (n.etype) {
case ExprType::Load: {
auto& le = *cast<LoadExpr>(n.e);
LoadStore(le.offset, le.opcode, le.opcode.GetResultType(),
le.align, n.children[0]);
break;
}
case ExprType::Store: {
auto& se = *cast<StoreExpr>(n.e);
LoadStore(se.offset, se.opcode, se.opcode.GetParamType2(),
se.align, n.children[0]);
break;
}
default:
break;
}
}
const std::string AddrExpName(const Node& addr_exp) const {
// TODO: expand this to more kinds of address expressions.
switch (addr_exp.etype) {
case ExprType::LocalGet:
return cast<LocalGetExpr>(addr_exp.e)->var.name();
break;
case ExprType::LocalTee:
return cast<LocalTeeExpr>(addr_exp.e)->var.name();
break;
default:
return "";
}
}
void LoadStore(uint64_t offset, Opcode opc, Type type, Address align,
const Node& addr_exp) {
auto byte_size = opc.GetMemorySize();
type = GetMemoryType(type, opc);
// We want to associate memory ops of a certain offset & size as being
// relative to a uniquely identifiable pointer, such as a local.
auto name = AddrExpName(addr_exp);
if (name.empty()) {
return;
}
auto& var = vars[name];
auto& access = var.accesses[offset];
// Check if previous access at this offset (if any) is of same size
// and type (see Checklayouts below).
if (access.byte_size &&
((access.byte_size != byte_size) ||
(access.type != type) ||
(access.align != align)))
access.is_uniform = false;
// Also exclude weird alignment accesses from structs.
if (!opc.IsNaturallyAligned(align))
access.is_uniform = false;
access.byte_size = byte_size;
access.type = type;
access.align = align;
// Additionally, check if all accesses are to the same type, so
// if layout check fails, we can at least declare it as pointer to
// a type.
if ((var.same_type == type || var.same_type == Type::Any) &&
(var.same_align == align || var.same_align == kInvalidAddress)) {
var.same_type = type;
var.same_align = align;
var.last_opc = opc;
} else {
var.same_type = Type::Void;
var.same_align = kInvalidAddress;
}
}
void CheckLayouts() {
// Here we check if the set of accesses we have collected form a sequence
// we could declare as a struct, meaning they are properly aligned,
// contiguous, and have no overlaps between different types and sizes.
// We do this because an int access of size 2 at offset 0 followed by
// a float access of size 4 at offset 4 can compactly represented as a
// struct { short, float }, whereas something that reads from overlapping
// or discontinuous offsets would need a more complicated syntax that
// involves explicit offsets.
// We assume that the bulk of memory accesses are of this very regular kind,
// so we choose not to even emit struct layouts for irregular ones,
// given that they are rare and confusing, and thus do not benefit from
// being represented as if they were structs.
for (auto& var : vars) {
if (var.second.accesses.size() == 1) {
// If we have just one access, this is better represented as a pointer
// than a struct.
var.second.struct_layout = false;
continue;
}
uint64_t cur_offset = 0;
uint32_t idx = 0;
for (auto& access : var.second.accesses) {
access.second.idx = idx++;
if (!access.second.is_uniform) {
var.second.struct_layout = false;
break;
}
// Align to next access: all elements are expected to be aligned to
// a memory address thats a multiple of their own size.
auto mask = static_cast<uint64_t>(access.second.byte_size - 1);
cur_offset = (cur_offset + mask) & ~mask;
if (cur_offset != access.first) {
var.second.struct_layout = false;
break;
}
cur_offset += access.second.byte_size;
}
}
}
std::string IdxToName(uint32_t idx) const {
return IndexToAlphaName(idx); // TODO: more descriptive names?
}
std::string GenAlign(Address align, Opcode opc) const {
return opc.IsNaturallyAligned(align)
? ""
: cat("@", std::to_string(align));
}
std::string GenTypeDecl(const std::string& name) const {
auto it = vars.find(name);
if (it == vars.end()) {
return "";
}
if (it->second.struct_layout) {
std::string s = "{ ";
for (auto& access : it->second.accesses) {
if (access.second.idx) s += ", ";
s += IdxToName(access.second.idx);
s += ':';
s += GetDecompTypeName(access.second.type);
}
s += " }";
return s;
}
// We don't have a struct layout, or the struct has just one field,
// so maybe we can just declare it as a pointer to one type?
if (it->second.same_type != Type::Void) {
return cat(GetDecompTypeName(it->second.same_type), "_ptr",
GenAlign(it->second.same_align, it->second.last_opc));
}
return "";
}
std::string GenAccess(uint64_t offset, const Node& addr_exp) const {
auto name = AddrExpName(addr_exp);
if (name.empty()) {
return "";
}
auto it = vars.find(name);
if (it == vars.end()) {
return "";
}
if (it->second.struct_layout) {
auto ait = it->second.accesses.find(offset);
assert (ait != it->second.accesses.end());
return IdxToName(ait->second.idx);
}
// Not a struct, see if it is a typed pointer.
if (it->second.same_type != Type::Void) {
return "*";
}
return "";
}
void Clear() {
vars.clear();
}
std::map<std::string, LSVar> vars;
};
} // namespace wabt
#endif // WABT_DECOMPILER_LS_H_

View File

@@ -0,0 +1,211 @@
/*
* Copyright 2019 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_DECOMPILER_NAMING_H_
#define WABT_DECOMPILER_NAMING_H_
#include "src/decompiler-ast.h"
#include <set>
namespace wabt {
inline void RenameToIdentifier(std::string& name, Index i,
BindingHash& bh,
const std::set<string_view>* filter) {
// Filter out non-identifier characters, and try to reduce the size of
// gigantic C++ signature names.
std::string s;
size_t nesting = 0;
size_t read = 0;
size_t word_start = 0;
for (auto c : name) {
read++;
// We most certainly don't want to parse the entirety of C++ signatures,
// but these names are sometimes several lines long, so would be great
// to trim down. One quick way to do that is to remove anything between
// nested (), which usually means the parameter list.
if (c == '(') {
nesting++;
}
if (c == ')') {
nesting--;
}
if (nesting) {
continue;
}
if (!isalnum(static_cast<unsigned char>(c))) {
c = '_';
}
if (c == '_') {
if (s.empty()) {
continue; // Skip leading.
}
if (s.back() == '_') {
continue; // Consecutive.
}
}
s += c;
if (filter && (c == '_' || read == name.size())) {
// We found a "word" inside a snake_case identifier.
auto word_end = s.size();
if (c == '_') {
word_end--;
}
assert(word_end > word_start);
auto word = string_view(s.c_str() + word_start, word_end - word_start);
if (filter->find(word) != filter->end()) {
s.resize(word_start);
}
word_start = s.size();
}
}
if (!s.empty() && s.back() == '_') {
s.pop_back(); // Trailing.
}
// If after all this culling, we're still gigantic (STL identifier can
// easily be hundreds of chars in size), just cut the identifier
// down, it will be disambiguated below, if needed.
const size_t max_identifier_length = 100;
if (s.size() > max_identifier_length) {
s.resize(max_identifier_length);
}
// Remove original binding first, such that it doesn't match with our
// new name.
bh.erase(name);
// Find a unique name.
Index disambiguator = 0;
auto base_len = s.size();
for (;;) {
if (bh.count(s) == 0) {
break;
}
disambiguator++;
s.resize(base_len);
s += '_';
s += std::to_string(disambiguator);
}
// Replace name in bindings.
name = s;
bh.emplace(s, Binding(i));
}
template<typename T>
void RenameToIdentifiers(std::vector<T*>& things, BindingHash& bh,
const std::set<string_view>* filter) {
Index i = 0;
for (auto thing : things) {
RenameToIdentifier(thing->name, i++, bh, filter);
}
}
enum {
// This a bit arbitrary, change at will.
min_content_identifier_size = 7,
max_content_identifier_size = 30
};
void RenameToContents(std::vector<DataSegment*>& segs, BindingHash& bh) {
std::string s;
for (auto seg : segs) {
if (seg->name.substr(0, 2) != "d_") {
// This segment was named explicitly by a symbol.
// FIXME: this is not a great check, a symbol could start with d_.
continue;
}
s = "d_";
for (auto c : seg->data) {
if (isalnum(c) || c == '_') {
s += static_cast<char>(c);
}
if (s.size() >= max_content_identifier_size) {
// We truncate any very long names, since those make for hard to
// format output. They can be somewhat long though, since data segment
// references tend to not occur that often.
break;
}
}
if (s.size() < min_content_identifier_size) {
// It is useful to have a minimum, since if there few printable characters
// in a data section, that is probably a sign of binary, and those few
// characters are not going to be very significant.
continue;
}
// We could do the same disambiguition as RenameToIdentifier and
// GenerateNames do, but if we come up with a clashing name here it is
// likely a sign of not very meaningful binary data, so it is easier to
// just keep the original generated name in that case.
if (bh.count(s) != 0) {
continue;
}
// Remove original entry.
bh.erase(seg->name);
seg->name = s;
bh.emplace(s, Binding(static_cast<Index>(&seg - &segs[0])));
}
}
// Function names may contain arbitrary C++ syntax, so we want to
// filter those to look like identifiers. A function name may be set
// by a name section (applied in ReadBinaryIr, called before this function)
// or by an export (applied by GenerateNames, called before this function),
// to both the Func and func_bindings.
// Those names then further perculate down the IR in ApplyNames (called after
// this function).
// To not have to add too many decompiler-specific code into those systems
// (using a callback??) we instead rename everything here.
// Also do data section renaming here.
void RenameAll(Module& module) {
// We also filter common C++ keywords/STL idents that make for huge
// identifiers.
// FIXME: this can obviously give bad results if the input is not C++..
std::set<string_view> filter = {
{ "const" },
{ "std" },
{ "allocator" },
{ "char" },
{ "basic" },
{ "traits" },
{ "wchar" },
{ "t" },
{ "void" },
{ "int" },
{ "unsigned" },
{ "2" },
{ "cxxabiv1" },
{ "short" },
{ "4096ul" },
};
RenameToIdentifiers(module.funcs, module.func_bindings, &filter);
// Also do this for some other kinds of names, but without the keyword
// substitution.
RenameToIdentifiers(module.globals, module.global_bindings, nullptr);
RenameToIdentifiers(module.tables, module.table_bindings, nullptr);
RenameToIdentifiers(module.events, module.event_bindings, nullptr);
RenameToIdentifiers(module.exports, module.export_bindings, nullptr);
RenameToIdentifiers(module.types, module.type_bindings, nullptr);
RenameToIdentifiers(module.memories, module.memory_bindings, nullptr);
RenameToIdentifiers(module.data_segments, module.data_segment_bindings,
nullptr);
RenameToIdentifiers(module.elem_segments, module.elem_segment_bindings,
nullptr);
// Special purpose naming for data segments.
RenameToContents(module.data_segments, module.data_segment_bindings);
}
} // namespace wabt
#endif // WABT_DECOMPILER_NAMING_H_

829
third_party/wasm2c/src/decompiler.cc vendored Normal file
View File

@@ -0,0 +1,829 @@
/*
* Copyright 2019 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/decompiler.h"
#include "src/decompiler-ast.h"
#include "src/decompiler-ls.h"
#include "src/decompiler-naming.h"
#include "src/stream.h"
#define WABT_TRACING 0
#include "src/tracing.h"
#include <inttypes.h>
namespace wabt {
struct Decompiler {
Decompiler(const Module& module, const DecompileOptions& options)
: mc(module), options(options) {}
// Sorted such that "greater precedence" is also the bigger enum val.
enum Precedence {
// Low precedence.
None, // precedence doesn't matter, since never nested.
Assign, // =
OtherBin, // min
Bit, // & |
Equal, // == != < > >= <=
Shift, // << >>
Add, // + -
Multiply, // * / %
If, // if{}
Indexing, // []
Atomic, // (), a, 1, a()
// High precedence.
};
// Anything besides these will get parentheses if used with equal precedence,
// for clarity.
bool Associative(Precedence p) {
return p == Precedence::Add || p == Precedence::Multiply;
}
struct Value {
std::vector<std::string> v;
// Lazily add bracketing only if the parent requires it.
// This is the precedence level of this value, for example, if this
// precedence is Add, and the parent is Multiply, bracketing is needed,
// but not if it is the reverse.
Precedence precedence;
Value(std::vector<std::string>&& v, Precedence p)
: v(v), precedence(p) {}
size_t width() {
size_t w = 0;
for (auto &s : v) {
w = std::max(w, s.size());
}
return w;
}
// This value should really never be copied, only moved.
Value(Value&& rhs) = default;
Value(const Value& rhs) = delete;
Value& operator=(Value&& rhs) = default;
Value& operator=(const Value& rhs) = delete;
};
std::string to_string(double d) {
auto s = std::to_string(d);
// Remove redundant trailing '0's that to_string produces.
while (s.size() > 2 && s.back() == '0' && s[s.size() - 2] != '.')
s.pop_back();
return s;
}
std::string Indent(size_t amount) {
return std::string(amount, ' ');
}
std::string OpcodeToToken(Opcode opcode) {
std::string s = opcode.GetDecomp();
std::replace(s.begin(), s.end(), '.', '_');
return s;
}
void IndentValue(Value &val, size_t amount, string_view first_indent) {
auto indent = Indent(amount);
for (auto& stat : val.v) {
auto is = (&stat != &val.v[0] || first_indent.empty())
? string_view(indent)
: first_indent;
stat.insert(0, is.data(), is.size());
}
}
Value WrapChild(Value &child, string_view prefix, string_view postfix,
Precedence precedence) {
auto width = prefix.size() + postfix.size() + child.width();
auto &v = child.v;
if (width < target_exp_width ||
(prefix.size() <= indent_amount && postfix.size() <= indent_amount)) {
if (v.size() == 1) {
// Fits in a single line.
v[0].insert(0, prefix.data(), prefix.size());
v[0].append(postfix.data(), postfix.size());
} else {
// Multiline, but with prefix on same line.
IndentValue(child, prefix.size(), prefix);
v.back().append(postfix.data(), postfix.size());
}
} else {
// Multiline with prefix on its own line.
IndentValue(child, indent_amount, {});
v.insert(v.begin(), std::string(prefix));
v.back().append(postfix.data(), postfix.size());
}
child.precedence = precedence;
return std::move(child);
}
void BracketIfNeeded(Value &val, Precedence parent_precedence) {
if (parent_precedence < val.precedence ||
(parent_precedence == val.precedence &&
Associative(parent_precedence))) return;
val = WrapChild(val, "(", ")", Precedence::Atomic);
}
Value WrapBinary(std::vector<Value>& args, string_view infix,
bool indent_right, Precedence precedence) {
assert(args.size() == 2);
auto& left = args[0];
auto& right = args[1];
BracketIfNeeded(left, precedence);
BracketIfNeeded(right, precedence);
auto width = infix.size() + left.width() + right.width();
if (width < target_exp_width && left.v.size() == 1 && right.v.size() == 1) {
return Value{{left.v[0] + infix + right.v[0]}, precedence};
} else {
Value bin { {}, precedence };
std::move(left.v.begin(), left.v.end(), std::back_inserter(bin.v));
bin.v.back().append(infix.data(), infix.size());
if (indent_right) IndentValue(right, indent_amount, {});
std::move(right.v.begin(), right.v.end(), std::back_inserter(bin.v));
return bin;
}
}
Value WrapNAry(std::vector<Value>& args, string_view prefix,
string_view postfix, Precedence precedence) {
size_t total_width = 0;
size_t max_width = 0;
bool multiline = false;
for (auto& child : args) {
auto w = child.width();
max_width = std::max(max_width, w);
total_width += w;
multiline = multiline || child.v.size() > 1;
}
if (!multiline &&
(total_width + prefix.size() + postfix.size() < target_exp_width ||
args.empty())) {
// Single line.
auto s = std::string(prefix);
for (auto& child : args) {
if (&child != &args[0])
s += ", ";
s += child.v[0];
}
s += postfix;
return Value{{std::move(s)}, precedence};
} else {
// Multi-line.
Value ml { {}, precedence };
auto ident_with_name = max_width + prefix.size() < target_exp_width;
size_t i = 0;
for (auto& child : args) {
IndentValue(child, ident_with_name ? prefix.size() : indent_amount,
!i && ident_with_name ? prefix : string_view {});
if (i < args.size() - 1) child.v.back() += ",";
std::move(child.v.begin(), child.v.end(),
std::back_inserter(ml.v));
i++;
}
if (!ident_with_name) ml.v.insert(ml.v.begin(), std::string(prefix));
ml.v.back() += postfix;
return ml;
}
}
string_view VarName(string_view name) {
assert(!name.empty());
return name[0] == '$' ? name.substr(1) : name;
}
template<ExprType T> Value Get(const VarExpr<T>& ve) {
return Value{{std::string(VarName(ve.var.name()))}, Precedence::Atomic};
}
template<ExprType T> Value Set(Value& child, const VarExpr<T>& ve) {
return WrapChild(child, VarName(ve.var.name()) + " = ", "", Precedence::Assign);
}
std::string TempVarName(Index n) {
// FIXME: this needs much better variable naming. Problem is, the code
// in generate-names.cc has allready run, its dictionaries deleted, so it
// is not easy to integrate with it.
return "t" + std::to_string(n);
}
std::string LocalDecl(const std::string& name, Type t) {
auto struc = lst.GenTypeDecl(name);
return cat(VarName(name), ":",
struc.empty() ? GetDecompTypeName(t) : struc);
}
bool ConstIntVal(const Expr* e, uint64_t &dest) {
dest = 0;
if (!e || e->type() != ExprType::Const) return false;
auto& c = cast<ConstExpr>(e)->const_;
if (c.type() != Type::I32 && c.type() != Type::I64) return false;
dest = c.type() == Type::I32 ? c.u32() : c.u64();
return true;
}
void LoadStore(Value &val, const Node& addr_exp, uint64_t offset,
Opcode opc, Address align, Type op_type) {
bool append_type = true;
auto access = lst.GenAccess(offset, addr_exp);
if (!access.empty()) {
if (access == "*") {
// The variable was declared as a typed pointer, so this access
// doesn't need a type.
append_type = false;
} else {
// We can do this load/store as a struct access.
BracketIfNeeded(val, Precedence::Indexing);
val.v.back() += "." + access;
return;
}
}
// Detect absolute addressing, which we try to turn into references to the
// data section when possible.
uint64_t abs_base;
if (ConstIntVal(addr_exp.e, abs_base)) {
// We don't care what part of the absolute address was stored where,
// 1[0] and 0[1] are the same.
abs_base += offset;
// FIXME: make this less expensive with a binary search or whatever.
for (auto dat : mc.module.data_segments) {
uint64_t dat_base;
if (dat->offset.size() == 1 &&
ConstIntVal(&dat->offset.front(), dat_base) &&
abs_base >= dat_base &&
abs_base < dat_base + dat->data.size()) {
// We are inside the range of this data segment!
// Turn expression into data_name[index]
val = Value { { dat->name }, Precedence::Atomic };
// The new offset is from the start of the data segment, instead of
// whatever it was.. this may be a different value from both the
// original const and offset!
offset = abs_base - dat_base;
}
}
}
// Do the load/store as a generalized indexing operation.
// The offset is divisible by the alignment in 99.99% of
// cases, but the spec doesn't guarantee it, so we must
// have a backup syntax.
auto index = offset % align == 0
? std::to_string(offset / align)
: cat(std::to_string(offset), "@", std::to_string(align));
// Detect the very common case of (base + (index << 2))[0]:int etc.
// so we can instead do base[index]:int
// TODO: (index << 2) on the left of + occurs also.
// TODO: sadly this does not address cases where the shift amount > align.
// (which happens for arrays of structs or arrays of long (with align=4)).
// TODO: also very common is (v = base + (index << 2))[0]:int
if (addr_exp.etype == ExprType::Binary) {
auto& pe = *cast<BinaryExpr>(addr_exp.e);
auto& shift_exp = addr_exp.children[1];
if (pe.opcode == Opcode::I32Add &&
shift_exp.etype == ExprType::Binary) {
auto& se = *cast<BinaryExpr>(shift_exp.e);
auto& const_exp = shift_exp.children[1];
if (se.opcode == Opcode::I32Shl &&
const_exp.etype == ExprType::Const) {
auto& ce = *cast<ConstExpr>(const_exp.e);
if (ce.const_.type() == Type::I32 &&
(1ULL << ce.const_.u32()) == align) {
// Pfew, case detected :( Lets re-write this in Haskell.
// TODO: we're decompiling these twice.
// The thing to the left of << is going to be part of the index.
auto ival = DecompileExpr(shift_exp.children[0], &shift_exp);
if (ival.v.size() == 1) { // Don't bother if huge.
if (offset == 0) {
index = ival.v[0];
} else {
BracketIfNeeded(ival, Precedence::Add);
index = cat(ival.v[0], " + ", index);
}
// We're going to use the thing to the left of + as the new
// base address:
val = DecompileExpr(addr_exp.children[0], &addr_exp);
}
}
}
}
}
BracketIfNeeded(val, Precedence::Indexing);
val.v.back() += cat("[", index, "]");
if (append_type) {
val.v.back() +=
cat(":", GetDecompTypeName(GetMemoryType(op_type, opc)),
lst.GenAlign(align, opc));
}
val.precedence = Precedence::Indexing;
}
Value DecompileExpr(const Node& n, const Node* parent) {
std::vector<Value> args;
for (auto& c : n.children) {
args.push_back(DecompileExpr(c, &n));
}
// First deal with the specialized node types.
switch (n.ntype) {
case NodeType::FlushToVars: {
std::string decls = "let ";
for (Index i = 0; i < n.u.var_count; i++) {
if (i) decls += ", ";
decls += TempVarName(n.u.var_start + i);
}
decls += " = ";
return WrapNAry(args, decls, "", Precedence::Assign);
}
case NodeType::FlushedVar: {
return Value { { TempVarName(n.u.var_start) }, Precedence::Atomic };
}
case NodeType::Statements: {
Value stats { {}, Precedence::None };
for (size_t i = 0; i < n.children.size(); i++) {
auto& s = args[i].v.back();
if (s.back() != '}' && s.back() != ':') s += ';';
std::move(args[i].v.begin(), args[i].v.end(),
std::back_inserter(stats.v));
}
return stats;
}
case NodeType::EndReturn: {
return WrapNAry(args, "return ", "", Precedence::None);
}
case NodeType::Decl: {
cur_ast->vars_defined[n.u.var->name()].defined = true;
return Value{
{"var " + LocalDecl(std::string(n.u.var->name()),
cur_func->GetLocalType(*n.u.var))},
Precedence::None};
}
case NodeType::DeclInit: {
if (cur_ast->vars_defined[n.u.var->name()].defined) {
// This has already been pre-declared, output as assign.
return WrapChild(args[0], cat(VarName(n.u.var->name()), " = "), "",
Precedence::None);
} else {
return WrapChild(
args[0],
cat("var ",
LocalDecl(std::string(n.u.var->name()),
cur_func->GetLocalType(*n.u.var)),
" = "),
"", Precedence::None);
}
}
case NodeType::Expr:
// We're going to fall thru to the second switch to deal with ExprType.
break;
case NodeType::Uninitialized:
assert(false);
break;
}
// Existing ExprTypes.
switch (n.etype) {
case ExprType::Const: {
auto& c = cast<ConstExpr>(n.e)->const_;
switch (c.type()) {
case Type::I32:
return Value{{std::to_string(static_cast<int32_t>(c.u32()))},
Precedence::Atomic};
case Type::I64:
return Value{{std::to_string(static_cast<int64_t>(c.u64())) + "L"},
Precedence::Atomic};
case Type::F32: {
float f = Bitcast<float>(c.f32_bits());
return Value{{to_string(f) + "f"}, Precedence::Atomic};
}
case Type::F64: {
double d = Bitcast<double>(c.f64_bits());
return Value{{to_string(d)}, Precedence::Atomic};
}
case Type::V128:
return Value{{"V128"}, Precedence::Atomic}; // FIXME
default:
WABT_UNREACHABLE;
}
}
case ExprType::LocalGet: {
return Get(*cast<LocalGetExpr>(n.e));
}
case ExprType::GlobalGet: {
return Get(*cast<GlobalGetExpr>(n.e));
}
case ExprType::LocalSet: {
return Set(args[0], *cast<LocalSetExpr>(n.e));
}
case ExprType::GlobalSet: {
return Set(args[0], *cast<GlobalSetExpr>(n.e));
}
case ExprType::LocalTee: {
auto& te = *cast<LocalTeeExpr>(n.e);
return args.empty() ? Get(te) : Set(args[0], te);
}
case ExprType::Binary: {
auto& be = *cast<BinaryExpr>(n.e);
auto opcs = OpcodeToToken(be.opcode);
// TODO: Is this selection better done on Opcode values directly?
// What if new values get added and OtherBin doesn't make sense?
auto prec = Precedence::OtherBin;
if (opcs == "*" || opcs == "/" || opcs == "%") {
prec = Precedence::Multiply;
} else if (opcs == "+" || opcs == "-") {
prec = Precedence::Add;
} else if (opcs == "&" || opcs == "|" || opcs == "^") {
prec = Precedence::Bit;
} else if (opcs == "<<" || opcs == ">>") {
prec = Precedence::Shift;
}
return WrapBinary(args, cat(" ", opcs, " "), false, prec);
}
case ExprType::Compare: {
auto& ce = *cast<CompareExpr>(n.e);
return WrapBinary(args, cat(" ", OpcodeToToken(ce.opcode), " "), false,
Precedence::Equal);
}
case ExprType::Unary: {
auto& ue = *cast<UnaryExpr>(n.e);
//BracketIfNeeded(stack.back());
// TODO: also version without () depending on precedence.
return WrapChild(args[0], OpcodeToToken(ue.opcode) + "(", ")",
Precedence::Atomic);
}
case ExprType::Load: {
auto& le = *cast<LoadExpr>(n.e);
LoadStore(args[0], n.children[0], le.offset, le.opcode, le.align,
le.opcode.GetResultType());
return std::move(args[0]);
}
case ExprType::Store: {
auto& se = *cast<StoreExpr>(n.e);
LoadStore(args[0], n.children[0], se.offset, se.opcode, se.align,
se.opcode.GetParamType2());
return WrapBinary(args, " = ", true, Precedence::Assign);
}
case ExprType::If: {
auto ife = cast<IfExpr>(n.e);
Value *elsep = nullptr;
if (!ife->false_.empty()) {
elsep = &args[2];
}
auto& thenp = args[1];
auto& ifs = args[0];
bool multiline = ifs.v.size() > 1 || thenp.v.size() > 1;
size_t width = ifs.width() + thenp.width();
if (elsep) {
width += elsep->width();
multiline = multiline || elsep->v.size() > 1;
}
multiline = multiline || width > target_exp_width;
if (multiline) {
auto if_start = string_view("if (");
IndentValue(ifs, if_start.size(), if_start);
ifs.v.back() += ") {";
IndentValue(thenp, indent_amount, {});
std::move(thenp.v.begin(), thenp.v.end(), std::back_inserter(ifs.v));
if (elsep) {
ifs.v.push_back("} else {");
IndentValue(*elsep, indent_amount, {});
std::move(elsep->v.begin(), elsep->v.end(), std::back_inserter(ifs.v));
}
ifs.v.push_back("}");
ifs.precedence = Precedence::If;
return std::move(ifs);
} else {
auto s = cat("if (", ifs.v[0], ") { ", thenp.v[0], " }");
if (elsep)
s += cat(" else { ", elsep->v[0], " }");
return Value{{std::move(s)}, Precedence::If};
}
}
case ExprType::Block: {
auto& val = args[0];
val.v.push_back(
cat("label ", VarName(cast<BlockExpr>(n.e)->block.label), ":"));
// If this block is part of a larger statement scope, it doesn't
// need its own indenting, but if its part of an exp we wrap it in {}.
if (parent && parent->ntype != NodeType::Statements
&& parent->etype != ExprType::Block
&& parent->etype != ExprType::Loop
&& (parent->etype != ExprType::If ||
&parent->children[0] == &n)) {
IndentValue(val, indent_amount, {});
val.v.insert(val.v.begin(), "{");
val.v.push_back("}");
}
val.precedence = Precedence::Atomic;
return std::move(val);
}
case ExprType::Loop: {
auto& val = args[0];
auto& block = cast<LoopExpr>(n.e)->block;
IndentValue(val, indent_amount, {});
val.v.insert(val.v.begin(), cat("loop ", VarName(block.label), " {"));
val.v.push_back("}");
val.precedence = Precedence::Atomic;
return std::move(val);
}
case ExprType::Br: {
auto be = cast<BrExpr>(n.e);
return Value{{(n.u.lt == LabelType::Loop ? "continue " : "goto ") +
VarName(be->var.name())},
Precedence::None};
}
case ExprType::BrIf: {
auto bie = cast<BrIfExpr>(n.e);
auto jmp = n.u.lt == LabelType::Loop ? "continue" : "goto";
return WrapChild(args[0], "if (", cat(") ", jmp, " ",
VarName(bie->var.name())),
Precedence::None);
}
case ExprType::Return: {
return WrapNAry(args, "return ", "", Precedence::None);
}
case ExprType::Rethrow: {
return WrapNAry(args, "rethrow ", "", Precedence::None);
}
case ExprType::Drop: {
// Silent dropping of return values is very common, so currently
// don't output this.
return std::move(args[0]);
}
case ExprType::Nop: {
return Value{{"nop"}, Precedence::None};
}
case ExprType::Unreachable: {
return Value{{"unreachable"}, Precedence::None};
}
case ExprType::RefNull: {
return Value{{"null"}, Precedence::Atomic};
}
case ExprType::BrTable: {
auto bte = cast<BrTableExpr>(n.e);
std::string ts = "br_table[";
for (auto &v : bte->targets) {
ts += VarName(v.name());
ts += ", ";
}
ts += "..";
ts += VarName(bte->default_target.name());
ts += "](";
return WrapChild(args[0], ts, ")", Precedence::Atomic);
}
default: {
// Everything that looks like a function call.
std::string name;
auto precedence = Precedence::Atomic;
switch (n.etype) {
case ExprType::Call:
name = cast<CallExpr>(n.e)->var.name();
break;
case ExprType::ReturnCall:
name = "return_call " + cast<ReturnCallExpr>(n.e)->var.name();
precedence = Precedence::None;
break;
case ExprType::Convert:
name = std::string(OpcodeToToken(cast<ConvertExpr>(n.e)->opcode));
break;
case ExprType::Ternary:
name = std::string(OpcodeToToken(cast<TernaryExpr>(n.e)->opcode));
break;
case ExprType::Select:
// This one looks like it could be translated to "?:" style ternary,
// but the arguments are NOT lazy, and side effects definitely do
// occur in the branches. So it has no clear equivalent in C-syntax.
// To emphasize that all args are being evaluated in order, we
// leave it as a function call.
name = "select_if";
break;
case ExprType::MemoryGrow:
name = "memory_grow";
break;
case ExprType::MemorySize:
name = "memory_size";
break;
case ExprType::MemoryCopy:
name = "memory_copy";
break;
case ExprType::MemoryFill:
name = "memory_fill";
break;
case ExprType::RefIsNull:
name = "is_null";
break;
case ExprType::CallIndirect:
name = "call_indirect";
break;
case ExprType::ReturnCallIndirect:
name = "return_call call_indirect";
break;
default:
name = GetExprTypeName(n.etype);
break;
}
return WrapNAry(args, name + "(", ")", precedence);
}
}
}
bool CheckImportExport(std::string& s,
ExternalKind kind,
Index index,
string_view name) {
// Figure out if this thing is imported, exported, or neither.
auto is_import = mc.module.IsImport(kind, Var(index));
// TODO: is this the best way to check for export?
// FIXME: this doesn't work for functions that get renamed in some way,
// as the export has the original name..
auto xport = mc.module.GetExport(name);
auto is_export = xport && xport->kind == kind;
if (is_export)
s += "export ";
if (is_import)
s += "import ";
return is_import;
}
std::string InitExp(const ExprList &el) {
assert(!el.empty());
AST ast(mc, nullptr);
ast.Construct(el, 1, 0, false);
auto val = DecompileExpr(ast.exp_stack[0], nullptr);
assert(ast.exp_stack.size() == 1 && val.v.size() == 1);
return std::move(val.v[0]);
}
// FIXME: Merge with WatWriter::WriteQuotedData somehow.
std::string BinaryToString(const std::vector<uint8_t> &in) {
std::string s = "\"";
size_t line_start = 0;
static const char s_hexdigits[] = "0123456789abcdef";
for (auto c : in) {
if (c >= ' ' && c <= '~') {
s += c;
} else {
s += '\\';
s += s_hexdigits[c >> 4];
s += s_hexdigits[c & 0xf];
}
if (s.size() - line_start > target_exp_width) {
if (line_start == 0) {
s = " " + s;
}
s += "\"\n ";
line_start = s.size();
s += "\"";
}
}
s += '\"';
return s;
}
std::string Decompile() {
std::string s;
// Memories.
Index memory_index = 0;
for (auto m : mc.module.memories) {
auto is_import =
CheckImportExport(s, ExternalKind::Memory, memory_index, m->name);
s += cat("memory ", m->name);
if (!is_import) {
s += cat("(initial: ", std::to_string(m->page_limits.initial),
", max: ", std::to_string(m->page_limits.max), ")");
}
s += ";\n";
memory_index++;
}
if (!mc.module.memories.empty())
s += "\n";
// Globals.
Index global_index = 0;
for (auto g : mc.module.globals) {
auto is_import =
CheckImportExport(s, ExternalKind::Global, global_index, g->name);
s += cat("global ", g->name, ":", GetDecompTypeName(g->type));
if (!is_import) {
s += cat(" = ", InitExp(g->init_expr));
}
s += ";\n";
global_index++;
}
if (!mc.module.globals.empty())
s += "\n";
// Tables.
Index table_index = 0;
for (auto tab : mc.module.tables) {
auto is_import =
CheckImportExport(s, ExternalKind::Table, table_index, tab->name);
s += cat("table ", tab->name, ":", GetDecompTypeName(tab->elem_type));
if (!is_import) {
s += cat("(min: ", std::to_string(tab->elem_limits.initial),
", max: ", std::to_string(tab->elem_limits.max), ")");
}
s += ";\n";
table_index++;
}
if (!mc.module.tables.empty())
s += "\n";
// Data.
for (auto dat : mc.module.data_segments) {
s += cat("data ", dat->name, "(offset: ", InitExp(dat->offset), ") = ");
auto ds = BinaryToString(dat->data);
if (ds.size() > target_exp_width / 2) {
s += "\n";
}
s += ds;
s += ";\n";
}
if (!mc.module.data_segments.empty())
s += "\n";
// Code.
Index func_index = 0;
for (auto f : mc.module.funcs) {
cur_func = f;
auto is_import =
CheckImportExport(s, ExternalKind::Func, func_index, f->name);
AST ast(mc, f);
cur_ast = &ast;
if (!is_import) {
ast.Construct(f->exprs, f->GetNumResults(), 0, true);
lst.Track(ast.exp_stack[0]);
lst.CheckLayouts();
}
s += cat("function ", f->name, "(");
for (Index i = 0; i < f->GetNumParams(); i++) {
if (i)
s += ", ";
auto t = f->GetParamType(i);
auto name = "$" + IndexToAlphaName(i);
s += LocalDecl(name, t);
}
s += ")";
if (f->GetNumResults()) {
if (f->GetNumResults() == 1) {
s += cat(":", GetDecompTypeName(f->GetResultType(0)));
} else {
s += ":(";
for (Index i = 0; i < f->GetNumResults(); i++) {
if (i)
s += ", ";
s += GetDecompTypeName(f->GetResultType(i));
}
s += ")";
}
}
if (is_import) {
s += ";";
} else {
s += " {\n";
auto val = DecompileExpr(ast.exp_stack[0], nullptr);
IndentValue(val, indent_amount, {});
for (auto& stat : val.v) {
s += stat;
s += "\n";
}
s += "}";
}
s += "\n\n";
mc.EndFunc();
lst.Clear();
func_index++;
cur_ast = nullptr;
cur_func = nullptr;
}
return s;
}
ModuleContext mc;
const DecompileOptions& options;
size_t indent_amount = 2;
size_t target_exp_width = 70;
const Func* cur_func = nullptr;
AST* cur_ast = nullptr;
LoadStoreTracking lst;
};
std::string Decompile(const Module& module, const DecompileOptions& options) {
Decompiler decompiler(module, options);
return decompiler.Decompile();
}
} // namespace wabt

36
third_party/wasm2c/src/decompiler.h vendored Normal file
View File

@@ -0,0 +1,36 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_DECOMPILER_H_
#define WABT_DECOMPILER_H_
#include "src/common.h"
namespace wabt {
struct Module;
class Stream;
struct DecompileOptions {
};
void RenameAll(Module&);
std::string Decompile(const Module&, const DecompileOptions&);
} // namespace wabt
#endif /* WABT_DECOMPILER_H_ */

View File

@@ -0,0 +1,59 @@
[
"_free",
"_malloc",
"_wabt_apply_names_module",
"_wabt_bulk_memory_enabled",
"_wabt_destroy_errors",
"_wabt_destroy_features",
"_wabt_destroy_module",
"_wabt_destroy_output_buffer",
"_wabt_destroy_parse_wat_result",
"_wabt_destroy_read_binary_result",
"_wabt_destroy_wast_lexer",
"_wabt_destroy_write_module_result",
"_wabt_exceptions_enabled",
"_wabt_format_binary_errors",
"_wabt_format_text_errors",
"_wabt_generate_names_module",
"_wabt_multi_value_enabled",
"_wabt_mutable_globals_enabled",
"_wabt_new_errors",
"_wabt_new_features",
"_wabt_new_wast_buffer_lexer",
"_wabt_output_buffer_get_data",
"_wabt_output_buffer_get_size",
"_wabt_parse_wast",
"_wabt_parse_wast_result_get_result",
"_wabt_parse_wast_result_release_module",
"_wabt_parse_wat",
"_wabt_parse_wat_result_get_result",
"_wabt_parse_wat_result_release_module",
"_wabt_read_binary",
"_wabt_read_binary_result_get_result",
"_wabt_read_binary_result_release_module",
"_wabt_reference_types_enabled",
"_wabt_sat_float_to_int_enabled",
"_wabt_set_bulk_memory_enabled",
"_wabt_set_exceptions_enabled",
"_wabt_set_multi_value_enabled",
"_wabt_set_mutable_globals_enabled",
"_wabt_set_reference_types_enabled",
"_wabt_set_sat_float_to_int_enabled",
"_wabt_set_sign_extension_enabled",
"_wabt_set_simd_enabled",
"_wabt_set_tail_call_enabled",
"_wabt_set_threads_enabled",
"_wabt_sign_extension_enabled",
"_wabt_simd_enabled",
"_wabt_tail_call_enabled",
"_wabt_threads_enabled",
"_wabt_validate_module",
"_wabt_validate_script",
"_wabt_write_binary_module",
"_wabt_write_binary_spec_script",
"_wabt_write_module_result_get_result",
"_wabt_write_module_result_release_log_output_buffer",
"_wabt_write_module_result_release_output_buffer",
"_wabt_write_text_module",
"_dummy_workaround_for_emscripten_issue_7073"
]

View File

@@ -0,0 +1,406 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_EMSCRIPTEN_HELPERS_H_
#define WABT_EMSCRIPTEN_HELPERS_H_
#include <cstddef>
#include <algorithm>
#include <iterator>
#include <memory>
#include <utility>
#include <vector>
#include "src/apply-names.h"
#include "src/binary-reader-ir.h"
#include "src/binary-reader.h"
#include "src/binary-writer-spec.h"
#include "src/binary-writer.h"
#include "src/common.h"
#include "src/error-formatter.h"
#include "src/feature.h"
#include "src/filenames.h"
#include "src/generate-names.h"
#include "src/ir.h"
#include "src/stream.h"
#include "src/validator.h"
#include "src/wast-lexer.h"
#include "src/wast-parser.h"
#include "src/wat-writer.h"
typedef std::unique_ptr<wabt::OutputBuffer> WabtOutputBufferPtr;
typedef std::pair<std::string, WabtOutputBufferPtr>
WabtFilenameOutputBufferPair;
struct WabtParseWatResult {
wabt::Result result;
std::unique_ptr<wabt::Module> module;
};
struct WabtReadBinaryResult {
wabt::Result result;
std::unique_ptr<wabt::Module> module;
};
struct WabtWriteModuleResult {
wabt::Result result;
WabtOutputBufferPtr buffer;
WabtOutputBufferPtr log_buffer;
};
struct WabtWriteScriptResult {
wabt::Result result;
WabtOutputBufferPtr json_buffer;
WabtOutputBufferPtr log_buffer;
std::vector<WabtFilenameOutputBufferPair> module_buffers;
};
struct WabtParseWastResult {
wabt::Result result;
std::unique_ptr<wabt::Script> script;
};
extern "C" {
wabt::Features* wabt_new_features(void) {
return new wabt::Features();
}
void wabt_destroy_features(wabt::Features* f) {
delete f;
}
#define WABT_FEATURE(variable, flag, default_, help) \
bool wabt_##variable##_enabled(wabt::Features* f) { \
return f->variable##_enabled(); \
} \
void wabt_set_##variable##_enabled(wabt::Features* f, int enabled) { \
f->set_##variable##_enabled(enabled); \
}
#include "src/feature.def"
#undef WABT_FEATURE
wabt::WastLexer* wabt_new_wast_buffer_lexer(const char* filename,
const void* data,
size_t size) {
std::unique_ptr<wabt::WastLexer> lexer =
wabt::WastLexer::CreateBufferLexer(filename, data, size);
return lexer.release();
}
WabtParseWatResult* wabt_parse_wat(wabt::WastLexer* lexer,
wabt::Features* features,
wabt::Errors* errors) {
wabt::WastParseOptions options(*features);
WabtParseWatResult* result = new WabtParseWatResult();
std::unique_ptr<wabt::Module> module;
result->result = wabt::ParseWatModule(lexer, &module, errors, &options);
result->module = std::move(module);
return result;
}
WabtParseWastResult* wabt_parse_wast(wabt::WastLexer* lexer,
wabt::Features* features,
wabt::Errors* errors) {
wabt::WastParseOptions options(*features);
WabtParseWastResult* result = new WabtParseWastResult();
std::unique_ptr<wabt::Script> script;
result->result = wabt::ParseWastScript(lexer, &script, errors, &options);
result->script = std::move(script);
return result;
}
WabtReadBinaryResult* wabt_read_binary(const void* data,
size_t size,
int read_debug_names,
wabt::Features* features,
wabt::Errors* errors) {
wabt::ReadBinaryOptions options;
options.features = *features;
options.read_debug_names = read_debug_names;
WabtReadBinaryResult* result = new WabtReadBinaryResult();
wabt::Module* module = new wabt::Module();
// TODO(binji): Pass through from wabt_read_binary parameter.
const char* filename = "<binary>";
result->result =
wabt::ReadBinaryIr(filename, data, size, options, errors, module);
result->module.reset(module);
return result;
}
wabt::Result::Enum wabt_validate_module(wabt::Module* module,
wabt::Features* features,
wabt::Errors* errors) {
wabt::ValidateOptions options;
options.features = *features;
return ValidateModule(module, errors, options);
}
wabt::Result::Enum wabt_validate_script(wabt::Script* script,
wabt::Features* features,
wabt::Errors* errors) {
wabt::ValidateOptions options;
options.features = *features;
return ValidateScript(script, errors, options);
}
WabtWriteScriptResult* wabt_write_binary_spec_script(
wabt::Script* script,
const char* source_filename,
const char* out_filename,
int log,
int canonicalize_lebs,
int relocatable,
int write_debug_names) {
wabt::MemoryStream log_stream;
wabt::MemoryStream* log_stream_p = log ? &log_stream : nullptr;
wabt::WriteBinaryOptions options;
options.canonicalize_lebs = canonicalize_lebs;
options.relocatable = relocatable;
options.write_debug_names = write_debug_names;
std::vector<wabt::FilenameMemoryStreamPair> module_streams;
wabt::MemoryStream json_stream(log_stream_p);
std::string module_filename_noext =
wabt::StripExtension(out_filename ? out_filename : source_filename)
.to_string();
WabtWriteScriptResult* result = new WabtWriteScriptResult();
result->result = WriteBinarySpecScript(&json_stream, script, source_filename,
module_filename_noext, options,
&module_streams, log_stream_p);
if (result->result == wabt::Result::Ok) {
result->json_buffer = json_stream.ReleaseOutputBuffer();
result->log_buffer = log ? log_stream.ReleaseOutputBuffer() : nullptr;
std::transform(module_streams.begin(), module_streams.end(),
std::back_inserter(result->module_buffers),
[](wabt::FilenameMemoryStreamPair& pair) {
return WabtFilenameOutputBufferPair(
pair.filename, pair.stream->ReleaseOutputBuffer());
});
}
return result;
}
wabt::Result::Enum wabt_apply_names_module(wabt::Module* module) {
return ApplyNames(module);
}
wabt::Result::Enum wabt_generate_names_module(wabt::Module* module) {
return GenerateNames(module);
}
WabtWriteModuleResult* wabt_write_binary_module(wabt::Module* module,
int log,
int canonicalize_lebs,
int relocatable,
int write_debug_names) {
wabt::MemoryStream log_stream;
wabt::WriteBinaryOptions options;
options.canonicalize_lebs = canonicalize_lebs;
options.relocatable = relocatable;
options.write_debug_names = write_debug_names;
wabt::MemoryStream stream(log ? &log_stream : nullptr);
WabtWriteModuleResult* result = new WabtWriteModuleResult();
result->result = WriteBinaryModule(&stream, module, options);
if (result->result == wabt::Result::Ok) {
result->buffer = stream.ReleaseOutputBuffer();
result->log_buffer = log ? log_stream.ReleaseOutputBuffer() : nullptr;
}
return result;
}
WabtWriteModuleResult* wabt_write_text_module(wabt::Module* module,
int fold_exprs,
int inline_export) {
wabt::WriteWatOptions options;
options.fold_exprs = fold_exprs;
options.inline_export = inline_export;
wabt::MemoryStream stream;
WabtWriteModuleResult* result = new WabtWriteModuleResult();
result->result = WriteWat(&stream, module, options);
if (result->result == wabt::Result::Ok) {
result->buffer = stream.ReleaseOutputBuffer();
}
return result;
}
void wabt_destroy_module(wabt::Module* module) {
delete module;
}
void wabt_destroy_wast_lexer(wabt::WastLexer* lexer) {
delete lexer;
}
// Errors
wabt::Errors* wabt_new_errors(void) {
return new wabt::Errors();
}
wabt::OutputBuffer* wabt_format_text_errors(wabt::Errors* errors,
wabt::WastLexer* lexer) {
auto line_finder = lexer->MakeLineFinder();
std::string string_result = FormatErrorsToString(
*errors, wabt::Location::Type::Text, line_finder.get());
wabt::OutputBuffer* result = new wabt::OutputBuffer();
std::copy(string_result.begin(), string_result.end(),
std::back_inserter(result->data));
return result;
}
wabt::OutputBuffer* wabt_format_binary_errors(wabt::Errors* errors) {
std::string string_result =
FormatErrorsToString(*errors, wabt::Location::Type::Binary);
wabt::OutputBuffer* result = new wabt::OutputBuffer();
std::copy(string_result.begin(), string_result.end(),
std::back_inserter(result->data));
return result;
}
void wabt_destroy_errors(wabt::Errors* errors) {
delete errors;
}
// WabtParseWatResult
wabt::Result::Enum wabt_parse_wat_result_get_result(
WabtParseWatResult* result) {
return result->result;
}
wabt::Module* wabt_parse_wat_result_release_module(WabtParseWatResult* result) {
return result->module.release();
}
void wabt_destroy_parse_wat_result(WabtParseWatResult* result) {
delete result;
}
// WabtParseWastResult
wabt::Result::Enum wabt_parse_wast_result_get_result(
WabtParseWastResult* result) {
return result->result;
}
wabt::Script* wabt_parse_wast_result_release_module(
WabtParseWastResult* result) {
return result->script.release();
}
void wabt_destroy_parse_wast_result(WabtParseWastResult* result) {
delete result;
}
// WabtReadBinaryResult
wabt::Result::Enum wabt_read_binary_result_get_result(
WabtReadBinaryResult* result) {
return result->result;
}
wabt::Module* wabt_read_binary_result_release_module(
WabtReadBinaryResult* result) {
return result->module.release();
}
void wabt_destroy_read_binary_result(WabtReadBinaryResult* result) {
delete result;
}
// WabtWriteModuleResult
wabt::Result::Enum wabt_write_module_result_get_result(
WabtWriteModuleResult* result) {
return result->result;
}
wabt::OutputBuffer* wabt_write_module_result_release_output_buffer(
WabtWriteModuleResult* result) {
return result->buffer.release();
}
wabt::OutputBuffer* wabt_write_module_result_release_log_output_buffer(
WabtWriteModuleResult* result) {
return result->log_buffer.release();
}
void wabt_destroy_write_module_result(WabtWriteModuleResult* result) {
delete result;
}
// WabtWriteScriptResult
wabt::Result::Enum wabt_write_script_result_get_result(
WabtWriteScriptResult* result) {
return result->result;
}
wabt::OutputBuffer* wabt_write_script_result_release_json_output_buffer(
WabtWriteScriptResult* result) {
return result->json_buffer.release();
}
wabt::OutputBuffer* wabt_write_script_result_release_log_output_buffer(
WabtWriteScriptResult* result) {
return result->log_buffer.release();
}
size_t wabt_write_script_result_get_module_count(
WabtWriteScriptResult* result) {
return result->module_buffers.size();
}
const char* wabt_write_script_result_get_module_filename(
WabtWriteScriptResult* result,
size_t index) {
return result->module_buffers[index].first.c_str();
}
wabt::OutputBuffer* wabt_write_script_result_release_module_output_buffer(
WabtWriteScriptResult* result,
size_t index) {
return result->module_buffers[index].second.release();
}
void wabt_destroy_write_script_result(WabtWriteScriptResult* result) {
delete result;
}
// wabt::OutputBuffer*
const void* wabt_output_buffer_get_data(wabt::OutputBuffer* output_buffer) {
return output_buffer->data.data();
}
size_t wabt_output_buffer_get_size(wabt::OutputBuffer* output_buffer) {
return output_buffer->data.size();
}
void wabt_destroy_output_buffer(wabt::OutputBuffer* output_buffer) {
delete output_buffer;
}
// See https://github.com/kripken/emscripten/issues/7073.
void dummy_workaround_for_emscripten_issue_7073(void) {}
} // extern "C"
#endif /* WABT_EMSCRIPTEN_HELPERS_H_ */

View File

@@ -0,0 +1,127 @@
/*
* Copyright 2018 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/error-formatter.h"
namespace wabt {
namespace {
std::string FormatError(const Error& error,
Location::Type location_type,
const Color& color,
LexerSourceLineFinder* line_finder,
int source_line_max_length,
int indent) {
std::string indent_str(indent, ' ');
std::string result = indent_str;
result += color.MaybeBoldCode();
const Location& loc = error.loc;
if (!loc.filename.empty()) {
result += loc.filename.to_string();
result += ":";
}
if (location_type == Location::Type::Text) {
result += StringPrintf("%d:%d: ", loc.line, loc.first_column);
} else if (loc.offset != kInvalidOffset) {
result += StringPrintf("%07" PRIzx ": ", loc.offset);
}
result += color.MaybeRedCode();
result += GetErrorLevelName(error.error_level);
result += ": ";
result += color.MaybeDefaultCode();
result += error.message;
result += '\n';
LexerSourceLineFinder::SourceLine source_line;
if (line_finder) {
line_finder->GetSourceLine(loc, source_line_max_length, &source_line);
}
if (!source_line.line.empty()) {
result += indent_str;
result += source_line.line;
result += '\n';
result += indent_str;
size_t num_spaces = (loc.first_column - 1) - source_line.column_offset;
size_t num_carets = loc.last_column - loc.first_column;
num_carets = std::min(num_carets, source_line.line.size() - num_spaces);
num_carets = std::max<size_t>(num_carets, 1);
result.append(num_spaces, ' ');
result += color.MaybeBoldCode();
result += color.MaybeGreenCode();
result.append(num_carets, '^');
result += color.MaybeDefaultCode();
result += '\n';
}
return result;
}
} // End of anonymous namespace
std::string FormatErrorsToString(const Errors& errors,
Location::Type location_type,
LexerSourceLineFinder* line_finder,
const Color& color,
const std::string& header,
PrintHeader print_header,
int source_line_max_length) {
std::string result;
for (const auto& error : errors) {
if (!header.empty()) {
switch (print_header) {
case PrintHeader::Never:
break;
case PrintHeader::Once:
print_header = PrintHeader::Never;
// Fallthrough.
case PrintHeader::Always:
result += header;
result += ":\n";
break;
}
}
int indent = header.empty() ? 0 : 2;
result += FormatError(error, location_type, color, line_finder,
source_line_max_length, indent);
}
return result;
}
void FormatErrorsToFile(const Errors& errors,
Location::Type location_type,
LexerSourceLineFinder* line_finder,
FILE* file,
const std::string& header,
PrintHeader print_header,
int source_line_max_length) {
Color color(file);
std::string s =
FormatErrorsToString(errors, location_type, line_finder, color, header,
print_header, source_line_max_length);
fwrite(s.data(), 1, s.size(), file);
}
} // namespace wabt

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2018 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_ERROR_FORMATTER_H_
#define WABT_ERROR_FORMATTER_H_
#include <cstdio>
#include <string>
#include <memory>
#include "src/color.h"
#include "src/error.h"
#include "src/lexer-source-line-finder.h"
namespace wabt {
enum class PrintHeader {
Never,
Once,
Always,
};
std::string FormatErrorsToString(const Errors&,
Location::Type,
LexerSourceLineFinder* = nullptr,
const Color& color = Color(nullptr, false),
const std::string& header = {},
PrintHeader print_header = PrintHeader::Never,
int source_line_max_length = 80);
void FormatErrorsToFile(const Errors&,
Location::Type,
LexerSourceLineFinder* = nullptr,
FILE* = stderr,
const std::string& header = {},
PrintHeader print_header = PrintHeader::Never,
int source_line_max_length = 80);
} // namespace wabt
#endif // WABT_ERROR_FORMATTER_H_

58
third_party/wasm2c/src/error.h vendored Normal file
View File

@@ -0,0 +1,58 @@
/*
* Copyright 2018 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_ERROR_H_
#define WABT_ERROR_H_
#include <string>
#include <vector>
#include "src/common.h"
#include "src/string-view.h"
namespace wabt {
enum class ErrorLevel {
Warning,
Error,
};
static WABT_INLINE const char* GetErrorLevelName(ErrorLevel error_level) {
switch (error_level) {
case ErrorLevel::Warning:
return "warning";
case ErrorLevel::Error:
return "error";
}
WABT_UNREACHABLE;
}
class Error {
public:
Error() : error_level(ErrorLevel::Error) {}
Error(ErrorLevel error_level, Location loc, string_view message)
: error_level(error_level), loc(loc), message(message.to_string()) {}
ErrorLevel error_level;
Location loc;
std::string message;
};
using Errors = std::vector<Error>;
} // namespace wabt
#endif // WABT_ERROR_H_

481
third_party/wasm2c/src/expr-visitor.cc vendored Normal file
View File

@@ -0,0 +1,481 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/expr-visitor.h"
#include "src/cast.h"
#include "src/ir.h"
namespace wabt {
ExprVisitor::ExprVisitor(Delegate* delegate) : delegate_(delegate) {}
Result ExprVisitor::VisitExpr(Expr* root_expr) {
state_stack_.clear();
expr_stack_.clear();
expr_iter_stack_.clear();
catch_index_stack_.clear();
PushDefault(root_expr);
while (!state_stack_.empty()) {
State state = state_stack_.back();
auto* expr = expr_stack_.back();
switch (state) {
case State::Default:
PopDefault();
CHECK_RESULT(HandleDefaultState(expr));
break;
case State::Block: {
auto block_expr = cast<BlockExpr>(expr);
auto& iter = expr_iter_stack_.back();
if (iter != block_expr->block.exprs.end()) {
PushDefault(&*iter++);
} else {
CHECK_RESULT(delegate_->EndBlockExpr(block_expr));
PopExprlist();
}
break;
}
case State::IfTrue: {
auto if_expr = cast<IfExpr>(expr);
auto& iter = expr_iter_stack_.back();
if (iter != if_expr->true_.exprs.end()) {
PushDefault(&*iter++);
} else {
CHECK_RESULT(delegate_->AfterIfTrueExpr(if_expr));
PopExprlist();
PushExprlist(State::IfFalse, expr, if_expr->false_);
}
break;
}
case State::IfFalse: {
auto if_expr = cast<IfExpr>(expr);
auto& iter = expr_iter_stack_.back();
if (iter != if_expr->false_.end()) {
PushDefault(&*iter++);
} else {
CHECK_RESULT(delegate_->EndIfExpr(if_expr));
PopExprlist();
}
break;
}
case State::Loop: {
auto loop_expr = cast<LoopExpr>(expr);
auto& iter = expr_iter_stack_.back();
if (iter != loop_expr->block.exprs.end()) {
PushDefault(&*iter++);
} else {
CHECK_RESULT(delegate_->EndLoopExpr(loop_expr));
PopExprlist();
}
break;
}
case State::Try: {
auto try_expr = cast<TryExpr>(expr);
auto& iter = expr_iter_stack_.back();
if (iter != try_expr->block.exprs.end()) {
PushDefault(&*iter++);
} else {
PopExprlist();
switch (try_expr->kind) {
case TryKind::Catch:
if (!try_expr->catches.empty()) {
Catch& catch_ = try_expr->catches[0];
CHECK_RESULT(delegate_->OnCatchExpr(try_expr, &catch_));
PushCatch(expr, 0, catch_.exprs);
} else {
CHECK_RESULT(delegate_->EndTryExpr(try_expr));
}
break;
case TryKind::Unwind:
CHECK_RESULT(delegate_->OnUnwindExpr(try_expr));
PushExprlist(State::Unwind, expr, try_expr->unwind);
break;
case TryKind::Delegate:
CHECK_RESULT(delegate_->OnDelegateExpr(try_expr));
break;
case TryKind::Invalid:
// Should not happen.
break;
}
}
break;
}
case State::Catch: {
auto try_expr = cast<TryExpr>(expr);
Index catch_index = catch_index_stack_.back();
auto& iter = expr_iter_stack_.back();
if (iter != try_expr->catches[catch_index].exprs.end()) {
PushDefault(&*iter++);
} else {
PopCatch();
catch_index++;
if (catch_index < try_expr->catches.size()) {
Catch& catch_ = try_expr->catches[catch_index];
CHECK_RESULT(delegate_->OnCatchExpr(try_expr, &catch_));
PushCatch(expr, catch_index, catch_.exprs);
} else {
CHECK_RESULT(delegate_->EndTryExpr(try_expr));
}
}
break;
}
case State::Unwind: {
auto try_expr = cast<TryExpr>(expr);
auto& iter = expr_iter_stack_.back();
if (iter != try_expr->unwind.end()) {
PushDefault(&*iter++);
} else {
CHECK_RESULT(delegate_->EndTryExpr(try_expr));
PopExprlist();
}
break;
}
}
}
return Result::Ok;
}
Result ExprVisitor::VisitExprList(ExprList& exprs) {
for (Expr& expr : exprs)
CHECK_RESULT(VisitExpr(&expr));
return Result::Ok;
}
Result ExprVisitor::VisitFunc(Func* func) {
return VisitExprList(func->exprs);
}
Result ExprVisitor::HandleDefaultState(Expr* expr) {
switch (expr->type()) {
case ExprType::AtomicLoad:
CHECK_RESULT(delegate_->OnAtomicLoadExpr(cast<AtomicLoadExpr>(expr)));
break;
case ExprType::AtomicStore:
CHECK_RESULT(delegate_->OnAtomicStoreExpr(cast<AtomicStoreExpr>(expr)));
break;
case ExprType::AtomicRmw:
CHECK_RESULT(delegate_->OnAtomicRmwExpr(cast<AtomicRmwExpr>(expr)));
break;
case ExprType::AtomicRmwCmpxchg:
CHECK_RESULT(
delegate_->OnAtomicRmwCmpxchgExpr(cast<AtomicRmwCmpxchgExpr>(expr)));
break;
case ExprType::AtomicWait:
CHECK_RESULT(delegate_->OnAtomicWaitExpr(cast<AtomicWaitExpr>(expr)));
break;
case ExprType::AtomicFence:
CHECK_RESULT(delegate_->OnAtomicFenceExpr(cast<AtomicFenceExpr>(expr)));
break;
case ExprType::AtomicNotify:
CHECK_RESULT(delegate_->OnAtomicNotifyExpr(cast<AtomicNotifyExpr>(expr)));
break;
case ExprType::Binary:
CHECK_RESULT(delegate_->OnBinaryExpr(cast<BinaryExpr>(expr)));
break;
case ExprType::Block: {
auto block_expr = cast<BlockExpr>(expr);
CHECK_RESULT(delegate_->BeginBlockExpr(block_expr));
PushExprlist(State::Block, expr, block_expr->block.exprs);
break;
}
case ExprType::Br:
CHECK_RESULT(delegate_->OnBrExpr(cast<BrExpr>(expr)));
break;
case ExprType::BrIf:
CHECK_RESULT(delegate_->OnBrIfExpr(cast<BrIfExpr>(expr)));
break;
case ExprType::BrTable:
CHECK_RESULT(delegate_->OnBrTableExpr(cast<BrTableExpr>(expr)));
break;
case ExprType::Call:
CHECK_RESULT(delegate_->OnCallExpr(cast<CallExpr>(expr)));
break;
case ExprType::CallIndirect:
CHECK_RESULT(delegate_->OnCallIndirectExpr(cast<CallIndirectExpr>(expr)));
break;
case ExprType::Compare:
CHECK_RESULT(delegate_->OnCompareExpr(cast<CompareExpr>(expr)));
break;
case ExprType::Const:
CHECK_RESULT(delegate_->OnConstExpr(cast<ConstExpr>(expr)));
break;
case ExprType::Convert:
CHECK_RESULT(delegate_->OnConvertExpr(cast<ConvertExpr>(expr)));
break;
case ExprType::Drop:
CHECK_RESULT(delegate_->OnDropExpr(cast<DropExpr>(expr)));
break;
case ExprType::GlobalGet:
CHECK_RESULT(delegate_->OnGlobalGetExpr(cast<GlobalGetExpr>(expr)));
break;
case ExprType::GlobalSet:
CHECK_RESULT(delegate_->OnGlobalSetExpr(cast<GlobalSetExpr>(expr)));
break;
case ExprType::If: {
auto if_expr = cast<IfExpr>(expr);
CHECK_RESULT(delegate_->BeginIfExpr(if_expr));
PushExprlist(State::IfTrue, expr, if_expr->true_.exprs);
break;
}
case ExprType::Load:
CHECK_RESULT(delegate_->OnLoadExpr(cast<LoadExpr>(expr)));
break;
case ExprType::LoadSplat:
CHECK_RESULT(delegate_->OnLoadSplatExpr(cast<LoadSplatExpr>(expr)));
break;
case ExprType::LoadZero:
CHECK_RESULT(delegate_->OnLoadZeroExpr(cast<LoadZeroExpr>(expr)));
break;
case ExprType::LocalGet:
CHECK_RESULT(delegate_->OnLocalGetExpr(cast<LocalGetExpr>(expr)));
break;
case ExprType::LocalSet:
CHECK_RESULT(delegate_->OnLocalSetExpr(cast<LocalSetExpr>(expr)));
break;
case ExprType::LocalTee:
CHECK_RESULT(delegate_->OnLocalTeeExpr(cast<LocalTeeExpr>(expr)));
break;
case ExprType::Loop: {
auto loop_expr = cast<LoopExpr>(expr);
CHECK_RESULT(delegate_->BeginLoopExpr(loop_expr));
PushExprlist(State::Loop, expr, loop_expr->block.exprs);
break;
}
case ExprType::MemoryCopy:
CHECK_RESULT(delegate_->OnMemoryCopyExpr(cast<MemoryCopyExpr>(expr)));
break;
case ExprType::DataDrop:
CHECK_RESULT(delegate_->OnDataDropExpr(cast<DataDropExpr>(expr)));
break;
case ExprType::MemoryFill:
CHECK_RESULT(delegate_->OnMemoryFillExpr(cast<MemoryFillExpr>(expr)));
break;
case ExprType::MemoryGrow:
CHECK_RESULT(delegate_->OnMemoryGrowExpr(cast<MemoryGrowExpr>(expr)));
break;
case ExprType::MemoryInit:
CHECK_RESULT(delegate_->OnMemoryInitExpr(cast<MemoryInitExpr>(expr)));
break;
case ExprType::MemorySize:
CHECK_RESULT(delegate_->OnMemorySizeExpr(cast<MemorySizeExpr>(expr)));
break;
case ExprType::TableCopy:
CHECK_RESULT(delegate_->OnTableCopyExpr(cast<TableCopyExpr>(expr)));
break;
case ExprType::ElemDrop:
CHECK_RESULT(delegate_->OnElemDropExpr(cast<ElemDropExpr>(expr)));
break;
case ExprType::TableInit:
CHECK_RESULT(delegate_->OnTableInitExpr(cast<TableInitExpr>(expr)));
break;
case ExprType::TableGet:
CHECK_RESULT(delegate_->OnTableGetExpr(cast<TableGetExpr>(expr)));
break;
case ExprType::TableSet:
CHECK_RESULT(delegate_->OnTableSetExpr(cast<TableSetExpr>(expr)));
break;
case ExprType::TableGrow:
CHECK_RESULT(delegate_->OnTableGrowExpr(cast<TableGrowExpr>(expr)));
break;
case ExprType::TableSize:
CHECK_RESULT(delegate_->OnTableSizeExpr(cast<TableSizeExpr>(expr)));
break;
case ExprType::TableFill:
CHECK_RESULT(delegate_->OnTableFillExpr(cast<TableFillExpr>(expr)));
break;
case ExprType::RefFunc:
CHECK_RESULT(delegate_->OnRefFuncExpr(cast<RefFuncExpr>(expr)));
break;
case ExprType::RefNull:
CHECK_RESULT(delegate_->OnRefNullExpr(cast<RefNullExpr>(expr)));
break;
case ExprType::RefIsNull:
CHECK_RESULT(delegate_->OnRefIsNullExpr(cast<RefIsNullExpr>(expr)));
break;
case ExprType::Nop:
CHECK_RESULT(delegate_->OnNopExpr(cast<NopExpr>(expr)));
break;
case ExprType::Rethrow:
CHECK_RESULT(delegate_->OnRethrowExpr(cast<RethrowExpr>(expr)));
break;
case ExprType::Return:
CHECK_RESULT(delegate_->OnReturnExpr(cast<ReturnExpr>(expr)));
break;
case ExprType::ReturnCall:
CHECK_RESULT(delegate_->OnReturnCallExpr(cast<ReturnCallExpr>(expr)));
break;
case ExprType::ReturnCallIndirect:
CHECK_RESULT(delegate_->OnReturnCallIndirectExpr(
cast<ReturnCallIndirectExpr>(expr)));
break;
case ExprType::Select:
CHECK_RESULT(delegate_->OnSelectExpr(cast<SelectExpr>(expr)));
break;
case ExprType::Store:
CHECK_RESULT(delegate_->OnStoreExpr(cast<StoreExpr>(expr)));
break;
case ExprType::Throw:
CHECK_RESULT(delegate_->OnThrowExpr(cast<ThrowExpr>(expr)));
break;
case ExprType::Try: {
auto try_expr = cast<TryExpr>(expr);
CHECK_RESULT(delegate_->BeginTryExpr(try_expr));
PushExprlist(State::Try, expr, try_expr->block.exprs);
break;
}
case ExprType::Unary:
CHECK_RESULT(delegate_->OnUnaryExpr(cast<UnaryExpr>(expr)));
break;
case ExprType::Ternary:
CHECK_RESULT(delegate_->OnTernaryExpr(cast<TernaryExpr>(expr)));
break;
case ExprType::SimdLaneOp: {
CHECK_RESULT(delegate_->OnSimdLaneOpExpr(cast<SimdLaneOpExpr>(expr)));
break;
}
case ExprType::SimdLoadLane: {
CHECK_RESULT(delegate_->OnSimdLoadLaneExpr(cast<SimdLoadLaneExpr>(expr)));
break;
}
case ExprType::SimdStoreLane: {
CHECK_RESULT(
delegate_->OnSimdStoreLaneExpr(cast<SimdStoreLaneExpr>(expr)));
break;
}
case ExprType::SimdShuffleOp: {
CHECK_RESULT(
delegate_->OnSimdShuffleOpExpr(cast<SimdShuffleOpExpr>(expr)));
break;
}
case ExprType::Unreachable:
CHECK_RESULT(delegate_->OnUnreachableExpr(cast<UnreachableExpr>(expr)));
break;
}
return Result::Ok;
}
void ExprVisitor::PushDefault(Expr* expr) {
state_stack_.emplace_back(State::Default);
expr_stack_.emplace_back(expr);
}
void ExprVisitor::PopDefault() {
state_stack_.pop_back();
expr_stack_.pop_back();
}
void ExprVisitor::PushExprlist(State state, Expr* expr, ExprList& expr_list) {
state_stack_.emplace_back(state);
expr_stack_.emplace_back(expr);
expr_iter_stack_.emplace_back(expr_list.begin());
}
void ExprVisitor::PopExprlist() {
state_stack_.pop_back();
expr_stack_.pop_back();
expr_iter_stack_.pop_back();
}
void ExprVisitor::PushCatch(Expr* expr,
Index catch_index,
ExprList& expr_list) {
state_stack_.emplace_back(State::Catch);
expr_stack_.emplace_back(expr);
expr_iter_stack_.emplace_back(expr_list.begin());
catch_index_stack_.emplace_back(catch_index);
}
void ExprVisitor::PopCatch() {
state_stack_.pop_back();
expr_stack_.pop_back();
expr_iter_stack_.pop_back();
catch_index_stack_.pop_back();
}
} // namespace wabt

221
third_party/wasm2c/src/expr-visitor.h vendored Normal file
View File

@@ -0,0 +1,221 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_EXPR_VISITOR_H_
#define WABT_EXPR_VISITOR_H_
#include "src/common.h"
#include "src/ir.h"
namespace wabt {
class ExprVisitor {
public:
class Delegate;
class DelegateNop;
explicit ExprVisitor(Delegate* delegate);
Result VisitExpr(Expr*);
Result VisitExprList(ExprList&);
Result VisitFunc(Func*);
private:
enum class State {
Default,
Block,
IfTrue,
IfFalse,
Loop,
Try,
Catch,
Unwind,
};
Result HandleDefaultState(Expr*);
void PushDefault(Expr*);
void PopDefault();
void PushExprlist(State state, Expr*, ExprList&);
void PopExprlist();
void PushCatch(Expr*, Index catch_index, ExprList&);
void PopCatch();
Delegate* delegate_;
// Use parallel arrays instead of array of structs so we can avoid allocating
// unneeded objects. ExprList::iterator has no default constructor, so it
// must only be allocated for states that use it.
std::vector<State> state_stack_;
std::vector<Expr*> expr_stack_;
std::vector<ExprList::iterator> expr_iter_stack_;
std::vector<Index> catch_index_stack_;
};
class ExprVisitor::Delegate {
public:
virtual ~Delegate() {}
virtual Result OnBinaryExpr(BinaryExpr*) = 0;
virtual Result BeginBlockExpr(BlockExpr*) = 0;
virtual Result EndBlockExpr(BlockExpr*) = 0;
virtual Result OnBrExpr(BrExpr*) = 0;
virtual Result OnBrIfExpr(BrIfExpr*) = 0;
virtual Result OnBrTableExpr(BrTableExpr*) = 0;
virtual Result OnCallExpr(CallExpr*) = 0;
virtual Result OnCallIndirectExpr(CallIndirectExpr*) = 0;
virtual Result OnCompareExpr(CompareExpr*) = 0;
virtual Result OnConstExpr(ConstExpr*) = 0;
virtual Result OnConvertExpr(ConvertExpr*) = 0;
virtual Result OnDropExpr(DropExpr*) = 0;
virtual Result OnGlobalGetExpr(GlobalGetExpr*) = 0;
virtual Result OnGlobalSetExpr(GlobalSetExpr*) = 0;
virtual Result BeginIfExpr(IfExpr*) = 0;
virtual Result AfterIfTrueExpr(IfExpr*) = 0;
virtual Result EndIfExpr(IfExpr*) = 0;
virtual Result OnLoadExpr(LoadExpr*) = 0;
virtual Result OnLocalGetExpr(LocalGetExpr*) = 0;
virtual Result OnLocalSetExpr(LocalSetExpr*) = 0;
virtual Result OnLocalTeeExpr(LocalTeeExpr*) = 0;
virtual Result BeginLoopExpr(LoopExpr*) = 0;
virtual Result EndLoopExpr(LoopExpr*) = 0;
virtual Result OnMemoryCopyExpr(MemoryCopyExpr*) = 0;
virtual Result OnDataDropExpr(DataDropExpr*) = 0;
virtual Result OnMemoryFillExpr(MemoryFillExpr*) = 0;
virtual Result OnMemoryGrowExpr(MemoryGrowExpr*) = 0;
virtual Result OnMemoryInitExpr(MemoryInitExpr*) = 0;
virtual Result OnMemorySizeExpr(MemorySizeExpr*) = 0;
virtual Result OnTableCopyExpr(TableCopyExpr*) = 0;
virtual Result OnElemDropExpr(ElemDropExpr*) = 0;
virtual Result OnTableInitExpr(TableInitExpr*) = 0;
virtual Result OnTableGetExpr(TableGetExpr*) = 0;
virtual Result OnTableSetExpr(TableSetExpr*) = 0;
virtual Result OnTableGrowExpr(TableGrowExpr*) = 0;
virtual Result OnTableSizeExpr(TableSizeExpr*) = 0;
virtual Result OnTableFillExpr(TableFillExpr*) = 0;
virtual Result OnRefFuncExpr(RefFuncExpr*) = 0;
virtual Result OnRefNullExpr(RefNullExpr*) = 0;
virtual Result OnRefIsNullExpr(RefIsNullExpr*) = 0;
virtual Result OnNopExpr(NopExpr*) = 0;
virtual Result OnReturnExpr(ReturnExpr*) = 0;
virtual Result OnReturnCallExpr(ReturnCallExpr*) = 0;
virtual Result OnReturnCallIndirectExpr(ReturnCallIndirectExpr*) = 0;
virtual Result OnSelectExpr(SelectExpr*) = 0;
virtual Result OnStoreExpr(StoreExpr*) = 0;
virtual Result OnUnaryExpr(UnaryExpr*) = 0;
virtual Result OnUnreachableExpr(UnreachableExpr*) = 0;
virtual Result BeginTryExpr(TryExpr*) = 0;
virtual Result OnCatchExpr(TryExpr*, Catch*) = 0;
virtual Result OnUnwindExpr(TryExpr*) = 0;
virtual Result OnDelegateExpr(TryExpr*) = 0;
virtual Result EndTryExpr(TryExpr*) = 0;
virtual Result OnThrowExpr(ThrowExpr*) = 0;
virtual Result OnRethrowExpr(RethrowExpr*) = 0;
virtual Result OnAtomicWaitExpr(AtomicWaitExpr*) = 0;
virtual Result OnAtomicFenceExpr(AtomicFenceExpr*) = 0;
virtual Result OnAtomicNotifyExpr(AtomicNotifyExpr*) = 0;
virtual Result OnAtomicLoadExpr(AtomicLoadExpr*) = 0;
virtual Result OnAtomicStoreExpr(AtomicStoreExpr*) = 0;
virtual Result OnAtomicRmwExpr(AtomicRmwExpr*) = 0;
virtual Result OnAtomicRmwCmpxchgExpr(AtomicRmwCmpxchgExpr*) = 0;
virtual Result OnTernaryExpr(TernaryExpr*) = 0;
virtual Result OnSimdLaneOpExpr(SimdLaneOpExpr*) = 0;
virtual Result OnSimdLoadLaneExpr(SimdLoadLaneExpr*) = 0;
virtual Result OnSimdStoreLaneExpr(SimdStoreLaneExpr*) = 0;
virtual Result OnSimdShuffleOpExpr(SimdShuffleOpExpr*) = 0;
virtual Result OnLoadSplatExpr(LoadSplatExpr*) = 0;
virtual Result OnLoadZeroExpr(LoadZeroExpr*) = 0;
};
class ExprVisitor::DelegateNop : public ExprVisitor::Delegate {
public:
Result OnBinaryExpr(BinaryExpr*) override { return Result::Ok; }
Result BeginBlockExpr(BlockExpr*) override { return Result::Ok; }
Result EndBlockExpr(BlockExpr*) override { return Result::Ok; }
Result OnBrExpr(BrExpr*) override { return Result::Ok; }
Result OnBrIfExpr(BrIfExpr*) override { return Result::Ok; }
Result OnBrTableExpr(BrTableExpr*) override { return Result::Ok; }
Result OnCallExpr(CallExpr*) override { return Result::Ok; }
Result OnCallIndirectExpr(CallIndirectExpr*) override { return Result::Ok; }
Result OnCompareExpr(CompareExpr*) override { return Result::Ok; }
Result OnConstExpr(ConstExpr*) override { return Result::Ok; }
Result OnConvertExpr(ConvertExpr*) override { return Result::Ok; }
Result OnDropExpr(DropExpr*) override { return Result::Ok; }
Result OnGlobalGetExpr(GlobalGetExpr*) override { return Result::Ok; }
Result OnGlobalSetExpr(GlobalSetExpr*) override { return Result::Ok; }
Result BeginIfExpr(IfExpr*) override { return Result::Ok; }
Result AfterIfTrueExpr(IfExpr*) override { return Result::Ok; }
Result EndIfExpr(IfExpr*) override { return Result::Ok; }
Result OnLoadExpr(LoadExpr*) override { return Result::Ok; }
Result OnLocalGetExpr(LocalGetExpr*) override { return Result::Ok; }
Result OnLocalSetExpr(LocalSetExpr*) override { return Result::Ok; }
Result OnLocalTeeExpr(LocalTeeExpr*) override { return Result::Ok; }
Result BeginLoopExpr(LoopExpr*) override { return Result::Ok; }
Result EndLoopExpr(LoopExpr*) override { return Result::Ok; }
Result OnMemoryCopyExpr(MemoryCopyExpr*) override { return Result::Ok; }
Result OnDataDropExpr(DataDropExpr*) override { return Result::Ok; }
Result OnMemoryFillExpr(MemoryFillExpr*) override { return Result::Ok; }
Result OnMemoryGrowExpr(MemoryGrowExpr*) override { return Result::Ok; }
Result OnMemoryInitExpr(MemoryInitExpr*) override { return Result::Ok; }
Result OnMemorySizeExpr(MemorySizeExpr*) override { return Result::Ok; }
Result OnTableCopyExpr(TableCopyExpr*) override { return Result::Ok; }
Result OnElemDropExpr(ElemDropExpr*) override { return Result::Ok; }
Result OnTableInitExpr(TableInitExpr*) override { return Result::Ok; }
Result OnTableGetExpr(TableGetExpr*) override { return Result::Ok; }
Result OnTableSetExpr(TableSetExpr*) override { return Result::Ok; }
Result OnTableGrowExpr(TableGrowExpr*) override { return Result::Ok; }
Result OnTableSizeExpr(TableSizeExpr*) override { return Result::Ok; }
Result OnTableFillExpr(TableFillExpr*) override { return Result::Ok; }
Result OnRefFuncExpr(RefFuncExpr*) override { return Result::Ok; }
Result OnRefNullExpr(RefNullExpr*) override { return Result::Ok; }
Result OnRefIsNullExpr(RefIsNullExpr*) override { return Result::Ok; }
Result OnNopExpr(NopExpr*) override { return Result::Ok; }
Result OnReturnExpr(ReturnExpr*) override { return Result::Ok; }
Result OnReturnCallExpr(ReturnCallExpr*) override { return Result::Ok; }
Result OnReturnCallIndirectExpr(ReturnCallIndirectExpr*) override {
return Result::Ok;
}
Result OnSelectExpr(SelectExpr*) override { return Result::Ok; }
Result OnStoreExpr(StoreExpr*) override { return Result::Ok; }
Result OnUnaryExpr(UnaryExpr*) override { return Result::Ok; }
Result OnUnreachableExpr(UnreachableExpr*) override { return Result::Ok; }
Result BeginTryExpr(TryExpr*) override { return Result::Ok; }
Result OnCatchExpr(TryExpr*, Catch*) override { return Result::Ok; }
Result OnUnwindExpr(TryExpr*) override { return Result::Ok; }
Result OnDelegateExpr(TryExpr*) override { return Result::Ok; }
Result EndTryExpr(TryExpr*) override { return Result::Ok; }
Result OnThrowExpr(ThrowExpr*) override { return Result::Ok; }
Result OnRethrowExpr(RethrowExpr*) override { return Result::Ok; }
Result OnAtomicWaitExpr(AtomicWaitExpr*) override { return Result::Ok; }
Result OnAtomicFenceExpr(AtomicFenceExpr*) override { return Result::Ok; }
Result OnAtomicNotifyExpr(AtomicNotifyExpr*) override { return Result::Ok; }
Result OnAtomicLoadExpr(AtomicLoadExpr*) override { return Result::Ok; }
Result OnAtomicStoreExpr(AtomicStoreExpr*) override { return Result::Ok; }
Result OnAtomicRmwExpr(AtomicRmwExpr*) override { return Result::Ok; }
Result OnAtomicRmwCmpxchgExpr(AtomicRmwCmpxchgExpr*) override {
return Result::Ok;
}
Result OnTernaryExpr(TernaryExpr*) override { return Result::Ok; }
Result OnSimdLaneOpExpr(SimdLaneOpExpr*) override { return Result::Ok; }
Result OnSimdLoadLaneExpr(SimdLoadLaneExpr*) override { return Result::Ok; }
Result OnSimdStoreLaneExpr(SimdStoreLaneExpr*) override { return Result::Ok; }
Result OnSimdShuffleOpExpr(SimdShuffleOpExpr*) override { return Result::Ok; }
Result OnLoadSplatExpr(LoadSplatExpr*) override { return Result::Ok; }
Result OnLoadZeroExpr(LoadZeroExpr*) override { return Result::Ok; }
};
} // namespace wabt
#endif // WABT_EXPR_VISITOR_H_

50
third_party/wasm2c/src/feature.cc vendored Normal file
View File

@@ -0,0 +1,50 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/feature.h"
#include "src/option-parser.h"
namespace wabt {
void Features::AddOptions(OptionParser* parser) {
#define WABT_FEATURE(variable, flag, default_, help) \
if (default_ == true) { \
parser->AddOption("disable-" flag, "Disable " help, \
[this]() { disable_##variable(); }); \
} else { \
parser->AddOption("enable-" flag, "Enable " help, \
[this]() { enable_##variable(); }); \
}
#include "src/feature.def"
#undef WABT_FEATURE
parser->AddOption("enable-all", "Enable all features",
[this]() { EnableAll(); });
}
void Features::UpdateDependencies() {
// Exception handling requires reference types.
if (exceptions_enabled_) {
reference_types_enabled_ = true;
}
// Reference types requires bulk memory.
if (reference_types_enabled_) {
bulk_memory_enabled_ = true;
}
}
} // namespace wabt

37
third_party/wasm2c/src/feature.def vendored Normal file
View File

@@ -0,0 +1,37 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_FEATURE
#error "You must define WABT_FEATURE before including this file."
#endif
/*
* variable flag default help
* ========================================================================= */
WABT_FEATURE(exceptions, "exceptions", false, "Experimental exception handling")
WABT_FEATURE(mutable_globals, "mutable-globals", true, "Import/export mutable globals")
WABT_FEATURE(sat_float_to_int, "saturating-float-to-int", true, "Saturating float-to-int operators")
WABT_FEATURE(sign_extension, "sign-extension", true, "Sign-extension operators")
WABT_FEATURE(simd, "simd", false, "SIMD support")
WABT_FEATURE(threads, "threads", false, "Threading support")
WABT_FEATURE(multi_value, "multi-value", true, "Multi-value")
WABT_FEATURE(tail_call, "tail-call", false, "Tail-call support")
WABT_FEATURE(bulk_memory, "bulk-memory", false, "Bulk-memory operations")
WABT_FEATURE(reference_types, "reference-types", false, "Reference types (externref)")
WABT_FEATURE(annotations, "annotations", false, "Custom annotation syntax")
WABT_FEATURE(gc, "gc", false, "Garbage collection")
WABT_FEATURE(memory64, "memory64", false, "64-bit memory")

58
third_party/wasm2c/src/feature.h vendored Normal file
View File

@@ -0,0 +1,58 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_FEATURE_H_
#define WABT_FEATURE_H_
#include "src/common.h"
namespace wabt {
class OptionParser;
class Features {
public:
void AddOptions(OptionParser*);
void EnableAll() {
#define WABT_FEATURE(variable, flag, default_, help) enable_##variable();
#include "src/feature.def"
#undef WABT_FEATURE
}
#define WABT_FEATURE(variable, flag, default_, help) \
bool variable##_enabled() const { return variable##_enabled_; } \
void enable_##variable() { set_##variable##_enabled(true); } \
void disable_##variable() { set_##variable##_enabled(false); } \
void set_##variable##_enabled(bool value) { \
variable##_enabled_ = value; \
UpdateDependencies(); \
}
#include "src/feature.def"
#undef WABT_FEATURE
private:
void UpdateDependencies();
#define WABT_FEATURE(variable, flag, default_, help) \
bool variable##_enabled_ = default_;
#include "src/feature.def"
#undef WABT_FEATURE
};
} // namespace wabt
#endif // WABT_FEATURE_H_

56
third_party/wasm2c/src/filenames.cc vendored Normal file
View File

@@ -0,0 +1,56 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/filenames.h"
namespace wabt {
const char* kWasmExtension = ".wasm";
const char* kWatExtension = ".wat";
string_view StripExtension(string_view filename) {
return filename.substr(0, filename.find_last_of('.'));
}
string_view GetBasename(string_view filename) {
size_t last_slash = filename.find_last_of('/');
size_t last_backslash = filename.find_last_of('\\');
if (last_slash == string_view::npos && last_backslash == string_view::npos) {
return filename;
}
if (last_slash == string_view::npos) {
if (last_backslash == string_view::npos) {
return filename;
}
last_slash = last_backslash;
} else if (last_backslash != string_view::npos) {
last_slash = std::max(last_slash, last_backslash);
}
return filename.substr(last_slash + 1);
}
string_view GetExtension(string_view filename) {
size_t pos = filename.find_last_of('.');
if (pos == string_view::npos) {
return "";
}
return filename.substr(pos);
}
} // namespace wabt

51
third_party/wasm2c/src/filenames.h vendored Normal file
View File

@@ -0,0 +1,51 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_FILENAMES_H_
#define WABT_FILENAMES_H_
#include "src/common.h"
namespace wabt {
extern const char* kWasmExtension;
extern const char* kWatExtension;
// Return only the file extension, e.g.:
//
// "foo.txt", => ".txt"
// "foo" => ""
// "/foo/bar/foo.wasm" => ".wasm"
string_view GetExtension(string_view filename);
// Strip extension, e.g.:
//
// "foo", => "foo"
// "foo.bar" => "foo"
// "/path/to/foo.bar" => "/path/to/foo"
// "\\path\\to\\foo.bar" => "\\path\\to\\foo"
string_view StripExtension(string_view s);
// Strip everything up to and including the last slash, e.g.:
//
// "/foo/bar/baz", => "baz"
// "/usr/local/include/stdio.h", => "stdio.h"
// "foo.bar", => "foo.bar"
string_view GetBasename(string_view filename);
} // namespace wabt
#endif /* WABT_FILENAMES_H_ */

431
third_party/wasm2c/src/generate-names.cc vendored Normal file
View File

@@ -0,0 +1,431 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/generate-names.h"
#include <cassert>
#include <cstdio>
#include <string>
#include <vector>
#include "src/cast.h"
#include "src/expr-visitor.h"
#include "src/ir.h"
namespace wabt {
namespace {
class NameGenerator : public ExprVisitor::DelegateNop {
public:
NameGenerator(NameOpts opts);
Result VisitModule(Module* module);
// Implementation of ExprVisitor::DelegateNop.
Result BeginBlockExpr(BlockExpr* expr) override;
Result BeginLoopExpr(LoopExpr* expr) override;
Result BeginIfExpr(IfExpr* expr) override;
private:
static bool HasName(const std::string& str);
// Generate a name with the given prefix, followed by the index and
// optionally a disambiguating number. If index == kInvalidIndex, the index
// is not appended.
void GenerateName(const char* prefix,
Index index,
unsigned disambiguator,
std::string* out_str);
// Like GenerateName, but only generates a name if |out_str| is empty.
void MaybeGenerateName(const char* prefix,
Index index,
std::string* out_str);
// Generate a name via GenerateName and bind it to the given binding hash. If
// the name already exists, the name will be disambiguated until it can be
// added.
void GenerateAndBindName(BindingHash* bindings,
const char* prefix,
Index index,
std::string* out_str);
// Like GenerateAndBindName, but only generates a name if |out_str| is empty.
void MaybeGenerateAndBindName(BindingHash* bindings,
const char* prefix,
Index index,
std::string* out_str);
// Like MaybeGenerateAndBindName but uses the name directly, without
// appending the index. If the name already exists, a disambiguating suffix
// is added.
void MaybeUseAndBindName(BindingHash* bindings,
const char* name,
Index index,
std::string* out_str);
void GenerateAndBindLocalNames(Func* func);
template <typename T>
Result VisitAll(const std::vector<T*>& items,
Result (NameGenerator::*func)(Index, T*));
Result VisitFunc(Index func_index, Func* func);
Result VisitGlobal(Index global_index, Global* global);
Result VisitType(Index func_type_index, TypeEntry* type);
Result VisitTable(Index table_index, Table* table);
Result VisitMemory(Index memory_index, Memory* memory);
Result VisitEvent(Index event_index, Event* event);
Result VisitDataSegment(Index data_segment_index, DataSegment* data_segment);
Result VisitElemSegment(Index elem_segment_index, ElemSegment* elem_segment);
Result VisitImport(Import* import);
Result VisitExport(Export* export_);
Module* module_ = nullptr;
ExprVisitor visitor_;
Index label_count_ = 0;
Index num_func_imports_ = 0;
Index num_table_imports_ = 0;
Index num_memory_imports_ = 0;
Index num_global_imports_ = 0;
Index num_event_imports_ = 0;
NameOpts opts_;
};
NameGenerator::NameGenerator(NameOpts opts)
: visitor_(this), opts_(opts) {}
// static
bool NameGenerator::HasName(const std::string& str) {
return !str.empty();
}
void NameGenerator::GenerateName(const char* prefix,
Index index,
unsigned disambiguator,
std::string* str) {
*str = "$";
*str += prefix;
if (index != kInvalidIndex) {
if (opts_ & NameOpts::AlphaNames) {
// For params and locals, do not use a prefix char.
if (!strcmp(prefix, "p") || !strcmp(prefix, "l")) {
str->pop_back();
} else {
*str += '_';
}
*str += IndexToAlphaName(index);
} else {
*str += std::to_string(index);
}
}
if (disambiguator != 0) {
*str += '_' + std::to_string(disambiguator);
}
}
void NameGenerator::MaybeGenerateName(const char* prefix,
Index index,
std::string* str) {
if (!HasName(*str)) {
// There's no bindings hash, so the name can't be a duplicate. Therefore it
// doesn't need a disambiguating number.
GenerateName(prefix, index, 0, str);
}
}
void NameGenerator::GenerateAndBindName(BindingHash* bindings,
const char* prefix,
Index index,
std::string* str) {
unsigned disambiguator = 0;
while (true) {
GenerateName(prefix, index, disambiguator, str);
if (bindings->find(*str) == bindings->end()) {
bindings->emplace(*str, Binding(index));
break;
}
disambiguator++;
}
}
void NameGenerator::MaybeGenerateAndBindName(BindingHash* bindings,
const char* prefix,
Index index,
std::string* str) {
if (!HasName(*str)) {
GenerateAndBindName(bindings, prefix, index, str);
}
}
void NameGenerator::MaybeUseAndBindName(BindingHash* bindings,
const char* name,
Index index,
std::string* str) {
if (!HasName(*str)) {
unsigned disambiguator = 0;
while (true) {
GenerateName(name, kInvalidIndex, disambiguator, str);
if (bindings->find(*str) == bindings->end()) {
bindings->emplace(*str, Binding(index));
break;
}
disambiguator++;
}
}
}
void NameGenerator::GenerateAndBindLocalNames(Func* func) {
std::vector<std::string> index_to_name;
MakeTypeBindingReverseMapping(func->GetNumParamsAndLocals(), func->bindings,
&index_to_name);
for (size_t i = 0; i < index_to_name.size(); ++i) {
const std::string& old_name = index_to_name[i];
if (!old_name.empty()) {
continue;
}
const char* prefix = i < func->GetNumParams() ? "p" : "l";
std::string new_name;
GenerateAndBindName(&func->bindings, prefix, i, &new_name);
index_to_name[i] = new_name;
}
}
Result NameGenerator::BeginBlockExpr(BlockExpr* expr) {
MaybeGenerateName("B", label_count_++, &expr->block.label);
return Result::Ok;
}
Result NameGenerator::BeginLoopExpr(LoopExpr* expr) {
MaybeGenerateName("L", label_count_++, &expr->block.label);
return Result::Ok;
}
Result NameGenerator::BeginIfExpr(IfExpr* expr) {
MaybeGenerateName("I", label_count_++, &expr->true_.label);
return Result::Ok;
}
Result NameGenerator::VisitFunc(Index func_index, Func* func) {
MaybeGenerateAndBindName(&module_->func_bindings, "f", func_index,
&func->name);
GenerateAndBindLocalNames(func);
label_count_ = 0;
CHECK_RESULT(visitor_.VisitFunc(func));
return Result::Ok;
}
Result NameGenerator::VisitGlobal(Index global_index, Global* global) {
MaybeGenerateAndBindName(&module_->global_bindings, "g", global_index,
&global->name);
return Result::Ok;
}
Result NameGenerator::VisitType(Index type_index, TypeEntry* type) {
MaybeGenerateAndBindName(&module_->type_bindings, "t", type_index,
&type->name);
return Result::Ok;
}
Result NameGenerator::VisitTable(Index table_index, Table* table) {
MaybeGenerateAndBindName(&module_->table_bindings, "T", table_index,
&table->name);
return Result::Ok;
}
Result NameGenerator::VisitMemory(Index memory_index, Memory* memory) {
MaybeGenerateAndBindName(&module_->memory_bindings, "M", memory_index,
&memory->name);
return Result::Ok;
}
Result NameGenerator::VisitEvent(Index event_index, Event* event) {
MaybeGenerateAndBindName(&module_->event_bindings, "e", event_index,
&event->name);
return Result::Ok;
}
Result NameGenerator::VisitDataSegment(Index data_segment_index,
DataSegment* data_segment) {
MaybeGenerateAndBindName(&module_->data_segment_bindings, "d",
data_segment_index, &data_segment->name);
return Result::Ok;
}
Result NameGenerator::VisitElemSegment(Index elem_segment_index,
ElemSegment* elem_segment) {
MaybeGenerateAndBindName(&module_->elem_segment_bindings, "e",
elem_segment_index, &elem_segment->name);
return Result::Ok;
}
Result NameGenerator::VisitImport(Import* import) {
BindingHash* bindings = nullptr;
std::string* name = nullptr;
Index index = kInvalidIndex;
switch (import->kind()) {
case ExternalKind::Func:
if (auto* func_import = cast<FuncImport>(import)) {
bindings = &module_->func_bindings;
name = &func_import->func.name;
index = num_func_imports_++;
}
break;
case ExternalKind::Table:
if (auto* table_import = cast<TableImport>(import)) {
bindings = &module_->table_bindings;
name = &table_import->table.name;
index = num_table_imports_++;
}
break;
case ExternalKind::Memory:
if (auto* memory_import = cast<MemoryImport>(import)) {
bindings = &module_->memory_bindings;
name = &memory_import->memory.name;
index = num_memory_imports_++;
}
break;
case ExternalKind::Global:
if (auto* global_import = cast<GlobalImport>(import)) {
bindings = &module_->global_bindings;
name = &global_import->global.name;
index = num_global_imports_++;
}
break;
case ExternalKind::Event:
if (auto* event_import = cast<EventImport>(import)) {
bindings = &module_->event_bindings;
name = &event_import->event.name;
index = num_event_imports_++;
}
break;
}
if (bindings && name) {
assert(index != kInvalidIndex);
std::string new_name = import->module_name + '.' + import->field_name;
MaybeUseAndBindName(bindings, new_name.c_str(), index, name);
}
return Result::Ok;
}
Result NameGenerator::VisitExport(Export* export_) {
BindingHash* bindings = nullptr;
std::string* name = nullptr;
Index index = kInvalidIndex;
switch (export_->kind) {
case ExternalKind::Func:
if (Func* func = module_->GetFunc(export_->var)) {
index = module_->GetFuncIndex(export_->var);
bindings = &module_->func_bindings;
name = &func->name;
}
break;
case ExternalKind::Table:
if (Table* table = module_->GetTable(export_->var)) {
index = module_->GetTableIndex(export_->var);
bindings = &module_->table_bindings;
name = &table->name;
}
break;
case ExternalKind::Memory:
if (Memory* memory = module_->GetMemory(export_->var)) {
index = module_->GetMemoryIndex(export_->var);
bindings = &module_->memory_bindings;
name = &memory->name;
}
break;
case ExternalKind::Global:
if (Global* global = module_->GetGlobal(export_->var)) {
index = module_->GetGlobalIndex(export_->var);
bindings = &module_->global_bindings;
name = &global->name;
}
break;
case ExternalKind::Event:
if (Event* event = module_->GetEvent(export_->var)) {
index = module_->GetEventIndex(export_->var);
bindings = &module_->event_bindings;
name = &event->name;
}
break;
}
if (bindings && name) {
MaybeUseAndBindName(bindings, export_->name.c_str(), index, name);
}
return Result::Ok;
}
template <typename T>
Result NameGenerator::VisitAll(const std::vector<T*>& items,
Result (NameGenerator::*func)(Index, T*)) {
for (Index i = 0; i < items.size(); ++i) {
CHECK_RESULT((this->*func)(i, items[i]));
}
return Result::Ok;
}
Result NameGenerator::VisitModule(Module* module) {
module_ = module;
// Visit imports and exports first to give better names, derived from the
// import/export name.
for (auto* import : module->imports) {
CHECK_RESULT(VisitImport(import));
}
for (auto* export_ : module->exports) {
CHECK_RESULT(VisitExport(export_));
}
VisitAll(module->globals, &NameGenerator::VisitGlobal);
VisitAll(module->types, &NameGenerator::VisitType);
VisitAll(module->funcs, &NameGenerator::VisitFunc);
VisitAll(module->tables, &NameGenerator::VisitTable);
VisitAll(module->memories, &NameGenerator::VisitMemory);
VisitAll(module->events, &NameGenerator::VisitEvent);
VisitAll(module->data_segments, &NameGenerator::VisitDataSegment);
VisitAll(module->elem_segments, &NameGenerator::VisitElemSegment);
module_ = nullptr;
return Result::Ok;
}
} // end anonymous namespace
Result GenerateNames(Module* module, NameOpts opts) {
NameGenerator generator(opts);
return generator.VisitModule(module);
}
} // namespace wabt

46
third_party/wasm2c/src/generate-names.h vendored Normal file
View File

@@ -0,0 +1,46 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_GENERATE_NAMES_H_
#define WABT_GENERATE_NAMES_H_
#include "src/common.h"
namespace wabt {
struct Module;
enum NameOpts {
None = 0,
AlphaNames = 1 << 0,
};
Result GenerateNames(struct Module*, NameOpts opts = NameOpts::None);
inline std::string IndexToAlphaName(Index index) {
std::string s;
do {
// For multiple chars, put most frequently changing char first.
s += 'a' + (index % 26);
index /= 26;
// Continue remaining sequence with 'a' rather than 'b'.
} while (index--);
return s;
}
} // namespace wabt
#endif /* WABT_GENERATE_NAMES_H_ */

38
third_party/wasm2c/src/hash-util.cc vendored Normal file
View File

@@ -0,0 +1,38 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/hash-util.h"
#include "config.h"
namespace wabt {
// Hash combiner from:
// http://stackoverflow.com/questions/4948780/magic-number-in-boosthash-combine
hash_code HashCombine(hash_code seed, hash_code y) {
#if SIZEOF_SIZE_T == 4
constexpr hash_code magic = 0x9e3779b9;
#elif SIZEOF_SIZE_T == 8
constexpr hash_code magic = 0x9e3779b97f4a7c16;
#else
#error "weird sizeof size_t"
#endif
seed ^= y + magic + (seed << 6) + (seed >> 2);
return seed;
}
} // namespace wabt

51
third_party/wasm2c/src/hash-util.h vendored Normal file
View File

@@ -0,0 +1,51 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_HASH_UTIL_H_
#define WABT_HASH_UTIL_H_
#include <cstdlib>
#include <functional>
namespace wabt {
typedef std::size_t hash_code;
inline hash_code HashCombine() {
return 0;
}
inline hash_code HashCombine(hash_code seed) {
return seed;
}
hash_code HashCombine(hash_code x, hash_code y);
template <typename T, typename... U>
inline hash_code HashCombine(const T& first, const U&... rest) {
return HashCombine(HashCombine(rest...), std::hash<T>()(first));
}
template <typename It>
inline hash_code HashRange(It first, It last) {
hash_code result = 0;
for (auto iter = first; iter != last; ++iter) {
result = HashCombine(result, *iter);
}
return result;
}
} // namespace wabt
#endif // WABT_HASH_UTIL_H_

633
third_party/wasm2c/src/intrusive-list.h vendored Normal file
View File

@@ -0,0 +1,633 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_INTRUSIVE_LIST_H_
#define WABT_INTRUSIVE_LIST_H_
#include <cassert>
#include <iterator>
#include <memory>
#include "src/make-unique.h"
// This uses a similar interface as std::list, but is missing the following
// features:
//
// * Add "extract_" functions that remove an element from the list and return
// it.
// * Only supports move-only operations
// * No allocator support
// * No initializer lists
// * Asserts instead of exceptions
// * Some functions are not implemented (merge, remove, remove_if, reverse,
// unique, sort, non-member comparison operators)
namespace wabt {
template <typename T>
class intrusive_list;
template <typename T>
class intrusive_list_base {
private:
friend class intrusive_list<T>;
mutable T* next_ = nullptr;
mutable T* prev_ = nullptr;
};
template <typename T>
class intrusive_list {
public:
// types:
typedef T value_type;
typedef value_type& reference;
typedef const value_type& const_reference;
class iterator;
class const_iterator;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
// construct/copy/destroy:
intrusive_list();
explicit intrusive_list(std::unique_ptr<T> node);
explicit intrusive_list(T&& node);
intrusive_list(const intrusive_list&) = delete;
intrusive_list(intrusive_list&&);
~intrusive_list();
intrusive_list& operator=(const intrusive_list& other) = delete;
intrusive_list& operator=(intrusive_list&& other);
// iterators:
iterator begin() noexcept;
const_iterator begin() const noexcept;
iterator end() noexcept;
const_iterator end() const noexcept;
reverse_iterator rbegin() noexcept;
const_reverse_iterator rbegin() const noexcept;
reverse_iterator rend() noexcept;
const_reverse_iterator rend() const noexcept;
const_iterator cbegin() const noexcept;
const_iterator cend() const noexcept;
const_reverse_iterator crbegin() const noexcept;
const_reverse_iterator crend() const noexcept;
// capacity:
size_type size() const noexcept;
bool empty() const noexcept;
// element access:
reference front();
const_reference front() const;
reference back();
const_reference back() const;
// modifiers:
template <class... Args>
void emplace_front(Args&&... args);
template <class... Args>
void emplace_back(Args&&... args);
void push_front(std::unique_ptr<T> node);
void push_front(T&& node);
void push_back(std::unique_ptr<T> node);
void push_back(T&& node);
void pop_front();
void pop_back();
std::unique_ptr<T> extract_front();
std::unique_ptr<T> extract_back();
template <class... Args>
iterator emplace(iterator pos, Args&&... args);
iterator insert(iterator pos, std::unique_ptr<T> node);
iterator insert(iterator pos, T&& node);
std::unique_ptr<T> extract(iterator it);
iterator erase(iterator pos);
iterator erase(iterator first, iterator last);
void swap(intrusive_list&);
void clear() noexcept;
void splice(iterator pos, intrusive_list& node);
void splice(iterator pos, intrusive_list&& node);
void splice(iterator pos, intrusive_list& node, iterator it);
void splice(iterator pos,
intrusive_list& node,
iterator first,
iterator last);
private:
T* first_ = nullptr;
T* last_ = nullptr;
size_t size_ = 0;
};
/// iterator
template <typename T>
class intrusive_list<T>::iterator {
public:
typedef std::ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
typedef T value_type;
typedef T* pointer;
typedef T& reference;
iterator(const intrusive_list<T>& list, T* node)
: list_(&list), node_(node) {}
reference operator*() const {
assert(node_);
return *node_;
}
pointer operator->() const {
assert(node_);
return node_;
}
iterator& operator++() {
assert(node_);
node_ = node_->next_;
return *this;
}
iterator operator++(int) {
iterator tmp = *this;
operator++();
return tmp;
}
iterator& operator--() {
node_ = node_ ? node_->prev_ : list_->last_;
return *this;
}
iterator operator--(int) {
iterator tmp = *this;
operator--();
return tmp;
}
bool operator==(iterator rhs) const {
assert(list_ == rhs.list_);
return node_ == rhs.node_;
}
bool operator!=(iterator rhs) const {
assert(list_ == rhs.list_);
return node_ != rhs.node_;
}
private:
friend class const_iterator;
const intrusive_list<T>* list_;
T* node_;
};
/// const_iterator
template <typename T>
class intrusive_list<T>::const_iterator {
public:
typedef std::ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
typedef T value_type;
typedef const T* pointer;
typedef const T& reference;
const_iterator(const intrusive_list<T>& list, T* node)
: list_(&list), node_(node) {}
const_iterator(const iterator& other)
: list_(other.list_), node_(other.node_) {}
reference operator*() const {
assert(node_);
return *node_;
}
pointer operator->() const {
assert(node_);
return node_;
}
const_iterator& operator++() {
assert(node_);
node_ = node_->next_;
return *this;
}
const_iterator operator++(int) {
const_iterator tmp = *this;
operator++();
return tmp;
}
const_iterator& operator--() {
node_ = node_ ? node_->prev_ : list_->last_;
return *this;
}
const_iterator operator--(int) {
const_iterator tmp = *this;
operator--();
return tmp;
}
bool operator==(const_iterator rhs) const {
assert(list_ == rhs.list_);
return node_ == rhs.node_;
}
bool operator!=(const_iterator rhs) const {
assert(list_ == rhs.list_);
return node_ != rhs.node_;
}
private:
const intrusive_list<T>* list_;
T* node_;
};
template <typename T>
inline intrusive_list<T>::intrusive_list() {}
template <typename T>
inline intrusive_list<T>::intrusive_list(std::unique_ptr<T> node) {
push_back(std::move(node));
}
template <typename T>
inline intrusive_list<T>::intrusive_list(T&& node) {
push_back(std::move(node));
}
template <typename T>
inline intrusive_list<T>::intrusive_list(intrusive_list&& other)
: first_(other.first_), last_(other.last_), size_(other.size_) {
other.first_ = other.last_ = nullptr;
other.size_ = 0;
}
template <typename T>
inline intrusive_list<T>::~intrusive_list() {
clear();
}
template <typename T>
inline intrusive_list<T>& intrusive_list<T>::operator=(
intrusive_list<T>&& other) {
clear();
first_ = other.first_;
last_ = other.last_;
size_ = other.size_;
other.first_ = other.last_ = nullptr;
other.size_ = 0;
return *this;
}
template <typename T>
inline typename intrusive_list<T>::iterator
intrusive_list<T>::begin() noexcept {
return iterator(*this, first_);
}
template <typename T>
inline typename intrusive_list<T>::const_iterator intrusive_list<T>::begin()
const noexcept {
return const_iterator(*this, first_);
}
template <typename T>
inline typename intrusive_list<T>::iterator intrusive_list<T>::end() noexcept {
return iterator(*this, nullptr);
}
template <typename T>
inline typename intrusive_list<T>::const_iterator intrusive_list<T>::end() const
noexcept {
return const_iterator(*this, nullptr);
}
template <typename T>
inline typename intrusive_list<T>::reverse_iterator
intrusive_list<T>::rbegin() noexcept {
return reverse_iterator(iterator(*this, nullptr));
}
template <typename T>
inline typename intrusive_list<T>::const_reverse_iterator
intrusive_list<T>::rbegin() const noexcept {
return const_reverse_iterator(const_iterator(*this, nullptr));
}
template <typename T>
inline typename intrusive_list<T>::reverse_iterator
intrusive_list<T>::rend() noexcept {
return reverse_iterator(iterator(*this, first_));
}
template <typename T>
inline typename intrusive_list<T>::const_reverse_iterator
intrusive_list<T>::rend() const noexcept {
return const_reverse_iterator(const_iterator(*this, first_));
}
template <typename T>
inline typename intrusive_list<T>::const_iterator intrusive_list<T>::cbegin()
const noexcept {
return const_iterator(*this, first_);
}
template <typename T>
inline typename intrusive_list<T>::const_iterator intrusive_list<T>::cend()
const noexcept {
return const_iterator(*this, nullptr);
}
template <typename T>
inline typename intrusive_list<T>::const_reverse_iterator
intrusive_list<T>::crbegin() const noexcept {
return const_reverse_iterator(const_iterator(*this, nullptr));
}
template <typename T>
inline typename intrusive_list<T>::const_reverse_iterator
intrusive_list<T>::crend() const noexcept {
return const_reverse_iterator(const_iterator(*this, first_));
}
template <typename T>
inline typename intrusive_list<T>::size_type intrusive_list<T>::size() const
noexcept {
return size_;
}
template <typename T>
inline bool intrusive_list<T>::empty() const noexcept {
return size_ == 0;
}
template <typename T>
inline typename intrusive_list<T>::reference intrusive_list<T>::front() {
assert(!empty());
return *first_;
}
template <typename T>
inline typename intrusive_list<T>::const_reference intrusive_list<T>::front()
const {
assert(!empty());
return *first_;
}
template <typename T>
inline typename intrusive_list<T>::reference intrusive_list<T>::back() {
assert(!empty());
return *last_;
}
template <typename T>
inline typename intrusive_list<T>::const_reference intrusive_list<T>::back()
const {
assert(!empty());
return *last_;
}
template <typename T>
template <class... Args>
inline void intrusive_list<T>::emplace_front(Args&&... args) {
push_front(MakeUnique<T>(std::forward<Args>(args)...));
}
template <typename T>
template <class... Args>
inline void intrusive_list<T>::emplace_back(Args&&... args) {
push_back(MakeUnique<T>(std::forward<Args>(args)...));
}
template <typename T>
inline void intrusive_list<T>::push_front(std::unique_ptr<T> node) {
assert(node->prev_ == nullptr && node->next_ == nullptr);
T* node_p = node.release();
if (first_) {
node_p->next_ = first_;
first_->prev_ = node_p;
} else {
last_ = node_p;
}
first_ = node_p;
size_++;
}
template <typename T>
inline void intrusive_list<T>::push_front(T&& node) {
push_front(MakeUnique<T>(std::move(node)));
}
template <typename T>
inline void intrusive_list<T>::push_back(std::unique_ptr<T> node) {
assert(node->prev_ == nullptr && node->next_ == nullptr);
T* node_p = node.release();
if (last_) {
node_p->prev_ = last_;
last_->next_ = node_p;
} else {
first_ = node_p;
}
last_ = node_p;
size_++;
}
template <typename T>
inline void intrusive_list<T>::push_back(T&& node) {
push_back(MakeUnique<T>(std::move(node)));
}
template <typename T>
inline void intrusive_list<T>::pop_front() {
extract_front();
}
template <typename T>
inline void intrusive_list<T>::pop_back() {
extract_back();
}
template <typename T>
inline std::unique_ptr<T> intrusive_list<T>::extract_front() {
assert(!empty());
T* node = first_;
if (first_ == last_) {
first_ = last_ = nullptr;
} else {
first_ = first_->next_;
first_->prev_ = nullptr;
}
node->next_ = node->prev_ = nullptr;
size_--;
return std::unique_ptr<T>(node);
}
template <typename T>
inline std::unique_ptr<T> intrusive_list<T>::extract_back() {
assert(!empty());
T* node = last_;
if (first_ == last_) {
first_ = last_ = nullptr;
} else {
last_ = last_->prev_;
last_->next_ = nullptr;
}
node->next_ = node->prev_ = nullptr;
size_--;
return std::unique_ptr<T>(node);
}
template <typename T>
template <class... Args>
inline typename intrusive_list<T>::iterator intrusive_list<T>::emplace(
iterator pos,
Args&&... args) {
return insert(pos, MakeUnique<T>(std::forward<Args>(args)...));
}
template <typename T>
inline typename intrusive_list<T>::iterator intrusive_list<T>::insert(
iterator pos,
std::unique_ptr<T> node) {
assert(node->prev_ == nullptr && node->next_ == nullptr);
T* node_p;
if (pos == end()) {
push_back(std::move(node));
node_p = &back();
} else {
node_p = node.release();
node_p->prev_ = pos->prev_;
node_p->next_ = &*pos;
if (pos->prev_) {
pos->prev_->next_ = node_p;
} else {
first_ = node_p;
}
pos->prev_ = node_p;
size_++;
}
return iterator(*this, node_p);
}
template <typename T>
inline typename intrusive_list<T>::iterator intrusive_list<T>::insert(
iterator pos,
T&& node) {
return insert(pos, MakeUnique<T>(std::move(node)));
}
template <typename T>
inline std::unique_ptr<T> intrusive_list<T>::extract(iterator pos) {
assert(!empty());
assert(pos != end());
T* node = &*pos;
if (first_ == last_) {
first_ = last_ = nullptr;
} else {
if (node->prev_) {
node->prev_->next_ = node->next_;
} else {
first_ = node->next_;
}
if (node->next_) {
node->next_->prev_ = node->prev_;
} else {
last_ = node->prev_;
}
}
node->next_ = node->prev_ = nullptr;
size_--;
return std::unique_ptr<T>(node);
}
template <typename T>
inline typename intrusive_list<T>::iterator intrusive_list<T>::erase(
iterator pos) {
iterator next = std::next(pos);
extract(pos);
return next;
}
template <typename T>
inline typename intrusive_list<T>::iterator intrusive_list<T>::erase(
iterator first,
iterator last) {
while (first != last)
first = erase(first);
return first;
}
template <typename T>
inline void intrusive_list<T>::swap(intrusive_list& other) {
std::swap(first_, other.first_);
std::swap(last_, other.last_);
std::swap(size_, other.size_);
}
template <typename T>
inline void intrusive_list<T>::clear() noexcept {
for (T* iter = first_; iter;) {
T* next = iter->next_;
delete iter;
iter = next;
}
first_ = last_ = nullptr;
size_ = 0;
}
template <typename T>
inline void intrusive_list<T>::splice(iterator pos, intrusive_list& other) {
splice(pos, other, other.begin(), other.end());
}
template <typename T>
inline void intrusive_list<T>::splice(iterator pos, intrusive_list&& other) {
splice(pos, other, other.begin(), other.end());
}
template <typename T>
inline void intrusive_list<T>::splice(iterator pos,
intrusive_list& other,
iterator it) {
insert(pos, other.extract(it));
}
template <typename T>
inline void intrusive_list<T>::splice(iterator pos,
intrusive_list& other,
iterator first,
iterator last) {
while (first != last)
insert(pos, other.extract(first++));
}
} // namespace wabt
#endif // WABT_INTRUSIVE_LIST_H_

267
third_party/wasm2c/src/ir-util.cc vendored Normal file
View File

@@ -0,0 +1,267 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/ir-util.h"
#include <algorithm>
#include <array>
#include <cassert>
#include <cinttypes>
#include <cstdarg>
#include <cstdio>
#include <iterator>
#include <map>
#include <string>
#include <vector>
#include "src/cast.h"
#include "src/common.h"
#include "src/expr-visitor.h"
#include "src/ir.h"
#include "src/ir-util.h"
#include "src/literal.h"
#include "src/stream.h"
#define WABT_TRACING 0
#include "src/tracing.h"
using namespace wabt;
const Label* ModuleContext::GetLabel(const Var& var) const {
if (var.is_name()) {
for (Index i = GetLabelStackSize(); i > 0; --i) {
auto label = &label_stack_[i - 1];
if (label->name == var.name()) {
return label;
}
}
} else if (var.index() < GetLabelStackSize()) {
auto label = &label_stack_[GetLabelStackSize() - var.index() - 1];
return label;
}
return nullptr;
}
Index ModuleContext::GetLabelArity(const Var& var) const {
auto label = GetLabel(var);
if (!label) {
return 0;
}
return label->label_type == LabelType::Loop ? label->param_types.size()
: label->result_types.size();
}
Index ModuleContext::GetFuncParamCount(const Var& var) const {
const Func* func = module.GetFunc(var);
return func ? func->GetNumParams() : 0;
}
Index ModuleContext::GetFuncResultCount(const Var& var) const {
const Func* func = module.GetFunc(var);
return func ? func->GetNumResults() : 0;
}
void ModuleContext::BeginBlock(LabelType label_type, const Block& block) {
label_stack_.emplace_back(label_type, block.label, block.decl.sig.param_types,
block.decl.sig.result_types);
}
void ModuleContext::EndBlock() {
label_stack_.pop_back();
}
void ModuleContext::BeginFunc(const Func& func) {
label_stack_.clear();
label_stack_.emplace_back(LabelType::Func, std::string(), TypeVector(),
func.decl.sig.result_types);
current_func_ = &func;
}
void ModuleContext::EndFunc() {
current_func_ = nullptr;
}
ModuleContext::Arities ModuleContext::GetExprArity(const Expr& expr) const {
switch (expr.type()) {
case ExprType::AtomicNotify:
case ExprType::AtomicRmw:
case ExprType::Binary:
case ExprType::Compare:
case ExprType::TableGrow:
return { 2, 1 };
case ExprType::AtomicStore:
case ExprType::Store:
case ExprType::TableSet:
return { 2, 0 };
case ExprType::Block:
return { 0, cast<BlockExpr>(&expr)->block.decl.sig.GetNumResults() };
case ExprType::Br:
return { GetLabelArity(cast<BrExpr>(&expr)->var), 1, true };
case ExprType::BrIf: {
Index arity = GetLabelArity(cast<BrIfExpr>(&expr)->var);
return { arity + 1, arity };
}
case ExprType::BrTable:
return { GetLabelArity(cast<BrTableExpr>(&expr)->default_target) + 1, 1,
true };
case ExprType::Call: {
const Var& var = cast<CallExpr>(&expr)->var;
return { GetFuncParamCount(var), GetFuncResultCount(var) };
}
case ExprType::ReturnCall: {
const Var& var = cast<ReturnCallExpr>(&expr)->var;
return { GetFuncParamCount(var), GetFuncResultCount(var), true };
}
case ExprType::CallIndirect: {
const auto* ci_expr = cast<CallIndirectExpr>(&expr);
return { ci_expr->decl.GetNumParams() + 1,
ci_expr->decl.GetNumResults() };
}
case ExprType::ReturnCallIndirect: {
const auto* rci_expr = cast<ReturnCallIndirectExpr>(&expr);
return { rci_expr->decl.GetNumParams() + 1,
rci_expr->decl.GetNumResults(), true };
}
case ExprType::Const:
case ExprType::GlobalGet:
case ExprType::LocalGet:
case ExprType::MemorySize:
case ExprType::TableSize:
case ExprType::RefNull:
case ExprType::RefFunc:
return { 0, 1 };
case ExprType::Unreachable:
return { 0, 1, true };
case ExprType::DataDrop:
case ExprType::ElemDrop:
case ExprType::AtomicFence:
return { 0, 0 };
case ExprType::MemoryInit:
case ExprType::TableInit:
case ExprType::MemoryFill:
case ExprType::MemoryCopy:
case ExprType::TableCopy:
case ExprType::TableFill:
return { 3, 0 };
case ExprType::AtomicLoad:
case ExprType::Convert:
case ExprType::Load:
case ExprType::LocalTee:
case ExprType::MemoryGrow:
case ExprType::Unary:
case ExprType::TableGet:
case ExprType::RefIsNull:
case ExprType::LoadSplat:
case ExprType::LoadZero:
return { 1, 1 };
case ExprType::Drop:
case ExprType::GlobalSet:
case ExprType::LocalSet:
return { 1, 0 };
case ExprType::If:
return { 1, cast<IfExpr>(&expr)->true_.decl.sig.GetNumResults() };
case ExprType::Loop:
return { 0, cast<LoopExpr>(&expr)->block.decl.sig.GetNumResults() };
case ExprType::Nop:
return { 0, 0 };
case ExprType::Return:
return
{ static_cast<Index>(current_func_->decl.sig.result_types.size()), 1,
true };
case ExprType::Rethrow:
return { 0, 0, true };
case ExprType::AtomicRmwCmpxchg:
case ExprType::AtomicWait:
case ExprType::Select:
return { 3, 1 };
case ExprType::Throw: {
auto throw_ = cast<ThrowExpr>(&expr);
Index operand_count = 0;
if (Event* event = module.GetEvent(throw_->var)) {
operand_count = event->decl.sig.param_types.size();
}
return { operand_count, 0, true };
}
case ExprType::Try:
return { 0, cast<TryExpr>(&expr)->block.decl.sig.GetNumResults() };
case ExprType::Ternary:
return { 3, 1 };
case ExprType::SimdLaneOp: {
const Opcode opcode = cast<SimdLaneOpExpr>(&expr)->opcode;
switch (opcode) {
case Opcode::I8X16ExtractLaneS:
case Opcode::I8X16ExtractLaneU:
case Opcode::I16X8ExtractLaneS:
case Opcode::I16X8ExtractLaneU:
case Opcode::I32X4ExtractLane:
case Opcode::I64X2ExtractLane:
case Opcode::F32X4ExtractLane:
case Opcode::F64X2ExtractLane:
return { 1, 1 };
case Opcode::I8X16ReplaceLane:
case Opcode::I16X8ReplaceLane:
case Opcode::I32X4ReplaceLane:
case Opcode::I64X2ReplaceLane:
case Opcode::F32X4ReplaceLane:
case Opcode::F64X2ReplaceLane:
return { 2, 1 };
default:
fprintf(stderr, "Invalid Opcode for expr type: %s\n",
GetExprTypeName(expr));
assert(0);
return { 0, 0 };
}
}
case ExprType::SimdLoadLane:
case ExprType::SimdStoreLane: {
return { 2, 1 };
}
case ExprType::SimdShuffleOp:
return { 2, 1 };
}
WABT_UNREACHABLE;
}

76
third_party/wasm2c/src/ir-util.h vendored Normal file
View File

@@ -0,0 +1,76 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_IR_UTIL_H_
#define WABT_IR_UTIL_H_
#include "src/common.h"
#include "src/ir.h"
namespace wabt {
struct Label {
Label(LabelType label_type,
const std::string& name,
const TypeVector& param_types,
const TypeVector& result_types)
: name(name),
label_type(label_type),
param_types(param_types),
result_types(result_types) {}
std::string name;
LabelType label_type;
TypeVector param_types;
TypeVector result_types;
};
struct ModuleContext {
ModuleContext(const Module &module) : module(module) {}
Index GetLabelStackSize() const { return label_stack_.size(); }
const Label* GetLabel(const Var& var) const;
Index GetLabelArity(const Var& var) const;
void SetTopLabelType(LabelType label_type) {
label_stack_.back().label_type = label_type;
}
Index GetFuncParamCount(const Var& var) const;
Index GetFuncResultCount(const Var& var) const;
void BeginBlock(LabelType label_type, const Block& block);
void EndBlock();
void BeginFunc(const Func& func);
void EndFunc();
struct Arities {
Index nargs;
Index nreturns;
bool unreachable;
Arities(Index na, Index nr, bool ur = false)
: nargs(na), nreturns(nr), unreachable(ur) {}
};
Arities GetExprArity(const Expr& expr) const;
const Module &module;
private:
const Func* current_func_ = nullptr;
std::vector<Label> label_stack_;
};
} // namespace wabt
#endif /* WABT_IR_UTIL_H_ */

694
third_party/wasm2c/src/ir.cc vendored Normal file
View File

@@ -0,0 +1,694 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/ir.h"
#include <cassert>
#include <cstddef>
#include <numeric>
#include "src/cast.h"
namespace {
const char* ExprTypeName[] = {
"AtomicFence",
"AtomicLoad",
"AtomicRmw",
"AtomicRmwCmpxchg",
"AtomicStore",
"AtomicNotify",
"AtomicWait",
"Binary",
"Block",
"Br",
"BrIf",
"BrTable",
"Call",
"CallIndirect",
"Compare",
"Const",
"Convert",
"Drop",
"GlobalGet",
"GlobalSet",
"If",
"Load",
"LocalGet",
"LocalSet",
"LocalTee",
"Loop",
"MemoryCopy",
"DataDrop",
"MemoryFill",
"MemoryGrow",
"MemoryInit",
"MemorySize",
"Nop",
"RefIsNull",
"RefFunc",
"RefNull",
"Rethrow",
"Return",
"ReturnCall",
"ReturnCallIndirect",
"Select",
"SimdLaneOp",
"SimdLoadLane",
"SimdStoreLane",
"SimdShuffleOp",
"LoadSplat",
"LoadZero",
"Store",
"TableCopy",
"ElemDrop",
"TableInit",
"TableGet",
"TableGrow",
"TableSize",
"TableSet",
"TableFill",
"Ternary",
"Throw",
"Try",
"Unary",
"Unreachable",
};
} // end of anonymous namespace
namespace wabt {
const char* GetExprTypeName(ExprType type) {
static_assert(WABT_ENUM_COUNT(ExprType) == WABT_ARRAY_SIZE(ExprTypeName),
"Malformed ExprTypeName array");
return ExprTypeName[size_t(type)];
}
const char* GetExprTypeName(const Expr& expr) {
return GetExprTypeName(expr.type());
}
bool FuncSignature::operator==(const FuncSignature& rhs) const {
return param_types == rhs.param_types && result_types == rhs.result_types;
}
const Export* Module::GetExport(string_view name) const {
Index index = export_bindings.FindIndex(name);
if (index >= exports.size()) {
return nullptr;
}
return exports[index];
}
Index Module::GetFuncIndex(const Var& var) const {
return func_bindings.FindIndex(var);
}
Index Module::GetGlobalIndex(const Var& var) const {
return global_bindings.FindIndex(var);
}
Index Module::GetTableIndex(const Var& var) const {
return table_bindings.FindIndex(var);
}
Index Module::GetMemoryIndex(const Var& var) const {
return memory_bindings.FindIndex(var);
}
Index Module::GetFuncTypeIndex(const Var& var) const {
return type_bindings.FindIndex(var);
}
Index Module::GetEventIndex(const Var& var) const {
return event_bindings.FindIndex(var);
}
Index Module::GetDataSegmentIndex(const Var& var) const {
return data_segment_bindings.FindIndex(var);
}
Index Module::GetElemSegmentIndex(const Var& var) const {
return elem_segment_bindings.FindIndex(var);
}
bool Module::IsImport(ExternalKind kind, const Var& var) const {
switch (kind) {
case ExternalKind::Func:
return GetFuncIndex(var) < num_func_imports;
case ExternalKind::Global:
return GetGlobalIndex(var) < num_global_imports;
case ExternalKind::Memory:
return GetMemoryIndex(var) < num_memory_imports;
case ExternalKind::Table:
return GetTableIndex(var) < num_table_imports;
case ExternalKind::Event:
return GetEventIndex(var) < num_event_imports;
default:
return false;
}
}
void LocalTypes::Set(const TypeVector& types) {
decls_.clear();
if (types.empty()) {
return;
}
Type type = types[0];
Index count = 1;
for (Index i = 1; i < types.size(); ++i) {
if (types[i] != type) {
decls_.emplace_back(type, count);
type = types[i];
count = 1;
} else {
++count;
}
}
decls_.emplace_back(type, count);
}
Index LocalTypes::size() const {
return std::accumulate(
decls_.begin(), decls_.end(), 0,
[](Index sum, const Decl& decl) { return sum + decl.second; });
}
Type LocalTypes::operator[](Index i) const {
Index count = 0;
for (auto decl: decls_) {
if (i < count + decl.second) {
return decl.first;
}
count += decl.second;
}
assert(i < count);
return Type::Any;
}
Type Func::GetLocalType(Index index) const {
Index num_params = decl.GetNumParams();
if (index < num_params) {
return GetParamType(index);
} else {
index -= num_params;
assert(index < local_types.size());
return local_types[index];
}
}
Type Func::GetLocalType(const Var& var) const {
return GetLocalType(GetLocalIndex(var));
}
Index Func::GetLocalIndex(const Var& var) const {
if (var.is_index()) {
return var.index();
}
return bindings.FindIndex(var);
}
const Func* Module::GetFunc(const Var& var) const {
return const_cast<Module*>(this)->GetFunc(var);
}
Func* Module::GetFunc(const Var& var) {
Index index = func_bindings.FindIndex(var);
if (index >= funcs.size()) {
return nullptr;
}
return funcs[index];
}
const Global* Module::GetGlobal(const Var& var) const {
return const_cast<Module*>(this)->GetGlobal(var);
}
Global* Module::GetGlobal(const Var& var) {
Index index = global_bindings.FindIndex(var);
if (index >= globals.size()) {
return nullptr;
}
return globals[index];
}
const Table* Module::GetTable(const Var& var) const {
return const_cast<Module*>(this)->GetTable(var);
}
Table* Module::GetTable(const Var& var) {
Index index = table_bindings.FindIndex(var);
if (index >= tables.size()) {
return nullptr;
}
return tables[index];
}
const Memory* Module::GetMemory(const Var& var) const {
return const_cast<Module*>(this)->GetMemory(var);
}
Memory* Module::GetMemory(const Var& var) {
Index index = memory_bindings.FindIndex(var);
if (index >= memories.size()) {
return nullptr;
}
return memories[index];
}
Event* Module::GetEvent(const Var& var) const {
Index index = GetEventIndex(var);
if (index >= events.size()) {
return nullptr;
}
return events[index];
}
const DataSegment* Module::GetDataSegment(const Var& var) const {
return const_cast<Module*>(this)->GetDataSegment(var);
}
DataSegment* Module::GetDataSegment(const Var& var) {
Index index = data_segment_bindings.FindIndex(var);
if (index >= data_segments.size()) {
return nullptr;
}
return data_segments[index];
}
const ElemSegment* Module::GetElemSegment(const Var& var) const {
return const_cast<Module*>(this)->GetElemSegment(var);
}
ElemSegment* Module::GetElemSegment(const Var& var) {
Index index = elem_segment_bindings.FindIndex(var);
if (index >= elem_segments.size()) {
return nullptr;
}
return elem_segments[index];
}
const FuncType* Module::GetFuncType(const Var& var) const {
return const_cast<Module*>(this)->GetFuncType(var);
}
FuncType* Module::GetFuncType(const Var& var) {
Index index = type_bindings.FindIndex(var);
if (index >= types.size()) {
return nullptr;
}
return dyn_cast<FuncType>(types[index]);
}
Index Module::GetFuncTypeIndex(const FuncSignature& sig) const {
for (size_t i = 0; i < types.size(); ++i) {
if (auto* func_type = dyn_cast<FuncType>(types[i])) {
if (func_type->sig == sig) {
return i;
}
}
}
return kInvalidIndex;
}
Index Module::GetFuncTypeIndex(const FuncDeclaration& decl) const {
if (decl.has_func_type) {
return GetFuncTypeIndex(decl.type_var);
} else {
return GetFuncTypeIndex(decl.sig);
}
}
void Module::AppendField(std::unique_ptr<DataSegmentModuleField> field) {
DataSegment& data_segment = field->data_segment;
if (!data_segment.name.empty()) {
data_segment_bindings.emplace(data_segment.name,
Binding(field->loc, data_segments.size()));
}
data_segments.push_back(&data_segment);
fields.push_back(std::move(field));
}
void Module::AppendField(std::unique_ptr<ElemSegmentModuleField> field) {
ElemSegment& elem_segment = field->elem_segment;
if (!elem_segment.name.empty()) {
elem_segment_bindings.emplace(elem_segment.name,
Binding(field->loc, elem_segments.size()));
}
elem_segments.push_back(&elem_segment);
fields.push_back(std::move(field));
}
void Module::AppendField(std::unique_ptr<EventModuleField> field) {
Event& event = field->event;
if (!event.name.empty()) {
event_bindings.emplace(event.name, Binding(field->loc, events.size()));
}
events.push_back(&event);
fields.push_back(std::move(field));
}
void Module::AppendField(std::unique_ptr<ExportModuleField> field) {
// Exported names are allowed to be empty.
Export& export_ = field->export_;
export_bindings.emplace(export_.name, Binding(field->loc, exports.size()));
exports.push_back(&export_);
fields.push_back(std::move(field));
}
void Module::AppendField(std::unique_ptr<FuncModuleField> field) {
Func& func = field->func;
if (!func.name.empty()) {
func_bindings.emplace(func.name, Binding(field->loc, funcs.size()));
}
funcs.push_back(&func);
fields.push_back(std::move(field));
}
void Module::AppendField(std::unique_ptr<TypeModuleField> field) {
TypeEntry& type = *field->type;
if (!type.name.empty()) {
type_bindings.emplace(type.name, Binding(field->loc, types.size()));
}
types.push_back(&type);
fields.push_back(std::move(field));
}
void Module::AppendField(std::unique_ptr<GlobalModuleField> field) {
Global& global = field->global;
if (!global.name.empty()) {
global_bindings.emplace(global.name, Binding(field->loc, globals.size()));
}
globals.push_back(&global);
fields.push_back(std::move(field));
}
void Module::AppendField(std::unique_ptr<ImportModuleField> field) {
Import* import = field->import.get();
const std::string* name = nullptr;
BindingHash* bindings = nullptr;
Index index = kInvalidIndex;
switch (import->kind()) {
case ExternalKind::Func: {
Func& func = cast<FuncImport>(import)->func;
name = &func.name;
bindings = &func_bindings;
index = funcs.size();
funcs.push_back(&func);
++num_func_imports;
break;
}
case ExternalKind::Table: {
Table& table = cast<TableImport>(import)->table;
name = &table.name;
bindings = &table_bindings;
index = tables.size();
tables.push_back(&table);
++num_table_imports;
break;
}
case ExternalKind::Memory: {
Memory& memory = cast<MemoryImport>(import)->memory;
name = &memory.name;
bindings = &memory_bindings;
index = memories.size();
memories.push_back(&memory);
++num_memory_imports;
break;
}
case ExternalKind::Global: {
Global& global = cast<GlobalImport>(import)->global;
name = &global.name;
bindings = &global_bindings;
index = globals.size();
globals.push_back(&global);
++num_global_imports;
break;
}
case ExternalKind::Event: {
Event& event = cast<EventImport>(import)->event;
name = &event.name;
bindings = &event_bindings;
index = events.size();
events.push_back(&event);
++num_event_imports;
break;
}
}
assert(name && bindings && index != kInvalidIndex);
if (!name->empty()) {
bindings->emplace(*name, Binding(field->loc, index));
}
imports.push_back(import);
fields.push_back(std::move(field));
}
void Module::AppendField(std::unique_ptr<MemoryModuleField> field) {
Memory& memory = field->memory;
if (!memory.name.empty()) {
memory_bindings.emplace(memory.name, Binding(field->loc, memories.size()));
}
memories.push_back(&memory);
fields.push_back(std::move(field));
}
void Module::AppendField(std::unique_ptr<StartModuleField> field) {
starts.push_back(&field->start);
fields.push_back(std::move(field));
}
void Module::AppendField(std::unique_ptr<TableModuleField> field) {
Table& table = field->table;
if (!table.name.empty()) {
table_bindings.emplace(table.name, Binding(field->loc, tables.size()));
}
tables.push_back(&table);
fields.push_back(std::move(field));
}
void Module::AppendField(std::unique_ptr<ModuleField> field) {
switch (field->type()) {
case ModuleFieldType::Func:
AppendField(cast<FuncModuleField>(std::move(field)));
break;
case ModuleFieldType::Global:
AppendField(cast<GlobalModuleField>(std::move(field)));
break;
case ModuleFieldType::Import:
AppendField(cast<ImportModuleField>(std::move(field)));
break;
case ModuleFieldType::Export:
AppendField(cast<ExportModuleField>(std::move(field)));
break;
case ModuleFieldType::Type:
AppendField(cast<TypeModuleField>(std::move(field)));
break;
case ModuleFieldType::Table:
AppendField(cast<TableModuleField>(std::move(field)));
break;
case ModuleFieldType::ElemSegment:
AppendField(cast<ElemSegmentModuleField>(std::move(field)));
break;
case ModuleFieldType::Memory:
AppendField(cast<MemoryModuleField>(std::move(field)));
break;
case ModuleFieldType::DataSegment:
AppendField(cast<DataSegmentModuleField>(std::move(field)));
break;
case ModuleFieldType::Start:
AppendField(cast<StartModuleField>(std::move(field)));
break;
case ModuleFieldType::Event:
AppendField(cast<EventModuleField>(std::move(field)));
break;
}
}
void Module::AppendFields(ModuleFieldList* fields) {
while (!fields->empty())
AppendField(std::unique_ptr<ModuleField>(fields->extract_front()));
}
const Module* Script::GetFirstModule() const {
return const_cast<Script*>(this)->GetFirstModule();
}
Module* Script::GetFirstModule() {
for (const std::unique_ptr<Command>& command : commands) {
if (auto* module_command = dyn_cast<ModuleCommand>(command.get())) {
return &module_command->module;
}
}
return nullptr;
}
const Module* Script::GetModule(const Var& var) const {
Index index = module_bindings.FindIndex(var);
if (index >= commands.size()) {
return nullptr;
}
auto* command = cast<ModuleCommand>(commands[index].get());
return &command->module;
}
void MakeTypeBindingReverseMapping(
size_t num_types,
const BindingHash& bindings,
std::vector<std::string>* out_reverse_mapping) {
out_reverse_mapping->clear();
out_reverse_mapping->resize(num_types);
for (const auto& pair : bindings) {
assert(static_cast<size_t>(pair.second.index) <
out_reverse_mapping->size());
(*out_reverse_mapping)[pair.second.index] = pair.first;
}
}
Var::Var(Index index, const Location& loc)
: loc(loc), type_(VarType::Index), index_(index) {}
Var::Var(string_view name, const Location& loc)
: loc(loc), type_(VarType::Name), name_(name) {}
Var::Var(Var&& rhs) : Var(kInvalidIndex) {
*this = std::move(rhs);
}
Var::Var(const Var& rhs) : Var(kInvalidIndex) {
*this = rhs;
}
Var& Var::operator=(Var&& rhs) {
loc = rhs.loc;
if (rhs.is_index()) {
set_index(rhs.index_);
} else {
set_name(rhs.name_);
}
return *this;
}
Var& Var::operator=(const Var& rhs) {
loc = rhs.loc;
if (rhs.is_index()) {
set_index(rhs.index_);
} else {
set_name(rhs.name_);
}
return *this;
}
Var::~Var() {
Destroy();
}
void Var::set_index(Index index) {
Destroy();
type_ = VarType::Index;
index_ = index;
}
void Var::set_name(std::string&& name) {
Destroy();
type_ = VarType::Name;
Construct(name_, std::move(name));
}
void Var::set_name(string_view name) {
set_name(name.to_string());
}
void Var::Destroy() {
if (is_name()) {
Destruct(name_);
}
}
uint8_t ElemSegment::GetFlags(const Module* module) const {
uint8_t flags = 0;
bool all_ref_func = elem_type == Type::FuncRef;
switch (kind) {
case SegmentKind::Active: {
Index table_index = module->GetTableIndex(table_var);
if (table_index != 0) {
flags |= SegExplicitIndex;
}
break;
}
case SegmentKind::Passive:
flags |= SegPassive;
break;
case SegmentKind::Declared:
flags |= SegDeclared;
break;
}
all_ref_func = all_ref_func &&
std::all_of(elem_exprs.begin(), elem_exprs.end(),
[](const ElemExpr& elem_expr) {
return elem_expr.kind == ElemExprKind::RefFunc;
});
if (!all_ref_func) {
flags |= SegUseElemExprs;
}
return flags;
}
uint8_t DataSegment::GetFlags(const Module* module) const {
uint8_t flags = 0;
if (kind == SegmentKind::Passive) {
flags |= SegPassive;
}
Index memory_index = module->GetMemoryIndex(memory_var);
if (memory_index != 0) {
flags |= SegExplicitIndex;
}
return flags;
}
} // namespace wabt

1345
third_party/wasm2c/src/ir.h vendored Normal file

File diff suppressed because it is too large Load Diff

354
third_party/wasm2c/src/leb128.cc vendored Normal file
View File

@@ -0,0 +1,354 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/leb128.h"
#include <type_traits>
#include "src/stream.h"
#define MAX_U32_LEB128_BYTES 5
#define MAX_U64_LEB128_BYTES 10
namespace wabt {
Offset U32Leb128Length(uint32_t value) {
uint32_t size = 0;
do {
value >>= 7;
size++;
} while (value != 0);
return size;
}
#define LEB128_LOOP_UNTIL(end_cond) \
do { \
uint8_t byte = value & 0x7f; \
value >>= 7; \
if (end_cond) { \
data[length++] = byte; \
break; \
} else { \
data[length++] = byte | 0x80; \
} \
} while (1)
Offset WriteFixedU32Leb128At(Stream* stream,
Offset offset,
uint32_t value,
const char* desc) {
uint8_t data[MAX_U32_LEB128_BYTES];
Offset length =
WriteFixedU32Leb128Raw(data, data + MAX_U32_LEB128_BYTES, value);
stream->WriteDataAt(offset, data, length, desc);
return length;
}
void WriteU32Leb128(Stream* stream, uint32_t value, const char* desc) {
uint8_t data[MAX_U32_LEB128_BYTES];
Offset length = 0;
LEB128_LOOP_UNTIL(value == 0);
stream->WriteData(data, length, desc);
}
void WriteFixedU32Leb128(Stream* stream, uint32_t value, const char* desc) {
uint8_t data[MAX_U32_LEB128_BYTES];
Offset length =
WriteFixedU32Leb128Raw(data, data + MAX_U32_LEB128_BYTES, value);
stream->WriteData(data, length, desc);
}
// returns the length of the leb128.
Offset WriteU32Leb128At(Stream* stream,
Offset offset,
uint32_t value,
const char* desc) {
uint8_t data[MAX_U32_LEB128_BYTES];
Offset length = 0;
LEB128_LOOP_UNTIL(value == 0);
stream->WriteDataAt(offset, data, length, desc);
return length;
}
Offset WriteU32Leb128Raw(uint8_t* dest, uint8_t* dest_end, uint32_t value) {
uint8_t data[MAX_U32_LEB128_BYTES];
Offset length = 0;
LEB128_LOOP_UNTIL(value == 0);
if (static_cast<Offset>(dest_end - dest) < length) {
return 0;
}
memcpy(dest, data, length);
return length;
}
Offset WriteFixedU32Leb128Raw(uint8_t* data, uint8_t* end, uint32_t value) {
if (end - data < MAX_U32_LEB128_BYTES) {
return 0;
}
data[0] = (value & 0x7f) | 0x80;
data[1] = ((value >> 7) & 0x7f) | 0x80;
data[2] = ((value >> 14) & 0x7f) | 0x80;
data[3] = ((value >> 21) & 0x7f) | 0x80;
data[4] = ((value >> 28) & 0x0f);
return MAX_U32_LEB128_BYTES;
}
static void WriteS32Leb128(Stream* stream, int32_t value, const char* desc) {
uint8_t data[MAX_U32_LEB128_BYTES];
Offset length = 0;
if (value < 0) {
LEB128_LOOP_UNTIL(value == -1 && (byte & 0x40));
} else {
LEB128_LOOP_UNTIL(value == 0 && !(byte & 0x40));
}
stream->WriteData(data, length, desc);
}
static void WriteS64Leb128(Stream* stream, int64_t value, const char* desc) {
uint8_t data[MAX_U64_LEB128_BYTES];
Offset length = 0;
if (value < 0) {
LEB128_LOOP_UNTIL(value == -1 && (byte & 0x40));
} else {
LEB128_LOOP_UNTIL(value == 0 && !(byte & 0x40));
}
stream->WriteData(data, length, desc);
}
void WriteS32Leb128(Stream* stream, uint32_t value, const char* desc) {
WriteS32Leb128(stream, Bitcast<int32_t>(value), desc);
}
void WriteS64Leb128(Stream* stream, uint64_t value, const char* desc) {
WriteS64Leb128(stream, Bitcast<int64_t>(value), desc);
}
void WriteFixedS32Leb128(Stream* stream, uint32_t value, const char* desc) {
uint8_t data[MAX_U32_LEB128_BYTES];
data[0] = (value & 0x7f) | 0x80;
data[1] = ((value >> 7) & 0x7f) | 0x80;
data[2] = ((value >> 14) & 0x7f) | 0x80;
data[3] = ((value >> 21) & 0x7f) | 0x80;
// The last byte needs to be sign-extended.
data[4] = ((value >> 28) & 0x0f);
if (static_cast<int32_t>(value) < 0) {
data[4] |= 0x70;
}
stream->WriteData(data, MAX_U32_LEB128_BYTES, desc);
}
#undef LEB128_LOOP_UNTIL
#define BYTE_AT(type, i, shift) ((static_cast<type>(p[i]) & 0x7f) << (shift))
#define LEB128_1(type) (BYTE_AT(type, 0, 0))
#define LEB128_2(type) (BYTE_AT(type, 1, 7) | LEB128_1(type))
#define LEB128_3(type) (BYTE_AT(type, 2, 14) | LEB128_2(type))
#define LEB128_4(type) (BYTE_AT(type, 3, 21) | LEB128_3(type))
#define LEB128_5(type) (BYTE_AT(type, 4, 28) | LEB128_4(type))
#define LEB128_6(type) (BYTE_AT(type, 5, 35) | LEB128_5(type))
#define LEB128_7(type) (BYTE_AT(type, 6, 42) | LEB128_6(type))
#define LEB128_8(type) (BYTE_AT(type, 7, 49) | LEB128_7(type))
#define LEB128_9(type) (BYTE_AT(type, 8, 56) | LEB128_8(type))
#define LEB128_10(type) (BYTE_AT(type, 9, 63) | LEB128_9(type))
#define SHIFT_AMOUNT(type, sign_bit) (sizeof(type) * 8 - 1 - (sign_bit))
#define SIGN_EXTEND(type, value, sign_bit) \
(static_cast<type>((value) << SHIFT_AMOUNT(type, sign_bit)) >> \
SHIFT_AMOUNT(type, sign_bit))
size_t ReadU32Leb128(const uint8_t* p,
const uint8_t* end,
uint32_t* out_value) {
if (p < end && (p[0] & 0x80) == 0) {
*out_value = LEB128_1(uint32_t);
return 1;
} else if (p + 1 < end && (p[1] & 0x80) == 0) {
*out_value = LEB128_2(uint32_t);
return 2;
} else if (p + 2 < end && (p[2] & 0x80) == 0) {
*out_value = LEB128_3(uint32_t);
return 3;
} else if (p + 3 < end && (p[3] & 0x80) == 0) {
*out_value = LEB128_4(uint32_t);
return 4;
} else if (p + 4 < end && (p[4] & 0x80) == 0) {
// The top bits set represent values > 32 bits.
if (p[4] & 0xf0) {
return 0;
}
*out_value = LEB128_5(uint32_t);
return 5;
} else {
// past the end.
*out_value = 0;
return 0;
}
}
size_t ReadU64Leb128(const uint8_t* p,
const uint8_t* end,
uint64_t* out_value) {
if (p < end && (p[0] & 0x80) == 0) {
*out_value = LEB128_1(uint64_t);
return 1;
} else if (p + 1 < end && (p[1] & 0x80) == 0) {
*out_value = LEB128_2(uint64_t);
return 2;
} else if (p + 2 < end && (p[2] & 0x80) == 0) {
*out_value = LEB128_3(uint64_t);
return 3;
} else if (p + 3 < end && (p[3] & 0x80) == 0) {
*out_value = LEB128_4(uint64_t);
return 4;
} else if (p + 4 < end && (p[4] & 0x80) == 0) {
*out_value = LEB128_5(uint64_t);
return 5;
} else if (p + 5 < end && (p[5] & 0x80) == 0) {
*out_value = LEB128_6(uint64_t);
return 6;
} else if (p + 6 < end && (p[6] & 0x80) == 0) {
*out_value = LEB128_7(uint64_t);
return 7;
} else if (p + 7 < end && (p[7] & 0x80) == 0) {
*out_value = LEB128_8(uint64_t);
return 8;
} else if (p + 8 < end && (p[8] & 0x80) == 0) {
*out_value = LEB128_9(uint64_t);
return 9;
} else if (p + 9 < end && (p[9] & 0x80) == 0) {
// The top bits set represent values > 32 bits.
if (p[9] & 0xf0) {
return 0;
}
*out_value = LEB128_10(uint64_t);
return 10;
} else {
// past the end.
*out_value = 0;
return 0;
}
}
size_t ReadS32Leb128(const uint8_t* p,
const uint8_t* end,
uint32_t* out_value) {
if (p < end && (p[0] & 0x80) == 0) {
uint32_t result = LEB128_1(uint32_t);
*out_value = SIGN_EXTEND(int32_t, result, 6);
return 1;
} else if (p + 1 < end && (p[1] & 0x80) == 0) {
uint32_t result = LEB128_2(uint32_t);
*out_value = SIGN_EXTEND(int32_t, result, 13);
return 2;
} else if (p + 2 < end && (p[2] & 0x80) == 0) {
uint32_t result = LEB128_3(uint32_t);
*out_value = SIGN_EXTEND(int32_t, result, 20);
return 3;
} else if (p + 3 < end && (p[3] & 0x80) == 0) {
uint32_t result = LEB128_4(uint32_t);
*out_value = SIGN_EXTEND(int32_t, result, 27);
return 4;
} else if (p + 4 < end && (p[4] & 0x80) == 0) {
// The top bits should be a sign-extension of the sign bit.
bool sign_bit_set = (p[4] & 0x8);
int top_bits = p[4] & 0xf0;
if ((sign_bit_set && top_bits != 0x70) ||
(!sign_bit_set && top_bits != 0)) {
return 0;
}
uint32_t result = LEB128_5(uint32_t);
*out_value = result;
return 5;
} else {
// Past the end.
return 0;
}
}
size_t ReadS64Leb128(const uint8_t* p,
const uint8_t* end,
uint64_t* out_value) {
if (p < end && (p[0] & 0x80) == 0) {
uint64_t result = LEB128_1(uint64_t);
*out_value = SIGN_EXTEND(int64_t, result, 6);
return 1;
} else if (p + 1 < end && (p[1] & 0x80) == 0) {
uint64_t result = LEB128_2(uint64_t);
*out_value = SIGN_EXTEND(int64_t, result, 13);
return 2;
} else if (p + 2 < end && (p[2] & 0x80) == 0) {
uint64_t result = LEB128_3(uint64_t);
*out_value = SIGN_EXTEND(int64_t, result, 20);
return 3;
} else if (p + 3 < end && (p[3] & 0x80) == 0) {
uint64_t result = LEB128_4(uint64_t);
*out_value = SIGN_EXTEND(int64_t, result, 27);
return 4;
} else if (p + 4 < end && (p[4] & 0x80) == 0) {
uint64_t result = LEB128_5(uint64_t);
*out_value = SIGN_EXTEND(int64_t, result, 34);
return 5;
} else if (p + 5 < end && (p[5] & 0x80) == 0) {
uint64_t result = LEB128_6(uint64_t);
*out_value = SIGN_EXTEND(int64_t, result, 41);
return 6;
} else if (p + 6 < end && (p[6] & 0x80) == 0) {
uint64_t result = LEB128_7(uint64_t);
*out_value = SIGN_EXTEND(int64_t, result, 48);
return 7;
} else if (p + 7 < end && (p[7] & 0x80) == 0) {
uint64_t result = LEB128_8(uint64_t);
*out_value = SIGN_EXTEND(int64_t, result, 55);
return 8;
} else if (p + 8 < end && (p[8] & 0x80) == 0) {
uint64_t result = LEB128_9(uint64_t);
*out_value = SIGN_EXTEND(int64_t, result, 62);
return 9;
} else if (p + 9 < end && (p[9] & 0x80) == 0) {
// The top bits should be a sign-extension of the sign bit.
bool sign_bit_set = (p[9] & 0x1);
int top_bits = p[9] & 0xfe;
if ((sign_bit_set && top_bits != 0x7e) ||
(!sign_bit_set && top_bits != 0)) {
return 0;
}
uint64_t result = LEB128_10(uint64_t);
*out_value = result;
return 10;
} else {
// Past the end.
return 0;
}
}
#undef BYTE_AT
#undef LEB128_1
#undef LEB128_2
#undef LEB128_3
#undef LEB128_4
#undef LEB128_5
#undef LEB128_6
#undef LEB128_7
#undef LEB128_8
#undef LEB128_9
#undef LEB128_10
#undef SHIFT_AMOUNT
#undef SIGN_EXTEND
} // namespace wabt

69
third_party/wasm2c/src/leb128.h vendored Normal file
View File

@@ -0,0 +1,69 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_LEB128_H_
#define WABT_LEB128_H_
#include <cstdint>
#include "src/common.h"
namespace wabt {
class Stream;
// Returns the length of the leb128.
Offset U32Leb128Length(uint32_t value);
void WriteU32Leb128(Stream* stream, uint32_t value, const char* desc);
void WriteS32Leb128(Stream* stream, uint32_t value, const char* desc);
void WriteS64Leb128(Stream* stream, uint64_t value, const char* desc);
void WriteFixedS32Leb128(Stream* stream, uint32_t value, const char* desc);
void WriteFixedU32Leb128(Stream* stream, uint32_t value, const char* desc);
Offset WriteU32Leb128At(Stream* stream,
Offset offset,
uint32_t value,
const char* desc);
Offset WriteFixedU32Leb128At(Stream* stream,
Offset offset,
uint32_t value,
const char* desc);
Offset WriteU32Leb128Raw(uint8_t* data, uint8_t* end, uint32_t value);
Offset WriteFixedU32Leb128Raw(uint8_t* data, uint8_t* end, uint32_t value);
// Convenience functions for writing enums as LEB128s.
template <typename T>
void WriteU32Leb128(Stream* stream, T value, const char* desc) {
WriteU32Leb128(stream, static_cast<uint32_t>(value), desc);
}
template <typename T>
void WriteS32Leb128(Stream* stream, T value, const char* desc) {
WriteS32Leb128(stream, static_cast<uint32_t>(value), desc);
}
// Returns the length of the leb128.
size_t ReadU32Leb128(const uint8_t* p, const uint8_t* end, uint32_t* out_value);
size_t ReadU64Leb128(const uint8_t* p, const uint8_t* end, uint64_t* out_value);
size_t ReadS32Leb128(const uint8_t* p, const uint8_t* end, uint32_t* out_value);
size_t ReadS64Leb128(const uint8_t* p, const uint8_t* end, uint64_t* out_value);
} // namespace wabt
#endif // WABT_LEB128_H_

View File

@@ -0,0 +1,631 @@
struct TokenInfo {
TokenInfo(const char* name) : name(name) {}
TokenInfo(const char* name, TokenType token_type)
: name(name), token_type(token_type) {}
TokenInfo(const char* name, Type value_type)
: name(name), token_type(TokenType::ValueType), value_type(value_type) {}
TokenInfo(const char* name, Type value_type, TokenType token_type)
: name(name), token_type(token_type), value_type(value_type) {}
TokenInfo(const char* name, TokenType token_type, Opcode opcode)
: name(name), token_type(token_type), opcode(opcode) {}
const char* name;
TokenType token_type;
union {
Type value_type;
Opcode opcode;
};
};
%%
array, Type::Array, TokenType::Array
assert_exhaustion, TokenType::AssertExhaustion
assert_invalid, TokenType::AssertInvalid
assert_malformed, TokenType::AssertMalformed
assert_return, TokenType::AssertReturn
assert_trap, TokenType::AssertTrap
assert_unlinkable, TokenType::AssertUnlinkable
atomic.fence, TokenType::AtomicFence, Opcode::AtomicFence
binary, TokenType::Bin
block, TokenType::Block, Opcode::Block
br_if, TokenType::BrIf, Opcode::BrIf
br_table, TokenType::BrTable, Opcode::BrTable
br, TokenType::Br, Opcode::Br
call_indirect, TokenType::CallIndirect, Opcode::CallIndirect
call, TokenType::Call, Opcode::Call
catch, TokenType::Catch, Opcode::Catch
catch_all, TokenType::CatchAll, Opcode::CatchAll
current_memory, TokenType::MemorySize, Opcode::MemorySize
data.drop, TokenType::DataDrop, Opcode::DataDrop
data, TokenType::Data
declare, TokenType::Declare
delegate, TokenType::Delegate
do, TokenType::Do
drop, TokenType::Drop, Opcode::Drop
elem.drop, TokenType::ElemDrop, Opcode::ElemDrop
elem, TokenType::Elem
else, TokenType::Else, Opcode::Else
end, TokenType::End, Opcode::End
event, TokenType::Event
extern, Type::ExternRef, TokenType::Extern
externref, Type::ExternRef
export, TokenType::Export
f32.abs, TokenType::Unary, Opcode::F32Abs
f32.add, TokenType::Binary, Opcode::F32Add
f32.ceil, TokenType::Unary, Opcode::F32Ceil
f32.const, TokenType::Const, Opcode::F32Const
f32.convert_i32_s, TokenType::Convert, Opcode::F32ConvertI32S
f32.convert_i32_u, TokenType::Convert, Opcode::F32ConvertI32U
f32.convert_i64_s, TokenType::Convert, Opcode::F32ConvertI64S
f32.convert_i64_u, TokenType::Convert, Opcode::F32ConvertI64U
f32.copysign, TokenType::Binary, Opcode::F32Copysign
f32.demote_f64, TokenType::Convert, Opcode::F32DemoteF64
f32.div, TokenType::Binary, Opcode::F32Div
f32.eq, TokenType::Compare, Opcode::F32Eq
f32.floor, TokenType::Unary, Opcode::F32Floor
f32.ge, TokenType::Compare, Opcode::F32Ge
f32.gt, TokenType::Compare, Opcode::F32Gt
f32.le, TokenType::Compare, Opcode::F32Le
f32.load, TokenType::Load, Opcode::F32Load
f32.lt, TokenType::Compare, Opcode::F32Lt
f32.max, TokenType::Binary, Opcode::F32Max
f32.min, TokenType::Binary, Opcode::F32Min
f32.mul, TokenType::Binary, Opcode::F32Mul
f32.nearest, TokenType::Unary, Opcode::F32Nearest
f32.neg, TokenType::Unary, Opcode::F32Neg
f32.ne, TokenType::Compare, Opcode::F32Ne
f32.reinterpret_i32, TokenType::Convert, Opcode::F32ReinterpretI32
f32.sqrt, TokenType::Unary, Opcode::F32Sqrt
f32.store, TokenType::Store, Opcode::F32Store
f32.sub, TokenType::Binary, Opcode::F32Sub
f32.trunc, TokenType::Unary, Opcode::F32Trunc
f32, Type::F32
f32x4.abs, TokenType::Unary, Opcode::F32X4Abs
f32x4.add, TokenType::Binary, Opcode::F32X4Add
f32x4.ceil, TokenType::Unary, Opcode::F32X4Ceil
f32x4.convert_i32x4_s, TokenType::Unary, Opcode::F32X4ConvertI32X4S
f32x4.convert_i32x4_u, TokenType::Unary, Opcode::F32X4ConvertI32X4U
f32x4.div, TokenType::Binary, Opcode::F32X4Div
f32x4.eq, TokenType::Compare, Opcode::F32X4Eq
f32x4.extract_lane, TokenType::SimdLaneOp, Opcode::F32X4ExtractLane
f32x4.floor, TokenType::Unary, Opcode::F32X4Floor
f32x4.ge, TokenType::Compare, Opcode::F32X4Ge
f32x4.gt, TokenType::Compare, Opcode::F32X4Gt
f32x4.le, TokenType::Compare, Opcode::F32X4Le
f32x4.lt, TokenType::Compare, Opcode::F32X4Lt
f32x4.max, TokenType::Binary, Opcode::F32X4Max
f32x4.min, TokenType::Binary, Opcode::F32X4Min
f32x4.mul, TokenType::Binary, Opcode::F32X4Mul
f32x4.nearest, TokenType::Unary, Opcode::F32X4Nearest
f32x4.neg, TokenType::Unary, Opcode::F32X4Neg
f32x4.ne, TokenType::Compare, Opcode::F32X4Ne
f32x4.pmax, TokenType::Binary, Opcode::F32X4PMax
f32x4.pmin, TokenType::Binary, Opcode::F32X4PMin
f32x4.replace_lane, TokenType::SimdLaneOp, Opcode::F32X4ReplaceLane
f32x4.splat, TokenType::Unary, Opcode::F32X4Splat
f32x4.sqrt, TokenType::Unary, Opcode::F32X4Sqrt
f32x4.sub, TokenType::Binary, Opcode::F32X4Sub
f32x4.trunc, TokenType::Unary, Opcode::F32X4Trunc
f32x4.demote_f64x2_zero, TokenType::Unary, Opcode::F32X4DemoteF64X2Zero
f32x4, TokenType::F32X4
f64.abs, TokenType::Unary, Opcode::F64Abs
f64.add, TokenType::Binary, Opcode::F64Add
f64.ceil, TokenType::Unary, Opcode::F64Ceil
f64.const, TokenType::Const, Opcode::F64Const
f64.convert_i32_s, TokenType::Convert, Opcode::F64ConvertI32S
f64.convert_i32_u, TokenType::Convert, Opcode::F64ConvertI32U
f64.convert_i64_s, TokenType::Convert, Opcode::F64ConvertI64S
f64.convert_i64_u, TokenType::Convert, Opcode::F64ConvertI64U
f64.copysign, TokenType::Binary, Opcode::F64Copysign
f64.div, TokenType::Binary, Opcode::F64Div
f64.eq, TokenType::Compare, Opcode::F64Eq
f64.floor, TokenType::Unary, Opcode::F64Floor
f64.ge, TokenType::Compare, Opcode::F64Ge
f64.gt, TokenType::Compare, Opcode::F64Gt
f64.le, TokenType::Compare, Opcode::F64Le
f64.load, TokenType::Load, Opcode::F64Load
f64.lt, TokenType::Compare, Opcode::F64Lt
f64.max, TokenType::Binary, Opcode::F64Max
f64.min, TokenType::Binary, Opcode::F64Min
f64.mul, TokenType::Binary, Opcode::F64Mul
f64.nearest, TokenType::Unary, Opcode::F64Nearest
f64.neg, TokenType::Unary, Opcode::F64Neg
f64.ne, TokenType::Compare, Opcode::F64Ne
f64.promote_f32, TokenType::Convert, Opcode::F64PromoteF32
f64.reinterpret_i64, TokenType::Convert, Opcode::F64ReinterpretI64
f64.sqrt, TokenType::Unary, Opcode::F64Sqrt
f64.store, TokenType::Store, Opcode::F64Store
f64.sub, TokenType::Binary, Opcode::F64Sub
f64.trunc, TokenType::Unary, Opcode::F64Trunc
f64, Type::F64
f64x2.abs, TokenType::Unary, Opcode::F64X2Abs
f64x2.add, TokenType::Binary, Opcode::F64X2Add
f64x2.ceil, TokenType::Unary, Opcode::F64X2Ceil
f64x2.div, TokenType::Binary, Opcode::F64X2Div
f64x2.eq, TokenType::Compare, Opcode::F64X2Eq
f64x2.extract_lane, TokenType::SimdLaneOp, Opcode::F64X2ExtractLane
f64x2.floor, TokenType::Unary, Opcode::F64X2Floor
f64x2.ge, TokenType::Compare, Opcode::F64X2Ge
f64x2.gt, TokenType::Compare, Opcode::F64X2Gt
f64x2.le, TokenType::Compare, Opcode::F64X2Le
f64x2.lt, TokenType::Compare, Opcode::F64X2Lt
f64x2.max, TokenType::Binary, Opcode::F64X2Max
f64x2.min, TokenType::Binary, Opcode::F64X2Min
f64x2.mul, TokenType::Binary, Opcode::F64X2Mul
f64x2.nearest, TokenType::Unary, Opcode::F64X2Nearest
f64x2.neg, TokenType::Unary, Opcode::F64X2Neg
f64x2.ne, TokenType::Compare, Opcode::F64X2Ne
f64x2.pmax, TokenType::Binary, Opcode::F64X2PMax
f64x2.pmin, TokenType::Binary, Opcode::F64X2PMin
f64x2.replace_lane, TokenType::SimdLaneOp, Opcode::F64X2ReplaceLane
f64x2.splat, TokenType::Unary, Opcode::F64X2Splat
f64x2.sqrt, TokenType::Unary, Opcode::F64X2Sqrt
f64x2.sub, TokenType::Binary, Opcode::F64X2Sub
f64x2.trunc, TokenType::Unary, Opcode::F64X2Trunc
f64x2.convert_low_i32x4_s, TokenType::Unary, Opcode::F64X2ConvertLowI32X4S
f64x2.convert_low_i32x4_u, TokenType::Unary, Opcode::F64X2ConvertLowI32X4U
f64x2.promote_low_f32x4, TokenType::Unary, Opcode::F64X2PromoteLowF32X4
f64x2, TokenType::F64X2
field, TokenType::Field
funcref, Type::FuncRef
func, Type::FuncRef, TokenType::Func
get, TokenType::Get
global.get, TokenType::GlobalGet, Opcode::GlobalGet
global.set, TokenType::GlobalSet, Opcode::GlobalSet
global, TokenType::Global
grow_memory, TokenType::MemoryGrow, Opcode::MemoryGrow
i16x8.abs, TokenType::Unary, Opcode::I16X8Abs
i16x8.add_sat_s, TokenType::Binary, Opcode::I16X8AddSatS
i16x8.add_sat_u, TokenType::Binary, Opcode::I16X8AddSatU
i16x8.add, TokenType::Binary, Opcode::I16X8Add
i16x8.all_true, TokenType::Unary, Opcode::I16X8AllTrue
i16x8.avgr_u, TokenType::Binary, Opcode::I16X8AvgrU
i16x8.bitmask, TokenType::Unary, Opcode::I16X8Bitmask
i16x8.eq, TokenType::Compare, Opcode::I16X8Eq
i16x8.extract_lane_s, TokenType::SimdLaneOp, Opcode::I16X8ExtractLaneS
i16x8.extract_lane_u, TokenType::SimdLaneOp, Opcode::I16X8ExtractLaneU
i16x8.ge_s, TokenType::Compare, Opcode::I16X8GeS
i16x8.ge_u, TokenType::Compare, Opcode::I16X8GeU
i16x8.gt_s, TokenType::Compare, Opcode::I16X8GtS
i16x8.gt_u, TokenType::Compare, Opcode::I16X8GtU
i16x8.le_s, TokenType::Compare, Opcode::I16X8LeS
i16x8.le_u, TokenType::Compare, Opcode::I16X8LeU
v128.load8x8_s, TokenType::Load, Opcode::V128Load8X8S
v128.load8x8_u, TokenType::Load, Opcode::V128Load8X8U
i16x8.lt_s, TokenType::Compare, Opcode::I16X8LtS
i16x8.lt_u, TokenType::Compare, Opcode::I16X8LtU
i16x8.max_s, TokenType::Binary, Opcode::I16X8MaxS
i16x8.max_u, TokenType::Binary, Opcode::I16X8MaxU
i16x8.min_s, TokenType::Binary, Opcode::I16X8MinS
i16x8.min_u, TokenType::Binary, Opcode::I16X8MinU
i16x8.mul, TokenType::Binary, Opcode::I16X8Mul
i16x8.narrow_i32x4_s, TokenType::Binary, Opcode::I16X8NarrowI32X4S
i16x8.narrow_i32x4_u, TokenType::Binary, Opcode::I16X8NarrowI32X4U
i16x8.neg, TokenType::Unary, Opcode::I16X8Neg
i16x8.q15mulr_sat_s, TokenType::Binary, Opcode::I16X8Q15mulrSatS
i16x8.ne, TokenType::Compare, Opcode::I16X8Ne
i16x8.replace_lane, TokenType::SimdLaneOp, Opcode::I16X8ReplaceLane
i16x8.shl, TokenType::Binary, Opcode::I16X8Shl
i16x8.shr_s, TokenType::Binary, Opcode::I16X8ShrS
i16x8.shr_u, TokenType::Binary, Opcode::I16X8ShrU
i16x8.splat, TokenType::Unary, Opcode::I16X8Splat
i16x8.sub_sat_s, TokenType::Binary, Opcode::I16X8SubSatS
i16x8.sub_sat_u, TokenType::Binary, Opcode::I16X8SubSatU
i16x8.sub, TokenType::Binary, Opcode::I16X8Sub
i16x8.extadd_pairwise_i8x16_s, TokenType::Unary, Opcode::I16X8ExtaddPairwiseI8X16S
i16x8.extadd_pairwise_i8x16_u, TokenType::Unary, Opcode::I16X8ExtaddPairwiseI8X16U
i16x8.extmul_low_i8x16_s, TokenType::Binary, Opcode::I16X8ExtmulLowI8X16S
i16x8.extmul_high_i8x16_s, TokenType::Binary, Opcode::I16X8ExtmulHighI8X16S
i16x8.extmul_low_i8x16_u, TokenType::Binary, Opcode::I16X8ExtmulLowI8X16U
i16x8.extmul_high_i8x16_u, TokenType::Binary, Opcode::I16X8ExtmulHighI8X16U
i16x8, TokenType::I16X8
i16x8.extend_high_i8x16_s, TokenType::Unary, Opcode::I16X8ExtendHighI8X16S
i16x8.extend_high_i8x16_u, TokenType::Unary, Opcode::I16X8ExtendHighI8X16U
i16x8.extend_low_i8x16_s, TokenType::Unary, Opcode::I16X8ExtendLowI8X16S
i16x8.extend_low_i8x16_u, TokenType::Unary, Opcode::I16X8ExtendLowI8X16U
i32.add, TokenType::Binary, Opcode::I32Add
i32.and, TokenType::Binary, Opcode::I32And
i32.atomic.load16_u, TokenType::AtomicLoad, Opcode::I32AtomicLoad16U
i32.atomic.load8_u, TokenType::AtomicLoad, Opcode::I32AtomicLoad8U
i32.atomic.load, TokenType::AtomicLoad, Opcode::I32AtomicLoad
i32.atomic.rmw16.add_u, TokenType::AtomicRmw, Opcode::I32AtomicRmw16AddU
i32.atomic.rmw16.and_u, TokenType::AtomicRmw, Opcode::I32AtomicRmw16AndU
i32.atomic.rmw16.cmpxchg_u, TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmw16CmpxchgU
i32.atomic.rmw16.or_u, TokenType::AtomicRmw, Opcode::I32AtomicRmw16OrU
i32.atomic.rmw16.sub_u, TokenType::AtomicRmw, Opcode::I32AtomicRmw16SubU
i32.atomic.rmw16.xchg_u, TokenType::AtomicRmw, Opcode::I32AtomicRmw16XchgU
i32.atomic.rmw16.xor_u, TokenType::AtomicRmw, Opcode::I32AtomicRmw16XorU
i32.atomic.rmw8.add_u, TokenType::AtomicRmw, Opcode::I32AtomicRmw8AddU
i32.atomic.rmw8.and_u, TokenType::AtomicRmw, Opcode::I32AtomicRmw8AndU
i32.atomic.rmw8.cmpxchg_u, TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmw8CmpxchgU
i32.atomic.rmw8.or_u, TokenType::AtomicRmw, Opcode::I32AtomicRmw8OrU
i32.atomic.rmw8.sub_u, TokenType::AtomicRmw, Opcode::I32AtomicRmw8SubU
i32.atomic.rmw8.xchg_u, TokenType::AtomicRmw, Opcode::I32AtomicRmw8XchgU
i32.atomic.rmw8.xor_u, TokenType::AtomicRmw, Opcode::I32AtomicRmw8XorU
i32.atomic.rmw.add, TokenType::AtomicRmw, Opcode::I32AtomicRmwAdd
i32.atomic.rmw.and, TokenType::AtomicRmw, Opcode::I32AtomicRmwAnd
i32.atomic.rmw.cmpxchg, TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmwCmpxchg
i32.atomic.rmw.or, TokenType::AtomicRmw, Opcode::I32AtomicRmwOr
i32.atomic.rmw.sub, TokenType::AtomicRmw, Opcode::I32AtomicRmwSub
i32.atomic.rmw.xchg, TokenType::AtomicRmw, Opcode::I32AtomicRmwXchg
i32.atomic.rmw.xor, TokenType::AtomicRmw, Opcode::I32AtomicRmwXor
i32.atomic.store16, TokenType::AtomicStore, Opcode::I32AtomicStore16
i32.atomic.store8, TokenType::AtomicStore, Opcode::I32AtomicStore8
i32.atomic.store, TokenType::AtomicStore, Opcode::I32AtomicStore
i32.clz, TokenType::Unary, Opcode::I32Clz
i32.const, TokenType::Const, Opcode::I32Const
i32.ctz, TokenType::Unary, Opcode::I32Ctz
i32.div_s, TokenType::Binary, Opcode::I32DivS
i32.div_u, TokenType::Binary, Opcode::I32DivU
i32.eq, TokenType::Compare, Opcode::I32Eq
i32.eqz, TokenType::Convert, Opcode::I32Eqz
i32.extend16_s, TokenType::Unary, Opcode::I32Extend16S
i32.extend8_s, TokenType::Unary, Opcode::I32Extend8S
i32.ge_s, TokenType::Compare, Opcode::I32GeS
i32.ge_u, TokenType::Compare, Opcode::I32GeU
i32.gt_s, TokenType::Compare, Opcode::I32GtS
i32.gt_u, TokenType::Compare, Opcode::I32GtU
i32.le_s, TokenType::Compare, Opcode::I32LeS
i32.le_u, TokenType::Compare, Opcode::I32LeU
i32.load16_s, TokenType::Load, Opcode::I32Load16S
i32.load16_u, TokenType::Load, Opcode::I32Load16U
i32.load8_s, TokenType::Load, Opcode::I32Load8S
i32.load8_u, TokenType::Load, Opcode::I32Load8U
i32.load, TokenType::Load, Opcode::I32Load
i32.lt_s, TokenType::Compare, Opcode::I32LtS
i32.lt_u, TokenType::Compare, Opcode::I32LtU
i32.mul, TokenType::Binary, Opcode::I32Mul
i32.ne, TokenType::Compare, Opcode::I32Ne
i32.or, TokenType::Binary, Opcode::I32Or
i32.popcnt, TokenType::Unary, Opcode::I32Popcnt
i32.reinterpret_f32, TokenType::Convert, Opcode::I32ReinterpretF32
i32.rem_s, TokenType::Binary, Opcode::I32RemS
i32.rem_u, TokenType::Binary, Opcode::I32RemU
i32.rotl, TokenType::Binary, Opcode::I32Rotl
i32.rotr, TokenType::Binary, Opcode::I32Rotr
i32.shl, TokenType::Binary, Opcode::I32Shl
i32.shr_s, TokenType::Binary, Opcode::I32ShrS
i32.shr_u, TokenType::Binary, Opcode::I32ShrU
i32.store16, TokenType::Store, Opcode::I32Store16
i32.store8, TokenType::Store, Opcode::I32Store8
i32.store, TokenType::Store, Opcode::I32Store
i32.sub, TokenType::Binary, Opcode::I32Sub
i32.trunc_f32_s, TokenType::Convert, Opcode::I32TruncF32S
i32.trunc_f32_u, TokenType::Convert, Opcode::I32TruncF32U
i32.trunc_f64_s, TokenType::Convert, Opcode::I32TruncF64S
i32.trunc_f64_u, TokenType::Convert, Opcode::I32TruncF64U
i32.trunc_sat_f32_s, TokenType::Convert, Opcode::I32TruncSatF32S
i32.trunc_sat_f32_u, TokenType::Convert, Opcode::I32TruncSatF32U
i32.trunc_sat_f64_s, TokenType::Convert, Opcode::I32TruncSatF64S
i32.trunc_sat_f64_u, TokenType::Convert, Opcode::I32TruncSatF64U
i32, Type::I32
i32.wrap_i64, TokenType::Convert, Opcode::I32WrapI64
i32x4.abs, TokenType::Unary, Opcode::I32X4Abs
i32x4.add, TokenType::Binary, Opcode::I32X4Add
i32x4.all_true, TokenType::Unary, Opcode::I32X4AllTrue
i32x4.bitmask, TokenType::Unary, Opcode::I32X4Bitmask
i32x4.eq, TokenType::Compare, Opcode::I32X4Eq
i32x4.extract_lane, TokenType::SimdLaneOp, Opcode::I32X4ExtractLane
i32x4.ge_s, TokenType::Compare, Opcode::I32X4GeS
i32x4.ge_u, TokenType::Compare, Opcode::I32X4GeU
i32x4.gt_s, TokenType::Compare, Opcode::I32X4GtS
i32x4.gt_u, TokenType::Compare, Opcode::I32X4GtU
i32x4.le_s, TokenType::Compare, Opcode::I32X4LeS
i32x4.le_u, TokenType::Compare, Opcode::I32X4LeU
v128.load16x4_s, TokenType::Load, Opcode::V128Load16X4S
v128.load16x4_u, TokenType::Load, Opcode::V128Load16X4U
i32x4.lt_s, TokenType::Compare, Opcode::I32X4LtS
i32x4.lt_u, TokenType::Compare, Opcode::I32X4LtU
i32x4.max_s, TokenType::Binary, Opcode::I32X4MaxS
i32x4.max_u, TokenType::Binary, Opcode::I32X4MaxU
i32x4.min_s, TokenType::Binary, Opcode::I32X4MinS
i32x4.min_u, TokenType::Binary, Opcode::I32X4MinU
i32x4.dot_i16x8_s, TokenType::Binary, Opcode::I32X4DotI16X8S
i32x4.mul, TokenType::Binary, Opcode::I32X4Mul
i32x4.neg, TokenType::Unary, Opcode::I32X4Neg
i32x4.ne, TokenType::Compare, Opcode::I32X4Ne
i32x4.replace_lane, TokenType::SimdLaneOp, Opcode::I32X4ReplaceLane
i32x4.shl, TokenType::Binary, Opcode::I32X4Shl
i32x4.shr_s, TokenType::Binary, Opcode::I32X4ShrS
i32x4.shr_u, TokenType::Binary, Opcode::I32X4ShrU
i32x4.splat, TokenType::Unary, Opcode::I32X4Splat
i32x4.sub, TokenType::Binary, Opcode::I32X4Sub
i32x4.extadd_pairwise_i16x8_s, TokenType::Unary, Opcode::I32X4ExtaddPairwiseI16X8S
i32x4.extadd_pairwise_i16x8_u, TokenType::Unary, Opcode::I32X4ExtaddPairwiseI16X8U
i32x4.extmul_low_i16x8_s, TokenType::Binary, Opcode::I32X4ExtmulLowI16X8S
i32x4.extmul_high_i16x8_s, TokenType::Binary, Opcode::I32X4ExtmulHighI16X8S
i32x4.extmul_low_i16x8_u, TokenType::Binary, Opcode::I32X4ExtmulLowI16X8U
i32x4.extmul_high_i16x8_u, TokenType::Binary, Opcode::I32X4ExtmulHighI16X8U
i32x4, TokenType::I32X4
i32x4.trunc_sat_f32x4_s, TokenType::Unary, Opcode::I32X4TruncSatF32X4S
i32x4.trunc_sat_f32x4_u, TokenType::Unary, Opcode::I32X4TruncSatF32X4U
i32x4.extend_high_i16x8_s, TokenType::Unary, Opcode::I32X4ExtendHighI16X8S
i32x4.extend_high_i16x8_u, TokenType::Unary, Opcode::I32X4ExtendHighI16X8U
i32x4.extend_low_i16x8_s, TokenType::Unary, Opcode::I32X4ExtendLowI16X8S
i32x4.extend_low_i16x8_u, TokenType::Unary, Opcode::I32X4ExtendLowI16X8U
i32x4.trunc_sat_f64x2_s_zero, TokenType::Unary, Opcode::I32X4TruncSatF64X2SZero
i32x4.trunc_sat_f64x2_u_zero, TokenType::Unary, Opcode::I32X4TruncSatF64X2UZero
i32.xor, TokenType::Binary, Opcode::I32Xor
i64.add, TokenType::Binary, Opcode::I64Add
i64.and, TokenType::Binary, Opcode::I64And
i64.atomic.load16_u, TokenType::AtomicLoad, Opcode::I64AtomicLoad16U
i64.atomic.load32_u, TokenType::AtomicLoad, Opcode::I64AtomicLoad32U
i64.atomic.load8_u, TokenType::AtomicLoad, Opcode::I64AtomicLoad8U
i64.atomic.load, TokenType::AtomicLoad, Opcode::I64AtomicLoad
i64.atomic.rmw16.add_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw16AddU
i64.atomic.rmw16.and_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw16AndU
i64.atomic.rmw16.cmpxchg_u, TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw16CmpxchgU
i64.atomic.rmw16.or_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw16OrU
i64.atomic.rmw16.sub_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw16SubU
i64.atomic.rmw16.xchg_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw16XchgU
i64.atomic.rmw16.xor_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw16XorU
i64.atomic.rmw32.add_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw32AddU
i64.atomic.rmw32.and_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw32AndU
i64.atomic.rmw32.cmpxchg_u, TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw32CmpxchgU
i64.atomic.rmw32.or_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw32OrU
i64.atomic.rmw32.sub_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw32SubU
i64.atomic.rmw32.xchg_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw32XchgU
i64.atomic.rmw32.xor_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw32XorU
i64.atomic.rmw8.add_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw8AddU
i64.atomic.rmw8.and_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw8AndU
i64.atomic.rmw8.cmpxchg_u, TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw8CmpxchgU
i64.atomic.rmw8.or_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw8OrU
i64.atomic.rmw8.sub_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw8SubU
i64.atomic.rmw8.xchg_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw8XchgU
i64.atomic.rmw8.xor_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw8XorU
i64.atomic.rmw.add, TokenType::AtomicRmw, Opcode::I64AtomicRmwAdd
i64.atomic.rmw.and, TokenType::AtomicRmw, Opcode::I64AtomicRmwAnd
i64.atomic.rmw.cmpxchg, TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmwCmpxchg
i64.atomic.rmw.or, TokenType::AtomicRmw, Opcode::I64AtomicRmwOr
i64.atomic.rmw.sub, TokenType::AtomicRmw, Opcode::I64AtomicRmwSub
i64.atomic.rmw.xchg, TokenType::AtomicRmw, Opcode::I64AtomicRmwXchg
i64.atomic.rmw.xor, TokenType::AtomicRmw, Opcode::I64AtomicRmwXor
i64.atomic.store16, TokenType::AtomicStore, Opcode::I64AtomicStore16
i64.atomic.store32, TokenType::AtomicStore, Opcode::I64AtomicStore32
i64.atomic.store8, TokenType::AtomicStore, Opcode::I64AtomicStore8
i64.atomic.store, TokenType::AtomicStore, Opcode::I64AtomicStore
i64.clz, TokenType::Unary, Opcode::I64Clz
i64.const, TokenType::Const, Opcode::I64Const
i64.ctz, TokenType::Unary, Opcode::I64Ctz
i64.div_s, TokenType::Binary, Opcode::I64DivS
i64.div_u, TokenType::Binary, Opcode::I64DivU
i64.eq, TokenType::Compare, Opcode::I64Eq
i64.eqz, TokenType::Convert, Opcode::I64Eqz
i64.extend16_s, TokenType::Unary, Opcode::I64Extend16S
i64.extend32_s, TokenType::Unary, Opcode::I64Extend32S
i64.extend8_s, TokenType::Unary, Opcode::I64Extend8S
i64.extend_i32_s, TokenType::Convert, Opcode::I64ExtendI32S
i64.extend_i32_u, TokenType::Convert, Opcode::I64ExtendI32U
i64.ge_s, TokenType::Compare, Opcode::I64GeS
i64.ge_u, TokenType::Compare, Opcode::I64GeU
i64.gt_s, TokenType::Compare, Opcode::I64GtS
i64.gt_u, TokenType::Compare, Opcode::I64GtU
i64.le_s, TokenType::Compare, Opcode::I64LeS
i64.le_u, TokenType::Compare, Opcode::I64LeU
i64.load16_s, TokenType::Load, Opcode::I64Load16S
i64.load16_u, TokenType::Load, Opcode::I64Load16U
i64.load32_s, TokenType::Load, Opcode::I64Load32S
i64.load32_u, TokenType::Load, Opcode::I64Load32U
i64.load8_s, TokenType::Load, Opcode::I64Load8S
i64.load8_u, TokenType::Load, Opcode::I64Load8U
i64.load, TokenType::Load, Opcode::I64Load
i64.lt_s, TokenType::Compare, Opcode::I64LtS
i64.lt_u, TokenType::Compare, Opcode::I64LtU
i64.mul, TokenType::Binary, Opcode::I64Mul
i64.ne, TokenType::Compare, Opcode::I64Ne
i64.or, TokenType::Binary, Opcode::I64Or
i64.popcnt, TokenType::Unary, Opcode::I64Popcnt
i64.reinterpret_f64, TokenType::Convert, Opcode::I64ReinterpretF64
i64.rem_s, TokenType::Binary, Opcode::I64RemS
i64.rem_u, TokenType::Binary, Opcode::I64RemU
i64.rotl, TokenType::Binary, Opcode::I64Rotl
i64.rotr, TokenType::Binary, Opcode::I64Rotr
i64.shl, TokenType::Binary, Opcode::I64Shl
i64.shr_s, TokenType::Binary, Opcode::I64ShrS
i64.shr_u, TokenType::Binary, Opcode::I64ShrU
i64.store16, TokenType::Store, Opcode::I64Store16
i64.store32, TokenType::Store, Opcode::I64Store32
i64.store8, TokenType::Store, Opcode::I64Store8
i64.store, TokenType::Store, Opcode::I64Store
i64.sub, TokenType::Binary, Opcode::I64Sub
i64.trunc_f32_s, TokenType::Convert, Opcode::I64TruncF32S
i64.trunc_f32_u, TokenType::Convert, Opcode::I64TruncF32U
i64.trunc_f64_s, TokenType::Convert, Opcode::I64TruncF64S
i64.trunc_f64_u, TokenType::Convert, Opcode::I64TruncF64U
i64.trunc_sat_f32_s, TokenType::Convert, Opcode::I64TruncSatF32S
i64.trunc_sat_f32_u, TokenType::Convert, Opcode::I64TruncSatF32U
i64.trunc_sat_f64_s, TokenType::Convert, Opcode::I64TruncSatF64S
i64.trunc_sat_f64_u, TokenType::Convert, Opcode::I64TruncSatF64U
i64, Type::I64
i64x2.add, TokenType::Binary, Opcode::I64X2Add
i64x2.extract_lane, TokenType::SimdLaneOp, Opcode::I64X2ExtractLane
v128.load32x2_s, TokenType::Load, Opcode::V128Load32X2S
v128.load32x2_u, TokenType::Load, Opcode::V128Load32X2U
i64x2.mul, TokenType::Binary, Opcode::I64X2Mul
i64x2.eq, TokenType::Binary, Opcode::I64X2Eq
i64x2.ne, TokenType::Binary, Opcode::I64X2Ne
i64x2.lt_s, TokenType::Binary, Opcode::I64X2LtS
i64x2.gt_s, TokenType::Binary, Opcode::I64X2GtS
i64x2.le_s, TokenType::Binary, Opcode::I64X2LeS
i64x2.ge_s, TokenType::Binary, Opcode::I64X2GeS
i64x2.abs, TokenType::Unary, Opcode::I64X2Abs
i64x2.neg, TokenType::Unary, Opcode::I64X2Neg
i64x2.all_true, TokenType::Unary, Opcode::I64X2AllTrue
i64x2.bitmask, TokenType::Unary, Opcode::I64X2Bitmask
i64x2.extend_low_i32x4_s, TokenType::Unary, Opcode::I64X2ExtendLowI32X4S
i64x2.extend_high_i32x4_s, TokenType::Unary, Opcode::I64X2ExtendHighI32X4S
i64x2.extend_low_i32x4_u, TokenType::Unary, Opcode::I64X2ExtendLowI32X4U
i64x2.extend_high_i32x4_u, TokenType::Unary, Opcode::I64X2ExtendHighI32X4U
i64x2.replace_lane, TokenType::SimdLaneOp, Opcode::I64X2ReplaceLane
i64x2.shl, TokenType::Binary, Opcode::I64X2Shl
i64x2.shr_s, TokenType::Binary, Opcode::I64X2ShrS
i64x2.shr_u, TokenType::Binary, Opcode::I64X2ShrU
i64x2.splat, TokenType::Unary, Opcode::I64X2Splat
i64x2.sub, TokenType::Binary, Opcode::I64X2Sub
i64x2.extmul_low_i32x4_s, TokenType::Binary, Opcode::I64X2ExtmulLowI32X4S
i64x2.extmul_high_i32x4_s, TokenType::Binary, Opcode::I64X2ExtmulHighI32X4S
i64x2.extmul_low_i32x4_u, TokenType::Binary, Opcode::I64X2ExtmulLowI32X4U
i64x2.extmul_high_i32x4_u, TokenType::Binary, Opcode::I64X2ExtmulHighI32X4U
i64x2, TokenType::I64X2
i64.xor, TokenType::Binary, Opcode::I64Xor
i8x16.abs, TokenType::Unary, Opcode::I8X16Abs
i8x16.add_sat_s, TokenType::Binary, Opcode::I8X16AddSatS
i8x16.add_sat_u, TokenType::Binary, Opcode::I8X16AddSatU
i8x16.add, TokenType::Binary, Opcode::I8X16Add
i8x16.all_true, TokenType::Unary, Opcode::I8X16AllTrue
i8x16.avgr_u, TokenType::Binary, Opcode::I8X16AvgrU
i8x16.bitmask, TokenType::Unary, Opcode::I8X16Bitmask
i8x16.eq, TokenType::Compare, Opcode::I8X16Eq
i8x16.extract_lane_s, TokenType::SimdLaneOp, Opcode::I8X16ExtractLaneS
i8x16.extract_lane_u, TokenType::SimdLaneOp, Opcode::I8X16ExtractLaneU
i8x16.ge_s, TokenType::Compare, Opcode::I8X16GeS
i8x16.ge_u, TokenType::Compare, Opcode::I8X16GeU
i8x16.gt_s, TokenType::Compare, Opcode::I8X16GtS
i8x16.gt_u, TokenType::Compare, Opcode::I8X16GtU
i8x16.le_s, TokenType::Compare, Opcode::I8X16LeS
i8x16.le_u, TokenType::Compare, Opcode::I8X16LeU
i8x16.lt_s, TokenType::Compare, Opcode::I8X16LtS
i8x16.lt_u, TokenType::Compare, Opcode::I8X16LtU
i8x16.max_s, TokenType::Binary, Opcode::I8X16MaxS
i8x16.max_u, TokenType::Binary, Opcode::I8X16MaxU
i8x16.min_s, TokenType::Binary, Opcode::I8X16MinS
i8x16.min_u, TokenType::Binary, Opcode::I8X16MinU
i8x16.narrow_i16x8_s, TokenType::Binary, Opcode::I8X16NarrowI16X8S
i8x16.narrow_i16x8_u, TokenType::Binary, Opcode::I8X16NarrowI16X8U
i8x16.neg, TokenType::Unary, Opcode::I8X16Neg
i8x16.popcnt, TokenType::Unary, Opcode::I8X16Popcnt
i8x16.ne, TokenType::Compare, Opcode::I8X16Ne
i8x16.replace_lane, TokenType::SimdLaneOp, Opcode::I8X16ReplaceLane
i8x16.shl, TokenType::Binary, Opcode::I8X16Shl
i8x16.shr_s, TokenType::Binary, Opcode::I8X16ShrS
i8x16.shr_u, TokenType::Binary, Opcode::I8X16ShrU
i8x16.splat, TokenType::Unary, Opcode::I8X16Splat
i8x16.sub_sat_s, TokenType::Binary, Opcode::I8X16SubSatS
i8x16.sub_sat_u, TokenType::Binary, Opcode::I8X16SubSatU
i8x16.sub, TokenType::Binary, Opcode::I8X16Sub
i8x16, TokenType::I8X16
if, TokenType::If, Opcode::If
import, TokenType::Import
input, TokenType::Input
invoke, TokenType::Invoke
item, TokenType::Item
local.get, TokenType::LocalGet, Opcode::LocalGet
local.set, TokenType::LocalSet, Opcode::LocalSet
local.tee, TokenType::LocalTee, Opcode::LocalTee
local, TokenType::Local
loop, TokenType::Loop, Opcode::Loop
memory.atomic.notify, TokenType::AtomicNotify, Opcode::MemoryAtomicNotify
memory.atomic.wait32, TokenType::AtomicWait, Opcode::MemoryAtomicWait32
memory.atomic.wait64, TokenType::AtomicWait, Opcode::MemoryAtomicWait64
memory.copy, TokenType::MemoryCopy, Opcode::MemoryCopy
memory.fill, TokenType::MemoryFill, Opcode::MemoryFill
memory.grow, TokenType::MemoryGrow, Opcode::MemoryGrow
memory.init, TokenType::MemoryInit, Opcode::MemoryInit
memory.size, TokenType::MemorySize, Opcode::MemorySize
memory, TokenType::Memory
module, TokenType::Module
mut, TokenType::Mut
nan:arithmetic, TokenType::NanArithmetic
nan:canonical, TokenType::NanCanonical
nop, TokenType::Nop, Opcode::Nop
offset, TokenType::Offset
output, TokenType::Output
param, TokenType::Param
quote, TokenType::Quote
ref.extern, TokenType::RefExtern
ref.func, TokenType::RefFunc, Opcode::RefFunc
ref.is_null, TokenType::RefIsNull, Opcode::RefIsNull
ref.null, TokenType::RefNull, Opcode::RefNull
register, TokenType::Register
result, TokenType::Result
rethrow, TokenType::Rethrow, Opcode::Rethrow
return_call_indirect, TokenType::ReturnCallIndirect, Opcode::ReturnCallIndirect
return_call, TokenType::ReturnCall, Opcode::ReturnCall
return, TokenType::Return, Opcode::Return
select, TokenType::Select, Opcode::Select
shared, TokenType::Shared
start, TokenType::Start
struct, Type::Struct, TokenType::Struct
table.copy, TokenType::TableCopy, Opcode::TableCopy
table.fill, TokenType::TableFill, Opcode::TableFill
table.get, TokenType::TableGet, Opcode::TableGet
table.grow, TokenType::TableGrow, Opcode::TableGrow
table.init, TokenType::TableInit, Opcode::TableInit
table.set, TokenType::TableSet, Opcode::TableSet
table.size, TokenType::TableSize, Opcode::TableSize
table, TokenType::Table
then, TokenType::Then
throw, TokenType::Throw, Opcode::Throw
try, TokenType::Try, Opcode::Try
type, TokenType::Type
unreachable, TokenType::Unreachable, Opcode::Unreachable
v128.andnot, TokenType::Binary, Opcode::V128Andnot
v128.and, TokenType::Binary, Opcode::V128And
v128.bitselect, TokenType::Ternary, Opcode::V128BitSelect
v128.const, TokenType::Const, Opcode::V128Const
v128.load, TokenType::Load, Opcode::V128Load
v128.not, TokenType::Unary, Opcode::V128Not
v128.or, TokenType::Binary, Opcode::V128Or
v128.any_true, TokenType::Unary, Opcode::V128AnyTrue
v128.load32_zero, TokenType::Load, Opcode::V128Load32Zero
v128.load64_zero, TokenType::Load, Opcode::V128Load64Zero
v128.store, TokenType::Store, Opcode::V128Store
v128, Type::V128
v128.xor, TokenType::Binary, Opcode::V128Xor
v128.load16_splat, TokenType::Load, Opcode::V128Load16Splat
v128.load32_splat, TokenType::Load, Opcode::V128Load32Splat
v128.load64_splat, TokenType::Load, Opcode::V128Load64Splat
v128.load8_splat, TokenType::Load, Opcode::V128Load8Splat
v128.load8_lane, TokenType::SimdLoadLane, Opcode::V128Load8Lane
v128.load16_lane, TokenType::SimdLoadLane, Opcode::V128Load16Lane
v128.load32_lane, TokenType::SimdLoadLane, Opcode::V128Load32Lane
v128.load64_lane, TokenType::SimdLoadLane, Opcode::V128Load64Lane
v128.store8_lane, TokenType::SimdStoreLane, Opcode::V128Store8Lane
v128.store16_lane, TokenType::SimdStoreLane, Opcode::V128Store16Lane
v128.store32_lane, TokenType::SimdStoreLane, Opcode::V128Store32Lane
v128.store64_lane, TokenType::SimdStoreLane, Opcode::V128Store64Lane
i8x16.shuffle, TokenType::SimdShuffleOp, Opcode::I8X16Shuffle
i8x16.swizzle, TokenType::Binary, Opcode::I8X16Swizzle
# Deprecated names.
atomic.notify, TokenType::AtomicNotify, Opcode::MemoryAtomicNotify
i32.atomic.wait, TokenType::AtomicWait, Opcode::MemoryAtomicWait32
i64.atomic.wait, TokenType::AtomicWait, Opcode::MemoryAtomicWait64
anyfunc, Type::FuncRef
f32.convert_s/i32, TokenType::Convert, Opcode::F32ConvertI32S
f32.convert_s/i64, TokenType::Convert, Opcode::F32ConvertI64S
f32.convert_u/i32, TokenType::Convert, Opcode::F32ConvertI32U
f32.convert_u/i64, TokenType::Convert, Opcode::F32ConvertI64U
f32.demote/f64, TokenType::Convert, Opcode::F32DemoteF64
f32.reinterpret/i32, TokenType::Convert, Opcode::F32ReinterpretI32
f64.convert_s/i32, TokenType::Convert, Opcode::F64ConvertI32S
f64.convert_s/i64, TokenType::Convert, Opcode::F64ConvertI64S
f64.convert_u/i32, TokenType::Convert, Opcode::F64ConvertI32U
f64.convert_u/i64, TokenType::Convert, Opcode::F64ConvertI64U
f64.promote/f32, TokenType::Convert, Opcode::F64PromoteF32
f64.reinterpret/i64, TokenType::Convert, Opcode::F64ReinterpretI64
get_global, TokenType::GlobalGet, Opcode::GlobalGet
get_local, TokenType::LocalGet, Opcode::LocalGet
i32.reinterpret/f32, TokenType::Convert, Opcode::I32ReinterpretF32
i32.trunc_s/f32, TokenType::Convert, Opcode::I32TruncF32S
i32.trunc_s/f64, TokenType::Convert, Opcode::I32TruncF64S
i32.trunc_s:sat/f32, TokenType::Convert, Opcode::I32TruncSatF32S
i32.trunc_s:sat/f64, TokenType::Convert, Opcode::I32TruncSatF64S
i32.trunc_u/f32, TokenType::Convert, Opcode::I32TruncF32U
i32.trunc_u/f64, TokenType::Convert, Opcode::I32TruncF64U
i32.trunc_u:sat/f32, TokenType::Convert, Opcode::I32TruncSatF32U
i32.trunc_u:sat/f64, TokenType::Convert, Opcode::I32TruncSatF64U
i32.wrap/i64, TokenType::Convert, Opcode::I32WrapI64
i64.extend_s/i32, TokenType::Convert, Opcode::I64ExtendI32S
i64.extend_u/i32, TokenType::Convert, Opcode::I64ExtendI32U
i64.reinterpret/f64, TokenType::Convert, Opcode::I64ReinterpretF64
i64.trunc_s/f32, TokenType::Convert, Opcode::I64TruncF32S
i64.trunc_s/f64, TokenType::Convert, Opcode::I64TruncF64S
i64.trunc_s:sat/f32, TokenType::Convert, Opcode::I64TruncSatF32S
i64.trunc_s:sat/f64, TokenType::Convert, Opcode::I64TruncSatF64S
i64.trunc_u/f32, TokenType::Convert, Opcode::I64TruncF32U
i64.trunc_u/f64, TokenType::Convert, Opcode::I64TruncF64U
i64.trunc_u:sat/f32, TokenType::Convert, Opcode::I64TruncSatF32U
i64.trunc_u:sat/f64, TokenType::Convert, Opcode::I64TruncSatF64U
set_global, TokenType::GlobalSet, Opcode::GlobalSet
set_local, TokenType::LocalSet, Opcode::LocalSet
tee_local, TokenType::LocalTee, Opcode::LocalTee
unwind, TokenType::Unwind, Opcode::Unwind

View File

@@ -0,0 +1,152 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/lexer-source-line-finder.h"
#include <algorithm>
#include "src/lexer-source.h"
namespace wabt {
LexerSourceLineFinder::LexerSourceLineFinder(
std::unique_ptr<LexerSource> source)
: source_(std::move(source)),
next_line_start_(0),
last_cr_(false),
eof_(false) {
source_->Seek(0);
// Line 0 should not be used; but it makes indexing simpler.
line_ranges_.emplace_back(0, 0);
}
Result LexerSourceLineFinder::GetSourceLine(const Location& loc,
Offset max_line_length,
SourceLine* out_source_line) {
ColumnRange column_range(loc.first_column, loc.last_column);
OffsetRange original;
CHECK_RESULT(GetLineOffsets(loc.line, &original));
OffsetRange clamped =
ClampSourceLineOffsets(original, column_range, max_line_length);
bool has_start_ellipsis = original.start != clamped.start;
bool has_end_ellipsis = original.end != clamped.end;
out_source_line->column_offset = clamped.start - original.start;
if (has_start_ellipsis) {
out_source_line->line += "...";
clamped.start += 3;
}
if (has_end_ellipsis) {
clamped.end -= 3;
}
std::vector<char> read_line;
CHECK_RESULT(source_->ReadRange(clamped, &read_line));
out_source_line->line.append(read_line.begin(), read_line.end());
if (has_end_ellipsis) {
out_source_line->line += "...";
}
return Result::Ok;
}
bool LexerSourceLineFinder::IsLineCached(int line) const {
return static_cast<size_t>(line) < line_ranges_.size();
}
OffsetRange LexerSourceLineFinder::GetCachedLine(int line) const {
assert(IsLineCached(line));
return line_ranges_[line];
}
Result LexerSourceLineFinder::GetLineOffsets(int find_line,
OffsetRange* out_range) {
if (IsLineCached(find_line)) {
*out_range = GetCachedLine(find_line);
return Result::Ok;
}
const size_t kBufferSize = 1 << 16;
std::vector<char> buffer(kBufferSize);
assert(!line_ranges_.empty());
Offset buffer_file_offset = 0;
while (!IsLineCached(find_line) && !eof_) {
CHECK_RESULT(source_->Tell(&buffer_file_offset));
size_t read_size = source_->Fill(buffer.data(), buffer.size());
if (read_size < buffer.size()) {
eof_ = true;
}
for (auto iter = buffer.begin(), end = iter + read_size; iter < end;
++iter) {
if (*iter == '\n') {
// Don't include \n or \r in the line range.
Offset line_offset =
buffer_file_offset + (iter - buffer.begin()) - last_cr_;
line_ranges_.emplace_back(next_line_start_, line_offset);
next_line_start_ = line_offset + last_cr_ + 1;
}
last_cr_ = *iter == '\r';
}
if (eof_) {
// Add the final line as an empty range.
Offset end = buffer_file_offset + read_size;
line_ranges_.emplace_back(next_line_start_, end);
}
}
if (IsLineCached(find_line)) {
*out_range = GetCachedLine(find_line);
return Result::Ok;
} else {
assert(eof_);
return Result::Error;
}
}
// static
OffsetRange LexerSourceLineFinder::ClampSourceLineOffsets(
OffsetRange offset_range,
ColumnRange column_range,
Offset max_line_length) {
Offset line_length = offset_range.size();
if (line_length > max_line_length) {
size_t column_count = column_range.size();
size_t center_on;
if (column_count > max_line_length) {
// The column range doesn't fit, just center on first_column.
center_on = column_range.start - 1;
} else {
// the entire range fits, display it all in the center.
center_on = (column_range.start + column_range.end) / 2 - 1;
}
if (center_on > max_line_length / 2) {
offset_range.start += center_on - max_line_length / 2;
}
offset_range.start =
std::min(offset_range.start, offset_range.end - max_line_length);
offset_range.end = offset_range.start + max_line_length;
}
return offset_range;
}
} // namespace wabt

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_LEXER_SOURCE_LINE_FINDER_H_
#define WABT_LEXER_SOURCE_LINE_FINDER_H_
#include <memory>
#include <string>
#include <vector>
#include "src/common.h"
#include "src/lexer-source.h"
#include "src/range.h"
namespace wabt {
class LexerSourceLineFinder {
public:
struct SourceLine {
std::string line;
int column_offset;
};
explicit LexerSourceLineFinder(std::unique_ptr<LexerSource>);
Result GetSourceLine(const Location& loc,
Offset max_line_length,
SourceLine* out_source_line);
Result GetLineOffsets(int line, OffsetRange* out_offsets);
private:
static OffsetRange ClampSourceLineOffsets(OffsetRange line_offset_range,
ColumnRange column_range,
Offset max_line_length);
bool IsLineCached(int line) const;
OffsetRange GetCachedLine(int line) const;
std::unique_ptr<LexerSource> source_;
std::vector<OffsetRange> line_ranges_;
Offset next_line_start_;
bool last_cr_; // Last read character was a '\r' (carriage return).
bool eof_;
};
} // namespace wabt
#endif // WABT_LEXER_SOURCE_LINE_FINDER_H_

67
third_party/wasm2c/src/lexer-source.cc vendored Normal file
View File

@@ -0,0 +1,67 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/lexer-source.h"
#include <algorithm>
namespace wabt {
LexerSource::LexerSource(const void* data, Offset size)
: data_(data), size_(size), read_offset_(0) {}
std::unique_ptr<LexerSource> LexerSource::Clone() {
LexerSource* result = new LexerSource(data_, size_);
result->read_offset_ = read_offset_;
return std::unique_ptr<LexerSource>(result);
}
Result LexerSource::Tell(Offset* out_offset) {
*out_offset = read_offset_;
return Result::Ok;
}
size_t LexerSource::Fill(void* dest, Offset size) {
Offset read_size = std::min(size, size_ - read_offset_);
if (read_size > 0) {
const void* src = static_cast<const char*>(data_) + read_offset_;
memcpy(dest, src, read_size);
read_offset_ += read_size;
}
return read_size;
}
Result LexerSource::Seek(Offset offset) {
if (offset < size_) {
read_offset_ = offset;
return Result::Ok;
}
return Result::Error;
}
Result LexerSource::ReadRange(OffsetRange range, std::vector<char>* out_data) {
OffsetRange clamped = range;
clamped.start = std::min(clamped.start, size_);
clamped.end = std::min(clamped.end, size_);
if (clamped.size()) {
out_data->resize(clamped.size());
const void* src = static_cast<const char*>(data_) + clamped.start;
memcpy(out_data->data(), src, clamped.size());
}
return Result::Ok;
}
} // namespace wabt

53
third_party/wasm2c/src/lexer-source.h vendored Normal file
View File

@@ -0,0 +1,53 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_LEXER_SOURCE_H_
#define WABT_LEXER_SOURCE_H_
#include <cstddef>
#include <memory>
#include <string>
#include <vector>
#include "src/common.h"
#include "src/range.h"
namespace wabt {
class LexerSource {
public:
LexerSource(const void* data, Offset size);
std::unique_ptr<LexerSource> Clone();
Result Tell(Offset* out_offset);
size_t Fill(void* dest, size_t size);
Result ReadRange(OffsetRange, std::vector<char>* out_data);
Result Seek(Offset offset);
WABT_DISALLOW_COPY_AND_ASSIGN(LexerSource);
const void* data() { return data_; }
Offset size() { return size_; }
private:
const void* data_;
Offset size_;
Offset read_offset_;
};
} // namespace wabt
#endif // WABT_LEXER_SOURCE_H_

830
third_party/wasm2c/src/literal.cc vendored Normal file
View File

@@ -0,0 +1,830 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/literal.h"
#include <cassert>
#include <cerrno>
#include <cinttypes>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <limits>
#include <type_traits>
namespace wabt {
namespace {
template <typename T>
struct FloatTraitsBase {};
// The "PlusOne" values are used because normal IEEE floats have an implicit
// leading one, so they have an additional bit of precision.
template <>
struct FloatTraitsBase<float> {
typedef uint32_t Uint;
static constexpr int kBits = sizeof(Uint) * 8;
static constexpr int kSigBits = 23;
static constexpr float kHugeVal = HUGE_VALF;
static constexpr int kMaxHexBufferSize = WABT_MAX_FLOAT_HEX;
static float Strto(const char* s, char** endptr) { return strtof(s, endptr); }
};
template <>
struct FloatTraitsBase<double> {
typedef uint64_t Uint;
static constexpr int kBits = sizeof(Uint) * 8;
static constexpr int kSigBits = 52;
static constexpr float kHugeVal = HUGE_VAL;
static constexpr int kMaxHexBufferSize = WABT_MAX_DOUBLE_HEX;
static double Strto(const char* s, char** endptr) {
return strtod(s, endptr);
}
};
template <typename T>
struct FloatTraits : FloatTraitsBase<T> {
typedef typename FloatTraitsBase<T>::Uint Uint;
using FloatTraitsBase<T>::kBits;
using FloatTraitsBase<T>::kSigBits;
static constexpr int kExpBits = kBits - kSigBits - 1;
static constexpr int kSignShift = kBits - 1;
static constexpr Uint kSigMask = (Uint(1) << kSigBits) - 1;
static constexpr int kSigPlusOneBits = kSigBits + 1;
static constexpr Uint kSigPlusOneMask = (Uint(1) << kSigPlusOneBits) - 1;
static constexpr int kExpMask = (1 << kExpBits) - 1;
static constexpr int kMaxExp = 1 << (kExpBits - 1);
static constexpr int kMinExp = -kMaxExp + 1;
static constexpr int kExpBias = -kMinExp;
static constexpr Uint kQuietNanTag = Uint(1) << (kSigBits - 1);
};
template <typename T>
class FloatParser {
public:
typedef FloatTraits<T> Traits;
typedef typename Traits::Uint Uint;
typedef T Float;
static Result Parse(LiteralType,
const char* s,
const char* end,
Uint* out_bits);
private:
static bool StringStartsWith(const char* start,
const char* end,
const char* prefix);
static Uint Make(bool sign, int exp, Uint sig);
static Uint ShiftAndRoundToNearest(Uint significand,
int shift,
bool seen_trailing_non_zero);
static Result ParseFloat(const char* s, const char* end, Uint* out_bits);
static Result ParseNan(const char* s, const char* end, Uint* out_bits);
static Result ParseHex(const char* s, const char* end, Uint* out_bits);
static void ParseInfinity(const char* s, const char* end, Uint* out_bits);
};
template <typename T>
class FloatWriter {
public:
typedef FloatTraits<T> Traits;
typedef typename Traits::Uint Uint;
static void WriteHex(char* out, size_t size, Uint bits);
};
// Return 1 if the non-NULL-terminated string starting with |start| and ending
// with |end| starts with the NULL-terminated string |prefix|.
template <typename T>
// static
bool FloatParser<T>::StringStartsWith(const char* start,
const char* end,
const char* prefix) {
while (start < end && *prefix) {
if (*start != *prefix) {
return false;
}
start++;
prefix++;
}
return *prefix == 0;
}
// static
template <typename T>
Result FloatParser<T>::ParseFloat(const char* s,
const char* end,
Uint* out_bits) {
// Here is the normal behavior for strtof/strtod:
//
// input | errno | output |
// ---------------------------------
// overflow | ERANGE | +-HUGE_VAL |
// underflow | ERANGE | 0.0 |
// otherwise | 0 | value |
//
// So normally we need to clear errno before calling strto{f,d}, and check
// afterward whether it was set to ERANGE.
//
// glibc seems to have a bug where
// strtof("340282356779733661637539395458142568448") will return HUGE_VAL,
// but will not set errno to ERANGE. Since this function is only called when
// we know that we have parsed a "normal" number (i.e. not "inf"), we know
// that if we ever get HUGE_VAL, it must be overflow.
//
// The WebAssembly spec also ignores underflow, so we don't need to check for
// ERANGE at all.
// WebAssembly floats can contain underscores, but strto* can't parse those,
// so remove them first.
assert(s <= end);
const size_t kBufferSize = end - s + 1; // +1 for \0.
char* buffer = static_cast<char*>(alloca(kBufferSize));
auto buffer_end =
std::copy_if(s, end, buffer, [](char c) -> bool { return c != '_'; });
assert(buffer_end < buffer + kBufferSize);
*buffer_end = 0;
char* endptr;
Float value = Traits::Strto(buffer, &endptr);
if (endptr != buffer_end ||
(value == Traits::kHugeVal || value == -Traits::kHugeVal)) {
return Result::Error;
}
memcpy(out_bits, &value, sizeof(value));
return Result::Ok;
}
// static
template <typename T>
typename FloatParser<T>::Uint FloatParser<T>::Make(bool sign,
int exp,
Uint sig) {
assert(exp >= Traits::kMinExp && exp <= Traits::kMaxExp);
assert(sig <= Traits::kSigMask);
return (Uint(sign) << Traits::kSignShift) |
(Uint(exp + Traits::kExpBias) << Traits::kSigBits) | sig;
}
// static
template <typename T>
typename FloatParser<T>::Uint FloatParser<T>::ShiftAndRoundToNearest(
Uint significand,
int shift,
bool seen_trailing_non_zero) {
assert(shift > 0);
// Round ties to even.
if ((significand & (Uint(1) << shift)) || seen_trailing_non_zero) {
significand += Uint(1) << (shift - 1);
}
significand >>= shift;
return significand;
}
// static
template <typename T>
Result FloatParser<T>::ParseNan(const char* s,
const char* end,
Uint* out_bits) {
bool is_neg = false;
if (*s == '-') {
is_neg = true;
s++;
} else if (*s == '+') {
s++;
}
assert(StringStartsWith(s, end, "nan"));
s += 3;
Uint tag;
if (s != end) {
tag = 0;
assert(StringStartsWith(s, end, ":0x"));
s += 3;
for (; s < end; ++s) {
if (*s == '_') {
continue;
}
uint32_t digit;
CHECK_RESULT(ParseHexdigit(*s, &digit));
tag = tag * 16 + digit;
// Check for overflow.
if (tag > Traits::kSigMask) {
return Result::Error;
}
}
// NaN cannot have a zero tag, that is reserved for infinity.
if (tag == 0) {
return Result::Error;
}
} else {
tag = Traits::kQuietNanTag;
}
*out_bits = Make(is_neg, Traits::kMaxExp, tag);
return Result::Ok;
}
// static
template <typename T>
Result FloatParser<T>::ParseHex(const char* s,
const char* end,
Uint* out_bits) {
bool is_neg = false;
if (*s == '-') {
is_neg = true;
s++;
} else if (*s == '+') {
s++;
}
assert(StringStartsWith(s, end, "0x"));
s += 2;
// Loop over the significand; everything up to the 'p'.
// This code is a bit nasty because we want to support extra zeroes anywhere
// without having to use many significand bits.
// e.g.
// 0x00000001.0p0 => significand = 1, significand_exponent = 0
// 0x10000000.0p0 => significand = 1, significand_exponent = 28
// 0x0.000001p0 => significand = 1, significand_exponent = -24
bool seen_dot = false;
bool seen_trailing_non_zero = false;
Uint significand = 0;
int significand_exponent = 0; // Exponent adjustment due to dot placement.
for (; s < end; ++s) {
uint32_t digit;
if (*s == '_') {
continue;
} else if (*s == '.') {
seen_dot = true;
} else if (Succeeded(ParseHexdigit(*s, &digit))) {
if (Traits::kBits - Clz(significand) <= Traits::kSigPlusOneBits) {
significand = (significand << 4) + digit;
if (seen_dot) {
significand_exponent -= 4;
}
} else {
if (!seen_trailing_non_zero && digit != 0) {
seen_trailing_non_zero = true;
}
if (!seen_dot) {
significand_exponent += 4;
}
}
} else {
break;
}
}
if (significand == 0) {
// 0 or -0.
*out_bits = Make(is_neg, Traits::kMinExp, 0);
return Result::Ok;
}
int exponent = 0;
bool exponent_is_neg = false;
if (s < end) {
assert(*s == 'p' || *s == 'P');
s++;
// Exponent is always positive, but significand_exponent is signed.
// significand_exponent_add is negated if exponent will be negative, so it
// can be easily summed to see if the exponent is too large (see below).
int significand_exponent_add = 0;
if (*s == '-') {
exponent_is_neg = true;
significand_exponent_add = -significand_exponent;
s++;
} else if (*s == '+') {
s++;
significand_exponent_add = significand_exponent;
}
for (; s < end; ++s) {
if (*s == '_') {
continue;
}
uint32_t digit = (*s - '0');
assert(digit <= 9);
exponent = exponent * 10 + digit;
if (exponent + significand_exponent_add >= Traits::kMaxExp) {
break;
}
}
}
if (exponent_is_neg) {
exponent = -exponent;
}
int significand_bits = Traits::kBits - Clz(significand);
// -1 for the implicit 1 bit of the significand.
exponent += significand_exponent + significand_bits - 1;
if (exponent <= Traits::kMinExp) {
// Maybe subnormal.
auto update_seen_trailing_non_zero = [&](int shift) {
assert(shift > 0);
auto mask = (Uint(1) << (shift - 1)) - 1;
seen_trailing_non_zero |= (significand & mask) != 0;
};
// Normalize significand.
if (significand_bits > Traits::kSigBits) {
int shift = significand_bits - Traits::kSigBits;
update_seen_trailing_non_zero(shift);
significand >>= shift;
} else if (significand_bits < Traits::kSigBits) {
significand <<= (Traits::kSigBits - significand_bits);
}
int shift = Traits::kMinExp - exponent;
if (shift <= Traits::kSigBits) {
if (shift) {
update_seen_trailing_non_zero(shift);
significand =
ShiftAndRoundToNearest(significand, shift, seen_trailing_non_zero) &
Traits::kSigMask;
}
exponent = Traits::kMinExp;
if (significand != 0) {
*out_bits = Make(is_neg, exponent, significand);
return Result::Ok;
}
}
// Not subnormal, too small; return 0 or -0.
*out_bits = Make(is_neg, Traits::kMinExp, 0);
} else {
// Maybe Normal value.
if (significand_bits > Traits::kSigPlusOneBits) {
significand = ShiftAndRoundToNearest(
significand, significand_bits - Traits::kSigPlusOneBits,
seen_trailing_non_zero);
if (significand > Traits::kSigPlusOneMask) {
exponent++;
}
} else if (significand_bits < Traits::kSigPlusOneBits) {
significand <<= (Traits::kSigPlusOneBits - significand_bits);
}
if (exponent >= Traits::kMaxExp) {
// Would be inf or -inf, but the spec doesn't allow rounding hex-floats to
// infinity.
return Result::Error;
}
*out_bits = Make(is_neg, exponent, significand & Traits::kSigMask);
}
return Result::Ok;
}
// static
template <typename T>
void FloatParser<T>::ParseInfinity(const char* s,
const char* end,
Uint* out_bits) {
bool is_neg = false;
if (*s == '-') {
is_neg = true;
s++;
} else if (*s == '+') {
s++;
}
assert(StringStartsWith(s, end, "inf"));
*out_bits = Make(is_neg, Traits::kMaxExp, 0);
}
// static
template <typename T>
Result FloatParser<T>::Parse(LiteralType literal_type,
const char* s,
const char* end,
Uint* out_bits) {
#if COMPILER_IS_MSVC
if (literal_type == LiteralType::Int && StringStartsWith(s, end, "0x")) {
// Some MSVC crt implementation of strtof doesn't support hex strings
literal_type = LiteralType::Hexfloat;
}
#endif
switch (literal_type) {
case LiteralType::Int:
case LiteralType::Float:
return ParseFloat(s, end, out_bits);
case LiteralType::Hexfloat:
return ParseHex(s, end, out_bits);
case LiteralType::Infinity:
ParseInfinity(s, end, out_bits);
return Result::Ok;
case LiteralType::Nan:
return ParseNan(s, end, out_bits);
}
WABT_UNREACHABLE;
}
// static
template <typename T>
void FloatWriter<T>::WriteHex(char* out, size_t size, Uint bits) {
static constexpr int kNumNybbles = Traits::kBits / 4;
static constexpr int kTopNybbleShift = Traits::kBits - 4;
static constexpr Uint kTopNybble = Uint(0xf) << kTopNybbleShift;
static const char s_hex_digits[] = "0123456789abcdef";
char buffer[Traits::kMaxHexBufferSize];
char* p = buffer;
bool is_neg = (bits >> Traits::kSignShift);
int exp = ((bits >> Traits::kSigBits) & Traits::kExpMask) - Traits::kExpBias;
Uint sig = bits & Traits::kSigMask;
if (is_neg) {
*p++ = '-';
}
if (exp == Traits::kMaxExp) {
// Infinity or nan.
if (sig == 0) {
strcpy(p, "inf");
p += 3;
} else {
strcpy(p, "nan");
p += 3;
if (sig != Traits::kQuietNanTag) {
strcpy(p, ":0x");
p += 3;
// Skip leading zeroes.
int num_nybbles = kNumNybbles;
while ((sig & kTopNybble) == 0) {
sig <<= 4;
num_nybbles--;
}
while (num_nybbles) {
Uint nybble = (sig >> kTopNybbleShift) & 0xf;
*p++ = s_hex_digits[nybble];
sig <<= 4;
--num_nybbles;
}
}
}
} else {
bool is_zero = sig == 0 && exp == Traits::kMinExp;
strcpy(p, "0x");
p += 2;
*p++ = is_zero ? '0' : '1';
// Shift sig up so the top 4-bits are at the top of the Uint.
sig <<= Traits::kBits - Traits::kSigBits;
if (sig) {
if (exp == Traits::kMinExp) {
// Subnormal; shift the significand up, and shift out the implicit 1.
Uint leading_zeroes = Clz(sig);
if (leading_zeroes < Traits::kSignShift) {
sig <<= leading_zeroes + 1;
} else {
sig = 0;
}
exp -= leading_zeroes;
}
*p++ = '.';
while (sig) {
int nybble = (sig >> kTopNybbleShift) & 0xf;
*p++ = s_hex_digits[nybble];
sig <<= 4;
}
}
*p++ = 'p';
if (is_zero) {
strcpy(p, "+0");
p += 2;
} else {
if (exp < 0) {
*p++ = '-';
exp = -exp;
} else {
*p++ = '+';
}
if (exp >= 1000) {
*p++ = '1';
}
if (exp >= 100) {
*p++ = '0' + (exp / 100) % 10;
}
if (exp >= 10) {
*p++ = '0' + (exp / 10) % 10;
}
*p++ = '0' + exp % 10;
}
}
size_t len = p - buffer;
if (len >= size) {
len = size - 1;
}
memcpy(out, buffer, len);
out[len] = '\0';
}
} // end anonymous namespace
Result ParseHexdigit(char c, uint32_t* out) {
if (static_cast<unsigned int>(c - '0') <= 9) {
*out = c - '0';
return Result::Ok;
} else if (static_cast<unsigned int>(c - 'a') < 6) {
*out = 10 + (c - 'a');
return Result::Ok;
} else if (static_cast<unsigned int>(c - 'A') < 6) {
*out = 10 + (c - 'A');
return Result::Ok;
}
return Result::Error;
}
Result ParseUint64(const char* s, const char* end, uint64_t* out) {
if (s == end) {
return Result::Error;
}
uint64_t value = 0;
if (*s == '0' && s + 1 < end && s[1] == 'x') {
s += 2;
if (s == end) {
return Result::Error;
}
constexpr uint64_t kMaxDiv16 = UINT64_MAX / 16;
constexpr uint64_t kMaxMod16 = UINT64_MAX % 16;
for (; s < end; ++s) {
uint32_t digit;
if (*s == '_') {
continue;
}
CHECK_RESULT(ParseHexdigit(*s, &digit));
// Check for overflow.
if (value > kMaxDiv16 || (value == kMaxDiv16 && digit > kMaxMod16)) {
return Result::Error;
}
value = value * 16 + digit;
}
} else {
constexpr uint64_t kMaxDiv10 = UINT64_MAX / 10;
constexpr uint64_t kMaxMod10 = UINT64_MAX % 10;
for (; s < end; ++s) {
if (*s == '_') {
continue;
}
uint32_t digit = (*s - '0');
if (digit > 9) {
return Result::Error;
}
// Check for overflow.
if (value > kMaxDiv10 || (value == kMaxDiv10 && digit > kMaxMod10)) {
return Result::Error;
}
value = value * 10 + digit;
}
}
if (s != end) {
return Result::Error;
}
*out = value;
return Result::Ok;
}
Result ParseInt64(const char* s,
const char* end,
uint64_t* out,
ParseIntType parse_type) {
bool has_sign = false;
if (*s == '-' || *s == '+') {
if (parse_type == ParseIntType::UnsignedOnly) {
return Result::Error;
}
if (*s == '-') {
has_sign = true;
}
s++;
}
uint64_t value = 0;
Result result = ParseUint64(s, end, &value);
if (has_sign) {
// abs(INT64_MIN) == INT64_MAX + 1.
if (value > static_cast<uint64_t>(INT64_MAX) + 1) {
return Result::Error;
}
value = UINT64_MAX - value + 1;
}
*out = value;
return result;
}
namespace {
uint32_t AddWithCarry(uint32_t x, uint32_t y, uint32_t* carry) {
// Increments *carry if the addition overflows, otherwise leaves carry alone.
if ((0xffffffff - x) < y) ++*carry;
return x + y;
}
void Mul10(v128* v) {
// Multiply-by-10 decomposes into (x << 3) + (x << 1). We implement those
// operations with carrying from smaller quads of the v128 to the larger
// quads.
constexpr uint32_t kTopThreeBits = 0xe0000000;
constexpr uint32_t kTopBit = 0x80000000;
uint32_t carry_into_v1 =
((v->u32(0) & kTopThreeBits) >> 29) + ((v->u32(0) & kTopBit) >> 31);
v->set_u32(0, AddWithCarry(v->u32(0) << 3, v->u32(0) << 1, &carry_into_v1));
uint32_t carry_into_v2 =
((v->u32(1) & kTopThreeBits) >> 29) + ((v->u32(1) & kTopBit) >> 31);
v->set_u32(1, AddWithCarry(v->u32(1) << 3, v->u32(1) << 1, &carry_into_v2));
v->set_u32(1, AddWithCarry(v->u32(1), carry_into_v1, &carry_into_v2));
uint32_t carry_into_v3 =
((v->u32(2) & kTopThreeBits) >> 29) + ((v->u32(2) & kTopBit) >> 31);
v->set_u32(2, AddWithCarry(v->u32(2) << 3, v->u32(2) << 1, &carry_into_v3));
v->set_u32(2, AddWithCarry(v->u32(2), carry_into_v2, &carry_into_v3));
v->set_u32(3, v->u32(3) * 10 + carry_into_v3);
}
}
Result ParseUint128(const char* s,
const char* end,
v128* out) {
if (s == end) {
return Result::Error;
}
out->set_zero();
while (true) {
uint32_t digit = (*s - '0');
if (digit > 9) {
return Result::Error;
}
uint32_t carry_into_v1 = 0;
uint32_t carry_into_v2 = 0;
uint32_t carry_into_v3 = 0;
uint32_t overflow = 0;
out->set_u32(0, AddWithCarry(out->u32(0), digit, &carry_into_v1));
out->set_u32(1, AddWithCarry(out->u32(1), carry_into_v1, &carry_into_v2));
out->set_u32(2, AddWithCarry(out->u32(2), carry_into_v2, &carry_into_v3));
out->set_u32(3, AddWithCarry(out->u32(3), carry_into_v3, &overflow));
if (overflow) {
return Result::Error;
}
++s;
if (s == end) {
break;
}
Mul10(out);
}
return Result::Ok;
}
template <typename U>
Result ParseInt(const char* s,
const char* end,
U* out,
ParseIntType parse_type) {
typedef typename std::make_signed<U>::type S;
uint64_t value;
bool has_sign = false;
if (*s == '-' || *s == '+') {
if (parse_type == ParseIntType::UnsignedOnly) {
return Result::Error;
}
if (*s == '-') {
has_sign = true;
}
s++;
}
CHECK_RESULT(ParseUint64(s, end, &value));
if (has_sign) {
// abs(INTN_MIN) == INTN_MAX + 1.
if (value > static_cast<uint64_t>(std::numeric_limits<S>::max()) + 1) {
return Result::Error;
}
value = std::numeric_limits<U>::max() - value + 1;
} else {
if (value > static_cast<uint64_t>(std::numeric_limits<U>::max())) {
return Result::Error;
}
}
*out = static_cast<U>(value);
return Result::Ok;
}
Result ParseInt8(const char* s,
const char* end,
uint8_t* out,
ParseIntType parse_type) {
return ParseInt(s, end, out, parse_type);
}
Result ParseInt16(const char* s,
const char* end,
uint16_t* out,
ParseIntType parse_type) {
return ParseInt(s, end, out, parse_type);
}
Result ParseInt32(const char* s,
const char* end,
uint32_t* out,
ParseIntType parse_type) {
return ParseInt(s, end, out, parse_type);
}
Result ParseFloat(LiteralType literal_type,
const char* s,
const char* end,
uint32_t* out_bits) {
return FloatParser<float>::Parse(literal_type, s, end, out_bits);
}
Result ParseDouble(LiteralType literal_type,
const char* s,
const char* end,
uint64_t* out_bits) {
return FloatParser<double>::Parse(literal_type, s, end, out_bits);
}
void WriteFloatHex(char* buffer, size_t size, uint32_t bits) {
return FloatWriter<float>::WriteHex(buffer, size, bits);
}
void WriteDoubleHex(char* buffer, size_t size, uint64_t bits) {
return FloatWriter<double>::WriteHex(buffer, size, bits);
}
void WriteUint128(char* buffer, size_t size, v128 bits) {
uint64_t digits;
uint64_t remainder;
char reversed_buffer[40];
size_t len = 0;
do {
remainder = bits.u32(3);
for (int i = 3; i != 0; --i) {
digits = remainder / 10;
remainder = ((remainder - digits * 10) << 32) + bits.u32(i-1);
bits.set_u32(i, digits);
}
digits = remainder / 10;
remainder = remainder - digits * 10;
bits.set_u32(0, digits);
char remainder_buffer[21];
snprintf(remainder_buffer, 21, "%" PRIu64, remainder);
int remainder_buffer_len = strlen(remainder_buffer);
assert(len + remainder_buffer_len < sizeof(reversed_buffer));
memcpy(&reversed_buffer[len], remainder_buffer, remainder_buffer_len);
len += remainder_buffer_len;
} while (!bits.is_zero());
size_t truncated_tail = 0;
if (len >= size) {
truncated_tail = len - size + 1;
len = size - 1;
}
std::reverse_copy(reversed_buffer + truncated_tail,
reversed_buffer + len + truncated_tail,
buffer);
buffer[len] = '\0';
}
} // namespace wabt

84
third_party/wasm2c/src/literal.h vendored Normal file
View File

@@ -0,0 +1,84 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_LITERAL_H_
#define WABT_LITERAL_H_
#include <cstdint>
#include "src/common.h"
namespace wabt {
// These functions all return Result::Ok on success and Result::Error on
// failure.
//
// NOTE: the functions are written for use with wast-lexer, assuming that the
// literal has already matched the patterns defined there. As a result, the
// only validation that is done is for overflow, not for otherwise bogus input.
enum class LiteralType {
Int,
Float,
Hexfloat,
Infinity,
Nan,
};
enum class ParseIntType {
UnsignedOnly = 0,
SignedAndUnsigned = 1,
};
/* Size of char buffer required to hold hex representation of a float/double */
#define WABT_MAX_FLOAT_HEX 20
#define WABT_MAX_DOUBLE_HEX 40
Result ParseHexdigit(char c, uint32_t* out);
Result ParseInt8(const char* s,
const char* end,
uint8_t* out,
ParseIntType parse_type);
Result ParseInt16(const char* s,
const char* end,
uint16_t* out,
ParseIntType parse_type);
Result ParseInt32(const char* s,
const char* end,
uint32_t* out,
ParseIntType parse_type);
Result ParseInt64(const char* s,
const char* end,
uint64_t* out,
ParseIntType parse_type);
Result ParseUint64(const char* s, const char* end, uint64_t* out);
Result ParseUint128(const char* s, const char* end, v128* out);
Result ParseFloat(LiteralType literal_type,
const char* s,
const char* end,
uint32_t* out_bits);
Result ParseDouble(LiteralType literal_type,
const char* s,
const char* end,
uint64_t* out_bits);
void WriteFloatHex(char* buffer, size_t size, uint32_t bits);
void WriteDoubleHex(char* buffer, size_t size, uint64_t bits);
void WriteUint128(char* buffer, size_t size, v128 bits);
} // namespace wabt
#endif /* WABT_LITERAL_H_ */

42
third_party/wasm2c/src/make-unique.h vendored Normal file
View File

@@ -0,0 +1,42 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_MAKE_UNIQUE_H_
#define WABT_MAKE_UNIQUE_H_
#include <memory>
namespace wabt {
// This is named MakeUnique instead of make_unique because make_unique has the
// potential to conflict with std::make_unique if it is defined.
//
// On gcc/clang, we currently compile with c++11, which doesn't define
// std::make_unique, but on MSVC the newest C++ version is always used, which
// includes std::make_unique. If an argument from the std namespace is used, it
// will cause ADL to find std::make_unique, and an unqualified call to
// make_unique will be ambiguous. We can work around this by fully qualifying
// the call (i.e. wabt::make_unique), but it's simpler to just use a different
// name. It's also more consistent with other names in the wabt namespace,
// which use CamelCase.
template <typename T, typename... Args>
std::unique_ptr<T> MakeUnique(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
} // namespace wabt
#endif // WABT_MAKE_UNIQUE_H_

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2018 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/opcode-code-table.h"
#include "config.h"
#include <stdint.h>
typedef enum WabtOpcodeEnum {
#define WABT_OPCODE(rtype, type1, type2, type3, mem_size, prefix, code, Name, \
text, decomp) \
Name,
#include "opcode.def"
#undef WABT_OPCODE
Invalid,
} WabtOpcodeEnum;
WABT_STATIC_ASSERT(Invalid <= WABT_OPCODE_CODE_TABLE_SIZE);
/* The array index calculated below must match the one in Opcode::FromCode. */
uint32_t WabtOpcodeCodeTable[WABT_OPCODE_CODE_TABLE_SIZE] = {
#define WABT_OPCODE(rtype, type1, type2, type3, mem_size, prefix, code, Name, \
text, decomp) \
[(prefix << 8) + code] = Name,
#include "opcode.def"
#undef WABT_OPCODE
};

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2018 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_OPCODE_CODE_TABLE_H_
#define WABT_OPCODE_CODE_TABLE_H_
#include <stdlib.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define WABT_OPCODE_CODE_TABLE_SIZE 65536
/* This structure is defined in C because C++ doesn't (yet) allow you to use
* designated array initializers, i.e. [10] = {foo}.
*/
extern uint32_t WabtOpcodeCodeTable[WABT_OPCODE_CODE_TABLE_SIZE];
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* WABT_OPCODE_CODE_TABLE_H_ */

405
third_party/wasm2c/src/opcode.cc vendored Normal file
View File

@@ -0,0 +1,405 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/opcode.h"
#include "src/feature.h"
namespace wabt {
// static
Opcode::Info Opcode::infos_[] = {
#define WABT_OPCODE(rtype, type1, type2, type3, mem_size, prefix, code, Name, \
text, decomp) \
{text, decomp, Type::rtype, {Type::type1, Type::type2, Type::type3}, \
mem_size, prefix, code, PrefixCode(prefix, code)},
#include "src/opcode.def"
#undef WABT_OPCODE
{"<invalid>", "", Type::Void, {Type::Void, Type::Void, Type::Void}, 0, 0, 0, 0},
};
#define WABT_OPCODE(rtype, type1, type2, type3, mem_size, prefix, code, Name, \
text, decomp) \
/* static */ Opcode Opcode::Name##_Opcode(Opcode::Name);
#include "src/opcode.def"
#undef WABT_OPCODE
Opcode::Info Opcode::GetInfo() const {
if (enum_ < Invalid) {
return infos_[enum_];
}
Info invalid_info = infos_[Opcode::Invalid];
DecodeInvalidOpcode(enum_, &invalid_info.prefix, &invalid_info.code);
invalid_info.prefix_code = PrefixCode(invalid_info.prefix, invalid_info.code);
return invalid_info;
}
bool Opcode::IsNaturallyAligned(Address alignment) const {
Address opcode_align = GetMemorySize();
return alignment == WABT_USE_NATURAL_ALIGNMENT || alignment == opcode_align;
}
Address Opcode::GetAlignment(Address alignment) const {
if (alignment == WABT_USE_NATURAL_ALIGNMENT) {
return GetMemorySize();
}
return alignment;
}
bool Opcode::IsEnabled(const Features& features) const {
switch (enum_) {
case Opcode::Try:
case Opcode::Catch:
case Opcode::Unwind:
case Opcode::Delegate:
case Opcode::Throw:
case Opcode::Rethrow:
return features.exceptions_enabled();
case Opcode::ReturnCallIndirect:
case Opcode::ReturnCall:
return features.tail_call_enabled();
case Opcode::I32TruncSatF32S:
case Opcode::I32TruncSatF32U:
case Opcode::I32TruncSatF64S:
case Opcode::I32TruncSatF64U:
case Opcode::I64TruncSatF32S:
case Opcode::I64TruncSatF32U:
case Opcode::I64TruncSatF64S:
case Opcode::I64TruncSatF64U:
return features.sat_float_to_int_enabled();
case Opcode::I32Extend8S:
case Opcode::I32Extend16S:
case Opcode::I64Extend8S:
case Opcode::I64Extend16S:
case Opcode::I64Extend32S:
return features.sign_extension_enabled();
case Opcode::MemoryAtomicNotify:
case Opcode::MemoryAtomicWait32:
case Opcode::MemoryAtomicWait64:
case Opcode::AtomicFence:
case Opcode::I32AtomicLoad:
case Opcode::I64AtomicLoad:
case Opcode::I32AtomicLoad8U:
case Opcode::I32AtomicLoad16U:
case Opcode::I64AtomicLoad8U:
case Opcode::I64AtomicLoad16U:
case Opcode::I64AtomicLoad32U:
case Opcode::I32AtomicStore:
case Opcode::I64AtomicStore:
case Opcode::I32AtomicStore8:
case Opcode::I32AtomicStore16:
case Opcode::I64AtomicStore8:
case Opcode::I64AtomicStore16:
case Opcode::I64AtomicStore32:
case Opcode::I32AtomicRmwAdd:
case Opcode::I64AtomicRmwAdd:
case Opcode::I32AtomicRmw8AddU:
case Opcode::I32AtomicRmw16AddU:
case Opcode::I64AtomicRmw8AddU:
case Opcode::I64AtomicRmw16AddU:
case Opcode::I64AtomicRmw32AddU:
case Opcode::I32AtomicRmwSub:
case Opcode::I64AtomicRmwSub:
case Opcode::I32AtomicRmw8SubU:
case Opcode::I32AtomicRmw16SubU:
case Opcode::I64AtomicRmw8SubU:
case Opcode::I64AtomicRmw16SubU:
case Opcode::I64AtomicRmw32SubU:
case Opcode::I32AtomicRmwAnd:
case Opcode::I64AtomicRmwAnd:
case Opcode::I32AtomicRmw8AndU:
case Opcode::I32AtomicRmw16AndU:
case Opcode::I64AtomicRmw8AndU:
case Opcode::I64AtomicRmw16AndU:
case Opcode::I64AtomicRmw32AndU:
case Opcode::I32AtomicRmwOr:
case Opcode::I64AtomicRmwOr:
case Opcode::I32AtomicRmw8OrU:
case Opcode::I32AtomicRmw16OrU:
case Opcode::I64AtomicRmw8OrU:
case Opcode::I64AtomicRmw16OrU:
case Opcode::I64AtomicRmw32OrU:
case Opcode::I32AtomicRmwXor:
case Opcode::I64AtomicRmwXor:
case Opcode::I32AtomicRmw8XorU:
case Opcode::I32AtomicRmw16XorU:
case Opcode::I64AtomicRmw8XorU:
case Opcode::I64AtomicRmw16XorU:
case Opcode::I64AtomicRmw32XorU:
case Opcode::I32AtomicRmwXchg:
case Opcode::I64AtomicRmwXchg:
case Opcode::I32AtomicRmw8XchgU:
case Opcode::I32AtomicRmw16XchgU:
case Opcode::I64AtomicRmw8XchgU:
case Opcode::I64AtomicRmw16XchgU:
case Opcode::I64AtomicRmw32XchgU:
case Opcode::I32AtomicRmwCmpxchg:
case Opcode::I64AtomicRmwCmpxchg:
case Opcode::I32AtomicRmw8CmpxchgU:
case Opcode::I32AtomicRmw16CmpxchgU:
case Opcode::I64AtomicRmw8CmpxchgU:
case Opcode::I64AtomicRmw16CmpxchgU:
case Opcode::I64AtomicRmw32CmpxchgU:
return features.threads_enabled();
case Opcode::V128Const:
case Opcode::V128Load:
case Opcode::V128Store:
case Opcode::I8X16Splat:
case Opcode::I16X8Splat:
case Opcode::I32X4Splat:
case Opcode::I64X2Splat:
case Opcode::F32X4Splat:
case Opcode::F64X2Splat:
case Opcode::I8X16ExtractLaneS:
case Opcode::I8X16ExtractLaneU:
case Opcode::I16X8ExtractLaneS:
case Opcode::I16X8ExtractLaneU:
case Opcode::I32X4ExtractLane:
case Opcode::I64X2ExtractLane:
case Opcode::F32X4ExtractLane:
case Opcode::F64X2ExtractLane:
case Opcode::I8X16ReplaceLane:
case Opcode::I16X8ReplaceLane:
case Opcode::I32X4ReplaceLane:
case Opcode::I64X2ReplaceLane:
case Opcode::F32X4ReplaceLane:
case Opcode::F64X2ReplaceLane:
case Opcode::I8X16Add:
case Opcode::I16X8Add:
case Opcode::I32X4Add:
case Opcode::I64X2Add:
case Opcode::I8X16Sub:
case Opcode::I16X8Sub:
case Opcode::I32X4Sub:
case Opcode::I64X2Sub:
case Opcode::I16X8Mul:
case Opcode::I32X4Mul:
case Opcode::I8X16Neg:
case Opcode::I16X8Neg:
case Opcode::I32X4Neg:
case Opcode::I64X2Neg:
case Opcode::I8X16AddSatS:
case Opcode::I8X16AddSatU:
case Opcode::I16X8AddSatS:
case Opcode::I16X8AddSatU:
case Opcode::I8X16SubSatS:
case Opcode::I8X16SubSatU:
case Opcode::I16X8SubSatS:
case Opcode::I16X8SubSatU:
case Opcode::I8X16Shl:
case Opcode::I16X8Shl:
case Opcode::I32X4Shl:
case Opcode::I64X2Shl:
case Opcode::I8X16ShrS:
case Opcode::I8X16ShrU:
case Opcode::I16X8ShrS:
case Opcode::I16X8ShrU:
case Opcode::I32X4ShrS:
case Opcode::I32X4ShrU:
case Opcode::I64X2ShrS:
case Opcode::I64X2ShrU:
case Opcode::V128And:
case Opcode::V128Or:
case Opcode::V128Xor:
case Opcode::V128Not:
case Opcode::V128BitSelect:
case Opcode::V128AnyTrue:
case Opcode::I8X16Bitmask:
case Opcode::I16X8Bitmask:
case Opcode::I32X4Bitmask:
case Opcode::I64X2Bitmask:
case Opcode::I8X16AllTrue:
case Opcode::I16X8AllTrue:
case Opcode::I32X4AllTrue:
case Opcode::I64X2AllTrue:
case Opcode::I8X16Eq:
case Opcode::I16X8Eq:
case Opcode::I32X4Eq:
case Opcode::F32X4Eq:
case Opcode::F64X2Eq:
case Opcode::I8X16Ne:
case Opcode::I16X8Ne:
case Opcode::I32X4Ne:
case Opcode::F32X4Ne:
case Opcode::F64X2Ne:
case Opcode::I8X16LtS:
case Opcode::I8X16LtU:
case Opcode::I16X8LtS:
case Opcode::I16X8LtU:
case Opcode::I32X4LtS:
case Opcode::I32X4LtU:
case Opcode::F32X4Lt:
case Opcode::F64X2Lt:
case Opcode::I8X16LeS:
case Opcode::I8X16LeU:
case Opcode::I16X8LeS:
case Opcode::I16X8LeU:
case Opcode::I32X4LeS:
case Opcode::I32X4LeU:
case Opcode::F32X4Le:
case Opcode::F64X2Le:
case Opcode::I8X16GtS:
case Opcode::I8X16GtU:
case Opcode::I16X8GtS:
case Opcode::I16X8GtU:
case Opcode::I32X4GtS:
case Opcode::I32X4GtU:
case Opcode::F32X4Gt:
case Opcode::F64X2Gt:
case Opcode::I8X16GeS:
case Opcode::I8X16GeU:
case Opcode::I16X8GeS:
case Opcode::I16X8GeU:
case Opcode::I32X4GeS:
case Opcode::I32X4GeU:
case Opcode::F32X4Ge:
case Opcode::F64X2Ge:
case Opcode::F32X4Neg:
case Opcode::F64X2Neg:
case Opcode::F32X4Abs:
case Opcode::F64X2Abs:
case Opcode::F32X4Min:
case Opcode::F32X4PMin:
case Opcode::F64X2Min:
case Opcode::F64X2PMin:
case Opcode::F32X4Max:
case Opcode::F32X4PMax:
case Opcode::F64X2Max:
case Opcode::F64X2PMax:
case Opcode::F32X4Add:
case Opcode::F64X2Add:
case Opcode::F32X4Sub:
case Opcode::F64X2Sub:
case Opcode::F32X4Div:
case Opcode::F64X2Div:
case Opcode::F32X4Mul:
case Opcode::F64X2Mul:
case Opcode::F32X4Sqrt:
case Opcode::F64X2Sqrt:
case Opcode::F32X4ConvertI32X4S:
case Opcode::F32X4ConvertI32X4U:
case Opcode::I32X4TruncSatF32X4S:
case Opcode::I32X4TruncSatF32X4U:
case Opcode::I8X16Swizzle:
case Opcode::I8X16Shuffle:
case Opcode::V128Load8Splat:
case Opcode::V128Load16Splat:
case Opcode::V128Load32Splat:
case Opcode::V128Load64Splat:
case Opcode::V128Load8Lane:
case Opcode::V128Load16Lane:
case Opcode::V128Load32Lane:
case Opcode::V128Load64Lane:
case Opcode::V128Store8Lane:
case Opcode::V128Store16Lane:
case Opcode::V128Store32Lane:
case Opcode::V128Store64Lane:
case Opcode::I8X16Abs:
case Opcode::I16X8Abs:
case Opcode::I32X4Abs:
return features.simd_enabled();
case Opcode::MemoryInit:
case Opcode::DataDrop:
case Opcode::MemoryCopy:
case Opcode::MemoryFill:
case Opcode::TableInit:
case Opcode::ElemDrop:
case Opcode::TableCopy:
return features.bulk_memory_enabled();
case Opcode::TableGet:
case Opcode::TableSet:
case Opcode::TableGrow:
case Opcode::TableSize:
case Opcode::RefNull:
case Opcode::RefIsNull:
return features.reference_types_enabled();
// Interpreter opcodes are never "enabled".
case Opcode::InterpAlloca:
case Opcode::InterpBrUnless:
case Opcode::InterpCallImport:
case Opcode::InterpData:
case Opcode::InterpDropKeep:
return false;
default:
return true;
}
}
uint32_t Opcode::GetSimdLaneCount() const {
switch (enum_) {
case Opcode::I8X16ExtractLaneS:
case Opcode::I8X16ExtractLaneU:
case Opcode::I8X16ReplaceLane:
case Opcode::V128Load8Lane:
case Opcode::V128Store8Lane:
return 16;
break;
case Opcode::I16X8ExtractLaneS:
case Opcode::I16X8ExtractLaneU:
case Opcode::I16X8ReplaceLane:
case Opcode::V128Load16Lane:
case Opcode::V128Store16Lane:
return 8;
break;
case Opcode::F32X4ExtractLane:
case Opcode::F32X4ReplaceLane:
case Opcode::I32X4ExtractLane:
case Opcode::I32X4ReplaceLane:
case Opcode::V128Load32Lane:
case Opcode::V128Store32Lane:
return 4;
break;
case Opcode::F64X2ExtractLane:
case Opcode::F64X2ReplaceLane:
case Opcode::I64X2ExtractLane:
case Opcode::I64X2ReplaceLane:
case Opcode::V128Load64Lane:
case Opcode::V128Store64Lane:
return 2;
break;
default:
WABT_UNREACHABLE;
}
}
// Get the byte sequence for this opcode, including prefix.
std::vector<uint8_t> Opcode::GetBytes() const {
std::vector<uint8_t> result;
if (HasPrefix()) {
result.push_back(GetPrefix());
uint8_t buffer[5];
Offset length =
WriteU32Leb128Raw(buffer, buffer + sizeof(buffer), GetCode());
assert(length != 0);
result.insert(result.end(), buffer, buffer + length);
} else {
result.push_back(GetCode());
}
return result;
}
} // namespace wabt

569
third_party/wasm2c/src/opcode.def vendored Normal file
View File

@@ -0,0 +1,569 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_OPCODE
#error "You must define WABT_OPCODE before including this file."
#endif
/* *** NOTE *** This list must be kept sorted so it can be binary searched */
/*
* tr: result type
* t1: type of the 1st parameter
* t2: type of the 2nd parameter
* t3: type of the 3rd parameter
* m: memory size of the operation, if any
* prefix: the 1-byte opcode prefix, if any
* code: opcode
* Name: used to generate the opcode enum
* text: a string of the opcode name in the text format
* decomp: an optional friendly version of text, used for decompilation.
*
* tr t1 t2 t3 m prefix code Name text
* ========================================================== */
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x00, Unreachable, "unreachable", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x01, Nop, "nop", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x02, Block, "block", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x03, Loop, "loop", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x04, If, "if", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x05, Else, "else", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x06, Try, "try", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x07, Catch, "catch", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x08, Throw, "throw", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x09, Rethrow, "rethrow", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x0a, Unwind, "unwind", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x0b, End, "end", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x0c, Br, "br", "")
WABT_OPCODE(___, I32, ___, ___, 0, 0, 0x0d, BrIf, "br_if", "")
WABT_OPCODE(___, I32, ___, ___, 0, 0, 0x0e, BrTable, "br_table", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x0f, Return, "return", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x10, Call, "call", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x11, CallIndirect, "call_indirect", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x12, ReturnCall, "return_call", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x13, ReturnCallIndirect, "return_call_indirect", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x18, Delegate, "delegate", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x19, CatchAll, "catch_all", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x1a, Drop, "drop", "")
WABT_OPCODE(___, ___, ___, I32, 0, 0, 0x1b, Select, "select", "")
WABT_OPCODE(___, ___, ___, I32, 0, 0, 0x1c, SelectT, "select", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x20, LocalGet, "local.get", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x21, LocalSet, "local.set", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x22, LocalTee, "local.tee", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x23, GlobalGet, "global.get", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x24, GlobalSet, "global.set", "")
WABT_OPCODE(I32, I32, ___, ___, 4, 0, 0x28, I32Load, "i32.load", "")
WABT_OPCODE(I64, I32, ___, ___, 8, 0, 0x29, I64Load, "i64.load", "")
WABT_OPCODE(F32, I32, ___, ___, 4, 0, 0x2a, F32Load, "f32.load", "")
WABT_OPCODE(F64, I32, ___, ___, 8, 0, 0x2b, F64Load, "f64.load", "")
WABT_OPCODE(I32, I32, ___, ___, 1, 0, 0x2c, I32Load8S, "i32.load8_s", "")
WABT_OPCODE(I32, I32, ___, ___, 1, 0, 0x2d, I32Load8U, "i32.load8_u", "")
WABT_OPCODE(I32, I32, ___, ___, 2, 0, 0x2e, I32Load16S, "i32.load16_s", "")
WABT_OPCODE(I32, I32, ___, ___, 2, 0, 0x2f, I32Load16U, "i32.load16_u", "")
WABT_OPCODE(I64, I32, ___, ___, 1, 0, 0x30, I64Load8S, "i64.load8_s", "")
WABT_OPCODE(I64, I32, ___, ___, 1, 0, 0x31, I64Load8U, "i64.load8_u", "")
WABT_OPCODE(I64, I32, ___, ___, 2, 0, 0x32, I64Load16S, "i64.load16_s", "")
WABT_OPCODE(I64, I32, ___, ___, 2, 0, 0x33, I64Load16U, "i64.load16_u", "")
WABT_OPCODE(I64, I32, ___, ___, 4, 0, 0x34, I64Load32S, "i64.load32_s", "")
WABT_OPCODE(I64, I32, ___, ___, 4, 0, 0x35, I64Load32U, "i64.load32_u", "")
WABT_OPCODE(___, I32, I32, ___, 4, 0, 0x36, I32Store, "i32.store", "")
WABT_OPCODE(___, I32, I64, ___, 8, 0, 0x37, I64Store, "i64.store", "")
WABT_OPCODE(___, I32, F32, ___, 4, 0, 0x38, F32Store, "f32.store", "")
WABT_OPCODE(___, I32, F64, ___, 8, 0, 0x39, F64Store, "f64.store", "")
WABT_OPCODE(___, I32, I32, ___, 1, 0, 0x3a, I32Store8, "i32.store8", "")
WABT_OPCODE(___, I32, I32, ___, 2, 0, 0x3b, I32Store16, "i32.store16", "")
WABT_OPCODE(___, I32, I64, ___, 1, 0, 0x3c, I64Store8, "i64.store8", "")
WABT_OPCODE(___, I32, I64, ___, 2, 0, 0x3d, I64Store16, "i64.store16", "")
WABT_OPCODE(___, I32, I64, ___, 4, 0, 0x3e, I64Store32, "i64.store32", "")
WABT_OPCODE(I32, ___, ___, ___, 0, 0, 0x3f, MemorySize, "memory.size", "")
WABT_OPCODE(I32, I32, ___, ___, 0, 0, 0x40, MemoryGrow, "memory.grow", "")
WABT_OPCODE(I32, ___, ___, ___, 0, 0, 0x41, I32Const, "i32.const", "")
WABT_OPCODE(I64, ___, ___, ___, 0, 0, 0x42, I64Const, "i64.const", "")
WABT_OPCODE(F32, ___, ___, ___, 0, 0, 0x43, F32Const, "f32.const", "")
WABT_OPCODE(F64, ___, ___, ___, 0, 0, 0x44, F64Const, "f64.const", "")
WABT_OPCODE(I32, I32, ___, ___, 0, 0, 0x45, I32Eqz, "i32.eqz", "eqz")
WABT_OPCODE(I32, I32, I32, ___, 0, 0, 0x46, I32Eq, "i32.eq", "==")
WABT_OPCODE(I32, I32, I32, ___, 0, 0, 0x47, I32Ne, "i32.ne", "!=")
WABT_OPCODE(I32, I32, I32, ___, 0, 0, 0x48, I32LtS, "i32.lt_s", "<")
WABT_OPCODE(I32, I32, I32, ___, 0, 0, 0x49, I32LtU, "i32.lt_u", "<")
WABT_OPCODE(I32, I32, I32, ___, 0, 0, 0x4a, I32GtS, "i32.gt_s", ">")
WABT_OPCODE(I32, I32, I32, ___, 0, 0, 0x4b, I32GtU, "i32.gt_u", ">")
WABT_OPCODE(I32, I32, I32, ___, 0, 0, 0x4c, I32LeS, "i32.le_s", "<=")
WABT_OPCODE(I32, I32, I32, ___, 0, 0, 0x4d, I32LeU, "i32.le_u", "<=")
WABT_OPCODE(I32, I32, I32, ___, 0, 0, 0x4e, I32GeS, "i32.ge_s", ">=")
WABT_OPCODE(I32, I32, I32, ___, 0, 0, 0x4f, I32GeU, "i32.ge_u", ">=")
WABT_OPCODE(I32, I64, ___, ___, 0, 0, 0x50, I64Eqz, "i64.eqz", "eqz")
WABT_OPCODE(I32, I64, I64, ___, 0, 0, 0x51, I64Eq, "i64.eq", "==")
WABT_OPCODE(I32, I64, I64, ___, 0, 0, 0x52, I64Ne, "i64.ne", "!=")
WABT_OPCODE(I32, I64, I64, ___, 0, 0, 0x53, I64LtS, "i64.lt_s", "<")
WABT_OPCODE(I32, I64, I64, ___, 0, 0, 0x54, I64LtU, "i64.lt_u", "<")
WABT_OPCODE(I32, I64, I64, ___, 0, 0, 0x55, I64GtS, "i64.gt_s", ">")
WABT_OPCODE(I32, I64, I64, ___, 0, 0, 0x56, I64GtU, "i64.gt_u", ">")
WABT_OPCODE(I32, I64, I64, ___, 0, 0, 0x57, I64LeS, "i64.le_s", "<=")
WABT_OPCODE(I32, I64, I64, ___, 0, 0, 0x58, I64LeU, "i64.le_u", "<=")
WABT_OPCODE(I32, I64, I64, ___, 0, 0, 0x59, I64GeS, "i64.ge_s", ">=")
WABT_OPCODE(I32, I64, I64, ___, 0, 0, 0x5a, I64GeU, "i64.ge_u", ">=")
WABT_OPCODE(I32, F32, F32, ___, 0, 0, 0x5b, F32Eq, "f32.eq", "==")
WABT_OPCODE(I32, F32, F32, ___, 0, 0, 0x5c, F32Ne, "f32.ne", "!=")
WABT_OPCODE(I32, F32, F32, ___, 0, 0, 0x5d, F32Lt, "f32.lt", "<")
WABT_OPCODE(I32, F32, F32, ___, 0, 0, 0x5e, F32Gt, "f32.gt", ">")
WABT_OPCODE(I32, F32, F32, ___, 0, 0, 0x5f, F32Le, "f32.le", "<=")
WABT_OPCODE(I32, F32, F32, ___, 0, 0, 0x60, F32Ge, "f32.ge", ">=")
WABT_OPCODE(I32, F64, F64, ___, 0, 0, 0x61, F64Eq, "f64.eq", "==")
WABT_OPCODE(I32, F64, F64, ___, 0, 0, 0x62, F64Ne, "f64.ne", "!=")
WABT_OPCODE(I32, F64, F64, ___, 0, 0, 0x63, F64Lt, "f64.lt", "<")
WABT_OPCODE(I32, F64, F64, ___, 0, 0, 0x64, F64Gt, "f64.gt", ">")
WABT_OPCODE(I32, F64, F64, ___, 0, 0, 0x65, F64Le, "f64.le", "<=")
WABT_OPCODE(I32, F64, F64, ___, 0, 0, 0x66, F64Ge, "f64.ge", ">=")
WABT_OPCODE(I32, I32, ___, ___, 0, 0, 0x67, I32Clz, "i32.clz", "clz")
WABT_OPCODE(I32, I32, ___, ___, 0, 0, 0x68, I32Ctz, "i32.ctz", "ctz")
WABT_OPCODE(I32, I32, ___, ___, 0, 0, 0x69, I32Popcnt, "i32.popcnt", "popcnt")
WABT_OPCODE(I32, I32, I32, ___, 0, 0, 0x6a, I32Add, "i32.add", "+")
WABT_OPCODE(I32, I32, I32, ___, 0, 0, 0x6b, I32Sub, "i32.sub", "-")
WABT_OPCODE(I32, I32, I32, ___, 0, 0, 0x6c, I32Mul, "i32.mul", "*")
WABT_OPCODE(I32, I32, I32, ___, 0, 0, 0x6d, I32DivS, "i32.div_s", "/")
WABT_OPCODE(I32, I32, I32, ___, 0, 0, 0x6e, I32DivU, "i32.div_u", "/")
WABT_OPCODE(I32, I32, I32, ___, 0, 0, 0x6f, I32RemS, "i32.rem_s", "%")
WABT_OPCODE(I32, I32, I32, ___, 0, 0, 0x70, I32RemU, "i32.rem_u", "%")
WABT_OPCODE(I32, I32, I32, ___, 0, 0, 0x71, I32And, "i32.and", "&")
WABT_OPCODE(I32, I32, I32, ___, 0, 0, 0x72, I32Or, "i32.or", "|")
WABT_OPCODE(I32, I32, I32, ___, 0, 0, 0x73, I32Xor, "i32.xor", "^")
WABT_OPCODE(I32, I32, I32, ___, 0, 0, 0x74, I32Shl, "i32.shl", "<<")
WABT_OPCODE(I32, I32, I32, ___, 0, 0, 0x75, I32ShrS, "i32.shr_s", ">>")
WABT_OPCODE(I32, I32, I32, ___, 0, 0, 0x76, I32ShrU, "i32.shr_u", ">>")
WABT_OPCODE(I32, I32, I32, ___, 0, 0, 0x77, I32Rotl, "i32.rotl", "<<")
WABT_OPCODE(I32, I32, I32, ___, 0, 0, 0x78, I32Rotr, "i32.rotr", ">>")
WABT_OPCODE(I64, I64, ___, ___, 0, 0, 0x79, I64Clz, "i64.clz", "clz")
WABT_OPCODE(I64, I64, ___, ___, 0, 0, 0x7a, I64Ctz, "i64.ctz", "ctz")
WABT_OPCODE(I64, I64, ___, ___, 0, 0, 0x7b, I64Popcnt, "i64.popcnt", "popcnt")
WABT_OPCODE(I64, I64, I64, ___, 0, 0, 0x7c, I64Add, "i64.add", "+")
WABT_OPCODE(I64, I64, I64, ___, 0, 0, 0x7d, I64Sub, "i64.sub", "-")
WABT_OPCODE(I64, I64, I64, ___, 0, 0, 0x7e, I64Mul, "i64.mul", "*")
WABT_OPCODE(I64, I64, I64, ___, 0, 0, 0x7f, I64DivS, "i64.div_s", "/")
WABT_OPCODE(I64, I64, I64, ___, 0, 0, 0x80, I64DivU, "i64.div_u", "/")
WABT_OPCODE(I64, I64, I64, ___, 0, 0, 0x81, I64RemS, "i64.rem_s", "%")
WABT_OPCODE(I64, I64, I64, ___, 0, 0, 0x82, I64RemU, "i64.rem_u", "%")
WABT_OPCODE(I64, I64, I64, ___, 0, 0, 0x83, I64And, "i64.and", "&")
WABT_OPCODE(I64, I64, I64, ___, 0, 0, 0x84, I64Or, "i64.or", "|")
WABT_OPCODE(I64, I64, I64, ___, 0, 0, 0x85, I64Xor, "i64.xor", "^")
WABT_OPCODE(I64, I64, I64, ___, 0, 0, 0x86, I64Shl, "i64.shl", "<<")
WABT_OPCODE(I64, I64, I64, ___, 0, 0, 0x87, I64ShrS, "i64.shr_s", ">>")
WABT_OPCODE(I64, I64, I64, ___, 0, 0, 0x88, I64ShrU, "i64.shr_u", ">>")
WABT_OPCODE(I64, I64, I64, ___, 0, 0, 0x89, I64Rotl, "i64.rotl", "<<")
WABT_OPCODE(I64, I64, I64, ___, 0, 0, 0x8a, I64Rotr, "i64.rotr", ">>")
WABT_OPCODE(F32, F32, F32, ___, 0, 0, 0x8b, F32Abs, "f32.abs", "abs")
WABT_OPCODE(F32, F32, F32, ___, 0, 0, 0x8c, F32Neg, "f32.neg", "-")
WABT_OPCODE(F32, F32, F32, ___, 0, 0, 0x8d, F32Ceil, "f32.ceil", "ceil")
WABT_OPCODE(F32, F32, F32, ___, 0, 0, 0x8e, F32Floor, "f32.floor", "floor")
WABT_OPCODE(F32, F32, F32, ___, 0, 0, 0x8f, F32Trunc, "f32.trunc", "trunc")
WABT_OPCODE(F32, F32, F32, ___, 0, 0, 0x90, F32Nearest, "f32.nearest", "nearest")
WABT_OPCODE(F32, F32, F32, ___, 0, 0, 0x91, F32Sqrt, "f32.sqrt", "sqrt")
WABT_OPCODE(F32, F32, F32, ___, 0, 0, 0x92, F32Add, "f32.add", "+")
WABT_OPCODE(F32, F32, F32, ___, 0, 0, 0x93, F32Sub, "f32.sub", "-")
WABT_OPCODE(F32, F32, F32, ___, 0, 0, 0x94, F32Mul, "f32.mul", "*")
WABT_OPCODE(F32, F32, F32, ___, 0, 0, 0x95, F32Div, "f32.div", "/")
WABT_OPCODE(F32, F32, F32, ___, 0, 0, 0x96, F32Min, "f32.min", "min")
WABT_OPCODE(F32, F32, F32, ___, 0, 0, 0x97, F32Max, "f32.max", "max")
WABT_OPCODE(F32, F32, F32, ___, 0, 0, 0x98, F32Copysign, "f32.copysign", "copysign")
WABT_OPCODE(F64, F64, F64, ___, 0, 0, 0x99, F64Abs, "f64.abs", "abs")
WABT_OPCODE(F64, F64, F64, ___, 0, 0, 0x9a, F64Neg, "f64.neg", "-")
WABT_OPCODE(F64, F64, F64, ___, 0, 0, 0x9b, F64Ceil, "f64.ceil", "ceil")
WABT_OPCODE(F64, F64, F64, ___, 0, 0, 0x9c, F64Floor, "f64.floor", "floor")
WABT_OPCODE(F64, F64, F64, ___, 0, 0, 0x9d, F64Trunc, "f64.trunc", "trunc")
WABT_OPCODE(F64, F64, F64, ___, 0, 0, 0x9e, F64Nearest, "f64.nearest", "nearest")
WABT_OPCODE(F64, F64, F64, ___, 0, 0, 0x9f, F64Sqrt, "f64.sqrt", "sqrt")
WABT_OPCODE(F64, F64, F64, ___, 0, 0, 0xa0, F64Add, "f64.add", "+")
WABT_OPCODE(F64, F64, F64, ___, 0, 0, 0xa1, F64Sub, "f64.sub", "-")
WABT_OPCODE(F64, F64, F64, ___, 0, 0, 0xa2, F64Mul, "f64.mul", "*")
WABT_OPCODE(F64, F64, F64, ___, 0, 0, 0xa3, F64Div, "f64.div", "/")
WABT_OPCODE(F64, F64, F64, ___, 0, 0, 0xa4, F64Min, "f64.min", "min")
WABT_OPCODE(F64, F64, F64, ___, 0, 0, 0xa5, F64Max, "f64.max", "max")
WABT_OPCODE(F64, F64, F64, ___, 0, 0, 0xa6, F64Copysign, "f64.copysign", "copysign")
WABT_OPCODE(I32, I64, ___, ___, 0, 0, 0xa7, I32WrapI64, "i32.wrap_i64", "")
WABT_OPCODE(I32, F32, ___, ___, 0, 0, 0xa8, I32TruncF32S, "i32.trunc_f32_s", "")
WABT_OPCODE(I32, F32, ___, ___, 0, 0, 0xa9, I32TruncF32U, "i32.trunc_f32_u", "")
WABT_OPCODE(I32, F64, ___, ___, 0, 0, 0xaa, I32TruncF64S, "i32.trunc_f64_s", "")
WABT_OPCODE(I32, F64, ___, ___, 0, 0, 0xab, I32TruncF64U, "i32.trunc_f64_u", "")
WABT_OPCODE(I64, I32, ___, ___, 0, 0, 0xac, I64ExtendI32S, "i64.extend_i32_s", "")
WABT_OPCODE(I64, I32, ___, ___, 0, 0, 0xad, I64ExtendI32U, "i64.extend_i32_u", "")
WABT_OPCODE(I64, F32, ___, ___, 0, 0, 0xae, I64TruncF32S, "i64.trunc_f32_s", "")
WABT_OPCODE(I64, F32, ___, ___, 0, 0, 0xaf, I64TruncF32U, "i64.trunc_f32_u", "")
WABT_OPCODE(I64, F64, ___, ___, 0, 0, 0xb0, I64TruncF64S, "i64.trunc_f64_s", "")
WABT_OPCODE(I64, F64, ___, ___, 0, 0, 0xb1, I64TruncF64U, "i64.trunc_f64_u", "")
WABT_OPCODE(F32, I32, ___, ___, 0, 0, 0xb2, F32ConvertI32S, "f32.convert_i32_s", "")
WABT_OPCODE(F32, I32, ___, ___, 0, 0, 0xb3, F32ConvertI32U, "f32.convert_i32_u", "")
WABT_OPCODE(F32, I64, ___, ___, 0, 0, 0xb4, F32ConvertI64S, "f32.convert_i64_s", "")
WABT_OPCODE(F32, I64, ___, ___, 0, 0, 0xb5, F32ConvertI64U, "f32.convert_i64_u", "")
WABT_OPCODE(F32, F64, ___, ___, 0, 0, 0xb6, F32DemoteF64, "f32.demote_f64", "")
WABT_OPCODE(F64, I32, ___, ___, 0, 0, 0xb7, F64ConvertI32S, "f64.convert_i32_s", "")
WABT_OPCODE(F64, I32, ___, ___, 0, 0, 0xb8, F64ConvertI32U, "f64.convert_i32_u", "")
WABT_OPCODE(F64, I64, ___, ___, 0, 0, 0xb9, F64ConvertI64S, "f64.convert_i64_s", "")
WABT_OPCODE(F64, I64, ___, ___, 0, 0, 0xba, F64ConvertI64U, "f64.convert_i64_u", "")
WABT_OPCODE(F64, F32, ___, ___, 0, 0, 0xbb, F64PromoteF32, "f64.promote_f32", "")
WABT_OPCODE(I32, F32, ___, ___, 0, 0, 0xbc, I32ReinterpretF32, "i32.reinterpret_f32", "")
WABT_OPCODE(I64, F64, ___, ___, 0, 0, 0xbd, I64ReinterpretF64, "i64.reinterpret_f64", "")
WABT_OPCODE(F32, I32, ___, ___, 0, 0, 0xbe, F32ReinterpretI32, "f32.reinterpret_i32", "")
WABT_OPCODE(F64, I64, ___, ___, 0, 0, 0xbf, F64ReinterpretI64, "f64.reinterpret_i64", "")
/* Sign-extension opcodes (--enable-sign-extension) */
WABT_OPCODE(I32, I32, ___, ___, 0, 0, 0xC0, I32Extend8S, "i32.extend8_s", "")
WABT_OPCODE(I32, I32, ___, ___, 0, 0, 0xC1, I32Extend16S, "i32.extend16_s", "")
WABT_OPCODE(I64, I64, ___, ___, 0, 0, 0xC2, I64Extend8S, "i64.extend8_s", "")
WABT_OPCODE(I64, I64, ___, ___, 0, 0, 0xC3, I64Extend16S, "i64.extend16_s", "")
WABT_OPCODE(I64, I64, ___, ___, 0, 0, 0xC4, I64Extend32S, "i64.extend32_s", "")
/* Interpreter-only opcodes */
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xe0, InterpAlloca, "alloca", "")
WABT_OPCODE(___, I32, ___, ___, 0, 0, 0xe1, InterpBrUnless, "br_unless", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xe2, InterpCallImport, "call_import", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xe3, InterpData, "data", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xe4, InterpDropKeep, "drop_keep", "")
/* Saturating float-to-int opcodes (--enable-saturating-float-to-int) */
WABT_OPCODE(I32, F32, ___, ___, 0, 0xfc, 0x00, I32TruncSatF32S, "i32.trunc_sat_f32_s", "")
WABT_OPCODE(I32, F32, ___, ___, 0, 0xfc, 0x01, I32TruncSatF32U, "i32.trunc_sat_f32_u", "")
WABT_OPCODE(I32, F64, ___, ___, 0, 0xfc, 0x02, I32TruncSatF64S, "i32.trunc_sat_f64_s", "")
WABT_OPCODE(I32, F64, ___, ___, 0, 0xfc, 0x03, I32TruncSatF64U, "i32.trunc_sat_f64_u", "")
WABT_OPCODE(I64, F32, ___, ___, 0, 0xfc, 0x04, I64TruncSatF32S, "i64.trunc_sat_f32_s", "")
WABT_OPCODE(I64, F32, ___, ___, 0, 0xfc, 0x05, I64TruncSatF32U, "i64.trunc_sat_f32_u", "")
WABT_OPCODE(I64, F64, ___, ___, 0, 0xfc, 0x06, I64TruncSatF64S, "i64.trunc_sat_f64_s", "")
WABT_OPCODE(I64, F64, ___, ___, 0, 0xfc, 0x07, I64TruncSatF64U, "i64.trunc_sat_f64_u", "")
/* Bulk-memory (--enable-bulk-memory) */
WABT_OPCODE(___, I32, I32, I32, 0, 0xfc, 0x08, MemoryInit, "memory.init", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0xfc, 0x09, DataDrop, "data.drop", "")
WABT_OPCODE(___, I32, I32, I32, 0, 0xfc, 0x0a, MemoryCopy,"memory.copy", "")
WABT_OPCODE(___, I32, I32, I32, 0, 0xfc, 0x0b, MemoryFill, "memory.fill", "")
WABT_OPCODE(___, I32, I32, I32, 0, 0xfc, 0x0c, TableInit, "table.init", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0xfc, 0x0d, ElemDrop, "elem.drop", "")
WABT_OPCODE(___, I32, I32, I32, 0, 0xfc, 0x0e, TableCopy, "table.copy", "")
/* Reference types (--enable-reference-types) */
WABT_OPCODE(___, I32, ___, ___, 0, 0, 0x25, TableGet, "table.get", "")
WABT_OPCODE(___, I32, ___, ___, 0, 0, 0x26, TableSet, "table.set", "")
WABT_OPCODE(___, ___, I32, ___, 0, 0xfc, 0x0f, TableGrow, "table.grow", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0xfc, 0x10, TableSize, "table.size", "")
WABT_OPCODE(___, I32, ___, I32, 0, 0xfc, 0x11, TableFill, "table.fill", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xd0, RefNull, "ref.null", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xd1, RefIsNull, "ref.is_null", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xd2, RefFunc, "ref.func", "")
/* Simd opcodes (--enable-simd) */
WABT_OPCODE(V128, I32, ___, ___, 16, 0xfd, 0x00, V128Load, "v128.load", "")
WABT_OPCODE(V128, I32, ___, ___, 8, 0xfd, 0x01, V128Load8X8S, "v128.load8x8_s", "")
WABT_OPCODE(V128, I32, ___, ___, 8, 0xfd, 0x02, V128Load8X8U, "v128.load8x8_u", "")
WABT_OPCODE(V128, I32, ___, ___, 8, 0xfd, 0x03, V128Load16X4S, "v128.load16x4_s", "")
WABT_OPCODE(V128, I32, ___, ___, 8, 0xfd, 0x04, V128Load16X4U, "v128.load16x4_u", "")
WABT_OPCODE(V128, I32, ___, ___, 8, 0xfd, 0x05, V128Load32X2S, "v128.load32x2_s", "")
WABT_OPCODE(V128, I32, ___, ___, 8, 0xfd, 0x06, V128Load32X2U, "v128.load32x2_u", "")
WABT_OPCODE(V128, I32, ___, ___, 1, 0xfd, 0x07, V128Load8Splat, "v128.load8_splat", "")
WABT_OPCODE(V128, I32, ___, ___, 2, 0xfd, 0x08, V128Load16Splat, "v128.load16_splat", "")
WABT_OPCODE(V128, I32, ___, ___, 4, 0xfd, 0x09, V128Load32Splat, "v128.load32_splat", "")
WABT_OPCODE(V128, I32, ___, ___, 8, 0xfd, 0x0a, V128Load64Splat, "v128.load64_splat", "")
WABT_OPCODE(___, I32, V128, ___, 16, 0xfd, 0x0b, V128Store, "v128.store", "")
WABT_OPCODE(V128, ___, ___, ___, 0, 0xfd, 0x0c, V128Const, "v128.const", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x0d, I8X16Shuffle, "i8x16.shuffle", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x0e, I8X16Swizzle, "i8x16.swizzle", "")
WABT_OPCODE(V128, I32, ___, ___, 0, 0xfd, 0x0f, I8X16Splat, "i8x16.splat", "")
WABT_OPCODE(V128, I32, ___, ___, 0, 0xfd, 0x10, I16X8Splat, "i16x8.splat", "")
WABT_OPCODE(V128, I32, ___, ___, 0, 0xfd, 0x11, I32X4Splat, "i32x4.splat", "")
WABT_OPCODE(V128, I64, ___, ___, 0, 0xfd, 0x12, I64X2Splat, "i64x2.splat", "")
WABT_OPCODE(V128, F32, ___, ___, 0, 0xfd, 0x13, F32X4Splat, "f32x4.splat", "")
WABT_OPCODE(V128, F64, ___, ___, 0, 0xfd, 0x14, F64X2Splat, "f64x2.splat", "")
WABT_OPCODE(I32, V128, ___, ___, 0, 0xfd, 0x15, I8X16ExtractLaneS, "i8x16.extract_lane_s", "")
WABT_OPCODE(I32, V128, ___, ___, 0, 0xfd, 0x16, I8X16ExtractLaneU, "i8x16.extract_lane_u", "")
WABT_OPCODE(V128, V128, I32, ___, 0, 0xfd, 0x17, I8X16ReplaceLane, "i8x16.replace_lane", "")
WABT_OPCODE(I32, V128, ___, ___, 0, 0xfd, 0x18, I16X8ExtractLaneS, "i16x8.extract_lane_s", "")
WABT_OPCODE(I32, V128, ___, ___, 0, 0xfd, 0x19, I16X8ExtractLaneU, "i16x8.extract_lane_u", "")
WABT_OPCODE(V128, V128, I32, ___, 0, 0xfd, 0x1a, I16X8ReplaceLane, "i16x8.replace_lane", "")
WABT_OPCODE(I32, V128, ___, ___, 0, 0xfd, 0x1b, I32X4ExtractLane, "i32x4.extract_lane", "")
WABT_OPCODE(V128, V128, I32, ___, 0, 0xfd, 0x1c, I32X4ReplaceLane, "i32x4.replace_lane", "")
WABT_OPCODE(I64, V128, ___, ___, 0, 0xfd, 0x1d, I64X2ExtractLane, "i64x2.extract_lane", "")
WABT_OPCODE(V128, V128, I64, ___, 0, 0xfd, 0x1e, I64X2ReplaceLane, "i64x2.replace_lane", "")
WABT_OPCODE(F32, V128, ___, ___, 0, 0xfd, 0x1f, F32X4ExtractLane, "f32x4.extract_lane", "")
WABT_OPCODE(V128, V128, F32, ___, 0, 0xfd, 0x20, F32X4ReplaceLane, "f32x4.replace_lane", "")
WABT_OPCODE(F64, V128, ___, ___, 0, 0xfd, 0x21, F64X2ExtractLane, "f64x2.extract_lane", "")
WABT_OPCODE(V128, V128, F64, ___, 0, 0xfd, 0x22, F64X2ReplaceLane, "f64x2.replace_lane", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x23, I8X16Eq, "i8x16.eq", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x24, I8X16Ne, "i8x16.ne", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x25, I8X16LtS, "i8x16.lt_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x26, I8X16LtU, "i8x16.lt_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x27, I8X16GtS, "i8x16.gt_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x28, I8X16GtU, "i8x16.gt_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x29, I8X16LeS, "i8x16.le_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x2a, I8X16LeU, "i8x16.le_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x2b, I8X16GeS, "i8x16.ge_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x2c, I8X16GeU, "i8x16.ge_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x2d, I16X8Eq, "i16x8.eq", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x2e, I16X8Ne, "i16x8.ne", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x2f, I16X8LtS, "i16x8.lt_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x30, I16X8LtU, "i16x8.lt_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x31, I16X8GtS, "i16x8.gt_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x32, I16X8GtU, "i16x8.gt_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x33, I16X8LeS, "i16x8.le_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x34, I16X8LeU, "i16x8.le_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x35, I16X8GeS, "i16x8.ge_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x36, I16X8GeU, "i16x8.ge_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x37, I32X4Eq, "i32x4.eq", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x38, I32X4Ne, "i32x4.ne", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x39, I32X4LtS, "i32x4.lt_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x3a, I32X4LtU, "i32x4.lt_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x3b, I32X4GtS, "i32x4.gt_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x3c, I32X4GtU, "i32x4.gt_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x3d, I32X4LeS, "i32x4.le_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x3e, I32X4LeU, "i32x4.le_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x3f, I32X4GeS, "i32x4.ge_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x40, I32X4GeU, "i32x4.ge_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x41, F32X4Eq, "f32x4.eq", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x42, F32X4Ne, "f32x4.ne", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x43, F32X4Lt, "f32x4.lt", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x44, F32X4Gt, "f32x4.gt", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x45, F32X4Le, "f32x4.le", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x46, F32X4Ge, "f32x4.ge", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x47, F64X2Eq, "f64x2.eq", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x48, F64X2Ne, "f64x2.ne", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x49, F64X2Lt, "f64x2.lt", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x4a, F64X2Gt, "f64x2.gt", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x4b, F64X2Le, "f64x2.le", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x4c, F64X2Ge, "f64x2.ge", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x4d, V128Not, "v128.not", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x4e, V128And, "v128.and", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x4f, V128Andnot, "v128.andnot", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x50, V128Or, "v128.or", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x51, V128Xor, "v128.xor", "")
WABT_OPCODE(V128, V128, V128, V128, 0, 0xfd, 0x52, V128BitSelect, "v128.bitselect", "")
WABT_OPCODE(I32, V128, ___, ___, 0, 0xfd, 0x53, V128AnyTrue, "v128.any_true", "")
WABT_OPCODE(V128, I32, V128, ___, 1, 0xfd, 0x54, V128Load8Lane, "v128.load8_lane", "")
WABT_OPCODE(V128, I32, V128, ___, 2, 0xfd, 0x55, V128Load16Lane, "v128.load16_lane", "")
WABT_OPCODE(V128, I32, V128, ___, 4, 0xfd, 0x56, V128Load32Lane, "v128.load32_lane", "")
WABT_OPCODE(V128, I32, V128, ___, 8, 0xfd, 0x57, V128Load64Lane, "v128.load64_lane", "")
WABT_OPCODE(___, I32, V128, ___, 1, 0xfd, 0x58, V128Store8Lane, "v128.store8_lane", "")
WABT_OPCODE(___, I32, V128, ___, 2, 0xfd, 0x59, V128Store16Lane, "v128.store16_lane", "")
WABT_OPCODE(___, I32, V128, ___, 4, 0xfd, 0x5a, V128Store32Lane, "v128.store32_lane", "")
WABT_OPCODE(___, I32, V128, ___, 8, 0xfd, 0x5b, V128Store64Lane, "v128.store64_lane", "")
WABT_OPCODE(V128, I32, ___, ___, 4, 0xfd, 0x5c, V128Load32Zero, "v128.load32_zero", "")
WABT_OPCODE(V128, I32, ___, ___, 8, 0xfd, 0x5d, V128Load64Zero, "v128.load64_zero", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x5e, F32X4DemoteF64X2Zero, "f32x4.demote_f64x2_zero", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x5f, F64X2PromoteLowF32X4, "f64x2.promote_low_f32x4", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x60, I8X16Abs, "i8x16.abs", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x61, I8X16Neg, "i8x16.neg", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x62, I8X16Popcnt, "i8x16.popcnt", "")
WABT_OPCODE(I32, V128, ___, ___, 0, 0xfd, 0x63, I8X16AllTrue, "i8x16.all_true", "")
WABT_OPCODE(I32, V128, ___, ___, 0, 0xfd, 0x64, I8X16Bitmask, "i8x16.bitmask", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x65, I8X16NarrowI16X8S, "i8x16.narrow_i16x8_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x66, I8X16NarrowI16X8U, "i8x16.narrow_i16x8_u", "")
WABT_OPCODE(V128, V128, I32, ___, 0, 0xfd, 0x6b, I8X16Shl, "i8x16.shl", "")
WABT_OPCODE(V128, V128, I32, ___, 0, 0xfd, 0x6c, I8X16ShrS, "i8x16.shr_s", "")
WABT_OPCODE(V128, V128, I32, ___, 0, 0xfd, 0x6d, I8X16ShrU, "i8x16.shr_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x6e, I8X16Add, "i8x16.add", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x6f, I8X16AddSatS, "i8x16.add_sat_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x70, I8X16AddSatU, "i8x16.add_sat_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x71, I8X16Sub, "i8x16.sub", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x72, I8X16SubSatS, "i8x16.sub_sat_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x73, I8X16SubSatU, "i8x16.sub_sat_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x76, I8X16MinS, "i8x16.min_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x77, I8X16MinU, "i8x16.min_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x78, I8X16MaxS, "i8x16.max_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x79, I8X16MaxU, "i8x16.max_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x7b, I8X16AvgrU, "i8x16.avgr_u", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x7c, I16X8ExtaddPairwiseI8X16S, "i16x8.extadd_pairwise_i8x16_s", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x7d, I16X8ExtaddPairwiseI8X16U, "i16x8.extadd_pairwise_i8x16_u", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x7e, I32X4ExtaddPairwiseI16X8S, "i32x4.extadd_pairwise_i16x8_s", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x7f, I32X4ExtaddPairwiseI16X8U, "i32x4.extadd_pairwise_i16x8_u", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x80, I16X8Abs, "i16x8.abs", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x81, I16X8Neg, "i16x8.neg", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x82, I16X8Q15mulrSatS, "i16x8.q15mulr_sat_s", "")
WABT_OPCODE(I32, V128, ___, ___, 0, 0xfd, 0x83, I16X8AllTrue, "i16x8.all_true", "")
WABT_OPCODE(I32, V128, ___, ___, 0, 0xfd, 0x84, I16X8Bitmask, "i16x8.bitmask", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x85, I16X8NarrowI32X4S, "i16x8.narrow_i32x4_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x86, I16X8NarrowI32X4U, "i16x8.narrow_i32x4_u", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x87, I16X8ExtendLowI8X16S, "i16x8.extend_low_i8x16_s", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x88, I16X8ExtendHighI8X16S, "i16x8.extend_high_i8x16_s", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x89, I16X8ExtendLowI8X16U, "i16x8.extend_low_i8x16_u", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x8a, I16X8ExtendHighI8X16U, "i16x8.extend_high_i8x16_u", "")
WABT_OPCODE(V128, V128, I32, ___, 0, 0xfd, 0x8b, I16X8Shl, "i16x8.shl", "")
WABT_OPCODE(V128, V128, I32, ___, 0, 0xfd, 0x8c, I16X8ShrS, "i16x8.shr_s", "")
WABT_OPCODE(V128, V128, I32, ___, 0, 0xfd, 0x8d, I16X8ShrU, "i16x8.shr_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x8e, I16X8Add, "i16x8.add", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x8f, I16X8AddSatS, "i16x8.add_sat_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x90, I16X8AddSatU, "i16x8.add_sat_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x91, I16X8Sub, "i16x8.sub", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x92, I16X8SubSatS, "i16x8.sub_sat_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x93, I16X8SubSatU, "i16x8.sub_sat_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x95, I16X8Mul, "i16x8.mul", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x96, I16X8MinS, "i16x8.min_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x97, I16X8MinU, "i16x8.min_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x98, I16X8MaxS, "i16x8.max_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x99, I16X8MaxU, "i16x8.max_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x9b, I16X8AvgrU, "i16x8.avgr_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x9c, I16X8ExtmulLowI8X16S, "i16x8.extmul_low_i8x16_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x9d, I16X8ExtmulHighI8X16S, "i16x8.extmul_high_i8x16_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x9e, I16X8ExtmulLowI8X16U, "i16x8.extmul_low_i8x16_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0x9f, I16X8ExtmulHighI8X16U, "i16x8.extmul_high_i8x16_u", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xa0, I32X4Abs, "i32x4.abs", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xa1, I32X4Neg, "i32x4.neg", "")
WABT_OPCODE(I32, V128, ___, ___, 0, 0xfd, 0xa3, I32X4AllTrue, "i32x4.all_true", "")
WABT_OPCODE(I32, V128, ___, ___, 0, 0xfd, 0xa4, I32X4Bitmask, "i32x4.bitmask", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xa7, I32X4ExtendLowI16X8S, "i32x4.extend_low_i16x8_s", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xa8, I32X4ExtendHighI16X8S, "i32x4.extend_high_i16x8_s", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xa9, I32X4ExtendLowI16X8U, "i32x4.extend_low_i16x8_u", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xaa, I32X4ExtendHighI16X8U, "i32x4.extend_high_i16x8_u", "")
WABT_OPCODE(V128, V128, I32, ___, 0, 0xfd, 0xab, I32X4Shl, "i32x4.shl", "")
WABT_OPCODE(V128, V128, I32, ___, 0, 0xfd, 0xac, I32X4ShrS, "i32x4.shr_s", "")
WABT_OPCODE(V128, V128, I32, ___, 0, 0xfd, 0xad, I32X4ShrU, "i32x4.shr_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xae, I32X4Add, "i32x4.add", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xb1, I32X4Sub, "i32x4.sub", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xb5, I32X4Mul, "i32x4.mul", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xb6, I32X4MinS, "i32x4.min_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xb7, I32X4MinU, "i32x4.min_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xb8, I32X4MaxS, "i32x4.max_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xb9, I32X4MaxU, "i32x4.max_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xba, I32X4DotI16X8S, "i32x4.dot_i16x8_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xbc, I32X4ExtmulLowI16X8S, "i32x4.extmul_low_i16x8_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xbd, I32X4ExtmulHighI16X8S, "i32x4.extmul_high_i16x8_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xbe, I32X4ExtmulLowI16X8U, "i32x4.extmul_low_i16x8_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xbf, I32X4ExtmulHighI16X8U, "i32x4.extmul_high_i16x8_u", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xc0, I64X2Abs, "i64x2.abs", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xc1, I64X2Neg, "i64x2.neg", "")
WABT_OPCODE( I32, V128, ___, ___, 0, 0xfd, 0xc3, I64X2AllTrue, "i64x2.all_true", "")
WABT_OPCODE( I32, V128, ___, ___, 0, 0xfd, 0xc4, I64X2Bitmask, "i64x2.bitmask", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xc7, I64X2ExtendLowI32X4S, "i64x2.extend_low_i32x4_s", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xc8, I64X2ExtendHighI32X4S, "i64x2.extend_high_i32x4_s", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xc9, I64X2ExtendLowI32X4U, "i64x2.extend_low_i32x4_u", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xca, I64X2ExtendHighI32X4U, "i64x2.extend_high_i32x4_u", "")
WABT_OPCODE(V128, V128, I32, ___, 0, 0xfd, 0xcb, I64X2Shl, "i64x2.shl", "")
WABT_OPCODE(V128, V128, I32, ___, 0, 0xfd, 0xcc, I64X2ShrS, "i64x2.shr_s", "")
WABT_OPCODE(V128, V128, I32, ___, 0, 0xfd, 0xcd, I64X2ShrU, "i64x2.shr_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xce, I64X2Add, "i64x2.add", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xd1, I64X2Sub, "i64x2.sub", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xd5, I64X2Mul, "i64x2.mul", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xd6, I64X2Eq, "i64x2.eq", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xd7, I64X2Ne, "i64x2.ne", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xd8, I64X2LtS, "i64x2.lt_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xd9, I64X2GtS, "i64x2.gt_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xda, I64X2LeS, "i64x2.le_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xdb, I64X2GeS, "i64x2.ge_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xdc, I64X2ExtmulLowI32X4S, "i64x2.extmul_low_i32x4_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xdd, I64X2ExtmulHighI32X4S, "i64x2.extmul_high_i32x4_s", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xde, I64X2ExtmulLowI32X4U, "i64x2.extmul_low_i32x4_u", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xdf, I64X2ExtmulHighI32X4U, "i64x2.extmul_high_i32x4_u", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x67, F32X4Ceil, "f32x4.ceil", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x68, F32X4Floor, "f32x4.floor", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x69, F32X4Trunc, "f32x4.trunc", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x6a, F32X4Nearest, "f32x4.nearest", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x74, F64X2Ceil, "f64x2.ceil", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x75, F64X2Floor, "f64x2.floor", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x7a, F64X2Trunc, "f64x2.trunc", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0x94, F64X2Nearest, "f64x2.nearest", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xe0, F32X4Abs, "f32x4.abs", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xe1, F32X4Neg, "f32x4.neg", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xe3, F32X4Sqrt, "f32x4.sqrt", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xe4, F32X4Add, "f32x4.add", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xe5, F32X4Sub, "f32x4.sub", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xe6, F32X4Mul, "f32x4.mul", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xe7, F32X4Div, "f32x4.div", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xe8, F32X4Min, "f32x4.min", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xe9, F32X4Max, "f32x4.max", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xea, F32X4PMin, "f32x4.pmin", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xeb, F32X4PMax, "f32x4.pmax", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xec, F64X2Abs, "f64x2.abs", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xed, F64X2Neg, "f64x2.neg", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xef, F64X2Sqrt, "f64x2.sqrt", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xf0, F64X2Add, "f64x2.add", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xf1, F64X2Sub, "f64x2.sub", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xf2, F64X2Mul, "f64x2.mul", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xf3, F64X2Div, "f64x2.div", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xf4, F64X2Min, "f64x2.min", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xf5, F64X2Max, "f64x2.max", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xf6, F64X2PMin, "f64x2.pmin", "")
WABT_OPCODE(V128, V128, V128, ___, 0, 0xfd, 0xf7, F64X2PMax, "f64x2.pmax", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xf8, I32X4TruncSatF32X4S,"i32x4.trunc_sat_f32x4_s", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xf9, I32X4TruncSatF32X4U,"i32x4.trunc_sat_f32x4_u", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xfa, F32X4ConvertI32X4S, "f32x4.convert_i32x4_s", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xfb, F32X4ConvertI32X4U, "f32x4.convert_i32x4_u", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xfc, I32X4TruncSatF64X2SZero, "i32x4.trunc_sat_f64x2_s_zero", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xfd, I32X4TruncSatF64X2UZero, "i32x4.trunc_sat_f64x2_u_zero", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xfe, F64X2ConvertLowI32X4S, "f64x2.convert_low_i32x4_s", "")
WABT_OPCODE(V128, V128, ___, ___, 0, 0xfd, 0xff, F64X2ConvertLowI32X4U, "f64x2.convert_low_i32x4_u", "")
/* Thread opcodes (--enable-threads) */
WABT_OPCODE(I32, I32, I32, ___, 4, 0xfe, 0x00, MemoryAtomicNotify, "memory.atomic.notify", "")
WABT_OPCODE(I32, I32, I32, I64, 4, 0xfe, 0x01, MemoryAtomicWait32, "memory.atomic.wait32", "")
WABT_OPCODE(I32, I32, I64, I64, 8, 0xfe, 0x02, MemoryAtomicWait64, "memory.atomic.wait64", "")
WABT_OPCODE(___, ___, ___, ___, 0, 0xfe, 0x03, AtomicFence, "atomic.fence", "")
WABT_OPCODE(I32, I32, ___, ___, 4, 0xfe, 0x10, I32AtomicLoad, "i32.atomic.load", "")
WABT_OPCODE(I64, I32, ___, ___, 8, 0xfe, 0x11, I64AtomicLoad, "i64.atomic.load", "")
WABT_OPCODE(I32, I32, ___, ___, 1, 0xfe, 0x12, I32AtomicLoad8U, "i32.atomic.load8_u", "")
WABT_OPCODE(I32, I32, ___, ___, 2, 0xfe, 0x13, I32AtomicLoad16U, "i32.atomic.load16_u", "")
WABT_OPCODE(I64, I32, ___, ___, 1, 0xfe, 0x14, I64AtomicLoad8U, "i64.atomic.load8_u", "")
WABT_OPCODE(I64, I32, ___, ___, 2, 0xfe, 0x15, I64AtomicLoad16U, "i64.atomic.load16_u", "")
WABT_OPCODE(I64, I32, ___, ___, 4, 0xfe, 0x16, I64AtomicLoad32U, "i64.atomic.load32_u", "")
WABT_OPCODE(___, I32, I32, ___, 4, 0xfe, 0x17, I32AtomicStore, "i32.atomic.store", "")
WABT_OPCODE(___, I32, I64, ___, 8, 0xfe, 0x18, I64AtomicStore, "i64.atomic.store", "")
WABT_OPCODE(___, I32, I32, ___, 1, 0xfe, 0x19, I32AtomicStore8, "i32.atomic.store8", "")
WABT_OPCODE(___, I32, I32, ___, 2, 0xfe, 0x1a, I32AtomicStore16, "i32.atomic.store16", "")
WABT_OPCODE(___, I32, I64, ___, 1, 0xfe, 0x1b, I64AtomicStore8, "i64.atomic.store8", "")
WABT_OPCODE(___, I32, I64, ___, 2, 0xfe, 0x1c, I64AtomicStore16, "i64.atomic.store16", "")
WABT_OPCODE(___, I32, I64, ___, 4, 0xfe, 0x1d, I64AtomicStore32, "i64.atomic.store32", "")
WABT_OPCODE(I32, I32, I32, ___, 4, 0xfe, 0x1e, I32AtomicRmwAdd, "i32.atomic.rmw.add", "")
WABT_OPCODE(I64, I32, I64, ___, 8, 0xfe, 0x1f, I64AtomicRmwAdd, "i64.atomic.rmw.add", "")
WABT_OPCODE(I32, I32, I32, ___, 1, 0xfe, 0x20, I32AtomicRmw8AddU, "i32.atomic.rmw8.add_u", "")
WABT_OPCODE(I32, I32, I32, ___, 2, 0xfe, 0x21, I32AtomicRmw16AddU, "i32.atomic.rmw16.add_u", "")
WABT_OPCODE(I64, I32, I64, ___, 1, 0xfe, 0x22, I64AtomicRmw8AddU, "i64.atomic.rmw8.add_u", "")
WABT_OPCODE(I64, I32, I64, ___, 2, 0xfe, 0x23, I64AtomicRmw16AddU, "i64.atomic.rmw16.add_u", "")
WABT_OPCODE(I64, I32, I64, ___, 4, 0xfe, 0x24, I64AtomicRmw32AddU, "i64.atomic.rmw32.add_u", "")
WABT_OPCODE(I32, I32, I32, ___, 4, 0xfe, 0x25, I32AtomicRmwSub, "i32.atomic.rmw.sub", "")
WABT_OPCODE(I64, I32, I64, ___, 8, 0xfe, 0x26, I64AtomicRmwSub, "i64.atomic.rmw.sub", "")
WABT_OPCODE(I32, I32, I32, ___, 1, 0xfe, 0x27, I32AtomicRmw8SubU, "i32.atomic.rmw8.sub_u", "")
WABT_OPCODE(I32, I32, I32, ___, 2, 0xfe, 0x28, I32AtomicRmw16SubU, "i32.atomic.rmw16.sub_u", "")
WABT_OPCODE(I64, I32, I64, ___, 1, 0xfe, 0x29, I64AtomicRmw8SubU, "i64.atomic.rmw8.sub_u", "")
WABT_OPCODE(I64, I32, I64, ___, 2, 0xfe, 0x2a, I64AtomicRmw16SubU, "i64.atomic.rmw16.sub_u", "")
WABT_OPCODE(I64, I32, I64, ___, 4, 0xfe, 0x2b, I64AtomicRmw32SubU, "i64.atomic.rmw32.sub_u", "")
WABT_OPCODE(I32, I32, I32, ___, 4, 0xfe, 0x2c, I32AtomicRmwAnd, "i32.atomic.rmw.and", "")
WABT_OPCODE(I64, I32, I64, ___, 8, 0xfe, 0x2d, I64AtomicRmwAnd, "i64.atomic.rmw.and", "")
WABT_OPCODE(I32, I32, I32, ___, 1, 0xfe, 0x2e, I32AtomicRmw8AndU, "i32.atomic.rmw8.and_u", "")
WABT_OPCODE(I32, I32, I32, ___, 2, 0xfe, 0x2f, I32AtomicRmw16AndU, "i32.atomic.rmw16.and_u", "")
WABT_OPCODE(I64, I32, I64, ___, 1, 0xfe, 0x30, I64AtomicRmw8AndU, "i64.atomic.rmw8.and_u", "")
WABT_OPCODE(I64, I32, I64, ___, 2, 0xfe, 0x31, I64AtomicRmw16AndU, "i64.atomic.rmw16.and_u", "")
WABT_OPCODE(I64, I32, I64, ___, 4, 0xfe, 0x32, I64AtomicRmw32AndU, "i64.atomic.rmw32.and_u", "")
WABT_OPCODE(I32, I32, I32, ___, 4, 0xfe, 0x33, I32AtomicRmwOr, "i32.atomic.rmw.or", "")
WABT_OPCODE(I64, I32, I64, ___, 8, 0xfe, 0x34, I64AtomicRmwOr, "i64.atomic.rmw.or", "")
WABT_OPCODE(I32, I32, I32, ___, 1, 0xfe, 0x35, I32AtomicRmw8OrU, "i32.atomic.rmw8.or_u", "")
WABT_OPCODE(I32, I32, I32, ___, 2, 0xfe, 0x36, I32AtomicRmw16OrU, "i32.atomic.rmw16.or_u", "")
WABT_OPCODE(I64, I32, I64, ___, 1, 0xfe, 0x37, I64AtomicRmw8OrU, "i64.atomic.rmw8.or_u", "")
WABT_OPCODE(I64, I32, I64, ___, 2, 0xfe, 0x38, I64AtomicRmw16OrU, "i64.atomic.rmw16.or_u", "")
WABT_OPCODE(I64, I32, I64, ___, 4, 0xfe, 0x39, I64AtomicRmw32OrU, "i64.atomic.rmw32.or_u", "")
WABT_OPCODE(I32, I32, I32, ___, 4, 0xfe, 0x3a, I32AtomicRmwXor, "i32.atomic.rmw.xor", "")
WABT_OPCODE(I64, I32, I64, ___, 8, 0xfe, 0x3b, I64AtomicRmwXor, "i64.atomic.rmw.xor", "")
WABT_OPCODE(I32, I32, I32, ___, 1, 0xfe, 0x3c, I32AtomicRmw8XorU, "i32.atomic.rmw8.xor_u", "")
WABT_OPCODE(I32, I32, I32, ___, 2, 0xfe, 0x3d, I32AtomicRmw16XorU, "i32.atomic.rmw16.xor_u", "")
WABT_OPCODE(I64, I32, I64, ___, 1, 0xfe, 0x3e, I64AtomicRmw8XorU, "i64.atomic.rmw8.xor_u", "")
WABT_OPCODE(I64, I32, I64, ___, 2, 0xfe, 0x3f, I64AtomicRmw16XorU, "i64.atomic.rmw16.xor_u", "")
WABT_OPCODE(I64, I32, I64, ___, 4, 0xfe, 0x40, I64AtomicRmw32XorU, "i64.atomic.rmw32.xor_u", "")
WABT_OPCODE(I32, I32, I32, ___, 4, 0xfe, 0x41, I32AtomicRmwXchg, "i32.atomic.rmw.xchg", "")
WABT_OPCODE(I64, I32, I64, ___, 8, 0xfe, 0x42, I64AtomicRmwXchg, "i64.atomic.rmw.xchg", "")
WABT_OPCODE(I32, I32, I32, ___, 1, 0xfe, 0x43, I32AtomicRmw8XchgU, "i32.atomic.rmw8.xchg_u", "")
WABT_OPCODE(I32, I32, I32, ___, 2, 0xfe, 0x44, I32AtomicRmw16XchgU, "i32.atomic.rmw16.xchg_u", "")
WABT_OPCODE(I64, I32, I64, ___, 1, 0xfe, 0x45, I64AtomicRmw8XchgU, "i64.atomic.rmw8.xchg_u", "")
WABT_OPCODE(I64, I32, I64, ___, 2, 0xfe, 0x46, I64AtomicRmw16XchgU, "i64.atomic.rmw16.xchg_u", "")
WABT_OPCODE(I64, I32, I64, ___, 4, 0xfe, 0x47, I64AtomicRmw32XchgU, "i64.atomic.rmw32.xchg_u", "")
WABT_OPCODE(I32, I32, I32, I32, 4, 0xfe, 0x48, I32AtomicRmwCmpxchg, "i32.atomic.rmw.cmpxchg", "")
WABT_OPCODE(I64, I32, I64, I64, 8, 0xfe, 0x49, I64AtomicRmwCmpxchg, "i64.atomic.rmw.cmpxchg", "")
WABT_OPCODE(I32, I32, I32, I32, 1, 0xfe, 0x4a, I32AtomicRmw8CmpxchgU, "i32.atomic.rmw8.cmpxchg_u", "")
WABT_OPCODE(I32, I32, I32, I32, 2, 0xfe, 0x4b, I32AtomicRmw16CmpxchgU, "i32.atomic.rmw16.cmpxchg_u", "")
WABT_OPCODE(I64, I32, I64, I64, 1, 0xfe, 0x4c, I64AtomicRmw8CmpxchgU, "i64.atomic.rmw8.cmpxchg_u", "")
WABT_OPCODE(I64, I32, I64, I64, 2, 0xfe, 0x4d, I64AtomicRmw16CmpxchgU, "i64.atomic.rmw16.cmpxchg_u", "")
WABT_OPCODE(I64, I32, I64, I64, 4, 0xfe, 0x4e, I64AtomicRmw32CmpxchgU, "i64.atomic.rmw32.cmpxchg_u", "")

182
third_party/wasm2c/src/opcode.h vendored Normal file
View File

@@ -0,0 +1,182 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_OPCODE_H_
#define WABT_OPCODE_H_
#include <vector>
#include "src/common.h"
#include "src/opcode-code-table.h"
#include "src/leb128.h"
namespace wabt {
class Features;
struct Opcode {
// Opcode enumerations.
//
// NOTE: this enum does not match the binary encoding.
//
enum Enum : uint32_t {
#define WABT_OPCODE(rtype, type1, type2, type3, mem_size, prefix, code, Name, \
text, decomp) \
Name,
#include "src/opcode.def"
#undef WABT_OPCODE
Invalid,
};
// Static opcode objects.
#define WABT_OPCODE(rtype, type1, type2, type3, mem_size, prefix, code, Name, \
text, decomp) \
static Opcode Name##_Opcode;
#include "src/opcode.def"
#undef WABT_OPCODE
Opcode() = default; // Provided so Opcode can be member of a union.
Opcode(Enum e) : enum_(e) {}
operator Enum() const { return enum_; }
static Opcode FromCode(uint32_t);
static Opcode FromCode(uint8_t prefix, uint32_t code);
bool HasPrefix() const { return GetInfo().prefix != 0; }
uint8_t GetPrefix() const { return GetInfo().prefix; }
uint32_t GetCode() const { return GetInfo().code; }
size_t GetLength() const { return GetBytes().size(); }
const char* GetName() const { return GetInfo().name; }
const char* GetDecomp() const {
return *GetInfo().decomp ? GetInfo().decomp : GetInfo().name;
}
Type GetResultType() const { return GetInfo().result_type; }
Type GetParamType1() const { return GetInfo().param_types[0]; }
Type GetParamType2() const { return GetInfo().param_types[1]; }
Type GetParamType3() const { return GetInfo().param_types[2]; }
Type GetParamType(int n) const { return GetInfo().param_types[n - 1]; }
Address GetMemorySize() const { return GetInfo().memory_size; }
// If this is a load/store op, the type depends on the memory used.
Type GetMemoryParam(Type param,
const Limits* limits,
bool has_address_operands) {
return limits && limits->is_64 && has_address_operands ? Type(Type::I64)
: param;
}
// Get the byte sequence for this opcode, including prefix.
std::vector<uint8_t> GetBytes() const;
// Get the lane count of an extract/replace simd op.
uint32_t GetSimdLaneCount() const;
// Return 1 if |alignment| matches the alignment of |opcode|, or if
// |alignment| is WABT_USE_NATURAL_ALIGNMENT.
bool IsNaturallyAligned(Address alignment) const;
// If |alignment| is WABT_USE_NATURAL_ALIGNMENT, return the alignment of
// |opcode|, else return |alignment|.
Address GetAlignment(Address alignment) const;
static bool IsPrefixByte(uint8_t byte) {
return byte == kMathPrefix || byte == kThreadsPrefix || byte == kSimdPrefix;
}
bool IsEnabled(const Features& features) const;
bool IsInvalid() const { return enum_ >= Invalid; }
private:
static const uint32_t kMathPrefix = 0xfc;
static const uint32_t kThreadsPrefix = 0xfe;
static const uint32_t kSimdPrefix = 0xfd;
struct Info {
const char* name;
const char* decomp;
Type result_type;
Type param_types[3];
Address memory_size;
uint8_t prefix;
uint32_t code;
uint32_t prefix_code; // See PrefixCode below. Used for fast lookup.
};
static uint32_t PrefixCode(uint8_t prefix, uint32_t code) {
// For now, 8 bits is enough for all codes.
if (code >= 0x100) {
// Clamp to 0xff, since we know that it is an invalid code.
code = 0xff;
}
return (prefix << 8) | code;
}
// The Opcode struct only stores an enumeration (Opcode::Enum) of all valid
// opcodes, densely packed. We want to be able to store invalid opcodes as
// well, for display to the user. To encode these, we use PrefixCode() to
// generate a uint32_t of the prefix/code pair, then negate the value so it
// doesn't overlap with the valid enum values. The negation is done using
// `~code + 1` since prefix_code is unsigned, and MSVC warns if you use - on
// an unsigned value.
//
// | 0 | Opcode::Invalid | INT32_MAX+1 UINT32_MAX |
// |---------------|-------------------------|---------------------------|
// | valid opcodes | unused space | invalid opcodes |
//
static Enum EncodeInvalidOpcode(uint32_t prefix_code) {
Enum result = static_cast<Enum>(~prefix_code + 1);
assert(result >= Invalid);
return result;
}
static void DecodeInvalidOpcode(Enum e,
uint8_t* out_prefix,
uint32_t* out_code) {
uint32_t prefix_code = ~static_cast<uint32_t>(e) + 1;
*out_prefix = prefix_code >> 8;
*out_code = prefix_code & 0xff;
}
Info GetInfo() const;
static Info infos_[];
Enum enum_;
};
// static
inline Opcode Opcode::FromCode(uint32_t code) {
return FromCode(0, code);
}
// static
inline Opcode Opcode::FromCode(uint8_t prefix, uint32_t code) {
uint32_t prefix_code = PrefixCode(prefix, code);
if (WABT_LIKELY(prefix_code < WABT_ARRAY_SIZE(WabtOpcodeCodeTable))) {
uint32_t value = WabtOpcodeCodeTable[prefix_code];
// The default value in the table is 0. That's a valid value, but only if
// the code is 0 (for nop).
if (WABT_LIKELY(value != 0 || code == 0)) {
return Opcode(static_cast<Enum>(value));
}
}
return Opcode(EncodeInvalidOpcode(prefix_code));
}
} // namespace wabt
#endif // WABT_OPCODE_H_

356
third_party/wasm2c/src/option-parser.cc vendored Normal file
View File

@@ -0,0 +1,356 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/option-parser.h"
#include <cstdarg>
#include <cstdio>
#include <cstring>
#include "config.h"
#if HAVE_ALLOCA
#include <alloca.h>
#endif
namespace wabt {
OptionParser::Option::Option(char short_name,
const std::string& long_name,
const std::string& metavar,
HasArgument has_argument,
const std::string& help,
const Callback& callback)
: short_name(short_name),
long_name(long_name),
metavar(metavar),
has_argument(has_argument == HasArgument::Yes),
help(help),
callback(callback) {}
OptionParser::Argument::Argument(const std::string& name,
ArgumentCount count,
const Callback& callback)
: name(name), count(count), callback(callback) {}
OptionParser::OptionParser(const char* program_name, const char* description)
: program_name_(program_name),
description_(description),
on_error_([this](const std::string& message) { DefaultError(message); }) {
// Add common options
AddOption("help", "Print this help message", [this]() {
PrintHelp();
exit(0);
});
AddOption("version", "Print version information", []() {
printf("%s\n", CMAKE_PROJECT_VERSION);
exit(0);
});
}
void OptionParser::AddOption(const Option& option) {
options_.emplace_back(option);
}
void OptionParser::AddArgument(const std::string& name,
ArgumentCount count,
const Callback& callback) {
arguments_.emplace_back(name, count, callback);
}
void OptionParser::AddOption(char short_name,
const char* long_name,
const char* help,
const NullCallback& callback) {
Option option(short_name, long_name, std::string(), HasArgument::No, help,
[callback](const char*) { callback(); });
AddOption(option);
}
void OptionParser::AddOption(const char* long_name,
const char* help,
const NullCallback& callback) {
Option option('\0', long_name, std::string(), HasArgument::No, help,
[callback](const char*) { callback(); });
AddOption(option);
}
void OptionParser::AddOption(char short_name,
const char* long_name,
const char* metavar,
const char* help,
const Callback& callback) {
Option option(short_name, long_name, metavar, HasArgument::Yes, help,
callback);
AddOption(option);
}
void OptionParser::SetErrorCallback(const Callback& callback) {
on_error_ = callback;
}
// static
int OptionParser::Match(const char* s,
const std::string& full,
bool has_argument) {
int i;
for (i = 0;; i++) {
if (full[i] == '\0') {
// Perfect match. Return +1, so it will be preferred over a longer option
// with the same prefix.
if (s[i] == '\0') {
return i + 1;
}
// We want to fail if s is longer than full, e.g. --foobar vs. --foo.
// However, if s ends with an '=', it's OK.
if (!(has_argument && s[i] == '=')) {
return -1;
}
break;
}
if (s[i] == '\0') {
break;
}
if (s[i] != full[i]) {
return -1;
}
}
return i;
}
void OptionParser::Errorf(const char* format, ...) {
WABT_SNPRINTF_ALLOCA(buffer, length, format);
std::string msg(program_name_);
msg += ": ";
msg += buffer;
msg += "\nTry '--help' for more information.";
on_error_(msg.c_str());
}
void OptionParser::DefaultError(const std::string& message) {
WABT_FATAL("%s\n", message.c_str());
}
void OptionParser::HandleArgument(size_t* arg_index, const char* arg_value) {
if (*arg_index >= arguments_.size()) {
Errorf("unexpected argument '%s'", arg_value);
return;
}
Argument& argument = arguments_[*arg_index];
argument.callback(arg_value);
argument.handled_count++;
if (argument.count == ArgumentCount::One) {
(*arg_index)++;
}
}
void OptionParser::Parse(int argc, char* argv[]) {
size_t arg_index = 0;
bool processing_options = true;
for (int i = 1; i < argc; ++i) {
const char* arg = argv[i];
if (!processing_options || arg[0] != '-') {
// Non-option argument.
HandleArgument(&arg_index, arg);
continue;
}
if (arg[1] == '-') {
if (arg[2] == '\0') {
// -- on its own means stop processing args, everything should
// be treated as positional.
processing_options = false;
continue;
}
// Long option.
int best_index = -1;
int best_length = 0;
int best_count = 0;
for (size_t j = 0; j < options_.size(); ++j) {
const Option& option = options_[j];
if (!option.long_name.empty()) {
int match_length =
Match(&arg[2], option.long_name, option.has_argument);
if (match_length > best_length) {
best_index = j;
best_length = match_length;
best_count = 1;
} else if (match_length == best_length && best_length > 0) {
best_count++;
}
}
}
if (best_count > 1) {
Errorf("ambiguous option '%s'", arg);
continue;
} else if (best_count == 0) {
Errorf("unknown option '%s'", arg);
continue;
}
const Option& best_option = options_[best_index];
const char* option_argument = nullptr;
if (best_option.has_argument) {
if (arg[best_length + 1] != 0 && // This byte is 0 on a full match.
arg[best_length + 2] == '=') { // +2 to skip "--".
option_argument = &arg[best_length + 3];
} else {
if (i + 1 == argc || argv[i + 1][0] == '-') {
Errorf("option '--%s' requires argument",
best_option.long_name.c_str());
continue;
}
++i;
option_argument = argv[i];
}
}
best_option.callback(option_argument);
} else {
// Short option.
if (arg[1] == '\0') {
// Just "-".
HandleArgument(&arg_index, arg);
continue;
}
// Allow short names to be combined, e.g. "-d -v" => "-dv".
for (int k = 1; arg[k]; ++k) {
bool matched = false;
for (const Option& option : options_) {
if (option.short_name && arg[k] == option.short_name) {
const char* option_argument = nullptr;
if (option.has_argument) {
// A short option with a required argument cannot be followed
// by other short options_.
if (arg[k + 1] != '\0') {
Errorf("option '-%c' requires argument", option.short_name);
break;
}
if (i + 1 == argc || argv[i + 1][0] == '-') {
Errorf("option '-%c' requires argument", option.short_name);
break;
}
++i;
option_argument = argv[i];
}
option.callback(option_argument);
matched = true;
break;
}
}
if (!matched) {
Errorf("unknown option '-%c'", arg[k]);
continue;
}
}
}
}
// For now, all arguments must be provided. Check that the last Argument was
// handled at least once.
if (!arguments_.empty() && arguments_.back().handled_count == 0) {
for (size_t i = arg_index; i < arguments_.size(); ++i) {
if (arguments_[i].count != ArgumentCount::ZeroOrMore) {
Errorf("expected %s argument.", arguments_[i].name.c_str());
}
}
}
}
void OptionParser::PrintHelp() {
printf("usage: %s [options]", program_name_.c_str());
for (size_t i = 0; i < arguments_.size(); ++i) {
Argument& argument = arguments_[i];
switch (argument.count) {
case ArgumentCount::One:
printf(" %s", argument.name.c_str());
break;
case ArgumentCount::OneOrMore:
printf(" %s+", argument.name.c_str());
break;
case ArgumentCount::ZeroOrMore:
printf(" [%s]...", argument.name.c_str());
break;
}
}
printf("\n\n");
printf("%s\n", description_.c_str());
printf("options:\n");
const size_t kExtraSpace = 8;
size_t longest_name_length = 0;
for (const Option& option : options_) {
size_t length;
if (!option.long_name.empty()) {
length = option.long_name.size();
if (!option.metavar.empty()) {
// +1 for '='.
length += option.metavar.size() + 1;
}
} else {
continue;
}
if (length > longest_name_length) {
longest_name_length = length;
}
}
for (const Option& option : options_) {
if (!option.short_name && option.long_name.empty()) {
continue;
}
std::string line;
if (option.short_name) {
line += std::string(" -") + option.short_name + ", ";
} else {
line += " ";
}
std::string flag;
if (!option.long_name.empty()) {
flag = "--";
if (!option.metavar.empty()) {
flag += option.long_name + '=' + option.metavar;
} else {
flag += option.long_name;
}
}
// +2 for "--" of the long flag name.
size_t remaining = longest_name_length + kExtraSpace + 2 - flag.size();
line += flag + std::string(remaining, ' ');
if (!option.help.empty()) {
line += option.help;
}
printf("%s\n", line.c_str());
}
}
} // namespace wabt

99
third_party/wasm2c/src/option-parser.h vendored Normal file
View File

@@ -0,0 +1,99 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_OPTION_PARSER_H_
#define WABT_OPTION_PARSER_H_
#include <functional>
#include <string>
#include <vector>
#include "src/common.h"
namespace wabt {
class OptionParser {
public:
enum class HasArgument { No, Yes };
enum class ArgumentCount { One, OneOrMore, ZeroOrMore };
struct Option;
typedef std::function<void(const char*)> Callback;
typedef std::function<void()> NullCallback;
struct Option {
Option(char short_name,
const std::string& long_name,
const std::string& metavar,
HasArgument has_argument,
const std::string& help,
const Callback&);
char short_name;
std::string long_name;
std::string metavar;
bool has_argument;
std::string help;
Callback callback;
};
struct Argument {
Argument(const std::string& name, ArgumentCount, const Callback&);
std::string name;
ArgumentCount count;
Callback callback;
int handled_count = 0;
};
explicit OptionParser(const char* program_name, const char* description);
void AddOption(const Option&);
void AddArgument(const std::string& name, ArgumentCount, const Callback&);
void SetErrorCallback(const Callback&);
void Parse(int argc, char* argv[]);
void PrintHelp();
// Helper functions.
void AddOption(char short_name,
const char* long_name,
const char* help,
const NullCallback&);
void AddOption(const char* long_name, const char* help, const NullCallback&);
void AddOption(char short_name,
const char* long_name,
const char* metavar,
const char* help,
const Callback&);
private:
static int Match(const char* s, const std::string& full, bool has_argument);
void WABT_PRINTF_FORMAT(2, 3) Errorf(const char* format, ...);
void HandleArgument(size_t* arg_index, const char* arg_value);
// Print the error and exit(1).
void DefaultError(const std::string&);
std::string program_name_;
std::string description_;
std::vector<Option> options_;
std::vector<Argument> arguments_;
Callback on_error_;
};
} // namespace wabt
#endif /* WABT_OPTION_PARSER_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,269 @@
/* Generated from 'wasm2c.c.tmpl' by wasm2c_tmpl.py, do not edit! */
const char SECTION_NAME(includes)[] =
"/* Automically generated by wasm2c */\n"
"#include <math.h>\n"
"#include <string.h>\n"
"#include <stdlib.h>\n"
;
const char SECTION_NAME(declarations)[] =
"#if defined(_MSC_VER)\n"
" #define UNLIKELY(x) (x)\n"
" #define LIKELY(x) (x)\n"
"#else\n"
" #define UNLIKELY(x) __builtin_expect(!!(x), 0)\n"
" #define LIKELY(x) __builtin_expect(!!(x), 1)\n"
"#endif\n"
"\n"
"#define TRAP(x) (wasm_rt_trap(WASM_RT_TRAP_##x), 0)\n"
"\n"
"#define FUNC_PROLOGUE\n"
"\n"
"#define FUNC_EPILOGUE\n"
"\n"
"#define UNREACHABLE TRAP(UNREACHABLE)\n"
"\n"
"#define CALL_INDIRECT(table, t, ft, x, func_types, ...) \\\n"
" (LIKELY((x) < table.size && table.data[x].func && \\\n"
" table.data[x].func_type == func_types[ft]) \\\n"
" ? ((t)table.data[x].func)(__VA_ARGS__) \\\n"
" : TRAP(CALL_INDIRECT))\n"
"\n"
"#if WASM_USING_GUARD_PAGES == 1\n"
"#define MEMCHECK(mem, a, t)\n"
"#else\n"
"#define MEMCHECK(mem, a, t) \\\n"
" if (UNLIKELY((a) + sizeof(t) > mem->size)) TRAP(OOB)\n"
"#endif\n"
"\n"
"#if defined(WASM_USING_GLOBAL_HEAP)\n"
"#define MEM_ACCESS_REF(mem, addr) (char*) addr\n"
"#else\n"
"#define MEM_ACCESS_REF(mem, addr) &mem->data[addr]\n"
"#endif\n"
"\n"
"#if WABT_BIG_ENDIAN\n"
"static inline void load_data(void *dest, const void *src, size_t n) {\n"
" size_t i = 0;\n"
" u8 *dest_chars = dest;\n"
" memcpy(dest, src, n);\n"
" for (i = 0; i < (n>>1); i++) {\n"
" u8 cursor = dest_chars[i];\n"
" dest_chars[i] = dest_chars[n - i - 1];\n"
" dest_chars[n - i - 1] = cursor;\n"
" }\n"
"}\n"
"#define LOAD_DATA(m, o, i, s) load_data(&(m.data[m.size - o - s]), i, s)\n"
"#define DEFINE_LOAD(name, t1, t2, t3) \\\n"
" static inline t3 name(wasm_rt_memory_t* mem, u64 addr) { \\\n"
" MEMCHECK(mem, addr, t1); \\\n"
" t1 result; \\\n"
" memcpy(&result, MEM_ACCESS_REF(mem, mem->size - addr - sizeof(t1)), sizeof(t1)); \\\n"
" return (t3)(t2)result; \\\n"
" }\n"
"\n"
"#define DEFINE_STORE(name, t1, t2) \\\n"
" static inline void name(wasm_rt_memory_t* mem, u64 addr, t2 value) { \\\n"
" MEMCHECK(mem, addr, t1); \\\n"
" t1 wrapped = (t1)value; \\\n"
" memcpy(MEM_ACCESS_REF(mem, mem->size - addr - sizeof(t1)), &wrapped, sizeof(t1)); \\\n"
" }\n"
"#else\n"
"static inline void load_data(void *dest, const void *src, size_t n) {\n"
" memcpy(dest, src, n);\n"
"}\n"
"#define LOAD_DATA(m, o, i, s) load_data(&(m.data[o]), i, s)\n"
"#define DEFINE_LOAD(name, t1, t2, t3) \\\n"
" static inline t3 name(wasm_rt_memory_t* mem, u64 addr) { \\\n"
" MEMCHECK(mem, addr, t1); \\\n"
" t1 result; \\\n"
" memcpy(&result, MEM_ACCESS_REF(mem, addr), sizeof(t1)); \\\n"
" return (t3)(t2)result; \\\n"
" }\n"
"\n"
"#define DEFINE_STORE(name, t1, t2) \\\n"
" static inline void name(wasm_rt_memory_t* mem, u64 addr, t2 value) { \\\n"
" MEMCHECK(mem, addr, t1); \\\n"
" t1 wrapped = (t1)value; \\\n"
" memcpy(MEM_ACCESS_REF(mem, addr), &wrapped, sizeof(t1)); \\\n"
" }\n"
"#endif\n"
"\n"
"DEFINE_LOAD(i32_load, u32, u32, u32);\n"
"DEFINE_LOAD(i64_load, u64, u64, u64);\n"
"DEFINE_LOAD(f32_load, f32, f32, f32);\n"
"DEFINE_LOAD(f64_load, f64, f64, f64);\n"
"DEFINE_LOAD(i32_load8_s, s8, s32, u32);\n"
"DEFINE_LOAD(i64_load8_s, s8, s64, u64);\n"
"DEFINE_LOAD(i32_load8_u, u8, u32, u32);\n"
"DEFINE_LOAD(i64_load8_u, u8, u64, u64);\n"
"DEFINE_LOAD(i32_load16_s, s16, s32, u32);\n"
"DEFINE_LOAD(i64_load16_s, s16, s64, u64);\n"
"DEFINE_LOAD(i32_load16_u, u16, u32, u32);\n"
"DEFINE_LOAD(i64_load16_u, u16, u64, u64);\n"
"DEFINE_LOAD(i64_load32_s, s32, s64, u64);\n"
"DEFINE_LOAD(i64_load32_u, u32, u64, u64);\n"
"DEFINE_STORE(i32_store, u32, u32);\n"
"DEFINE_STORE(i64_store, u64, u64);\n"
"DEFINE_STORE(f32_store, f32, f32);\n"
"DEFINE_STORE(f64_store, f64, f64);\n"
"DEFINE_STORE(i32_store8, u8, u32);\n"
"DEFINE_STORE(i32_store16, u16, u32);\n"
"DEFINE_STORE(i64_store8, u8, u64);\n"
"DEFINE_STORE(i64_store16, u16, u64);\n"
"DEFINE_STORE(i64_store32, u32, u64);\n"
"\n"
"#if defined(_MSC_VER)\n"
" #include <intrin.h>\n"
"\n"
"// Adapted from https://github.com/nemequ/portable-snippets/blob/master/builtin/builtin.h\n"
"\n"
"static inline int I64_CLZ(unsigned long long v) {\n"
" unsigned long r = 0;\n"
" #if defined(_M_AMD64) || defined(_M_ARM)\n"
" if (_BitScanReverse64(&r, v)) {\n"
" return 63 - r;\n"
" }\n"
" #else\n"
" if (_BitScanReverse(&r, (unsigned long) (v >> 32))) {\n"
" return 31 - r;\n"
" } else if (_BitScanReverse(&r, (unsigned long) v)) {\n"
" return 63 - r;\n"
" }\n"
" #endif\n"
" return 64;\n"
"}\n"
"\n"
"static inline int I32_CLZ(unsigned long v) {\n"
" unsigned long r = 0;\n"
" if (_BitScanReverse(&r, v)) {\n"
" return 31 - r;\n"
" }\n"
" return 32;\n"
"}\n"
"\n"
"static inline int I64_CTZ(unsigned long long v) {\n"
" if (!v) {\n"
" return 64;\n"
" }\n"
" unsigned long r = 0;\n"
" #if defined(_M_AMD64) || defined(_M_ARM)\n"
" _BitScanForward64(&r, v);\n"
" return (int) r;\n"
" #else\n"
" if (_BitScanForward(&r, (unsigned int) (v))) {\n"
" return (int) (r);\n"
" }\n"
"\n"
" _BitScanForward(&r, (unsigned int) (v >> 32));\n"
" return (int) (r + 32);\n"
" #endif\n"
"}\n"
"\n"
"static inline int I32_CTZ(unsigned long v) {\n"
" if (!v) {\n"
" return 32;\n"
" }\n"
" unsigned long r = 0;\n"
" _BitScanForward(&r, v);\n"
" return (int) r;\n"
"}\n"
"\n"
"#define POPCOUNT_DEFINE_PORTABLE(f_n, T) \\\n"
" static inline u32 f_n(T x) { \\\n"
" x = x - ((x >> 1) & (T)~(T)0/3); \\\n"
" x = (x & (T)~(T)0/15*3) + ((x >> 2) & (T)~(T)0/15*3); \\\n"
" x = (x + (x >> 4)) & (T)~(T)0/255*15; \\\n"
" return (T)(x * ((T)~(T)0/255)) >> (sizeof(T) - 1) * 8; \\\n"
" }\n"
"\n"
"POPCOUNT_DEFINE_PORTABLE(I32_POPCNT, u32)\n"
"POPCOUNT_DEFINE_PORTABLE(I64_POPCNT, u64)\n"
"\n"
"#undef POPCOUNT_DEFINE_PORTABLE\n"
"\n"
"#else\n"
" #define I32_CLZ(x) ((x) ? __builtin_clz(x) : 32)\n"
" #define I64_CLZ(x) ((x) ? __builtin_clzll(x) : 64)\n"
" #define I32_CTZ(x) ((x) ? __builtin_ctz(x) : 32)\n"
" #define I64_CTZ(x) ((x) ? __builtin_ctzll(x) : 64)\n"
" #define I32_POPCNT(x) (__builtin_popcount(x))\n"
" #define I64_POPCNT(x) (__builtin_popcountll(x))\n"
"#endif\n"
"\n"
"#define DIV_S(ut, min, x, y) \\\n"
" ((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) \\\n"
" : (UNLIKELY((x) == min && (y) == -1)) ? TRAP(INT_OVERFLOW) \\\n"
" : (ut)((x) / (y)))\n"
"\n"
"#define REM_S(ut, min, x, y) \\\n"
" ((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) \\\n"
" : (UNLIKELY((x) == min && (y) == -1)) ? 0 \\\n"
" : (ut)((x) % (y)))\n"
"\n"
"#define I32_DIV_S(x, y) DIV_S(u32, INT32_MIN, (s32)x, (s32)y)\n"
"#define I64_DIV_S(x, y) DIV_S(u64, INT64_MIN, (s64)x, (s64)y)\n"
"#define I32_REM_S(x, y) REM_S(u32, INT32_MIN, (s32)x, (s32)y)\n"
"#define I64_REM_S(x, y) REM_S(u64, INT64_MIN, (s64)x, (s64)y)\n"
"\n"
"#define DIVREM_U(op, x, y) \\\n"
" ((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) : ((x) op (y)))\n"
"\n"
"#define DIV_U(x, y) DIVREM_U(/, x, y)\n"
"#define REM_U(x, y) DIVREM_U(%, x, y)\n"
"\n"
"#define ROTL(x, y, mask) \\\n"
" (((x) << ((y) & (mask))) | ((x) >> (((mask) - (y) + 1) & (mask))))\n"
"#define ROTR(x, y, mask) \\\n"
" (((x) >> ((y) & (mask))) | ((x) << (((mask) - (y) + 1) & (mask))))\n"
"\n"
"#define I32_ROTL(x, y) ROTL(x, y, 31)\n"
"#define I64_ROTL(x, y) ROTL(x, y, 63)\n"
"#define I32_ROTR(x, y) ROTR(x, y, 31)\n"
"#define I64_ROTR(x, y) ROTR(x, y, 63)\n"
"\n"
"#define FMIN(x, y) \\\n"
" ((UNLIKELY((x) != (x))) ? NAN \\\n"
" : (UNLIKELY((y) != (y))) ? NAN \\\n"
" : (UNLIKELY((x) == 0 && (y) == 0)) ? (signbit(x) ? x : y) \\\n"
" : (x < y) ? x : y)\n"
"\n"
"#define FMAX(x, y) \\\n"
" ((UNLIKELY((x) != (x))) ? NAN \\\n"
" : (UNLIKELY((y) != (y))) ? NAN \\\n"
" : (UNLIKELY((x) == 0 && (y) == 0)) ? (signbit(x) ? y : x) \\\n"
" : (x > y) ? x : y)\n"
"\n"
"#define TRUNC_S(ut, st, ft, min, minop, max, x) \\\n"
" ((UNLIKELY((x) != (x))) ? TRAP(INVALID_CONVERSION) \\\n"
" : (UNLIKELY(!((x)minop(min) && (x) < (max)))) ? TRAP(INT_OVERFLOW) \\\n"
" : (ut)(st)(x))\n"
"\n"
"#define I32_TRUNC_S_F32(x) TRUNC_S(u32, s32, f32, (f32)INT32_MIN, >=, 2147483648.f, x)\n"
"#define I64_TRUNC_S_F32(x) TRUNC_S(u64, s64, f32, (f32)INT64_MIN, >=, (f32)INT64_MAX, x)\n"
"#define I32_TRUNC_S_F64(x) TRUNC_S(u32, s32, f64, -2147483649., >, 2147483648., x)\n"
"#define I64_TRUNC_S_F64(x) TRUNC_S(u64, s64, f64, (f64)INT64_MIN, >=, (f64)INT64_MAX, x)\n"
"\n"
"#define TRUNC_U(ut, ft, max, x) \\\n"
" ((UNLIKELY((x) != (x))) ? TRAP(INVALID_CONVERSION) \\\n"
" : (UNLIKELY(!((x) > (ft)-1 && (x) < (max)))) ? TRAP(INT_OVERFLOW) \\\n"
" : (ut)(x))\n"
"\n"
"#define I32_TRUNC_U_F32(x) TRUNC_U(u32, f32, 4294967296.f, x)\n"
"#define I64_TRUNC_U_F32(x) TRUNC_U(u64, f32, (f32)UINT64_MAX, x)\n"
"#define I32_TRUNC_U_F64(x) TRUNC_U(u32, f64, 4294967296., x)\n"
"#define I64_TRUNC_U_F64(x) TRUNC_U(u64, f64, (f64)UINT64_MAX, x)\n"
"\n"
"#define DEFINE_REINTERPRET(name, t1, t2) \\\n"
" static inline t2 name(t1 x) { \\\n"
" t2 result; \\\n"
" memcpy(&result, &x, sizeof(result)); \\\n"
" return result; \\\n"
" }\n"
"\n"
"DEFINE_REINTERPRET(f32_reinterpret_i32, u32, f32)\n"
"DEFINE_REINTERPRET(i32_reinterpret_f32, f32, u32)\n"
"DEFINE_REINTERPRET(f64_reinterpret_i64, u64, f64)\n"
"DEFINE_REINTERPRET(i64_reinterpret_f64, f64, u64)\n"
"\n"
;

View File

@@ -0,0 +1,48 @@
/* Generated from 'wasm2c.h.tmpl' by wasm2c_tmpl.py, do not edit! */
const char SECTION_NAME(top)[] =
"/* Automically generated by wasm2c */\n"
"#ifdef __cplusplus\n"
"extern \"C\" {\n"
"#endif\n"
"\n"
"#include <stdint.h>\n"
"\n"
"#include \"wasm-rt.h\"\n"
"\n"
"#ifndef WASM_RT_MODULE_PREFIX\n"
"#define WASM_RT_MODULE_PREFIX\n"
"#endif\n"
"\n"
"#define WASM_RT_PASTE_(x, y) x ## y\n"
"#define WASM_RT_PASTE(x, y) WASM_RT_PASTE_(x, y)\n"
"#define WASM_RT_ADD_PREFIX(x) WASM_RT_PASTE(WASM_RT_MODULE_PREFIX, x)\n"
"\n"
"#define WASM_CURR_ADD_PREFIX(x) WASM_RT_PASTE(WASM_CURR_MODULE_PREFIX, x)\n"
"\n"
"/* TODO(binji): only use stdint.h types in header */\n"
"typedef uint8_t u8;\n"
"typedef int8_t s8;\n"
"typedef uint16_t u16;\n"
"typedef int16_t s16;\n"
"typedef uint32_t u32;\n"
"typedef int32_t s32;\n"
"typedef uint64_t u64;\n"
"typedef int64_t s64;\n"
"typedef float f32;\n"
"typedef double f64;\n"
"\n"
"#if defined(_WIN32)\n"
" #define FUNC_EXPORT __declspec(dllexport)\n"
"#else\n"
" #define FUNC_EXPORT\n"
"#endif\n"
"\n"
"FUNC_EXPORT wasm2c_sandbox_funcs_t WASM_CURR_ADD_PREFIX(get_wasm2c_sandbox_info)();\n"
;
const char SECTION_NAME(bottom)[] =
"\n"
"#ifdef __cplusplus\n"
"}\n"
"#endif\n"
;

37
third_party/wasm2c/src/range.h vendored Normal file
View File

@@ -0,0 +1,37 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_RANGE_H_
#define WABT_RANGE_H_
namespace wabt {
template <typename T>
struct Range {
Range() : start(0), end(0) {}
Range(T start, T end) : start(start), end(end) {}
T start;
T end;
T size() const { return end - start; }
};
typedef Range<Offset> OffsetRange;
typedef Range<int> ColumnRange;
} // namespace wabt
#endif // WABT_RANGE_H_

589
third_party/wasm2c/src/resolve-names.cc vendored Normal file
View File

@@ -0,0 +1,589 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/resolve-names.h"
#include <cassert>
#include <cstdio>
#include "src/cast.h"
#include "src/expr-visitor.h"
#include "src/ir.h"
#include "src/wast-lexer.h"
namespace wabt {
namespace {
class NameResolver : public ExprVisitor::DelegateNop {
public:
NameResolver(Script* script, Errors* errors);
Result VisitModule(Module* module);
Result VisitScript(Script* script);
// Implementation of ExprVisitor::DelegateNop.
Result BeginBlockExpr(BlockExpr*) override;
Result EndBlockExpr(BlockExpr*) override;
Result OnBrExpr(BrExpr*) override;
Result OnBrIfExpr(BrIfExpr*) override;
Result OnBrTableExpr(BrTableExpr*) override;
Result OnCallExpr(CallExpr*) override;
Result OnCallIndirectExpr(CallIndirectExpr*) override;
Result OnCatchExpr(TryExpr*, Catch*) override;
Result OnDelegateExpr(TryExpr*) override;
Result OnReturnCallExpr(ReturnCallExpr *) override;
Result OnReturnCallIndirectExpr(ReturnCallIndirectExpr*) override;
Result OnGlobalGetExpr(GlobalGetExpr*) override;
Result OnGlobalSetExpr(GlobalSetExpr*) override;
Result BeginIfExpr(IfExpr*) override;
Result EndIfExpr(IfExpr*) override;
Result OnLocalGetExpr(LocalGetExpr*) override;
Result OnLocalSetExpr(LocalSetExpr*) override;
Result OnLocalTeeExpr(LocalTeeExpr*) override;
Result BeginLoopExpr(LoopExpr*) override;
Result EndLoopExpr(LoopExpr*) override;
Result OnDataDropExpr(DataDropExpr*) override;
Result OnMemoryInitExpr(MemoryInitExpr*) override;
Result OnElemDropExpr(ElemDropExpr*) override;
Result OnTableCopyExpr(TableCopyExpr*) override;
Result OnTableInitExpr(TableInitExpr*) override;
Result OnTableGetExpr(TableGetExpr*) override;
Result OnTableSetExpr(TableSetExpr*) override;
Result OnTableGrowExpr(TableGrowExpr*) override;
Result OnTableSizeExpr(TableSizeExpr*) override;
Result OnTableFillExpr(TableFillExpr*) override;
Result OnRefFuncExpr(RefFuncExpr*) override;
Result BeginTryExpr(TryExpr*) override;
Result EndTryExpr(TryExpr*) override;
Result OnThrowExpr(ThrowExpr*) override;
Result OnRethrowExpr(RethrowExpr*) override;
private:
void PrintError(const Location* loc, const char* fmt, ...);
void PushLabel(const std::string& label);
void PopLabel();
void CheckDuplicateBindings(const BindingHash* bindings, const char* desc);
void PrintDuplicateBindingsError(const BindingHash::value_type&,
const BindingHash::value_type&,
const char* desc);
void ResolveLabelVar(Var* var);
void ResolveVar(const BindingHash* bindings, Var* var, const char* desc);
void ResolveFuncVar(Var* var);
void ResolveGlobalVar(Var* var);
void ResolveFuncTypeVar(Var* var);
void ResolveTableVar(Var* var);
void ResolveMemoryVar(Var* var);
void ResolveEventVar(Var* var);
void ResolveDataSegmentVar(Var* var);
void ResolveElemSegmentVar(Var* var);
void ResolveLocalVar(Var* var);
void ResolveBlockDeclarationVar(BlockDeclaration* decl);
void VisitFunc(Func* func);
void VisitExport(Export* export_);
void VisitGlobal(Global* global);
void VisitEvent(Event* event);
void VisitElemSegment(ElemSegment* segment);
void VisitDataSegment(DataSegment* segment);
void VisitScriptModule(ScriptModule* script_module);
void VisitCommand(Command* command);
Errors* errors_ = nullptr;
Script* script_ = nullptr;
Module* current_module_ = nullptr;
Func* current_func_ = nullptr;
ExprVisitor visitor_;
std::vector<std::string> labels_;
Result result_ = Result::Ok;
};
NameResolver::NameResolver(Script* script, Errors* errors)
: errors_(errors),
script_(script),
visitor_(this) {}
} // end anonymous namespace
void WABT_PRINTF_FORMAT(3, 4) NameResolver::PrintError(const Location* loc,
const char* format,
...) {
result_ = Result::Error;
WABT_SNPRINTF_ALLOCA(buffer, length, format);
errors_->emplace_back(ErrorLevel::Error, *loc, buffer);
}
void NameResolver::PushLabel(const std::string& label) {
labels_.push_back(label);
}
void NameResolver::PopLabel() {
labels_.pop_back();
}
void NameResolver::CheckDuplicateBindings(const BindingHash* bindings,
const char* desc) {
bindings->FindDuplicates([this, desc](const BindingHash::value_type& a,
const BindingHash::value_type& b) {
PrintDuplicateBindingsError(a, b, desc);
});
}
void NameResolver::PrintDuplicateBindingsError(const BindingHash::value_type& a,
const BindingHash::value_type& b,
const char* desc) {
// Choose the location that is later in the file.
const Location& a_loc = a.second.loc;
const Location& b_loc = b.second.loc;
const Location& loc = a_loc.line > b_loc.line ? a_loc : b_loc;
PrintError(&loc, "redefinition of %s \"%s\"", desc, a.first.c_str());
}
void NameResolver::ResolveLabelVar(Var* var) {
if (var->is_name()) {
for (int i = labels_.size() - 1; i >= 0; --i) {
const std::string& label = labels_[i];
if (label == var->name()) {
var->set_index(labels_.size() - i - 1);
return;
}
}
PrintError(&var->loc, "undefined label variable \"%s\"",
var->name().c_str());
}
}
void NameResolver::ResolveVar(const BindingHash* bindings,
Var* var,
const char* desc) {
if (var->is_name()) {
Index index = bindings->FindIndex(*var);
if (index == kInvalidIndex) {
PrintError(&var->loc, "undefined %s variable \"%s\"", desc,
var->name().c_str());
return;
}
var->set_index(index);
}
}
void NameResolver::ResolveFuncVar(Var* var) {
ResolveVar(&current_module_->func_bindings, var, "function");
}
void NameResolver::ResolveGlobalVar(Var* var) {
ResolveVar(&current_module_->global_bindings, var, "global");
}
void NameResolver::ResolveFuncTypeVar(Var* var) {
ResolveVar(&current_module_->type_bindings, var, "type");
}
void NameResolver::ResolveTableVar(Var* var) {
ResolveVar(&current_module_->table_bindings, var, "table");
}
void NameResolver::ResolveMemoryVar(Var* var) {
ResolveVar(&current_module_->memory_bindings, var, "memory");
}
void NameResolver::ResolveEventVar(Var* var) {
ResolveVar(&current_module_->event_bindings, var, "event");
}
void NameResolver::ResolveDataSegmentVar(Var* var) {
ResolveVar(&current_module_->data_segment_bindings, var, "data segment");
}
void NameResolver::ResolveElemSegmentVar(Var* var) {
ResolveVar(&current_module_->elem_segment_bindings, var, "elem segment");
}
void NameResolver::ResolveLocalVar(Var* var) {
if (var->is_name()) {
if (!current_func_) {
return;
}
Index index = current_func_->GetLocalIndex(*var);
if (index == kInvalidIndex) {
PrintError(&var->loc, "undefined local variable \"%s\"",
var->name().c_str());
return;
}
var->set_index(index);
}
}
void NameResolver::ResolveBlockDeclarationVar(BlockDeclaration* decl) {
if (decl->has_func_type) {
ResolveFuncTypeVar(&decl->type_var);
}
}
Result NameResolver::BeginBlockExpr(BlockExpr* expr) {
PushLabel(expr->block.label);
ResolveBlockDeclarationVar(&expr->block.decl);
return Result::Ok;
}
Result NameResolver::EndBlockExpr(BlockExpr* expr) {
PopLabel();
return Result::Ok;
}
Result NameResolver::BeginLoopExpr(LoopExpr* expr) {
PushLabel(expr->block.label);
ResolveBlockDeclarationVar(&expr->block.decl);
return Result::Ok;
}
Result NameResolver::EndLoopExpr(LoopExpr* expr) {
PopLabel();
return Result::Ok;
}
Result NameResolver::OnBrExpr(BrExpr* expr) {
ResolveLabelVar(&expr->var);
return Result::Ok;
}
Result NameResolver::OnBrIfExpr(BrIfExpr* expr) {
ResolveLabelVar(&expr->var);
return Result::Ok;
}
Result NameResolver::OnBrTableExpr(BrTableExpr* expr) {
for (Var& target : expr->targets)
ResolveLabelVar(&target);
ResolveLabelVar(&expr->default_target);
return Result::Ok;
}
Result NameResolver::OnCallExpr(CallExpr* expr) {
ResolveFuncVar(&expr->var);
return Result::Ok;
}
Result NameResolver::OnCallIndirectExpr(CallIndirectExpr* expr) {
if (expr->decl.has_func_type) {
ResolveFuncTypeVar(&expr->decl.type_var);
}
ResolveTableVar(&expr->table);
return Result::Ok;
}
Result NameResolver::OnReturnCallExpr(ReturnCallExpr* expr) {
ResolveFuncVar(&expr->var);
return Result::Ok;
}
Result NameResolver::OnReturnCallIndirectExpr(ReturnCallIndirectExpr* expr) {
if (expr->decl.has_func_type) {
ResolveFuncTypeVar(&expr->decl.type_var);
}
ResolveTableVar(&expr->table);
return Result::Ok;
}
Result NameResolver::OnGlobalGetExpr(GlobalGetExpr* expr) {
ResolveGlobalVar(&expr->var);
return Result::Ok;
}
Result NameResolver::OnGlobalSetExpr(GlobalSetExpr* expr) {
ResolveGlobalVar(&expr->var);
return Result::Ok;
}
Result NameResolver::BeginIfExpr(IfExpr* expr) {
PushLabel(expr->true_.label);
ResolveBlockDeclarationVar(&expr->true_.decl);
return Result::Ok;
}
Result NameResolver::EndIfExpr(IfExpr* expr) {
PopLabel();
return Result::Ok;
}
Result NameResolver::OnLocalGetExpr(LocalGetExpr* expr) {
ResolveLocalVar(&expr->var);
return Result::Ok;
}
Result NameResolver::OnLocalSetExpr(LocalSetExpr* expr) {
ResolveLocalVar(&expr->var);
return Result::Ok;
}
Result NameResolver::OnLocalTeeExpr(LocalTeeExpr* expr) {
ResolveLocalVar(&expr->var);
return Result::Ok;
}
Result NameResolver::OnDataDropExpr(DataDropExpr* expr) {
ResolveDataSegmentVar(&expr->var);
return Result::Ok;
}
Result NameResolver::OnMemoryInitExpr(MemoryInitExpr* expr) {
ResolveDataSegmentVar(&expr->var);
return Result::Ok;
}
Result NameResolver::OnElemDropExpr(ElemDropExpr* expr) {
ResolveElemSegmentVar(&expr->var);
return Result::Ok;
}
Result NameResolver::OnTableCopyExpr(TableCopyExpr* expr) {
ResolveTableVar(&expr->dst_table);
ResolveTableVar(&expr->src_table);
return Result::Ok;
}
Result NameResolver::OnTableInitExpr(TableInitExpr* expr) {
ResolveElemSegmentVar(&expr->segment_index);
ResolveTableVar(&expr->table_index);
return Result::Ok;
}
Result NameResolver::OnTableGetExpr(TableGetExpr* expr) {
ResolveTableVar(&expr->var);
return Result::Ok;
}
Result NameResolver::OnTableSetExpr(TableSetExpr* expr) {
ResolveTableVar(&expr->var);
return Result::Ok;
}
Result NameResolver::OnTableGrowExpr(TableGrowExpr* expr) {
ResolveTableVar(&expr->var);
return Result::Ok;
}
Result NameResolver::OnTableSizeExpr(TableSizeExpr* expr) {
ResolveTableVar(&expr->var);
return Result::Ok;
}
Result NameResolver::OnTableFillExpr(TableFillExpr* expr) {
ResolveTableVar(&expr->var);
return Result::Ok;
}
Result NameResolver::OnRefFuncExpr(RefFuncExpr* expr) {
ResolveFuncVar(&expr->var);
return Result::Ok;
}
Result NameResolver::BeginTryExpr(TryExpr* expr) {
PushLabel(expr->block.label);
ResolveBlockDeclarationVar(&expr->block.decl);
return Result::Ok;
}
Result NameResolver::EndTryExpr(TryExpr*) {
PopLabel();
return Result::Ok;
}
Result NameResolver::OnCatchExpr(TryExpr*, Catch* catch_) {
if (!catch_->IsCatchAll()) {
ResolveEventVar(&catch_->var);
}
return Result::Ok;
}
Result NameResolver::OnDelegateExpr(TryExpr* expr) {
ResolveLabelVar(&expr->delegate_target);
return Result::Ok;
}
Result NameResolver::OnThrowExpr(ThrowExpr* expr) {
ResolveEventVar(&expr->var);
return Result::Ok;
}
Result NameResolver::OnRethrowExpr(RethrowExpr* expr) {
// Note: the variable refers to corresponding (enclosing) catch, using the try
// block label for context.
ResolveLabelVar(&expr->var);
return Result::Ok;
}
void NameResolver::VisitFunc(Func* func) {
current_func_ = func;
if (func->decl.has_func_type) {
ResolveFuncTypeVar(&func->decl.type_var);
}
func->bindings.FindDuplicates(
[=](const BindingHash::value_type& a, const BindingHash::value_type& b) {
const char* desc =
(a.second.index < func->GetNumParams()) ? "parameter" : "local";
PrintDuplicateBindingsError(a, b, desc);
});
visitor_.VisitFunc(func);
current_func_ = nullptr;
}
void NameResolver::VisitExport(Export* export_) {
switch (export_->kind) {
case ExternalKind::Func:
ResolveFuncVar(&export_->var);
break;
case ExternalKind::Table:
ResolveTableVar(&export_->var);
break;
case ExternalKind::Memory:
ResolveMemoryVar(&export_->var);
break;
case ExternalKind::Global:
ResolveGlobalVar(&export_->var);
break;
case ExternalKind::Event:
ResolveEventVar(&export_->var);
break;
}
}
void NameResolver::VisitGlobal(Global* global) {
visitor_.VisitExprList(global->init_expr);
}
void NameResolver::VisitEvent(Event* event) {
if (event->decl.has_func_type) {
ResolveFuncTypeVar(&event->decl.type_var);
}
}
void NameResolver::VisitElemSegment(ElemSegment* segment) {
ResolveTableVar(&segment->table_var);
visitor_.VisitExprList(segment->offset);
for (ElemExpr& elem_expr : segment->elem_exprs) {
if (elem_expr.kind == ElemExprKind::RefFunc) {
ResolveFuncVar(&elem_expr.var);
}
}
}
void NameResolver::VisitDataSegment(DataSegment* segment) {
ResolveMemoryVar(&segment->memory_var);
visitor_.VisitExprList(segment->offset);
}
Result NameResolver::VisitModule(Module* module) {
current_module_ = module;
CheckDuplicateBindings(&module->elem_segment_bindings, "elem");
CheckDuplicateBindings(&module->func_bindings, "function");
CheckDuplicateBindings(&module->global_bindings, "global");
CheckDuplicateBindings(&module->type_bindings, "type");
CheckDuplicateBindings(&module->table_bindings, "table");
CheckDuplicateBindings(&module->memory_bindings, "memory");
CheckDuplicateBindings(&module->event_bindings, "event");
for (Func* func : module->funcs)
VisitFunc(func);
for (Export* export_ : module->exports)
VisitExport(export_);
for (Global* global : module->globals)
VisitGlobal(global);
for (Event* event : module->events)
VisitEvent(event);
for (ElemSegment* elem_segment : module->elem_segments)
VisitElemSegment(elem_segment);
for (DataSegment* data_segment : module->data_segments)
VisitDataSegment(data_segment);
for (Var* start : module->starts)
ResolveFuncVar(start);
current_module_ = nullptr;
return result_;
}
void NameResolver::VisitScriptModule(ScriptModule* script_module) {
if (auto* tsm = dyn_cast<TextScriptModule>(script_module)) {
VisitModule(&tsm->module);
}
}
void NameResolver::VisitCommand(Command* command) {
switch (command->type) {
case CommandType::Module:
VisitModule(&cast<ModuleCommand>(command)->module);
break;
case CommandType::Action:
case CommandType::AssertReturn:
case CommandType::AssertTrap:
case CommandType::AssertExhaustion:
case CommandType::Register:
/* Don't resolve a module_var, since it doesn't really behave like other
* vars. You can't reference a module by index. */
break;
case CommandType::AssertMalformed:
/* Malformed modules should not be text; the whole point of this
* assertion is to test for malformed binary modules. */
break;
case CommandType::AssertInvalid: {
auto* assert_invalid_command = cast<AssertInvalidCommand>(command);
/* The module may be invalid because the names cannot be resolved; we
* don't want to print errors or fail if that's the case, but we still
* should try to resolve names when possible. */
Errors errors;
NameResolver new_resolver(script_, &errors);
new_resolver.VisitScriptModule(assert_invalid_command->module.get());
break;
}
case CommandType::AssertUnlinkable:
VisitScriptModule(cast<AssertUnlinkableCommand>(command)->module.get());
break;
case CommandType::AssertUninstantiable:
VisitScriptModule(
cast<AssertUninstantiableCommand>(command)->module.get());
break;
}
}
Result NameResolver::VisitScript(Script* script) {
for (const std::unique_ptr<Command>& command : script->commands)
VisitCommand(command.get());
return result_;
}
Result ResolveNamesModule(Module* module, Errors* errors) {
NameResolver resolver(nullptr, errors);
return resolver.VisitModule(module);
}
Result ResolveNamesScript(Script* script, Errors* errors) {
NameResolver resolver(script, errors);
return resolver.VisitScript(script);
}
} // namespace wabt

33
third_party/wasm2c/src/resolve-names.h vendored Normal file
View File

@@ -0,0 +1,33 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_RESOLVE_NAMES_H_
#define WABT_RESOLVE_NAMES_H_
#include "src/common.h"
#include "src/error.h"
namespace wabt {
struct Module;
struct Script;
Result ResolveNamesModule(Module*, Errors*);
Result ResolveNamesScript(Script*, Errors*);
} // namespace wabt
#endif /* WABT_RESOLVE_NAMES_H_ */

63
third_party/wasm2c/src/result.h vendored Normal file
View File

@@ -0,0 +1,63 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_RESULT_H_
#define WABT_RESULT_H_
namespace wabt {
struct Result {
enum Enum {
Ok,
Error,
};
Result() : Result(Ok) {}
Result(Enum e) : enum_(e) {}
operator Enum() const { return enum_; }
Result& operator|=(Result rhs);
private:
Enum enum_;
};
inline Result operator|(Result lhs, Result rhs) {
return (lhs == Result::Error || rhs == Result::Error) ? Result::Error
: Result::Ok;
}
inline Result& Result::operator|=(Result rhs) {
enum_ = *this | rhs;
return *this;
}
inline bool Succeeded(Result result) {
return result == Result::Ok;
}
inline bool Failed(Result result) {
return result == Result::Error;
}
#define CHECK_RESULT(expr) \
do { \
if (Failed(expr)) { \
return ::wabt::Result::Error; \
} \
} while (0)
} // namespace wabt
#endif // WABT_RESULT_H_

1250
third_party/wasm2c/src/shared-validator.cc vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,314 @@
/*
* Copyright 2020 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_SHARED_VALIDATOR_H_
#define WABT_SHARED_VALIDATOR_H_
#include <map>
#include <set>
#include <string>
#include <vector>
#include "src/common.h"
#include "src/error.h"
#include "src/feature.h"
#include "src/ir.h"
#include "src/opcode.h"
#include "src/type-checker.h"
#include "src/binary-reader.h" // For TypeMut.
namespace wabt {
struct ValidateOptions {
ValidateOptions() = default;
ValidateOptions(const Features& features) : features(features) {}
Features features;
};
class SharedValidator {
public:
WABT_DISALLOW_COPY_AND_ASSIGN(SharedValidator);
SharedValidator(Errors*, const ValidateOptions& options);
// TODO: Move into SharedValidator?
using Label = TypeChecker::Label;
size_t type_stack_size() const { return typechecker_.type_stack_size(); }
Result GetLabel(Index depth, Label** out_label) {
return typechecker_.GetLabel(depth, out_label);
}
Result WABT_PRINTF_FORMAT(3, 4)
PrintError(const Location& loc, const char* fmt, ...);
void OnTypecheckerError(const char* msg);
Index GetLocalCount() const;
Result EndModule();
Result OnFuncType(const Location&,
Index param_count,
const Type* param_types,
Index result_count,
const Type* result_types);
Result OnStructType(const Location&, Index field_count, TypeMut* fields);
Result OnArrayType(const Location&, TypeMut field);
Result OnFunction(const Location&, Var sig_var);
Result OnTable(const Location&, Type elem_type, const Limits&);
Result OnMemory(const Location&, const Limits&);
Result OnGlobalImport(const Location&, Type type, bool mutable_);
Result OnGlobal(const Location&, Type type, bool mutable_);
Result OnGlobalInitExpr_Const(const Location&, Type);
Result OnGlobalInitExpr_GlobalGet(const Location&, Var global_var);
Result OnGlobalInitExpr_RefNull(const Location&, Type type);
Result OnGlobalInitExpr_RefFunc(const Location&, Var func_var);
Result OnGlobalInitExpr_Other(const Location&);
Result OnEvent(const Location&, Var sig_var);
Result OnExport(const Location&,
ExternalKind,
Var item_var,
string_view name);
Result OnStart(const Location&, Var func_var);
Result OnElemSegment(const Location&, Var table_var, SegmentKind);
void OnElemSegmentElemType(Type elem_type);
Result OnElemSegmentInitExpr_Const(const Location&, Type);
Result OnElemSegmentInitExpr_GlobalGet(const Location&, Var global_var);
Result OnElemSegmentInitExpr_Other(const Location&);
Result OnElemSegmentElemExpr_RefNull(const Location&, Type type);
Result OnElemSegmentElemExpr_RefFunc(const Location&, Var func_var);
Result OnElemSegmentElemExpr_Other(const Location&);
void OnDataCount(Index count);
Result OnDataSegment(const Location&, Var memory_var, SegmentKind);
Result OnDataSegmentInitExpr_Const(const Location&, Type);
Result OnDataSegmentInitExpr_GlobalGet(const Location&, Var global_var);
Result OnDataSegmentInitExpr_Other(const Location&);
Result BeginFunctionBody(const Location&, Index func_index);
Result EndFunctionBody(const Location&);
Result OnLocalDecl(const Location&, Index count, Type type);
Result OnAtomicFence(const Location&, uint32_t consistency_model);
Result OnAtomicLoad(const Location&, Opcode, Address align);
Result OnAtomicNotify(const Location&, Opcode, Address align);
Result OnAtomicRmwCmpxchg(const Location&, Opcode, Address align);
Result OnAtomicRmw(const Location&, Opcode, Address align);
Result OnAtomicStore(const Location&, Opcode, Address align);
Result OnAtomicWait(const Location&, Opcode, Address align);
Result OnBinary(const Location&, Opcode);
Result OnBlock(const Location&, Type sig_type);
Result OnBr(const Location&, Var depth);
Result OnBrIf(const Location&, Var depth);
Result BeginBrTable(const Location&);
Result OnBrTableTarget(const Location&, Var depth);
Result EndBrTable(const Location&);
Result OnCall(const Location&, Var func_var);
Result OnCallIndirect(const Location&, Var sig_var, Var table_var);
Result OnCatch(const Location&, Var event_var, bool is_catch_all);
Result OnCompare(const Location&, Opcode);
Result OnConst(const Location&, Type);
Result OnConvert(const Location&, Opcode);
Result OnDataDrop(const Location&, Var segment_var);
Result OnDelegate(const Location&, Var depth);
Result OnDrop(const Location&);
Result OnElemDrop(const Location&, Var segment_var);
Result OnElse(const Location&);
Result OnEnd(const Location&);
Result OnGlobalGet(const Location&, Var);
Result OnGlobalSet(const Location&, Var);
Result OnIf(const Location&, Type sig_type);
Result OnLoad(const Location&, Opcode, Address align);
Result OnLoadSplat(const Location&, Opcode, Address align);
Result OnLoadZero(const Location&, Opcode, Address align);
Result OnLocalGet(const Location&, Var);
Result OnLocalSet(const Location&, Var);
Result OnLocalTee(const Location&, Var);
Result OnLoop(const Location&, Type sig_type);
Result OnMemoryCopy(const Location&);
Result OnMemoryFill(const Location&);
Result OnMemoryGrow(const Location&);
Result OnMemoryInit(const Location&, Var segment_var);
Result OnMemorySize(const Location&);
Result OnNop(const Location&);
Result OnRefFunc(const Location&, Var func_var);
Result OnRefIsNull(const Location&);
Result OnRefNull(const Location&, Type type);
Result OnRethrow(const Location&, Var depth);
Result OnReturnCall(const Location&, Var func_var);
Result OnReturnCallIndirect(const Location&, Var sig_var, Var table_var);
Result OnReturn(const Location&);
Result OnSelect(const Location&, Index result_count, Type* result_types);
Result OnSimdLaneOp(const Location&, Opcode, uint64_t lane_idx);
Result OnSimdLoadLane(const Location&, Opcode, Address align, uint64_t lane_idx);
Result OnSimdStoreLane(const Location&, Opcode, Address align, uint64_t lane_idx);
Result OnSimdShuffleOp(const Location&, Opcode, v128 lane_idx);
Result OnStore(const Location&, Opcode, Address align);
Result OnTableCopy(const Location&, Var dst_var, Var src_var);
Result OnTableFill(const Location&, Var table_var);
Result OnTableGet(const Location&, Var table_var);
Result OnTableGrow(const Location&, Var table_var);
Result OnTableInit(const Location&, Var segment_var, Var table_var);
Result OnTableSet(const Location&, Var table_var);
Result OnTableSize(const Location&, Var table_var);
Result OnTernary(const Location&, Opcode);
Result OnThrow(const Location&, Var event_var);
Result OnTry(const Location&, Type sig_type);
Result OnUnary(const Location&, Opcode);
Result OnUnreachable(const Location&);
Result OnUnwind(const Location&);
private:
struct FuncType {
FuncType() = default;
FuncType(const TypeVector& params, const TypeVector& results)
: params(params), results(results) {}
TypeVector params;
TypeVector results;
};
struct StructType {
StructType() = default;
StructType(const TypeMutVector& fields) : fields(fields) {}
TypeMutVector fields;
};
struct ArrayType {
ArrayType() = default;
ArrayType(TypeMut field) : field(field) {}
TypeMut field;
};
struct TableType {
TableType() = default;
TableType(Type element, Limits limits) : element(element), limits(limits) {}
Type element = Type::Any;
Limits limits;
};
struct MemoryType {
MemoryType() = default;
MemoryType(Limits limits) : limits(limits) {}
Limits limits;
};
struct GlobalType {
GlobalType() = default;
GlobalType(Type type, bool mutable_) : type(type), mutable_(mutable_) {}
Type type = Type::Any;
bool mutable_ = true;
};
struct EventType {
TypeVector params;
};
struct ElemType {
ElemType() = default;
ElemType(Type element) : element(element) {}
Type element;
};
struct LocalDecl {
Type type;
Index end;
};
Result CheckType(const Location&,
Type actual,
Type expected,
const char* desc);
Result CheckLimits(const Location&,
const Limits&,
uint64_t absolute_max,
const char* desc);
Result CheckLocalIndex(Var local_var, Type* out_type);
Result CheckDeclaredFunc(Var func_var);
Result CheckIndex(Var var, Index max_index, const char* desc);
template <typename T>
Result CheckIndexWithValue(Var var,
const std::vector<T>& values,
T* out,
const char* desc);
Result CheckFuncTypeIndex(Var sig_var, FuncType* out = nullptr);
Result CheckFuncIndex(Var func_var, FuncType* out = nullptr);
Result CheckTableIndex(Var table_var, TableType* out = nullptr);
Result CheckMemoryIndex(Var memory_var, MemoryType* out = nullptr);
Result CheckGlobalIndex(Var global_var, GlobalType* out = nullptr);
Result CheckEventIndex(Var event_var, EventType* out = nullptr);
Result CheckElemSegmentIndex(Var elem_segment_var, ElemType* out = nullptr);
Result CheckDataSegmentIndex(Var data_segment_var);
Result CheckAlign(const Location&, Address align, Address natural_align);
Result CheckAtomicAlign(const Location&, Address align, Address natural_align);
Result CheckBlockSignature(const Location&,
Opcode,
Type sig_type,
TypeVector* out_param_types,
TypeVector* out_result_types);
TypeVector ToTypeVector(Index count, const Type* types);
ValidateOptions options_;
Errors* errors_;
TypeChecker typechecker_; // TODO: Move into SharedValidator.
// Cached for access by OnTypecheckerError.
const Location* expr_loc_ = nullptr;
Index num_types_ = 0;
std::map<Index, FuncType> func_types_;
std::map<Index, StructType> struct_types_;
std::map<Index, ArrayType> array_types_;
std::vector<FuncType> funcs_; // Includes imported and defined.
std::vector<TableType> tables_; // Includes imported and defined.
std::vector<MemoryType> memories_; // Includes imported and defined.
std::vector<GlobalType> globals_; // Includes imported and defined.
std::vector<EventType> events_; // Includes imported and defined.
std::vector<ElemType> elems_;
Index starts_ = 0;
Index num_imported_globals_ = 0;
Index data_segments_ = 0;
// Includes parameters, since this is only used for validating
// local.{get,set,tee} instructions.
std::vector<LocalDecl> locals_;
std::set<std::string> export_names_; // Used to check for duplicates.
std::set<Index> declared_funcs_; // TODO: optimize?
std::vector<Var> init_expr_funcs_;
};
} // namespace wabt
#endif // WABT_SHARED_VALIDATOR_H_

316
third_party/wasm2c/src/stream.cc vendored Normal file
View File

@@ -0,0 +1,316 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/stream.h"
#include <cassert>
#include <cctype>
#include <cerrno>
#define DUMP_OCTETS_PER_LINE 16
#define DUMP_OCTETS_PER_GROUP 2
#define ERROR0(msg) fprintf(stderr, "%s:%d: " msg, __FILE__, __LINE__)
#define ERROR(fmt, ...) \
fprintf(stderr, "%s:%d: " fmt, __FILE__, __LINE__, __VA_ARGS__)
namespace wabt {
Stream::Stream(Stream* log_stream)
: offset_(0), result_(Result::Ok), log_stream_(log_stream) {}
void Stream::AddOffset(ssize_t delta) {
offset_ += delta;
}
void Stream::WriteDataAt(size_t at,
const void* src,
size_t size,
const char* desc,
PrintChars print_chars) {
if (Failed(result_)) {
return;
}
if (log_stream_) {
log_stream_->WriteMemoryDump(src, size, at, print_chars, nullptr, desc);
}
result_ = WriteDataImpl(at, src, size);
}
void Stream::WriteData(const void* src,
size_t size,
const char* desc,
PrintChars print_chars) {
WriteDataAt(offset_, src, size, desc, print_chars);
offset_ += size;
}
void Stream::MoveData(size_t dst_offset, size_t src_offset, size_t size) {
if (Failed(result_)) {
return;
}
if (log_stream_) {
log_stream_->Writef(
"; move data: [%" PRIzx ", %" PRIzx ") -> [%" PRIzx ", %" PRIzx ")\n",
src_offset, src_offset + size, dst_offset, dst_offset + size);
}
result_ = MoveDataImpl(dst_offset, src_offset, size);
}
void Stream::Truncate(size_t size) {
if (Failed(result_)) {
return;
}
if (log_stream_) {
log_stream_->Writef("; truncate to %" PRIzd " (0x%" PRIzx ")\n", size,
size);
}
result_ = TruncateImpl(size);
if (Succeeded(result_) && offset_ > size) {
offset_ = size;
}
}
void Stream::Writef(const char* format, ...) {
WABT_SNPRINTF_ALLOCA(buffer, length, format);
WriteData(buffer, length);
}
void Stream::WriteMemoryDump(const void* start,
size_t size,
size_t offset,
PrintChars print_chars,
const char* prefix,
const char* desc) {
const uint8_t* p = static_cast<const uint8_t*>(start);
const uint8_t* end = p + size;
while (p < end) {
const uint8_t* line = p;
const uint8_t* line_end = p + DUMP_OCTETS_PER_LINE;
if (prefix) {
Writef("%s", prefix);
}
Writef("%07" PRIzx ": ", reinterpret_cast<intptr_t>(p) -
reinterpret_cast<intptr_t>(start) + offset);
while (p < line_end) {
for (int i = 0; i < DUMP_OCTETS_PER_GROUP; ++i, ++p) {
if (p < end) {
Writef("%02x", *p);
} else {
WriteChar(' ');
WriteChar(' ');
}
}
WriteChar(' ');
}
if (print_chars == PrintChars::Yes) {
WriteChar(' ');
p = line;
for (int i = 0; i < DUMP_OCTETS_PER_LINE && p < end; ++i, ++p)
WriteChar(isprint(*p) ? *p : '.');
}
/* if there are multiple lines, only print the desc on the last one */
if (p >= end && desc) {
Writef(" ; %s", desc);
}
WriteChar('\n');
}
}
Result OutputBuffer::WriteToFile(string_view filename) const {
std::string filename_str = filename.to_string();
FILE* file = fopen(filename_str.c_str(), "wb");
if (!file) {
ERROR("unable to open %s for writing\n", filename_str.c_str());
return Result::Error;
}
if (data.empty()) {
fclose(file);
return Result::Ok;
}
ssize_t bytes = fwrite(data.data(), 1, data.size(), file);
if (bytes < 0 || static_cast<size_t>(bytes) != data.size()) {
ERROR("failed to write %" PRIzd " bytes to %s\n", data.size(),
filename_str.c_str());
fclose(file);
return Result::Error;
}
fclose(file);
return Result::Ok;
}
MemoryStream::MemoryStream(Stream* log_stream)
: Stream(log_stream), buf_(new OutputBuffer()) {}
MemoryStream::MemoryStream(std::unique_ptr<OutputBuffer>&& buf,
Stream* log_stream)
: Stream(log_stream), buf_(std::move(buf)) {}
std::unique_ptr<OutputBuffer> MemoryStream::ReleaseOutputBuffer() {
return std::move(buf_);
}
void MemoryStream::Clear() {
if (buf_)
buf_->clear();
else
buf_.reset(new OutputBuffer());
}
Result MemoryStream::WriteDataImpl(size_t dst_offset,
const void* src,
size_t size) {
if (size == 0) {
return Result::Ok;
}
size_t end = dst_offset + size;
if (end > buf_->data.size()) {
buf_->data.resize(end);
}
uint8_t* dst = &buf_->data[dst_offset];
memcpy(dst, src, size);
return Result::Ok;
}
Result MemoryStream::MoveDataImpl(size_t dst_offset,
size_t src_offset,
size_t size) {
if (size == 0) {
return Result::Ok;
}
size_t src_end = src_offset + size;
size_t dst_end = dst_offset + size;
size_t end = src_end > dst_end ? src_end : dst_end;
if (end > buf_->data.size()) {
buf_->data.resize(end);
}
uint8_t* dst = &buf_->data[dst_offset];
uint8_t* src = &buf_->data[src_offset];
memmove(dst, src, size);
return Result::Ok;
}
Result MemoryStream::TruncateImpl(size_t size) {
if (size > buf_->data.size()) {
return Result::Error;
}
buf_->data.resize(size);
return Result::Ok;
}
FileStream::FileStream(string_view filename, Stream* log_stream)
: Stream(log_stream), file_(nullptr), offset_(0), should_close_(false) {
std::string filename_str = filename.to_string();
file_ = fopen(filename_str.c_str(), "wb");
// TODO(binji): this is pretty cheesy, should come up with a better API.
if (file_) {
should_close_ = true;
} else {
ERROR("fopen name=\"%s\" failed, errno=%d\n", filename_str.c_str(), errno);
}
}
FileStream::FileStream(FILE* file, Stream* log_stream)
: Stream(log_stream), file_(file), offset_(0), should_close_(false) {}
FileStream::FileStream(FileStream&& other) {
*this = std::move(other);
}
FileStream& FileStream::operator=(FileStream&& other) {
file_ = other.file_;
offset_ = other.offset_;
should_close_ = other.should_close_;
other.file_ = nullptr;
other.offset_ = 0;
other.should_close_ = false;
return *this;
}
FileStream::~FileStream() {
// We don't want to close existing files (stdout/sterr, for example).
if (should_close_) {
fclose(file_);
}
}
void FileStream::Flush() {
if (file_) fflush(file_);
}
Result FileStream::WriteDataImpl(size_t at, const void* data, size_t size) {
if (!file_) {
return Result::Error;
}
if (size == 0) {
return Result::Ok;
}
if (at != offset_) {
if (fseek(file_, at, SEEK_SET) != 0) {
ERROR("fseek offset=%" PRIzd " failed, errno=%d\n", size, errno);
return Result::Error;
}
offset_ = at;
}
if (fwrite(data, size, 1, file_) != 1) {
ERROR("fwrite size=%" PRIzd " failed, errno=%d\n", size, errno);
return Result::Error;
}
offset_ += size;
return Result::Ok;
}
Result FileStream::MoveDataImpl(size_t dst_offset,
size_t src_offset,
size_t size) {
if (!file_) {
return Result::Error;
}
if (size == 0) {
return Result::Ok;
}
// TODO(binji): implement if needed.
ERROR0("FileStream::MoveDataImpl not implemented!\n");
return Result::Error;
}
Result FileStream::TruncateImpl(size_t size) {
if (!file_) {
return Result::Error;
}
// TODO(binji): implement if needed.
ERROR0("FileStream::TruncateImpl not implemented!\n");
return Result::Error;
}
// static
std::unique_ptr<FileStream> FileStream::CreateStdout() {
return std::unique_ptr<FileStream>(new FileStream(stdout));
}
// static
std::unique_ptr<FileStream> FileStream::CreateStderr() {
return std::unique_ptr<FileStream>(new FileStream(stderr));
}
} // namespace wabt

227
third_party/wasm2c/src/stream.h vendored Normal file
View File

@@ -0,0 +1,227 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_STREAM_H_
#define WABT_STREAM_H_
#include <cassert>
#include <memory>
#include <vector>
#include "src/common.h"
namespace wabt {
/* whether to display the ASCII characters in the debug output for
* write_memory */
enum class PrintChars {
No = 0,
Yes = 1,
};
class Stream {
public:
explicit Stream(Stream* log_stream = nullptr);
virtual ~Stream() = default;
size_t offset() { return offset_; }
Result result() { return result_; }
void set_log_stream(Stream* stream) {
assert(stream);
log_stream_ = stream;
}
Stream& log_stream() {
assert(log_stream_);
return *log_stream_;
}
bool has_log_stream() const { return log_stream_ != nullptr; }
void ClearOffset() { offset_ = 0; }
void AddOffset(ssize_t delta);
void WriteData(const void* src,
size_t size,
const char* desc = nullptr,
PrintChars = PrintChars::No);
template <typename T>
void WriteData(const std::vector<T> src,
const char* desc,
PrintChars print_chars = PrintChars::No) {
if (!src.empty()) {
WriteData(src.data(), src.size() * sizeof(T), desc, print_chars);
}
}
void WriteDataAt(size_t offset,
const void* src,
size_t size,
const char* desc = nullptr,
PrintChars = PrintChars::No);
void MoveData(size_t dst_offset, size_t src_offset, size_t size);
void Truncate(size_t size);
void WABT_PRINTF_FORMAT(2, 3) Writef(const char* format, ...);
// Specified as uint32_t instead of uint8_t so we can check if the value
// given is in range before wrapping.
void WriteU8(uint32_t value,
const char* desc = nullptr,
PrintChars print_chars = PrintChars::No) {
assert(value <= UINT8_MAX);
Write(static_cast<uint8_t>(value), desc, print_chars);
}
void WriteU32(uint32_t value,
const char* desc = nullptr,
PrintChars print_chars = PrintChars::No) {
Write(value, desc, print_chars);
}
void WriteU64(uint64_t value,
const char* desc = nullptr,
PrintChars print_chars = PrintChars::No) {
Write(value, desc, print_chars);
}
void WriteU128(v128 value,
const char* desc = nullptr,
PrintChars print_chars = PrintChars::No) {
Write(value, desc, print_chars);
}
void WriteChar(char c,
const char* desc = nullptr,
PrintChars print_chars = PrintChars::No) {
WriteU8(static_cast<unsigned char>(c), desc, print_chars);
}
// Dump memory as text, similar to the xxd format.
void WriteMemoryDump(const void* start,
size_t size,
size_t offset = 0,
PrintChars print_chars = PrintChars::No,
const char* prefix = nullptr,
const char* desc = nullptr);
// Convenience functions for writing enums.
template <typename T>
void WriteU8Enum(T value,
const char* desc = nullptr,
PrintChars print_chars = PrintChars::No) {
WriteU8(static_cast<uint32_t>(value), desc, print_chars);
}
virtual void Flush() {}
protected:
virtual Result WriteDataImpl(size_t offset,
const void* data,
size_t size) = 0;
virtual Result MoveDataImpl(size_t dst_offset,
size_t src_offset,
size_t size) = 0;
virtual Result TruncateImpl(size_t size) = 0;
private:
template <typename T>
void Write(const T& data, const char* desc, PrintChars print_chars) {
#if WABT_BIG_ENDIAN
char tmp[sizeof(T)];
memcpy(tmp, &data, sizeof(tmp));
SwapBytesSized(tmp, sizeof(tmp));
WriteData(tmp, sizeof(tmp), desc, print_chars);
#else
WriteData(&data, sizeof(data), desc, print_chars);
#endif
}
size_t offset_;
Result result_;
// Not owned. If non-null, log all writes to this stream.
Stream* log_stream_;
};
struct OutputBuffer {
Result WriteToFile(string_view filename) const;
void clear() { data.clear(); }
size_t size() const { return data.size(); }
std::vector<uint8_t> data;
};
class MemoryStream : public Stream {
public:
WABT_DISALLOW_COPY_AND_ASSIGN(MemoryStream);
explicit MemoryStream(Stream* log_stream = nullptr);
explicit MemoryStream(std::unique_ptr<OutputBuffer>&&,
Stream* log_stream = nullptr);
OutputBuffer& output_buffer() { return *buf_; }
std::unique_ptr<OutputBuffer> ReleaseOutputBuffer();
void Clear();
Result WriteToFile(string_view filename) {
return buf_->WriteToFile(filename);
}
protected:
Result WriteDataImpl(size_t offset, const void* data, size_t size) override;
Result MoveDataImpl(size_t dst_offset,
size_t src_offset,
size_t size) override;
Result TruncateImpl(size_t size) override;
private:
std::unique_ptr<OutputBuffer> buf_;
};
class FileStream : public Stream {
public:
WABT_DISALLOW_COPY_AND_ASSIGN(FileStream);
explicit FileStream(string_view filename, Stream* log_stream = nullptr);
explicit FileStream(FILE*, Stream* log_stream = nullptr);
FileStream(FileStream&&);
FileStream& operator=(FileStream&&);
~FileStream() override;
static std::unique_ptr<FileStream> CreateStdout();
static std::unique_ptr<FileStream> CreateStderr();
bool is_open() const { return file_ != nullptr; }
void Flush() override;
protected:
Result WriteDataImpl(size_t offset, const void* data, size_t size) override;
Result MoveDataImpl(size_t dst_offset,
size_t src_offset,
size_t size) override;
Result TruncateImpl(size_t size) override;
private:
FILE* file_;
size_t offset_;
bool should_close_;
};
} // namespace wabt
#endif /* WABT_STREAM_H_ */

196
third_party/wasm2c/src/string-view.cc vendored Normal file
View File

@@ -0,0 +1,196 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/string-view.h"
#include <algorithm>
#include <limits>
namespace wabt {
void string_view::remove_prefix(size_type n) {
assert(n <= size_);
data_ += n;
size_ -= n;
}
void string_view::remove_suffix(size_type n) {
assert(n <= size_);
size_ -= n;
}
void string_view::swap(string_view& s) noexcept {
std::swap(data_, s.data_);
std::swap(size_, s.size_);
}
string_view::operator std::string() const {
return std::string(data_, size_);
}
std::string string_view::to_string() const {
return std::string(data_, size_);
}
constexpr string_view::size_type string_view::max_size() const noexcept {
return std::numeric_limits<size_type>::max();
}
string_view::size_type string_view::copy(char* s,
size_type n,
size_type pos) const {
assert(pos <= size_);
size_t count = std::min(n, size_ - pos);
traits_type::copy(s, data_ + pos, count);
return count;
}
string_view string_view::substr(size_type pos, size_type n) const {
assert(pos <= size_);
size_t count = std::min(n, size_ - pos);
return string_view(data_ + pos, count);
}
int string_view::compare(string_view s) const noexcept {
size_type rlen = std::min(size_, s.size_);
int result = traits_type::compare(data_, s.data_, rlen);
if (result != 0 || size_ == s.size_) {
return result;
}
return size_ < s.size_ ? -1 : 1;
}
int string_view::compare(size_type pos1, size_type n1, string_view s) const {
return substr(pos1, n1).compare(s);
}
int string_view::compare(size_type pos1,
size_type n1,
string_view s,
size_type pos2,
size_type n2) const {
return substr(pos1, n1).compare(s.substr(pos2, n2));
}
int string_view::compare(const char* s) const {
return compare(string_view(s));
}
int string_view::compare(size_type pos1, size_type n1, const char* s) const {
return substr(pos1, n1).compare(string_view(s));
}
int string_view::compare(size_type pos1,
size_type n1,
const char* s,
size_type n2) const {
return substr(pos1, n1).compare(string_view(s, n2));
}
string_view::size_type string_view::find(string_view s, size_type pos) const
noexcept {
pos = std::min(pos, size_);
const_iterator iter = std::search(begin() + pos, end(), s.begin(), s.end());
return iter == end() ? npos : iter - begin();
}
string_view::size_type string_view::find(char c, size_type pos) const noexcept {
return find(string_view(&c, 1), pos);
}
string_view::size_type string_view::find(const char* s,
size_type pos,
size_type n) const {
return find(string_view(s, n), pos);
}
string_view::size_type string_view::find(const char* s, size_type pos) const {
return find(string_view(s), pos);
}
string_view::size_type string_view::rfind(string_view s, size_type pos) const
noexcept {
pos = std::min(std::min(pos, size_ - s.size_) + s.size_, size_);
reverse_iterator iter = std::search(reverse_iterator(begin() + pos), rend(),
s.rbegin(), s.rend());
return iter == rend() ? npos : (rend() - iter - s.size_);
}
string_view::size_type string_view::rfind(char c, size_type pos) const
noexcept {
return rfind(string_view(&c, 1), pos);
}
string_view::size_type string_view::rfind(const char* s,
size_type pos,
size_type n) const {
return rfind(string_view(s, n), pos);
}
string_view::size_type string_view::rfind(const char* s, size_type pos) const {
return rfind(string_view(s), pos);
}
string_view::size_type string_view::find_first_of(string_view s,
size_type pos) const
noexcept {
pos = std::min(pos, size_);
const_iterator iter =
std::find_first_of(begin() + pos, end(), s.begin(), s.end());
return iter == end() ? npos : iter - begin();
}
string_view::size_type string_view::find_first_of(char c, size_type pos) const
noexcept {
return find_first_of(string_view(&c, 1), pos);
}
string_view::size_type string_view::find_first_of(const char* s,
size_type pos,
size_type n) const {
return find_first_of(string_view(s, n), pos);
}
string_view::size_type string_view::find_first_of(const char* s,
size_type pos) const {
return find_first_of(string_view(s), pos);
}
string_view::size_type string_view::find_last_of(string_view s,
size_type pos) const noexcept {
pos = std::min(pos, size_ - 1);
reverse_iterator iter = std::find_first_of(
reverse_iterator(begin() + (pos + 1)), rend(), s.begin(), s.end());
return iter == rend() ? npos : (rend() - iter - 1);
}
string_view::size_type string_view::find_last_of(char c, size_type pos) const
noexcept {
return find_last_of(string_view(&c, 1), pos);
}
string_view::size_type string_view::find_last_of(const char* s,
size_type pos,
size_type n) const {
return find_last_of(string_view(s, n), pos);
}
string_view::size_type string_view::find_last_of(const char* s,
size_type pos) const {
return find_last_of(string_view(s), pos);
}
} // namespace wabt

347
third_party/wasm2c/src/string-view.h vendored Normal file
View File

@@ -0,0 +1,347 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WABT_STRING_VIEW_H_
#define WABT_STRING_VIEW_H_
#include <cassert>
#include <functional>
#include <iterator>
#include <ostream>
#include <string>
#include "src/hash-util.h"
namespace wabt {
// This is a simplified implemention of C++17's basic_string_view template.
//
// Missing features:
// * Not a template
// * No allocator support
// * Some functions are not implemented
// * Asserts instead of exceptions
// * Some functions are not constexpr because we don't compile in C++17 mode
class string_view {
public:
typedef std::char_traits<char> traits_type;
typedef char value_type;
typedef char* pointer;
typedef const char* const_pointer;
typedef char& reference;
typedef const char& const_reference;
typedef const char* const_iterator;
typedef const_iterator iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
typedef const_reverse_iterator reverse_iterator;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
static const size_type npos = size_type(-1);
// construction and assignment
constexpr string_view() noexcept;
constexpr string_view(const string_view&) noexcept = default;
string_view& operator=(const string_view&) noexcept = default;
string_view(const std::string& str) noexcept;
/*constexpr*/ string_view(const char* str);
constexpr string_view(const char* str, size_type len);
// iterator support
constexpr const_iterator begin() const noexcept;
constexpr const_iterator end() const noexcept;
constexpr const_iterator cbegin() const noexcept;
constexpr const_iterator cend() const noexcept;
const_reverse_iterator rbegin() const noexcept;
const_reverse_iterator rend() const noexcept;
const_reverse_iterator crbegin() const noexcept;
const_reverse_iterator crend() const noexcept;
// capacity
constexpr size_type size() const noexcept;
constexpr size_type length() const noexcept;
constexpr size_type max_size() const noexcept;
constexpr bool empty() const noexcept;
// element access
constexpr const_reference operator[](size_type pos) const;
/*constexpr*/ const_reference at(size_type pos) const;
/*constexpr*/ const_reference front() const;
/*constexpr*/ const_reference back() const;
constexpr const_pointer data() const noexcept;
// modifiers
/*constexpr*/ void remove_prefix(size_type n);
/*constexpr*/ void remove_suffix(size_type n);
/*constexpr*/ void swap(string_view& s) noexcept;
// string operations
explicit operator std::string() const;
std::string to_string() const;
size_type copy(char* s, size_type n, size_type pos = 0) const;
/*constexpr*/ string_view substr(size_type pos = 0, size_type n = npos) const;
/*constexpr*/ int compare(string_view s) const noexcept;
/*constexpr*/ int compare(size_type pos1, size_type n1, string_view s) const;
/*constexpr*/ int compare(size_type pos1,
size_type n1,
string_view s,
size_type pos2,
size_type n2) const;
/*constexpr*/ int compare(const char* s) const;
/*constexpr*/ int compare(size_type pos1, size_type n1, const char* s) const;
/*constexpr*/ int compare(size_type pos1,
size_type n1,
const char* s,
size_type n2) const;
/*constexpr*/ size_type find(string_view s, size_type pos = 0) const noexcept;
/*constexpr*/ size_type find(char c, size_type pos = 0) const noexcept;
/*constexpr*/ size_type find(const char* s, size_type pos, size_type n) const;
/*constexpr*/ size_type find(const char* s, size_type pos = 0) const;
/*constexpr*/ size_type rfind(string_view s, size_type pos = npos) const
noexcept;
/*constexpr*/ size_type rfind(char c, size_type pos = npos) const noexcept;
/*constexpr*/ size_type rfind(const char* s,
size_type pos,
size_type n) const;
/*constexpr*/ size_type rfind(const char* s, size_type pos = npos) const;
/*constexpr*/ size_type find_first_of(string_view s, size_type pos = 0) const
noexcept;
/*constexpr*/ size_type find_first_of(char c, size_type pos = 0) const
noexcept;
/*constexpr*/ size_type find_first_of(const char* s,
size_type pos,
size_type n) const;
/*constexpr*/ size_type find_first_of(const char* s, size_type pos = 0) const;
/*constexpr*/ size_type find_last_of(string_view s,
size_type pos = npos) const noexcept;
/*constexpr*/ size_type find_last_of(char c, size_type pos = npos) const
noexcept;
/*constexpr*/ size_type find_last_of(const char* s,
size_type pos,
size_type n) const;
/*constexpr*/ size_type find_last_of(const char* s,
size_type pos = npos) const;
// TODO(binji): These are defined by C++17 basic_string_view but not
// implemented here.
#if 0
constexpr size_type find_first_not_of(string_view s, size_type pos = 0) const
noexcept;
constexpr size_type find_first_not_of(char c, size_type pos = 0) const
noexcept;
constexpr size_type find_first_not_of(const char* s,
size_type pos,
size_type n) const;
constexpr size_type find_first_not_of(const char* s, size_type pos = 0) const;
constexpr size_type find_last_not_of(string_view s,
size_type pos = npos) const noexcept;
constexpr size_type find_last_not_of(char c, size_type pos = npos) const
noexcept;
constexpr size_type find_last_not_of(const char* s,
size_type pos,
size_type n) const;
constexpr size_type find_last_not_of(const char* s,
size_type pos = npos) const;
#endif
private:
const char* data_;
size_type size_;
};
// non-member comparison functions
inline bool operator==(string_view x, string_view y) noexcept {
return x.compare(y) == 0;
}
inline bool operator!=(string_view x, string_view y) noexcept {
return x.compare(y) != 0;
}
inline bool operator<(string_view x, string_view y) noexcept {
return x.compare(y) < 0;
}
inline bool operator>(string_view x, string_view y) noexcept {
return x.compare(y) > 0;
}
inline bool operator<=(string_view x, string_view y) noexcept {
return x.compare(y) <= 0;
}
inline bool operator>=(string_view x, string_view y) noexcept {
return x.compare(y) >= 0;
}
// non-member append.
inline std::string& operator+=(std::string& x, string_view y) {
x.append(y.data(), y.size());
return x;
}
inline std::string operator+(string_view x, string_view y) {
std::string s;
s.reserve(x.size() + y.size());
s.append(x.data(), x.size());
s.append(y.data(), y.size());
return s;
}
inline std::string operator+(const std::string& x, string_view y) {
return string_view(x) + y;
}
inline std::string operator+(string_view x, const std::string& y) {
return x + string_view(y);
}
inline std::string operator+(const char* x, string_view y) {
return string_view(x) + y;
}
inline std::string operator+(string_view x, const char* y) {
return x + string_view(y);
}
inline void cat_concatenate(std::string&) {}
template<typename T, typename ...Ts>
void cat_concatenate(std::string& s, const T& t, const Ts&... args) {
s += t;
cat_concatenate(s, args...);
}
inline size_t cat_compute_size() { return 0; }
template<typename T, typename ...Ts>
size_t cat_compute_size(const T& t, const Ts&... args) {
return string_view(t).size() + cat_compute_size(args...);
}
// Is able to concatenate any combination of string/string_view/char*
template<typename ...Ts> std::string cat(const Ts&... args) {
std::string s;
s.reserve(cat_compute_size(args...));
cat_concatenate(s, args...);
return s;
}
inline constexpr string_view::string_view() noexcept
: data_(nullptr), size_(0) {}
inline string_view::string_view(const std::string& str) noexcept
: data_(str.data()), size_(str.size()) {}
inline string_view::string_view(const char* str)
: data_(str), size_(traits_type::length(str)) {}
inline constexpr string_view::string_view(const char* str, size_type len)
: data_(str), size_(len) {}
inline constexpr string_view::const_iterator string_view::begin() const
noexcept {
return data_;
}
inline constexpr string_view::const_iterator string_view::end() const noexcept {
return data_ + size_;
}
inline constexpr string_view::const_iterator string_view::cbegin() const
noexcept {
return data_;
}
inline constexpr string_view::const_iterator string_view::cend() const
noexcept {
return data_ + size_;
}
inline string_view::const_reverse_iterator string_view::rbegin() const
noexcept {
return const_reverse_iterator(end());
}
inline string_view::const_reverse_iterator string_view::rend() const noexcept {
return const_reverse_iterator(begin());
}
inline string_view::const_reverse_iterator string_view::crbegin() const
noexcept {
return const_reverse_iterator(cend());
}
inline string_view::const_reverse_iterator string_view::crend() const noexcept {
return const_reverse_iterator(cbegin());
}
constexpr inline string_view::size_type string_view::size() const noexcept {
return size_;
}
constexpr inline string_view::size_type string_view::length() const noexcept {
return size_;
}
constexpr inline bool string_view::empty() const noexcept {
return size_ == 0;
}
constexpr inline string_view::const_reference string_view::operator[](
size_type pos) const {
return data_[pos];
}
inline string_view::const_reference string_view::at(size_type pos) const {
assert(pos < size_);
return data_[pos];
}
inline string_view::const_reference string_view::front() const {
assert(!empty());
return *data_;
}
inline string_view::const_reference string_view::back() const {
assert(!empty());
return data_[size_ - 1];
}
constexpr inline string_view::const_pointer string_view::data() const noexcept {
return data_;
}
inline std::ostream& operator<<(std::ostream& os, string_view sv) {
os.write(sv.data(), sv.size());
return os;
}
} // namespace wabt
namespace std {
// hash support
template <>
struct hash<::wabt::string_view> {
::wabt::hash_code operator()(const ::wabt::string_view& sv) {
return ::wabt::HashRange(sv.begin(), sv.end());
}
};
} // namespace std
#endif // WABT_STRING_VIEW_H_

View File

@@ -0,0 +1,75 @@
/*
* Copyright 2018 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "gtest/gtest.h"
#include "src/binary-reader.h"
#include "src/binary-reader-nop.h"
#include "src/leb128.h"
#include "src/opcode.h"
using namespace wabt;
namespace {
struct BinaryReaderError : BinaryReaderNop {
bool OnError(const Error& error) override {
first_error = error;
return true; // Error handled.
}
Error first_error;
};
} // End of anonymous namespace
TEST(BinaryReader, DisabledOpcodes) {
// Use the default features.
ReadBinaryOptions options;
// Loop through all opcodes.
for (uint32_t i = 0; i < static_cast<uint32_t>(Opcode::Invalid); ++i) {
Opcode opcode(static_cast<Opcode::Enum>(i));
if (opcode.IsEnabled(options.features)) {
continue;
}
// Use a shorter name to make the clang-formatted table below look nicer.
std::vector<uint8_t> b = opcode.GetBytes();
assert(b.size() <= 3);
b.resize(3);
uint8_t data[] = {
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, // magic + version
0x01, 0x04, 0x01, 0x60, 0x00, 0x00, // type section: 1 type, (func)
0x03, 0x02, 0x01, 0x00, // func section: 1 func, type 0
0x0a, 0x07, 0x01, 0x05, 0x00, // code section: 1 func, 0 locals
b[0], b[1], b[2], // The instruction, padded with zeroes
0x0b, // end
};
const size_t size = sizeof(data);
BinaryReaderError reader;
Result result = ReadBinary(data, size, &reader, options);
EXPECT_EQ(Result::Error, result);
// This relies on the binary reader checking whether the opcode is allowed
// before reading any further data needed by the instruction.
const std::string& message = reader.first_error.message;
EXPECT_EQ(0u, message.find("unexpected opcode"))
<< "Got error message: " << message;
}
}

View File

@@ -0,0 +1,284 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "gtest/gtest.h"
#include <memory>
#include "src/circular-array.h"
using namespace wabt;
namespace {
struct TestObject {
static int construct_count;
static int destruct_count;
TestObject(int data = 0, int data2 = 0) : data(data), data2(data2) {
construct_count++;
}
TestObject(const TestObject& other) {
*this = other;
construct_count++;
}
TestObject& operator=(const TestObject& other) {
data = other.data;
data2 = other.data2;
return *this;
}
TestObject(TestObject&& other) { *this = std::move(other); }
TestObject& operator=(TestObject&& other) {
data = other.data;
data2 = other.data2;
other.moved = true;
return *this;
}
~TestObject() {
if (!moved) {
destruct_count++;
}
}
int data = 0;
int data2 = 0;
bool moved = false;
};
// static
int TestObject::construct_count = 0;
// static
int TestObject::destruct_count = 0;
class CircularArrayTest : public ::testing::Test {
protected:
virtual void SetUp() {
// Reset to 0 even if the previous test leaked objects to keep the tests
// independent.
TestObject::construct_count = 0;
TestObject::destruct_count = 0;
}
virtual void TearDown() {
ASSERT_EQ(0, TestObject::construct_count - TestObject::destruct_count)
<< "construct count: " << TestObject::construct_count
<< ", destruct_count: " << TestObject::destruct_count;
}
template <size_t N>
void AssertCircularArrayEq(const CircularArray<TestObject, N>& ca,
const std::vector<int>& expected) {
if (expected.empty()) {
ASSERT_EQ(0U, ca.size());
ASSERT_TRUE(ca.empty());
} else {
ASSERT_EQ(expected.size(), ca.size());
ASSERT_FALSE(ca.empty());
ASSERT_EQ(expected.front(), ca.front().data);
ASSERT_EQ(expected.back(), ca.back().data);
for (size_t i = 0; i < ca.size(); ++i) {
ASSERT_EQ(expected[i], ca.at(i).data);
ASSERT_EQ(expected[i], ca[i].data);
}
}
}
};
} // end anonymous namespace
// Basic API tests
TEST_F(CircularArrayTest, default_constructor) {
CircularArray<TestObject, 2> ca;
}
TEST_F(CircularArrayTest, at) {
CircularArray<TestObject, 2> ca;
ca.push_back(TestObject(1));
ca.push_back(TestObject(2));
ASSERT_EQ(1, ca.at(0).data);
ASSERT_EQ(2, ca.at(1).data);
}
TEST_F(CircularArrayTest, const_at) {
CircularArray<TestObject, 2> ca;
const auto& cca = ca;
ca.push_back(TestObject(1));
ca.push_back(TestObject(2));
ASSERT_EQ(1, cca.at(0).data);
ASSERT_EQ(2, cca.at(1).data);
}
TEST_F(CircularArrayTest, operator_brackets) {
CircularArray<TestObject, 2> ca;
ca.push_back(TestObject(1));
ca.push_back(TestObject(2));
ASSERT_EQ(1, ca[0].data);
ASSERT_EQ(2, ca[1].data);
}
TEST_F(CircularArrayTest, const_operator_brackets) {
CircularArray<TestObject, 2> ca;
const auto& cca = ca;
ca.push_back(TestObject(1));
ca.push_back(TestObject(2));
ASSERT_EQ(1, cca[0].data);
ASSERT_EQ(2, cca[1].data);
}
TEST_F(CircularArrayTest, back) {
CircularArray<TestObject, 2> ca;
ca.push_back(TestObject(1));
ASSERT_EQ(1, ca.back().data);
ca.push_back(TestObject(2));
ASSERT_EQ(2, ca.back().data);
}
TEST_F(CircularArrayTest, const_back) {
CircularArray<TestObject, 2> ca;
const auto& cca = ca;
ca.push_back(TestObject(1));
ASSERT_EQ(1, cca.back().data);
ca.push_back(TestObject(2));
ASSERT_EQ(2, cca.back().data);
}
TEST_F(CircularArrayTest, empty) {
CircularArray<TestObject, 2> ca;
ASSERT_TRUE(ca.empty());
ca.push_back(TestObject(1));
ASSERT_FALSE(ca.empty());
ca.push_back(TestObject(2));
ASSERT_FALSE(ca.empty());
ca.pop_back();
ASSERT_FALSE(ca.empty());
ca.pop_back();
ASSERT_TRUE(ca.empty());
}
TEST_F(CircularArrayTest, front) {
CircularArray<TestObject, 2> ca;
ca.push_back(TestObject(1));
ASSERT_EQ(1, ca.front().data);
ca.push_back(TestObject(2));
ASSERT_EQ(1, ca.front().data);
}
TEST_F(CircularArrayTest, const_front) {
CircularArray<TestObject, 2> ca;
const auto& cca = ca;
ca.push_back(TestObject(1));
ASSERT_EQ(1, cca.front().data);
ca.push_back(TestObject(2));
ASSERT_EQ(1, cca.front().data);
}
TEST_F(CircularArrayTest, size) {
CircularArray<TestObject, 2> ca;
ASSERT_EQ(0U, ca.size());
ca.push_back(TestObject(1));
ASSERT_EQ(1U, ca.size());
ca.push_back(TestObject(2));
ASSERT_EQ(2U, ca.size());
ca.pop_back();
ASSERT_EQ(1U, ca.size());
ca.pop_back();
ASSERT_EQ(0U, ca.size());
}
TEST_F(CircularArrayTest, clear) {
CircularArray<TestObject, 2> ca;
ca.push_back(TestObject(1));
ca.push_back(TestObject(2));
ASSERT_EQ(2U, ca.size());
ca.clear();
ASSERT_EQ(0U, ca.size());
}
// More involved tests
TEST_F(CircularArrayTest, circular) {
CircularArray<TestObject, 4> ca;
ca.push_back(TestObject(1));
AssertCircularArrayEq(ca, {1});
ca.push_back(TestObject(2));
AssertCircularArrayEq(ca, {1, 2});
ca.push_back(TestObject(3));
AssertCircularArrayEq(ca, {1, 2, 3});
ca.pop_front();
AssertCircularArrayEq(ca, {2, 3});
ca.push_back(TestObject(4));
AssertCircularArrayEq(ca, {2, 3, 4});
ca.pop_front();
AssertCircularArrayEq(ca, {3, 4});
ca.pop_front();
AssertCircularArrayEq(ca, {4});
ca.push_back(TestObject(5));
AssertCircularArrayEq(ca, {4, 5});
ca.push_back(TestObject(6));
AssertCircularArrayEq(ca, {4, 5, 6});
ca.pop_back();
AssertCircularArrayEq(ca, {4, 5});
ca.pop_back();
AssertCircularArrayEq(ca, {4});
ca.pop_front();
AssertCircularArrayEq(ca, {});
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "gtest/gtest.h"
#include "src/filenames.h"
using namespace wabt;
namespace {
void assert_string_view_eq(const char* s, string_view sv) {
size_t len = std::strlen(s);
ASSERT_EQ(len, sv.size());
for (size_t i = 0; i < len; ++i) {
ASSERT_EQ(s[i], sv[i]);
}
}
} // end anonymous namespace
TEST(filenames, GetBasename) {
assert_string_view_eq("foo.txt", GetBasename("/bar/dir/foo.txt"));
assert_string_view_eq("foo.txt", GetBasename("bar/dir/foo.txt"));
assert_string_view_eq("foo.txt", GetBasename("/foo.txt"));
assert_string_view_eq("foo.txt", GetBasename("\\bar\\dir\\foo.txt"));
assert_string_view_eq("foo.txt", GetBasename("bar\\dir\\foo.txt"));
assert_string_view_eq("foo.txt", GetBasename("\\foo.txt"));
assert_string_view_eq("foo.txt", GetBasename("foo.txt"));
assert_string_view_eq("foo", GetBasename("foo"));
assert_string_view_eq("", GetBasename(""));
}
TEST(filenames, GetExtension) {
assert_string_view_eq(".txt", GetExtension("/bar/dir/foo.txt"));
assert_string_view_eq(".txt", GetExtension("bar/dir/foo.txt"));
assert_string_view_eq(".txt", GetExtension("foo.txt"));
assert_string_view_eq("", GetExtension("foo"));
assert_string_view_eq("", GetExtension(""));
}
TEST(filenames, StripExtension) {
assert_string_view_eq("/bar/dir/foo", StripExtension("/bar/dir/foo.txt"));
assert_string_view_eq("bar/dir/foo", StripExtension("bar/dir/foo.txt"));
assert_string_view_eq("foo", StripExtension("foo.txt"));
assert_string_view_eq("foo", StripExtension("foo"));
assert_string_view_eq("", StripExtension(""));
}

264
third_party/wasm2c/src/test-hexfloat.cc vendored Normal file
View File

@@ -0,0 +1,264 @@
/*
* Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <cstdio>
#include <thread>
#include <vector>
#include "gtest/gtest.h"
#include "src/literal.h"
#define FOREACH_UINT32_MULTIPLIER 1
#define FOREACH_UINT32(bits) \
uint32_t last_bits = 0; \
uint32_t bits = shard; \
int last_top_byte = -1; \
for (; bits >= last_bits; \
last_bits = bits, bits += num_threads_ * FOREACH_UINT32_MULTIPLIER)
#define LOG_COMPLETION(bits) \
if (shard == 0) { \
int top_byte = bits >> 24; \
if (top_byte != last_top_byte) { \
printf("value: 0x%08x (%d%%)\r", bits, \
static_cast<int>(static_cast<double>(bits) * 100 / UINT32_MAX)); \
fflush(stdout); \
last_top_byte = top_byte; \
} \
}
#define LOG_DONE() \
if (shard == 0) { \
printf("done.\n"); \
fflush(stdout); \
}
using namespace wabt;
template <typename T, typename F>
T bit_cast(F value) {
T result;
memcpy(&result, &value, sizeof(result));
return result;
}
static bool is_infinity_or_nan(uint32_t float_bits) {
return ((float_bits >> 23) & 0xff) == 0xff;
}
static bool is_infinity_or_nan(uint64_t double_bits) {
return ((double_bits >> 52) & 0x7ff) == 0x7ff;
}
class ThreadedTest : public ::testing::Test {
protected:
static const int kDefaultNumThreads = 2;
virtual void SetUp() {
num_threads_ = std::thread::hardware_concurrency();
if (num_threads_ == 0)
num_threads_ = kDefaultNumThreads;
}
virtual void RunShard(int shard) = 0;
void RunThreads() {
std::vector<std::thread> threads;
for (int i = 0; i < num_threads_; ++i) {
threads.emplace_back(&ThreadedTest::RunShard, this, i);
}
for (std::thread& thread : threads) {
thread.join();
}
}
int num_threads_;
};
/* floats */
class AllFloatsParseTest : public ThreadedTest {
protected:
virtual void RunShard(int shard) {
char buffer[100];
FOREACH_UINT32(bits) {
LOG_COMPLETION(bits);
if (is_infinity_or_nan(bits))
continue;
float value = bit_cast<float>(bits);
int len = snprintf(buffer, sizeof(buffer), "%a", value);
uint32_t me;
ASSERT_EQ(Result::Ok,
ParseFloat(LiteralType::Hexfloat, buffer, buffer + len, &me));
ASSERT_EQ(me, bits);
}
LOG_DONE();
}
};
TEST_F(AllFloatsParseTest, Run) {
RunThreads();
}
class AllFloatsWriteTest : public ThreadedTest {
protected:
virtual void RunShard(int shard) {
char buffer[100];
FOREACH_UINT32(bits) {
LOG_COMPLETION(bits);
if (is_infinity_or_nan(bits))
continue;
WriteFloatHex(buffer, sizeof(buffer), bits);
char* endptr;
float them_float = strtof(buffer, &endptr);
uint32_t them_bits = bit_cast<uint32_t>(them_float);
ASSERT_EQ(bits, them_bits);
}
LOG_DONE();
}
};
TEST_F(AllFloatsWriteTest, Run) {
RunThreads();
}
class AllFloatsRoundtripTest : public ThreadedTest {
protected:
static LiteralType ClassifyFloat(uint32_t float_bits) {
if (is_infinity_or_nan(float_bits)) {
if (float_bits & 0x7fffff) {
return LiteralType::Nan;
} else {
return LiteralType::Infinity;
}
} else {
return LiteralType::Hexfloat;
}
}
virtual void RunShard(int shard) {
char buffer[100];
FOREACH_UINT32(bits) {
LOG_COMPLETION(bits);
WriteFloatHex(buffer, sizeof(buffer), bits);
int len = strlen(buffer);
uint32_t new_bits;
ASSERT_EQ(Result::Ok, ParseFloat(ClassifyFloat(bits), buffer,
buffer + len, &new_bits));
ASSERT_EQ(new_bits, bits);
}
LOG_DONE();
}
};
TEST_F(AllFloatsRoundtripTest, Run) {
RunThreads();
}
/* doubles */
class ManyDoublesParseTest : public ThreadedTest {
protected:
virtual void RunShard(int shard) {
char buffer[100];
FOREACH_UINT32(halfbits) {
LOG_COMPLETION(halfbits);
uint64_t bits = (static_cast<uint64_t>(halfbits) << 32) | halfbits;
if (is_infinity_or_nan(bits))
continue;
double value = bit_cast<double>(bits);
int len = snprintf(buffer, sizeof(buffer), "%a", value);
uint64_t me;
ASSERT_EQ(Result::Ok,
ParseDouble(LiteralType::Hexfloat, buffer, buffer + len, &me));
ASSERT_EQ(me, bits);
}
LOG_DONE();
}
};
TEST_F(ManyDoublesParseTest, Run) {
RunThreads();
}
class ManyDoublesWriteTest : public ThreadedTest {
protected:
virtual void RunShard(int shard) {
char buffer[100];
FOREACH_UINT32(halfbits) {
LOG_COMPLETION(halfbits);
uint64_t bits = (static_cast<uint64_t>(halfbits) << 32) | halfbits;
if (is_infinity_or_nan(bits))
continue;
WriteDoubleHex(buffer, sizeof(buffer), bits);
char* endptr;
double them_double = strtod(buffer, &endptr);
uint64_t them_bits = bit_cast<uint64_t>(them_double);
ASSERT_EQ(bits, them_bits);
}
LOG_DONE();
}
};
TEST_F(ManyDoublesWriteTest, Run) {
RunThreads();
}
class ManyDoublesRoundtripTest : public ThreadedTest {
protected:
static LiteralType ClassifyDouble(uint64_t double_bits) {
if (is_infinity_or_nan(double_bits)) {
if (double_bits & 0xfffffffffffffULL) {
return LiteralType::Nan;
} else {
return LiteralType::Infinity;
}
} else {
return LiteralType::Hexfloat;
}
}
virtual void RunShard(int shard) {
char buffer[100];
FOREACH_UINT32(halfbits) {
LOG_COMPLETION(halfbits);
uint64_t bits = (static_cast<uint64_t>(halfbits) << 32) | halfbits;
WriteDoubleHex(buffer, sizeof(buffer), bits);
int len = strlen(buffer);
uint64_t new_bits;
ASSERT_EQ(Result::Ok, ParseDouble(ClassifyDouble(bits), buffer,
buffer + len, &new_bits));
ASSERT_EQ(new_bits, bits);
}
LOG_DONE();
}
};
TEST_F(ManyDoublesRoundtripTest, Run) {
RunThreads();
}

693
third_party/wasm2c/src/test-interp.cc vendored Normal file
View File

@@ -0,0 +1,693 @@
/*
* Copyright 2020 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "gtest/gtest.h"
#include "src/binary-reader.h"
#include "src/error-formatter.h"
#include "src/interp/binary-reader-interp.h"
#include "src/interp/interp.h"
using namespace wabt;
using namespace wabt::interp;
class InterpTest : public ::testing::Test {
public:
void ReadModule(const std::vector<u8>& data) {
Errors errors;
ReadBinaryOptions options;
Result result = ReadBinaryInterp(data.data(), data.size(), options, &errors,
&module_desc_);
ASSERT_EQ(Result::Ok, result)
<< FormatErrorsToString(errors, Location::Type::Binary);
}
void Instantiate(const RefVec& imports = RefVec{}) {
mod_ = Module::New(store_, module_desc_);
RefPtr<Trap> trap;
inst_ = Instance::Instantiate(store_, mod_.ref(), imports, &trap);
ASSERT_TRUE(inst_) << trap->message();
}
DefinedFunc::Ptr GetFuncExport(interp::Index index) {
EXPECT_LT(index, inst_->exports().size());
return store_.UnsafeGet<DefinedFunc>(inst_->exports()[index]);
}
void ExpectBufferStrEq(OutputBuffer& buf, const char* str) {
std::string buf_str(buf.data.begin(), buf.data.end());
EXPECT_STREQ(buf_str.c_str(), str);
}
Store store_;
ModuleDesc module_desc_;
Module::Ptr mod_;
Instance::Ptr inst_;
};
TEST_F(InterpTest, Empty) {
ASSERT_TRUE(mod_.empty());
ReadModule({0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00});
Instantiate();
ASSERT_FALSE(mod_.empty());
}
TEST_F(InterpTest, MVP) {
// (module
// (type (;0;) (func (param i32) (result i32)))
// (type (;1;) (func (param f32) (result f32)))
// (type (;2;) (func))
// (import "foo" "bar" (func (;0;) (type 0)))
// (func (;1;) (type 1) (param f32) (result f32)
// (f32.const 0x1.5p+5 (;=42;)))
// (func (;2;) (type 2))
// (table (;0;) 1 2 funcref)
// (memory (;0;) 1)
// (global (;0;) i32 (i32.const 1))
// (export "quux" (func 1))
// (start 2)
// (elem (;0;) (i32.const 0) 0 1)
// (data (;0;) (i32.const 2) "hello"))
ReadModule({
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x03, 0x60,
0x01, 0x7f, 0x01, 0x7f, 0x60, 0x01, 0x7d, 0x01, 0x7d, 0x60, 0x00, 0x00,
0x02, 0x0b, 0x01, 0x03, 0x66, 0x6f, 0x6f, 0x03, 0x62, 0x61, 0x72, 0x00,
0x00, 0x03, 0x03, 0x02, 0x01, 0x02, 0x04, 0x05, 0x01, 0x70, 0x01, 0x01,
0x02, 0x05, 0x03, 0x01, 0x00, 0x01, 0x06, 0x06, 0x01, 0x7f, 0x00, 0x41,
0x01, 0x0b, 0x07, 0x08, 0x01, 0x04, 0x71, 0x75, 0x75, 0x78, 0x00, 0x01,
0x08, 0x01, 0x02, 0x09, 0x08, 0x01, 0x00, 0x41, 0x00, 0x0b, 0x02, 0x00,
0x01, 0x0a, 0x0c, 0x02, 0x07, 0x00, 0x43, 0x00, 0x00, 0x28, 0x42, 0x0b,
0x02, 0x00, 0x0b, 0x0b, 0x0b, 0x01, 0x00, 0x41, 0x02, 0x0b, 0x05, 0x68,
0x65, 0x6c, 0x6c, 0x6f,
});
EXPECT_EQ(3u, module_desc_.func_types.size());
EXPECT_EQ(1u, module_desc_.imports.size());
EXPECT_EQ(2u, module_desc_.funcs.size());
EXPECT_EQ(1u, module_desc_.tables.size());
EXPECT_EQ(1u, module_desc_.memories.size());
EXPECT_EQ(1u, module_desc_.globals.size());
EXPECT_EQ(0u, module_desc_.events.size());
EXPECT_EQ(1u, module_desc_.exports.size());
EXPECT_EQ(1u, module_desc_.starts.size());
EXPECT_EQ(1u, module_desc_.elems.size());
EXPECT_EQ(1u, module_desc_.datas.size());
}
namespace {
// (func (export "fac") (param $n i32) (result i32)
// (local $result i32)
// (local.set $result (i32.const 1))
// (loop (result i32)
// (local.set $result
// (i32.mul
// (br_if 1 (local.get $result) (i32.eqz (local.get $n)))
// (local.get $n)))
// (local.set $n (i32.sub (local.get $n) (i32.const 1)))
// (br 0)))
const std::vector<u8> s_fac_module = {
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01,
0x60, 0x01, 0x7f, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x07, 0x07,
0x01, 0x03, 0x66, 0x61, 0x63, 0x00, 0x00, 0x0a, 0x22, 0x01, 0x20,
0x01, 0x01, 0x7f, 0x41, 0x01, 0x21, 0x01, 0x03, 0x7f, 0x20, 0x01,
0x20, 0x00, 0x45, 0x0d, 0x01, 0x20, 0x00, 0x6c, 0x21, 0x01, 0x20,
0x00, 0x41, 0x01, 0x6b, 0x21, 0x00, 0x0c, 0x00, 0x0b, 0x0b,
};
} // namespace
TEST_F(InterpTest, Disassemble) {
ReadModule(s_fac_module);
MemoryStream stream;
module_desc_.istream.Disassemble(&stream);
auto buf = stream.ReleaseOutputBuffer();
ExpectBufferStrEq(*buf,
R"( 0| alloca 1
8| i32.const 1
16| local.set $2, %[-1]
24| local.get $1
32| local.get $3
40| i32.eqz %[-1]
44| br_unless @60, %[-1]
52| br @116
60| local.get $3
68| i32.mul %[-2], %[-1]
72| local.set $2, %[-1]
80| local.get $2
88| i32.const 1
96| i32.sub %[-2], %[-1]
100| local.set $3, %[-1]
108| br @24
116| drop_keep $2 $1
128| return
)");
}
TEST_F(InterpTest, Fac) {
ReadModule(s_fac_module);
Instantiate();
auto func = GetFuncExport(0);
Values results;
Trap::Ptr trap;
Result result = func->Call(store_, {Value::Make(5)}, results, &trap);
ASSERT_EQ(Result::Ok, result);
EXPECT_EQ(1u, results.size());
EXPECT_EQ(120u, results[0].Get<u32>());
}
TEST_F(InterpTest, Fac_Trace) {
ReadModule(s_fac_module);
Instantiate();
auto func = GetFuncExport(0);
Values results;
Trap::Ptr trap;
MemoryStream stream;
Result result = func->Call(store_, {Value::Make(2)}, results, &trap, &stream);
ASSERT_EQ(Result::Ok, result);
auto buf = stream.ReleaseOutputBuffer();
ExpectBufferStrEq(*buf,
R"(#0. 0: V:1 | alloca 1
#0. 8: V:2 | i32.const 1
#0. 16: V:3 | local.set $2, 1
#0. 24: V:2 | local.get $1
#0. 32: V:3 | local.get $3
#0. 40: V:4 | i32.eqz 2
#0. 44: V:4 | br_unless @60, 0
#0. 60: V:3 | local.get $3
#0. 68: V:4 | i32.mul 1, 2
#0. 72: V:3 | local.set $2, 2
#0. 80: V:2 | local.get $2
#0. 88: V:3 | i32.const 1
#0. 96: V:4 | i32.sub 2, 1
#0. 100: V:3 | local.set $3, 1
#0. 108: V:2 | br @24
#0. 24: V:2 | local.get $1
#0. 32: V:3 | local.get $3
#0. 40: V:4 | i32.eqz 1
#0. 44: V:4 | br_unless @60, 0
#0. 60: V:3 | local.get $3
#0. 68: V:4 | i32.mul 2, 1
#0. 72: V:3 | local.set $2, 2
#0. 80: V:2 | local.get $2
#0. 88: V:3 | i32.const 1
#0. 96: V:4 | i32.sub 1, 1
#0. 100: V:3 | local.set $3, 0
#0. 108: V:2 | br @24
#0. 24: V:2 | local.get $1
#0. 32: V:3 | local.get $3
#0. 40: V:4 | i32.eqz 0
#0. 44: V:4 | br_unless @60, 1
#0. 52: V:3 | br @116
#0. 116: V:3 | drop_keep $2 $1
#0. 128: V:1 | return
)");
}
TEST_F(InterpTest, Local_Trace) {
// (func (export "a")
// (local i32 i64 f32 f64)
// (local.set 0 (i32.const 0))
// (local.set 1 (i64.const 1))
// (local.set 2 (f32.const 2))
// (local.set 3 (f64.const 3)))
ReadModule({
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01,
0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x07, 0x05, 0x01, 0x01,
0x61, 0x00, 0x00, 0x0a, 0x26, 0x01, 0x24, 0x04, 0x01, 0x7f, 0x01,
0x7e, 0x01, 0x7d, 0x01, 0x7c, 0x41, 0x00, 0x21, 0x00, 0x42, 0x01,
0x21, 0x01, 0x43, 0x00, 0x00, 0x00, 0x40, 0x21, 0x02, 0x44, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, 0x21, 0x03, 0x0b,
});
Instantiate();
auto func = GetFuncExport(0);
Values results;
Trap::Ptr trap;
MemoryStream stream;
Result result = func->Call(store_, {}, results, &trap, &stream);
ASSERT_EQ(Result::Ok, result);
auto buf = stream.ReleaseOutputBuffer();
ExpectBufferStrEq(*buf,
R"(#0. 0: V:0 | alloca 4
#0. 8: V:4 | i32.const 0
#0. 16: V:5 | local.set $5, 0
#0. 24: V:4 | i64.const 1
#0. 36: V:5 | local.set $4, 1
#0. 44: V:4 | f32.const 2
#0. 52: V:5 | local.set $3, 2
#0. 60: V:4 | f64.const 3
#0. 72: V:5 | local.set $2, 3
#0. 80: V:4 | drop_keep $4 $0
#0. 92: V:0 | return
)");
}
TEST_F(InterpTest, HostFunc) {
// (import "" "f" (func $f (param i32) (result i32)))
// (func (export "g") (result i32)
// (call $f (i32.const 1)))
ReadModule({
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0a,
0x02, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x00, 0x01, 0x7f,
0x02, 0x06, 0x01, 0x00, 0x01, 0x66, 0x00, 0x00, 0x03, 0x02,
0x01, 0x01, 0x07, 0x05, 0x01, 0x01, 0x67, 0x00, 0x01, 0x0a,
0x08, 0x01, 0x06, 0x00, 0x41, 0x01, 0x10, 0x00, 0x0b,
});
auto host_func =
HostFunc::New(store_, FuncType{{ValueType::I32}, {ValueType::I32}},
[](Thread& thread, const Values& params, Values& results,
Trap::Ptr* out_trap) -> Result {
results[0] = Value::Make(params[0].Get<u32>() + 1);
return Result::Ok;
});
Instantiate({host_func->self()});
Values results;
Trap::Ptr trap;
Result result = GetFuncExport(0)->Call(store_, {}, results, &trap);
ASSERT_EQ(Result::Ok, result);
EXPECT_EQ(1u, results.size());
EXPECT_EQ(2u, results[0].Get<u32>());
}
TEST_F(InterpTest, HostFunc_PingPong) {
// (import "" "f" (func $f (param i32) (result i32)))
// (func (export "g") (param i32) (result i32)
// (call $f (i32.add (local.get 0) (i32.const 1))))
ReadModule({
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60,
0x01, 0x7f, 0x01, 0x7f, 0x02, 0x06, 0x01, 0x00, 0x01, 0x66, 0x00, 0x00,
0x03, 0x02, 0x01, 0x00, 0x07, 0x05, 0x01, 0x01, 0x67, 0x00, 0x01, 0x0a,
0x0b, 0x01, 0x09, 0x00, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x10, 0x00, 0x0b,
});
auto host_func = HostFunc::New(
store_, FuncType{{ValueType::I32}, {ValueType::I32}},
[&](Thread& thread, const Values& params, Values& results,
Trap::Ptr* out_trap) -> Result {
auto val = params[0].Get<u32>();
if (val < 10) {
return GetFuncExport(0)->Call(store_, {Value::Make(val * 2)}, results,
out_trap);
}
results[0] = Value::Make(val);
return Result::Ok;
});
Instantiate({host_func->self()});
// Should produce the following calls:
// g(1) -> f(2) -> g(4) -> f(5) -> g(10) -> f(11) -> return 11
Values results;
Trap::Ptr trap;
Result result = GetFuncExport(0)->Call(store_, {Value::Make(1)}, results, &trap);
ASSERT_EQ(Result::Ok, result);
EXPECT_EQ(1u, results.size());
EXPECT_EQ(11u, results[0].Get<u32>());
}
TEST_F(InterpTest, HostFunc_PingPong_SameThread) {
// (import "" "f" (func $f (param i32) (result i32)))
// (func (export "g") (param i32) (result i32)
// (call $f (i32.add (local.get 0) (i32.const 1))))
ReadModule({
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60,
0x01, 0x7f, 0x01, 0x7f, 0x02, 0x06, 0x01, 0x00, 0x01, 0x66, 0x00, 0x00,
0x03, 0x02, 0x01, 0x00, 0x07, 0x05, 0x01, 0x01, 0x67, 0x00, 0x01, 0x0a,
0x0b, 0x01, 0x09, 0x00, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x10, 0x00, 0x0b,
});
auto thread = Thread::New(store_, {});
auto host_func =
HostFunc::New(store_, FuncType{{ValueType::I32}, {ValueType::I32}},
[&](Thread& t, const Values& params, Values& results,
Trap::Ptr* out_trap) -> Result {
auto val = params[0].Get<u32>();
if (val < 10) {
return GetFuncExport(0)->Call(t, {Value::Make(val * 2)},
results, out_trap);
}
results[0] = Value::Make(val);
return Result::Ok;
});
Instantiate({host_func->self()});
// Should produce the following calls:
// g(1) -> f(2) -> g(4) -> f(5) -> g(10) -> f(11) -> return 11
Values results;
Trap::Ptr trap;
Result result = GetFuncExport(0)->Call(*thread, {Value::Make(1)}, results, &trap);
ASSERT_EQ(Result::Ok, result);
EXPECT_EQ(1u, results.size());
EXPECT_EQ(11u, results[0].Get<u32>());
}
TEST_F(InterpTest, HostTrap) {
// (import "host" "a" (func $0))
// (func $1 call $0)
// (start $1)
ReadModule({
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01,
0x60, 0x00, 0x00, 0x02, 0x0a, 0x01, 0x04, 0x68, 0x6f, 0x73, 0x74,
0x01, 0x61, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x08, 0x01, 0x01,
0x0a, 0x06, 0x01, 0x04, 0x00, 0x10, 0x00, 0x0b,
});
auto host_func =
HostFunc::New(store_, FuncType{{}, {}},
[&](Thread& thread, const Values& params, Values& results,
Trap::Ptr* out_trap) -> Result {
*out_trap = Trap::New(store_, "boom");
return Result::Error;
});
mod_ = Module::New(store_, module_desc_);
RefPtr<Trap> trap;
Instance::Instantiate(store_, mod_.ref(), {host_func->self()}, &trap);
ASSERT_TRUE(trap);
ASSERT_EQ("boom", trap->message());
}
TEST_F(InterpTest, Rot13) {
// (import "host" "mem" (memory $mem 1))
// (import "host" "fill_buf" (func $fill_buf (param i32 i32) (result i32)))
// (import "host" "buf_done" (func $buf_done (param i32 i32)))
//
// (func $rot13c (param $c i32) (result i32)
// (local $uc i32)
//
// ;; No change if < 'A'.
// (if (i32.lt_u (get_local $c) (i32.const 65))
// (return (get_local $c)))
//
// ;; Clear 5th bit of c, to force uppercase. 0xdf = 0b11011111
// (set_local $uc (i32.and (get_local $c) (i32.const 0xdf)))
//
// ;; In range ['A', 'M'] return |c| + 13.
// (if (i32.le_u (get_local $uc) (i32.const 77))
// (return (i32.add (get_local $c) (i32.const 13))))
//
// ;; In range ['N', 'Z'] return |c| - 13.
// (if (i32.le_u (get_local $uc) (i32.const 90))
// (return (i32.sub (get_local $c) (i32.const 13))))
//
// ;; No change for everything else.
// (return (get_local $c))
// )
//
// (func (export "rot13")
// (local $size i32)
// (local $i i32)
//
// ;; Ask host to fill memory [0, 1024) with data.
// (call $fill_buf (i32.const 0) (i32.const 1024))
//
// ;; The host returns the size filled.
// (set_local $size)
//
// ;; Loop over all bytes and rot13 them.
// (block $exit
// (loop $top
// ;; if (i >= size) break
// (if (i32.ge_u (get_local $i) (get_local $size)) (br $exit))
//
// ;; mem[i] = rot13c(mem[i])
// (i32.store8
// (get_local $i)
// (call $rot13c
// (i32.load8_u (get_local $i))))
//
// ;; i++
// (set_local $i (i32.add (get_local $i) (i32.const 1)))
// (br $top)
// )
// )
//
// (call $buf_done (i32.const 0) (get_local $size))
// )
ReadModule({
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x14, 0x04, 0x60,
0x02, 0x7f, 0x7f, 0x01, 0x7f, 0x60, 0x02, 0x7f, 0x7f, 0x00, 0x60, 0x01,
0x7f, 0x01, 0x7f, 0x60, 0x00, 0x00, 0x02, 0x2d, 0x03, 0x04, 0x68, 0x6f,
0x73, 0x74, 0x03, 0x6d, 0x65, 0x6d, 0x02, 0x00, 0x01, 0x04, 0x68, 0x6f,
0x73, 0x74, 0x08, 0x66, 0x69, 0x6c, 0x6c, 0x5f, 0x62, 0x75, 0x66, 0x00,
0x00, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x08, 0x62, 0x75, 0x66, 0x5f, 0x64,
0x6f, 0x6e, 0x65, 0x00, 0x01, 0x03, 0x03, 0x02, 0x02, 0x03, 0x07, 0x09,
0x01, 0x05, 0x72, 0x6f, 0x74, 0x31, 0x33, 0x00, 0x03, 0x0a, 0x74, 0x02,
0x39, 0x01, 0x01, 0x7f, 0x20, 0x00, 0x41, 0xc1, 0x00, 0x49, 0x04, 0x40,
0x20, 0x00, 0x0f, 0x0b, 0x20, 0x00, 0x41, 0xdf, 0x01, 0x71, 0x21, 0x01,
0x20, 0x01, 0x41, 0xcd, 0x00, 0x4d, 0x04, 0x40, 0x20, 0x00, 0x41, 0x0d,
0x6a, 0x0f, 0x0b, 0x20, 0x01, 0x41, 0xda, 0x00, 0x4d, 0x04, 0x40, 0x20,
0x00, 0x41, 0x0d, 0x6b, 0x0f, 0x0b, 0x20, 0x00, 0x0f, 0x0b, 0x38, 0x01,
0x02, 0x7f, 0x41, 0x00, 0x41, 0x80, 0x08, 0x10, 0x00, 0x21, 0x00, 0x02,
0x40, 0x03, 0x40, 0x20, 0x01, 0x20, 0x00, 0x4f, 0x04, 0x40, 0x0c, 0x02,
0x0b, 0x20, 0x01, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x10, 0x02, 0x3a, 0x00,
0x00, 0x20, 0x01, 0x41, 0x01, 0x6a, 0x21, 0x01, 0x0c, 0x00, 0x0b, 0x0b,
0x41, 0x00, 0x20, 0x00, 0x10, 0x01, 0x0b,
});
auto host_func =
HostFunc::New(store_, FuncType{{ValueType::I32}, {ValueType::I32}},
[](Thread& thread, const Values& params, Values& results,
Trap::Ptr* out_trap) -> Result {
results[0] = Value::Make(params[0].Get<u32>() + 1);
return Result::Ok;
});
std::string string_data = "Hello, WebAssembly!";
auto memory = Memory::New(store_, MemoryType{Limits{1}});
auto fill_buf = [&](Thread& thread, const Values& params, Values& results,
Trap::Ptr* out_trap) -> Result {
// (param $ptr i32) (param $max_size i32) (result $size i32)
EXPECT_EQ(2u, params.size());
EXPECT_EQ(1u, results.size());
u32 ptr = params[0].Get<u32>();
u32 max_size = params[1].Get<u32>();
u32 size = std::min(max_size, u32(string_data.size()));
EXPECT_LT(ptr + size, memory->ByteSize());
std::copy(string_data.begin(), string_data.begin() + size,
memory->UnsafeData() + ptr);
results[0].Set(size);
return Result::Ok;
};
auto fill_buf_func = HostFunc::New(
store_, FuncType{{ValueType::I32, ValueType::I32}, {ValueType::I32}},
fill_buf);
auto buf_done = [&](Thread& thread, const Values& params, Values& results,
Trap::Ptr* out_trap) -> Result {
// (param $ptr i32) (param $size i32)
EXPECT_EQ(2u, params.size());
EXPECT_EQ(0u, results.size());
u32 ptr = params[0].Get<u32>();
u32 size = params[1].Get<u32>();
EXPECT_LT(ptr + size, memory->ByteSize());
string_data.resize(size);
std::copy(memory->UnsafeData() + ptr, memory->UnsafeData() + ptr + size,
string_data.begin());
return Result::Ok;
};
auto buf_done_func = HostFunc::New(
store_, FuncType{{ValueType::I32, ValueType::I32}, {}}, buf_done);
Instantiate({memory->self(), fill_buf_func->self(), buf_done_func->self()});
auto rot13 = GetFuncExport(0);
Values results;
Trap::Ptr trap;
ASSERT_EQ(Result::Ok, rot13->Call(store_, {}, results, &trap));
ASSERT_EQ("Uryyb, JroNffrzoyl!", string_data);
ASSERT_EQ(Result::Ok, rot13->Call(store_, {}, results, &trap));
ASSERT_EQ("Hello, WebAssembly!", string_data);
}
class InterpGCTest : public InterpTest {
public:
void SetUp() override {
before_new = store_.object_count();
}
void TearDown() override {
// Reset instance and module, in case they were allocated.
inst_.reset();
mod_.reset();
store_.Collect();
EXPECT_EQ(before_new, store_.object_count());
}
size_t before_new;
};
TEST_F(InterpGCTest, Collect_Basic) {
auto foreign = Foreign::New(store_, nullptr);
auto after_new = store_.object_count();
EXPECT_EQ(before_new + 1, after_new);
// Remove root, but object is not destroyed until collect.
foreign.reset();
EXPECT_EQ(after_new, store_.object_count());
}
TEST_F(InterpGCTest, Collect_GlobalCycle) {
auto gt = GlobalType{ValueType::ExternRef, Mutability::Var};
auto g1 = Global::New(store_, gt, Value::Make(Ref::Null));
auto g2 = Global::New(store_, gt, Value::Make(g1->self()));
g1->Set(store_, g2->self());
auto after_new = store_.object_count();
EXPECT_EQ(before_new + 2, after_new);
// Remove g1 root, but it's kept alive by g2.
g1.reset();
store_.Collect();
EXPECT_EQ(after_new, store_.object_count());
// Remove g2 root, now both should be removed.
g2.reset();
}
TEST_F(InterpGCTest, Collect_TableCycle) {
auto tt = TableType{ValueType::ExternRef, Limits{2}};
auto t1 = Table::New(store_, tt);
auto t2 = Table::New(store_, tt);
auto t3 = Table::New(store_, tt);
t1->Set(store_, 0, t1->self()); // t1 references itself.
t2->Set(store_, 0, t3->self());
t3->Set(store_, 0, t2->self()); // t2 and t3 reference each other.
t3->Set(store_, 1, t1->self()); // t3 also references t1.
auto after_new = store_.object_count();
EXPECT_EQ(before_new + 3, after_new);
// Remove t1 and t2 roots, but their kept alive by t3.
t1.reset();
t2.reset();
store_.Collect();
EXPECT_EQ(after_new, store_.object_count());
// Remove t3 root, now all should be removed.
t3.reset();
}
TEST_F(InterpGCTest, Collect_Func) {
ReadModule(s_fac_module);
Instantiate();
auto func = GetFuncExport(0);
auto after_new = store_.object_count();
EXPECT_EQ(before_new + 3, after_new); // module, instance, func.
// Reset module and instance roots, but they'll be kept alive by the func.
mod_.reset();
inst_.reset();
store_.Collect();
EXPECT_EQ(after_new, store_.object_count());
}
TEST_F(InterpGCTest, Collect_InstanceImport) {
// (import "" "f" (func))
// (import "" "t" (table 0 funcref))
// (import "" "m" (memory 0))
// (import "" "g" (global i32))
ReadModule({
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01,
0x60, 0x00, 0x00, 0x02, 0x19, 0x04, 0x00, 0x01, 0x66, 0x00, 0x00,
0x00, 0x01, 0x74, 0x01, 0x70, 0x00, 0x00, 0x00, 0x01, 0x6d, 0x02,
0x00, 0x00, 0x00, 0x01, 0x67, 0x03, 0x7f, 0x00,
});
auto f = HostFunc::New(store_, FuncType{{}, {}},
[](Thread& thread, const Values&, Values&,
Trap::Ptr*) -> Result { return Result::Ok; });
auto t = Table::New(store_, TableType{ValueType::FuncRef, Limits{0}});
auto m = Memory::New(store_, MemoryType{Limits{0}});
auto g = Global::New(store_, GlobalType{ValueType::I32, Mutability::Const},
Value::Make(5));
Instantiate({f->self(), t->self(), m->self(), g->self()});
auto after_new = store_.object_count();
EXPECT_EQ(before_new + 6, after_new); // module, instance, f, t, m, g
// Instance keeps all imports alive.
f.reset();
t.reset();
m.reset();
g.reset();
store_.Collect();
EXPECT_EQ(after_new, store_.object_count());
}
TEST_F(InterpGCTest, Collect_InstanceExport) {
// (func (export "f"))
// (global (export "g") i32 (i32.const 0))
// (table (export "t") 0 funcref)
// (memory (export "m") 0)
ReadModule({
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01,
0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x04, 0x04, 0x01, 0x70,
0x00, 0x00, 0x05, 0x03, 0x01, 0x00, 0x00, 0x06, 0x06, 0x01, 0x7f,
0x00, 0x41, 0x00, 0x0b, 0x07, 0x11, 0x04, 0x01, 0x66, 0x00, 0x00,
0x01, 0x67, 0x03, 0x00, 0x01, 0x74, 0x01, 0x00, 0x01, 0x6d, 0x02,
0x00, 0x0a, 0x04, 0x01, 0x02, 0x00, 0x0b,
});
Instantiate();
auto after_new = store_.object_count();
EXPECT_EQ(before_new + 6, after_new); // module, instance, f, t, m, g
// Instance keeps all exports alive.
store_.Collect();
EXPECT_EQ(after_new, store_.object_count());
}
// TODO: Test for Thread keeping references alive as locals/params/stack values.
// This requires better tracking of references than currently exists in the
// interpreter. (see TODOs in Select/LocalGet/GlobalGet)

View File

@@ -0,0 +1,584 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "gtest/gtest.h"
#include <memory>
#include "src/intrusive-list.h"
#include "src/make-unique.h"
using namespace wabt;
namespace {
struct TestObject : intrusive_list_base<TestObject> {
static int creation_count;
TestObject(int data = 0, int data2 = 0) : data(data), data2(data2) {
++creation_count;
}
// Allow move.
TestObject(TestObject&& other) {
// Don't increment creation_count; we're moving from other.
*this = std::move(other);
}
TestObject& operator=(TestObject&& other) {
data = other.data;
data2 = other.data2;
other.moved = true;
return *this;
}
// Disallow copy.
TestObject(const TestObject&) = delete;
TestObject& operator=(const TestObject&) = delete;
~TestObject() {
if (!moved) {
creation_count--;
}
}
int data;
int data2;
bool moved = false;
};
// static
int TestObject::creation_count = 0;
typedef intrusive_list<TestObject> TestObjectList;
class IntrusiveListTest : public ::testing::Test {
protected:
virtual void SetUp() {
// Reset to 0 even if the previous test leaked objects to keep the tests
// independent.
TestObject::creation_count = 0;
}
virtual void TearDown() { ASSERT_EQ(0, TestObject::creation_count); }
TestObjectList NewList(const std::vector<int>& data_values) {
TestObjectList result;
for (auto data_value : data_values)
result.emplace_back(data_value);
return result;
}
void AssertListEq(const TestObjectList& list,
const std::vector<int>& expected) {
size_t count = 0;
for (const TestObject& node : list) {
ASSERT_EQ(expected[count++], node.data);
}
ASSERT_EQ(count, expected.size());
}
void AssertListEq(const TestObjectList& list,
const std::vector<int>& expected,
const std::vector<int>& expected2) {
assert(expected.size() == expected2.size());
size_t count = 0;
for (const TestObject& node : list) {
ASSERT_EQ(expected[count], node.data);
ASSERT_EQ(expected2[count], node.data2);
count++;
}
ASSERT_EQ(count, expected.size());
}
};
} // end anonymous namespace
TEST_F(IntrusiveListTest, default_constructor) {
TestObjectList list;
}
TEST_F(IntrusiveListTest, node_constructor) {
TestObjectList list(MakeUnique<TestObject>(1));
AssertListEq(list, {1});
}
TEST_F(IntrusiveListTest, node_move_constructor) {
TestObjectList list(TestObject(1));
AssertListEq(list, {1});
}
TEST_F(IntrusiveListTest, move_constructor) {
TestObjectList list1 = NewList({1, 2, 3});
TestObjectList list2(std::move(list1));
AssertListEq(list1, {});
AssertListEq(list2, {1, 2, 3});
}
TEST_F(IntrusiveListTest, move_assignment_operator) {
TestObjectList list1 = NewList({1, 2, 3});
TestObjectList list2;
list2 = std::move(list1);
AssertListEq(list1, {});
AssertListEq(list2, {1, 2, 3});
}
namespace {
class IntrusiveListIteratorTest : public IntrusiveListTest {
protected:
virtual void SetUp() {
IntrusiveListTest::SetUp();
list_.emplace_back(1);
list_.emplace_back(2);
list_.emplace_back(3);
}
virtual void TearDown() {
list_.clear();
IntrusiveListTest::TearDown();
}
template <typename Iter>
void TestForward(Iter first, Iter last, const std::vector<int>& expected) {
size_t count = 0;
while (first != last) {
ASSERT_EQ(expected[count], first->data);
++first;
++count;
}
ASSERT_EQ(count, expected.size());
}
template <typename Iter>
void TestBackward(Iter first, Iter last, const std::vector<int>& expected) {
size_t count = 0;
while (first != last) {
--last;
ASSERT_EQ(expected[count], last->data);
++count;
}
ASSERT_EQ(count, expected.size());
}
TestObjectList list_;
const TestObjectList& clist_ = list_;
};
} // end of anonymous namespace
TEST_F(IntrusiveListIteratorTest, begin_end_forward) {
TestForward(list_.begin(), list_.end(), {1, 2, 3});
TestForward(clist_.begin(), clist_.end(), {1, 2, 3});
}
TEST_F(IntrusiveListIteratorTest, rbegin_rend_forward) {
TestForward(list_.rbegin(), list_.rend(), {3, 2, 1});
TestForward(clist_.rbegin(), clist_.rend(), {3, 2, 1});
}
TEST_F(IntrusiveListIteratorTest, cbegin_cend_forward) {
TestForward(list_.cbegin(), list_.cend(), {1, 2, 3});
TestForward(clist_.cbegin(), clist_.cend(), {1, 2, 3});
}
TEST_F(IntrusiveListIteratorTest, crbegin_crend_forward) {
TestForward(list_.crbegin(), list_.crend(), {3, 2, 1});
TestForward(clist_.crbegin(), clist_.crend(), {3, 2, 1});
}
TEST_F(IntrusiveListIteratorTest, begin_end_backward) {
TestBackward(list_.begin(), list_.end(), {3, 2, 1});
TestBackward(clist_.begin(), clist_.end(), {3, 2, 1});
}
TEST_F(IntrusiveListIteratorTest, rbegin_rend_backward) {
TestBackward(list_.rbegin(), list_.rend(), {1, 2, 3});
TestBackward(clist_.rbegin(), clist_.rend(), {1, 2, 3});
}
TEST_F(IntrusiveListIteratorTest, cbegin_cend_backward) {
TestBackward(list_.cbegin(), list_.cend(), {3, 2, 1});
TestBackward(clist_.cbegin(), clist_.cend(), {3, 2, 1});
}
TEST_F(IntrusiveListIteratorTest, crbegin_crend_backward) {
TestBackward(list_.crbegin(), list_.crend(), {1, 2, 3});
TestBackward(clist_.crbegin(), clist_.crend(), {1, 2, 3});
}
TEST_F(IntrusiveListTest, size_empty) {
TestObjectList list;
ASSERT_EQ(0U, list.size());
ASSERT_TRUE(list.empty());
list.emplace_back(1);
ASSERT_EQ(1U, list.size());
ASSERT_FALSE(list.empty());
}
TEST_F(IntrusiveListTest, front_back) {
TestObjectList list;
list.emplace_back(1);
ASSERT_EQ(1, list.front().data);
ASSERT_EQ(1, list.back().data);
list.emplace_back(2);
ASSERT_EQ(1, list.front().data);
ASSERT_EQ(2, list.back().data);
const TestObjectList& clist = list;
ASSERT_EQ(1, clist.front().data);
ASSERT_EQ(2, clist.back().data);
}
TEST_F(IntrusiveListTest, emplace_front) {
TestObjectList list;
// Pass an additional arg to show that forwarding works properly.
list.emplace_front(1, 100);
list.emplace_front(2, 200);
list.emplace_front(3, 300);
list.emplace_front(4, 400);
AssertListEq(list, {4, 3, 2, 1}, {400, 300, 200, 100});
}
TEST_F(IntrusiveListTest, emplace_back) {
TestObjectList list;
// Pass an additional arg to show that forwarding works properly.
list.emplace_back(1, 100);
list.emplace_back(2, 200);
list.emplace_back(3, 300);
list.emplace_back(4, 400);
AssertListEq(list, {1, 2, 3, 4}, {100, 200, 300, 400});
}
TEST_F(IntrusiveListTest, push_front_pointer) {
TestObjectList list;
list.push_front(MakeUnique<TestObject>(1));
list.push_front(MakeUnique<TestObject>(2));
list.push_front(MakeUnique<TestObject>(3));
AssertListEq(list, {3, 2, 1});
}
TEST_F(IntrusiveListTest, push_back_pointer) {
TestObjectList list;
list.push_back(MakeUnique<TestObject>(1));
list.push_back(MakeUnique<TestObject>(2));
list.push_back(MakeUnique<TestObject>(3));
AssertListEq(list, {1, 2, 3});
}
TEST_F(IntrusiveListTest, push_front_move) {
TestObjectList list;
list.push_front(TestObject(1));
list.push_front(TestObject(2));
list.push_front(TestObject(3));
AssertListEq(list, {3, 2, 1});
}
TEST_F(IntrusiveListTest, push_back_move) {
TestObjectList list;
list.push_back(TestObject(1));
list.push_back(TestObject(2));
list.push_back(TestObject(3));
AssertListEq(list, {1, 2, 3});
}
TEST_F(IntrusiveListTest, pop_front) {
TestObjectList list = NewList({1, 2, 3, 4});
list.pop_front();
AssertListEq(list, {2, 3, 4});
list.pop_front();
AssertListEq(list, {3, 4});
list.pop_front();
AssertListEq(list, {4});
list.pop_front();
AssertListEq(list, {});
}
TEST_F(IntrusiveListTest, pop_back) {
TestObjectList list = NewList({1, 2, 3, 4});
list.pop_back();
AssertListEq(list, {1, 2, 3});
list.pop_back();
AssertListEq(list, {1, 2});
list.pop_back();
AssertListEq(list, {1});
list.pop_back();
AssertListEq(list, {});
}
TEST_F(IntrusiveListTest, extract_front) {
TestObjectList list = NewList({1, 2, 3});
std::unique_ptr<TestObject> t1(list.extract_front());
ASSERT_EQ(1, t1->data);
AssertListEq(list, {2, 3});
std::unique_ptr<TestObject> t2(list.extract_front());
ASSERT_EQ(2, t2->data);
AssertListEq(list, {3});
std::unique_ptr<TestObject> t3(list.extract_front());
ASSERT_EQ(3, t3->data);
AssertListEq(list, {});
}
TEST_F(IntrusiveListTest, extract_back) {
TestObjectList list = NewList({1, 2, 3});
std::unique_ptr<TestObject> t1(list.extract_back());
ASSERT_EQ(3, t1->data);
AssertListEq(list, {1, 2});
std::unique_ptr<TestObject> t2(list.extract_back());
ASSERT_EQ(2, t2->data);
AssertListEq(list, {1});
std::unique_ptr<TestObject> t3(list.extract_back());
ASSERT_EQ(1, t3->data);
AssertListEq(list, {});
}
TEST_F(IntrusiveListTest, emplace) {
TestObjectList list;
// Pass an additional arg to show that forwarding works properly.
list.emplace(list.begin(), 2, 200);
list.emplace(list.end(), 4, 400);
list.emplace(std::next(list.begin()), 3, 300);
list.emplace(list.begin(), 1, 100);
AssertListEq(list, {1, 2, 3, 4}, {100, 200, 300, 400});
}
TEST_F(IntrusiveListTest, insert_pointer) {
TestObjectList list;
list.insert(list.begin(), MakeUnique<TestObject>(2));
list.insert(list.end(), MakeUnique<TestObject>(4));
list.insert(std::next(list.begin()), MakeUnique<TestObject>(3));
list.insert(list.begin(), MakeUnique<TestObject>(1));
AssertListEq(list, {1, 2, 3, 4});
}
TEST_F(IntrusiveListTest, insert_move) {
TestObjectList list;
list.insert(list.begin(), TestObject(2));
list.insert(list.end(), TestObject(4));
list.insert(std::next(list.begin()), TestObject(3));
list.insert(list.begin(), TestObject(1));
AssertListEq(list, {1, 2, 3, 4});
}
TEST_F(IntrusiveListTest, extract) {
TestObjectList list = NewList({1, 2, 3, 4});
TestObjectList::iterator t1_iter = std::next(list.begin(), 0);
TestObjectList::iterator t2_iter = std::next(list.begin(), 1);
TestObjectList::iterator t3_iter = std::next(list.begin(), 2);
TestObjectList::iterator t4_iter = std::next(list.begin(), 3);
std::unique_ptr<TestObject> t2(list.extract(t2_iter));
ASSERT_EQ(2, t2->data);
AssertListEq(list, {1, 3, 4});
std::unique_ptr<TestObject> t4(list.extract(t4_iter));
ASSERT_EQ(4, t4->data);
AssertListEq(list, {1, 3});
std::unique_ptr<TestObject> t1(list.extract(t1_iter));
ASSERT_EQ(1, t1->data);
AssertListEq(list, {3});
std::unique_ptr<TestObject> t3(list.extract(t3_iter));
ASSERT_EQ(3, t3->data);
AssertListEq(list, {});
}
TEST_F(IntrusiveListTest, erase) {
TestObjectList list = NewList({1, 2, 3, 4});
TestObjectList::iterator t1_iter = std::next(list.begin(), 0);
TestObjectList::iterator t2_iter = std::next(list.begin(), 1);
TestObjectList::iterator t3_iter = std::next(list.begin(), 2);
TestObjectList::iterator t4_iter = std::next(list.begin(), 3);
// erase returns an iterator to the following node.
ASSERT_EQ(3, list.erase(t2_iter)->data);
AssertListEq(list, {1, 3, 4});
ASSERT_EQ(list.end(), list.erase(t4_iter));
AssertListEq(list, {1, 3});
ASSERT_EQ(3, list.erase(t1_iter)->data);
AssertListEq(list, {3});
ASSERT_EQ(list.end(), list.erase(t3_iter));
AssertListEq(list, {});
}
TEST_F(IntrusiveListTest, erase_range) {
TestObjectList list = NewList({1, 2, 3, 4, 5, 6});
// OK to erase an empty range.
list.erase(list.begin(), list.begin());
list.erase(list.end(), list.end());
// Erase the first element (1).
list.erase(list.begin(), std::next(list.begin()));
AssertListEq(list, {2, 3, 4, 5, 6});
// Erase the last element (6).
list.erase(std::prev(list.end()), list.end());
AssertListEq(list, {2, 3, 4, 5});
// Erase [3, 4] => [2, 5]
list.erase(std::next(list.begin()), std::prev(list.end()));
AssertListEq(list, {2, 5});
// Erase the rest.
list.erase(list.begin(), list.end());
AssertListEq(list, {});
}
TEST_F(IntrusiveListTest, swap) {
TestObjectList list1 = NewList({1, 2, 3, 4});
TestObjectList list2 = NewList({100, 200, 300});
AssertListEq(list1, {1, 2, 3, 4});
AssertListEq(list2, {100, 200, 300});
list1.swap(list2);
AssertListEq(list1, {100, 200, 300});
AssertListEq(list2, {1, 2, 3, 4});
}
TEST_F(IntrusiveListTest, clear) {
TestObjectList list = NewList({1, 2, 3, 4});
ASSERT_FALSE(list.empty());
list.clear();
ASSERT_EQ(0U, list.size());
ASSERT_TRUE(list.empty());
}
TEST_F(IntrusiveListTest, splice_list) {
TestObjectList list1 = NewList({1, 2, 3});
// Splice at beginning.
TestObjectList list2 = NewList({100, 200});
list1.splice(list1.begin(), list2);
AssertListEq(list1, {100, 200, 1, 2, 3});
AssertListEq(list2, {});
// Splice at end.
TestObjectList list3 = NewList({500, 600, 700});
list1.splice(list1.end(), list3);
AssertListEq(list1, {100, 200, 1, 2, 3, 500, 600, 700});
AssertListEq(list3, {});
// Splice in the middle.
TestObjectList list4 = NewList({400});
list1.splice(std::next(list1.begin(), 4), list4);
AssertListEq(list1, {100, 200, 1, 2, 400, 3, 500, 600, 700});
AssertListEq(list4, {});
}
TEST_F(IntrusiveListTest, splice_list_move) {
TestObjectList list1 = NewList({1, 2, 3});
// Splice at beginning.
list1.splice(list1.begin(), NewList({100, 200}));
AssertListEq(list1, {100, 200, 1, 2, 3});
// Splice at end.
list1.splice(list1.end(), NewList({500, 600, 700}));
AssertListEq(list1, {100, 200, 1, 2, 3, 500, 600, 700});
// Splice in the middle.
list1.splice(std::next(list1.begin(), 4), NewList({400}));
AssertListEq(list1, {100, 200, 1, 2, 400, 3, 500, 600, 700});
}
TEST_F(IntrusiveListTest, splice_node) {
TestObjectList list1 = NewList({1, 2, 3});
// Splice at beginning.
TestObjectList list2 = NewList({100, 200});
list1.splice(list1.begin(), list2, list2.begin());
AssertListEq(list1, {100, 1, 2, 3});
AssertListEq(list2, {200});
// Splice at end.
TestObjectList list3 = NewList({500, 600, 700});
list1.splice(list1.end(), list3, std::next(list3.begin(), 2));
AssertListEq(list1, {100, 1, 2, 3, 700});
AssertListEq(list3, {500, 600});
// Splice in the middle.
TestObjectList list4 = NewList({400});
list1.splice(std::next(list1.begin(), 3), list4, list4.begin());
AssertListEq(list1, {100, 1, 2, 400, 3, 700});
AssertListEq(list4, {});
}
TEST_F(IntrusiveListTest, splice_range) {
TestObjectList list1 = NewList({1, 2, 3});
// Splice at beginning.
TestObjectList list2 = NewList({100, 200, 300});
list1.splice(list1.begin(), list2, list2.begin(), std::prev(list2.end()));
AssertListEq(list1, {100, 200, 1, 2, 3});
AssertListEq(list2, {300});
// Splice at end.
TestObjectList list3 = NewList({500, 600, 700});
list1.splice(list1.end(), list3, std::next(list3.begin()), list3.end());
AssertListEq(list1, {100, 200, 1, 2, 3, 600, 700});
AssertListEq(list3, {500});
// Splice in the middle.
TestObjectList list4 = NewList({400});
list1.splice(std::next(list1.begin(), 4), list4, list4.begin(), list4.end());
AssertListEq(list1, {100, 200, 1, 2, 400, 3, 600, 700});
AssertListEq(list4, {});
}

838
third_party/wasm2c/src/test-literal.cc vendored Normal file
View File

@@ -0,0 +1,838 @@
/*
* Copyright 2018 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <cassert>
#include <cstdio>
#include <thread>
#include <vector>
#include "gtest/gtest.h"
#include "src/literal.h"
using namespace wabt;
namespace {
enum ParseIntTypeCombo {
UnsignedOnly,
SignedAndUnsigned,
Both,
};
template <typename T, typename F>
void AssertIntEquals(T expected,
const char* s,
F&& parse_int,
ParseIntTypeCombo parse_type = Both) {
const char* const end = s + strlen(s);
T actual;
if (parse_type == UnsignedOnly || parse_type == Both) {
ASSERT_EQ(Result::Ok,
parse_int(s, end, &actual, ParseIntType::UnsignedOnly))
<< s;
ASSERT_EQ(expected, actual);
} else {
ASSERT_EQ(Result::Error,
parse_int(s, end, &actual, ParseIntType::UnsignedOnly))
<< s;
}
if (parse_type == SignedAndUnsigned || parse_type == Both) {
ASSERT_EQ(Result::Ok,
parse_int(s, end, &actual, ParseIntType::SignedAndUnsigned))
<< s;
ASSERT_EQ(expected, actual);
} else {
ASSERT_EQ(Result::Error,
parse_int(s, end, &actual, ParseIntType::SignedAndUnsigned))
<< s;
}
}
void AssertInt8Equals(uint8_t expected,
const char* s,
ParseIntTypeCombo parse_type = Both) {
AssertIntEquals(expected, s, ParseInt8, parse_type);
}
void AssertInt16Equals(uint16_t expected,
const char* s,
ParseIntTypeCombo parse_type = Both) {
AssertIntEquals(expected, s, ParseInt16, parse_type);
}
void AssertInt32Equals(uint32_t expected,
const char* s,
ParseIntTypeCombo parse_type = Both) {
AssertIntEquals(expected, s, ParseInt32, parse_type);
}
void AssertInt64Equals(uint64_t expected,
const char* s,
ParseIntTypeCombo parse_type = Both) {
AssertIntEquals(expected, s, ParseInt64, parse_type);
}
void AssertUint128Equals(v128 expected,
const char* s) {
const char* const end = s + strlen(s);
v128 actual;
ASSERT_EQ(Result::Ok, ParseUint128(s, end, &actual)) << s;
ASSERT_EQ(expected, actual);
}
void AssertInt8Fails(const char* s) {
const char* const end = s + strlen(s);
uint8_t actual;
ASSERT_EQ(Result::Error,
ParseInt8(s, end, &actual, ParseIntType::SignedAndUnsigned))
<< s;
ASSERT_EQ(Result::Error,
ParseInt8(s, end, &actual, ParseIntType::UnsignedOnly))
<< s;
}
void AssertInt16Fails(const char* s) {
const char* const end = s + strlen(s);
uint16_t actual;
ASSERT_EQ(Result::Error,
ParseInt16(s, end, &actual, ParseIntType::SignedAndUnsigned))
<< s;
ASSERT_EQ(Result::Error,
ParseInt16(s, end, &actual, ParseIntType::UnsignedOnly))
<< s;
}
void AssertInt32Fails(const char* s) {
const char* const end = s + strlen(s);
uint32_t actual;
ASSERT_EQ(Result::Error,
ParseInt32(s, end, &actual, ParseIntType::SignedAndUnsigned))
<< s;
ASSERT_EQ(Result::Error,
ParseInt32(s, end, &actual, ParseIntType::UnsignedOnly))
<< s;
}
void AssertInt64Fails(const char* s) {
const char* const end = s + strlen(s);
uint64_t actual;
ASSERT_EQ(Result::Error,
ParseInt64(s, end, &actual, ParseIntType::SignedAndUnsigned))
<< s;
ASSERT_EQ(Result::Error,
ParseInt64(s, end, &actual, ParseIntType::UnsignedOnly))
<< s;
}
void AssertUint64Equals(uint64_t expected, const char* s) {
uint64_t actual;
ASSERT_EQ(Result::Ok, ParseUint64(s, s + strlen(s), &actual)) << s;
ASSERT_EQ(expected, actual);
}
void AssertUint64Fails(const char* s) {
uint64_t actual_bits;
ASSERT_EQ(Result::Error, ParseUint64(s, s + strlen(s), &actual_bits)) << s;
}
void AssertUint128Fails(const char* s) {
v128 actual;
ASSERT_EQ(Result::Error, ParseUint128(s, s + strlen(s), &actual)) << s;
}
void AssertHexFloatEquals(uint32_t expected_bits, const char* s) {
uint32_t actual_bits;
ASSERT_EQ(Result::Ok,
ParseFloat(LiteralType::Hexfloat, s, s + strlen(s), &actual_bits))
<< s;
ASSERT_EQ(expected_bits, actual_bits) << s;
}
void AssertHexFloatFails(const char* s) {
uint32_t actual_bits;
ASSERT_EQ(Result::Error,
ParseFloat(LiteralType::Hexfloat, s, s + strlen(s), &actual_bits))
<< s;
}
void AssertHexDoubleEquals(uint64_t expected_bits, const char* s) {
uint64_t actual_bits;
ASSERT_EQ(Result::Ok,
ParseDouble(LiteralType::Hexfloat, s, s + strlen(s), &actual_bits))
<< s;
ASSERT_EQ(expected_bits, actual_bits);
}
void AssertHexDoubleFails(const char* s) {
uint64_t actual_bits;
ASSERT_EQ(Result::Error,
ParseDouble(LiteralType::Hexfloat, s, s + strlen(s), &actual_bits))
<< s;
}
} // end anonymous namespace
TEST(ParseInt8, Both) {
AssertInt8Equals(0, "0");
AssertInt8Equals(100, "100");
AssertInt8Equals(123, "123");
AssertInt8Equals(127, "127");
AssertInt8Equals(255, "255");
AssertInt8Equals(0xca, "0xca");
AssertInt8Equals(0x7f, "0x7f");
AssertInt8Equals(0x80, "0x80");
AssertInt8Equals(0xff, "0xff");
}
TEST(ParseInt8, SignedAndUnsigned) {
AssertInt8Equals(128, "-128", SignedAndUnsigned);
AssertInt8Equals(-0x80, "-0x80", SignedAndUnsigned);
AssertInt8Equals(255, "-1", SignedAndUnsigned);
AssertInt8Equals(-1, "-0x1", SignedAndUnsigned);
AssertInt8Equals(1, "+1", SignedAndUnsigned);
AssertInt8Equals(-0x7b, "-0x7B", SignedAndUnsigned);
AssertInt8Equals(0xab, "+0xab", SignedAndUnsigned);
}
TEST(ParseInt8, Invalid) {
AssertInt8Fails("");
AssertInt8Fails("-100hello");
AssertInt8Fails("0XAB");
AssertInt8Fails("0xga");
AssertInt8Fails("two");
}
TEST(ParseInt8, Underscores) {
AssertInt8Equals(123, "12_3", Both);
AssertInt8Equals(123, "+12_3", SignedAndUnsigned);
AssertInt8Equals(-123, "-1_23", SignedAndUnsigned);
AssertInt8Equals(19, "1______9", Both);
AssertInt8Equals(0xab, "0xa_b", Both);
AssertInt8Equals(0xab, "+0xa_b", SignedAndUnsigned);
AssertInt8Equals(-0x7b, "-0x7_b", SignedAndUnsigned);
}
TEST(ParseInt8, Overflow) {
AssertInt8Fails("256");
AssertInt8Fails("-129");
AssertInt8Fails("0x100");
AssertInt8Fails("-0x81");
AssertInt8Fails("1231231231231231231231");
}
TEST(ParseInt16, Both) {
AssertInt16Equals(0, "0");
AssertInt16Equals(1000, "1000");
AssertInt16Equals(12345, "12345");
AssertInt16Equals(32767, "32767");
AssertInt16Equals(65535, "65535");
AssertInt16Equals(0xcafe, "0xcafe");
AssertInt16Equals(0x7fff, "0x7fff");
AssertInt16Equals(0x8000, "0x8000");
AssertInt16Equals(0xffff, "0xffff");
}
TEST(ParseInt16, SignedAndUnsigned) {
AssertInt16Equals(32768, "-32768", SignedAndUnsigned);
AssertInt16Equals(-0x8000, "-0x8000", SignedAndUnsigned);
AssertInt16Equals(65535, "-1", SignedAndUnsigned);
AssertInt16Equals(-1, "-0x1", SignedAndUnsigned);
AssertInt16Equals(1, "+1", SignedAndUnsigned);
AssertInt16Equals(-0x7bcd, "-0x7BCD", SignedAndUnsigned);
AssertInt16Equals(0xabcd, "+0xabcd", SignedAndUnsigned);
}
TEST(ParseInt16, Invalid) {
AssertInt16Fails("");
AssertInt16Fails("-100hello");
AssertInt16Fails("0XABCD");
AssertInt16Fails("0xgabb");
AssertInt16Fails("two");
}
TEST(ParseInt16, Underscores) {
AssertInt16Equals(12345, "12_345", Both);
AssertInt16Equals(12345, "+12_345", SignedAndUnsigned);
AssertInt16Equals(-12345, "-123_45", SignedAndUnsigned);
AssertInt16Equals(19, "1______9", Both);
AssertInt16Equals(0xabcd, "0xa_b_c_d", Both);
AssertInt16Equals(0xabcd, "+0xa_b_c_d", SignedAndUnsigned);
AssertInt16Equals(-0x7bcd, "-0x7_b_c_d", SignedAndUnsigned);
}
TEST(ParseInt16, Overflow) {
AssertInt16Fails("65536");
AssertInt16Fails("-32769");
AssertInt16Fails("0x10000");
AssertInt16Fails("-0x8001");
AssertInt16Fails("1231231231231231231231");
}
TEST(ParseInt32, Both) {
AssertInt32Equals(0, "0");
AssertInt32Equals(1000, "1000");
AssertInt32Equals(123456789, "123456789");
AssertInt32Equals(2147483647, "2147483647");
AssertInt32Equals(4294967295u, "4294967295");
AssertInt32Equals(0xcafef00du, "0xcafef00d");
AssertInt32Equals(0x7fffffff, "0x7fffffff");
AssertInt32Equals(0x80000000u, "0x80000000");
AssertInt32Equals(0xffffffffu, "0xffffffff");
}
TEST(ParseInt32, SignedAndUnsigned) {
AssertInt32Equals(2147483648, "-2147483648", SignedAndUnsigned);
AssertInt32Equals(-0x80000000u, "-0x80000000", SignedAndUnsigned);
AssertInt32Equals(4294967295u, "-1", SignedAndUnsigned);
AssertInt32Equals(-1, "-0x1", SignedAndUnsigned);
AssertInt32Equals(1, "+1", SignedAndUnsigned);
AssertInt32Equals(-0xabcd, "-0xABCD", SignedAndUnsigned);
AssertInt32Equals(0xabcd, "+0xabcd", SignedAndUnsigned);
}
TEST(ParseInt32, Invalid) {
AssertInt32Fails("");
AssertInt32Fails("-100hello");
AssertInt32Fails("0XABCDEF");
AssertInt32Fails("0xgabba");
AssertInt32Fails("two");
}
TEST(ParseInt32, Underscores) {
AssertInt32Equals(123456789, "12_345_6789", Both);
AssertInt32Equals(123456789, "+12_345_6789", SignedAndUnsigned);
AssertInt32Equals(-123456789, "-12345_6789", SignedAndUnsigned);
AssertInt32Equals(19, "1______9", Both);
AssertInt32Equals(0xabcd, "0xa_b_c_d", Both);
AssertInt32Equals(0xabcd, "+0xa_b_c_d", SignedAndUnsigned);
AssertInt32Equals(-0xabcd, "-0xa_b_c_d", SignedAndUnsigned);
}
TEST(ParseInt32, Overflow) {
AssertInt32Fails("4294967296");
AssertInt32Fails("-2147483649");
AssertInt32Fails("0x100000000");
AssertInt32Fails("-0x80000001");
AssertInt32Fails("1231231231231231231231");
}
TEST(ParseInt64, Both) {
AssertInt64Equals(0, "0");
AssertInt64Equals(1000, "1000");
AssertInt64Equals(123456789, "123456789");
AssertInt64Equals(9223372036854775807ull, "9223372036854775807");
AssertInt64Equals(18446744073709551615ull, "18446744073709551615");
AssertInt64Equals(0x7fffffffffffffffull, "0x7fffffffffffffff");
AssertInt64Equals(0x8000000000000000ull, "0x8000000000000000");
AssertInt64Equals(0xffffffffffffffffull, "0xffffffffffffffff");
}
TEST(ParseInt64, SignedAndUnsigned) {
AssertInt64Equals(9223372036854775808ull, "-9223372036854775808",
SignedAndUnsigned);
AssertInt64Equals(18446744073709551615ull, "-1", SignedAndUnsigned);
AssertInt64Equals(-1, "-0x1", SignedAndUnsigned);
AssertInt64Equals(1, "+1", SignedAndUnsigned);
AssertInt64Equals(-0x0bcdefabcdefabcdull, "-0x0BCDEFABCDEFABCD",
SignedAndUnsigned);
AssertInt64Equals(0xabcdefabcdefabcdull, "+0xabcdefabcdefabcd",
SignedAndUnsigned);
}
TEST(ParseInt64, Invalid) {
AssertInt64Fails("");
AssertInt64Fails("-100hello");
AssertInt64Fails("0XABCDEF");
AssertInt64Fails("0xgabba");
AssertInt64Fails("two");
}
TEST(ParseInt64, Underscores) {
AssertInt64Equals(123456789, "12_345_6789", Both);
AssertInt64Equals(123456789, "+12_345_6789", SignedAndUnsigned);
AssertInt64Equals(-123456789, "-12345_6789", SignedAndUnsigned);
AssertInt64Equals(19, "1______9", Both);
AssertInt64Equals(0xabcd, "0xa_b_c_d", Both);
AssertInt64Equals(0xabcd, "+0xa_b_c_d", SignedAndUnsigned);
AssertInt64Equals(-0xabcd, "-0xa_b_c_d", SignedAndUnsigned);
}
TEST(ParseInt64, Overflow) {
AssertInt64Fails("18446744073709551616");
AssertInt64Fails("-9223372036854775809");
AssertInt32Fails("0x10000000000000000");
AssertInt32Fails("-0x80000000000000001");
AssertInt64Fails("1231231231231231231231");
}
TEST(ParseUint64, Basic) {
AssertUint64Equals(0, "0");
AssertUint64Equals(1000, "1000");
AssertUint64Equals(123456789, "123456789");
AssertUint64Equals(1844674407370955161ull, "1844674407370955161");
AssertUint64Equals(18446744073709551615ull, "18446744073709551615");
AssertUint64Equals(0, "0x0");
AssertUint64Equals(0x1000, "0x1000");
AssertUint64Equals(0x123456789, "0x123456789");
AssertUint64Equals(0xabcdef, "0xabcdef");
AssertUint64Equals(0xffffffffffffffull, "0xffffffffffffff");
AssertUint64Equals(0xfffffffffffffffull, "0xfffffffffffffff");
AssertUint64Equals(0xabcdefabcdefabcdull, "0xabcdefabcdefabcd");
}
TEST(ParseUint64, NoOctal) {
AssertUint64Equals(100, "0100");
AssertUint64Equals(888, "0000888");
}
TEST(ParseUint64, Invalid) {
AssertUint64Fails("");
AssertUint64Fails("-100");
AssertUint64Fails("0XABCDEF");
AssertUint64Fails("0xgabba");
AssertUint64Fails("two");
}
TEST(ParseUint64, Underscores) {
AssertUint64Equals(123456789, "12_345_6789");
AssertUint64Equals(19, "1______9");
AssertUint64Equals(0xabcd, "0xa_b_c_d");
}
TEST(ParseUint64, Overflow) {
AssertUint64Fails("0x10000000000000000");
AssertUint64Fails("18446744073709551616");
AssertUint64Fails("62857453058642199420");
AssertUint64Fails("82000999361882825820");
AssertUint64Fails("126539114687237086210");
AssertUint64Fails("10000000000000000000000000000000000000000");
}
TEST(ParseUint128, Basic) {
AssertUint128Equals({0, 0, 0, 0}, "0");
AssertUint128Equals({1, 0, 0, 0}, "1");
AssertUint128Equals({0x100f0e0d, 0x0c0b0a09, 0x08070605, 0x04030201},
"5332529520247008778714484145835150861");
AssertUint128Equals({0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff},
"340282366920938463463374607431768211455");
AssertUint128Equals({0, 0, 1, 0}, "18446744073709551616");
}
TEST(ParseUint128, Invalid) {
AssertUint128Fails("");
AssertUint128Fails("-1");
AssertUint128Fails("340282366920938463463374607431768211456");
AssertUint128Fails("123a456");
}
TEST(ParseFloat, NonCanonical) {
AssertHexFloatEquals(0x3f800000, "0x00000000000000000000001.0p0");
AssertHexFloatEquals(0x3f800000, "0x1.00000000000000000000000p0");
AssertHexFloatEquals(0x3f800000, "0x0.0000000000000000000001p88");
}
TEST(ParseFloat, Basic) {
AssertHexFloatEquals(0, "0x0p0");
AssertHexFloatEquals(0x3f800000, "0x1");
}
TEST(ParseFloat, Rounding) {
// |------- 23 bits -----| V-- extra bit
//
// 11111111111111111111101 0 ==> no rounding
AssertHexFloatEquals(0x7f7ffffd, "0x1.fffffap127");
// 11111111111111111111101 1 ==> round up
AssertHexFloatEquals(0x7f7ffffe, "0x1.fffffbp127");
// 11111111111111111111110 0 ==> no rounding
AssertHexFloatEquals(0x7f7ffffe, "0x1.fffffcp127");
// 11111111111111111111110 1 ==> round down
AssertHexFloatEquals(0x7f7ffffe, "0x1.fffffdp127");
// 11111111111111111111111 0 ==> no rounding
AssertHexFloatEquals(0x7f7fffff, "0x1.fffffep127");
}
// Duplicate the spec tests here for easier debugging.
TEST(ParseFloat, RoundingSpec) {
static const struct {
const char* input;
uint32_t output;
} kTests[] = {
{"+0x1.00000100000000000p-50", 0x26800000},
{"-0x1.00000100000000000p-50", 0xa6800000},
{"+0x1.00000100000000001p-50", 0x26800001},
{"-0x1.00000100000000001p-50", 0xa6800001},
{"+0x1.000001fffffffffffp-50", 0x26800001},
{"-0x1.000001fffffffffffp-50", 0xa6800001},
{"+0x1.00000200000000000p-50", 0x26800001},
{"-0x1.00000200000000000p-50", 0xa6800001},
{"+0x1.00000200000000001p-50", 0x26800001},
{"-0x1.00000200000000001p-50", 0xa6800001},
{"+0x1.000002fffffffffffp-50", 0x26800001},
{"-0x1.000002fffffffffffp-50", 0xa6800001},
{"+0x1.00000300000000000p-50", 0x26800002},
{"-0x1.00000300000000000p-50", 0xa6800002},
{"+0x1.00000300000000001p-50", 0x26800002},
{"-0x1.00000300000000001p-50", 0xa6800002},
{"+0x1.000003fffffffffffp-50", 0x26800002},
{"-0x1.000003fffffffffffp-50", 0xa6800002},
{"+0x1.00000400000000000p-50", 0x26800002},
{"-0x1.00000400000000000p-50", 0xa6800002},
{"+0x1.00000400000000001p-50", 0x26800002},
{"-0x1.00000400000000001p-50", 0xa6800002},
{"+0x1.000004fffffffffffp-50", 0x26800002},
{"-0x1.000004fffffffffffp-50", 0xa6800002},
{"+0x1.00000500000000000p-50", 0x26800002},
{"-0x1.00000500000000000p-50", 0xa6800002},
{"+0x1.00000500000000001p-50", 0x26800003},
{"-0x1.00000500000000001p-50", 0xa6800003},
{"+0x4000.004000000p-64", 0x26800000},
{"-0x4000.004000000p-64", 0xa6800000},
{"+0x4000.004000001p-64", 0x26800001},
{"-0x4000.004000001p-64", 0xa6800001},
{"+0x4000.007ffffffp-64", 0x26800001},
{"-0x4000.007ffffffp-64", 0xa6800001},
{"+0x4000.008000000p-64", 0x26800001},
{"-0x4000.008000000p-64", 0xa6800001},
{"+0x4000.008000001p-64", 0x26800001},
{"-0x4000.008000001p-64", 0xa6800001},
{"+0x4000.00bffffffp-64", 0x26800001},
{"-0x4000.00bffffffp-64", 0xa6800001},
{"+0x4000.00c000000p-64", 0x26800002},
{"-0x4000.00c000000p-64", 0xa6800002},
{"+0x4000.00c000001p-64", 0x26800002},
{"-0x4000.00c000001p-64", 0xa6800002},
{"+0x4000.00fffffffp-64", 0x26800002},
{"-0x4000.00fffffffp-64", 0xa6800002},
{"+0x4000.010000001p-64", 0x26800002},
{"-0x4000.010000001p-64", 0xa6800002},
{"+0x4000.013ffffffp-64", 0x26800002},
{"-0x4000.013ffffffp-64", 0xa6800002},
{"+0x4000.014000001p-64", 0x26800003},
{"-0x4000.014000001p-64", 0xa6800003},
{"+0x1.00000100000000000p+50", 0x58800000},
{"-0x1.00000100000000000p+50", 0xd8800000},
{"+0x1.00000100000000001p+50", 0x58800001},
{"-0x1.00000100000000001p+50", 0xd8800001},
{"+0x1.000001fffffffffffp+50", 0x58800001},
{"-0x1.000001fffffffffffp+50", 0xd8800001},
{"+0x1.00000200000000000p+50", 0x58800001},
{"-0x1.00000200000000000p+50", 0xd8800001},
{"+0x1.00000200000000001p+50", 0x58800001},
{"-0x1.00000200000000001p+50", 0xd8800001},
{"+0x1.000002fffffffffffp+50", 0x58800001},
{"-0x1.000002fffffffffffp+50", 0xd8800001},
{"+0x1.00000300000000000p+50", 0x58800002},
{"-0x1.00000300000000000p+50", 0xd8800002},
{"+0x1.00000300000000001p+50", 0x58800002},
{"-0x1.00000300000000001p+50", 0xd8800002},
{"+0x1.000003fffffffffffp+50", 0x58800002},
{"-0x1.000003fffffffffffp+50", 0xd8800002},
{"+0x1.00000400000000000p+50", 0x58800002},
{"-0x1.00000400000000000p+50", 0xd8800002},
{"+0x1.00000400000000001p+50", 0x58800002},
{"-0x1.00000400000000001p+50", 0xd8800002},
{"+0x1.000004fffffffffffp+50", 0x58800002},
{"-0x1.000004fffffffffffp+50", 0xd8800002},
{"+0x1.00000500000000000p+50", 0x58800002},
{"-0x1.00000500000000000p+50", 0xd8800002},
{"+0x1.00000500000000001p+50", 0x58800003},
{"-0x1.00000500000000001p+50", 0xd8800003},
{"+0x4000004000000", 0x58800000},
{"-0x4000004000000", 0xd8800000},
{"+0x4000004000001", 0x58800001},
{"-0x4000004000001", 0xd8800001},
{"+0x4000007ffffff", 0x58800001},
{"-0x4000007ffffff", 0xd8800001},
{"+0x4000008000000", 0x58800001},
{"-0x4000008000000", 0xd8800001},
{"+0x4000008000001", 0x58800001},
{"-0x4000008000001", 0xd8800001},
{"+0x400000bffffff", 0x58800001},
{"-0x400000bffffff", 0xd8800001},
{"+0x400000c000000", 0x58800002},
{"-0x400000c000000", 0xd8800002},
{"+0x0.00000100000000000p-126", 0x0},
{"-0x0.00000100000000000p-126", 0x80000000},
{"+0x0.00000100000000001p-126", 0x1},
{"-0x0.00000100000000001p-126", 0x80000001},
{"+0x0.00000101000000000p-126", 0x1},
{"+0x0.000001fffffffffffp-126", 0x1},
{"-0x0.000001fffffffffffp-126", 0x80000001},
{"+0x0.00000200000000000p-126", 0x1},
{"-0x0.00000200000000000p-126", 0x80000001},
{"+0x0.00000200000000001p-126", 0x1},
{"-0x0.00000200000000001p-126", 0x80000001},
{"+0x0.000002fffffffffffp-126", 0x1},
{"-0x0.000002fffffffffffp-126", 0x80000001},
{"+0x0.00000300000000000p-126", 0x2},
{"-0x0.00000300000000000p-126", 0x80000002},
{"+0x0.00000300000000001p-126", 0x2},
{"-0x0.00000300000000001p-126", 0x80000002},
{"+0x0.000003fffffffffffp-126", 0x2},
{"-0x0.000003fffffffffffp-126", 0x80000002},
{"+0x0.00000400000000000p-126", 0x2},
{"-0x0.00000400000000000p-126", 0x80000002},
{"+0x0.00000400000000001p-126", 0x2},
{"-0x0.00000400000000001p-126", 0x80000002},
{"+0x0.000004fffffffffffp-126", 0x2},
{"-0x0.000004fffffffffffp-126", 0x80000002},
{"+0x0.00000500000000000p-126", 0x2},
{"-0x0.00000500000000000p-126", 0x80000002},
{"+0x0.00000500000000001p-126", 0x3},
{"-0x0.00000500000000001p-126", 0x80000003},
{"+0x1.fffffe8p127", 0x7f7fffff},
{"-0x1.fffffe8p127", 0xff7fffff},
{"+0x1.fffffefffffff8p127", 0x7f7fffff},
{"-0x1.fffffefffffff8p127", 0xff7fffff},
{"+0x1.fffffefffffffffffp127", 0x7f7fffff},
{"-0x1.fffffefffffffffffp127", 0xff7fffff},
};
for (auto test: kTests) {
AssertHexFloatEquals(test.output, test.input);
}
}
TEST(ParseFloat, OutOfRange) {
AssertHexFloatFails("0x1p128");
AssertHexFloatFails("-0x1p128");
AssertHexFloatFails("0x1.ffffffp127");
AssertHexFloatFails("-0x1.ffffffp127");
}
TEST(ParseDouble, NonCanonical) {
AssertHexDoubleEquals(0x3ff0000000000000, "0x00000000000000000000001.0p0");
AssertHexDoubleEquals(0x3ff0000000000000, "0x1.00000000000000000000000p0");
AssertHexDoubleEquals(0x3ff0000000000000, "0x0.0000000000000000000001p88");
}
TEST(ParseDouble, Rounding) {
// |-------------------- 52 bits ---------------------| V-- extra bit
//
// 1111111111111111111111111111111111111111111111111101 0 ==> no rounding
AssertHexDoubleEquals(0x7feffffffffffffd, "0x1.ffffffffffffd0p1023");
// 1111111111111111111111111111111111111111111111111101 1 ==> round up
AssertHexDoubleEquals(0x7feffffffffffffe, "0x1.ffffffffffffd8p1023");
// 1111111111111111111111111111111111111111111111111110 0 ==> no rounding
AssertHexDoubleEquals(0x7feffffffffffffe, "0x1.ffffffffffffe0p1023");
// 1111111111111111111111111111111111111111111111111110 1 ==> round down
AssertHexDoubleEquals(0x7feffffffffffffe, "0x1.ffffffffffffe8p1023");
// 1111111111111111111111111111111111111111111111111111 0 ==> no rounding
AssertHexDoubleEquals(0x7fefffffffffffff, "0x1.fffffffffffff0p1023");
}
TEST(ParseDouble, OutOfRange) {
AssertHexDoubleFails("0x1p1024");
AssertHexDoubleFails("-0x1p1024");
AssertHexDoubleFails("0x1.fffffffffffff8p1023");
AssertHexDoubleFails("-0x1.fffffffffffff8p1023");
}
// Duplicate the spec tests here for easier debugging.
TEST(ParseDouble, RoundingSpec) {
static const struct {
const char* input;
uint64_t output;
} kTests[] = {
{"+0x1.000000000000080000000000p-600", 1905022642377719808ull},
{"-0x1.000000000000080000000000p-600", 11128394679232495616ull},
{"+0x1.000000000000080000000001p-600", 1905022642377719809ull},
{"-0x1.000000000000080000000001p-600", 11128394679232495617ull},
{"+0x1.0000000000000fffffffffffp-600", 1905022642377719809ull},
{"-0x1.0000000000000fffffffffffp-600", 11128394679232495617ull},
{"+0x1.000000000000100000000000p-600", 1905022642377719809ull},
{"-0x1.000000000000100000000000p-600", 11128394679232495617ull},
{"+0x1.000000000000100000000001p-600", 1905022642377719809ull},
{"-0x1.000000000000100000000001p-600", 11128394679232495617ull},
{"+0x1.00000000000017ffffffffffp-600", 1905022642377719809ull},
{"-0x1.00000000000017ffffffffffp-600", 11128394679232495617ull},
{"+0x1.000000000000180000000000p-600", 1905022642377719810ull},
{"-0x1.000000000000180000000000p-600", 11128394679232495618ull},
{"+0x1.000000000000180000000001p-600", 1905022642377719810ull},
{"-0x1.000000000000180000000001p-600", 11128394679232495618ull},
{"+0x1.0000000000001fffffffffffp-600", 1905022642377719810ull},
{"-0x1.0000000000001fffffffffffp-600", 11128394679232495618ull},
{"+0x1.000000000000200000000000p-600", 1905022642377719810ull},
{"-0x1.000000000000200000000000p-600", 11128394679232495618ull},
{"+0x1.000000000000200000000001p-600", 1905022642377719810ull},
{"-0x1.000000000000200000000001p-600", 11128394679232495618ull},
{"+0x1.00000000000027ffffffffffp-600", 1905022642377719810ull},
{"-0x1.00000000000027ffffffffffp-600", 11128394679232495618ull},
{"+0x1.000000000000280000000001p-600", 1905022642377719811ull},
{"-0x1.000000000000280000000001p-600", 11128394679232495619ull},
{"+0x8000000.000000400000000000p-627", 1905022642377719808ull},
{"-0x8000000.000000400000000000p-627", 11128394679232495616ull},
{"+0x8000000.000000400000000001p-627", 1905022642377719809ull},
{"-0x8000000.000000400000000001p-627", 11128394679232495617ull},
{"+0x8000000.0000007fffffffffffp-627", 1905022642377719809ull},
{"-0x8000000.0000007fffffffffffp-627", 11128394679232495617ull},
{"+0x8000000.000000800000000000p-627", 1905022642377719809ull},
{"-0x8000000.000000800000000000p-627", 11128394679232495617ull},
{"+0x8000000.000000800000000001p-627", 1905022642377719809ull},
{"-0x8000000.000000800000000001p-627", 11128394679232495617ull},
{"+0x8000000.000000bfffffffffffp-627", 1905022642377719809ull},
{"-0x8000000.000000bfffffffffffp-627", 11128394679232495617ull},
{"+0x8000000.000000c00000000000p-627", 1905022642377719810ull},
{"-0x8000000.000000c00000000000p-627", 11128394679232495618ull},
{"+0x8000000.000000c00000000001p-627", 1905022642377719810ull},
{"-0x8000000.000000c00000000001p-627", 11128394679232495618ull},
{"+0x8000000.000000ffffffffffffp-627", 1905022642377719810ull},
{"-0x8000000.000000ffffffffffffp-627", 11128394679232495618ull},
{"+0x8000000.000001000000000000p-627", 1905022642377719810ull},
{"-0x8000000.000001000000000000p-627", 11128394679232495618ull},
{"+0x8000000.000001000000000001p-627", 1905022642377719810ull},
{"-0x8000000.000001000000000001p-627", 11128394679232495618ull},
{"+0x8000000.0000013fffffffffffp-627", 1905022642377719810ull},
{"-0x8000000.0000013fffffffffffp-627", 11128394679232495618ull},
{"+0x8000000.000001400000000001p-627", 1905022642377719811ull},
{"-0x8000000.000001400000000001p-627", 11128394679232495619ull},
{"+0x1.000000000000080000000000p+600", 7309342195222315008ull},
{"-0x1.000000000000080000000000p+600", 16532714232077090816ull},
{"+0x1.000000000000080000000001p+600", 7309342195222315009ull},
{"-0x1.000000000000080000000001p+600", 16532714232077090817ull},
{"+0x1.0000000000000fffffffffffp+600", 7309342195222315009ull},
{"-0x1.0000000000000fffffffffffp+600", 16532714232077090817ull},
{"+0x1.000000000000100000000000p+600", 7309342195222315009ull},
{"-0x1.000000000000100000000000p+600", 16532714232077090817ull},
{"+0x1.000000000000100000000001p+600", 7309342195222315009ull},
{"-0x1.000000000000100000000001p+600", 16532714232077090817ull},
{"+0x1.00000000000017ffffffffffp+600", 7309342195222315009ull},
{"-0x1.00000000000017ffffffffffp+600", 16532714232077090817ull},
{"+0x1.000000000000180000000000p+600", 7309342195222315010ull},
{"-0x1.000000000000180000000000p+600", 16532714232077090818ull},
{"+0x1.000000000000180000000001p+600", 7309342195222315010ull},
{"-0x1.000000000000180000000001p+600", 16532714232077090818ull},
{"+0x1.0000000000001fffffffffffp+600", 7309342195222315010ull},
{"-0x1.0000000000001fffffffffffp+600", 16532714232077090818ull},
{"+0x1.000000000000200000000000p+600", 7309342195222315010ull},
{"-0x1.000000000000200000000000p+600", 16532714232077090818ull},
{"+0x1.000000000000200000000001p+600", 7309342195222315010ull},
{"-0x1.000000000000200000000001p+600", 16532714232077090818ull},
{"+0x1.00000000000027ffffffffffp+600", 7309342195222315010ull},
{"-0x1.00000000000027ffffffffffp+600", 16532714232077090818ull},
{"+0x1.000000000000280000000000p+600", 7309342195222315010ull},
{"-0x1.000000000000280000000000p+600", 16532714232077090818ull},
{"+0x1.000000000000280000000001p+600", 7309342195222315011ull},
{"-0x1.000000000000280000000001p+600", 16532714232077090819ull},
{"+0x2000000000000100000000000", 5044031582654955520ull},
{"-0x2000000000000100000000000", 14267403619509731328ull},
{"+0x2000000000000100000000001", 5044031582654955521ull},
{"-0x2000000000000100000000001", 14267403619509731329ull},
{"+0x20000000000001fffffffffff", 5044031582654955521ull},
{"-0x20000000000001fffffffffff", 14267403619509731329ull},
{"+0x2000000000000200000000000", 5044031582654955521ull},
{"-0x2000000000000200000000000", 14267403619509731329ull},
{"+0x2000000000000200000000001", 5044031582654955521ull},
{"-0x2000000000000200000000001", 14267403619509731329ull},
{"+0x20000000000002fffffffffff", 5044031582654955521ull},
{"-0x20000000000002fffffffffff", 14267403619509731329ull},
{"+0x2000000000000300000000000", 5044031582654955522ull},
{"-0x2000000000000300000000000", 14267403619509731330ull},
{"+0x2000000000000300000000001", 5044031582654955522ull},
{"-0x2000000000000300000000001", 14267403619509731330ull},
{"+0x20000000000003fffffffffff", 5044031582654955522ull},
{"-0x20000000000003fffffffffff", 14267403619509731330ull},
{"+0x2000000000000400000000000", 5044031582654955522ull},
{"-0x2000000000000400000000000", 14267403619509731330ull},
{"+0x2000000000000400000000001", 5044031582654955522ull},
{"-0x2000000000000400000000001", 14267403619509731330ull},
{"+0x20000000000004fffffffffff", 5044031582654955522ull},
{"-0x20000000000004fffffffffff", 14267403619509731330ull},
{"+0x2000000000000500000000000", 5044031582654955522ull},
{"-0x2000000000000500000000000", 14267403619509731330ull},
{"+0x2000000000000500000000001", 5044031582654955523ull},
{"-0x2000000000000500000000001", 14267403619509731331ull},
{"+0x0.000000000000080000000000p-1022", 0ull},
{"-0x0.000000000000080000000000p-1022", 9223372036854775808ull},
{"+0x0.000000000000080000000001p-1022", 1ull},
{"-0x0.000000000000080000000001p-1022", 9223372036854775809ull},
{"+0x0.0000000000000fffffffffffp-1022", 1ull},
{"-0x0.0000000000000fffffffffffp-1022", 9223372036854775809ull},
{"+0x0.000000000000100000000000p-1022", 1ull},
{"-0x0.000000000000100000000000p-1022", 9223372036854775809ull},
{"+0x0.000000000000100000000001p-1022", 1ull},
{"-0x0.000000000000100000000001p-1022", 9223372036854775809ull},
{"+0x0.00000000000017ffffffffffp-1022", 1ull},
{"-0x0.00000000000017ffffffffffp-1022", 9223372036854775809ull},
{"+0x0.000000000000180000000000p-1022", 2ull},
{"-0x0.000000000000180000000000p-1022", 9223372036854775810ull},
{"+0x0.000000000000180000000001p-1022", 2ull},
{"-0x0.000000000000180000000001p-1022", 9223372036854775810ull},
{"+0x0.0000000000001fffffffffffp-1022", 2ull},
{"-0x0.0000000000001fffffffffffp-1022", 9223372036854775810ull},
{"+0x0.000000000000200000000000p-1022", 2ull},
{"-0x0.000000000000200000000000p-1022", 9223372036854775810ull},
{"+0x0.000000000000200000000001p-1022", 2ull},
{"-0x0.000000000000200000000001p-1022", 9223372036854775810ull},
{"+0x0.00000000000027ffffffffffp-1022", 2ull},
{"-0x0.00000000000027ffffffffffp-1022", 9223372036854775810ull},
{"+0x0.000000000000280000000000p-1022", 2ull},
{"-0x0.000000000000280000000000p-1022", 9223372036854775810ull},
{"+0x1.000000000000280000000001p-1022", 4503599627370499ull},
{"-0x1.000000000000280000000001p-1022", 9227875636482146307ull},
{"+0x1.fffffffffffff4p1023", 9218868437227405311ull},
{"-0x1.fffffffffffff4p1023", 18442240474082181119ull},
{"+0x1.fffffffffffff7ffffffp1023", 9218868437227405311ull},
{"-0x1.fffffffffffff7ffffffp1023", 18442240474082181119ull},
};
for (auto test: kTests) {
AssertHexDoubleEquals(test.output, test.input);
}
}
void AssertWriteUint128Equals(const v128& value, const std::string& expected) {
assert(expected.length() < 128);
char buffer[128];
WriteUint128(buffer, 128, value);
std::string actual(buffer, buffer + expected.length());
ASSERT_EQ(expected, actual);
ASSERT_EQ(buffer[expected.length()], '\0');
}
TEST(WriteUint128, Basic) {
AssertWriteUint128Equals({0, 0, 0, 0}, "0");
AssertWriteUint128Equals({1, 0, 0, 0}, "1");
AssertWriteUint128Equals({0x100f0e0d, 0x0c0b0a09, 0x08070605, 0x04030201},
"5332529520247008778714484145835150861");
AssertWriteUint128Equals({0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff},
"272314856204801878456120017448021860915");
AssertWriteUint128Equals({0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff},
"340282366920938463463374607431768211455");
AssertWriteUint128Equals({0, 0, 1, 0}, "18446744073709551616");
}
TEST(WriteUint128, BufferTooSmall) {
{
char buffer[20];
WriteUint128(buffer, 20, {0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff});
ASSERT_EQ(buffer[19], '\0');
std::string actual(buffer, buffer + 19);
ASSERT_EQ("3402823669209384634", actual);
}
{
char buffer[3];
WriteUint128(buffer, 3, {123, 0, 0, 0});
ASSERT_EQ(buffer[0], '1');
ASSERT_EQ(buffer[1], '2');
ASSERT_EQ(buffer[2], '\0');
}
}

View File

@@ -0,0 +1,181 @@
// Copyright 2019 WebAssembly Community Group participants
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "gtest/gtest.h"
#include <string>
#include "src/option-parser.h"
using namespace wabt;
#define ERROR_ENDING "\nTry '--help' for more information."
TEST(OptionParser, LongFlag) {
bool flag = false;
OptionParser parser("prog", "desc");
parser.AddOption("flag", "help", [&]() { flag = true; });
const char* args[] = {"prog name", "--flag"};
parser.Parse(2, const_cast<char**>(args));
EXPECT_EQ(true, flag);
}
TEST(OptionParser, ShortAndLongFlag) {
int count = 0;
OptionParser parser("prog", "desc");
parser.AddOption('f', "flag", "help", [&]() { ++count; });
const char* args[] = {"prog name", "-f", "--flag", "-f", "--flag"};
parser.Parse(5, const_cast<char**>(args));
EXPECT_EQ(4, count);
}
TEST(OptionParser, ShortFlagCombined) {
int count = 0;
OptionParser parser("prog", "desc");
parser.AddOption('a', "a", "help", [&]() { count += 1; });
parser.AddOption('b', "b", "help", [&]() { count += 2; });
const char* args[] = {"prog name", "-aa", "-abb"};
parser.Parse(3, const_cast<char**>(args));
EXPECT_EQ(7, count);
}
TEST(OptionParser, UnknownShortOption) {
std::string error;
OptionParser parser("prog", "desc");
parser.SetErrorCallback([&](const char* msg) { error = msg; });
const char* args[] = {"prog name", "-f"};
parser.Parse(2, const_cast<char**>(args));
EXPECT_EQ(error, "prog: unknown option '-f'" ERROR_ENDING);
}
TEST(OptionParser, UnknownLongOption) {
std::string error;
OptionParser parser("prog", "desc");
parser.SetErrorCallback([&](const char* msg) { error = msg; });
const char* args[] = {"prog name", "--foo"};
parser.Parse(2, const_cast<char**>(args));
EXPECT_EQ(error, "prog: unknown option '--foo'" ERROR_ENDING);
}
TEST(OptionParser, ShortAndLongParam) {
std::string param;
OptionParser parser("prog", "desc");
parser.AddOption('p', "param", "metavar", "help",
[&](const char* arg) { param += arg; });
const char* args[] = {"prog name", "-p", "h", "--param", "el", "--param=lo"};
parser.Parse(6, const_cast<char**>(args));
EXPECT_EQ("hello", param);
}
TEST(OptionParser, MissingParam) {
std::string error;
std::string param;
OptionParser parser("prog", "desc");
parser.SetErrorCallback([&](const char* msg) { error = msg; });
parser.AddOption('p', "param", "metavar", "help",
[&](const char* arg) { param = arg; });
const char* args[] = {"prog name", "--param"};
parser.Parse(2, const_cast<char**>(args));
EXPECT_EQ("", param);
EXPECT_EQ(error, "prog: option '--param' requires argument" ERROR_ENDING);
}
TEST(OptionParser, MissingArgument) {
std::string error;
OptionParser parser("prog", "desc");
parser.AddArgument("arg", OptionParser::ArgumentCount::One,
[&](const char* arg) {});
parser.SetErrorCallback([&](const char* msg) { error = msg; });
const char* args[] = {"prog name"};
parser.Parse(1, const_cast<char**>(args));
EXPECT_EQ(error, "prog: expected arg argument." ERROR_ENDING);
}
TEST(OptionParser, FlagCombinedAfterShortParam) {
std::string error;
std::string param;
bool has_x = false;
OptionParser parser("prog", "desc");
parser.SetErrorCallback([&](const char* msg) { error = msg; });
parser.AddOption('p', "p", "metavar", "help",
[&](const char* arg) { param = arg; });
parser.AddOption('x', "x", "help", [&]() { has_x = true; });
const char* args[] = {"prog name", "-px", "stuff"};
parser.Parse(3, const_cast<char**>(args));
EXPECT_EQ("", param);
EXPECT_TRUE(has_x);
EXPECT_EQ(error, "prog: unexpected argument 'stuff'" ERROR_ENDING);
}
TEST(OptionParser, OneArgument) {
std::string argument;
OptionParser parser("prog", "desc");
parser.AddArgument("arg", OptionParser::ArgumentCount::One,
[&](const char* arg) { argument = arg; });
const char* args[] = {"prog name", "hello"};
parser.Parse(2, const_cast<char**>(args));
EXPECT_EQ("hello", argument);
}
TEST(OptionParser, TooManyArguments) {
std::string error;
OptionParser parser("prog", "desc");
parser.SetErrorCallback([&](const char* msg) { error = msg; });
parser.AddArgument("arg", OptionParser::ArgumentCount::One,
[&](const char* arg) {});
const char* args[] = {"prog name", "hello", "goodbye"};
parser.Parse(3, const_cast<char**>(args));
EXPECT_EQ(error, "prog: unexpected argument 'goodbye'" ERROR_ENDING);
}
TEST(OptionParser, OneOrMoreArguments) {
std::string argument;
OptionParser parser("prog", "desc");
parser.AddArgument("arg", OptionParser::ArgumentCount::OneOrMore,
[&](const char* arg) { argument += arg; });
const char* args[] = {"prog name", "hello", "goodbye"};
parser.Parse(3, const_cast<char**>(args));
EXPECT_EQ("hellogoodbye", argument);
}
TEST(OptionParser, ZeroOrMoreArguments) {
std::string argument;
OptionParser parser("prog", "desc");
parser.AddArgument("arg", OptionParser::ArgumentCount::ZeroOrMore,
[&](const char* arg) { argument += arg; });
const char* args_none[] = {"prog name"};
parser.Parse(1, const_cast<char**>(args_none));
EXPECT_EQ("", argument);
const char* args_many[] = {"prog name", "hello", "goodbye"};
parser.Parse(3, const_cast<char**>(args_many));
EXPECT_EQ("hellogoodbye", argument);
}
TEST(OptionParser, StopProccessing) {
std::string argument;
bool has_x = false;
OptionParser parser("prog", "desc");
parser.AddArgument("arg", OptionParser::ArgumentCount::ZeroOrMore,
[&](const char* arg) { argument += arg; });
parser.AddOption('x', "x", "help", [&]() { has_x = true; });
const char* args_many[] = {"prog name", "-x", "--", "foo", "-x", "-y", "bar"};
parser.Parse(7, const_cast<char**>(args_many));
EXPECT_TRUE(has_x);
EXPECT_EQ("foo-x-ybar", argument);
}

View File

@@ -0,0 +1,415 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "gtest/gtest.h"
#include "src/string-view.h"
#include <cstring>
#include <functional>
using namespace wabt;
namespace {
void assert_string_view_eq(const char* s, string_view sv) {
size_t len = std::strlen(s);
ASSERT_EQ(len, sv.size());
for (size_t i = 0; i < len; ++i) {
ASSERT_EQ(s[i], sv[i]);
}
}
constexpr string_view::size_type npos = string_view::npos;
} // end anonymous namespace
TEST(string_view, default_constructor) {
assert_string_view_eq("", string_view());
}
TEST(string_view, copy_constructor) {
string_view sv1("copy");
assert_string_view_eq("copy", string_view(sv1));
string_view sv2;
assert_string_view_eq("", string_view(sv2));
}
TEST(string_view, assignment_operator) {
string_view sv1;
sv1 = string_view("assign");
assert_string_view_eq("assign", sv1);
string_view sv2;
sv2 = string_view();
assert_string_view_eq("", sv2);
}
TEST(string_view, string_constructor) {
assert_string_view_eq("", string_view(std::string()));
assert_string_view_eq("string", string_view(std::string("string")));
}
TEST(string_view, cstr_constructor) {
assert_string_view_eq("", string_view(""));
assert_string_view_eq("cstr", string_view("cstr"));
}
TEST(string_view, cstr_len_constructor) {
assert_string_view_eq("", string_view("foo-bar-baz", 0));
assert_string_view_eq("foo", string_view("foo-bar-baz", 3));
assert_string_view_eq("foo-bar", string_view("foo-bar-baz", 7));
}
TEST(string_view, begin_end) {
string_view sv("012345");
char count = 0;
for (auto iter = sv.begin(), end = sv.end(); iter != end; ++iter) {
ASSERT_EQ('0' + count, *iter);
++count;
}
ASSERT_EQ(6, count);
}
TEST(string_view, cbegin_cend) {
const string_view sv("012345");
char count = 0;
for (auto iter = sv.cbegin(), end = sv.cend(); iter != end; ++iter) {
ASSERT_EQ('0' + count, *iter);
++count;
}
ASSERT_EQ(6, count);
}
TEST(string_view, rbegin_rend) {
string_view sv("012345");
char count = 0;
for (auto iter = sv.rbegin(), end = sv.rend(); iter != end; ++iter) {
ASSERT_EQ('5' - count, *iter);
++count;
}
ASSERT_EQ(6, count);
}
TEST(string_view, crbegin_crend) {
const string_view sv("012345");
char count = 0;
for (auto iter = sv.crbegin(), end = sv.crend(); iter != end; ++iter) {
ASSERT_EQ('5' - count, *iter);
++count;
}
ASSERT_EQ(6, count);
}
TEST(string_view, size) {
string_view sv1;
ASSERT_EQ(0U, sv1.size());
string_view sv2("");
ASSERT_EQ(0U, sv2.size());
string_view sv3("hello");
ASSERT_EQ(5U, sv3.size());
}
TEST(string_view, length) {
string_view sv1;
ASSERT_EQ(0U, sv1.length());
string_view sv2("hello");
ASSERT_EQ(5U, sv2.length());
}
TEST(string_view, empty) {
string_view sv1;
ASSERT_TRUE(sv1.empty());
string_view sv2("bye");
ASSERT_FALSE(sv2.empty());
}
TEST(string_view, operator_bracket) {
string_view sv("words");
ASSERT_EQ('w', sv[0]);
ASSERT_EQ('o', sv[1]);
ASSERT_EQ('r', sv[2]);
ASSERT_EQ('d', sv[3]);
ASSERT_EQ('s', sv[4]);
}
TEST(string_view, at) {
string_view sv("words");
ASSERT_EQ('w', sv.at(0));
ASSERT_EQ('o', sv.at(1));
ASSERT_EQ('r', sv.at(2));
ASSERT_EQ('d', sv.at(3));
ASSERT_EQ('s', sv.at(4));
}
TEST(string_view, front) {
string_view sv("words");
ASSERT_EQ('w', sv.front());
}
TEST(string_view, back) {
string_view sv("words");
ASSERT_EQ('s', sv.back());
}
TEST(string_view, data) {
const char* cstr = "words";
string_view sv(cstr);
ASSERT_EQ(cstr, sv.data());
}
TEST(string_view, remove_prefix) {
string_view sv("words");
sv.remove_prefix(2);
assert_string_view_eq("rds", sv);
}
TEST(string_view, remove_suffix) {
string_view sv("words");
sv.remove_suffix(2);
assert_string_view_eq("wor", sv);
}
TEST(string_view, swap) {
string_view sv1("hello");
string_view sv2("bye");
sv1.swap(sv2);
assert_string_view_eq("bye", sv1);
assert_string_view_eq("hello", sv2);
}
TEST(string_view, operator_std_string) {
string_view sv1("hi");
std::string s(sv1);
ASSERT_EQ(2U, s.size());
ASSERT_EQ('h', s[0]);
ASSERT_EQ('i', s[1]);
}
TEST(string_view, copy) {
string_view sv("words");
char buffer[10] = {0};
sv.copy(buffer, 10, 2);
ASSERT_EQ('r', buffer[0]);
ASSERT_EQ('d', buffer[1]);
ASSERT_EQ('s', buffer[2]);
for (int i = 3; i < 10; ++i) {
ASSERT_EQ(0, buffer[i]);
}
}
TEST(string_view, substr) {
string_view sv1("abcdefghij");
string_view sv2 = sv1.substr(2, 3);
assert_string_view_eq("cde", sv2);
}
TEST(string_view, compare0) {
ASSERT_TRUE(string_view("meat").compare(string_view("meet")) < 0);
ASSERT_TRUE(string_view("rest").compare(string_view("rate")) > 0);
ASSERT_TRUE(string_view("equal").compare(string_view("equal")) == 0);
ASSERT_TRUE(string_view("star").compare(string_view("start")) < 0);
ASSERT_TRUE(string_view("finished").compare(string_view("fin")) > 0);
}
TEST(string_view, compare1) {
ASSERT_TRUE(string_view("abcdef").compare(2, 2, string_view("ca")) > 0);
ASSERT_TRUE(string_view("abcdef").compare(2, 2, string_view("cd")) == 0);
ASSERT_TRUE(string_view("abcdef").compare(2, 2, string_view("cz")) < 0);
}
TEST(string_view, compare2) {
ASSERT_TRUE(string_view("abcdef").compare(2, 2, string_view("_ca__"), 1, 2) >
0);
ASSERT_TRUE(string_view("abcdef").compare(2, 2, string_view("_cd__"), 1, 2) ==
0);
ASSERT_TRUE(string_view("abcdef").compare(2, 2, string_view("_cz__"), 1, 2) <
0);
}
TEST(string_view, compare3) {
ASSERT_TRUE(string_view("abcdef").compare("aaaa") > 0);
ASSERT_TRUE(string_view("abcdef").compare("abcdef") == 0);
ASSERT_TRUE(string_view("abcdef").compare("zzzz") < 0);
}
TEST(string_view, compare4) {
ASSERT_TRUE(string_view("abcdef").compare(2, 2, "ca") > 0);
ASSERT_TRUE(string_view("abcdef").compare(2, 2, "cd") == 0);
ASSERT_TRUE(string_view("abcdef").compare(2, 2, "cz") < 0);
}
TEST(string_view, compare5) {
ASSERT_TRUE(string_view("abcdef").compare(2, 2, "ca____", 2) > 0);
ASSERT_TRUE(string_view("abcdef").compare(2, 2, "cd___", 2) == 0);
ASSERT_TRUE(string_view("abcdef").compare(2, 2, "cz__", 2) < 0);
}
TEST(string_view, find0) {
ASSERT_EQ(0U, string_view("find fins").find(string_view("fin")));
ASSERT_EQ(5U, string_view("find fins").find(string_view("fin"), 1));
ASSERT_EQ(npos, string_view("find fins").find(string_view("fin"), 6));
}
TEST(string_view, find1) {
ASSERT_EQ(0U, string_view("012340123").find('0'));
ASSERT_EQ(5U, string_view("012340123").find('0', 2));
ASSERT_EQ(npos, string_view("012340123").find('0', 6));
}
TEST(string_view, find2) {
ASSERT_EQ(1U, string_view("012340123").find("12345", 0, 2));
ASSERT_EQ(6U, string_view("012340123").find("12345", 3, 2));
ASSERT_EQ(npos, string_view("012340123").find("12345", 10, 2));
}
TEST(string_view, find3) {
ASSERT_EQ(1U, string_view("012340123").find("12"));
ASSERT_EQ(6U, string_view("012340123").find("12", 2));
ASSERT_EQ(npos, string_view("012340123").find("12", 10));
}
TEST(string_view, rfind0) {
ASSERT_EQ(5U, string_view("find fins").rfind(string_view("fin")));
ASSERT_EQ(0U, string_view("find fins").rfind(string_view("fin"), 4));
ASSERT_EQ(npos, string_view("find fins").rfind(string_view("no")));
ASSERT_EQ(npos, string_view("foo").rfind(string_view("foobar")));
}
TEST(string_view, rfind1) {
ASSERT_EQ(5U, string_view("012340123").rfind('0'));
ASSERT_EQ(0U, string_view("012340123").rfind('0', 2));
ASSERT_EQ(npos, string_view("012340123").rfind('9'));
}
TEST(string_view, rfind2) {
ASSERT_EQ(6U, string_view("012340123").rfind("12345", npos, 2));
ASSERT_EQ(1U, string_view("012340123").rfind("12345", 4, 2));
ASSERT_EQ(npos, string_view("012340123").rfind("12345", npos, 5));
ASSERT_EQ(npos, string_view("012").rfind("12345", npos, 5));
}
TEST(string_view, rfind3) {
ASSERT_EQ(6U, string_view("012340123").rfind("12"));
ASSERT_EQ(1U, string_view("012340123").rfind("12", 2));
ASSERT_EQ(npos, string_view("012340123").rfind("12", 0));
ASSERT_EQ(npos, string_view("012").rfind("12345"));
}
TEST(string_view, find_first_of0) {
ASSERT_EQ(0U, string_view("0123abc").find_first_of(string_view("0a")));
ASSERT_EQ(4U, string_view("0123abc").find_first_of(string_view("0a"), 1));
ASSERT_EQ(npos, string_view("0123abc").find_first_of(string_view("xyz")));
}
TEST(string_view, find_first_of1) {
ASSERT_EQ(1U, string_view("ahellohi").find_first_of('h'));
ASSERT_EQ(6U, string_view("ahellohi").find_first_of('h', 2));
ASSERT_EQ(npos, string_view("ahellohi").find_first_of('z', 2));
}
TEST(string_view, find_first_of2) {
ASSERT_EQ(0U, string_view("0123abc").find_first_of("0a1b", 0, 2));
ASSERT_EQ(4U, string_view("0123abc").find_first_of("0a1b", 1, 2));
ASSERT_EQ(npos, string_view("0123abc").find_first_of("0a1b", 5, 2));
}
TEST(string_view, find_first_of3) {
ASSERT_EQ(0U, string_view("0123abc").find_first_of("0a"));
ASSERT_EQ(0U, string_view("0123abc").find_first_of("0a", 0));
ASSERT_EQ(4U, string_view("0123abc").find_first_of("0a", 1));
ASSERT_EQ(npos, string_view("0123abc").find_first_of("0a", 5));
}
TEST(string_view, find_last_of0) {
ASSERT_EQ(4U, string_view("0123abc").find_last_of(string_view("0a")));
ASSERT_EQ(0U, string_view("0123abc").find_last_of(string_view("0a"), 1));
ASSERT_EQ(npos, string_view("0123abc").find_last_of(string_view("xyz")));
}
TEST(string_view, find_last_of1) {
ASSERT_EQ(6U, string_view("ahellohi").find_last_of('h'));
ASSERT_EQ(1U, string_view("ahellohi").find_last_of('h', 2));
ASSERT_EQ(npos, string_view("ahellohi").find_last_of('z', 2));
}
TEST(string_view, find_last_of2) {
ASSERT_EQ(4U, string_view("0123abc").find_last_of("0a1b", npos, 2));
ASSERT_EQ(0U, string_view("0123abc").find_last_of("0a1b", 1, 2));
ASSERT_EQ(npos, string_view("0123abc").find_last_of("a1b", 0, 2));
ASSERT_EQ(npos, string_view("0123abc").find_last_of("xyz", npos, 0));
}
TEST(string_view, find_last_of3) {
ASSERT_EQ(4U, string_view("0123abc").find_last_of("0a"));
ASSERT_EQ(4U, string_view("0123abc").find_last_of("0a", npos));
ASSERT_EQ(0U, string_view("0123abc").find_last_of("0a", 1));
ASSERT_EQ(npos, string_view("0123abc").find_last_of("a1", 0));
}
TEST(string_view, operator_equal) {
ASSERT_TRUE(string_view("this") == string_view("this"));
ASSERT_FALSE(string_view("this") == string_view("that"));
}
TEST(string_view, operator_not_equal) {
ASSERT_FALSE(string_view("here") != string_view("here"));
ASSERT_TRUE(string_view("here") != string_view("there"));
}
TEST(string_view, operator_less_than) {
ASSERT_TRUE(string_view("abc") < string_view("xyz"));
ASSERT_FALSE(string_view("later") < string_view("earlier"));
ASSERT_FALSE(string_view("one") < string_view("one"));
}
TEST(string_view, operator_greater_than) {
ASSERT_TRUE(string_view("much") > string_view("little"));
ASSERT_FALSE(string_view("future") > string_view("past"));
ASSERT_FALSE(string_view("now") > string_view("now"));
}
TEST(string_view, operator_less_than_or_equal) {
ASSERT_TRUE(string_view("abc") <= string_view("xyz"));
ASSERT_FALSE(string_view("later") <= string_view("earlier"));
ASSERT_TRUE(string_view("one") <= string_view("one"));
}
TEST(string_view, operator_greater_than_or_equal) {
ASSERT_TRUE(string_view("much") >= string_view("little"));
ASSERT_FALSE(string_view("future") >= string_view("past"));
ASSERT_TRUE(string_view("now") >= string_view("now"));
}
TEST(string_view, hash) {
std::hash<string_view> hasher;
ASSERT_NE(hasher(string_view("hello")), hasher(string_view("goodbye")));
ASSERT_EQ(hasher(string_view("same")), hasher(string_view("same")));
}

167
third_party/wasm2c/src/test-utf8.cc vendored Normal file
View File

@@ -0,0 +1,167 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "gtest/gtest.h"
#include "src/utf8.h"
using namespace wabt;
namespace {
void assert_is_valid_utf8(bool expected,
int length,
int cu0 = 0,
int cu1 = 0,
int cu2 = 0,
int cu3 = 0) {
assert(length <= 4);
char buf[4] = {static_cast<char>(cu0), static_cast<char>(cu1),
static_cast<char>(cu2), static_cast<char>(cu3)};
if (expected) {
// Make sure it fails if there are continuation bytes past the end of the
// string.
for (int bad_length = 1; bad_length < length; ++bad_length) {
ASSERT_FALSE(IsValidUtf8(buf, bad_length))
<< cu0 << ", " << cu1 << ", " << cu2 << ", " << cu3;
}
}
ASSERT_TRUE(expected == IsValidUtf8(buf, length))
<< cu0 << ", " << cu1 << ", " << cu2 << ", " << cu3;
}
bool is_in_range(int x, int low, int high) {
return x >= low && x < high;
}
} // end anonymous namespace
#define FOR_RANGE(var, low, high) for (int var = low; var < high; var++)
#define FOR_EACH_BYTE(var) FOR_RANGE(var, 0, 0x100)
TEST(utf8, valid_empty) {
assert_is_valid_utf8(true, 0);
}
TEST(utf8, valid_1_byte) {
FOR_RANGE(cu0, 0, 0x80) { assert_is_valid_utf8(true, 1, cu0); }
}
TEST(utf8, invalid_continuation_bytes) {
FOR_RANGE(cu0, 0x80, 0xc0) { assert_is_valid_utf8(false, 1, cu0); }
}
TEST(utf8, invalid_2_byte) {
FOR_RANGE(cu0, 0xc0, 0xc2) { assert_is_valid_utf8(false, 1, cu0); }
}
TEST(utf8, valid_2_bytes) {
FOR_RANGE(cu0, 0xc2, 0xe0) {
FOR_EACH_BYTE(cu1) {
bool is_valid = is_in_range(cu1, 0x80, 0xc0);
assert_is_valid_utf8(is_valid, 2, cu0, cu1);
}
}
}
TEST(utf8, valid_3_bytes_e0) {
int cu0 = 0xe0;
FOR_EACH_BYTE(cu1) {
FOR_EACH_BYTE(cu2) {
bool is_valid =
is_in_range(cu1, 0xa0, 0xc0) && is_in_range(cu2, 0x80, 0xc0);
assert_is_valid_utf8(is_valid, 3, cu0, cu1, cu2);
}
}
}
TEST(utf8, valid_3_bytes) {
FOR_RANGE(cu0, 0xe1, 0xf0) {
// Handle 0xed in valid_3_bytes_ed.
if (cu0 == 0xed) {
continue;
}
FOR_EACH_BYTE(cu1) {
FOR_EACH_BYTE(cu2) {
bool is_valid =
is_in_range(cu1, 0x80, 0xc0) && is_in_range(cu2, 0x80, 0xc0);
assert_is_valid_utf8(is_valid, 3, cu0, cu1, cu2);
}
}
}
}
TEST(utf8, valid_3_bytes_ed) {
int cu0 = 0xed;
FOR_EACH_BYTE(cu1) {
FOR_EACH_BYTE(cu2) {
bool is_valid =
is_in_range(cu1, 0x80, 0xa0) && is_in_range(cu2, 0x80, 0xc0);
assert_is_valid_utf8(is_valid, 3, cu0, cu1, cu2);
}
}
}
TEST(utf8, valid_4_bytes_f0) {
int cu0 = 0xf0;
FOR_EACH_BYTE(cu1) {
FOR_EACH_BYTE(cu2) {
FOR_EACH_BYTE(cu3) {
bool is_valid = is_in_range(cu1, 0x90, 0xc0) &&
is_in_range(cu2, 0x80, 0xc0) &&
is_in_range(cu3, 0x80, 0xc0);
assert_is_valid_utf8(is_valid, 4, cu0, cu1, cu2, cu3);
}
}
}
}
TEST(utf8, valid_4_bytes) {
FOR_RANGE(cu0, 0xf1, 0xf4) {
FOR_EACH_BYTE(cu1) {
FOR_EACH_BYTE(cu2) {
FOR_EACH_BYTE(cu3) {
bool is_valid = is_in_range(cu1, 0x80, 0xc0) &&
is_in_range(cu2, 0x80, 0xc0) &&
is_in_range(cu3, 0x80, 0xc0);
assert_is_valid_utf8(is_valid, 4, cu0, cu1, cu2, cu3);
}
}
}
}
}
TEST(utf8, valid_4_bytes_f4) {
int cu0 = 0xf4;
FOR_EACH_BYTE(cu1) {
FOR_EACH_BYTE(cu2) {
FOR_EACH_BYTE(cu3) {
bool is_valid = is_in_range(cu1, 0x80, 0x90) &&
is_in_range(cu2, 0x80, 0xc0) &&
is_in_range(cu3, 0x80, 0xc0);
assert_is_valid_utf8(is_valid, 4, cu0, cu1, cu2, cu3);
}
}
}
}
TEST(utf8, invalid_4_bytes) {
FOR_RANGE(cu0, 0xf5, 0x100) {
assert_is_valid_utf8(false, 4, cu0, 0x80, 0x80, 0x80);
}
}

View File

@@ -0,0 +1,87 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "gtest/gtest.h"
#include <memory>
#include "src/wast-lexer.h"
#include "src/wast-parser.h"
using namespace wabt;
namespace {
std::string repeat(std::string s, size_t count) {
std::string result;
for (size_t i = 0; i < count; ++i) {
result += s;
}
return result;
}
Errors ParseInvalidModule(std::string text) {
auto lexer = WastLexer::CreateBufferLexer("test", text.c_str(), text.size());
Errors errors;
std::unique_ptr<Module> module;
Features features;
WastParseOptions options(features);
Result result = ParseWatModule(lexer.get(), &module, &errors, &options);
EXPECT_EQ(Result::Error, result);
return errors;
}
} // end of anonymous namespace
TEST(WastParser, LongToken) {
std::string text;
text = "(module (memory ";
text += repeat("a", 0x5000);
text += "))";
Errors errors = ParseInvalidModule(text);
ASSERT_EQ(1u, errors.size());
ASSERT_EQ(ErrorLevel::Error, errors[0].error_level);
ASSERT_EQ(1, errors[0].loc.line);
ASSERT_EQ(17, errors[0].loc.first_column);
ASSERT_STREQ(
R"(unexpected token "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...", expected a natural number (e.g. 123).)",
errors[0].message.c_str());
}
TEST(WastParser, LongTokenSpace) {
std::string text;
text = "notparen";
text += repeat(" ", 0x10000);
text += "notmodule";
Errors errors = ParseInvalidModule(text);
ASSERT_EQ(2u, errors.size());
ASSERT_EQ(ErrorLevel::Error, errors[0].error_level);
ASSERT_EQ(1, errors[0].loc.line);
ASSERT_EQ(1, errors[0].loc.first_column);
ASSERT_STREQ(
R"(unexpected token "notparen", expected a module field or a module.)",
errors[0].message.c_str());
ASSERT_EQ(1, errors[1].loc.line);
ASSERT_EQ(65545, errors[1].loc.first_column);
ASSERT_STREQ(R"(unexpected token notmodule, expected EOF.)",
errors[1].message.c_str());
}

99
third_party/wasm2c/src/token.cc vendored Normal file
View File

@@ -0,0 +1,99 @@
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/token.h"
namespace wabt {
const char* GetTokenTypeName(TokenType token_type) {
static const char* s_names[] = {
#define WABT_TOKEN(name, string) string,
#define WABT_TOKEN_FIRST(name, string)
#define WABT_TOKEN_LAST(name, string)
#include "token.def"
#undef WABT_TOKEN
#undef WABT_TOKEN_FIRST
#undef WABT_TOKEN_LAST
};
static_assert(
WABT_ARRAY_SIZE(s_names) == WABT_ENUM_COUNT(TokenType),
"Expected TokenType names list length to match number of TokenTypes.");
int x = static_cast<int>(token_type);
if (x < WABT_ENUM_COUNT(TokenType)) {
return s_names[x];
}
return "Invalid";
}
Token::Token(Location loc, TokenType token_type)
: loc(loc), token_type_(token_type) {
assert(IsTokenTypeBare(token_type_));
}
Token::Token(Location loc, TokenType token_type, Type type)
: loc(loc), token_type_(token_type) {
assert(HasType());
Construct(type_, type);
}
Token::Token(Location loc, TokenType token_type, string_view text)
: loc(loc), token_type_(token_type) {
assert(HasText());
Construct(text_, text);
}
Token::Token(Location loc, TokenType token_type, Opcode opcode)
: loc(loc), token_type_(token_type) {
assert(HasOpcode());
Construct(opcode_, opcode);
}
Token::Token(Location loc, TokenType token_type, const Literal& literal)
: loc(loc), token_type_(token_type) {
assert(HasLiteral());
Construct(literal_, literal);
}
std::string Token::to_string() const {
if (IsTokenTypeBare(token_type_)) {
return GetTokenTypeName(token_type_);
} else if (HasLiteral()) {
return literal_.text.to_string();
} else if (HasOpcode()) {
return opcode_.GetName();
} else if (HasText()) {
return text_.to_string();
} else if (IsTokenTypeRefKind(token_type_)) {
return type_.GetRefKindName();
} else {
assert(HasType());
return type_.GetName();
}
}
std::string Token::to_string_clamp(size_t max_length) const {
std::string s = to_string();
if (s.length() > max_length) {
return s.substr(0, max_length - 3) + "...";
} else {
return s;
}
}
} // namespace wabt

Some files were not shown because too many files have changed in this diff Show More