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: Sathya Gunasekaran <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51489}
diff --git a/src/builtins/builtins-function.cc b/src/builtins/builtins-function.cc
index 771c724..1f58c98 100644
--- a/src/builtins/builtins-function.cc
+++ b/src/builtins/builtins-function.cc
@@ -305,9 +305,16 @@
Handle<Object> receiver = args.receiver();
if (receiver->IsJSBoundFunction()) {
return *JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(receiver));
- } else if (receiver->IsJSFunction()) {
+ }
+ if (receiver->IsJSFunction()) {
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(
isolate, NewTypeError(MessageTemplate::kNotGeneric,
isolate->factory()->NewStringFromAsciiChecked(
diff --git a/src/heap-symbols.h b/src/heap-symbols.h
index 6efe9da..ae06892 100644
--- a/src/heap-symbols.h
+++ b/src/heap-symbols.h
@@ -79,6 +79,7 @@
V(Float64Array_string, "Float64Array") \
V(fraction_string, "fraction") \
V(Function_string, "Function") \
+ V(function_native_code_string, "function () { [native code] }") \
V(function_string, "function") \
V(function_to_string, "[object Function]") \
V(Generator_string, "Generator") \
diff --git a/src/objects.cc b/src/objects.cc
index 085776a..e4bb52d 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -13212,9 +13212,6 @@
namespace {
-char const kNativeCodeSource[] = "function () { [native code] }";
-
-
Handle<String> NativeCodeFunctionSourceString(
Handle<SharedFunctionInfo> shared_info) {
Isolate* const isolate = shared_info->GetIsolate();
@@ -13231,7 +13228,7 @@
// static
Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) {
Isolate* const isolate = function->GetIsolate();
- return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource);
+ return isolate->factory()->function_native_code_string();
}
diff --git a/test/mjsunit/es6/proxies.js b/test/mjsunit/es6/proxies.js
index 75a80a1..f67f9df 100644
--- a/test/mjsunit/es6/proxies.js
+++ b/test/mjsunit/es6/proxies.js
@@ -1287,8 +1287,7 @@
// ---------------------------------------------------------------------------
// String conversion (Object.prototype.toString,
-// Object.prototype.toLocaleString,
-// Function.prototype.toString)
+// Object.prototype.toLocaleString)
var key
@@ -1306,7 +1305,6 @@
assertEquals(Symbol.toStringTag, key)
assertEquals("my_proxy", Object.prototype.toLocaleString.call(f))
assertEquals("toString", key)
- assertThrows(function(){ Function.prototype.toString.call(f) })
var o = Object.create(p)
key = ""
diff --git a/test/mjsunit/es6/proxy-function-tostring.js b/test/mjsunit/es6/proxy-function-tostring.js
new file mode 100644
index 0000000..d859822
--- /dev/null
+++ b/test/mjsunit/es6/proxy-function-tostring.js
@@ -0,0 +1,7 @@
+// 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);
diff --git a/test/mjsunit/harmony/function-tostring.js b/test/mjsunit/harmony/function-tostring.js
index 949ac22..8fccf0d 100644
--- a/test/mjsunit/harmony/function-tostring.js
+++ b/test/mjsunit/harmony/function-tostring.js
@@ -122,3 +122,25 @@
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());
+
+// Non-callable proxies still throw.
+assertThrows(() => Function.prototype.toString.call(new Proxy({}, {})),
+ TypeError);