Commit 87def2c8 by Eric Holk

Subzero, Wasm: Dynamically reallocate read buffer. Runtime improvements.

This change fills in several more runtime functions needed by several benchmarks, as well as changing the buffer handling in the WASM decoder. Now the decoder will resize the buffer as needed to accomodate large .wasm modules. Tracing can now be enabled on runtime functions to aid with debugging. Additionally, runtime failures such as bounds check failures or invalid indirect function calls tell what kind of failure occured. BUG= https://bugs.chromium.org/p/nativeclient/issues/detail?id=4369 R=jpp@chromium.org, stichnot@chromium.org Review URL: https://codereview.chromium.org/1918213003 .
parent de29f120
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
./wasm-install/bin/emscripten/emcc "$1" -s BINARYEN=1 \ ./wasm-install/bin/emscripten/emcc "$1" -s BINARYEN=1 \
-s 'BINARYEN_METHOD="native-wasm"' \ -s 'BINARYEN_METHOD="native-wasm"' \
--em-config wasm-install/emscripten_config_vanilla && \ --em-config wasm-install/emscripten_config_vanilla -O2 && \
./wasm-install/bin/sexpr-wasm a.out.wast -o a.out.wasm && \ ./wasm-install/bin/sexpr-wasm a.out.wast -o a.out.wasm && \
./pnacl-sz a.out.wasm -o a.out.o -filetype=obj -O2 && \ ./pnacl-sz a.out.wasm -o a.out.o -filetype=obj -O2 && \
clang -m32 a.out.o ./runtime/szrt.c \ clang -m32 a.out.o ./runtime/szrt.c \
./runtime/wasm-runtime.cpp -lm -g ./runtime/wasm-runtime.cpp -lm -g -lstdc++
...@@ -163,7 +163,7 @@ def run_test(test_file, verbose=False): ...@@ -163,7 +163,7 @@ def run_test(test_file, verbose=False):
# Try to link and run the program. # Try to link and run the program.
cmd = "clang -g -m32 {} -o {} " + \ cmd = "clang -g -m32 {} -o {} " + \
"./runtime/szrt.c ./runtime/wasm-runtime.cpp -lm" "./runtime/szrt.c ./runtime/wasm-runtime.cpp -lm -lstdc++"
cmd = cmd.format(obj_file, exe_file) cmd = cmd.format(obj_file, exe_file)
if not run_test or os.system(cmd) == 0: if not run_test or os.system(cmd) == 0:
......
...@@ -14,8 +14,40 @@ ...@@ -14,8 +14,40 @@
#include <cassert> #include <cassert>
#include <cmath> #include <cmath>
// TODO (eholk): change to cstdint #include <errno.h>
#include <fcntl.h>
#include <iostream>
#include <math.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>
#ifdef WASM_TRACE_RUNTIME
#define TRACE_ENTRY() \
{ std::cerr << __func__ << "(...) = "; }
template <typename T> T trace(T x) {
std::cerr << x << std::endl;
return x;
}
void trace() { std::cerr << "(void)" << std::endl; }
#else
#define TRACE_ENTRY()
template <typename T> T trace(T x) { return x; }
void trace() {}
#endif // WASM_TRACE_RUNTIME
extern "C" {
extern char WASM_MEMORY[];
extern uint32_t WASM_DATA_SIZE;
extern uint32_t WASM_NUM_PAGES;
} // end of extern "C"
namespace { namespace {
uint32_t HeapBreak; uint32_t HeapBreak;
...@@ -35,20 +67,75 @@ float floor(float X) { return std::floor(X); } ...@@ -35,20 +67,75 @@ float floor(float X) { return std::floor(X); }
} // end of namespace env } // end of namespace env
// TODO (eholk): move the C parts outside and use C++ name mangling. // TODO (eholk): move the C parts outside and use C++ name mangling.
namespace {
/// Some runtime functions need to return pointers. The WasmData struct is used
/// to preallocate space for these on the heap.
struct WasmData {
/// StrBuf is returned by functions that return strings.
char StrBuf[256];
};
WasmData *GlobalData = NULL;
int toWasm(void *Ptr) {
return reinterpret_cast<int>(reinterpret_cast<char *>(Ptr) - WASM_MEMORY);
}
template <typename T> T *wasmPtr(int Index) {
if (pageNum(Index) < WASM_NUM_PAGES) {
return reinterpret_cast<T *>(WASM_MEMORY + Index);
}
abort();
}
template <typename T> class WasmPtr {
int Ptr;
public:
WasmPtr(int Ptr) : Ptr(Ptr) {
// TODO (eholk): make this a static_assert once we have C++11
assert(sizeof(*this) == sizeof(int));
}
WasmPtr(T *Ptr) : Ptr(toWasm(Ptr)) {}
T &operator*() const { return *asPtr(); }
T *asPtr() const { return wasmPtr<T>(Ptr); }
int asInt() const { return Ptr; }
};
typedef WasmPtr<char> WasmCharPtr;
template <typename T> class WasmArray {
int Ptr;
public:
WasmArray(int Ptr) : Ptr(Ptr) {
// TODO (eholk): make this a static_assert once we have C++11.
assert(sizeof(*this) == sizeof(int));
}
T &operator[](unsigned int Index) const { return wasmPtr<T>(Ptr)[Index]; }
};
} // end of anonymous namespace
// TODO (eholk): move the C parts outside and use C++ name mangling.
extern "C" { extern "C" {
#include <errno.h>
#include <fcntl.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
extern char WASM_MEMORY[]; void __Sz_bounds_fail() {
extern uint32_t WASM_DATA_SIZE; std::cerr << "Bounds check failure" << std::endl;
extern uint32_t WASM_NUM_PAGES; abort();
}
void __Sz_indirect_fail() {
std::cerr << "Invalid indirect call target" << std::endl;
abort();
}
void env$$abort() { void env$$abort() {
fprintf(stderr, "Aborting...\n"); fprintf(stderr, "Aborting...\n");
...@@ -57,11 +144,23 @@ void env$$abort() { ...@@ -57,11 +144,23 @@ void env$$abort() {
void env$$_abort() { env$$abort(); } void env$$_abort() { env$$abort(); }
double env$$floor_f(float X) { return env::floor(X); } double env$$floor_f(float X) {
double env$$floor_d(double X) { return env::floor(X); } TRACE_ENTRY();
return env::floor(X);
}
double env$$floor_d(double X) {
TRACE_ENTRY();
return env::floor(X);
}
void env$$exit(int Status) { exit(Status); } void env$$exit(int Status) {
void env$$_exit(int Status) { env$$exit(Status); } TRACE_ENTRY();
exit(Status);
}
void env$$_exit(int Status) {
TRACE_ENTRY();
env$$exit(Status);
}
#define UNIMPLEMENTED(f) \ #define UNIMPLEMENTED(f) \
void env$$##f() { \ void env$$##f() { \
...@@ -70,138 +169,259 @@ void env$$_exit(int Status) { env$$exit(Status); } ...@@ -70,138 +169,259 @@ void env$$_exit(int Status) { env$$exit(Status); }
} }
int32_t env$$sbrk(int32_t Increment) { int32_t env$$sbrk(int32_t Increment) {
TRACE_ENTRY();
uint32_t OldBreak = HeapBreak;
HeapBreak += Increment; HeapBreak += Increment;
return HeapBreak; return trace(OldBreak);
} }
UNIMPLEMENTED(setjmp) UNIMPLEMENTED(__addtf3)
UNIMPLEMENTED(longjmp)
UNIMPLEMENTED(__assert_fail) UNIMPLEMENTED(__assert_fail)
UNIMPLEMENTED(__builtin_malloc)
UNIMPLEMENTED(__builtin_isinff)
UNIMPLEMENTED(__builtin_isinfl)
UNIMPLEMENTED(__builtin_apply) UNIMPLEMENTED(__builtin_apply)
UNIMPLEMENTED(__builtin_apply_args) UNIMPLEMENTED(__builtin_apply_args)
UNIMPLEMENTED(pthread_cleanup_push) UNIMPLEMENTED(__builtin_isinff)
UNIMPLEMENTED(pthread_cleanup_pop) UNIMPLEMENTED(__builtin_isinfl)
UNIMPLEMENTED(pthread_self) UNIMPLEMENTED(__builtin_malloc)
UNIMPLEMENTED(__floatditf) UNIMPLEMENTED(__divtf3)
UNIMPLEMENTED(__floatsitf) UNIMPLEMENTED(__eqtf2)
UNIMPLEMENTED(__extenddftf2)
UNIMPLEMENTED(__extendsftf2)
UNIMPLEMENTED(__fixsfti)
UNIMPLEMENTED(__fixtfdi) UNIMPLEMENTED(__fixtfdi)
UNIMPLEMENTED(__fixtfsi) UNIMPLEMENTED(__fixtfsi)
UNIMPLEMENTED(__fixsfti) UNIMPLEMENTED(__fixunstfsi)
UNIMPLEMENTED(__netf2) UNIMPLEMENTED(__floatditf)
UNIMPLEMENTED(__floatsitf)
UNIMPLEMENTED(__floatunsitf)
UNIMPLEMENTED(__getf2) UNIMPLEMENTED(__getf2)
UNIMPLEMENTED(__eqtf2) UNIMPLEMENTED(__letf2)
UNIMPLEMENTED(__lttf2) UNIMPLEMENTED(__lttf2)
UNIMPLEMENTED(__addtf3)
UNIMPLEMENTED(__subtf3)
UNIMPLEMENTED(__divtf3)
UNIMPLEMENTED(__multf3) UNIMPLEMENTED(__multf3)
UNIMPLEMENTED(__multi3) UNIMPLEMENTED(__multi3)
UNIMPLEMENTED(__lock) UNIMPLEMENTED(__netf2)
UNIMPLEMENTED(__unlock) UNIMPLEMENTED(__subtf3)
UNIMPLEMENTED(__syscall6) // sys_close
UNIMPLEMENTED(__syscall140) // sys_llseek UNIMPLEMENTED(__syscall140) // sys_llseek
UNIMPLEMENTED(__syscall221) // sys_fcntl64
UNIMPLEMENTED(__trunctfdf2)
UNIMPLEMENTED(__trunctfsf2)
UNIMPLEMENTED(__unordtf2) UNIMPLEMENTED(__unordtf2)
UNIMPLEMENTED(__fixunstfsi) UNIMPLEMENTED(longjmp)
UNIMPLEMENTED(__floatunsitf) UNIMPLEMENTED(pthread_cleanup_pop)
UNIMPLEMENTED(__extenddftf2) UNIMPLEMENTED(pthread_cleanup_push)
UNIMPLEMENTED(pthread_self)
void *wasmPtr(uint32_t Index) { UNIMPLEMENTED(setjmp)
if (pageNum(Index) < WASM_NUM_PAGES) {
return WASM_MEMORY + Index;
}
abort();
}
extern int __szwasm_main(int, const char **); extern int __szwasm_main(int, WasmPtr<WasmCharPtr>);
#define WASM_REF(Type, Index) ((Type *)wasmPtr(Index)) #define WASM_REF(Type, Index) (WasmPtr<Type>(Index).asPtr())
#define WASM_DEREF(Type, Index) (*WASM_REF(Type, Index)) #define WASM_DEREF(Type, Index) (*WASM_REF(Type, Index))
int main(int argc, const char **argv) { int main(int argc, const char **argv) {
// TODO (eholk): align these allocations correctly.
// Allocate space for the global data.
HeapBreak = WASM_DATA_SIZE;
GlobalData = WASM_REF(WasmData, HeapBreak);
HeapBreak += sizeof(WasmData);
// copy the command line arguments.
WasmPtr<WasmCharPtr> WasmArgV = HeapBreak;
WasmPtr<char> *WasmArgVPtr = WasmArgV.asPtr();
HeapBreak += argc * sizeof(*WasmArgVPtr);
for (int i = 0; i < argc; ++i) {
WasmArgVPtr[i] = HeapBreak;
strcpy(WASM_REF(char, HeapBreak), argv[i]);
HeapBreak += strlen(argv[i]) + 1;
}
// Initialize the break to the nearest page boundary after the data segment // Initialize the break to the nearest page boundary after the data segment
HeapBreak = (WASM_DATA_SIZE + PageSize - 1) & ~(PageSize - 1); HeapBreak = (WASM_DATA_SIZE + PageSize - 1) & ~(PageSize - 1);
// Initialize the stack pointer. // Initialize the stack pointer.
WASM_DEREF(int32_t, StackPtrLoc) = WASM_NUM_PAGES << PageSizeLog2; WASM_DEREF(int32_t, StackPtrLoc) = WASM_NUM_PAGES << PageSizeLog2;
return __szwasm_main(argc, argv); return __szwasm_main(argc, WasmArgV);
}
int env$$abs(int a) {
TRACE_ENTRY();
return trace(abs(a));
}
clock_t env$$clock() {
TRACE_ENTRY();
return trace(clock());
}
int env$$ctime(WasmPtr<time_t> Time) {
TRACE_ENTRY();
char *CTime = ctime(Time.asPtr());
strncpy(GlobalData->StrBuf, CTime, sizeof(GlobalData->StrBuf));
GlobalData->StrBuf[sizeof(GlobalData->StrBuf) - 1] = '\0';
return trace(WasmPtr<char>(GlobalData->StrBuf).asInt());
} }
int env$$abs(int a) { return abs(a); } double env$$pow(double x, double y) {
TRACE_ENTRY();
return trace(pow(x, y));
}
double env$$pow(double x, double y) { return pow(x, y); } time_t env$$time(WasmPtr<time_t> Time) {
TRACE_ENTRY();
time_t *TimePtr = WASM_REF(time_t, Time);
return trace(time(TimePtr));
}
// lock and unlock are no-ops in wasm.js, so we mimic that behavior.
void env$$__lock(int32_t) {
TRACE_ENTRY();
trace();
}
void env$$__unlock(int32_t) {
TRACE_ENTRY();
trace();
}
/// sys_read
int env$$__syscall3(int Which, WasmArray<int> VarArgs) {
TRACE_ENTRY();
int Fd = VarArgs[0];
int Buffer = VarArgs[1];
int Length = VarArgs[2];
return trace(read(Fd, WASM_REF(char *, Buffer), Length));
}
/// sys_write /// sys_write
int env$$__syscall4(int Which, int VarArgs) { int env$$__syscall4(int Which, WasmArray<int> VarArgs) {
int Fd = WASM_DEREF(int, VarArgs + 0 * sizeof(int)); TRACE_ENTRY();
int Buffer = WASM_DEREF(int, VarArgs + 1 * sizeof(int)); int Fd = VarArgs[0];
int Length = WASM_DEREF(int, VarArgs + 2 * sizeof(int)); int Buffer = VarArgs[1];
int Length = VarArgs[2];
return write(Fd, WASM_REF(char *, Buffer), Length); return trace(write(Fd, WASM_REF(char *, Buffer), Length));
} }
/// sys_open /// sys_open
int env$$__syscall5(int Which, int VarArgs) { int env$$__syscall5(int Which, WasmArray<int> VarArgs) {
int WasmPath = WASM_DEREF(int, VarArgs); TRACE_ENTRY();
int Flags = WASM_DEREF(int, VarArgs + 4); int WasmPath = VarArgs[0];
int Mode = WASM_DEREF(int, VarArgs + 8); int Flags = VarArgs[1];
int Mode = VarArgs[2];
const char *Path = WASM_REF(char, WasmPath); const char *Path = WASM_REF(char, WasmPath);
fprintf(stderr, "sys_open(%s, %d, %d)\n", Path, Flags, Mode); return trace(open(Path, Flags, Mode));
}
return open(Path, Flags, Mode); /// sys_close
int env$$__syscall6(int Which, WasmArray<int> VarArgs) {
TRACE_ENTRY();
int Fd = VarArgs[0];
return trace(close(Fd));
}
/// sys_unlink
int env$$__syscall10(int Which, WasmArray<int> VarArgs) {
TRACE_ENTRY();
int WasmPath = VarArgs[0];
const char *Path = WASM_REF(char, WasmPath);
return trace(unlink(Path));
} }
/// sys_getpid /// sys_getpid
int env$$__syscall20(int Which, int VarArgs) { int env$$__syscall20(int Which, WasmArray<int> VarArgs) {
TRACE_ENTRY();
(void)Which; (void)Which;
(void)VarArgs; (void)VarArgs;
return getpid(); return trace(getpid());
}
/// sys_rmdir
int env$$__syscall40(int Which, WasmArray<int> VarArgs) {
TRACE_ENTRY();
int WasmPath = VarArgs[0];
const char *Path = WASM_REF(char, WasmPath);
return trace(rmdir(Path));
} }
/// sys_ioctl /// sys_ioctl
int env$$__syscall54(int A, int B) { int env$$__syscall54(int Which, WasmArray<int> VarArgs) {
int Fd = WASM_DEREF(int, B + 0 * sizeof(int)); TRACE_ENTRY();
int Op = WASM_DEREF(int, B + 1 * sizeof(int)); int Fd = VarArgs[0];
int ArgP = WASM_DEREF(int, B + 2 * sizeof(int)); int Op = VarArgs[1];
// TODO (eholk): implement sys_ioctl int ArgP = VarArgs[2];
return -ENOTTY;
switch (Op) {
case TCGETS: {
// struct termios has no pointers. Otherwise, we'd have to rewrite them.
struct termios *TermIOS = WASM_REF(struct termios, ArgP);
return trace(ioctl(Fd, TCGETS, TermIOS));
}
default:
// TODO (eholk): implement more ioctls
return trace(-ENOTTY);
}
} }
/// sys_write struct IoVec {
int env$$__syscall146(int Which, int VarArgs) { WasmPtr<char> Ptr;
int Length;
};
int Fd = WASM_DEREF(int, VarArgs); /// sys_readv
int Iov = WASM_DEREF(int, VarArgs + sizeof(int)); int env$$__syscall145(int Which, WasmArray<int> VarArgs) {
int Iovcnt = WASM_DEREF(int, VarArgs + 2 * sizeof(int)); TRACE_ENTRY();
int Fd = VarArgs[0];
WasmArray<IoVec> Iov = VarArgs[1];
int Iovcnt = VarArgs[2];
int Count = 0; int Count = 0;
for (int I = 0; I < Iovcnt; ++I) { for (int I = 0; I < Iovcnt; ++I) {
void *Ptr = WASM_REF(void, WASM_DEREF(int, Iov + I * 8)); int Curr = read(Fd, Iov[I].Ptr.asPtr(), Iov[I].Length);
int Length = WASM_DEREF(int, Iov + I * 8 + 4);
if (Curr < 0) {
return trace(-1);
}
Count += Curr;
}
return trace(Count);
}
int Curr = write(Fd, Ptr, Length); /// sys_writev
int env$$__syscall146(int Which, WasmArray<int> VarArgs) {
TRACE_ENTRY();
int Fd = VarArgs[0];
WasmArray<IoVec> Iov = VarArgs[1];
int Iovcnt = VarArgs[2];
int Count = 0;
for (int I = 0; I < Iovcnt; ++I) {
int Curr = write(Fd, Iov[I].Ptr.asPtr(), Iov[I].Length);
if (Curr < 0) { if (Curr < 0) {
return -1; return trace(-1);
} }
Count += Curr; Count += Curr;
} }
return Count; return trace(Count);
} }
/// sys_mmap_pgoff /// sys_mmap_pgoff
int env$$__syscall192(int Which, int VarArgs) { int env$$__syscall192(int Which, WasmArray<int> VarArgs) {
TRACE_ENTRY();
(void)Which; (void)Which;
(void)VarArgs; (void)VarArgs;
// TODO (eholk): figure out how to implement this. // TODO (eholk): figure out how to implement this.
return -ENOMEM; return trace(-ENOMEM);
} }
} // end of extern "C" } // end of extern "C"
...@@ -56,7 +56,7 @@ bool llvmIRInput(const std::string &Filename) { ...@@ -56,7 +56,7 @@ bool llvmIRInput(const std::string &Filename) {
} }
bool wasmInput(const std::string &Filename) { bool wasmInput(const std::string &Filename) {
return BuildDefs::llvmIrAsInput() && return BuildDefs::wasm() &&
std::regex_match(Filename, std::regex(".*\\.wasm")); std::regex_match(Filename, std::regex(".*\\.wasm"));
} }
......
...@@ -680,6 +680,7 @@ public: ...@@ -680,6 +680,7 @@ public:
<< ") = "); << ") = ");
Ice::Variable *Dest = nullptr; Ice::Variable *Dest = nullptr;
switch (Opcode) { switch (Opcode) {
// TODO (eholk): merge these next two cases using getConstantInteger
case kExprI32Eqz: { case kExprI32Eqz: {
Dest = makeVariable(IceType_i32); Dest = makeVariable(IceType_i32);
auto *Tmp = makeVariable(IceType_i1); auto *Tmp = makeVariable(IceType_i1);
...@@ -772,6 +773,34 @@ public: ...@@ -772,6 +773,34 @@ public:
Control()->appendInst(Call); Control()->appendInst(Call);
break; break;
} }
case kExprF32Sqrt: {
Dest = makeVariable(IceType_f32);
const auto FnName = Ctx->getGlobalString("llvm.sqrt.f32");
bool BadInstrinsic = false;
const auto *Info = Ctx->getIntrinsicsInfo().find(FnName, BadInstrinsic);
assert(!BadInstrinsic);
assert(Info);
auto *Call = InstIntrinsicCall::create(
Func, 1, Dest, Ctx->getConstantExternSym(FnName), Info->Info);
Call->addArg(Input);
Control()->appendInst(Call);
break;
}
case kExprF64Sqrt: {
Dest = makeVariable(IceType_f64);
const auto FnName = Ctx->getGlobalString("llvm.sqrt.f64");
bool BadInstrinsic = false;
const auto *Info = Ctx->getIntrinsicsInfo().find(FnName, BadInstrinsic);
assert(!BadInstrinsic);
assert(Info);
auto *Call = InstIntrinsicCall::create(
Func, 1, Dest, Ctx->getConstantExternSym(FnName), Info->Info);
Call->addArg(Input);
Control()->appendInst(Call);
break;
}
case kExprI64UConvertI32: case kExprI64UConvertI32:
Dest = makeVariable(IceType_i64); Dest = makeVariable(IceType_i64);
Control()->appendInst( Control()->appendInst(
...@@ -1065,7 +1094,7 @@ public: ...@@ -1065,7 +1094,7 @@ public:
assert(Module); assert(Module);
const auto &IndirectTable = Module->function_table; const auto &IndirectTable = Module->function_table;
auto *Abort = getAbortTarget(); auto *Abort = getIndirectFailTarget();
assert(Args[0].toOperand()); assert(Args[0].toOperand());
...@@ -1173,7 +1202,7 @@ public: ...@@ -1173,7 +1202,7 @@ public:
// terrible (see https://goo.gl/Zj7DTr). Try adding a new instruction that // terrible (see https://goo.gl/Zj7DTr). Try adding a new instruction that
// encapsulates this "abort if false" pattern. // encapsulates this "abort if false" pattern.
auto *CheckPassed = Func->makeNode(); auto *CheckPassed = Func->makeNode();
auto *CheckFailed = getAbortTarget(); auto *CheckFailed = getBoundsFailTarget();
auto *Check = makeVariable(IceType_i1); auto *Check = makeVariable(IceType_i1);
Control()->appendInst(InstIcmp::create(Func, InstIcmp::Ult, Check, Base, Control()->appendInst(InstIcmp::create(Func, InstIcmp::Ult, Check, Base,
...@@ -1281,7 +1310,8 @@ private: ...@@ -1281,7 +1310,8 @@ private:
class Cfg *Func; class Cfg *Func;
GlobalContext *Ctx; GlobalContext *Ctx;
CfgNode *AbortTarget = nullptr; CfgNode *BoundsFailTarget = nullptr;
CfgNode *IndirectFailTarget = nullptr;
SizeT NextArg = 0; SizeT NextArg = 0;
...@@ -1319,16 +1349,33 @@ private: ...@@ -1319,16 +1349,33 @@ private:
return Iter->second; return Iter->second;
} }
CfgNode *getAbortTarget() { CfgNode *getBoundsFailTarget() {
if (!AbortTarget) { if (!BoundsFailTarget) {
// TODO (eholk): Move this node to the end of the CFG, or even better,
// have only one abort block for the whole module.
BoundsFailTarget = Func->makeNode();
BoundsFailTarget->appendInst(InstCall::create(
Func, 0, nullptr,
Ctx->getConstantExternSym(Ctx->getGlobalString("__Sz_bounds_fail")),
false));
BoundsFailTarget->appendInst(InstUnreachable::create(Func));
}
return BoundsFailTarget;
}
CfgNode *getIndirectFailTarget() {
if (!IndirectFailTarget) {
// TODO (eholk): Move this node to the end of the CFG, or even better, // TODO (eholk): Move this node to the end of the CFG, or even better,
// have only one abort block for the whole module. // have only one abort block for the whole module.
AbortTarget = Func->makeNode(); IndirectFailTarget = Func->makeNode();
// TODO (eholk): This should probably actually call abort instead. IndirectFailTarget->appendInst(InstCall::create(
AbortTarget->appendInst(InstUnreachable::create(Func)); Func, 0, nullptr,
Ctx->getConstantExternSym(Ctx->getGlobalString("__Sz_indirect_fail")),
false));
IndirectFailTarget->appendInst(InstUnreachable::create(Func));
} }
return AbortTarget; return IndirectFailTarget;
} }
template <typename F = std::function<void(Ostream &)>> void log(F Fn) const { template <typename F = std::function<void(Ostream &)>> void log(F Fn) const {
...@@ -1364,13 +1411,10 @@ std::unique_ptr<Cfg> WasmTranslator::translateFunction(Zone *Zone, ...@@ -1364,13 +1411,10 @@ std::unique_ptr<Cfg> WasmTranslator::translateFunction(Zone *Zone,
return Func; return Func;
} }
// TODO(eholk): compute the correct buffer size. This uses 256k by default, constexpr SizeT InitialBufferSize = 16 << 10; // 16KB
// which has been big enough for testing but is not a general solution.
constexpr SizeT BufferSize = 256 << 10;
WasmTranslator::WasmTranslator(GlobalContext *Ctx) WasmTranslator::WasmTranslator(GlobalContext *Ctx)
: Translator(Ctx), Buffer(new uint8_t[ ::BufferSize]), : Translator(Ctx), Buffer(InitialBufferSize) {}
BufferSize(::BufferSize) {}
void WasmTranslator::translate( void WasmTranslator::translate(
const std::string &IRFilename, const std::string &IRFilename,
...@@ -1380,16 +1424,22 @@ void WasmTranslator::translate( ...@@ -1380,16 +1424,22 @@ void WasmTranslator::translate(
Zone Zone; Zone Zone;
ZoneScope _(&Zone); ZoneScope _(&Zone);
SizeT BytesRead = InputStream->GetBytes(Buffer.get(), BufferSize); SizeT BytesRead = 0;
LOG(out << "Read " << BytesRead << " bytes" while (true) {
<< "\n"); BytesRead +=
assert(BytesRead < BufferSize); InputStream->GetBytes(&Buffer[BytesRead], Buffer.size() - BytesRead);
LOG(out << "Read " << BytesRead << " bytes"
<< "\n");
if (BytesRead < Buffer.size())
break;
Buffer.resize(Buffer.size() * 2);
}
LOG(out << "Decoding module " << IRFilename << "\n"); LOG(out << "Decoding module " << IRFilename << "\n");
constexpr v8::internal::Isolate *NoIsolate = nullptr; constexpr v8::internal::Isolate *NoIsolate = nullptr;
auto Result = DecodeWasmModule(NoIsolate, &Zone, Buffer.get(), auto Result = DecodeWasmModule(NoIsolate, &Zone, Buffer.data(),
Buffer.get() + BytesRead, false, kWasmOrigin); Buffer.data() + BytesRead, false, kWasmOrigin);
auto Module = Result.val; auto Module = Result.val;
...@@ -1540,9 +1590,9 @@ void WasmTranslator::translate( ...@@ -1540,9 +1590,9 @@ void WasmTranslator::translate(
LOG(out << " " << Fn.func_index << ": " << FnName << "..."); LOG(out << " " << Fn.func_index << ": " << FnName << "...");
Body.sig = Fn.sig; Body.sig = Fn.sig;
Body.base = Buffer.get(); Body.base = Buffer.data();
Body.start = Buffer.get() + Fn.code_start_offset; Body.start = Buffer.data() + Fn.code_start_offset;
Body.end = Buffer.get() + Fn.code_end_offset; Body.end = Buffer.data() + Fn.code_end_offset;
auto Func = translateFunction(&Zone, Body); auto Func = translateFunction(&Zone, Body);
Func->setFunctionName(Ctx->getGlobalString(FnName)); Func->setFunctionName(Ctx->getGlobalString(FnName));
......
...@@ -70,8 +70,7 @@ public: ...@@ -70,8 +70,7 @@ public:
v8::internal::wasm::FunctionBody &Body); v8::internal::wasm::FunctionBody &Body);
private: private:
std::unique_ptr<uint8_t[]> Buffer; std::vector<uint8_t> Buffer;
SizeT BufferSize;
}; };
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment