[X2Go-Commits] [pale-moon] 05/294: Stage 1-3: Generate better source in Object.prototype.toSource.

git-admin at x2go.org git-admin at x2go.org
Sat Apr 27 08:57:40 CEST 2019


This is an automated email from the git hooks/post-receive script.

x2go pushed a commit to branch upstream/28.5.0
in repository pale-moon.

commit 90f6b2704658a554a12ed3c37545cb6474fbcf51
Author: wolfbeast <mcwerewolf at wolfbeast.com>
Date:   Sat Feb 2 14:29:54 2019 +0100

    Stage 1-3: Generate better source in Object.prototype.toSource.
    
    Tag #960.
---
 js/src/builtin/Object.cpp | 280 ++++++++++++++++++++++++++++++++--------------
 1 file changed, 193 insertions(+), 87 deletions(-)

diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp
index cd4ac12..389bb57 100644
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -9,11 +9,13 @@
 #include "mozilla/ArrayUtils.h"
 
 #include "jscntxt.h"
+#include "jsstr.h"
 
 #include "builtin/Eval.h"
 #include "frontend/BytecodeCompiler.h"
 #include "jit/InlinableNatives.h"
 #include "js/UniquePtr.h"
+#include "vm/AsyncFunction.h"
 #include "vm/StringBuffer.h"
 
 #include "jsobjinlines.h"
@@ -124,6 +126,27 @@ obj_toSource(JSContext* cx, unsigned argc, Value* vp)
     return true;
 }
 
+template <typename CharT>
+static bool
+Consume(const CharT*& s, const CharT* e, const char *chars)
+{
+    size_t len = strlen(chars);
+    if (s + len >= e)
+        return false;
+    if (!EqualChars(s, chars, len))
+        return false;
+    s += len;
+    return true;
+}
+
+template <typename CharT>
+static void
+ConsumeSpaces(const CharT*& s, const CharT* e)
+{
+    while (*s == ' ' && s < e)
+        s++;
+}
+
 /*
  * Given a function source string, return the offset and length of the part
  * between '(function $name' and ')'.
@@ -133,37 +156,53 @@ static bool
 ArgsAndBodySubstring(mozilla::Range<const CharT> chars, size_t* outOffset, size_t* outLen)
 {
     const CharT* const start = chars.begin().get();
-    const CharT* const end = chars.end().get();
     const CharT* s = start;
+    const CharT* e = chars.end().get();
 
-    uint8_t parenChomp = 0;
-    if (s[0] == '(') {
-        s++;
-        parenChomp = 1;
-    }
-
-    /* Try to jump "function" keyword. */
-    s = js_strchr_limit(s, ' ', end);
-    if (!s)
+    if (s == e)
         return false;
 
-    /*
-     * Jump over the function's name: it can't be encoded as part
-     * of an ECMA getter or setter.
-     */
-    s = js_strchr_limit(s, '(', end);
-    if (!s)
-        return false;
+    // Remove enclosing parentheses.
+    if (*s == '(' && *(e - 1) == ')') {
+        s++;
+        e--;
+    }
 
-    if (*s == ' ')
+    (void) Consume(s, e, "async");
+    ConsumeSpaces(s, e);
+    (void) (Consume(s, e, "function") || Consume(s, e, "get") || Consume(s, e, "set"));
+    ConsumeSpaces(s, e);
+    (void) Consume(s, e, "*");
+    ConsumeSpaces(s, e);
+
+    // Jump over the function's name.
+    if (Consume(s, e, "[")) {
+        s = js_strchr_limit(s, ']', e);
+        if (!s)
+            return false;
         s++;
+        ConsumeSpaces(s, e);
+        if (*s != '(')
+            return false;
+    } else {
+        s = js_strchr_limit(s, '(', e);
+        if (!s)
+            return false;
+    }
 
     *outOffset = s - start;
-    *outLen = end - s - parenChomp;
+    *outLen = e - s;
     MOZ_ASSERT(*outOffset + *outLen <= chars.length());
     return true;
 }
 
+enum class PropertyKind {
+    Getter,
+    Setter,
+    Method,
+    Normal
+};
+
 JSString*
 js::ObjectToSource(JSContext* cx, HandleObject obj)
 {
@@ -182,59 +221,28 @@ js::ObjectToSource(JSContext* cx, HandleObject obj)
     if (!buf.append('{'))
         return nullptr;
 
-    RootedValue v0(cx), v1(cx);
-    MutableHandleValue val[2] = {&v0, &v1};
-
-    RootedString str0(cx), str1(cx);
-    MutableHandleString gsop[2] = {&str0, &str1};
-
     AutoIdVector idv(cx);
     if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY | JSITER_SYMBOLS, &idv))
         return nullptr;
 
     bool comma = false;
-    for (size_t i = 0; i < idv.length(); ++i) {
-        RootedId id(cx, idv[i]);
-        Rooted<PropertyDescriptor> desc(cx);
-        if (!GetOwnPropertyDescriptor(cx, obj, id, &desc))
-            return nullptr;
-
-        int valcnt = 0;
-        if (desc.object()) {
-            if (desc.isAccessorDescriptor()) {
-                if (desc.hasGetterObject() && desc.getterObject()) {
-                    val[valcnt].setObject(*desc.getterObject());
-                    gsop[valcnt].set(cx->names().get);
-                    valcnt++;
-                }
-                if (desc.hasSetterObject() && desc.setterObject()) {
-                    val[valcnt].setObject(*desc.setterObject());
-                    gsop[valcnt].set(cx->names().set);
-                    valcnt++;
-                }
-            } else {
-                valcnt = 1;
-                val[0].set(desc.value());
-                gsop[0].set(nullptr);
-            }
-        }
-
+    auto AddProperty = [cx, &comma, &buf](HandleId id, HandleValue val, PropertyKind kind) -> bool {
         /* Convert id to a string. */
         RootedString idstr(cx);
         if (JSID_IS_SYMBOL(id)) {
             RootedValue v(cx, SymbolValue(JSID_TO_SYMBOL(id)));
             idstr = ValueToSource(cx, v);
             if (!idstr)
-                return nullptr;
+                return false;
         } else {
             RootedValue idv(cx, IdToValue(id));
             idstr = ToString<CanGC>(cx, idv);
             if (!idstr)
-                return nullptr;
+                return false;
 
             /*
-             * If id is a string that's not an identifier, or if it's a negative
-             * integer, then it must be quoted.
+             * If id is a string that's not an identifier, or if it's a
+             * negative integer, then it must be quoted.
              */
             if (JSID_IS_ATOM(id)
                 ? !IsIdentifier(JSID_TO_ATOM(id))
@@ -242,28 +250,65 @@ js::ObjectToSource(JSContext* cx, HandleObject obj)
             {
                 idstr = QuoteString(cx, idstr, char16_t('\''));
                 if (!idstr)
-                    return nullptr;
+                    return false;
             }
         }
 
-        for (int j = 0; j < valcnt; j++) {
-            /* Convert val[j] to its canonical source form. */
-            JSString* valsource = ValueToSource(cx, val[j]);
-            if (!valsource)
-                return nullptr;
+        RootedString valsource(cx, ValueToSource(cx, val));
+        if (!valsource)
+            return false;
 
-            RootedLinearString valstr(cx, valsource->ensureLinear(cx));
-            if (!valstr)
-                return nullptr;
+        RootedLinearString valstr(cx, valsource->ensureLinear(cx));
+        if (!valstr)
+            return false;
+
+        if (comma && !buf.append(", "))
+            return false;
+        comma = true;
+
+        size_t voffset, vlength;
+
+        // Methods and accessors can return exact syntax of source, that fits
+        // into property without adding property name or "get"/"set" prefix.
+        // Use the exact syntax when the following conditions are met:
+        //
+        //   * It's a function object
+        //     (exclude proxies)
+        //   * Function's kind and property's kind are same
+        //     (this can be false for dynamically defined properties)
+        //   * Function has explicit name
+        //     (this can be false for computed property and dynamically defined
+        //      properties)
+        //   * Function's name and property's name are same
+        //     (this can be false for dynamically defined properties)
+        if (kind == PropertyKind::Getter || kind == PropertyKind::Setter ||
+            kind == PropertyKind::Method)
+        {
+            RootedFunction fun(cx);
+            if (val.toObject().is<JSFunction>()) {
+                fun = &val.toObject().as<JSFunction>();
+                // Method's case should be checked on caller.
+                if (((fun->isGetter() && kind == PropertyKind::Getter) ||
+                     (fun->isSetter() && kind == PropertyKind::Setter) ||
+                     kind == PropertyKind::Method) &&
+                    fun->explicitName())
+                {
+                    bool result;
+                    if (!EqualStrings(cx, fun->explicitName(), idstr, &result))
+                        return false;
 
-            size_t voffset = 0;
-            size_t vlength = valstr->length();
+                    if (result)  {
+                        if (!buf.append(valstr))
+                            return false;
+                        return true;
+                    }
+                }
+            }
 
-            /*
-             * Remove '(function ' from the beginning of valstr and ')' from the
-             * end so that we can put "get" in front of the function definition.
-             */
-            if (gsop[j] && IsFunctionObject(val[j])) {
+            {
+                // When falling back try to generate a better string
+                // representation by skipping the prelude, and also removing
+                // the enclosing parentheses.
                 bool success;
                 JS::AutoCheckCannotGC nogc;
                 if (valstr->hasLatin1Chars())
@@ -271,29 +316,90 @@ js::ObjectToSource(JSContext* cx, HandleObject obj)
                 else
                     success = ArgsAndBodySubstring(valstr->twoByteRange(nogc), &voffset, &vlength);
                 if (!success)
-                    gsop[j].set(nullptr);
+                    kind = PropertyKind::Normal;
             }
 
-            if (comma && !buf.append(", "))
-                return nullptr;
-            comma = true;
+            if (kind == PropertyKind::Getter) {
+                if (!buf.append("get "))
+                    return false;
+            } else if (kind == PropertyKind::Setter) {
+                if (!buf.append("set "))
+                    return false;
+            } else if (kind == PropertyKind::Method && fun) {
+                if (IsWrappedAsyncFunction(fun)) {
+                    if (!buf.append("async "))
+                        return false;
+                }
 
-            if (gsop[j]) {
-                if (!buf.append(gsop[j]) || !buf.append(' '))
-                    return nullptr;
+                if (fun->isStarGenerator()) {
+                    if (!buf.append('*'))
+                        return false;
+                }
             }
-            if (JSID_IS_SYMBOL(id) && !buf.append('['))
-                return nullptr;
-            if (!buf.append(idstr))
-                return nullptr;
-            if (JSID_IS_SYMBOL(id) && !buf.append(']'))
-                return nullptr;
-            if (!buf.append(gsop[j] ? ' ' : ':'))
-                return nullptr;
+        }
 
+        bool needsBracket = JSID_IS_SYMBOL(id);
+        if (needsBracket && !buf.append('['))
+            return false;
+        if (!buf.append(idstr))
+            return false;
+        if (needsBracket && !buf.append(']'))
+            return false;
+
+        if (kind == PropertyKind::Getter || kind == PropertyKind::Setter ||
+            kind == PropertyKind::Method)
+        {
             if (!buf.appendSubstring(valstr, voffset, vlength))
-                return nullptr;
+                return false;
+        } else {
+            if (!buf.append(':'))
+                return false;
+            if (!buf.append(valstr))
+                return false;
+        }
+        return true;
+    };
+
+    RootedId id(cx);
+    Rooted<PropertyDescriptor> desc(cx);
+    RootedValue val(cx);
+    RootedFunction fun(cx);
+    for (size_t i = 0; i < idv.length(); ++i) {
+        id = idv[i];
+        if (!GetOwnPropertyDescriptor(cx, obj, id, &desc))
+            return nullptr;
+
+        if (!desc.object())
+            continue;
+
+        if (desc.isAccessorDescriptor()) {
+            if (desc.hasGetterObject() && desc.getterObject()) {
+                val.setObject(*desc.getterObject());
+                if (!AddProperty(id, val, PropertyKind::Getter))
+                    return nullptr;
+            }
+            if (desc.hasSetterObject() && desc.setterObject()) {
+                val.setObject(*desc.setterObject());
+                if (!AddProperty(id, val, PropertyKind::Setter))
+                    return nullptr;
+            }
+            continue;
         }
+
+        val.set(desc.value());
+        if (IsFunctionObject(val, fun.address())) {
+            if (IsWrappedAsyncFunction(fun))
+                fun = GetUnwrappedAsyncFunction(fun);
+
+            if (fun->isMethod()) {
+                if (!AddProperty(id, val, PropertyKind::Method))
+                    return nullptr;
+                continue;
+            }
+        }
+
+        if (!AddProperty(id, val, PropertyKind::Normal))
+            return nullptr;
     }
 
     if (!buf.append('}'))

--
Alioth's /home/x2go-admin/maintenancescripts/git/hooks/post-receive-email on /srv/git/code.x2go.org/pale-moon.git


More information about the x2go-commits mailing list