Sfoglia il codice sorgente

Fix several bugs around handling of functions wrapped in proxies.

The proxies are callable (have [[Call]] method) and in some scenarios should defer to the underlying functions.

Fixes:https://github.com/Microsoft/ChakraCore/issues/5282
Fixes:https://github.com/Microsoft/ChakraCore/issues/4728
Fixes:https://github.com/Microsoft/ChakraCore/issues/4730
Vladimir Sadov 7 anni fa
parent
commit
7a98bec1e1

+ 12 - 2
lib/Runtime/Library/JavascriptFunction.cpp

@@ -1551,12 +1551,22 @@ dbl_align:
 
         Assert(!(callInfo.Flags & CallFlags_New));
 
+        Var arg0 = args[0];
+
+        // callable proxy is considered as having [[Call]] internal method 
+        // and should behave here like a function.
+        // we will defer to the underlying target.
+        while (JavascriptProxy::Is(arg0) && JavascriptConversion::IsCallable(arg0))
+        {
+            arg0 = JavascriptProxy::FromVar(arg0)->GetTarget();
+        }
+
         AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
-        if (args.Info.Count == 0 || !JavascriptFunction::Is(args[0]))
+        if (args.Info.Count == 0 || !JavascriptFunction::Is(arg0))
         {
             JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedFunction, _u("Function.prototype.toString"));
         }
-        JavascriptFunction *pFunc = JavascriptFunction::FromVar(args[0]);
+        JavascriptFunction *pFunc = JavascriptFunction::FromVar(arg0);
 
         // pFunc can be from a different script context if Function.prototype.toString is invoked via .call/.apply.
         // Marshal the resulting string to the current script context (that of the toString)

+ 6 - 0
lib/Runtime/Library/JavascriptObject.cpp

@@ -478,6 +478,12 @@ using namespace Js;
             return library->GetObjectArrayDisplayString();
         }
 
+        // callable proxy is considered as having [[Call]] internal method and should match #8 below
+        if (type == TypeIds_Proxy && JavascriptConversion::IsCallable(thisArgAsObject))
+        {
+            type = TypeIds_Function;
+        }
+
         JavascriptString* builtInTag = nullptr;
         switch (type)
         {

+ 2 - 1
lib/Runtime/Library/JavascriptProxy.cpp

@@ -1657,7 +1657,8 @@ namespace Js
         }
         else
         {
-            return requestContext->GetLibrary()->GetObjectTypeDisplayString();
+            // handle nested cases recursively
+            return this->target->GetTypeOfString(requestContext);
         }
     }
 

+ 15 - 0
test/es6/ProxyInProxy.baseline

@@ -97,3 +97,18 @@ Symbol(prop5)
 "ownKeys" called
 "apply" called
 "construct" called
+***function wrapped in 2+ proxies
+function
+function
+function
+*** proxied function and Object.prototype.toString.call
+[object Function]
+[object Function]
+[object Array]
+[object Object]
+[object Object]
+[object Object]
+[object Object]
+*** proxied function and Function.prototype.toString.call
+function a() { }
+function a() { }

+ 53 - 0
test/es6/ProxyInProxy.js

@@ -172,7 +172,60 @@ function test4() {
     new (getProxy("construct", {}, function () {}));
 }
 
+function test5() {
+    print("***function wrapped in 2+ proxies");
+
+    function a() {}
+
+    const p1 = new Proxy(a, {})
+    console.log(typeof p1) // "function"
+    
+    const p2 = new Proxy(p1, {})
+    console.log(typeof p2) // "object" but should be "function"
+
+    const p3 = new Proxy(p2, {})
+    console.log(typeof p3) // "object" but should be "function"
+}
+
+function test6() {
+    print("*** proxied function and Object.prototype.toString.call");
+
+    console.log(Object.prototype.toString.call(new Proxy(function a() {}, {})));
+    // "[object Function]"
+
+    console.log(Object.prototype.toString.call(new Proxy(new Proxy(function a() {}, {}), {})));
+    // "[object Function]"
+
+    console.log(Object.prototype.toString.call(new Proxy([], {})));
+    // "[object Array]"
+    
+    console.log(Object.prototype.toString.call(new Proxy(new Number(1), {})));
+    // "[object Object]"
+    
+    console.log(Object.prototype.toString.call(new Proxy(new String(""), {})));
+    // "[object Object]"
+    
+    console.log(Object.prototype.toString.call(new Proxy(new Boolean(true), {})));
+    // "[object Object]"
+    
+    console.log(Object.prototype.toString.call(new Proxy(new Date, {})));
+    // "[object Object]"
+}
+
+function test7() {
+    print("*** proxied function and Function.prototype.toString.call");
+
+    console.log(Function.prototype.toString.call(new Proxy(function a() { }, {})));
+    // "[object Function]"
+
+    console.log(Function.prototype.toString.call(new Proxy(new Proxy(function a() { }, {}), {})));
+    // "[object Function]"
+}
+
 test1();
 test2();
 test3();
 test4();
+test5();
+test6();
+test7();

+ 1 - 1
test/es6/toStringTag.js

@@ -129,7 +129,7 @@ var tests = [
             }
 
             for (var row of internalSlotBuiltInsNoArray) {
-                testBuiltIn(row, "Object");
+                testBuiltIn(row, row.tag == "Function" ? "Function": "Object");
             }
         }
     },