v8/test/mjsunit/harmony/function-tostring.js
Ross McIlroy ce409375b3 [sfi] Reduce FunctionTokenPosition and ExpectedNofProperties to 16 bits.
Changes SharedFunctionInfo to store a function_token_offset, relative
to the start_position, instead of the full function_token_position.
This enables us to reduce both FunctionTokenPosition and
ExpectedNofProperties to 16 bits each, saving 32 bits per SFI.

BUG=chromium:818642,chromium:783853
TBR=yangguo@chromium.org

Cq-Include-Trybots: luci.chromium.try:linux_chromium_rel_ng
Change-Id: I45aefcec605c1da502053c23c73564ceaed6c9b5
Reviewed-on: https://chromium-review.googlesource.com/1122982
Commit-Queue: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: Yang Guo <yangguo@chromium.org>
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54220}
2018-07-04 16:53:37 +00:00

171 lines
7.7 KiB
JavaScript

// 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: --harmony-function-tostring
var prefix = "/*before*/";
var suffix = "/*after*/";
function checkStringRepresentation(f, source) {
assertEquals(typeof f, "function");
assertEquals(source, f.toString());
}
function testDeclaration(source) {
// this eval should define a local variable f that is a function
eval(prefix + source + suffix);
checkStringRepresentation(f, source);
}
testDeclaration( "function f(){}");
testDeclaration( "function*f(){}");
testDeclaration("async function f(){}");
testDeclaration( "function/*A*/ f/*B*/(/*C*/a/*D*/,/*E*/b/*G*/)/*H*/{/*I*/}");
testDeclaration( "function/*A*/*f/*B*/(/*C*/a/*D*/,/*E*/b/*G*/)/*H*/{/*I*/}");
testDeclaration("async/*Z*/function/*A*/ f/*B*/(/*C*/a/*D*/,/*E*/b/*G*/)/*H*/{/*I*/}");
testDeclaration( "function \t f \n ( \r a \r\n,\n\r b ) {'\u2654'}");
testDeclaration( "function \t *f \n ( \r a \r\n,\n\r b ) { }");
testDeclaration( "function *\t f \n ( \r a \r\n,\n\r b ) { }");
testDeclaration("async \t function f \n ( \r a \r\n,\n\r b ) { }");
function testExpression(source) {
// this eval should return a function
var f = eval("(" + prefix + source + suffix + ")");
checkStringRepresentation(f, source);
}
testExpression( "function (){}");
testExpression( "function f(){}");
testExpression( "function* (){}");
testExpression( "function*f(){}");
testExpression("async function (){}");
testExpression("async function f(){}");
testExpression( "function/*A*/ /*B*/(/*C*/a/*D*/,/*E*/b/*G*/)/*H*/{/*I*/}");
testExpression( "function/*A*/ f/*B*/(/*C*/a/*D*/,/*E*/b/*G*/)/*H*/{/*I*/}");
testExpression( "function/*A*/* /*B*/(/*C*/a/*D*/,/*E*/b/*G*/)/*H*/{/*I*/}");
testExpression( "function/*A*/*f/*B*/(/*C*/a/*D*/,/*E*/b/*G*/)/*H*/{/*I*/}");
testExpression("async/*Z*/function/*A*/ f/*B*/(/*C*/a/*D*/,/*E*/b/*G*/)/*H*/{/*I*/}");
testExpression( "function \t \n ( \r a \r\n,\n\r b ) { }");
testExpression( "function \t f \n ( \r a \r\n,\n\r b ) { }");
testExpression( "function \t * \n ( \r a \r\n,\n\r b ) { }");
testExpression( "function \t *f \n ( \r a \r\n,\n\r b ) { }");
testExpression( "function *\t \n ( \r a \r\n,\n\r b ) { }");
testExpression( "function *\t f \n ( \r a \r\n,\n\r b ) { }");
testExpression("async \t function \n ( \r a \r\n,\n\r b ) { }");
testExpression( "(/*A*/ /*B*/ /*C*/ /*D*/ /*E*/ /*F*/)/*G*/=>/*H*/0");
testExpression( "a/*B*/ /*C*/ /*D*/ /*E*/ /*F*/ /*G*/=>/*H*/{}");
testExpression( "(/*A*/a/*B*/ /*C*/ /*D*/ /*E*/ /*F*/)/*G*/=>/*H*/0");
testExpression( "(/*A*/a/*B*/,/*C*/b/*D*/,/*E*/c/*F*/)/*G*/=>/*H*/{}");
testExpression("async (/*A*/ /*B*/ /*C*/ /*D*/ /*E*/ /*F*/)/*G*/=>/*H*/0");
testExpression("async a/*B*/ /*C*/ /*D*/ /*E*/ /*F*/ /*G*/=>/*H*/{}");
testExpression("async (/*A*/a/*B*/ /*C*/ /*D*/ /*E*/ /*F*/)/*G*/=>/*H*/0");
testExpression("async (/*A*/a/*B*/,/*C*/b/*D*/,/*E*/c/*F*/)/*G*/=>/*H*/{}");
function testSimpleMethod(source) {
// the source should define a method f
// object method
var f = eval("({" + prefix + source + suffix + "}.f)");
checkStringRepresentation(f, source);
// nonstatic class method
var f = eval("new class{" + prefix + source + suffix + "}().f");
checkStringRepresentation(f, source);
// static class method
var f = eval("(class{static" + prefix + source + suffix + "}).f");
checkStringRepresentation(f, source);
}
testSimpleMethod("f(){}");
testSimpleMethod("*f(){}");
testSimpleMethod("async f(){}");
testSimpleMethod("f \t (){}");
testSimpleMethod("* \tf(){}");
testSimpleMethod("async \t f (){}");
function testAccessorMethod(source, getOrSet) {
// the source should define a getter or setter method
// object method
var f = Object.getOwnPropertyDescriptor(eval("({" + prefix + source + suffix + "})"), "f")[getOrSet];
checkStringRepresentation(f, source);
// nonstatic class method
var f = Object.getOwnPropertyDescriptor(eval("(class{" + prefix + source + suffix + "})").prototype, "f")[getOrSet];
// static class method
var f = Object.getOwnPropertyDescriptor(eval("(class{static" + prefix + source + suffix + "})"), "f")[getOrSet];
checkStringRepresentation(f, source);
}
testAccessorMethod("get f( ){}", "get");
testAccessorMethod("set f(a){}", "set");
testAccessorMethod("get/*A*/f/*B*/(/*C*/ /*D*/)/*E*/{/*F*/}", "get");
testAccessorMethod("set/*A*/f/*B*/(/*C*/a/*D*/)/*E*/{/*F*/}", "set");
const GeneratorFunction = function*(){}.constructor;
const AsyncFunction = async function(){}.constructor;
function testDynamicFunction(...args) {
var P = args.slice(0, args.length - 1).join(",");
var bodyText = args.length > 0 ? args[args.length - 1] : "";
var source = " anonymous(" + P + "\n) {\n" + bodyText + "\n}";
checkStringRepresentation( Function(...args), "function" + source);
checkStringRepresentation(GeneratorFunction(...args), "function*" + source);
checkStringRepresentation( AsyncFunction(...args), "async function" + source);
}
testDynamicFunction();
testDynamicFunction(";");
testDynamicFunction("return");
testDynamicFunction("a", "return a");
testDynamicFunction("a", "b", "return a");
testDynamicFunction("a, b", "return a");
testDynamicFunction("a,/*A*/b", "return a");
testDynamicFunction("/*A*/a,b", "return a");
testDynamicFunction("a,b", "return a/*A*/");
// Proxies of functions should not throw, but return a NativeFunction.
assertEquals("function () { [native code] }",
new Proxy(function () { hidden }, {}).toString());
assertEquals("function () { [native code] }",
new Proxy(() => { hidden }, {}).toString());
assertEquals("function () { [native code] }",
new Proxy(class {}, {}).toString());
assertEquals("function () { [native code] }",
new Proxy(function() { hidden }.bind({}), {}).toString());
assertEquals("function () { [native code] }",
new Proxy(function*() { hidden }, {}).toString());
assertEquals("function () { [native code] }",
new Proxy(async function() { hidden }, {}).toString());
assertEquals("function () { [native code] }",
new Proxy(async function*() { hidden }, {}).toString());
assertEquals("function () { [native code] }",
new Proxy({ method() { hidden } }.method, {}).toString());
// Assert that we return a NativeFunction for script that has too large an
// offset between function token position and start position for us to return
// an exact representation of the source code.
function testLongFunctionTokenOffset(functionType) {
var expected = "function f() { [native code] }";
// Spec requires that we return something that will cause eval to throws if we
// can't reproduce the function's source code.
assertThrows(() => eval(expected), SyntaxError);
var functionSource = functionType + " ".repeat(65535) + " f(){}";
// Function declaration
eval(functionSource);
assertEquals(expected, f.toString());
// Function expression
var f = eval("(" + functionSource + ")");
assertEquals(expected, f.toString());
}
testLongFunctionTokenOffset("function");
testLongFunctionTokenOffset("function*");
testLongFunctionTokenOffset("async function");
testLongFunctionTokenOffset("async function*");
// Non-callable proxies still throw.
assertThrows(() => Function.prototype.toString.call(new Proxy({}, {})),
TypeError);