2008-10-06 Maciej Stachowiak <mjs@apple.com>
authormjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 6 Oct 2008 17:50:08 +0000 (17:50 +0000)
committermjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 6 Oct 2008 17:50:08 +0000 (17:50 +0000)
        Reviewed by Sam Weinig.

        - optimize op_jtrue, op_loop_if_true and op_not in various ways
        https://bugs.webkit.org/show_bug.cgi?id=21404

        1) Make JSValue::toBoolean nonvirtual and completely inline by
        making use of the StructureID type field.

        2) Make JSValue::toBoolean not take an ExecState; doesn't need it.

        3) Make op_not, op_loop_if_true and op_jtrue not read the
        ExecState (toBoolean doesn't need it any more) and not check
        exceptions (toBoolean can't throw).

        * API/JSValueRef.cpp:
        (JSValueToBoolean):
        * JavaScriptCore.exp:
        * VM/CodeBlock.cpp:
        (JSC::CodeBlock::dump):
        * VM/Machine.cpp:
        (JSC::Machine::privateExecute):
        (JSC::Machine::cti_op_loop_if_true):
        (JSC::Machine::cti_op_not):
        (JSC::Machine::cti_op_jtrue):
        * kjs/ArrayPrototype.cpp:
        (JSC::arrayProtoFuncFilter):
        (JSC::arrayProtoFuncEvery):
        (JSC::arrayProtoFuncSome):
        * kjs/BooleanConstructor.cpp:
        (JSC::constructBoolean):
        (JSC::callBooleanConstructor):
        * kjs/GetterSetter.h:
        * kjs/JSCell.h:
        (JSC::JSValue::toBoolean):
        * kjs/JSNumberCell.cpp:
        * kjs/JSNumberCell.h:
        (JSC::JSNumberCell::toBoolean):
        * kjs/JSObject.cpp:
        * kjs/JSObject.h:
        (JSC::JSObject::toBoolean):
        (JSC::JSCell::toBoolean):
        * kjs/JSString.cpp:
        * kjs/JSString.h:
        (JSC::JSString::toBoolean):
        * kjs/JSValue.h:
        * kjs/RegExpConstructor.cpp:
        (JSC::setRegExpConstructorMultiline):
        * kjs/RegExpObject.cpp:
        (JSC::RegExpObject::match):
        * kjs/RegExpPrototype.cpp:
        (JSC::regExpProtoFuncToString):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@37333 268f45cc-cd09-0410-ab3c-d52691b4dbfc

19 files changed:
JavaScriptCore/API/JSValueRef.cpp
JavaScriptCore/ChangeLog
JavaScriptCore/JavaScriptCore.exp
JavaScriptCore/VM/CodeBlock.cpp
JavaScriptCore/VM/Machine.cpp
JavaScriptCore/kjs/ArrayPrototype.cpp
JavaScriptCore/kjs/BooleanConstructor.cpp
JavaScriptCore/kjs/GetterSetter.h
JavaScriptCore/kjs/JSCell.h
JavaScriptCore/kjs/JSNumberCell.cpp
JavaScriptCore/kjs/JSNumberCell.h
JavaScriptCore/kjs/JSObject.cpp
JavaScriptCore/kjs/JSObject.h
JavaScriptCore/kjs/JSString.cpp
JavaScriptCore/kjs/JSString.h
JavaScriptCore/kjs/JSValue.h
JavaScriptCore/kjs/RegExpConstructor.cpp
JavaScriptCore/kjs/RegExpObject.cpp
JavaScriptCore/kjs/RegExpPrototype.cpp

index 4e99d3dd96e54b6d0589fb2f85b3eda09b82e6c1..68641a8bb57704fd02b8889e1eb5c0b28705e6a9 100644 (file)
@@ -188,11 +188,9 @@ JSValueRef JSValueMakeString(JSContextRef ctx, JSStringRef string)
     return toRef(jsString(exec, string->ustring()));
 }
 
-bool JSValueToBoolean(JSContextRef ctx, JSValueRef value)
+bool JSValueToBoolean(JSContextRef, JSValueRef value)
 {
-    ExecState* exec = toJS(ctx);
-    JSValue* jsValue = toJS(value);
-    return jsValue->toBoolean(exec);
+    return toJS(value)->toBoolean();
 }
 
 double JSValueToNumber(JSContextRef ctx, JSValueRef value, JSValueRef* exception)
index f23cedb86f7f125c2fd5e39a5718d912f2995599..11c2ffb558e6a1e14aec2e1c30051f1180e73936 100644 (file)
@@ -1,3 +1,57 @@
+2008-10-06  Maciej Stachowiak  <mjs@apple.com>
+
+        Reviewed by Sam Weinig.
+        
+        - optimize op_jtrue, op_loop_if_true and op_not in various ways
+        https://bugs.webkit.org/show_bug.cgi?id=21404
+        
+        1) Make JSValue::toBoolean nonvirtual and completely inline by
+        making use of the StructureID type field.
+        
+        2) Make JSValue::toBoolean not take an ExecState; doesn't need it.
+        
+        3) Make op_not, op_loop_if_true and op_jtrue not read the
+        ExecState (toBoolean doesn't need it any more) and not check
+        exceptions (toBoolean can't throw).
+
+        * API/JSValueRef.cpp:
+        (JSValueToBoolean):
+        * JavaScriptCore.exp:
+        * VM/CodeBlock.cpp:
+        (JSC::CodeBlock::dump):
+        * VM/Machine.cpp:
+        (JSC::Machine::privateExecute):
+        (JSC::Machine::cti_op_loop_if_true):
+        (JSC::Machine::cti_op_not):
+        (JSC::Machine::cti_op_jtrue):
+        * kjs/ArrayPrototype.cpp:
+        (JSC::arrayProtoFuncFilter):
+        (JSC::arrayProtoFuncEvery):
+        (JSC::arrayProtoFuncSome):
+        * kjs/BooleanConstructor.cpp:
+        (JSC::constructBoolean):
+        (JSC::callBooleanConstructor):
+        * kjs/GetterSetter.h:
+        * kjs/JSCell.h:
+        (JSC::JSValue::toBoolean):
+        * kjs/JSNumberCell.cpp:
+        * kjs/JSNumberCell.h:
+        (JSC::JSNumberCell::toBoolean):
+        * kjs/JSObject.cpp:
+        * kjs/JSObject.h:
+        (JSC::JSObject::toBoolean):
+        (JSC::JSCell::toBoolean):
+        * kjs/JSString.cpp:
+        * kjs/JSString.h:
+        (JSC::JSString::toBoolean):
+        * kjs/JSValue.h:
+        * kjs/RegExpConstructor.cpp:
+        (JSC::setRegExpConstructorMultiline):
+        * kjs/RegExpObject.cpp:
+        (JSC::RegExpObject::match):
+        * kjs/RegExpPrototype.cpp:
+        (JSC::regExpProtoFuncToString):
+
 2008-10-06  Ariya Hidayat  <ariya.hidayat@trolltech.com>
 
         Reviewed by Simon.
index 30e3b918df2ddc9c74eef5a6dcc95e9ea75dd2a8..1c969f2a40b480f5b427028424fd872324a14187 100644 (file)
@@ -335,7 +335,6 @@ __ZNK3JSC8JSObject8toNumberEPNS_9ExecStateE
 __ZNK3JSC8JSObject8toObjectEPNS_9ExecStateE
 __ZNK3JSC8JSObject8toStringEPNS_9ExecStateE
 __ZNK3JSC8JSObject9classNameEv
-__ZNK3JSC8JSObject9toBooleanEPNS_9ExecStateE
 __ZNK3JSC9CodeBlock17derefStructureIDsEPNS_11InstructionE
 __ZNK3JSC9HashTable11createTableEPNS_12JSGlobalDataE
 __ZNK3WTF8Collator7collateEPKtmS2_m
index 92371e374e7de26e55f25bef959f992c03a954c2..5bdb17a88e16c68e633533718afe41ff4bb2bef5 100644 (file)
@@ -810,13 +810,11 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
             break;
         }
         case op_tear_off_activation: {
-            int r0 = (++it)->u.operand;
-            printf("[%4d] tear_off_activation\t %s\n", location, registerName(r0).c_str());
+            printf("[%4d] tear_off_activation\n", location);
             break;
         }
         case op_tear_off_arguments: {
-            int r0 = (++it)->u.operand;
-            printf("[%4d] tear_off_arguments\t %s\n", location, registerName(r0).c_str());
+            printf("[%4d] tear_off_arguments\n", location);
             break;
         }
         case op_ret: {
index 280ecb2e0cfe4f2c4b516a3d7294f3eac1e95809..26bef38812601d53b5ae670efa2318a898c14a26 100644 (file)
@@ -2127,8 +2127,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, RegisterFile* registerFile,
         */
         int dst = (++vPC)->u.operand;
         int src = (++vPC)->u.operand;
-        JSValue* result = jsBoolean(!r[src].jsValue(exec)->toBoolean(exec));
-        VM_CHECK_EXCEPTION();
+        JSValue* result = jsBoolean(!r[src].jsValue(exec)->toBoolean());
         r[dst] = result;
 
         ++vPC;
@@ -2986,7 +2985,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, RegisterFile* registerFile,
          */
         int cond = (++vPC)->u.operand;
         int target = (++vPC)->u.operand;
-        if (r[cond].jsValue(exec)->toBoolean(exec)) {
+        if (r[cond].jsValue(exec)->toBoolean()) {
             vPC += target;
             CHECK_FOR_TIMEOUT();
             NEXT_OPCODE;
@@ -3003,7 +3002,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, RegisterFile* registerFile,
         */
         int cond = (++vPC)->u.operand;
         int target = (++vPC)->u.operand;
-        if (r[cond].jsValue(exec)->toBoolean(exec)) {
+        if (r[cond].jsValue(exec)->toBoolean()) {
             vPC += target;
             NEXT_OPCODE;
         }
@@ -3019,7 +3018,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, RegisterFile* registerFile,
         */
         int cond = (++vPC)->u.operand;
         int target = (++vPC)->u.operand;
-        if (!r[cond].jsValue(exec)->toBoolean(exec)) {
+        if (!r[cond].jsValue(exec)->toBoolean()) {
             vPC += target;
             NEXT_OPCODE;
         }
@@ -4988,11 +4987,7 @@ int Machine::cti_op_loop_if_true(CTI_ARGS)
 {
     JSValue* src1 = ARG_src1;
 
-    ExecState* exec = ARG_exec;
-
-    bool result = src1->toBoolean(exec);
-    VM_CHECK_EXCEPTION_AT_END();
-    return result;
+    return src1->toBoolean();
 }
 
 JSValue* Machine::cti_op_negate(CTI_ARGS)
@@ -5115,24 +5110,12 @@ int Machine::cti_op_jless(CTI_ARGS)
 
 JSValue* Machine::cti_op_not(CTI_ARGS)
 {
-    JSValue* src = ARG_src1;
-
-    ExecState* exec = ARG_exec;
-
-    JSValue* result = jsBoolean(!src->toBoolean(exec));
-    VM_CHECK_EXCEPTION_AT_END();
-    return result;
+    return jsBoolean(!ARG_src1->toBoolean());
 }
 
 int SFX_CALL Machine::cti_op_jtrue(CTI_ARGS)
 {
-    JSValue* src1 = ARG_src1;
-
-    ExecState* exec = ARG_exec;
-
-    bool result = src1->toBoolean(exec);
-    VM_CHECK_EXCEPTION_AT_END();
-    return result;
+    return ARG_src1->toBoolean();
 }
 
 JSValue* Machine::cti_op_post_inc(CTI_ARGS)
index 8dcfba20764e7b24b4dbcb0741a5a7129aff4436..9715663f133ac0b1c727041d54c50badc541cc1a 100644 (file)
@@ -582,7 +582,7 @@ JSValue* arrayProtoFuncFilter(ExecState* exec, JSObject*, JSValue* thisValue, co
 
         JSValue* result = call(exec, function, callType, callData, applyThis, eachArguments);
 
-        if (result->toBoolean(exec))
+        if (result->toBoolean())
             resultArray->put(exec, filterIndex++, v);
     }
     return resultArray;
@@ -656,7 +656,7 @@ JSValue* arrayProtoFuncEvery(ExecState* exec, JSObject*, JSValue* thisValue, con
         eachArguments.append(jsNumber(exec, k));
         eachArguments.append(thisObj);
 
-        bool predicateResult = call(exec, function, callType, callData, applyThis, eachArguments)->toBoolean(exec);
+        bool predicateResult = call(exec, function, callType, callData, applyThis, eachArguments)->toBoolean();
 
         if (!predicateResult) {
             result = jsBoolean(false);
@@ -720,7 +720,7 @@ JSValue* arrayProtoFuncSome(ExecState* exec, JSObject*, JSValue* thisValue, cons
         eachArguments.append(jsNumber(exec, k));
         eachArguments.append(thisObj);
 
-        bool predicateResult = call(exec, function, callType, callData, applyThis, eachArguments)->toBoolean(exec);
+        bool predicateResult = call(exec, function, callType, callData, applyThis, eachArguments)->toBoolean();
 
         if (predicateResult) {
             result = jsBoolean(true);
index 7eeb7776ddb6defe99415e3730ee28e7696fbaa5..16ccdf0c4c8dfbf8b27d5fab065e3fe9e0324079 100644 (file)
@@ -41,7 +41,7 @@ BooleanConstructor::BooleanConstructor(ExecState* exec, PassRefPtr<StructureID>
 JSObject* constructBoolean(ExecState* exec, const ArgList& args)
 {
     BooleanObject* obj = new (exec) BooleanObject(exec->lexicalGlobalObject()->booleanObjectStructure());
-    obj->setInternalValue(jsBoolean(args.at(exec, 0)->toBoolean(exec)));
+    obj->setInternalValue(jsBoolean(args.at(exec, 0)->toBoolean()));
     return obj;
 }
 
@@ -59,7 +59,7 @@ ConstructType BooleanConstructor::getConstructData(ConstructData& constructData)
 // ECMA 15.6.1
 static JSValue* callBooleanConstructor(ExecState* exec, JSObject*, JSValue*, const ArgList& args)
 {
-    return jsBoolean(args.at(exec, 0)->toBoolean(exec));
+    return jsBoolean(args.at(exec, 0)->toBoolean());
 }
 
 CallType BooleanConstructor::getCallData(CallData& callData)
index e8e6ff6bc58712f994223aa2449d93b4d0db9c40..cd9683da55ea39adddb4d400770b834c1e339ac5 100644 (file)
@@ -52,7 +52,7 @@ namespace JSC {
 
         virtual JSValue* toPrimitive(ExecState*, PreferredPrimitiveType) const;
         virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue*& value);
-        virtual bool toBoolean(ExecState*) const;
+        bool toBoolean(ExecState*) const;
         virtual double toNumber(ExecState*) const;
         virtual UString toString(ExecState*) const;
         virtual JSObject* toObject(ExecState*) const;
index bced0cd7940e7974a884fc476904527007486ea6..cd5753799d18a5b1ca1fb5c69f0256c45a807abf 100644 (file)
@@ -72,7 +72,7 @@ namespace JSC {
         // Basic conversions.
         virtual JSValue* toPrimitive(ExecState*, PreferredPrimitiveType) const = 0;
         virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue*&) = 0;
-        virtual bool toBoolean(ExecState*) const = 0;
+        bool toBoolean() const;
         virtual double toNumber(ExecState*) const = 0;
         virtual UString toString(ExecState*) const = 0;
         virtual JSObject* toObject(ExecState*) const = 0;
@@ -272,9 +272,9 @@ namespace JSC {
         return asCell()->getPrimitiveNumber(exec, number, value);
     }
 
-    inline bool JSValue::toBoolean(ExecState* exec) const
+    inline bool JSValue::toBoolean() const
     {
-        return JSImmediate::isImmediate(this) ? JSImmediate::toBoolean(this) : asCell()->toBoolean(exec);
+        return JSImmediate::isImmediate(this) ? JSImmediate::toBoolean(this) : asCell()->toBoolean();
     }
 
     ALWAYS_INLINE double JSValue::toNumber(ExecState* exec) const
index 5b3f3bd54b060c44c2bc106d01dfb4d56ffcdf5c..b8db2efdacbf85532d5a57cb9c82abb3767b7e5d 100644 (file)
@@ -40,11 +40,6 @@ bool JSNumberCell::getPrimitiveNumber(ExecState*, double& number, JSValue*& valu
     return true;
 }
 
-bool JSNumberCell::toBoolean(ExecState*) const
-{
-    return m_value < 0.0 || m_value > 0.0; // false for NaN
-}
-
 double JSNumberCell::toNumber(ExecState*) const
 {
   return m_value;
index 111665139718043b9162f1ed2fce1665ce90b3c3..44029a610b0409601675811bdeea92e8cd548297 100644 (file)
@@ -52,7 +52,7 @@ namespace JSC {
 
         virtual JSValue* toPrimitive(ExecState*, PreferredPrimitiveType) const;
         virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue*& value);
-        virtual bool toBoolean(ExecState*) const;
+        bool toBoolean() const { return m_value < 0.0 || m_value > 0.0; /* false for NaN */ }
         virtual double toNumber(ExecState*) const;
         virtual UString toString(ExecState*) const;
         virtual JSObject* toObject(ExecState*) const;
index cf5132e852a90d4796fcbf7bad46f9dc5effebb0..86ee2d1adc6cc7c613a1f90d86382654fd5f4ca1 100644 (file)
@@ -430,11 +430,6 @@ void JSObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyName
     m_structureID->getEnumerablePropertyNames(exec, propertyNames, this);
 }
 
-bool JSObject::toBoolean(ExecState*) const
-{
-    return true;
-}
-
 double JSObject::toNumber(ExecState* exec) const
 {
     JSValue* primitive = toPrimitive(exec, PreferNumber);
index c6c9cb99bdf62765fc7f3661f14d15ac8e01e3d7..14599e12ad5ead7ff3b9884ac1c7ece8e8aa8396 100644 (file)
@@ -28,6 +28,7 @@
 #include "CommonIdentifiers.h"
 #include "ExecState.h"
 #include "JSNumberCell.h"
+#include "JSString.h"
 #include "PropertyMap.h"
 #include "PropertySlot.h"
 #include "PutPropertySlot.h"
@@ -109,7 +110,7 @@ namespace JSC {
 
         virtual JSValue* toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const;
         virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue*& value);
-        virtual bool toBoolean(ExecState*) const;
+        bool toBoolean() const { return true; }
         virtual double toNumber(ExecState*) const;
         virtual UString toString(ExecState*) const;
         virtual JSObject* toObject(ExecState*) const;
@@ -246,6 +247,17 @@ inline bool JSCell::isObject(const ClassInfo* info) const
     return false;
 }
 
+inline bool JSCell::toBoolean() const
+{
+    JSType type = structureID()->typeInfo().type();
+    if (type == NumberType)
+        return static_cast<const JSNumberCell*>(this)->toBoolean();
+    if (type == ObjectType)
+        return static_cast<const JSObject*>(this)->toBoolean();
+    ASSERT(type == StringType);
+    return static_cast<const JSString*>(this)->toBoolean();
+}
+
 // this method is here to be after the inline declaration of JSCell::isObject
 inline bool JSValue::isObject(const ClassInfo* classInfo) const
 {
index 5844290a4f182488f33f7ce09b1c0c698edd2522..d3fbc3ed2ee13ab899433937bebe7e0e0585e5bf 100644 (file)
@@ -42,11 +42,6 @@ bool JSString::getPrimitiveNumber(ExecState*, double& number, JSValue*& value)
     return false;
 }
 
-bool JSString::toBoolean(ExecState*) const
-{
-    return !m_value.isEmpty();
-}
-
 double JSString::toNumber(ExecState*) const
 {
     return m_value.toDouble();
index d7c37bfc77d4f95f828d9213c5fe421337063fa3..fc49c1316db49b557dcd0bf602e8174dbbf160db 100644 (file)
@@ -92,6 +92,8 @@ namespace JSC {
 
         static PassRefPtr<StructureID> createStructureID(JSValue* proto) { return StructureID::create(proto, TypeInfo(StringType, NeedsThisConversion)); }
 
+        bool toBoolean() const { return !m_value.isEmpty(); }
+
     private:
         enum VPtrStealingHackType { VPtrStealingHack };
         JSString(VPtrStealingHackType) 
@@ -101,7 +103,6 @@ namespace JSC {
 
         virtual JSValue* toPrimitive(ExecState*, PreferredPrimitiveType) const;
         virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue*& value);
-        virtual bool toBoolean(ExecState*) const;
         virtual double toNumber(ExecState*) const;
         virtual JSObject* toObject(ExecState*) const;
         virtual UString toString(ExecState*) const;
index d0e45131ebdcf57a7982fbe2d63f1673f6d0b271..e3243a836d996b1460532331e36297f623edd896 100644 (file)
@@ -96,7 +96,7 @@ namespace JSC {
         JSValue* toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const;
         bool getPrimitiveNumber(ExecState*, double& number, JSValue*&);
 
-        bool toBoolean(ExecState*) const;
+        bool toBoolean() const;
 
         // toNumber conversion is expected to be side effect free if an exception has
         // been set in the ExecState already.
index d13f8363680422faab5bb4634ca8e92f38be2622..8441e50b2de0032cf32dd8426c3ab8bd17eae8e6 100644 (file)
@@ -311,9 +311,9 @@ void setRegExpConstructorInput(ExecState* exec, JSObject* baseObject, JSValue* v
     static_cast<RegExpConstructor*>(baseObject)->setInput(value->toString(exec));
 }
 
-void setRegExpConstructorMultiline(ExecState* exec, JSObject* baseObject, JSValue* value)
+void setRegExpConstructorMultiline(ExecState*, JSObject* baseObject, JSValue* value)
 {
-    static_cast<RegExpConstructor*>(baseObject)->setMultiline(value->toBoolean(exec));
+    static_cast<RegExpConstructor*>(baseObject)->setMultiline(value->toBoolean());
 }
   
 // ECMA 15.10.4
index 30896a215c471bde1b6203af675b031f540f4141..8d1b30594319dbec4107d2809e4a1d45cac465c6 100644 (file)
@@ -121,7 +121,7 @@ bool RegExpObject::match(ExecState* exec, const ArgList& args)
         }
     }
 
-    bool global = get(exec, exec->propertyNames().global)->toBoolean(exec);
+    bool global = get(exec, exec->propertyNames().global)->toBoolean();
     int lastIndex = 0;
     if (global) {
         if (d->lastIndex < 0 || d->lastIndex > input.size()) {
index 80d6dc790f69d03c14728ddb989f030585f8bba8..21a49cb00da358a6a9e973b5f1680f5549b3fdb5 100644 (file)
@@ -106,11 +106,11 @@ JSValue* regExpProtoFuncToString(ExecState* exec, JSObject*, JSValue* thisValue,
 
     UString result = "/" + static_cast<RegExpObject*>(thisValue)->get(exec, exec->propertyNames().source)->toString(exec);
     result.append('/');
-    if (static_cast<RegExpObject*>(thisValue)->get(exec, exec->propertyNames().global)->toBoolean(exec))
+    if (static_cast<RegExpObject*>(thisValue)->get(exec, exec->propertyNames().global)->toBoolean())
         result.append('g');
-    if (static_cast<RegExpObject*>(thisValue)->get(exec, exec->propertyNames().ignoreCase)->toBoolean(exec))
+    if (static_cast<RegExpObject*>(thisValue)->get(exec, exec->propertyNames().ignoreCase)->toBoolean())
         result.append('i');
-    if (static_cast<RegExpObject*>(thisValue)->get(exec, exec->propertyNames().multiline)->toBoolean(exec))
+    if (static_cast<RegExpObject*>(thisValue)->get(exec, exec->propertyNames().multiline)->toBoolean())
         result.append('m');
     return jsNontrivialString(exec, result);
 }