mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-05 01:37:00 +00:00
@@ -342,6 +342,10 @@ abs(Number x) noexcept
|
||||
Number
|
||||
power(Number const& f, unsigned n);
|
||||
|
||||
// logarithm with base 10
|
||||
Number
|
||||
lg(Number const& value);
|
||||
|
||||
// Returns f^(1/d)
|
||||
// Uses Newton–Raphson iterations until the result stops changing
|
||||
// to find the root of the polynomial g(x) = x^d - f
|
||||
|
||||
@@ -623,6 +623,48 @@ power(Number const& f, unsigned n)
|
||||
return r;
|
||||
}
|
||||
|
||||
// Continued fraction approximation of ln(x)
|
||||
static Number
|
||||
ln(Number const& x, unsigned iterations = 50)
|
||||
{
|
||||
if (x <= 0)
|
||||
throw std::runtime_error("Not positive value");
|
||||
|
||||
Number const z = (x - 1) / (x + 1);
|
||||
Number const zz = z * z;
|
||||
Number denom = Number(1, -10);
|
||||
|
||||
// Construct the fraction from the bottom up
|
||||
for (int i = iterations; i > 0; --i)
|
||||
{
|
||||
Number k(2 * i - 1);
|
||||
denom = k - (i * i * zz / denom);
|
||||
}
|
||||
|
||||
auto const r = 2 * z / denom;
|
||||
return r;
|
||||
}
|
||||
|
||||
Number
|
||||
lg(Number const& x)
|
||||
{
|
||||
static Number const ln10 = ln(Number(10));
|
||||
|
||||
if (x <= Number(10))
|
||||
{
|
||||
auto const r = ln(x) / ln10;
|
||||
return r;
|
||||
}
|
||||
|
||||
// ln(x) = ln(normX * 10^norm) = ln(normX) + norm * ln(10)
|
||||
int diffExp = 15 + x.exponent();
|
||||
Number const normalX = x / Number(1, diffExp); // (1 <= normalX < 10)
|
||||
auto const lnX = ln(normalX) + diffExp * ln10;
|
||||
|
||||
auto const r = lnX / ln10;
|
||||
return r;
|
||||
}
|
||||
|
||||
// Returns f^(1/d)
|
||||
// Uses Newton–Raphson iterations until the result stops changing
|
||||
// to find the non-negative root of the polynomial g(x) = x^d - f
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <xrpld/ledger/detail/ApplyViewBase.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
namespace test {
|
||||
|
||||
struct TestLedgerDataProvider : public HostFunctions
|
||||
@@ -378,6 +379,89 @@ public:
|
||||
#endif
|
||||
return msg.size() + sizeof(data);
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
traceFloat(std::string_view const& msg, Slice const& data) override
|
||||
{
|
||||
#ifdef DEBUG_OUTPUT
|
||||
auto& j = std::cerr;
|
||||
#else
|
||||
auto j = getJournal().trace();
|
||||
#endif
|
||||
auto const s = floatToString(data);
|
||||
j << "WAMR TRACE FLOAT: " << msg << " " << s;
|
||||
|
||||
#ifdef DEBUG_OUTPUT
|
||||
j << std::endl;
|
||||
#endif
|
||||
return msg.size() + s.size();
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromInt(int64_t x, int32_t mode) override
|
||||
{
|
||||
return floatFromIntImpl(x, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromUint(uint64_t x, int32_t mode) override
|
||||
{
|
||||
return floatFromUintImpl(x, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatSet(int64_t mantissa, int32_t exponent, int32_t mode) override
|
||||
{
|
||||
return floatSetImpl(mantissa, exponent, mode);
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
floatCompare(Slice const& x, Slice const& y) override
|
||||
{
|
||||
return floatCompareImpl(x, y);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatAdd(Slice const& x, Slice const& y, int32_t mode) override
|
||||
{
|
||||
return floatAddImpl(x, y, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatSubtract(Slice const& x, Slice const& y, int32_t mode) override
|
||||
{
|
||||
return floatSubtractImpl(x, y, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatMultiply(Slice const& x, Slice const& y, int32_t mode) override
|
||||
{
|
||||
return floatMultiplyImpl(x, y, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatDivide(Slice const& x, Slice const& y, int32_t mode) override
|
||||
{
|
||||
return floatDivideImpl(x, y, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatRoot(Slice const& x, int32_t n, int32_t mode) override
|
||||
{
|
||||
return floatRootImpl(x, n, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatPower(Slice const& x, int32_t n, int32_t mode) override
|
||||
{
|
||||
return floatPowerImpl(x, n, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatLog(Slice const& x, int32_t mode) override
|
||||
{
|
||||
return floatLogImpl(x, mode);
|
||||
}
|
||||
};
|
||||
|
||||
struct TestHostFunctionsSink : public TestHostFunctions
|
||||
|
||||
@@ -509,6 +509,31 @@ struct Wasm_test : public beast::unit_test::suite
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testFloat()
|
||||
{
|
||||
testcase("float point");
|
||||
|
||||
std::string const funcName("finish");
|
||||
|
||||
using namespace test::jtx;
|
||||
|
||||
Env env(*this);
|
||||
{
|
||||
std::string const wasmHex = floatHex;
|
||||
std::string const wasmStr = boost::algorithm::unhex(wasmHex);
|
||||
std::vector<uint8_t> const wasm(wasmStr.begin(), wasmStr.end());
|
||||
|
||||
TestHostFunctions hf(env, 0);
|
||||
auto re = runEscrowWasm(wasm, funcName, {}, &hf, 100'000);
|
||||
if (BEAST_EXPECT(re.has_value()))
|
||||
{
|
||||
BEAST_EXPECT(re->result && (re->cost == 91'412));
|
||||
}
|
||||
env.close();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
perfTest()
|
||||
{
|
||||
@@ -656,6 +681,7 @@ struct Wasm_test : public beast::unit_test::suite
|
||||
testHFCost();
|
||||
|
||||
testEscrowWasmDN();
|
||||
testFloat();
|
||||
|
||||
testCodecovWasm();
|
||||
|
||||
|
||||
@@ -12222,3 +12222,151 @@ extern std::string const codecovWasm =
|
||||
"31352900490f7461726765745f6665617475726573042b0f6d757461626c652d676c6f6261"
|
||||
"6c732b087369676e2d6578742b0f7265666572656e63652d74797065732b0a6d756c746976"
|
||||
"616c7565";
|
||||
|
||||
extern std::string const floatHex =
|
||||
"0061736d0100000001430860057f7f7f7f7f017f60047e7f7f7f017f60047f7f7f7f017f60"
|
||||
"057f7e7f7f7f017f60077f7f7f7f7f7f7f017f60067f7f7f7f7f7f017f60037f7f7e017f60"
|
||||
"00017f02c9020e08686f73745f6c6962057472616365000008686f73745f6c69620e666c6f"
|
||||
"61745f66726f6d5f696e74000108686f73745f6c69620f666c6f61745f66726f6d5f75696e"
|
||||
"74000008686f73745f6c69621274726163655f6f70617175655f666c6f6174000208686f73"
|
||||
"745f6c696209666c6f61745f736574000308686f73745f6c69620d666c6f61745f636f6d70"
|
||||
"617265000208686f73745f6c696209666c6f61745f616464000408686f73745f6c69620e66"
|
||||
"6c6f61745f7375627472616374000408686f73745f6c69620e666c6f61745f6d756c746970"
|
||||
"6c79000408686f73745f6c69620c666c6f61745f646976696465000408686f73745f6c6962"
|
||||
"09666c6f61745f706f77000508686f73745f6c69620974726163655f6e756d000608686f73"
|
||||
"745f6c69620a666c6f61745f726f6f74000508686f73745f6c696209666c6f61745f6c6f67"
|
||||
"00000302010705030100110619037f01418080c0000b7f0041b48ac0000b7f0041c08ac000"
|
||||
"0b072e04066d656d6f727902000666696e697368000e0a5f5f646174615f656e6403010b5f"
|
||||
"5f686561705f6261736503020acf1301cc1301027f23808080800041206b22002480808080"
|
||||
"00418080c08000411d4100410041001080808080001a2000420037031002400240428ce000"
|
||||
"200041106a410841001081808080004108470d00419d80c080004117200041106a41084101"
|
||||
"1080808080001a0c010b41b480c08000411e4100410041001080808080001a0b2000428ce0"
|
||||
"0037031802400240200041186a4108200041106a410841001082808080004108470d0041d2"
|
||||
"80c080004117200041106a41081083808080001a0c010b41e980c08000411e410041004100"
|
||||
"1080808080001a0b02400240410242fb00200041106a410841001084808080004108470d00"
|
||||
"418781c080004121200041106a41081083808080001a0c010b41a881c08000412641004100"
|
||||
"41001080808080001a0b41ce81c08000411541e381c0800041081083808080001a41f381c0"
|
||||
"8000411641eb81c0800041081083808080001a418982c08000411b41004100410010808080"
|
||||
"80001a20004200370318024002404201200041186a410841001081808080004108470d0041"
|
||||
"a482c08000410f200041186a41081083808080001a0c010b41b382c0800041164100410041"
|
||||
"001080808080001a0b02400240200041186a410841e381c0800041081085808080000d0041"
|
||||
"c982c08000411b4100410041001080808080001a0c010b41e482c08000411b410041004100"
|
||||
"1080808080001a0b02400240200041186a410841eb81c0800041081085808080004101470d"
|
||||
"0041ff82c0800041234100410041001080808080001a0c010b41a283c08000412441004100"
|
||||
"41001080808080001a0b0240024041eb81c080004108200041186a41081085808080004102"
|
||||
"470d0041c683c0800041234100410041001080808080001a0c010b41e983c0800041244100"
|
||||
"410041001080808080001a0b418d84c0800041204100410041001080808080001a200042d4"
|
||||
"87b6f4c7d4b1c000370310410921010340200041106a410841e381c080004108200041106a"
|
||||
"410841001086808080001a2001417f6a22010d000b20004200370318420a200041186a4108"
|
||||
"41001081808080001a02400240200041186a4108200041106a41081085808080000d0041ad"
|
||||
"84c0800041144100410041001080808080001a0c010b41c184c08000411341004100410010"
|
||||
"80808080001a0b410b21010340200041106a410841e381c080004108200041106a41084100"
|
||||
"1087808080001a2001417f6a22010d000b02400240200041106a410841eb81c08000410810"
|
||||
"85808080000d0041d484c0800041194100410041001080808080001a0c010b41ed84c08000"
|
||||
"41184100410041001080808080001a0b418585c0800041234100410041001080808080001a"
|
||||
"20004200370300420a2000410841001081808080001a200042d487b6f4c7d4b1c000370308"
|
||||
"410621010340200041086a410820004108200041086a410841001088808080001a2001417f"
|
||||
"6a22010d000b2000420037031042c0843d200041106a410841001081808080001a02400240"
|
||||
"200041106a4108200041086a41081085808080000d0041a885c08000411941004100410010"
|
||||
"80808080001a0c010b41c185c0800041184100410041001080808080001a0b410721010340"
|
||||
"200041086a410820004108200041086a410841001089808080001a2001417f6a22010d000b"
|
||||
"20004200370318417f4201200041186a410841001084808080001a02400240200041086a41"
|
||||
"08200041186a41081085808080000d0041d985c0800041174100410041001080808080001a"
|
||||
"0c010b41f085c0800041164100410041001080808080001a0b418686c08000411741004100"
|
||||
"41001080808080001a2000420037030841e381c0800041084103200041086a41084100108a"
|
||||
"808080001a419d86c080004112200041086a41081083808080001a41eb81c0800041084106"
|
||||
"200041086a41084100108a808080001a41af86c080004118200041086a4108108380808000"
|
||||
"1a200042003703104209200041106a410841001081808080001a200041106a410841022000"
|
||||
"41086a41084100108a808080001a41c786c080004114200041086a41081083808080001a20"
|
||||
"0041106a41084100200041086a41084100108a808080001a41db86c080004117200041086a"
|
||||
"41081083808080001a200042003703184200200041186a410841001081808080001a200041"
|
||||
"186a41084102200041086a41084100108a808080001a41f286c080004114200041086a4108"
|
||||
"1083808080001a418687c080004138200041186a41084100200041086a41084100108a8080"
|
||||
"8000ac108b808080001a41be87c0800041184100410041001080808080001a200042003703"
|
||||
"084209200041086a410841001081808080001a20004200370310200041086a410841022000"
|
||||
"41106a41084100108c808080001a41d687c080004112200041106a41081083808080001a20"
|
||||
"0041086a41084103200041106a41084100108c808080001a41e887c080004112200041106a"
|
||||
"41081083808080001a2000420037031842c0843d200041186a410841001081808080001a20"
|
||||
"0041186a41084103200041106a41084100108c808080001a41fa87c080004118200041106a"
|
||||
"41081083808080001a200041186a41084106200041106a41084100108c808080001a419288"
|
||||
"c08000411c200041106a41081083808080001a41ae88c08000411741004100410010808080"
|
||||
"80001a2000420037031042c0843d200041106a410841001081808080001a20004200370318"
|
||||
"200041106a4108200041186a41084100108d808080001a41c588c080004114200041186a41"
|
||||
"081083808080001a41d988c08000411a4100410041001080808080001a2000420037031841"
|
||||
"e381c08000410841eb81c080004108200041186a410841001088808080001a0240024041eb"
|
||||
"81c080004108200041186a41081085808080000d0041f388c0800041164100410041001080"
|
||||
"808080001a0c010b418989c0800041154100410041001080808080001a0b41eb81c0800041"
|
||||
"0841eb81c080004108200041186a410841001088808080001a0240024041e381c080004108"
|
||||
"200041186a41081085808080000d00419e89c0800041174100410041001080808080001a0c"
|
||||
"010b41b589c0800041164100410041001080808080001a0b41cb89c08000411a4100410041"
|
||||
"001080808080001a2000420037031020004200370318420a200041186a4108410010818080"
|
||||
"80001a41e381c080004108200041186a4108200041106a410841001089808080001a41e589"
|
||||
"c080004119200041106a41081083808080001a41e381c080004108200041106a4108200041"
|
||||
"106a410841001089808080001a41fe89c08000410f200041106a41081083808080001a0240"
|
||||
"0240200041186a4108200041106a41081085808080000d00418d8ac0800041144100410041"
|
||||
"001080808080001a0c010b41a18ac0800041134100410041001080808080001a0b20004120"
|
||||
"6a24808080800041010b0bbe0a0100418080c0000bb40a0a24242420746573745f666c6f61"
|
||||
"745f66726f6d5f7761736d202424242020666c6f61742066726f6d20693634203132333030"
|
||||
"3a2020666c6f61742066726f6d206936342031323330303a206661696c65642020666c6f61"
|
||||
"742066726f6d207536342031323330303a2020666c6f61742066726f6d2075363420313233"
|
||||
"30303a206661696c65642020666c6f61742066726f6d2065787020322c206d616e74697373"
|
||||
"61203132333a2020666c6f61742066726f6d2065787020322c206d616e746973736120333a"
|
||||
"206661696c65642020666c6f61742066726f6d20636f6e737420313ad4838d7ea4c6800094"
|
||||
"838d7ea4c680002020666c6f61742066726f6d20636f6e7374202d313a0a24242420746573"
|
||||
"745f666c6f61745f636f6d70617265202424242020666c6f61742066726f6d20313a202066"
|
||||
"6c6f61742066726f6d20313a206661696c65642020666c6f61742066726f6d2031203d3d20"
|
||||
"464c4f41545f4f4e452020666c6f61742066726f6d203120213d20464c4f41545f4f4e4520"
|
||||
"20666c6f61742066726f6d2031203e20464c4f41545f4e454741544956455f4f4e45202066"
|
||||
"6c6f61742066726f6d203120213e20464c4f41545f4e454741544956455f4f4e452020464c"
|
||||
"4f41545f4e454741544956455f4f4e45203c20666c6f61742066726f6d20312020464c4f41"
|
||||
"545f4e454741544956455f4f4e4520213c20666c6f61742066726f6d20310a242424207465"
|
||||
"73745f666c6f61745f6164645f737562747261637420242424202072657065617465642061"
|
||||
"64643a20676f6f6420207265706561746564206164643a2062616420207265706561746564"
|
||||
"2073756274726163743a20676f6f64202072657065617465642073756274726163743a2062"
|
||||
"61640a24242420746573745f666c6f61745f6d756c7469706c795f64697669646520242424"
|
||||
"20207265706561746564206d756c7469706c793a20676f6f6420207265706561746564206d"
|
||||
"756c7469706c793a2062616420207265706561746564206469766964653a20676f6f642020"
|
||||
"7265706561746564206469766964653a206261640a24242420746573745f666c6f61745f70"
|
||||
"6f77202424242020666c6f61742063756265206f6620313a2020666c6f6174203674682070"
|
||||
"6f776572206f66202d313a2020666c6f617420737175617265206f6620393a2020666c6f61"
|
||||
"742030746820706f776572206f6620393a2020666c6f617420737175617265206f6620303a"
|
||||
"2020666c6f61742030746820706f776572206f6620302028657870656374696e6720494e56"
|
||||
"414c49445f504152414d53206572726f72293a0a24242420746573745f666c6f61745f726f"
|
||||
"6f74202424242020666c6f61742073717274206f6620393a2020666c6f6174206362727420"
|
||||
"6f6620393a2020666c6f61742063627274206f6620313030303030303a2020666c6f617420"
|
||||
"36746820726f6f74206f6620313030303030303a0a24242420746573745f666c6f61745f6c"
|
||||
"6f672024242420206c6f675f3130206f6620313030303030303a0a24242420746573745f66"
|
||||
"6c6f61745f6e65676174652024242420206e656761746520636f6e737420313a20676f6f64"
|
||||
"20206e656761746520636f6e737420313a2062616420206e656761746520636f6e7374202d"
|
||||
"313a20676f6f6420206e656761746520636f6e7374202d313a206261640a24242420746573"
|
||||
"745f666c6f61745f696e76657274202424242020696e76657274206120666c6f6174206672"
|
||||
"6f6d2031303a2020696e7665727420616761696e3a2020696e766572742074776963653a20"
|
||||
"676f6f642020696e766572742074776963653a20626164009c06046e616d65001110666c6f"
|
||||
"61745f74657374732e7761736d01e1050f002b5f5a4e387872706c5f73746434686f737435"
|
||||
"7472616365313768303332393563316538663365373233614501355f5a4e387872706c5f73"
|
||||
"746434686f73743134666c6f61745f66726f6d5f696e743137683032306436373439326164"
|
||||
"39346333304502365f5a4e387872706c5f73746434686f73743135666c6f61745f66726f6d"
|
||||
"5f75696e74313768346166373638366538353062383432364503395f5a4e387872706c5f73"
|
||||
"746434686f7374313874726163655f6f70617175655f666c6f617431376831396639386666"
|
||||
"35663362313932336245042f5f5a4e387872706c5f73746434686f737439666c6f61745f73"
|
||||
"6574313768323964346230383964626561326664624505345f5a4e387872706c5f73746434"
|
||||
"686f73743133666c6f61745f636f6d70617265313768346362313239626634623330373233"
|
||||
"6445062f5f5a4e387872706c5f73746434686f737439666c6f61745f616464313768383661"
|
||||
"336165636435336234643937374507355f5a4e387872706c5f73746434686f73743134666c"
|
||||
"6f61745f7375627472616374313768653033313036323931393464333931364508355f5a4e"
|
||||
"387872706c5f73746434686f73743134666c6f61745f6d756c7469706c7931376830323839"
|
||||
"3337633039656534323630644509335f5a4e387872706c5f73746434686f73743132666c6f"
|
||||
"61745f64697669646531376834363036323038303562623237353632450a2f5f5a4e387872"
|
||||
"706c5f73746434686f737439666c6f61745f706f7731376833326463303662646430303338"
|
||||
"626331450b2f5f5a4e387872706c5f73746434686f73743974726163655f6e756d31376830"
|
||||
"336535336633646539393463633033450c315f5a4e387872706c5f73746434686f73743130"
|
||||
"666c6f61745f726f6f7431376863656632313139376565656136653630450d2f5f5a4e3878"
|
||||
"72706c5f73746434686f737439666c6f61745f6c6f67313768323530663038303633353663"
|
||||
"35653639450e0666696e697368071201000f5f5f737461636b5f706f696e746572090a0100"
|
||||
"072e726f64617461004d0970726f64756365727302086c616e677561676501045275737400"
|
||||
"0c70726f6365737365642d6279010572757374631d312e38382e3020283662303062633338"
|
||||
"3820323032352d30362d3233290094010f7461726765745f6665617475726573082b0b6275"
|
||||
"6c6b2d6d656d6f72792b0f62756c6b2d6d656d6f72792d6f70742b1663616c6c2d696e6469"
|
||||
"726563742d6f7665726c6f6e672b0a6d756c746976616c75652b0f6d757461626c652d676c"
|
||||
"6f62616c732b136e6f6e7472617070696e672d6670746f696e742b0f7265666572656e6365"
|
||||
"2d74797065732b087369676e2d657874";
|
||||
|
||||
@@ -60,3 +60,5 @@ extern std::string const opcCallPerfTest;
|
||||
extern std::string const keyletHostFunctions;
|
||||
|
||||
extern std::string const codecovWasm;
|
||||
|
||||
extern std::string const floatHex;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <xrpld/app/misc/WasmParamsHelper.h>
|
||||
|
||||
#include <xrpl/basics/Expected.h>
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
@@ -49,8 +50,46 @@ enum class HostFunctionError : int32_t {
|
||||
INVALID_ACCOUNT = -16,
|
||||
INVALID_FIELD = -17,
|
||||
INDEX_OUT_OF_BOUNDS = -18,
|
||||
FLOAT_INPUT_MALFORMED = -19,
|
||||
FLOAT_COMPUTATION_ERROR = -20,
|
||||
};
|
||||
|
||||
std::string
|
||||
floatToString(Slice const& data);
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromIntImpl(int64_t x, int32_t mode);
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromUintImpl(uint64_t x, int32_t mode);
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatSetImpl(int64_t mantissa, int32_t exponent, int32_t mode);
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
floatCompareImpl(Slice const& x, Slice const& y);
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatAddImpl(Slice const& x, Slice const& y, int32_t mode);
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatSubtractImpl(Slice const& x, Slice const& y, int32_t mode);
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatMultiplyImpl(Slice const& x, Slice const& y, int32_t mode);
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatDivideImpl(Slice const& x, Slice const& y, int32_t mode);
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatRootImpl(Slice const& x, int32_t n, int32_t mode);
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatPowerImpl(Slice const& x, int32_t n, int32_t mode);
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatLogImpl(Slice const& x, int32_t mode);
|
||||
|
||||
struct HostFunctions
|
||||
{
|
||||
virtual void
|
||||
@@ -289,6 +328,78 @@ struct HostFunctions
|
||||
return Unexpected(HostFunctionError::INTERNAL);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
traceFloat(std::string_view const& msg, Slice const& data)
|
||||
{
|
||||
return Unexpected(HostFunctionError::INTERNAL);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatFromInt(int64_t x, int32_t mode)
|
||||
{
|
||||
return Unexpected(HostFunctionError::INTERNAL);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatFromUint(uint64_t x, int32_t mode)
|
||||
{
|
||||
return Unexpected(HostFunctionError::INTERNAL);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatSet(int64_t mantissa, int32_t exponent, int32_t mode)
|
||||
{
|
||||
return Unexpected(HostFunctionError::INTERNAL);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
floatCompare(Slice const& x, Slice const& y)
|
||||
{
|
||||
return Unexpected(HostFunctionError::INTERNAL);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatAdd(Slice const& x, Slice const& y, int32_t mode)
|
||||
{
|
||||
return Unexpected(HostFunctionError::INTERNAL);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatSubtract(Slice const& x, Slice const& y, int32_t mode)
|
||||
{
|
||||
return Unexpected(HostFunctionError::INTERNAL);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatMultiply(Slice const& x, Slice const& y, int32_t mode)
|
||||
{
|
||||
return Unexpected(HostFunctionError::INTERNAL);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatDivide(Slice const& x, Slice const& y, int32_t mode)
|
||||
{
|
||||
return Unexpected(HostFunctionError::INTERNAL);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatRoot(Slice const& x, int32_t n, int32_t mode)
|
||||
{
|
||||
return Unexpected(HostFunctionError::INTERNAL);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatPower(Slice const& x, int32_t n, int32_t mode)
|
||||
{
|
||||
return Unexpected(HostFunctionError::INTERNAL);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatLog(Slice const& x, int32_t mode)
|
||||
{
|
||||
return Unexpected(HostFunctionError::INTERNAL);
|
||||
}
|
||||
|
||||
virtual ~HostFunctions() = default;
|
||||
};
|
||||
|
||||
|
||||
@@ -654,4 +654,544 @@ WasmHostFunctionsImpl::traceNum(std::string_view const& msg, int64_t data)
|
||||
return msg.size() + sizeof(data);
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::traceFloat(
|
||||
std::string_view const& msg,
|
||||
Slice const& data)
|
||||
{
|
||||
#ifdef DEBUG_OUTPUT
|
||||
auto j = getJournal().error();
|
||||
#else
|
||||
auto j = getJournal().trace();
|
||||
#endif
|
||||
auto const s = floatToString(data);
|
||||
j << "WAMR TRACE FLOAT(" << leKey.key << "): " << msg << " " << s;
|
||||
return msg.size() + s.size();
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatFromInt(int64_t x, int32_t mode)
|
||||
{
|
||||
return floatFromIntImpl(x, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatFromUint(uint64_t x, int32_t mode)
|
||||
{
|
||||
return floatFromUintImpl(x, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatSet(
|
||||
int64_t mantissa,
|
||||
int32_t exponent,
|
||||
int32_t mode)
|
||||
{
|
||||
return floatSetImpl(mantissa, exponent, mode);
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatCompare(Slice const& x, Slice const& y)
|
||||
{
|
||||
return floatCompareImpl(x, y);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatAdd(Slice const& x, Slice const& y, int32_t mode)
|
||||
{
|
||||
return floatAddImpl(x, y, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatSubtract(
|
||||
Slice const& x,
|
||||
Slice const& y,
|
||||
int32_t mode)
|
||||
{
|
||||
return floatSubtractImpl(x, y, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatMultiply(
|
||||
Slice const& x,
|
||||
Slice const& y,
|
||||
int32_t mode)
|
||||
{
|
||||
return floatMultiplyImpl(x, y, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatDivide(Slice const& x, Slice const& y, int32_t mode)
|
||||
{
|
||||
return floatDivideImpl(x, y, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatRoot(Slice const& x, int32_t n, int32_t mode)
|
||||
{
|
||||
return floatRootImpl(x, n, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatPower(Slice const& x, int32_t n, int32_t mode)
|
||||
{
|
||||
return floatPowerImpl(x, n, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatLog(Slice const& x, int32_t mode)
|
||||
{
|
||||
return floatLogImpl(x, mode);
|
||||
}
|
||||
|
||||
class Number2 : public Number
|
||||
{
|
||||
bool good_;
|
||||
|
||||
enum Issue { XRP, MPT, IOU };
|
||||
Issue issue_;
|
||||
|
||||
public:
|
||||
Number2(Slice const& data) : Number(0), good_(false), issue_(IOU)
|
||||
{
|
||||
if (data.size() != 8)
|
||||
return;
|
||||
|
||||
uint64_t const v = SerialIter(data).get64();
|
||||
int const neg = (v & STAmount::cPositive) ? 1 : -1;
|
||||
|
||||
Number x;
|
||||
|
||||
if (v & STAmount::cIssuedCurrency)
|
||||
{
|
||||
// IOU
|
||||
int32_t const e =
|
||||
static_cast<uint8_t>((v >> (64 - 10)) & ((1ull << 8) - 1));
|
||||
int64_t const m = neg * (v & ((1ull << 54) - 1));
|
||||
x = !m ? Number() : Number(m, e - 97);
|
||||
if (m && (x.exponent() > 80 || x.exponent() < -96))
|
||||
return; // invalid number
|
||||
issue_ = IOU;
|
||||
}
|
||||
else if (v & STAmount::cMPToken)
|
||||
{
|
||||
// MPT
|
||||
int64_t const m = neg * (v & ((1ull << 61) - 1));
|
||||
x = !m ? Number() : Number(m);
|
||||
issue_ = MPT;
|
||||
}
|
||||
else
|
||||
{
|
||||
// XRP
|
||||
int64_t const m = neg * (v & ((1ull << 61) - 1));
|
||||
x = !m ? Number() : Number(m);
|
||||
issue_ = XRP;
|
||||
}
|
||||
|
||||
*static_cast<Number*>(this) = x;
|
||||
good_ = true;
|
||||
}
|
||||
|
||||
Number2(int64_t x) : Number(x), good_(true), issue_(IOU)
|
||||
{
|
||||
}
|
||||
|
||||
Number2(uint64_t x) : Number(0), good_(false), issue_(IOU)
|
||||
{
|
||||
if (x <=
|
||||
std::numeric_limits<
|
||||
std::invoke_result_t<decltype(&Number::mantissa), Number>>::
|
||||
max())
|
||||
*static_cast<Number*>(this) = Number(x);
|
||||
else
|
||||
{
|
||||
*static_cast<Number*>(this) = Number(x / 10, 1) + Number(x % 10);
|
||||
}
|
||||
|
||||
good_ = true;
|
||||
}
|
||||
|
||||
Number2(int64_t mantissa, int32_t exponent)
|
||||
: Number(mantissa, exponent), good_(true), issue_(IOU)
|
||||
{
|
||||
}
|
||||
|
||||
Number2(Number const& n) : Number(n), good_(true), issue_(IOU)
|
||||
{
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return good_;
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
toBytes() const
|
||||
{
|
||||
uint64_t v = mantissa() >= 0 ? STAmount::cPositive : 0;
|
||||
|
||||
if (issue_ == IOU)
|
||||
{
|
||||
v |= STAmount::cIssuedCurrency;
|
||||
|
||||
if (!mantissa())
|
||||
{
|
||||
if (exponent() != std::numeric_limits<int>::lowest())
|
||||
return Unexpected(
|
||||
HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
}
|
||||
else if (exponent() > 80 || exponent() < -96)
|
||||
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
|
||||
uint64_t absM = mantissa() >= 0 ? mantissa() : -mantissa();
|
||||
if (absM > ((1ull << 54) - 1))
|
||||
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
|
||||
v |= absM;
|
||||
|
||||
int const e = (!mantissa() ? 0 : exponent()) + 97;
|
||||
v |= ((uint64_t)e) << 54;
|
||||
}
|
||||
else if (issue_ == MPT)
|
||||
{
|
||||
v |= STAmount::cMPToken;
|
||||
uint64_t x = toUInt(61);
|
||||
if (x == std::numeric_limits<uint64_t>::max())
|
||||
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
v |= x;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint64_t x = toUInt(61);
|
||||
if (x == std::numeric_limits<uint64_t>::max())
|
||||
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
v |= x;
|
||||
}
|
||||
|
||||
Serializer msg;
|
||||
msg.add64(v);
|
||||
auto const data = msg.getData();
|
||||
return data;
|
||||
}
|
||||
|
||||
protected:
|
||||
uint64_t
|
||||
toUInt(unsigned bits) const
|
||||
{
|
||||
if (bits >= sizeof(uint64_t) * 8)
|
||||
return std::numeric_limits<uint64_t>::max();
|
||||
|
||||
uint64_t maxV = (1ull << bits) - 1;
|
||||
uint64_t absM = mantissa() >= 0 ? mantissa() : -mantissa();
|
||||
|
||||
if (!absM)
|
||||
return 0;
|
||||
else if (exponent() < 0)
|
||||
{
|
||||
for (int i = 0; i > exponent(); --i)
|
||||
{
|
||||
if (absM < 10)
|
||||
return std::numeric_limits<uint64_t>::max(); // underflow
|
||||
absM /= 10;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < exponent(); ++i)
|
||||
{
|
||||
if (absM > maxV / 10)
|
||||
return std::numeric_limits<uint64_t>::max(); // overflow
|
||||
absM *= 10;
|
||||
}
|
||||
}
|
||||
|
||||
return absM > maxV ? std::numeric_limits<uint64_t>::max() : absM;
|
||||
}
|
||||
};
|
||||
|
||||
struct SetRound
|
||||
{
|
||||
Number::rounding_mode oldMode_;
|
||||
bool good_;
|
||||
|
||||
SetRound(int32_t mode) : oldMode_(Number::getround()), good_(false)
|
||||
{
|
||||
if (mode < Number::rounding_mode::to_nearest ||
|
||||
mode > Number::rounding_mode::upward)
|
||||
return;
|
||||
|
||||
Number::setround(static_cast<Number::rounding_mode>(mode));
|
||||
good_ = true;
|
||||
}
|
||||
|
||||
~SetRound()
|
||||
{
|
||||
Number::setround(oldMode_);
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return good_;
|
||||
}
|
||||
};
|
||||
|
||||
std::string
|
||||
floatToString(Slice const& data)
|
||||
{
|
||||
Number2 const num(data);
|
||||
if (!num)
|
||||
{
|
||||
std::string hex;
|
||||
hex.reserve(data.size() * 2);
|
||||
boost::algorithm::hex(
|
||||
data.begin(), data.end(), std::back_inserter(hex));
|
||||
return "Invalid data: " + hex;
|
||||
}
|
||||
|
||||
auto const s = to_string(num);
|
||||
return s;
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromIntImpl(int64_t x, int32_t mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
SetRound rm(mode);
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
|
||||
Number2 num(x);
|
||||
if (!num)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
|
||||
return num.toBytes();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromUintImpl(uint64_t x, int32_t mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
SetRound rm(mode);
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
|
||||
Number2 num(x);
|
||||
if (!num)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
|
||||
return num.toBytes();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatSetImpl(int64_t mantissa, int32_t exponent, int32_t mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
SetRound rm(mode);
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
Number2 num(mantissa, exponent);
|
||||
if (!num)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
return num.toBytes();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
floatCompareImpl(Slice const& x, Slice const& y)
|
||||
{
|
||||
try
|
||||
{
|
||||
Number2 xx(x);
|
||||
if (!xx)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
Number2 yy(y);
|
||||
if (!yy)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
return xx < yy ? 2 : (xx == yy ? 0 : 1);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatAddImpl(Slice const& x, Slice const& y, int32_t mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
SetRound rm(mode);
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
|
||||
Number2 xx(x);
|
||||
if (!xx)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
Number2 yy(y);
|
||||
if (!yy)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
Number2 res = xx + yy;
|
||||
return res.toBytes();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatSubtractImpl(Slice const& x, Slice const& y, int32_t mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
SetRound rm(mode);
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
Number2 xx(x);
|
||||
if (!xx)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
Number2 yy(y);
|
||||
if (!yy)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
Number2 res = xx - yy;
|
||||
return res.toBytes();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatMultiplyImpl(Slice const& x, Slice const& y, int32_t mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
SetRound rm(mode);
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
Number2 xx(x);
|
||||
if (!xx)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
Number2 yy(y);
|
||||
if (!yy)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
Number2 res = xx * yy;
|
||||
return res.toBytes();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatDivideImpl(Slice const& x, Slice const& y, int32_t mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
SetRound rm(mode);
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
Number2 xx(x);
|
||||
if (!xx)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
Number2 yy(y);
|
||||
if (!yy)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
Number2 res = xx / yy;
|
||||
return res.toBytes();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatRootImpl(Slice const& x, int32_t n, int32_t mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
SetRound rm(mode);
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
|
||||
Number2 xx(x);
|
||||
if (!xx)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
Number2 const res(root(xx, n));
|
||||
|
||||
return res.toBytes();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatPowerImpl(Slice const& x, int32_t n, int32_t mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
SetRound rm(mode);
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
|
||||
Number2 xx(x);
|
||||
if (!xx)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
if (xx == Number() && !n)
|
||||
return Unexpected(HostFunctionError::INVALID_PARAMS);
|
||||
|
||||
Number2 const res(power(xx, n, 1));
|
||||
|
||||
return res.toBytes();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatLogImpl(Slice const& x, int32_t mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
SetRound rm(mode);
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
|
||||
Number2 xx(x);
|
||||
if (!xx)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
Number2 const res(lg(xx));
|
||||
|
||||
return res.toBytes();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -190,6 +190,42 @@ public:
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
traceNum(std::string_view const& msg, int64_t data) override;
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
traceFloat(std::string_view const& msg, Slice const& data) override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromInt(int64_t x, int32_t mode) override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromUint(uint64_t x, int32_t mode) override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatSet(int64_t mantissa, int32_t exponent, int32_t mode) override;
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
floatCompare(Slice const& x, Slice const& y) override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatAdd(Slice const& x, Slice const& y, int32_t mode) override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatSubtract(Slice const& x, Slice const& y, int32_t mode) override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatMultiply(Slice const& x, Slice const& y, int32_t mode) override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatDivide(Slice const& x, Slice const& y, int32_t mode) override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatRoot(Slice const& x, int32_t n, int32_t mode) override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatPower(Slice const& x, int32_t n, int32_t mode) override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatLog(Slice const& x, int32_t mode) override;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <xrpld/app/misc/WasmHostFuncWrapper.h>
|
||||
#include <xrpld/app/tx/detail/NFTokenUtils.h>
|
||||
|
||||
#include <xrpl/protocol/STNumber.h>
|
||||
#include <xrpl/protocol/digest.h>
|
||||
|
||||
namespace ripple {
|
||||
@@ -64,7 +65,7 @@ setData(
|
||||
|
||||
template <class IW>
|
||||
Expected<int32_t, HostFunctionError>
|
||||
getDataInt32(IW const* _rt, wasm_val_vec_t const* params, int32_t& i)
|
||||
getDataInt32(IW const* _runtime, wasm_val_vec_t const* params, int32_t& i)
|
||||
{
|
||||
auto const result = params->data[i].of.i32;
|
||||
i++;
|
||||
@@ -73,16 +74,29 @@ getDataInt32(IW const* _rt, wasm_val_vec_t const* params, int32_t& i)
|
||||
|
||||
template <class IW>
|
||||
Expected<int64_t, HostFunctionError>
|
||||
getDataInt64(IW const* _rt, wasm_val_vec_t const* params, int32_t& i)
|
||||
getDataInt64(IW const* _runtime, wasm_val_vec_t const* params, int32_t& i)
|
||||
{
|
||||
auto const result = params->data[i].of.i64;
|
||||
i++;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class IW>
|
||||
Expected<uint64_t, HostFunctionError>
|
||||
getDataUint64(IW const* runtime, wasm_val_vec_t const* params, int32_t& i)
|
||||
{
|
||||
auto const r = getDataSlice(runtime, params, i);
|
||||
if (!r)
|
||||
return Unexpected(r.error());
|
||||
if (r->size() != sizeof(uint64_t))
|
||||
return Unexpected(HostFunctionError::INVALID_PARAMS);
|
||||
|
||||
return *reinterpret_cast<uint64_t const*>(r->data());
|
||||
}
|
||||
|
||||
template <class IW>
|
||||
Expected<SFieldCRef, HostFunctionError>
|
||||
getDataSField(IW const* _rt, wasm_val_vec_t const* params, int32_t& i)
|
||||
getDataSField(IW const* _runtime, wasm_val_vec_t const* params, int32_t& i)
|
||||
{
|
||||
auto const& m = SField::getKnownCodeToField();
|
||||
auto const it = m.find(params->data[i].of.i32);
|
||||
@@ -217,7 +231,9 @@ returnResult(
|
||||
{
|
||||
return hfResult(results, res.error());
|
||||
}
|
||||
if constexpr (std::is_same_v<std::decay_t<decltype(*res)>, Bytes>)
|
||||
|
||||
using t = std::decay_t<decltype(*res)>;
|
||||
if constexpr (std::is_same_v<t, Bytes>)
|
||||
{
|
||||
return hfResult(
|
||||
results,
|
||||
@@ -228,7 +244,7 @@ returnResult(
|
||||
res->data(),
|
||||
res->size()));
|
||||
}
|
||||
else if constexpr (std::is_same_v<std::decay_t<decltype(*res)>, Hash>)
|
||||
else if constexpr (std::is_same_v<t, Hash>)
|
||||
{
|
||||
return hfResult(
|
||||
results,
|
||||
@@ -239,13 +255,11 @@ returnResult(
|
||||
res->data(),
|
||||
res->size()));
|
||||
}
|
||||
else if constexpr (std::is_same_v<std::decay_t<decltype(*res)>, int32_t>)
|
||||
else if constexpr (std::is_same_v<t, int32_t>)
|
||||
{
|
||||
return hfResult(results, res.value());
|
||||
}
|
||||
else if constexpr (std::is_same_v<
|
||||
std::decay_t<decltype(*res)>,
|
||||
std::uint32_t>)
|
||||
else if constexpr (std::is_same_v<t, std::uint32_t>)
|
||||
{
|
||||
auto const resultValue = res.value();
|
||||
return hfResult(
|
||||
@@ -1044,7 +1058,6 @@ ticketKeylet_wrap(
|
||||
results,
|
||||
hf->ticketKeylet(acc.value(), seq.value()),
|
||||
index);
|
||||
;
|
||||
}
|
||||
|
||||
wasm_trap_t*
|
||||
@@ -1131,6 +1144,310 @@ traceNum_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results)
|
||||
runtime, params, results, hf->traceNum(*msg, *number), index);
|
||||
}
|
||||
|
||||
wasm_trap_t*
|
||||
traceFloat_wrap(
|
||||
void* env,
|
||||
wasm_val_vec_t const* params,
|
||||
wasm_val_vec_t* results)
|
||||
{
|
||||
auto* hf = reinterpret_cast<HostFunctions*>(env);
|
||||
auto const* runtime = reinterpret_cast<InstanceWrapper const*>(hf->getRT());
|
||||
|
||||
if (params->data[1].of.i32 > maxWasmDataLength)
|
||||
return hfResult(results, HostFunctionError::DATA_FIELD_TOO_LARGE);
|
||||
|
||||
int i = 0;
|
||||
auto const msg = getDataString(runtime, params, i);
|
||||
if (!msg)
|
||||
return hfResult(results, msg.error());
|
||||
|
||||
auto const number = getDataSlice(runtime, params, i);
|
||||
if (!number)
|
||||
return hfResult(results, number.error());
|
||||
|
||||
return returnResult(
|
||||
runtime, params, results, hf->traceFloat(*msg, *number), i);
|
||||
}
|
||||
|
||||
wasm_trap_t*
|
||||
floatFromInt_wrap(
|
||||
void* env,
|
||||
wasm_val_vec_t const* params,
|
||||
wasm_val_vec_t* results)
|
||||
{
|
||||
auto* hf = reinterpret_cast<HostFunctions*>(env);
|
||||
auto const* runtime = reinterpret_cast<InstanceWrapper const*>(hf->getRT());
|
||||
|
||||
int i = 0;
|
||||
auto const x = getDataInt64(runtime, params, i);
|
||||
if (!x)
|
||||
return hfResult(results, x.error());
|
||||
|
||||
i = 3;
|
||||
auto const rounding = getDataInt32(runtime, params, i);
|
||||
if (!rounding)
|
||||
return hfResult(results, rounding.error());
|
||||
|
||||
i = 1;
|
||||
return returnResult(
|
||||
runtime, params, results, hf->floatFromInt(*x, *rounding), i);
|
||||
}
|
||||
|
||||
wasm_trap_t*
|
||||
floatFromUint_wrap(
|
||||
void* env,
|
||||
wasm_val_vec_t const* params,
|
||||
wasm_val_vec_t* results)
|
||||
{
|
||||
auto* hf = reinterpret_cast<HostFunctions*>(env);
|
||||
auto const* runtime = reinterpret_cast<InstanceWrapper const*>(hf->getRT());
|
||||
|
||||
int i = 0;
|
||||
auto const x = getDataUint64(runtime, params, i);
|
||||
if (!x)
|
||||
return hfResult(results, x.error());
|
||||
|
||||
i = 4;
|
||||
auto const rounding = getDataInt32(runtime, params, i);
|
||||
if (!rounding)
|
||||
return hfResult(results, rounding.error());
|
||||
|
||||
i = 2;
|
||||
return returnResult(
|
||||
runtime, params, results, hf->floatFromUint(*x, *rounding), i);
|
||||
}
|
||||
|
||||
wasm_trap_t*
|
||||
floatSet_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results)
|
||||
{
|
||||
auto* hf = reinterpret_cast<HostFunctions*>(env);
|
||||
auto const* runtime = reinterpret_cast<InstanceWrapper const*>(hf->getRT());
|
||||
|
||||
int i = 0;
|
||||
auto const exp = getDataInt32(runtime, params, i);
|
||||
if (!exp)
|
||||
return hfResult(results, exp.error());
|
||||
|
||||
auto const mant = getDataInt64(runtime, params, i);
|
||||
if (!mant)
|
||||
return hfResult(results, mant.error());
|
||||
|
||||
i = 4;
|
||||
auto const rounding = getDataInt32(runtime, params, i);
|
||||
if (!rounding)
|
||||
return hfResult(results, rounding.error());
|
||||
|
||||
i = 2;
|
||||
return returnResult(
|
||||
runtime, params, results, hf->floatSet(*mant, *exp, *rounding), i);
|
||||
}
|
||||
|
||||
wasm_trap_t*
|
||||
floatCompare_wrap(
|
||||
void* env,
|
||||
wasm_val_vec_t const* params,
|
||||
wasm_val_vec_t* results)
|
||||
{
|
||||
auto* hf = reinterpret_cast<HostFunctions*>(env);
|
||||
auto const* runtime = reinterpret_cast<InstanceWrapper const*>(hf->getRT());
|
||||
|
||||
int i = 0;
|
||||
auto const x = getDataSlice(runtime, params, i);
|
||||
if (!x)
|
||||
return hfResult(results, x.error());
|
||||
|
||||
auto const y = getDataSlice(runtime, params, i);
|
||||
if (!y)
|
||||
return hfResult(results, y.error());
|
||||
|
||||
return returnResult(runtime, params, results, hf->floatCompare(*x, *y), i);
|
||||
}
|
||||
|
||||
wasm_trap_t*
|
||||
floatAdd_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results)
|
||||
{
|
||||
auto* hf = reinterpret_cast<HostFunctions*>(env);
|
||||
auto const* runtime = reinterpret_cast<InstanceWrapper const*>(hf->getRT());
|
||||
|
||||
int i = 0;
|
||||
auto const x = getDataSlice(runtime, params, i);
|
||||
if (!x)
|
||||
return hfResult(results, x.error());
|
||||
|
||||
auto const y = getDataSlice(runtime, params, i);
|
||||
if (!y)
|
||||
return hfResult(results, y.error());
|
||||
|
||||
i = 6;
|
||||
auto const rounding = getDataInt32(runtime, params, i);
|
||||
if (!rounding)
|
||||
return hfResult(results, rounding.error());
|
||||
|
||||
i = 4;
|
||||
return returnResult(
|
||||
runtime, params, results, hf->floatAdd(*x, *y, *rounding), i);
|
||||
}
|
||||
|
||||
wasm_trap_t*
|
||||
floatSubtract_wrap(
|
||||
void* env,
|
||||
wasm_val_vec_t const* params,
|
||||
wasm_val_vec_t* results)
|
||||
{
|
||||
auto* hf = reinterpret_cast<HostFunctions*>(env);
|
||||
auto const* runtime = reinterpret_cast<InstanceWrapper const*>(hf->getRT());
|
||||
|
||||
int i = 0;
|
||||
auto const x = getDataSlice(runtime, params, i);
|
||||
if (!x)
|
||||
return hfResult(results, x.error());
|
||||
|
||||
auto const y = getDataSlice(runtime, params, i);
|
||||
if (!y)
|
||||
return hfResult(results, y.error());
|
||||
|
||||
i = 6;
|
||||
auto const rounding = getDataInt32(runtime, params, i);
|
||||
if (!rounding)
|
||||
return hfResult(results, rounding.error());
|
||||
|
||||
i = 4;
|
||||
return returnResult(
|
||||
runtime, params, results, hf->floatSubtract(*x, *y, *rounding), i);
|
||||
}
|
||||
|
||||
wasm_trap_t*
|
||||
floatMultiply_wrap(
|
||||
void* env,
|
||||
wasm_val_vec_t const* params,
|
||||
wasm_val_vec_t* results)
|
||||
{
|
||||
auto* hf = reinterpret_cast<HostFunctions*>(env);
|
||||
auto const* runtime = reinterpret_cast<InstanceWrapper const*>(hf->getRT());
|
||||
|
||||
int i = 0;
|
||||
auto const x = getDataSlice(runtime, params, i);
|
||||
if (!x)
|
||||
return hfResult(results, x.error());
|
||||
|
||||
auto const y = getDataSlice(runtime, params, i);
|
||||
if (!y)
|
||||
return hfResult(results, y.error());
|
||||
|
||||
i = 6;
|
||||
auto const rounding = getDataInt32(runtime, params, i);
|
||||
if (!rounding)
|
||||
return hfResult(results, rounding.error());
|
||||
|
||||
i = 4;
|
||||
return returnResult(
|
||||
runtime, params, results, hf->floatMultiply(*x, *y, *rounding), i);
|
||||
}
|
||||
|
||||
wasm_trap_t*
|
||||
floatDivide_wrap(
|
||||
void* env,
|
||||
wasm_val_vec_t const* params,
|
||||
wasm_val_vec_t* results)
|
||||
{
|
||||
auto* hf = reinterpret_cast<HostFunctions*>(env);
|
||||
auto const* runtime = reinterpret_cast<InstanceWrapper const*>(hf->getRT());
|
||||
|
||||
int i = 0;
|
||||
auto const x = getDataSlice(runtime, params, i);
|
||||
if (!x)
|
||||
return hfResult(results, x.error());
|
||||
|
||||
auto const y = getDataSlice(runtime, params, i);
|
||||
if (!y)
|
||||
return hfResult(results, y.error());
|
||||
|
||||
i = 6;
|
||||
auto const rounding = getDataInt32(runtime, params, i);
|
||||
if (!rounding)
|
||||
return hfResult(results, rounding.error());
|
||||
|
||||
i = 4;
|
||||
return returnResult(
|
||||
runtime, params, results, hf->floatDivide(*x, *y, *rounding), i);
|
||||
}
|
||||
|
||||
wasm_trap_t*
|
||||
floatRoot_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results)
|
||||
{
|
||||
auto* hf = reinterpret_cast<HostFunctions*>(env);
|
||||
auto const* runtime = reinterpret_cast<InstanceWrapper const*>(hf->getRT());
|
||||
|
||||
int i = 0;
|
||||
auto const x = getDataSlice(runtime, params, i);
|
||||
if (!x)
|
||||
return hfResult(results, x.error());
|
||||
|
||||
auto const n = getDataInt32(runtime, params, i);
|
||||
if (!n)
|
||||
return hfResult(results, n.error());
|
||||
|
||||
i = 5;
|
||||
auto const rounding = getDataInt32(runtime, params, i);
|
||||
if (!rounding)
|
||||
return hfResult(results, rounding.error());
|
||||
|
||||
i = 3;
|
||||
return returnResult(
|
||||
runtime, params, results, hf->floatRoot(*x, *n, *rounding), i);
|
||||
}
|
||||
|
||||
wasm_trap_t*
|
||||
floatPower_wrap(
|
||||
void* env,
|
||||
wasm_val_vec_t const* params,
|
||||
wasm_val_vec_t* results)
|
||||
{
|
||||
auto* hf = reinterpret_cast<HostFunctions*>(env);
|
||||
auto const* runtime = reinterpret_cast<InstanceWrapper const*>(hf->getRT());
|
||||
|
||||
int i = 0;
|
||||
auto const x = getDataSlice(runtime, params, i);
|
||||
if (!x)
|
||||
return hfResult(results, x.error());
|
||||
|
||||
auto const n = getDataInt32(runtime, params, i);
|
||||
if (!n)
|
||||
return hfResult(results, n.error());
|
||||
|
||||
i = 5;
|
||||
auto const rounding = getDataInt32(runtime, params, i);
|
||||
if (!rounding)
|
||||
return hfResult(results, rounding.error());
|
||||
|
||||
i = 3;
|
||||
return returnResult(
|
||||
runtime, params, results, hf->floatPower(*x, *n, *rounding), i);
|
||||
}
|
||||
|
||||
wasm_trap_t*
|
||||
floatLog_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results)
|
||||
{
|
||||
auto* hf = reinterpret_cast<HostFunctions*>(env);
|
||||
auto const* runtime = reinterpret_cast<InstanceWrapper const*>(hf->getRT());
|
||||
|
||||
int i = 0;
|
||||
auto const x = getDataSlice(runtime, params, i);
|
||||
if (!x)
|
||||
return hfResult(results, x.error());
|
||||
|
||||
i = 4;
|
||||
auto const rounding = getDataInt32(runtime, params, i);
|
||||
if (!rounding)
|
||||
return hfResult(results, rounding.error());
|
||||
|
||||
i = 2;
|
||||
return returnResult(
|
||||
runtime, params, results, hf->floatLog(*x, *rounding), i);
|
||||
}
|
||||
|
||||
namespace test {
|
||||
|
||||
class MockInstanceWrapper
|
||||
{
|
||||
wmem mem_;
|
||||
@@ -1148,8 +1465,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
namespace test {
|
||||
|
||||
// LCOV_EXCL_START
|
||||
bool
|
||||
testGetDataIncrement()
|
||||
|
||||
@@ -313,4 +313,113 @@ using traceNum_proto = int32_t(uint8_t const*, int32_t, int64_t);
|
||||
wasm_trap_t*
|
||||
traceNum_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results);
|
||||
|
||||
using traceFloat_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t);
|
||||
wasm_trap_t*
|
||||
traceFloat_wrap(
|
||||
void* env,
|
||||
wasm_val_vec_t const* params,
|
||||
wasm_val_vec_t* results);
|
||||
|
||||
using floatFromInt_proto = int32_t(int64_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t*
|
||||
floatFromInt_wrap(
|
||||
void* env,
|
||||
wasm_val_vec_t const* params,
|
||||
wasm_val_vec_t* results);
|
||||
|
||||
using floatFromUint_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t*
|
||||
floatFromUint_wrap(
|
||||
void* env,
|
||||
wasm_val_vec_t const* params,
|
||||
wasm_val_vec_t* results);
|
||||
|
||||
using floatSet_proto = int32_t(int32_t, int64_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t*
|
||||
floatSet_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results);
|
||||
|
||||
using floatCompare_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t);
|
||||
wasm_trap_t*
|
||||
floatCompare_wrap(
|
||||
void* env,
|
||||
wasm_val_vec_t const* params,
|
||||
wasm_val_vec_t* results);
|
||||
|
||||
using floatAdd_proto = int32_t(
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t*,
|
||||
int32_t,
|
||||
int32_t);
|
||||
wasm_trap_t*
|
||||
floatAdd_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results);
|
||||
|
||||
using floatSubtract_proto = int32_t(
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t*,
|
||||
int32_t,
|
||||
int32_t);
|
||||
wasm_trap_t*
|
||||
floatSubtract_wrap(
|
||||
void* env,
|
||||
wasm_val_vec_t const* params,
|
||||
wasm_val_vec_t* results);
|
||||
|
||||
using floatMultiply_proto = int32_t(
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t*,
|
||||
int32_t,
|
||||
int32_t);
|
||||
wasm_trap_t*
|
||||
floatMultiply_wrap(
|
||||
void* env,
|
||||
wasm_val_vec_t const* params,
|
||||
wasm_val_vec_t* results);
|
||||
|
||||
using floatDivide_proto = int32_t(
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t*,
|
||||
int32_t,
|
||||
int32_t);
|
||||
wasm_trap_t*
|
||||
floatDivide_wrap(
|
||||
void* env,
|
||||
wasm_val_vec_t const* params,
|
||||
wasm_val_vec_t* results);
|
||||
|
||||
using floatRoot_proto =
|
||||
int32_t(uint8_t const*, int32_t, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t*
|
||||
floatRoot_wrap(
|
||||
void* env,
|
||||
wasm_val_vec_t const* params,
|
||||
wasm_val_vec_t* results);
|
||||
|
||||
using floatPower_proto =
|
||||
int32_t(uint8_t const*, int32_t, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t*
|
||||
floatPower_wrap(
|
||||
void* env,
|
||||
wasm_val_vec_t const* params,
|
||||
wasm_val_vec_t* results);
|
||||
|
||||
using floatLog_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t*
|
||||
floatLog_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results);
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -77,6 +77,19 @@ createWasmImport(HostFunctions* hfs)
|
||||
WASM_IMPORT_FUNC2(i, getNFT, "get_nft", hfs, 1000);
|
||||
WASM_IMPORT_FUNC (i, trace, hfs, 500);
|
||||
WASM_IMPORT_FUNC2(i, traceNum, "trace_num", hfs, 500);
|
||||
WASM_IMPORT_FUNC2(i, traceFloat, "trace_opaque_float", hfs, 500);
|
||||
|
||||
WASM_IMPORT_FUNC2(i, floatFromInt, "float_from_int", hfs, 1000);
|
||||
WASM_IMPORT_FUNC2(i, floatFromUint, "float_from_uint", hfs, 1000);
|
||||
WASM_IMPORT_FUNC2(i, floatSet, "float_set", hfs, 1000);
|
||||
WASM_IMPORT_FUNC2(i, floatCompare, "float_compare", hfs, 1000);
|
||||
WASM_IMPORT_FUNC2(i, floatAdd, "float_add", hfs, 1000);
|
||||
WASM_IMPORT_FUNC2(i, floatSubtract, "float_subtract", hfs, 1000);
|
||||
WASM_IMPORT_FUNC2(i, floatMultiply, "float_multiply", hfs, 1000);
|
||||
WASM_IMPORT_FUNC2(i, floatDivide, "float_divide", hfs, 1000);
|
||||
WASM_IMPORT_FUNC2(i, floatRoot, "float_root", hfs, 1000);
|
||||
WASM_IMPORT_FUNC2(i, floatPower, "float_pow", hfs, 1000);
|
||||
WASM_IMPORT_FUNC2(i, floatLog, "float_log", hfs, 1000);
|
||||
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user