summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/abi/js.h52
-rw-r--r--src/asmjs/shared-constants.cpp16
-rw-r--r--src/passes/I64ToI32Lowering.cpp59
-rw-r--r--src/passes/RemoveNonJSOps.cpp4
-rw-r--r--src/passes/wasm-intrinsics.wast29
-rw-r--r--src/wasm2js.h159
6 files changed, 237 insertions, 82 deletions
diff --git a/src/abi/js.h b/src/abi/js.h
index bcc7dbb6e..6994a4291 100644
--- a/src/abi/js.h
+++ b/src/abi/js.h
@@ -18,6 +18,7 @@
#define wasm_abi_abi_h
#include "wasm.h"
+#include "asmjs/shared-constants.h"
namespace wasm {
@@ -36,6 +37,57 @@ inline std::string getLegalizationPass(LegalizationLevel level) {
}
}
+namespace wasm2js {
+
+extern cashew::IString SCRATCH_LOAD_I32,
+ SCRATCH_STORE_I32,
+ SCRATCH_LOAD_I64,
+ SCRATCH_STORE_I64,
+ SCRATCH_LOAD_F32,
+ SCRATCH_STORE_F32,
+ SCRATCH_LOAD_F64,
+ SCRATCH_STORE_F64;
+
+// The wasm2js scratch memory helpers let us read and write to scratch memory
+// for purposes of implementing things like reinterpret, etc.
+// The optional "specific" parameter is a specific function we want. If not
+// provided, we create them all.
+inline void ensureScratchMemoryHelpers(Module* wasm, cashew::IString specific = cashew::IString()) {
+ auto ensureImport = [&](Name name, const std::vector<Type> params, Type result) {
+ if (wasm->getFunctionOrNull(name)) return;
+ if (specific.is() && name != specific) return;
+ auto func = make_unique<Function>();
+ func->name = name;
+ func->params = params;
+ func->result = result;
+ func->module = ENV;
+ func->base = name;
+ wasm->addFunction(std::move(func));
+ };
+
+ ensureImport(SCRATCH_LOAD_I32, { i32 }, i32);
+ ensureImport(SCRATCH_STORE_I32, { i32, i32 }, none);
+ ensureImport(SCRATCH_LOAD_I64, {}, i64);
+ ensureImport(SCRATCH_STORE_I64, { i64 }, none);
+ ensureImport(SCRATCH_LOAD_F32, {}, f32);
+ ensureImport(SCRATCH_STORE_F32, { f32 }, none);
+ ensureImport(SCRATCH_LOAD_F64, {}, f64);
+ ensureImport(SCRATCH_STORE_F64, { f64 }, none);
+}
+
+inline bool isScratchMemoryHelper(cashew::IString name) {
+ return name == SCRATCH_LOAD_I32 ||
+ name == SCRATCH_STORE_I32 ||
+ name == SCRATCH_LOAD_I64 ||
+ name == SCRATCH_STORE_I64 ||
+ name == SCRATCH_LOAD_F32 ||
+ name == SCRATCH_STORE_F32 ||
+ name == SCRATCH_LOAD_F64 ||
+ name == SCRATCH_STORE_F64;
+}
+
+} // namespace wasm2js
+
} // namespace ABI
} // namespace wasm
diff --git a/src/asmjs/shared-constants.cpp b/src/asmjs/shared-constants.cpp
index 0cf3668b1..ec04b63e7 100644
--- a/src/asmjs/shared-constants.cpp
+++ b/src/asmjs/shared-constants.cpp
@@ -102,4 +102,20 @@ cashew::IString GLOBAL("global"),
WASM_I64_UDIV("__wasm_i64_udiv"),
WASM_I64_SREM("__wasm_i64_srem"),
WASM_I64_UREM("__wasm_i64_urem");
+
+namespace ABI {
+namespace wasm2js {
+
+cashew::IString SCRATCH_LOAD_I32("wasm2js_scratch_load_i32"),
+ SCRATCH_STORE_I32("wasm2js_scratch_store_i32"),
+ SCRATCH_LOAD_I64("wasm2js_scratch_load_i64"),
+ SCRATCH_STORE_I64("wasm2js_scratch_store_i64"),
+ SCRATCH_LOAD_F32("wasm2js_scratch_load_f32"),
+ SCRATCH_STORE_F32("wasm2js_scratch_store_f32"),
+ SCRATCH_LOAD_F64("wasm2js_scratch_load_f64"),
+ SCRATCH_STORE_F64("wasm2js_scratch_store_f64");
+
+} // namespace wasm2js
+} // namespace ABI
+
}
diff --git a/src/passes/I64ToI32Lowering.cpp b/src/passes/I64ToI32Lowering.cpp
index 33bb7229e..e6dc90607 100644
--- a/src/passes/I64ToI32Lowering.cpp
+++ b/src/passes/I64ToI32Lowering.cpp
@@ -27,6 +27,7 @@
#include "emscripten-optimizer/istring.h"
#include "support/name.h"
#include "wasm-builder.h"
+#include "abi/js.h"
#include "ir/flat.h"
#include "ir/iteration.h"
#include "ir/memory-utils.h"
@@ -337,25 +338,30 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
template<typename T>
using BuilderFunc = std::function<T*(std::vector<Expression*>&, Type)>;
+ // Fixes up a call. If we performed fixups, returns the call; otherwise returns nullptr;
template<typename T>
- void visitGenericCall(T* curr, BuilderFunc<T> callBuilder) {
+ T* visitGenericCall(T* curr, BuilderFunc<T> callBuilder) {
+ bool fixed = false;
std::vector<Expression*> args;
for (auto* e : curr->operands) {
args.push_back(e);
if (hasOutParam(e)) {
TempVar argHighBits = fetchOutParam(e);
args.push_back(builder->makeGetLocal(argHighBits, i32));
+ fixed = true;
}
}
if (curr->type != i64) {
- replaceCurrent(callBuilder(args, curr->type));
- return;
+ auto* ret = callBuilder(args, curr->type);
+ replaceCurrent(ret);
+ return fixed ? ret : nullptr;
}
TempVar lowBits = getTemp();
TempVar highBits = getTemp();
+ auto* call = callBuilder(args, i32);
SetLocal* doCall = builder->makeSetLocal(
lowBits,
- callBuilder(args, i32)
+ call
);
SetLocal* setHigh = builder->makeSetLocal(
highBits,
@@ -365,14 +371,21 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
Block* result = builder->blockify(doCall, setHigh, getLow);
setOutParam(result, std::move(highBits));
replaceCurrent(result);
+ return call;
}
void visitCall(Call* curr) {
- visitGenericCall<Call>(
+ auto* fixedCall = visitGenericCall<Call>(
curr,
[&](std::vector<Expression*>& args, Type ty) {
return builder->makeCall(curr->target, args, ty);
}
);
+ // If this was to an import, we need to call the legal version. This assumes
+ // that legalize-js-interface has been run before.
+ if (fixedCall && getModule()->getFunction(fixedCall->target)->imported()) {
+ fixedCall->target = std::string("legalfunc$") + fixedCall->target.str;
+ return;
+ }
}
void visitCallIndirect(CallIndirect* curr) {
@@ -635,17 +648,17 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
// our f64 through memory at address 0
TempVar highBits = getTemp();
Block *result = builder->blockify(
- builder->makeStore(8, 0, 8, makeGetTempMemory(), curr->value, f64),
+ builder->makeCall(ABI::wasm2js::SCRATCH_STORE_F64, { curr->value }, none),
builder->makeSetLocal(
highBits,
- builder->makeLoad(4, true, 4, 4, makeGetTempMemory(), i32)
+ builder->makeCall(ABI::wasm2js::SCRATCH_LOAD_I32, { builder->makeConst(Literal(int32_t(1))) }, i32)
),
- builder->makeLoad(4, true, 0, 4, makeGetTempMemory(), i32)
+ builder->makeCall(ABI::wasm2js::SCRATCH_LOAD_I32, { builder->makeConst(Literal(int32_t(0))) }, i32)
);
setOutParam(result, std::move(highBits));
replaceCurrent(result);
MemoryUtils::ensureExists(getModule()->memory);
- ensureTempMemoryGlobal();
+ ABI::wasm2js::ensureScratchMemoryHelpers(getModule());
}
void lowerReinterpretInt64(Unary* curr) {
@@ -653,33 +666,13 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
// our i64 through memory at address 0
TempVar highBits = fetchOutParam(curr->value);
Block *result = builder->blockify(
- builder->makeStore(4, 0, 4, makeGetTempMemory(), curr->value, i32),
- builder->makeStore(4, 4, 4, makeGetTempMemory(), builder->makeGetLocal(highBits, i32), i32),
- builder->makeLoad(8, true, 0, 8, makeGetTempMemory(), f64)
+ builder->makeCall(ABI::wasm2js::SCRATCH_STORE_I32, { builder->makeConst(Literal(int32_t(0))), curr->value }, none),
+ builder->makeCall(ABI::wasm2js::SCRATCH_STORE_I32, { builder->makeConst(Literal(int32_t(1))), builder->makeGetLocal(highBits, i32) }, none),
+ builder->makeCall(ABI::wasm2js::SCRATCH_LOAD_F64, {}, f64)
);
replaceCurrent(result);
MemoryUtils::ensureExists(getModule()->memory);
- ensureTempMemoryGlobal();
- }
-
- Name tempMemory = "__tempMemory__";
-
- void ensureTempMemoryGlobal() {
- // Ensure the existence of an imported global, __tempMemory__, which points to 8
- // bytes of scratch memory we can use for roundtrip purposes.
- if (!getModule()->getGlobalOrNull(tempMemory)) {
- auto global = make_unique<Global>();
- global->name = tempMemory;
- global->type = i32;
- global->mutable_ = false;
- global->module = ENV;
- global->base = tempMemory;
- getModule()->addGlobal(global.release());
- }
- }
-
- Expression* makeGetTempMemory() {
- return builder->makeGetGlobal(tempMemory, i32);
+ ABI::wasm2js::ensureScratchMemoryHelpers(getModule());
}
void lowerTruncFloatToInt(Unary *curr) {
diff --git a/src/passes/RemoveNonJSOps.cpp b/src/passes/RemoveNonJSOps.cpp
index 906c34bc4..fc3e42185 100644
--- a/src/passes/RemoveNonJSOps.cpp
+++ b/src/passes/RemoveNonJSOps.cpp
@@ -33,6 +33,7 @@
#include "asmjs/shared-constants.h"
#include "wasm-builder.h"
#include "wasm-s-parser.h"
+#include "abi/js.h"
#include "ir/memory-utils.h"
#include "ir/module-utils.h"
#include "ir/find_all.h"
@@ -50,6 +51,9 @@ struct RemoveNonJSOpsPass : public WalkerPass<PostWalker<RemoveNonJSOpsPass>> {
Pass* create() override { return new RemoveNonJSOpsPass; }
void doWalkModule(Module* module) {
+ // Intrinsics may use scratch memory, ensure it.
+ ABI::wasm2js::ensureScratchMemoryHelpers(module);
+
// Discover all of the intrinsics that we need to inject, lowering all
// operations to intrinsic calls while we're at it.
if (!builder) builder = make_unique<Builder>(*module);
diff --git a/src/passes/wasm-intrinsics.wast b/src/passes/wasm-intrinsics.wast
index a8ee5be0b..f54547a0d 100644
--- a/src/passes/wasm-intrinsics.wast
+++ b/src/passes/wasm-intrinsics.wast
@@ -7,8 +7,8 @@
;;
;; LOCAL MODS done by hand afterwards:
;; * Remove hardcoded address 1024 (apparently a free memory location rustc
-;; thinks is ok to use?); add a global __tempMemory__ which is used for that
-;; purpose.
+;; thinks is ok to use?); add intrinsic functions, which load/store to
+;; special scratch space, wasm2js_scratch_load_i32 etc.
;; * Fix function type of __wasm_ctz_i64, which was wrong somehow,
;; i32, i32 => i32 instead of i64 => i64
;;
@@ -22,7 +22,8 @@
(type $4 (func (param i32 i32) (result i32)))
(type $5 (func (param i64) (result i64)))
(import "env" "memory" (memory $0 17))
- (import "env" "__tempMemory__" (global $__tempMemory__ i32))
+ (import "env" "wasm2js_scratch_load_i64" (func $wasm2js_scratch_load_i64 (result i64)))
+ (import "env" "wasm2js_scratch_store_i64" (func $wasm2js_scratch_store_i64 (param i64)))
(export "__wasm_i64_sdiv" (func $__wasm_i64_sdiv))
(export "__wasm_i64_udiv" (func $__wasm_i64_udiv))
(export "__wasm_i64_srem" (func $__wasm_i64_srem))
@@ -136,9 +137,7 @@
(local.get $var$1)
)
)
- (i64.load
- (global.get $__tempMemory__)
- )
+ (call $wasm2js_scratch_load_i64)
)
;; lowering of the i64.mul instruction, return $var0 * $var$1
(func $__wasm_i64_mul (; 4 ;) (type $0) (param $var$0 i64) (param $var$1 i64) (result i64)
@@ -579,8 +578,7 @@
(i64.const 4294967296)
)
)
- (i64.store
- (global.get $__tempMemory__)
+ (call $wasm2js_scratch_store_i64
(i64.extend_i32_u
(i32.sub
(local.tee $var$2
@@ -641,8 +639,7 @@
(local.get $var$3)
)
)
- (i64.store
- (global.get $__tempMemory__)
+ (call $wasm2js_scratch_store_i64
(i64.or
(i64.shl
(i64.extend_i32_u
@@ -722,8 +719,7 @@
)
(br $label$3)
)
- (i64.store
- (global.get $__tempMemory__)
+ (call $wasm2js_scratch_store_i64
(i64.shl
(i64.extend_i32_u
(i32.sub
@@ -765,8 +761,7 @@
)
(br $label$2)
)
- (i64.store
- (global.get $__tempMemory__)
+ (call $wasm2js_scratch_store_i64
(i64.extend_i32_u
(i32.and
(local.get $var$4)
@@ -897,8 +892,7 @@
)
)
)
- (i64.store
- (global.get $__tempMemory__)
+ (call $wasm2js_scratch_store_i64
(local.get $var$5)
)
(return
@@ -911,8 +905,7 @@
)
)
)
- (i64.store
- (global.get $__tempMemory__)
+ (call $wasm2js_scratch_store_i64
(local.get $var$0)
)
(local.set $var$0
diff --git a/src/wasm2js.h b/src/wasm2js.h
index faad6c3fa..311f8be10 100644
--- a/src/wasm2js.h
+++ b/src/wasm2js.h
@@ -34,6 +34,7 @@
#include "emscripten-optimizer/optimizer.h"
#include "mixed_arena.h"
#include "asm_v_wasm.h"
+#include "abi/js.h"
#include "ir/import-utils.h"
#include "ir/load-utils.h"
#include "ir/module-utils.h"
@@ -288,6 +289,10 @@ private:
};
Ref Wasm2JSBuilder::processWasm(Module* wasm, Name funcName) {
+ // Ensure the scratch memory helpers.
+ // If later on they aren't needed, we'll clean them up.
+ ABI::wasm2js::ensureScratchMemoryHelpers(wasm);
+
PassRunner runner(wasm);
runner.add<AutoDrop>();
runner.add("legalize-js-interface");
@@ -485,6 +490,10 @@ void Wasm2JSBuilder::addBasics(Ref ast) {
}
void Wasm2JSBuilder::addFunctionImport(Ref ast, Function* import) {
+ // The scratch memory helpers are emitted in the glue, see code and comments below.
+ if (ABI::wasm2js::isScratchMemoryHelper(import->base)) {
+ return;
+ }
Ref theVar = ValueBuilder::makeVar();
ast->push_back(theVar);
Ref module = ValueBuilder::makeName(ENV); // TODO: handle nested module imports
@@ -1194,12 +1203,7 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, IString resul
return ValueBuilder::makeSeq(ptrSet, rest);
}
// normal load
- Ref ptr = visit(curr->ptr, EXPRESSION_RESULT);
- if (curr->offset) {
- ptr = makeAsmCoercion(
- ValueBuilder::makeBinary(ptr, PLUS, ValueBuilder::makeNum(curr->offset)),
- ASM_INT);
- }
+ Ref ptr = makePointer(curr->ptr, curr->offset);
Ref ret;
switch (curr->type) {
case i32: {
@@ -1322,10 +1326,7 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, IString resul
return ValueBuilder::makeSeq(ValueBuilder::makeSeq(ptrSet, valueSet), rest);
}
// normal store
- Ref ptr = visit(curr->ptr, EXPRESSION_RESULT);
- if (curr->offset) {
- ptr = makeAsmCoercion(ValueBuilder::makeBinary(ptr, PLUS, ValueBuilder::makeNum(curr->offset)), ASM_INT);
- }
+ Ref ptr = makePointer(curr->ptr, curr->offset);
Ref value = visit(curr->value, EXPRESSION_RESULT);
Ref ret;
switch (curr->valueType) {
@@ -1419,20 +1420,15 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, IString resul
EXPRESSION_RESULT), ASM_INT), EQ,
makeAsmCoercion(ValueBuilder::makeInt(0), ASM_INT));
case ReinterpretFloat32: {
- // Naively assume that the address 0 and the next 4 bytes are
- // permanently unused by the source program, which is definitely
- // true for languages like C/C++/Rust
- Ref zero = ValueBuilder::makeInt(0);
- Ref ret = ValueBuilder::makeSub(ValueBuilder::makeName(HEAPF32), zero);
- Ref value = visit(curr->value, EXPRESSION_RESULT);
- Ref store = ValueBuilder::makeBinary(ret, SET, value);
- return ValueBuilder::makeSeq(
- store,
- makeAsmCoercion(
- ValueBuilder::makeSub(ValueBuilder::makeName(HEAP32), zero),
- ASM_INT
- )
+ ABI::wasm2js::ensureScratchMemoryHelpers(module, ABI::wasm2js::SCRATCH_STORE_F32);
+ ABI::wasm2js::ensureScratchMemoryHelpers(module, ABI::wasm2js::SCRATCH_LOAD_I32);
+
+ Ref store = ValueBuilder::makeCall(
+ ABI::wasm2js::SCRATCH_STORE_F32,
+ visit(curr->value, EXPRESSION_RESULT)
);
+ Ref load = ValueBuilder::makeCall(ABI::wasm2js::SCRATCH_LOAD_I32, ValueBuilder::makeInt(0));
+ return ValueBuilder::makeSeq(store, load);
}
// generate (~~expr), what Emscripten does
case TruncSFloat32ToInt32:
@@ -1512,15 +1508,16 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, IString resul
return makeAsmCoercion(visit(curr->value, EXPRESSION_RESULT),
ASM_FLOAT);
case ReinterpretInt32: {
- // Like above, assume address 0 is unused.
- Ref zero = ValueBuilder::makeInt(0);
- Ref ret = ValueBuilder::makeSub(ValueBuilder::makeName(HEAP32), zero);
- Ref value = visit(curr->value, EXPRESSION_RESULT);
- Ref store = ValueBuilder::makeBinary(ret, SET, value);
- return ValueBuilder::makeSeq(
- store,
- ValueBuilder::makeSub(ValueBuilder::makeName(HEAPF32), zero)
+ ABI::wasm2js::ensureScratchMemoryHelpers(module, ABI::wasm2js::SCRATCH_STORE_I32);
+ ABI::wasm2js::ensureScratchMemoryHelpers(module, ABI::wasm2js::SCRATCH_LOAD_F32);
+
+ Ref store = ValueBuilder::makeCall(
+ ABI::wasm2js::SCRATCH_STORE_I32,
+ ValueBuilder::makeNum(0),
+ visit(curr->value, EXPRESSION_RESULT)
);
+ Ref load = ValueBuilder::makeCall(ABI::wasm2js::SCRATCH_LOAD_F32);
+ return ValueBuilder::makeSeq(store, load);
}
// Coerce the integer to a float as emscripten does
case ConvertSInt32ToFloat32:
@@ -1858,7 +1855,19 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, IString resul
Ref visitUnreachable(Unreachable* curr) {
return ValueBuilder::makeCall(ABORT_FUNC);
}
+
+ private:
+ Ref makePointer(Expression* ptr, Address offset) {
+ auto ret = visit(ptr, EXPRESSION_RESULT);
+ if (offset) {
+ ret = makeAsmCoercion(
+ ValueBuilder::makeBinary(ret, PLUS, ValueBuilder::makeNum(offset)),
+ ASM_INT);
+ }
+ return ret;
+ }
};
+
return ExpressionProcessor(this, m, func).visit(func->body, result);
}
@@ -2049,6 +2058,7 @@ private:
void emitPostES6();
void emitMemory(std::string buffer, std::string segmentWriter);
+ void emitScratchMemorySupport();
};
void Wasm2JSGlue::emitPre() {
@@ -2057,6 +2067,8 @@ void Wasm2JSGlue::emitPre() {
} else {
emitPreES6();
}
+
+ emitScratchMemorySupport();
}
void Wasm2JSGlue::emitPreEmscripten() {
@@ -2089,6 +2101,10 @@ void Wasm2JSGlue::emitPreES6() {
noteImport(import->module, import->base);
});
ModuleUtils::iterImportedFunctions(wasm, [&](Function* import) {
+ // The scratch memory helpers are emitted in the glue, see code and comments below.
+ if (ABI::wasm2js::isScratchMemoryHelper(import->base)) {
+ return;
+ }
noteImport(import->module, import->base);
});
@@ -2163,6 +2179,10 @@ void Wasm2JSGlue::emitPostES6() {
out << "abort:function() { throw new Error('abort'); }";
ModuleUtils::iterImportedFunctions(wasm, [&](Function* import) {
+ // The scratch memory helpers are emitted in the glue, see code and comments below.
+ if (ABI::wasm2js::isScratchMemoryHelper(import->base)) {
+ return;
+ }
out << "," << import->base.str;
});
out << "},mem" << moduleName.str << ");\n";
@@ -2234,6 +2254,83 @@ void Wasm2JSGlue::emitMemory(std::string buffer, std::string segmentWriter) {
<< "\");\n";
}
}
+
+void Wasm2JSGlue::emitScratchMemorySupport() {
+ // The scratch memory helpers are emitted here the glue. We may also want to
+ // emit them inline at some point. (The reason they are imports is so that
+ // they appear as "intrinsics" placeholders, and not normal functions that
+ // the optimizer might want to do something with.)
+ bool needScratchMemory = false;
+ ModuleUtils::iterImportedFunctions(wasm, [&](Function* import) {
+ if (ABI::wasm2js::isScratchMemoryHelper(import->base)) {
+ needScratchMemory = true;
+ }
+ });
+ if (!needScratchMemory) return;
+
+ out << R"(
+ var scratchBuffer = new ArrayBuffer(8);
+ var i32ScratchView = new Int32Array(scratchBuffer);
+ var f32ScratchView = new Float32Array(scratchBuffer);
+ var f64ScratchView = new Float64Array(scratchBuffer);
+ )";
+
+ ModuleUtils::iterImportedFunctions(wasm, [&](Function* import) {
+ if (import->base == ABI::wasm2js::SCRATCH_STORE_I32) {
+ out << R"(
+ function wasm2js_scratch_store_i32(index, value) {
+ i32ScratchView[index] = value;
+ }
+ )";
+ } else if (import->base == ABI::wasm2js::SCRATCH_LOAD_I32) {
+ out << R"(
+ function wasm2js_scratch_load_i32(index) {
+ return i32ScratchView[index];
+ }
+ )";
+ } else if (import->base == ABI::wasm2js::SCRATCH_STORE_I64) {
+ out << R"(
+ function legalimport$wasm2js_scratch_store_i64(low, high) {
+ i32ScratchView[0] = low;
+ i32ScratchView[1] = high;
+ }
+ )";
+ } else if (import->base == ABI::wasm2js::SCRATCH_LOAD_I64) {
+ out << R"(
+ function legalimport$wasm2js_scratch_load_i64() {
+ if (typeof setTempRet0 === 'function') setTempRet0(i32ScratchView[1]);
+ return i32ScratchView[0];
+ }
+ )";
+ } else if (import->base == ABI::wasm2js::SCRATCH_STORE_F32) {
+ out << R"(
+ function wasm2js_scratch_store_f32(value) {
+ f32ScratchView[0] = value;
+ }
+ )";
+ } else if (import->base == ABI::wasm2js::SCRATCH_LOAD_F32) {
+ out << R"(
+ function wasm2js_scratch_load_f32() {
+ return f32ScratchView[0];
+ }
+ )";
+ } else if (import->base == ABI::wasm2js::SCRATCH_STORE_F64) {
+ out << R"(
+ function wasm2js_scratch_store_f64(value) {
+ f64ScratchView[0] = value;
+ }
+ )";
+ } else if (import->base == ABI::wasm2js::SCRATCH_LOAD_F64) {
+ out << R"(
+ function wasm2js_scratch_load_f64() {
+ return f64ScratchView[0];
+ }
+ )";
+ }
+ });
+ out << '\n';
+}
+
} // namespace wasm
#endif // wasm_wasm2js_h