[DFG][FTL] regExpMatchFast should be handled
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 11 Jan 2018 14:20:40 +0000 (14:20 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 11 Jan 2018 14:20:40 +0000 (14:20 +0000)
https://bugs.webkit.org/show_bug.cgi?id=180988

Reviewed by Mark Lam.

RegExp.prototype.@@match has a fast path, @regExpMatchFast. This patch annotates this function
with RegExpMatchFastIntrinsic, and introduces RegExpMatch DFG node. This paves the way to
make NewRegexp PhantomNewRegexp if it is not used except for setting/getting its lastIndex property.

To improve RegExp.prototype.@@match's performance more, we make this builtin function small by moving
slow path part to `@matchSlow()` private function.

It improves SixSpeed regex-u.{es5,es6} largely since they stress String.prototype.match, which calls
this regExpMatchFast function.

                         baseline                  patched

regex-u.es5          55.3835+-6.3002     ^     36.2431+-2.0797        ^ definitely 1.5281x faster
regex-u.es6         110.4624+-6.2896     ^     94.1012+-7.2433        ^ definitely 1.1739x faster

* builtins/RegExpPrototype.js:
(globalPrivate.matchSlow):
(overriddenName.string_appeared_here.match):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsicCall):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNode.h:
(JSC::DFG::Node::hasHeapPrediction):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileRegExpMatch):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileRegExpMatch):
* runtime/Intrinsic.cpp:
(JSC::intrinsicName):
* runtime/Intrinsic.h:
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
* runtime/RegExpPrototype.cpp:
(JSC::regExpProtoFuncMatchFast):

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

23 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/builtins/RegExpPrototype.js
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGDoesGC.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/dfg/DFGOperations.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
Source/JavaScriptCore/runtime/Intrinsic.cpp
Source/JavaScriptCore/runtime/Intrinsic.h
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/RegExpPrototype.cpp

index c158bca..c5e2ffe 100644 (file)
@@ -1,3 +1,66 @@
+2018-01-11  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [DFG][FTL] regExpMatchFast should be handled
+        https://bugs.webkit.org/show_bug.cgi?id=180988
+
+        Reviewed by Mark Lam.
+
+        RegExp.prototype.@@match has a fast path, @regExpMatchFast. This patch annotates this function
+        with RegExpMatchFastIntrinsic, and introduces RegExpMatch DFG node. This paves the way to
+        make NewRegexp PhantomNewRegexp if it is not used except for setting/getting its lastIndex property.
+
+        To improve RegExp.prototype.@@match's performance more, we make this builtin function small by moving
+        slow path part to `@matchSlow()` private function.
+
+        It improves SixSpeed regex-u.{es5,es6} largely since they stress String.prototype.match, which calls
+        this regExpMatchFast function.
+
+                                 baseline                  patched
+
+        regex-u.es5          55.3835+-6.3002     ^     36.2431+-2.0797        ^ definitely 1.5281x faster
+        regex-u.es6         110.4624+-6.2896     ^     94.1012+-7.2433        ^ definitely 1.1739x faster
+
+        * builtins/RegExpPrototype.js:
+        (globalPrivate.matchSlow):
+        (overriddenName.string_appeared_here.match):
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::hasHeapPrediction):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileRegExpMatch):
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileRegExpMatch):
+        * runtime/Intrinsic.cpp:
+        (JSC::intrinsicName):
+        * runtime/Intrinsic.h:
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        * runtime/RegExpPrototype.cpp:
+        (JSC::regExpProtoFuncMatchFast):
+
 2018-01-11  Saam Barati  <sbarati@apple.com>
 
         Our for-in caching is wrong when we add indexed properties on things in the prototype chain
index 604cce2..4d17ac0 100644 (file)
@@ -79,22 +79,11 @@ function hasObservableSideEffectsForRegExpMatch(regexp) {
     return !@isRegExpObject(regexp);
 }
 
-@overriddenName="[Symbol.match]"
-function match(strArg)
+@globalPrivate
+function matchSlow(regexp, str)
 {
     "use strict";
 
-    if (!@isObject(this))
-        @throwTypeError("RegExp.prototype.@@match requires that |this| be an Object");
-
-    let regexp = this;
-
-    // Check for observable side effects and call the fast path if there aren't any.
-    if (!@hasObservableSideEffectsForRegExpMatch(regexp))
-        return @regExpMatchFast.@call(regexp, strArg);
-
-    let str = @toString(strArg);
-
     if (!regexp.global)
         return @regExpExec(regexp, str);
     
@@ -131,6 +120,22 @@ function match(strArg)
     }
 }
 
+@overriddenName="[Symbol.match]"
+function match(strArg)
+{
+    "use strict";
+
+    if (!@isObject(this))
+        @throwTypeError("RegExp.prototype.@@match requires that |this| be an Object");
+
+    let str = @toString(strArg);
+
+    // Check for observable side effects and call the fast path if there aren't any.
+    if (!@hasObservableSideEffectsForRegExpMatch(this))
+        return @regExpMatchFast.@call(this, str);
+    return @matchSlow(this, str);
+}
+
 @overriddenName="[Symbol.replace]"
 function replace(strArg, replace)
 {
index 3b203bf..bba74a8 100644 (file)
@@ -1964,6 +1964,12 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
             clobberWorld(node->origin.semantic, clobberLimit);
         forNode(node).setType(SpecBoolean);
         break;
+
+    case RegExpMatchFast:
+        ASSERT(node->child2().useKind() == RegExpObjectUse);
+        ASSERT(node->child3().useKind() == StringUse);
+        forNode(node).setType(m_graph, SpecOther | SpecArray);
+        break;
             
     case StringReplace:
     case StringReplaceRegExp:
index eebd1b4..7efe433 100644 (file)
@@ -2620,6 +2620,15 @@ bool ByteCodeParser::handleIntrinsicCall(Node* callee, int resultOperand, Intrin
         return true;
     }
 
+    case RegExpMatchFastIntrinsic: {
+        RELEASE_ASSERT(argumentCountIncludingThis == 2);
+
+        insertChecks();
+        Node* regExpMatch = addToGraph(RegExpMatchFast, OpInfo(0), OpInfo(prediction), addToGraph(GetGlobalObject, callee), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset)));
+        set(VirtualRegister(resultOperand), regExpMatch);
+        return true;
+    }
+
     case ObjectGetPrototypeOfIntrinsic: {
         if (argumentCountIncludingThis != 2)
             return false;
index bf2ac6e..c16c361 100644 (file)
@@ -1487,6 +1487,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
 
     case RegExpExec:
     case RegExpTest:
+    case RegExpMatchFast:
         if (node->child2().useKind() == RegExpObjectUse
             && node->child3().useKind() == StringUse) {
             read(RegExpState);
index cb0bbc4..c3e1646 100644 (file)
@@ -137,6 +137,7 @@ bool doesGC(Graph& graph, Node* node)
     case CheckStringIdent:
     case RegExpExec:
     case RegExpTest:
+    case RegExpMatchFast:
     case CompareLess:
     case CompareLessEq:
     case CompareGreater:
index 241912c..249e3b3 100644 (file)
@@ -1095,6 +1095,13 @@ private:
             break;
         }
 
+        case RegExpMatchFast: {
+            fixEdge<KnownCellUse>(node->child1());
+            fixEdge<RegExpObjectUse>(node->child2());
+            fixEdge<StringUse>(node->child3());
+            break;
+        }
+
         case StringReplace:
         case StringReplaceRegExp: {
             if (node->child2()->shouldSpeculateString()) {
index 59c779f..d4e4286 100644 (file)
@@ -1570,6 +1570,7 @@ public:
         case ArrayPush:
         case RegExpExec:
         case RegExpTest:
+        case RegExpMatchFast:
         case GetGlobalVar:
         case GetGlobalLexicalVariable:
         case StringReplace:
index fda29b1..46df7e9 100644 (file)
@@ -268,6 +268,7 @@ namespace JSC { namespace DFG {
     /* Optimizations for regular expression matching. */\
     macro(RegExpExec, NodeResultJS | NodeMustGenerate) \
     macro(RegExpTest, NodeResultJS | NodeMustGenerate) \
+    macro(RegExpMatchFast, NodeResultJS | NodeMustGenerate) \
     macro(StringReplace, NodeResultJS | NodeMustGenerate) \
     macro(StringReplaceRegExp, NodeResultJS | NodeMustGenerate) \
     \
index 1b7abed..21994c6 100644 (file)
@@ -1023,6 +1023,18 @@ EncodedJSValue JIT_OPERATION operationRegExpExecGeneric(ExecState* exec, JSGloba
     return JSValue::encode(asRegExpObject(base)->exec(exec, globalObject, input));
 }
 
+EncodedJSValue JIT_OPERATION operationRegExpMatchFastString(ExecState* exec, JSGlobalObject* globalObject, RegExpObject* regExpObject, JSString* argument)
+{
+    SuperSamplerScope superSamplerScope(false);
+
+    VM& vm = globalObject->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+
+    if (!regExpObject->regExp()->global())
+        return JSValue::encode(regExpObject->execInline(exec, globalObject, argument));
+    return JSValue::encode(regExpObject->matchGlobal(exec, globalObject, argument));
+}
+
 EncodedJSValue JIT_OPERATION operationParseIntNoRadixGeneric(ExecState* exec, EncodedJSValue value)
 {
     VM& vm = exec->vm();
index 7cf59ff..f7c3bdc 100644 (file)
@@ -151,6 +151,7 @@ EncodedJSValue JIT_OPERATION operationArrayPopAndRecoverLength(ExecState*, JSArr
 EncodedJSValue JIT_OPERATION operationRegExpExecString(ExecState*, JSGlobalObject*, RegExpObject*, JSString*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationRegExpExec(ExecState*, JSGlobalObject*, RegExpObject*, EncodedJSValue) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationRegExpExecGeneric(ExecState*, JSGlobalObject*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationRegExpMatchFastString(ExecState*, JSGlobalObject*, RegExpObject*, JSString*) WTF_INTERNAL;
 // These comparisons return a boolean within a size_t such that the value is zero extended to fill the register.
 size_t JIT_OPERATION operationRegExpTestString(ExecState*, JSGlobalObject*, RegExpObject*, JSString*) WTF_INTERNAL;
 size_t JIT_OPERATION operationRegExpTest(ExecState*, JSGlobalObject*, RegExpObject*, EncodedJSValue) WTF_INTERNAL;
index 4e36178..458f670 100644 (file)
@@ -697,6 +697,7 @@ private:
         case ArrayPush:
         case RegExpExec:
         case RegExpTest:
+        case RegExpMatchFast:
         case StringReplace:
         case StringReplaceRegExp:
         case GetById:
index c632c96..4ffe5d0 100644 (file)
@@ -261,6 +261,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
     case CheckStringIdent:
     case RegExpExec:
     case RegExpTest:
+    case RegExpMatchFast:
     case CompareLess:
     case CompareLessEq:
     case CompareGreater:
index a9f6a2c..3c07cc9 100644 (file)
@@ -10620,6 +10620,28 @@ void SpeculativeJIT::compileStringReplace(Node* node)
         m_jit.decrementSuperSamplerCount();
 }
 
+void SpeculativeJIT::compileRegExpMatchFast(Node* node)
+{
+    SpeculateCellOperand globalObject(this, node->child1());
+    SpeculateCellOperand base(this, node->child2());
+    SpeculateCellOperand argument(this, node->child3());
+    GPRReg globalObjectGPR = globalObject.gpr();
+    GPRReg baseGPR = base.gpr();
+    GPRReg argumentGPR = argument.gpr();
+    speculateRegExpObject(node->child2(), baseGPR);
+    speculateString(node->child3(), argumentGPR);
+
+    flushRegisters();
+    JSValueRegsFlushedCallResult result(this);
+    JSValueRegs resultRegs = result.regs();
+    callOperation(
+        operationRegExpMatchFastString, resultRegs,
+        globalObjectGPR, baseGPR, argumentGPR);
+    m_jit.exceptionCheck();
+
+    jsValueResult(resultRegs, node);
+}
+
 void SpeculativeJIT::compileLazyJSConstant(Node* node)
 {
     JSValueRegsTemporary result(this);
index e5e5a91..f21f624 100644 (file)
@@ -3065,6 +3065,7 @@ public:
     void compileArrayPush(Node*);
     void compileNotifyWrite(Node*);
     void compileRegExpExec(Node*);
+    void compileRegExpMatchFast(Node*);
     void compileRegExpTest(Node*);
     void compileStringReplace(Node*);
     void compileIsObjectOrNull(Node*);
index 4f3ed05..25ced1b 100644 (file)
@@ -3168,6 +3168,11 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
 
+    case RegExpMatchFast: {
+        compileRegExpMatchFast(node);
+        break;
+    }
+
     case StringReplace:
     case StringReplaceRegExp: {
         compileStringReplace(node);
index e1d684f..204af0c 100644 (file)
@@ -3438,6 +3438,11 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
 
+    case RegExpMatchFast: {
+        compileRegExpMatchFast(node);
+        break;
+    }
+
     case StringReplace:
     case StringReplaceRegExp: {
         compileStringReplace(node);
index d878f6e..0cf89ca 100644 (file)
@@ -276,6 +276,7 @@ inline CapabilityLevel canCompile(Node* node)
     case GetRestLength:
     case RegExpExec:
     case RegExpTest:
+    case RegExpMatchFast:
     case NewRegexp:
     case StringReplace:
     case StringReplaceRegExp: 
index a3d2aab..9951cf7 100644 (file)
@@ -1182,6 +1182,9 @@ private:
         case RegExpTest:
             compileRegExpTest();
             break;
+        case RegExpMatchFast:
+            compileRegExpMatchFast();
+            break;
         case NewRegexp:
             compileNewRegexp();
             break;
@@ -10270,6 +10273,17 @@ private:
         setBoolean(result);
     }
 
+    void compileRegExpMatchFast()
+    {
+        LValue globalObject = lowCell(m_node->child1());
+        LValue base = lowRegExpObject(m_node->child2());
+        LValue argument = lowString(m_node->child3());
+        LValue result = vmCall(
+            Int64, m_out.operation(operationRegExpMatchFastString), m_callFrame, globalObject,
+            base, argument);
+        setJSValue(result);
+    }
+
     void compileNewRegexp()
     {
         FrozenValue* regexp = m_node->cellOperand();
index ca15591..644151b 100644 (file)
@@ -111,6 +111,8 @@ const char* intrinsicName(Intrinsic intrinsic)
         return "RegExpTestIntrinsic";
     case RegExpTestFastIntrinsic:
         return "RegExpTestFastIntrinsic";
+    case RegExpMatchFastIntrinsic:
+        return "RegExpMatchFastIntrinsic";
     case ObjectGetPrototypeOfIntrinsic:
         return "ObjectGetPrototypeOfIntrinsic";
     case ReflectGetPrototypeOfIntrinsic:
index 390def8..bff96c0 100644 (file)
@@ -68,6 +68,7 @@ enum Intrinsic {
     RegExpExecIntrinsic,
     RegExpTestIntrinsic,
     RegExpTestFastIntrinsic,
+    RegExpMatchFastIntrinsic,
     ObjectGetPrototypeOfIntrinsic,
     ReflectGetPrototypeOfIntrinsic,
     StringPrototypeValueOfIntrinsic,
index d25e53a..9480613 100644 (file)
@@ -907,7 +907,7 @@ putDirectWithoutTransition(vm, vm.propertyNames-> jsName, lowerName ## Construct
         // RegExp.prototype helpers.
         GlobalPropertyInfo(vm.propertyNames->builtinNames().regExpBuiltinExecPrivateName(), builtinRegExpExec, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().regExpCreatePrivateName(), JSFunction::create(vm, this, 2, String(), esSpecRegExpCreate, NoIntrinsic), PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
-        GlobalPropertyInfo(vm.propertyNames->builtinNames().regExpMatchFastPrivateName(), JSFunction::create(vm, this, 1, String(), regExpProtoFuncMatchFast), PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
+        GlobalPropertyInfo(vm.propertyNames->builtinNames().regExpMatchFastPrivateName(), JSFunction::create(vm, this, 1, String(), regExpProtoFuncMatchFast, RegExpMatchFastIntrinsic), PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().regExpSearchFastPrivateName(), JSFunction::create(vm, this, 1, String(), regExpProtoFuncSearchFast), PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().regExpSplitFastPrivateName(), JSFunction::create(vm, this, 2, String(), regExpProtoFuncSplitFast), PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().regExpPrototypeSymbolReplacePrivateName(), m_regExpPrototype->getDirect(vm, vm.propertyNames->replaceSymbol), PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
index 7080738..37402a0 100644 (file)
@@ -131,22 +131,11 @@ EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState* exec)
 
 EncodedJSValue JSC_HOST_CALL regExpProtoFuncMatchFast(ExecState* exec)
 {
-    VM& vm = exec->vm();
-    auto scope = DECLARE_THROW_SCOPE(vm);
-
-    JSValue thisValue = exec->thisValue();
-    if (!thisValue.inherits(vm, RegExpObject::info()))
-        return throwVMTypeError(exec, scope);
-    JSString* string = exec->argument(0).toStringOrNull(exec);
-    EXCEPTION_ASSERT(!!scope.exception() == !string);
-    if (!string)
-        return encodedJSValue();
-    if (!asRegExpObject(thisValue)->regExp()->global()) {
-        scope.release();
-        return JSValue::encode(asRegExpObject(thisValue)->exec(exec, exec->lexicalGlobalObject(), string));
-    }
-    scope.release();
-    return JSValue::encode(asRegExpObject(thisValue)->matchGlobal(exec, exec->lexicalGlobalObject(), string));
+    RegExpObject* thisObject = asRegExpObject(exec->thisValue());
+    JSString* string = jsCast<JSString*>(exec->uncheckedArgument(0));
+    if (!thisObject->regExp()->global())
+        return JSValue::encode(thisObject->exec(exec, exec->lexicalGlobalObject(), string));
+    return JSValue::encode(thisObject->matchGlobal(exec, exec->lexicalGlobalObject(), string));
 }
 
 EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec)