// Copyright 2020 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: --allow-natives-syntax --super-ic --sparkplug --no-always-sparkplug function run(f, ...args) { try { f(...args); } catch (e) {} %CompileBaseline(f); return f(...args); } function construct(f, ...args) { try { new f(...args); } catch (e) {} %CompileBaseline(f); return new f(...args); } // Constants assertEquals(run(()=>undefined), undefined); assertEquals(run(()=>null), null); assertEquals(run(()=>true), true); assertEquals(run(()=>false), false); assertEquals(run(()=>"bla"), "bla"); assertEquals(run(()=>42), 42); assertEquals(run(()=>0), 0); // Variables assertEquals(run(()=>{let a = 42; return a}), 42); assertEquals(run(()=>{let a = 42; let b = 32; return a}), 42); // Arguments assertEquals(run((a)=>a, 42), 42); assertEquals(run((a,b)=>b, 1, 42), 42); assertEquals(run((a,b,c)=>c, 1, 2, 42), 42); // Property load assertEquals(run((o)=>o.a, {a:42}), 42); assertEquals(run((o, k)=>o[k], {a:42}, "a"), 42); // Property store assertEquals(run((o)=>{o.a=42; return o}, {}).a, 42); assertEquals(run((o, k)=>{o[k]=42; return o}, {}, "a").a, 42); // Global load/store global_x = 45; assertEquals(run(()=>global_x), 45); run(()=>{ global_x = 49 }) assertEquals(global_x, 49); // Context load (function () { let x = 42; assertEquals(run(()=>{return x;}), 42); })(); (function () { let x = 4; x = 42; assertEquals(run(()=>{return x;}), 42); })(); // Context store (function () { let x = 4; run(()=>{x = 42;}); assertEquals(x, 42); })(); // Super // var o = {__proto__:{a:42}, m() { return super.a }}; // assertEquals(run(o.m), 42); // Control flow assertEquals(run((x)=>{ if(x) return 5; return 10;}), 10); assertEquals(run(()=>{ var x = 0; for(var i = 1; i; i=0) x=10; return x;}), 10); assertEquals(run(()=>{ var x = 0; for(var i = 0; i < 10; i+=1) x+=1; return x;}), 10); assertEquals(run(()=>{ var x = 0; for(var i = 0; i < 10; ++i) x+=1; return x;}), 10); // Typeof function testTypeOf(o, t) { let types = ['number', 'string', 'symbol', 'boolean', 'bigint', 'undefined', 'function', 'object']; assertEquals(t, eval('run(()=>typeof ' + o + ')'), `(()=>typeof ${o})() == ${t}`); assertTrue(eval('run(()=>typeof ' + o + ' == "' + t + '")'), `typeof ${o} == ${t}`); var other_types = types.filter((x) => x !== t); for (var other of other_types) { assertFalse(eval('run(()=>typeof ' + o + ' == "' + other + '")'), `typeof ${o} != ${other}`); } } testTypeOf('undefined', 'undefined'); testTypeOf('null', 'object'); testTypeOf('true', 'boolean'); testTypeOf('false', 'boolean'); testTypeOf('42.42', 'number'); testTypeOf('42', 'number'); testTypeOf('42n', 'bigint'); testTypeOf('"42"', 'string'); testTypeOf('Symbol(42)', 'symbol'); testTypeOf('{}', 'object'); testTypeOf('[]', 'object'); testTypeOf('new Proxy({}, {})', 'object'); testTypeOf('new Proxy([], {})', 'object'); testTypeOf('(_ => 42)', 'function'); testTypeOf('function() {}', 'function'); testTypeOf('function*() {}', 'function'); testTypeOf('async function() {}', 'function'); testTypeOf('async function*() {}', 'function'); testTypeOf('new Proxy(_ => 42, {})', 'function'); testTypeOf('class {}', 'function'); testTypeOf('Object', 'function'); // Binop assertEquals(run((a,b)=>{return a+b}, 41, 1), 42); assertEquals(run((a,b)=>{return a*b}, 21, 2), 42); assertEquals(run((a)=>{return a+3}, 39), 42); assertEquals(run((a,b)=>{return a&b}, 0x23, 0x7), 0x3); assertEquals(run((a)=>{return a&0x7}, 0x23), 0x3); assertEquals(run((a,b)=>{return a|b}, 0x23, 0x7), 0x27); assertEquals(run((a)=>{return a|0x7}, 0x23), 0x27); assertEquals(run((a,b)=>{return a^b}, 0x23, 0x7), 0x24); assertEquals(run((a)=>{return a^0x7}, 0x23), 0x24); // Unop assertEquals(run((x)=>{return x++}, 41), 41); assertEquals(run((x)=>{return ++x}, 41), 42); assertEquals(run((x)=>{return x--}, 41), 41); assertEquals(run((x)=>{return --x}, 41), 40); assertEquals(run((x)=>{return !x}, 41), false); assertEquals(run((x)=>{return ~x}, 41), ~41); // Calls function f0() { return 42; } function f1(x) { return x; } function f2(x, y) { return x + y; } function f3(x, y, z) { return y + z; } assertEquals(run(()=>{return f0()}), 42); assertEquals(run(()=>{return f1(42)}), 42); assertEquals(run(()=>{return f2(41, 1)}), 42); assertEquals(run(()=>{return f3(1, 2, 40)}), 42); // Mapped Arguments function mapped_args() { return [arguments.length, ...arguments]; } function mapped_args_dup(a,a) { return [arguments.length, ...arguments]; } assertEquals(run(mapped_args, 1, 2, 3), [3,1,2,3]); assertEquals(run(mapped_args_dup, 1, 2, 3), [3,1,2,3]); // Unmapped Arguments function unmapped_args() { "use strict"; return [arguments.length, ...arguments]; } assertEquals(run(unmapped_args, 1, 2, 3), [3,1,2,3]); // Rest Arguments function rest_args(...rest) { return [rest.length, ...rest]; } assertEquals(run(rest_args, 1, 2, 3), [3,1,2,3]); // Property call let obj = { f0: () => { return 42; }, f1: (x) => { return x; }, f2: (x, y) => { return x + y; }, f3: (x, y, z) => { return y + z; } } assertEquals(run(()=>{return obj.f0()}), 42); assertEquals(run(()=>{return obj.f1(42)}), 42); assertEquals(run(()=>{return obj.f2(41, 1)}), 42); assertEquals(run(()=>{return obj.f3(1, 2, 40)}), 42); // Call with spread let ns = [2, 40]; assertEquals(run(()=>{return f3("x", ...ns)}), 42); // Construct function C(a, b, c) { this.x = 39 + b + c; } assertEquals(run(()=>{return (new C("a", 1, 2)).x}), 42); assertEquals(run(()=>{return (new C("a", ...ns)).x}), 81); // Construct Array assertEquals(run(()=>{return new Array(1, 2, 39);}).reduce((a,x)=>a+x), 42); // Call Runtime assertMatches(run(() => { return %NewRegExpWithBacktrackLimit("ax", "", 50); }), "ax"); run(() => { %CompileBaseline(()=>{}); }); // CallRuntimeForPair assertEquals(run(()=>{with (f0) return f0();}), 42); // Closure assertEquals(run((o)=>{if (true) {let x = o; return ()=>x}}, 42)(), 42); assertEquals(run((o)=>{return ()=>o}, 42)(), 42); // Object / Array Literals assertEquals(run((o)=>{return {a:42}}), {a:42}); assertEquals(run((o)=>{return [42]}), [42]); assertEquals(run((o)=>{return []}), []); assertEquals(run((o)=>{return {}}), {}); assertEquals(run((o)=>{return {...o}}, {a:42}), {a:42}); assertEquals(run((o)=>{return /42/}), /42/); assertEquals(run((o)=>{return [...o]}, [1,2,3,4]), [1,2,3,4]); // Construct // Throw if the super() isn't a constructor class T extends Object { constructor() { super() } } T.__proto__ = null; assertThrows(()=>construct(T)); run((o)=>{ try { } finally { } }); // SwitchOnSmiNoFeeback run((o) => { var x = 0; var y = 0; while (true) { try { x++; if (x == 2) continue; if (x == 5) break; } finally { y++; } } return x + y; }, 10); // GetIterator assertEquals(run((o)=>{ let sum = 0; for (x of [1, 2]) {sum += x;} return sum;}), 3); // ForIn assertEquals(run((o)=>{ let sum = 0; for (let k in o) { sum += o[k] }; return sum }, {a:41,b:1}), 42); // In assertTrue(run((o, k)=>{return k in o}, {a:1}, "a")); assertFalse(run((o, k)=>{return k in o}, {a:1}, "b")); class D {} assertTrue(run((o, c)=>{return o instanceof c}, new D(), D)); assertTrue(run((o, c)=>{return o instanceof c}, new D(), Object)); assertFalse(run((o, c)=>{return o instanceof c}, new D(), RegExp)); // CreateArrayFromIterable assertEquals(run((a)=>{return [...a]}, [1,2,3]), [1,2,3]); // Generator let gen = run(function*() { yield 1; yield 2; yield 3; }); let i = 1; for (let val of gen) { assertEquals(i++, val); } assertEquals(4, i); // Generator with a lot of locals let gen_func_with_a_lot_of_locals = eval(`(function*() { ${ Array(32*1024).fill().map((x,i)=>`let local_${i};`).join("\n") } yield 1; yield 2; yield 3; })`); i = 1; for (let val of run(gen_func_with_a_lot_of_locals)) { assertEquals(i++, val); } assertEquals(4, i); // Async await run(async function() { await 1; await 1; await 1; return 42; }).then(x=>assertEquals(42, x)); // Try-catch assertEquals(run((x)=>{ if (x) { try { if (x) throw x; return 45; } catch (e) { return e; } } }, 42), 42); // Tier-up via InterpreterEntryTrampoline (function() { function factory() { return function(a) { return a; }; } let f1 = factory(); let f2 = factory(); %NeverOptimizeFunction(f1); %NeverOptimizeFunction(f2); assertEquals(f1(0), 0); assertEquals(f2(0), 0); assertTrue(isInterpreted(f1)) assertFalse(isBaseline(f1)); assertTrue(isInterpreted(f2)) assertFalse(isBaseline(f2)); %CompileBaseline(f1); assertEquals(f1(0), 0); assertTrue(isBaseline(f1)); assertFalse(isBaseline(f2)); assertEquals(f2(0), 0); assertTrue(isBaseline(f1)); assertTrue(isBaseline(f2)); })();