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:
202
third_party/wasm2c/LICENSE
vendored
Normal file
202
third_party/wasm2c/LICENSE
vendored
Normal 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
510
third_party/wasm2c/src/apply-names.cc
vendored
Normal 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,
|
||||
¶m_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
45
third_party/wasm2c/src/apply-names.h
vendored
Normal 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
1585
third_party/wasm2c/src/binary-reader-ir.cc
vendored
Normal file
File diff suppressed because it is too large
Load Diff
37
third_party/wasm2c/src/binary-reader-ir.h
vendored
Normal file
37
third_party/wasm2c/src/binary-reader-ir.h
vendored
Normal 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_ */
|
||||
967
third_party/wasm2c/src/binary-reader-logging.cc
vendored
Normal file
967
third_party/wasm2c/src/binary-reader-logging.cc
vendored
Normal 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
|
||||
399
third_party/wasm2c/src/binary-reader-logging.h
vendored
Normal file
399
third_party/wasm2c/src/binary-reader-logging.h
vendored
Normal 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_
|
||||
567
third_party/wasm2c/src/binary-reader-nop.h
vendored
Normal file
567
third_party/wasm2c/src/binary-reader-nop.h
vendored
Normal 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_ */
|
||||
2039
third_party/wasm2c/src/binary-reader-objdump.cc
vendored
Normal file
2039
third_party/wasm2c/src/binary-reader-objdump.cc
vendored
Normal file
File diff suppressed because it is too large
Load Diff
87
third_party/wasm2c/src/binary-reader-objdump.h
vendored
Normal file
87
third_party/wasm2c/src/binary-reader-objdump.h
vendored
Normal 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_ */
|
||||
290
third_party/wasm2c/src/binary-reader-opcnt.cc
vendored
Normal file
290
third_party/wasm2c/src/binary-reader-opcnt.cc
vendored
Normal 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
|
||||
93
third_party/wasm2c/src/binary-reader-opcnt.h
vendored
Normal file
93
third_party/wasm2c/src/binary-reader-opcnt.h
vendored
Normal 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
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
480
third_party/wasm2c/src/binary-reader.h
vendored
Normal 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_ */
|
||||
630
third_party/wasm2c/src/binary-writer-spec.cc
vendored
Normal file
630
third_party/wasm2c/src/binary-writer-spec.cc
vendored
Normal 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
|
||||
60
third_party/wasm2c/src/binary-writer-spec.h
vendored
Normal file
60
third_party/wasm2c/src/binary-writer-spec.h
vendored
Normal 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
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
62
third_party/wasm2c/src/binary-writer.h
vendored
Normal 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
62
third_party/wasm2c/src/binary.cc
vendored
Normal 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
93
third_party/wasm2c/src/binary.h
vendored
Normal 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
91
third_party/wasm2c/src/binding-hash.cc
vendored
Normal 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
72
third_party/wasm2c/src/binding-hash.h
vendored
Normal 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
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
41
third_party/wasm2c/src/c-writer.h
vendored
Normal 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
109
third_party/wasm2c/src/cast.h
vendored
Normal 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
123
third_party/wasm2c/src/circular-array.h
vendored
Normal 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
84
third_party/wasm2c/src/color.cc
vendored
Normal 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
72
third_party/wasm2c/src/color.h
vendored
Normal 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
147
third_party/wasm2c/src/common.cc
vendored
Normal 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
479
third_party/wasm2c/src/common.h
vendored
Normal 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
162
third_party/wasm2c/src/config.cc
vendored
Normal 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
316
third_party/wasm2c/src/config.h.in
vendored
Normal 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
378
third_party/wasm2c/src/decompiler-ast.h
vendored
Normal 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
265
third_party/wasm2c/src/decompiler-ls.h
vendored
Normal 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_
|
||||
211
third_party/wasm2c/src/decompiler-naming.h
vendored
Normal file
211
third_party/wasm2c/src/decompiler-naming.h
vendored
Normal 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
829
third_party/wasm2c/src/decompiler.cc
vendored
Normal 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 = *
|
||||
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
36
third_party/wasm2c/src/decompiler.h
vendored
Normal 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_ */
|
||||
59
third_party/wasm2c/src/emscripten-exported.json
vendored
Normal file
59
third_party/wasm2c/src/emscripten-exported.json
vendored
Normal 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"
|
||||
]
|
||||
406
third_party/wasm2c/src/emscripten-helpers.cc
vendored
Normal file
406
third_party/wasm2c/src/emscripten-helpers.cc
vendored
Normal 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_ */
|
||||
127
third_party/wasm2c/src/error-formatter.cc
vendored
Normal file
127
third_party/wasm2c/src/error-formatter.cc
vendored
Normal 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
|
||||
54
third_party/wasm2c/src/error-formatter.h
vendored
Normal file
54
third_party/wasm2c/src/error-formatter.h
vendored
Normal 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
58
third_party/wasm2c/src/error.h
vendored
Normal 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
481
third_party/wasm2c/src/expr-visitor.cc
vendored
Normal 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
221
third_party/wasm2c/src/expr-visitor.h
vendored
Normal 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
50
third_party/wasm2c/src/feature.cc
vendored
Normal 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
37
third_party/wasm2c/src/feature.def
vendored
Normal 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
58
third_party/wasm2c/src/feature.h
vendored
Normal 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
56
third_party/wasm2c/src/filenames.cc
vendored
Normal 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
51
third_party/wasm2c/src/filenames.h
vendored
Normal 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
431
third_party/wasm2c/src/generate-names.cc
vendored
Normal 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
46
third_party/wasm2c/src/generate-names.h
vendored
Normal 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
38
third_party/wasm2c/src/hash-util.cc
vendored
Normal 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
51
third_party/wasm2c/src/hash-util.h
vendored
Normal 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
633
third_party/wasm2c/src/intrusive-list.h
vendored
Normal 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
267
third_party/wasm2c/src/ir-util.cc
vendored
Normal 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
76
third_party/wasm2c/src/ir-util.h
vendored
Normal 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
694
third_party/wasm2c/src/ir.cc
vendored
Normal 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
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
354
third_party/wasm2c/src/leb128.cc
vendored
Normal 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
69
third_party/wasm2c/src/leb128.h
vendored
Normal 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_
|
||||
631
third_party/wasm2c/src/lexer-keywords.txt
vendored
Normal file
631
third_party/wasm2c/src/lexer-keywords.txt
vendored
Normal 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
|
||||
152
third_party/wasm2c/src/lexer-source-line-finder.cc
vendored
Normal file
152
third_party/wasm2c/src/lexer-source-line-finder.cc
vendored
Normal 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
|
||||
61
third_party/wasm2c/src/lexer-source-line-finder.h
vendored
Normal file
61
third_party/wasm2c/src/lexer-source-line-finder.h
vendored
Normal 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
67
third_party/wasm2c/src/lexer-source.cc
vendored
Normal 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
53
third_party/wasm2c/src/lexer-source.h
vendored
Normal 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
830
third_party/wasm2c/src/literal.cc
vendored
Normal 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
84
third_party/wasm2c/src/literal.h
vendored
Normal 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
42
third_party/wasm2c/src/make-unique.h
vendored
Normal 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_
|
||||
41
third_party/wasm2c/src/opcode-code-table.c
vendored
Normal file
41
third_party/wasm2c/src/opcode-code-table.c
vendored
Normal 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
|
||||
};
|
||||
38
third_party/wasm2c/src/opcode-code-table.h
vendored
Normal file
38
third_party/wasm2c/src/opcode-code-table.h
vendored
Normal 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
405
third_party/wasm2c/src/opcode.cc
vendored
Normal 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
569
third_party/wasm2c/src/opcode.def
vendored
Normal 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
182
third_party/wasm2c/src/opcode.h
vendored
Normal 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
356
third_party/wasm2c/src/option-parser.cc
vendored
Normal 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
99
third_party/wasm2c/src/option-parser.h
vendored
Normal 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_ */
|
||||
1862
third_party/wasm2c/src/prebuilt/lexer-keywords.cc
vendored
Normal file
1862
third_party/wasm2c/src/prebuilt/lexer-keywords.cc
vendored
Normal file
File diff suppressed because it is too large
Load Diff
269
third_party/wasm2c/src/prebuilt/wasm2c.include.c
vendored
Normal file
269
third_party/wasm2c/src/prebuilt/wasm2c.include.c
vendored
Normal 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"
|
||||
;
|
||||
48
third_party/wasm2c/src/prebuilt/wasm2c.include.h
vendored
Normal file
48
third_party/wasm2c/src/prebuilt/wasm2c.include.h
vendored
Normal 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
37
third_party/wasm2c/src/range.h
vendored
Normal 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
589
third_party/wasm2c/src/resolve-names.cc
vendored
Normal 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(¤t_module_->func_bindings, var, "function");
|
||||
}
|
||||
|
||||
void NameResolver::ResolveGlobalVar(Var* var) {
|
||||
ResolveVar(¤t_module_->global_bindings, var, "global");
|
||||
}
|
||||
|
||||
void NameResolver::ResolveFuncTypeVar(Var* var) {
|
||||
ResolveVar(¤t_module_->type_bindings, var, "type");
|
||||
}
|
||||
|
||||
void NameResolver::ResolveTableVar(Var* var) {
|
||||
ResolveVar(¤t_module_->table_bindings, var, "table");
|
||||
}
|
||||
|
||||
void NameResolver::ResolveMemoryVar(Var* var) {
|
||||
ResolveVar(¤t_module_->memory_bindings, var, "memory");
|
||||
}
|
||||
|
||||
void NameResolver::ResolveEventVar(Var* var) {
|
||||
ResolveVar(¤t_module_->event_bindings, var, "event");
|
||||
}
|
||||
|
||||
void NameResolver::ResolveDataSegmentVar(Var* var) {
|
||||
ResolveVar(¤t_module_->data_segment_bindings, var, "data segment");
|
||||
}
|
||||
|
||||
void NameResolver::ResolveElemSegmentVar(Var* var) {
|
||||
ResolveVar(¤t_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
33
third_party/wasm2c/src/resolve-names.h
vendored
Normal 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
63
third_party/wasm2c/src/result.h
vendored
Normal 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
1250
third_party/wasm2c/src/shared-validator.cc
vendored
Normal file
File diff suppressed because it is too large
Load Diff
314
third_party/wasm2c/src/shared-validator.h
vendored
Normal file
314
third_party/wasm2c/src/shared-validator.h
vendored
Normal 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
316
third_party/wasm2c/src/stream.cc
vendored
Normal 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
227
third_party/wasm2c/src/stream.h
vendored
Normal 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
196
third_party/wasm2c/src/string-view.cc
vendored
Normal 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
347
third_party/wasm2c/src/string-view.h
vendored
Normal 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_
|
||||
75
third_party/wasm2c/src/test-binary-reader.cc
vendored
Normal file
75
third_party/wasm2c/src/test-binary-reader.cc
vendored
Normal 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;
|
||||
}
|
||||
}
|
||||
284
third_party/wasm2c/src/test-circular-array.cc
vendored
Normal file
284
third_party/wasm2c/src/test-circular-array.cc
vendored
Normal 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, {});
|
||||
}
|
||||
61
third_party/wasm2c/src/test-filenames.cc
vendored
Normal file
61
third_party/wasm2c/src/test-filenames.cc
vendored
Normal 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
264
third_party/wasm2c/src/test-hexfloat.cc
vendored
Normal 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
693
third_party/wasm2c/src/test-interp.cc
vendored
Normal 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)
|
||||
584
third_party/wasm2c/src/test-intrusive-list.cc
vendored
Normal file
584
third_party/wasm2c/src/test-intrusive-list.cc
vendored
Normal 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
838
third_party/wasm2c/src/test-literal.cc
vendored
Normal 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');
|
||||
}
|
||||
}
|
||||
181
third_party/wasm2c/src/test-option-parser.cc
vendored
Normal file
181
third_party/wasm2c/src/test-option-parser.cc
vendored
Normal 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);
|
||||
}
|
||||
415
third_party/wasm2c/src/test-string-view.cc
vendored
Normal file
415
third_party/wasm2c/src/test-string-view.cc
vendored
Normal 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
167
third_party/wasm2c/src/test-utf8.cc
vendored
Normal 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);
|
||||
}
|
||||
}
|
||||
87
third_party/wasm2c/src/test-wast-parser.cc
vendored
Normal file
87
third_party/wasm2c/src/test-wast-parser.cc
vendored
Normal 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
99
third_party/wasm2c/src/token.cc
vendored
Normal 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
Reference in New Issue
Block a user