Revert "Revert "Upgrade to 5.0.71.48"" DO NOT MERGE
This reverts commit f2e3994fa5148cc3d9946666f0b0596290192b0e,
and updates the x64 makefile properly so it doesn't break that
build.
FPIIM-449
Change-Id: Ib83e35bfbae6af627451c926a9650ec57c045605
(cherry picked from commit 109988c7ccb6f3fd1a58574fa3dfb88beaef6632)
diff --git a/test/cctest/wasm/wasm-run-utils.h b/test/cctest/wasm/wasm-run-utils.h
index cc23b46..7ee3981 100644
--- a/test/cctest/wasm/wasm-run-utils.h
+++ b/test/cctest/wasm/wasm-run-utils.h
@@ -12,7 +12,10 @@
#include "src/base/utils/random-number-generator.h"
#include "src/compiler/graph-visualizer.h"
+#include "src/compiler/int64-lowering.h"
#include "src/compiler/js-graph.h"
+#include "src/compiler/node.h"
+#include "src/compiler/pipeline.h"
#include "src/compiler/wasm-compiler.h"
#include "src/wasm/ast-decoder.h"
@@ -20,8 +23,10 @@
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-opcodes.h"
+#include "src/zone.h"
+
#include "test/cctest/cctest.h"
-#include "test/cctest/compiler/codegen-tester.h"
+#include "test/cctest/compiler/call-tester.h"
#include "test/cctest/compiler/graph-builder-tester.h"
// TODO(titzer): pull WASM_64 up to a common header.
@@ -31,6 +36,8 @@
#define WASM_64 0
#endif
+static const uint32_t kMaxFunctions = 10;
+
// TODO(titzer): check traps more robustly in tests.
// Currently, in tests, we just return 0xdeadbeef from the function in which
// the trap occurs if the runtime context is not available to throw a JavaScript
@@ -41,6 +48,9 @@
CHECK_EQ(0xdeadbeefdeadbeef, (bit_cast<uint64_t>(x)) & 0xFFFFFFFFFFFFFFFF)
#define CHECK_TRAP(x) CHECK_TRAP32(x)
+#define WASM_RUNNER_MAX_NUM_PARAMETERS 4
+#define WASM_WRAPPER_RETURN_VALUE 8754
+
namespace {
using namespace v8::base;
using namespace v8::internal;
@@ -50,47 +60,51 @@
inline void init_env(FunctionEnv* env, FunctionSig* sig) {
env->module = nullptr;
env->sig = sig;
- env->local_int32_count = 0;
- env->local_int64_count = 0;
- env->local_float32_count = 0;
- env->local_float64_count = 0;
+ env->local_i32_count = 0;
+ env->local_i64_count = 0;
+ env->local_f32_count = 0;
+ env->local_f64_count = 0;
env->SumLocals();
}
const uint32_t kMaxGlobalsSize = 128;
// A helper for module environments that adds the ability to allocate memory
-// and global variables.
+// and global variables. Contains a built-in {WasmModule} and
+// {WasmModuleInstance}.
class TestingModule : public ModuleEnv {
public:
- TestingModule() : mem_size(0), global_offset(0) {
- globals_area = 0;
- mem_start = 0;
- mem_end = 0;
- module = nullptr;
+ TestingModule() : instance_(&module_), global_offset(0) {
+ module_.shared_isolate = CcTest::InitIsolateOnce();
+ module = &module_;
+ instance = &instance_;
+ instance->module = &module_;
+ instance->globals_start = global_data;
+ instance->globals_size = kMaxGlobalsSize;
+ instance->mem_start = nullptr;
+ instance->mem_size = 0;
+ instance->function_code = nullptr;
linker = nullptr;
- function_code = nullptr;
asm_js = false;
memset(global_data, 0, sizeof(global_data));
}
~TestingModule() {
- if (mem_start) {
- free(raw_mem_start<byte>());
+ if (instance->mem_start) {
+ free(instance->mem_start);
}
- if (function_code) delete function_code;
- if (module) delete module;
+ if (instance->function_code) {
+ delete instance->function_code;
+ }
}
byte* AddMemory(size_t size) {
- CHECK_EQ(0, mem_start);
- CHECK_EQ(0, mem_size);
- mem_start = reinterpret_cast<uintptr_t>(malloc(size));
- CHECK(mem_start);
- byte* raw = raw_mem_start<byte>();
- memset(raw, 0, size);
- mem_end = mem_start + size;
- mem_size = size;
+ CHECK_NULL(instance->mem_start);
+ CHECK_EQ(0, instance->mem_size);
+ instance->mem_start = reinterpret_cast<byte*>(malloc(size));
+ CHECK(instance->mem_start);
+ memset(instance->mem_start, 0, size);
+ instance->mem_size = size;
return raw_mem_start<byte>();
}
@@ -103,11 +117,10 @@
template <typename T>
T* AddGlobal(MachineType mem_type) {
WasmGlobal* global = AddGlobal(mem_type);
- return reinterpret_cast<T*>(globals_area + global->offset);
+ return reinterpret_cast<T*>(instance->globals_start + global->offset);
}
byte AddSignature(FunctionSig* sig) {
- AllocModule();
if (!module->signatures) {
module->signatures = new std::vector<FunctionSig*>();
}
@@ -119,33 +132,33 @@
template <typename T>
T* raw_mem_start() {
- DCHECK(mem_start);
- return reinterpret_cast<T*>(mem_start);
+ DCHECK(instance->mem_start);
+ return reinterpret_cast<T*>(instance->mem_start);
}
template <typename T>
T* raw_mem_end() {
- DCHECK(mem_end);
- return reinterpret_cast<T*>(mem_end);
+ DCHECK(instance->mem_start);
+ return reinterpret_cast<T*>(instance->mem_start + instance->mem_size);
}
template <typename T>
T raw_mem_at(int i) {
- DCHECK(mem_start);
- return reinterpret_cast<T*>(mem_start)[i];
+ DCHECK(instance->mem_start);
+ return reinterpret_cast<T*>(instance->mem_start)[i];
}
template <typename T>
T raw_val_at(int i) {
T val;
- memcpy(&val, reinterpret_cast<void*>(mem_start + i), sizeof(T));
+ memcpy(&val, reinterpret_cast<void*>(instance->mem_start + i), sizeof(T));
return val;
}
// Zero-initialize the memory.
void BlankMemory() {
byte* raw = raw_mem_start<byte>();
- memset(raw, 0, mem_size);
+ memset(raw, 0, instance->mem_size);
}
// Pseudo-randomly intialize the memory.
@@ -157,26 +170,57 @@
rng.NextBytes(raw, end - raw);
}
- WasmFunction* AddFunction(FunctionSig* sig, Handle<Code> code) {
- AllocModule();
+ int AddFunction(FunctionSig* sig, Handle<Code> code) {
if (module->functions == nullptr) {
module->functions = new std::vector<WasmFunction>();
- function_code = new std::vector<Handle<Code>>();
+ // TODO(titzer): Reserving space here to avoid the underlying WasmFunction
+ // structs from moving.
+ module->functions->reserve(kMaxFunctions);
+ instance->function_code = new std::vector<Handle<Code>>();
}
- module->functions->push_back({sig, 0, 0, 0, 0, 0, 0, 0, false, false});
- function_code->push_back(code);
- return &module->functions->back();
+ uint32_t index = static_cast<uint32_t>(module->functions->size());
+ module->functions->push_back(
+ {sig, index, 0, 0, 0, 0, 0, 0, 0, false, false});
+ instance->function_code->push_back(code);
+ DCHECK_LT(index, kMaxFunctions); // limited for testing.
+ return index;
+ }
+
+ void SetFunctionCode(uint32_t index, Handle<Code> code) {
+ instance->function_code->at(index) = code;
+ }
+
+ void AddIndirectFunctionTable(int* functions, int table_size) {
+ Isolate* isolate = module->shared_isolate;
+ Handle<FixedArray> fixed =
+ isolate->factory()->NewFixedArray(2 * table_size);
+ instance->function_table = fixed;
+ module->function_table = new std::vector<uint16_t>();
+ for (int i = 0; i < table_size; i++) {
+ module->function_table->push_back(functions[i]);
+ }
+ }
+
+ void PopulateIndirectFunctionTable() {
+ if (instance->function_table.is_null()) return;
+ int table_size = static_cast<int>(module->function_table->size());
+ for (int i = 0; i < table_size; i++) {
+ int function_index = module->function_table->at(i);
+ WasmFunction* function = &module->functions->at(function_index);
+ instance->function_table->set(i, Smi::FromInt(function->sig_index));
+ instance->function_table->set(
+ i + table_size, *instance->function_code->at(function_index));
+ }
}
private:
- size_t mem_size;
+ WasmModule module_;
+ WasmModuleInstance instance_;
uint32_t global_offset;
- byte global_data[kMaxGlobalsSize];
+ V8_ALIGNED(8) byte global_data[kMaxGlobalsSize]; // preallocated global data.
WasmGlobal* AddGlobal(MachineType mem_type) {
- AllocModule();
- if (globals_area == 0) {
- globals_area = reinterpret_cast<uintptr_t>(global_data);
+ if (!module->globals) {
module->globals = new std::vector<WasmGlobal>();
}
byte size = WasmOpcodes::MemSize(mem_type);
@@ -187,15 +231,6 @@
CHECK_LT(global_offset, kMaxGlobalsSize);
return &module->globals->back();
}
- void AllocModule() {
- if (module == nullptr) {
- module = new WasmModule();
- module->shared_isolate = CcTest::InitIsolateOnce();
- module->globals = nullptr;
- module->functions = nullptr;
- module->data_segments = nullptr;
- }
- }
};
@@ -212,39 +247,212 @@
str << ", msg = " << result.error_msg.get();
FATAL(str.str().c_str());
}
+ builder.Int64LoweringForTesting();
if (FLAG_trace_turbo_graph) {
OFStream os(stdout);
os << AsRPO(*jsgraph->graph());
}
}
+template <typename ReturnType>
+class WasmFunctionWrapper : public HandleAndZoneScope,
+ private GraphAndBuilders {
+ public:
+ WasmFunctionWrapper()
+ : GraphAndBuilders(main_zone()),
+ inner_code_node_(nullptr),
+ signature_(nullptr) {
+ // One additional parameter for the pointer to the return value memory.
+ Signature<MachineType>::Builder sig_builder(
+ zone(), 1, WASM_RUNNER_MAX_NUM_PARAMETERS + 1);
-// A helper for compiling functions that are only internally callable WASM code.
+ sig_builder.AddReturn(MachineType::Int32());
+ for (int i = 0; i < WASM_RUNNER_MAX_NUM_PARAMETERS + 1; i++) {
+ sig_builder.AddParam(MachineType::Pointer());
+ }
+ signature_ = sig_builder.Build();
+ }
+
+ void Init(CallDescriptor* descriptor, MachineType p0 = MachineType::None(),
+ MachineType p1 = MachineType::None(),
+ MachineType p2 = MachineType::None(),
+ MachineType p3 = MachineType::None()) {
+ // Create the TF graph for the wrapper. The wrapper always takes four
+ // pointers as parameters, but may not pass the values of all pointers to
+ // the actual test function.
+
+ // Function, effect, and control.
+ Node** parameters =
+ zone()->template NewArray<Node*>(WASM_RUNNER_MAX_NUM_PARAMETERS + 3);
+ graph()->SetStart(graph()->NewNode(common()->Start(6)));
+ Node* effect = graph()->start();
+ int parameter_count = 0;
+
+ // Dummy node which gets replaced in SetInnerCode.
+ inner_code_node_ = graph()->NewNode(common()->Int32Constant(0));
+ parameters[parameter_count++] = inner_code_node_;
+
+ if (p0 != MachineType::None()) {
+ parameters[parameter_count] = graph()->NewNode(
+ machine()->Load(p0),
+ graph()->NewNode(common()->Parameter(0), graph()->start()),
+ graph()->NewNode(common()->Int32Constant(0)), effect,
+ graph()->start());
+ effect = parameters[parameter_count++];
+ }
+ if (p1 != MachineType::None()) {
+ parameters[parameter_count] = graph()->NewNode(
+ machine()->Load(p0),
+ graph()->NewNode(common()->Parameter(1), graph()->start()),
+ graph()->NewNode(common()->Int32Constant(0)), effect,
+ graph()->start());
+ effect = parameters[parameter_count++];
+ }
+ if (p2 != MachineType::None()) {
+ parameters[parameter_count] = graph()->NewNode(
+ machine()->Load(p0),
+ graph()->NewNode(common()->Parameter(2), graph()->start()),
+ graph()->NewNode(common()->Int32Constant(0)), effect,
+ graph()->start());
+ effect = parameters[parameter_count++];
+ }
+ if (p3 != MachineType::None()) {
+ parameters[parameter_count] = graph()->NewNode(
+ machine()->Load(p0),
+ graph()->NewNode(common()->Parameter(3), graph()->start()),
+ graph()->NewNode(common()->Int32Constant(0)), effect,
+ graph()->start());
+ effect = parameters[parameter_count++];
+ }
+
+ parameters[parameter_count++] = effect;
+ parameters[parameter_count++] = graph()->start();
+ Node* call = graph()->NewNode(common()->Call(descriptor), parameter_count,
+ parameters);
+
+ effect = graph()->NewNode(
+ machine()->Store(
+ StoreRepresentation(MachineTypeForC<ReturnType>().representation(),
+ WriteBarrierKind::kNoWriteBarrier)),
+ graph()->NewNode(common()->Parameter(WASM_RUNNER_MAX_NUM_PARAMETERS),
+ graph()->start()),
+ graph()->NewNode(common()->Int32Constant(0)), call, effect,
+ graph()->start());
+ Node* r = graph()->NewNode(
+ common()->Return(),
+ graph()->NewNode(common()->Int32Constant(WASM_WRAPPER_RETURN_VALUE)),
+ effect, graph()->start());
+ graph()->SetEnd(graph()->NewNode(common()->End(2), r, graph()->start()));
+ }
+
+ void SetInnerCode(Handle<Code> code_handle) {
+ NodeProperties::ChangeOp(inner_code_node_,
+ common()->HeapConstant(code_handle));
+ }
+
+ Handle<Code> GetWrapperCode() {
+ if (code_.is_null()) {
+ Isolate* isolate = CcTest::InitIsolateOnce();
+
+ CallDescriptor* descriptor =
+ Linkage::GetSimplifiedCDescriptor(zone(), signature_, true);
+
+ if (kPointerSize == 4) {
+ // One additional parameter for the pointer of the return value.
+ Signature<MachineRepresentation>::Builder rep_builder(
+ zone(), 1, WASM_RUNNER_MAX_NUM_PARAMETERS + 1);
+
+ rep_builder.AddReturn(MachineRepresentation::kWord32);
+ for (int i = 0; i < WASM_RUNNER_MAX_NUM_PARAMETERS + 1; i++) {
+ rep_builder.AddParam(MachineRepresentation::kWord32);
+ }
+ Int64Lowering r(graph(), machine(), common(), zone(),
+ rep_builder.Build());
+ r.LowerGraph();
+ }
+
+ CompilationInfo info("testing", isolate, graph()->zone());
+ code_ =
+ Pipeline::GenerateCodeForTesting(&info, descriptor, graph(), nullptr);
+ CHECK(!code_.is_null());
+#ifdef ENABLE_DISASSEMBLER
+ if (FLAG_print_opt_code) {
+ OFStream os(stdout);
+ code_->Disassemble("wasm wrapper", os);
+ }
+#endif
+ }
+
+ return code_;
+ }
+
+ Signature<MachineType>* signature() const { return signature_; }
+
+ private:
+ Node* inner_code_node_;
+ Handle<Code> code_;
+ Signature<MachineType>* signature_;
+};
+
+// A helper for compiling WASM functions for testing. This class can create a
+// standalone function if {module} is NULL or a function within a
+// {TestingModule}. It contains the internal state for compilation (i.e.
+// TurboFan graph) and, later, interpretation.
class WasmFunctionCompiler : public HandleAndZoneScope,
private GraphAndBuilders {
public:
- explicit WasmFunctionCompiler(FunctionSig* sig, ModuleEnv* module = nullptr)
+ explicit WasmFunctionCompiler(FunctionSig* sig, TestingModule* module)
: GraphAndBuilders(main_zone()),
jsgraph(this->isolate(), this->graph(), this->common(), nullptr,
nullptr, this->machine()),
- descriptor_(nullptr) {
+ descriptor_(nullptr),
+ testing_module_(module) {
init_env(&env, sig);
env.module = module;
+ if (module) {
+ // Get a new function from the testing module.
+ function_ = nullptr;
+ function_index_ = module->AddFunction(sig, Handle<Code>::null());
+ } else {
+ // Create our own function.
+ function_ = new WasmFunction();
+ function_->sig = sig;
+ function_index_ = 0;
+ }
+ }
+
+ ~WasmFunctionCompiler() {
+ if (function_) delete function_;
}
JSGraph jsgraph;
FunctionEnv env;
// The call descriptor is initialized when the function is compiled.
CallDescriptor* descriptor_;
+ TestingModule* testing_module_;
+ WasmFunction* function_;
+ int function_index_;
Isolate* isolate() { return main_isolate(); }
Graph* graph() const { return main_graph_; }
Zone* zone() const { return graph()->zone(); }
CommonOperatorBuilder* common() { return &main_common_; }
MachineOperatorBuilder* machine() { return &main_machine_; }
+ void InitializeDescriptor() {
+ if (descriptor_ == nullptr) {
+ descriptor_ = env.module->GetWasmCallDescriptor(main_zone(), env.sig);
+ }
+ }
CallDescriptor* descriptor() { return descriptor_; }
void Build(const byte* start, const byte* end) {
+ // Transfer local counts before compiling.
+ function()->local_i32_count = env.local_i32_count;
+ function()->local_i64_count = env.local_i64_count;
+ function()->local_f32_count = env.local_f32_count;
+ function()->local_f64_count = env.local_f64_count;
+
+ // Build the TurboFan graph.
TestBuildingGraph(main_zone(), &jsgraph, &env, start, end);
}
@@ -256,11 +464,16 @@
return b;
}
- Handle<Code> Compile(ModuleEnv* module) {
- descriptor_ = module->GetWasmCallDescriptor(this->zone(), env.sig);
+ // TODO(titzer): remove me.
+ Handle<Code> Compile() {
+ InitializeDescriptor();
+ CallDescriptor* desc = descriptor_;
+ if (kPointerSize == 4) {
+ desc = testing_module_->GetI32WasmCallDescriptor(this->zone(), desc);
+ }
CompilationInfo info("wasm compile", this->isolate(), this->zone());
Handle<Code> result =
- Pipeline::GenerateCodeForTesting(&info, descriptor_, this->graph());
+ Pipeline::GenerateCodeForTesting(&info, desc, this->graph());
#ifdef ENABLE_DISASSEMBLER
if (!result.is_null() && FLAG_print_opt_code) {
OFStream os(stdout);
@@ -271,17 +484,21 @@
return result;
}
- uint32_t CompileAndAdd(TestingModule* module) {
- uint32_t index = 0;
- if (module->module && module->module->functions) {
- index = static_cast<uint32_t>(module->module->functions->size());
- }
- module->AddFunction(env.sig, Compile(module));
- return index;
+ // TODO(titzer): remove me.
+ uint32_t CompileAndAdd(uint16_t sig_index = 0) {
+ CHECK(testing_module_);
+ function()->sig_index = sig_index;
+ Handle<Code> code = Compile();
+ testing_module_->SetFunctionCode(function_index_, code);
+ return static_cast<uint32_t>(function_index_);
+ }
+
+ WasmFunction* function() {
+ if (function_) return function_;
+ return &testing_module_->module->functions->at(function_index_);
}
};
-
// A helper class to build graphs from Wasm bytecode, generate machine
// code, and run that code.
template <typename ReturnType>
@@ -291,11 +508,28 @@
MachineType p1 = MachineType::None(),
MachineType p2 = MachineType::None(),
MachineType p3 = MachineType::None())
- : signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1,
+ : compiled_(false),
+
+ signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1,
GetParameterCount(p0, p1, p2, p3), storage_),
- compiler_(&signature_),
- call_wrapper_(p0, p1, p2, p3),
- compilation_done_(false) {
+ compiler_(&signature_, nullptr) {
+ InitSigStorage(p0, p1, p2, p3);
+ }
+
+ WasmRunner(TestingModule* module, MachineType p0 = MachineType::None(),
+ MachineType p1 = MachineType::None(),
+ MachineType p2 = MachineType::None(),
+ MachineType p3 = MachineType::None())
+ : compiled_(false),
+ signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1,
+ GetParameterCount(p0, p1, p2, p3), storage_),
+ compiler_(&signature_, module) {
+ DCHECK(module);
+ InitSigStorage(p0, p1, p2, p3);
+ }
+
+ void InitSigStorage(MachineType p0, MachineType p1, MachineType p2,
+ MachineType p3) {
int index = 0;
MachineType ret = MachineTypeForC<ReturnType>();
if (ret != MachineType::None()) {
@@ -309,56 +543,60 @@
storage_[index++] = WasmOpcodes::LocalTypeFor(p2);
if (p3 != MachineType::None())
storage_[index++] = WasmOpcodes::LocalTypeFor(p3);
- }
+ compiler_.InitializeDescriptor();
+ wrapper_.Init(compiler_.descriptor(), p0, p1, p2, p3);
+ }
FunctionEnv* env() { return &compiler_.env; }
-
- // Builds a graph from the given Wasm code, and generates the machine
+ // Builds a graph from the given Wasm code and generates the machine
// code and call wrapper for that graph. This method must not be called
// more than once.
void Build(const byte* start, const byte* end) {
- DCHECK(!compilation_done_);
- compilation_done_ = true;
- // Build the TF graph.
+ CHECK(!compiled_);
+ compiled_ = true;
+
+ // Build the TF graph within the compiler.
compiler_.Build(start, end);
// Generate code.
- Handle<Code> code = compiler_.Compile(env()->module);
+ Handle<Code> code = compiler_.Compile();
- // Construct the call wrapper.
- Node* inputs[5];
- int input_count = 0;
- inputs[input_count++] = call_wrapper_.HeapConstant(code);
- for (size_t i = 0; i < signature_.parameter_count(); i++) {
- inputs[input_count++] = call_wrapper_.Parameter(i);
+ if (compiler_.testing_module_) {
+ // Update the table of function code in the module.
+ compiler_.testing_module_->SetFunctionCode(compiler_.function_index_,
+ code);
}
- call_wrapper_.Return(call_wrapper_.AddNode(
- call_wrapper_.common()->Call(compiler_.descriptor()), input_count,
- inputs));
+ wrapper_.SetInnerCode(code);
}
- ReturnType Call() { return call_wrapper_.Call(); }
+ ReturnType Call() { return Call(0, 0, 0, 0); }
template <typename P0>
ReturnType Call(P0 p0) {
- return call_wrapper_.Call(p0);
+ return Call(p0, 0, 0, 0);
}
template <typename P0, typename P1>
ReturnType Call(P0 p0, P1 p1) {
- return call_wrapper_.Call(p0, p1);
+ return Call(p0, p1, 0, 0);
}
template <typename P0, typename P1, typename P2>
ReturnType Call(P0 p0, P1 p1, P2 p2) {
- return call_wrapper_.Call(p0, p1, p2);
+ return Call(p0, p1, p2, 0);
}
template <typename P0, typename P1, typename P2, typename P3>
ReturnType Call(P0 p0, P1 p1, P2 p2, P3 p3) {
- return call_wrapper_.Call(p0, p1, p2, p3);
+ CodeRunner<int32_t> runner(CcTest::InitIsolateOnce(),
+ wrapper_.GetWrapperCode(), wrapper_.signature());
+ ReturnType return_value;
+ int32_t result = runner.Call<void*, void*, void*, void*, void*>(
+ &p0, &p1, &p2, &p3, &return_value);
+ CHECK_EQ(WASM_WRAPPER_RETURN_VALUE, result);
+ return return_value;
}
byte AllocateLocal(LocalType type) {
@@ -369,12 +607,13 @@
return b;
}
- private:
- LocalType storage_[5];
+ protected:
+ Zone zone;
+ bool compiled_;
+ LocalType storage_[WASM_RUNNER_MAX_NUM_PARAMETERS];
FunctionSig signature_;
WasmFunctionCompiler compiler_;
- BufferedRawMachineAssemblerTester<ReturnType> call_wrapper_;
- bool compilation_done_;
+ WasmFunctionWrapper<ReturnType> wrapper_;
static size_t GetParameterCount(MachineType p0, MachineType p1,
MachineType p2, MachineType p3) {