asm-validation.js 11.3 KB
Newer Older
1 2 3 4 5 6
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Flags: --validate-asm --allow-natives-syntax

7 8 9 10 11 12
// Note that this test file contains tests that explicitly check modules are
// valid asm.js and then break them with invalid instantiation arguments. If
// this script is run more than once (e.g. --stress-opt) then modules remain
// broken in the second run and assertions would fail. We prevent re-runs.
// Flags: --nostress-opt

13 14
function assertValidAsm(func) {
  assertTrue(%IsAsmWasmCode(func));
15 16
}

17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
(function TestConst() {
  function Module(s) {
    "use asm";
    var fround = s.Math.fround;
    // Global constants. These are treated just like numeric literals.
    const fConst = fround(-3.0);
    const dConst = -3.0;
    const iConst = -3;

    // consts can be used to initialize other consts.
    const fPrime = fConst;

    // The following methods verify that return statements with global constants
    // do not need type annotations.
    function f() {
      return fPrime;
    }
    function d() {
      return dConst;
    }
    function i() {
      return iConst;
    }

    // The following methods verify that locals initialized with global
    // constants do not need type annotations.
    function fVar() {
      var v = fPrime;
      return fround(v);
    }
    function iVar() {
      var v = iConst;
      return v|0;
    }
    function dVar() {
      var v = dConst;
      return +v;
    }

    return {
      f: f, d: d, i: i,
      fVar: fVar, dVar: dVar, iVar: iVar,
    };
  }

  function DisallowAssignToConstGlobal() {
    const constant = 0;
    function invalid(i) {
      i = i|0;
      constant = i;
      return constant;
    }
    return invalid;
  }

  var m = Module(this);
  assertValidAsm(Module);

  assertEquals(-3, m.i());
  assertEquals(-3.0, m.d());
  assertEquals(Math.fround(-3.0), m.f());

  assertEquals(-3, m.iVar());
  assertEquals(-3.0, m.dVar());
  assertEquals(Math.fround(-3.0), m.fVar());

  var m = DisallowAssignToConstGlobal();
84
  assertFalse(%IsAsmWasmCode(DisallowAssignToConstGlobal));
85 86
})();

87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
(function TestModuleArgs() {
  function Module1(stdlib) {
    "use asm";
    function foo() { }
    return { foo: foo };
  }
  function Module2(stdlib, ffi) {
    "use asm";
    function foo() { }
    return { foo: foo };
  }
  function Module3(stdlib, ffi, heap) {
    "use asm";
    function foo() { }
    return { foo: foo };
  }
  var modules = [Module1, Module2, Module3];
  var heap = new ArrayBuffer(1024 * 1024);
  for (var i = 0; i < modules.length; ++i) {
    print('Module' + (i + 1));
    var module = modules[i];
108 109
    var m = module();
    assertValidAsm(module);
110
    var m = module({});
111
    assertValidAsm(module);
112
    var m = module({}, {});
113
    assertValidAsm(module);
114
    var m = module({}, {}, heap);
115
    assertValidAsm(module);
116
    var m = module({}, {}, heap, {});
117
    assertValidAsm(module);
118 119 120 121 122 123 124 125 126 127
  }
})();

(function TestBadModule() {
  function Module(stdlib, ffi, heap) {
    "use asm";
    function foo() { var y = 3; var x = 1 + y; return 123; }
    return { foo: foo };
  }
  var m = Module({});
128
  assertFalse(%IsAsmWasmCode(Module));
129 130 131 132 133 134
  assertEquals(123, m.foo());
})();

(function TestBadArgTypes() {
  function Module(a, b, c) {
    "use asm";
135
    var NaN = a.NaN;
136 137 138
    return {};
  }
  var m = Module(1, 2, 3);
139
  assertFalse(%IsAsmWasmCode(Module));
140 141 142 143 144 145
  assertEquals({}, m);
})();

(function TestBadArgTypesMismatch() {
  function Module(a, b, c) {
    "use asm";
146
    var NaN = a.NaN;
147 148 149
    return {};
  }
  var m = Module(1, 2);
150
  assertFalse(%IsAsmWasmCode(Module));
151 152 153 154 155 156 157 158 159 160
  assertEquals({}, m);
})();

(function TestModuleNoStdlib() {
  function Module() {
    "use asm";
    function foo() { return 123; }
    return { foo: foo };
  }
  var m = Module({});
161
  assertValidAsm(Module);
162 163 164 165 166 167 168 169 170 171 172
  assertEquals(123, m.foo());
})();

(function TestModuleWith5() {
  function Module(a, b, c, d, e) {
    "use asm";
    function foo() { return 123; }
    return { foo: foo };
  }
  var heap = new ArrayBuffer(1024 * 1024);
  var m = Module({}, {}, heap);
173
  assertFalse(%IsAsmWasmCode(Module));
174 175 176 177 178 179 180 181 182 183
  assertEquals(123, m.foo());
})();

(function TestModuleNoStdlibCall() {
  function Module(stdlib, ffi, heap) {
    "use asm";
    function foo() { return 123; }
    return { foo: foo };
  }
  var m = Module();
184
  assertValidAsm(Module);
185 186 187 188 189 190 191 192 193 194
  assertEquals(123, m.foo());
})();

(function TestModuleNew() {
  function Module(stdlib, ffi, heap) {
    "use asm";
    function foo() { return 123; }
    return { foo: foo };
  }
  var m = new Module({}, {});
195
  assertValidAsm(Module);
196 197 198 199 200 201
  assertEquals(123, m.foo());
})();

(function TestMultipleFailures() {
  function Module(stdlib) {
    "use asm";
202
    var NaN = stdlib.NaN;
203 204 205 206
    function foo() { return 123; }
    return { foo: foo };
  }
  var m1 = Module(1, 2, 3);
207
  assertFalse(%IsAsmWasmCode(Module));
208
  var m2 = Module(1, 2, 3);
209
  assertFalse(%IsAsmWasmCode(Module));
210 211 212 213 214 215 216 217
  assertEquals(123, m1.foo());
  assertEquals(123, m2.foo());
})();

(function TestFailureThenSuccess() {
  function MkModule() {
    function Module(stdlib, ffi, heap) {
      "use asm";
218
      var NaN = stdlib.NaN;
219 220 221 222 223 224 225 226 227
      function foo() { return 123; }
      return { foo: foo };
    }
    return Module;
  }
  var Module1 = MkModule();
  var Module2 = MkModule();
  var heap = new ArrayBuffer(1024 * 1024);
  var m1 = Module1(1, 2, 3);
228
  assertFalse(%IsAsmWasmCode(Module1));
229
  var m2 = Module2({}, {}, heap);
230
  assertFalse(%IsAsmWasmCode(Module2));
231 232 233 234 235 236 237 238
  assertEquals(123, m1.foo());
  assertEquals(123, m2.foo());
})();

(function TestSuccessThenFailure() {
  function MkModule() {
    function Module(stdlib, ffi, heap) {
      "use asm";
239
      var NaN = stdlib.NaN;
240 241 242 243 244 245 246 247
      function foo() { return 123; }
      return { foo: foo };
    }
    return Module;
  }
  var Module1 = MkModule();
  var Module2 = MkModule();
  var heap = new ArrayBuffer(1024 * 1024);
248 249
  var m1 = Module1({NaN: NaN}, {}, heap);
  assertValidAsm(Module1);
250
  var m2 = Module2(1, 2, 3);
251
  assertFalse(%IsAsmWasmCode(Module2));
252 253 254 255
  assertEquals(123, m1.foo());
  assertEquals(123, m2.foo());
})();

256 257 258 259
(function TestSuccessThenFailureThenRetry() {
  function MkModule() {
    function Module(stdlib, ffi, heap) {
      "use asm";
260
      var NaN = stdlib.NaN;
261 262 263 264 265 266 267 268
      function foo() { return 123; }
      return { foo: foo };
    }
    return Module;
  }
  var Module1 = MkModule();
  var Module2 = MkModule();
  var heap = new ArrayBuffer(1024 * 1024);
269 270
  var m1a = Module1({NaN: NaN}, {}, heap);
  assertValidAsm(Module1);
271
  var m2 = Module2(1, 2, 3);
272
  assertFalse(%IsAsmWasmCode(Module2));
273
  var m1b = Module1({NaN: NaN}, {}, heap);
274
  assertFalse(%IsAsmWasmCode(Module1));
275 276 277 278 279
  assertEquals(123, m1a.foo());
  assertEquals(123, m1b.foo());
  assertEquals(123, m2.foo());
})();

280 281 282 283 284 285 286 287 288
(function TestBoundFunction() {
  function Module(stdlib, ffi, heap) {
    "use asm";
    function foo() { return 123; }
    return { foo: foo };
  }
  var heap = new ArrayBuffer(1024 * 1024);
  var ModuleBound = Module.bind(this, {}, {}, heap);
  var m = ModuleBound();
289
  assertValidAsm(Module);
290 291
  assertEquals(123, m.foo());
})();
292 293 294 295 296 297 298 299 300

(function TestBadConstUnsignedReturn() {
  function Module() {
    "use asm";
    const i = 0xffffffff;
    function foo() { return i; }
    return { foo: foo };
  }
  var m = Module();
301
  assertFalse(%IsAsmWasmCode(Module));
302 303
  assertEquals(0xffffffff, m.foo());
})();
304

305
(function TestBadBooleanParamAnnotation() {
306 307 308 309 310 311 312 313 314
  function Module() {
    "use asm";
    function foo(x) {
      x = x | true;
      return x;
    }
    return { foo: foo };
  }
  var m = Module();
315
  assertFalse(%IsAsmWasmCode(Module));
316 317 318
  assertEquals(3, m.foo(3));
})();

319 320 321 322 323 324 325 326 327 328 329 330
(function TestBadExportTwice() {
  function Module() {
    "use asm";
    function bar() { return 1; }
    function baz() { return 2; }
    return {foo: bar, foo: baz};
  }
  var m = Module();
  assertTrue(%IsAsmWasmCode(Module));
  assertEquals(2, m.foo());
})();

331 332 333 334 335 336 337 338 339 340 341
(function TestBadImport() {
  function Module(stdlib) {
    "use asm";
    var set = 0;
    var foo = stdlib[set];
    return {};
  }
  var m = Module(this);
  assertFalse(%IsAsmWasmCode(Module));
})();

342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
(function TestBadFroundTrue() {
  function Module(stdlib) {
    "use asm";
    var fround = stdlib.Math.fround;
    function foo() {
      var x = fround(true);
      return +x;
    }
    return { foo: foo };
  }
  var m = Module(this);
  assertFalse(%IsAsmWasmCode(Module));
  assertEquals(1, m.foo());
})();

357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
(function TestBadCase() {
  function Module() {
    "use asm";
    function foo(x) {
      x = x | 0;
      switch (x|0) {
        case true:
          return 42;
        default:
          return 43;
      }
      return 0;
    }
    return { foo: foo };
  }
  var m = Module();
373
  assertFalse(%IsAsmWasmCode(Module));
374 375
  assertEquals(43, m.foo(3));
})();
376 377 378 379 380 381 382 383 384 385 386

(function TestVarHidesExport() {
  function Module() {
    "use asm";
    var foo;
    function foo() {}
    return foo;
  }
  Module();
  assertFalse(%IsAsmWasmCode(Module));
})();
387 388 389 390 391 392 393 394 395 396 397 398

(function TestUndefinedGlobalCall() {
  function Module() {
    "use asm";
    function foo() {
      return bar() | 0;
    }
    return foo;
  }
  Module();
  assertFalse(%IsAsmWasmCode(Module));
})();
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428

(function TestConditionalReturn() {
  function Module() {
    'use asm';
    function foo(a, b) {
      a = +a;
      b = +b;
      // Allowed, despite not matching the spec, as emscripten emits this in
      // practice.
      return a == b ? +a : +b;
    }
    return foo;
  }
  var m = Module();
  assertEquals(4, m(4, 4));
  assertEquals(5, m(4, 5));
  assertEquals(4, m(5, 4));
  assertValidAsm(Module);
})();

(function TestMismatchedConditionalReturn() {
  function Module() {
    'use asm';
    function foo(a, b) {
      a = +a;
      return a == 0.0 ? 0 : +a;
    }
    return foo;
  }
  Module();
429
  assertFalse(%IsAsmWasmCode(Module));
430 431 432 433 434 435 436 437 438 439 440 441 442 443
})();

(function TestBadIntConditionalReturn() {
  function Module() {
    'use asm';
    function foo(a, b) {
      a = a | 0;
      b = b | 0;
      // Disallowed because signature must be signed, but these will be int.
      return 1 ? a : b;
    }
    return foo;
  }
  Module();
444
  assertFalse(%IsAsmWasmCode(Module));
445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
})();

(function TestBadSignedConditionalReturn() {
  function Module() {
    'use asm';
    function foo(a, b) {
      a = a | 0;
      b = b | 0;
      // Disallowed because conditional yields int, even when both sides
      // are signed.
      return 1 ? a | 0 : b | 0;
    }
    return foo;
  }
  Module();
460
  assertFalse(%IsAsmWasmCode(Module));
461
})();
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476

(function TestAsmIsRegular() {
  function Module() {
    'use asm';
    var g = 123;
    function foo() {
      return g | 0;
    }
    return {x: foo};
  }
  var o = Module();
  assertValidAsm(Module);
  assertFalse(o instanceof WebAssembly.Instance);
  assertTrue(o instanceof Object);
  assertTrue(o.__proto__ === Object.prototype);
477 478 479 480 481
  var p = Object.getOwnPropertyDescriptor(o, "x")
  assertTrue(p.writable);
  assertTrue(p.enumerable);
  assertTrue(p.configurable);
  assertTrue(typeof o.x === 'function');
482 483 484 485 486
  o.x = 5;
  assertTrue(typeof o.x === 'number');
  assertTrue(o.__single_function__ === undefined);
  assertTrue(o.__foreign_init__ === undefined);
})();
487 488 489 490 491

(function TestAsmExportOrderPreserved() {
  function Module() {
    "use asm";
    function f() {}
492 493
    function g() {}
    return { a:f, b:g, x:f, c:g, d:f };
494 495 496 497 498 499
  }
  var m = Module();
  assertValidAsm(Module);
  var props = Object.getOwnPropertyNames(m);
  assertEquals(["a","b","x","c","d"], props);
})();