Commit f7d7b5c6 authored by Adam Klein's avatar Adam Klein Committed by Commit Bot

ToString of a Proxied function should not throw

Without --harmony-function-tostring, anything other than a JSFunction
or JSBoundFunction throw when Function.prototype.toString is called on
them. But with the toString revision, anything callable allows toString
(and for non-Functions returns the good old "function () { [native code] }"
string).

Bug: v8:7484
Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel
Change-Id: I3540e213a40992151761b59666fe36e0510da908
Reviewed-on: https://chromium-review.googlesource.com/932825
Commit-Queue: Adam Klein <adamk@chromium.org>
Reviewed-by: 's avatarSathya Gunasekaran <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51489}
parent 8a78db6d
...@@ -305,9 +305,16 @@ BUILTIN(FunctionPrototypeToString) { ...@@ -305,9 +305,16 @@ BUILTIN(FunctionPrototypeToString) {
Handle<Object> receiver = args.receiver(); Handle<Object> receiver = args.receiver();
if (receiver->IsJSBoundFunction()) { if (receiver->IsJSBoundFunction()) {
return *JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(receiver)); return *JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(receiver));
} else if (receiver->IsJSFunction()) { }
if (receiver->IsJSFunction()) {
return *JSFunction::ToString(Handle<JSFunction>::cast(receiver)); return *JSFunction::ToString(Handle<JSFunction>::cast(receiver));
} }
// With the revised toString behavior, all callable objects are valid
// receivers for this method.
if (FLAG_harmony_function_tostring && receiver->IsJSReceiver() &&
JSReceiver::cast(*receiver)->map()->is_callable()) {
return isolate->heap()->function_native_code_string();
}
THROW_NEW_ERROR_RETURN_FAILURE( THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kNotGeneric, isolate, NewTypeError(MessageTemplate::kNotGeneric,
isolate->factory()->NewStringFromAsciiChecked( isolate->factory()->NewStringFromAsciiChecked(
......
...@@ -79,6 +79,7 @@ ...@@ -79,6 +79,7 @@
V(Float64Array_string, "Float64Array") \ V(Float64Array_string, "Float64Array") \
V(fraction_string, "fraction") \ V(fraction_string, "fraction") \
V(Function_string, "Function") \ V(Function_string, "Function") \
V(function_native_code_string, "function () { [native code] }") \
V(function_string, "function") \ V(function_string, "function") \
V(function_to_string, "[object Function]") \ V(function_to_string, "[object Function]") \
V(Generator_string, "Generator") \ V(Generator_string, "Generator") \
......
...@@ -13212,9 +13212,6 @@ bool JSFunction::SetName(Handle<JSFunction> function, Handle<Name> name, ...@@ -13212,9 +13212,6 @@ bool JSFunction::SetName(Handle<JSFunction> function, Handle<Name> name,
namespace { namespace {
char const kNativeCodeSource[] = "function () { [native code] }";
Handle<String> NativeCodeFunctionSourceString( Handle<String> NativeCodeFunctionSourceString(
Handle<SharedFunctionInfo> shared_info) { Handle<SharedFunctionInfo> shared_info) {
Isolate* const isolate = shared_info->GetIsolate(); Isolate* const isolate = shared_info->GetIsolate();
...@@ -13231,7 +13228,7 @@ Handle<String> NativeCodeFunctionSourceString( ...@@ -13231,7 +13228,7 @@ Handle<String> NativeCodeFunctionSourceString(
// static // static
Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) { Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) {
Isolate* const isolate = function->GetIsolate(); Isolate* const isolate = function->GetIsolate();
return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource); return isolate->factory()->function_native_code_string();
} }
......
...@@ -1287,8 +1287,7 @@ TestKeysThrow({ ...@@ -1287,8 +1287,7 @@ TestKeysThrow({
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// String conversion (Object.prototype.toString, // String conversion (Object.prototype.toString,
// Object.prototype.toLocaleString, // Object.prototype.toLocaleString)
// Function.prototype.toString)
var key var key
...@@ -1306,7 +1305,6 @@ function TestToString(handler) { ...@@ -1306,7 +1305,6 @@ function TestToString(handler) {
assertEquals(Symbol.toStringTag, key) assertEquals(Symbol.toStringTag, key)
assertEquals("my_proxy", Object.prototype.toLocaleString.call(f)) assertEquals("my_proxy", Object.prototype.toLocaleString.call(f))
assertEquals("toString", key) assertEquals("toString", key)
assertThrows(function(){ Function.prototype.toString.call(f) })
var o = Object.create(p) var o = Object.create(p)
key = "" key = ""
......
// Copyright 2018 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: --noharmony-function-tostring
assertThrows(() => new Proxy(function() {}, {}).toString(), TypeError);
...@@ -122,3 +122,25 @@ testDynamicFunction("a, b", "return a"); ...@@ -122,3 +122,25 @@ testDynamicFunction("a, b", "return a");
testDynamicFunction("a,/*A*/b", "return a"); testDynamicFunction("a,/*A*/b", "return a");
testDynamicFunction("/*A*/a,b", "return a"); testDynamicFunction("/*A*/a,b", "return a");
testDynamicFunction("a,b", "return a/*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());
// Non-callable proxies still throw.
assertThrows(() => Function.prototype.toString.call(new Proxy({}, {})),
TypeError);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment