Skip to content

Add an option to select how to seed random() #1080

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions cli/asc.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const mkdirp = require("./util/mkdirp");
const find = require("./util/find");
const EOL = process.platform === "win32" ? "\r\n" : "\n";
const SEP = process.platform === "win32" ? "\\" : "/";
const Long = require("long");
const binaryen = global.Binaryen || (global.Binaryen = require("binaryen"));

// Proxy Binaryen's ready event
Expand Down Expand Up @@ -238,6 +239,43 @@ exports.main = function main(argv, options, callback) {
assemblyscript.setGlobalAlias(compilerOptions, "abort", "~lib/builtins/abort");
assemblyscript.setGlobalAlias(compilerOptions, "trace", "~lib/builtins/trace");

// Initialize randomness source
switch (args.seedRandom) {
case "const": {
assemblyscript.setGlobalAlias(compilerOptions, "ASC_SEEDRANDOM_CONST", "1");
// fall-through
}
case undefined: {
let value = Long.fromBits(Math.random() * 0xffffffff, Math.random() * 0xffffffff, true);
assemblyscript.setGlobalAlias(compilerOptions, "ASC_SEEDRANDOM_LOW", (value.low >>> 0).toString());
assemblyscript.setGlobalAlias(compilerOptions, "ASC_SEEDRANDOM_HIGH", (value.high >>> 0).toString());
break;
Comment on lines +249 to +252
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems use Long.fromBits here is unnecessary. What about:

const low = Math.random() * 0xffffffff >>> 0;
const high = Math.random() * 0xffffffff >>> 0;
assemblyscript.setGlobalAlias(compilerOptions, "ASC_SEEDRANDOM_LOW", low.toString());
assemblyscript.setGlobalAlias(compilerOptions, "ASC_SEEDRANDOM_HIGH", high.toString());

}
case "math": {
assemblyscript.setGlobalAlias(compilerOptions, "ASC_SEEDRANDOM_MATH", "1");
break;
}
case "date": {
assemblyscript.setGlobalAlias(compilerOptions, "ASC_SEEDRANDOM_DATE", "1");
break;
}
case "wasi": {
assemblyscript.setGlobalAlias(compilerOptions, "ASC_SEEDRANDOM_WASI", "1");
break;
}
default: {
if (/^\d+$/.test(args.seedRandom)) {
let value = Long.fromString(args.seedRandom);
assemblyscript.setGlobalAlias(compilerOptions, "ASC_SEEDRANDOM_CONST", "1");
assemblyscript.setGlobalAlias(compilerOptions, "ASC_SEEDRANDOM_LOW", (value.low >>> 0).toString());
assemblyscript.setGlobalAlias(compilerOptions, "ASC_SEEDRANDOM_HIGH", (value.high >>> 0).toString());
} else {
assemblyscript.setGlobalAlias(compilerOptions, "ASC_SEEDRANDOM_FUNC", String(args.seedRandom));
}
break;
}
}

// Add or override aliases if specified
if (args.use) {
let aliases = args.use;
Expand Down
16 changes: 16 additions & 0 deletions cli/asc.json
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,22 @@
"type": "S",
"alias": "u"
},
"seedRandom": {
"category": "Features",
"description": [
"Sets the randomness source used by Math.random. Defalts to",
"a compile-time constant while emitting a warning.",
"",
" const Compile-time constant without a warning.",
" 12345 Custom constant without a warning.",
" date Imports 'Date' from JS and calls Date.now()",
" math Imports 'Math' from JS and calls Math.random()",
" wasi Uses the respective WASI interface.",
" ... Internal name of a custom function returning i64.",
""
],
"type": "s"
},

"memoryBase": {
"category": "Linking",
Expand Down
41 changes: 37 additions & 4 deletions std/assembly/math.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
/// <reference path="./util/seedrandom.d.ts" />

import { ArrayBufferView } from "./arraybuffer";
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By doing that, we can changetype<ArrayBufferView> anything accessing .dataStart, getting rid of TS syntax highlighting issues.

import * as JSMath from "./bindings/Math";
import * as JSDate from "./bindings/Date";
import * as wasi from "./bindings/wasi_snapshot";
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's something wrong here in that "./bindings/wasi" does not work. Can't find the symbols. Thought we had fixed those export * / import * problems :(


export { JSMath };

import {
Expand Down Expand Up @@ -135,7 +141,7 @@ function umuldi(u: u64, v: u64): u64 {

/** @internal */
function pio2_large_quot(x: f64, u: i64): i32 { // see: jdh8/metallic/blob/master/src/math/double/rem_pio2.c
const bits = PIO2_TABLE.dataStart;
const bits = changetype<ArrayBufferView>(PIO2_TABLE).dataStart;

var magnitude = u & 0x7FFFFFFFFFFFFFFF;
var offset = (magnitude >> 52) - 1045;
Expand Down Expand Up @@ -1410,7 +1416,7 @@ export namespace NativeMath {
}

export function random(): f64 { // see: v8/src/base/utils/random-number-generator.cc
if (!random_seeded) throw new Error("PRNG must be seeded.");
if (!random_seeded) seedRandom(seedRandomSelect());
var s1 = random_state0_64;
var s0 = random_state1_64;
random_state0_64 = s0;
Expand Down Expand Up @@ -1782,7 +1788,7 @@ function expo2f(x: f32): f32 { // exp(x)/2 for x >= log(DBL_MAX)
@inline
function pio2f_large_quot(x: f32, u: i32): i32 { // see: jdh8/metallic/blob/master/src/math/float/rem_pio2f.c
const coeff = reinterpret<f64>(0x3BF921FB54442D18); // π * 0x1p-65 = 8.51530395021638647334e-20
const bits = PIO2F_TABLE.dataStart;
const bits = changetype<ArrayBufferView>(PIO2F_TABLE).dataStart;

var offset = (u >> 23) - 152;
var shift = <u64>(offset & 63);
Expand Down Expand Up @@ -2603,7 +2609,7 @@ export namespace NativeMathf {

// Using xoroshiro64starstar from http://xoshiro.di.unimi.it/xoroshiro64starstar.c
export function random(): f32 {
if (!random_seeded) throw new Error("PRNG must be seeded.");
if (!random_seeded) NativeMath.seedRandom(seedRandomSelect());

var s0 = random_state0_32;
var s1 = random_state1_32;
Expand Down Expand Up @@ -3132,3 +3138,30 @@ export function ipow64f(x: f64, e: i32): f64 {
}
return sign ? 1.0 / out : out;
}

// @ts-ignore: decorator
@lazy
const seedRandomSelect_wasiBuf: i64[] = [ 0 ];

function seedRandomSelect(): i64 {
if (isDefined(ASC_SEEDRANDOM_FUNC)) return ASC_SEEDRANDOM_FUNC();
if (isDefined(ASC_SEEDRANDOM_MATH)) {
let val: i64;
do val = reinterpret<i64>(JSMath.random());
while (!val);
return val;
}
if (isDefined(ASC_SEEDRANDOM_DATE)) return <i64>JSDate.now();
if (isDefined(ASC_SEEDRANDOM_WASI)) {
let buf = changetype<ArrayBufferView>(seedRandomSelect_wasiBuf).dataStart;
let val: i64;
do assert(wasi.random_get(buf, 8) == wasi.errno.SUCCESS);
while (!(val = load<i64>(buf)));
return val;
}
if (!isDefined(ASC_SEEDRANDOM_CONST)) {
WARNING("Falling back to a compile-time constant random seed. See --seedRandom to silence this warning.");
}
const value = ((<i64>ASC_SEEDRANDOM_HIGH) << 32) | <i64><u32>ASC_SEEDRANDOM_LOW;
return value;
}
7 changes: 7 additions & 0 deletions std/assembly/util/seedrandom.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
declare const ASC_SEEDRANDOM_LOW: i32;
declare const ASC_SEEDRANDOM_HIGH: i32;
declare const ASC_SEEDRANDOM_CONST: i32;
declare const ASC_SEEDRANDOM_DATE: i32;
declare const ASC_SEEDRANDOM_MATH: i32;
declare const ASC_SEEDRANDOM_WASI: i32;
declare const ASC_SEEDRANDOM_FUNC: i32;
1 change: 1 addition & 0 deletions tests/compiler/std/array.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"asc_flags": [
"--runtime half",
"--explicitStart",
"--seedRandom math",
"--use ASC_RTRACE=1"
]
}
Loading