Use plain JSArray for RegExp matches instead of a lazily populated custom object.
authorakling@apple.com <akling@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 30 Oct 2014 03:54:23 +0000 (03:54 +0000)
committerakling@apple.com <akling@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 30 Oct 2014 03:54:23 +0000 (03:54 +0000)
<https://webkit.org/b/138191>

Reviewed by Geoffrey Garen.

We're already offering two RegExp matching APIs, one that collects subpattern
matches (exec), and one that simply tests for a match (test).
Given that, it was pretty overkill to lazily populate the resulting array of
matches, since the user could simply use test() if they didn't need them.

This allows the JIT to generate better code for RegExp match arrays, and also
enables some fast paths in the JSC runtime that check if an object isJSArray().

Looks like ~1.5% improvement on Octane/regexp according to run-jsc-benchmarks.

* jit/Repatch.cpp:
(JSC::tryCacheGetByID):
* runtime/JSArray.h:
(JSC::createArrayButterflyWithExactLength): Deleted.
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
* runtime/RegExpCachedResult.cpp:
(JSC::RegExpCachedResult::visitChildren):
(JSC::RegExpCachedResult::lastResult):
(JSC::RegExpCachedResult::leftContext):
(JSC::RegExpCachedResult::rightContext):
* runtime/RegExpCachedResult.h:
(JSC::RegExpCachedResult::RegExpCachedResult):
(JSC::RegExpCachedResult::record):
(JSC::RegExpCachedResult::input):
* runtime/RegExpConstructor.cpp:
(JSC::RegExpConstructor::getBackref):
(JSC::RegExpConstructor::getLastParen):
(JSC::RegExpConstructor::getLeftContext):
(JSC::RegExpConstructor::getRightContext):
* runtime/RegExpMatchesArray.cpp:
(JSC::createRegExpMatchesArray):
(JSC::RegExpMatchesArray::RegExpMatchesArray): Deleted.
(JSC::RegExpMatchesArray::create): Deleted.
(JSC::RegExpMatchesArray::finishCreation): Deleted.
(JSC::RegExpMatchesArray::visitChildren): Deleted.
(JSC::RegExpMatchesArray::reifyAllProperties): Deleted.
(JSC::RegExpMatchesArray::reifyMatchProperty): Deleted.
(JSC::RegExpMatchesArray::leftContext): Deleted.
(JSC::RegExpMatchesArray::rightContext): Deleted.
* runtime/RegExpMatchesArray.h:
(JSC::RegExpMatchesArray::createStructure): Deleted.
(JSC::RegExpMatchesArray::reifyAllPropertiesIfNecessary): Deleted.
(JSC::RegExpMatchesArray::reifyMatchPropertyIfNecessary): Deleted.
(JSC::RegExpMatchesArray::getOwnPropertySlot): Deleted.
(JSC::RegExpMatchesArray::getOwnPropertySlotByIndex): Deleted.
(JSC::RegExpMatchesArray::put): Deleted.
(JSC::RegExpMatchesArray::putByIndex): Deleted.
(JSC::RegExpMatchesArray::deleteProperty): Deleted.
(JSC::RegExpMatchesArray::deletePropertyByIndex): Deleted.
(JSC::RegExpMatchesArray::getOwnPropertyNames): Deleted.
(JSC::RegExpMatchesArray::defineOwnProperty): Deleted.
(JSC::isRegExpMatchesArray): Deleted.
* runtime/RegExpObject.cpp:
(JSC::RegExpObject::exec):
* runtime/StringPrototype.cpp:
(JSC::stringProtoFuncMatch):

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

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/jit/Repatch.cpp
Source/JavaScriptCore/runtime/JSArray.h
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/RegExpCachedResult.cpp
Source/JavaScriptCore/runtime/RegExpCachedResult.h
Source/JavaScriptCore/runtime/RegExpConstructor.cpp
Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp
Source/JavaScriptCore/runtime/RegExpMatchesArray.h
Source/JavaScriptCore/runtime/RegExpObject.cpp
Source/JavaScriptCore/runtime/StringPrototype.cpp

index 7bd3917..9d09b37 100644 (file)
@@ -1,3 +1,68 @@
+2014-10-29  Andreas Kling  <akling@apple.com>
+
+        Use plain JSArray for RegExp matches instead of a lazily populated custom object.
+        <https://webkit.org/b/138191>
+
+        Reviewed by Geoffrey Garen.
+
+        We're already offering two RegExp matching APIs, one that collects subpattern
+        matches (exec), and one that simply tests for a match (test).
+        Given that, it was pretty overkill to lazily populate the resulting array of
+        matches, since the user could simply use test() if they didn't need them.
+
+        This allows the JIT to generate better code for RegExp match arrays, and also
+        enables some fast paths in the JSC runtime that check if an object isJSArray().
+
+        Looks like ~1.5% improvement on Octane/regexp according to run-jsc-benchmarks.
+
+        * jit/Repatch.cpp:
+        (JSC::tryCacheGetByID):
+        * runtime/JSArray.h:
+        (JSC::createArrayButterflyWithExactLength): Deleted.
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        * runtime/RegExpCachedResult.cpp:
+        (JSC::RegExpCachedResult::visitChildren):
+        (JSC::RegExpCachedResult::lastResult):
+        (JSC::RegExpCachedResult::leftContext):
+        (JSC::RegExpCachedResult::rightContext):
+        * runtime/RegExpCachedResult.h:
+        (JSC::RegExpCachedResult::RegExpCachedResult):
+        (JSC::RegExpCachedResult::record):
+        (JSC::RegExpCachedResult::input):
+        * runtime/RegExpConstructor.cpp:
+        (JSC::RegExpConstructor::getBackref):
+        (JSC::RegExpConstructor::getLastParen):
+        (JSC::RegExpConstructor::getLeftContext):
+        (JSC::RegExpConstructor::getRightContext):
+        * runtime/RegExpMatchesArray.cpp:
+        (JSC::createRegExpMatchesArray):
+        (JSC::RegExpMatchesArray::RegExpMatchesArray): Deleted.
+        (JSC::RegExpMatchesArray::create): Deleted.
+        (JSC::RegExpMatchesArray::finishCreation): Deleted.
+        (JSC::RegExpMatchesArray::visitChildren): Deleted.
+        (JSC::RegExpMatchesArray::reifyAllProperties): Deleted.
+        (JSC::RegExpMatchesArray::reifyMatchProperty): Deleted.
+        (JSC::RegExpMatchesArray::leftContext): Deleted.
+        (JSC::RegExpMatchesArray::rightContext): Deleted.
+        * runtime/RegExpMatchesArray.h:
+        (JSC::RegExpMatchesArray::createStructure): Deleted.
+        (JSC::RegExpMatchesArray::reifyAllPropertiesIfNecessary): Deleted.
+        (JSC::RegExpMatchesArray::reifyMatchPropertyIfNecessary): Deleted.
+        (JSC::RegExpMatchesArray::getOwnPropertySlot): Deleted.
+        (JSC::RegExpMatchesArray::getOwnPropertySlotByIndex): Deleted.
+        (JSC::RegExpMatchesArray::put): Deleted.
+        (JSC::RegExpMatchesArray::putByIndex): Deleted.
+        (JSC::RegExpMatchesArray::deleteProperty): Deleted.
+        (JSC::RegExpMatchesArray::deletePropertyByIndex): Deleted.
+        (JSC::RegExpMatchesArray::getOwnPropertyNames): Deleted.
+        (JSC::RegExpMatchesArray::defineOwnProperty): Deleted.
+        (JSC::isRegExpMatchesArray): Deleted.
+        * runtime/RegExpObject.cpp:
+        (JSC::RegExpObject::exec):
+        * runtime/StringPrototype.cpp:
+        (JSC::stringProtoFuncMatch):
+
 2014-10-29  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Fix Type Dependency Issues
index d6e5cca..fb000d4 100644 (file)
@@ -638,7 +638,7 @@ static InlineCacheAction tryCacheGetByID(ExecState* exec, JSValue baseValue, con
     CodeBlock* codeBlock = exec->codeBlock();
     VM* vm = &exec->vm();
 
-    if ((isJSArray(baseValue) || isRegExpMatchesArray(baseValue) || isJSString(baseValue)) && propertyName == exec->propertyNames().length) {
+    if ((isJSArray(baseValue) || isJSString(baseValue)) && propertyName == exec->propertyNames().length) {
         GPRReg baseGPR = static_cast<GPRReg>(stubInfo.patch.baseGPR);
 #if USE(JSVALUE32_64)
         GPRReg resultTagGPR = static_cast<GPRReg>(stubInfo.patch.valueTagGPR);
@@ -647,7 +647,7 @@ static InlineCacheAction tryCacheGetByID(ExecState* exec, JSValue baseValue, con
 
         MacroAssembler stubJit;
 
-        if (isJSArray(baseValue) || isRegExpMatchesArray(baseValue)) {
+        if (isJSArray(baseValue)) {
             GPRReg scratchGPR = TempRegisterSet(stubInfo.patch.usedRegisters).getFreeGPR();
             bool needToRestoreScratch = false;
 
index 3e2b668..70029e6 100644 (file)
@@ -190,18 +190,6 @@ inline Butterfly* createContiguousArrayButterfly(VM& vm, JSCell* intendedOwner,
     return result;
 }
 
-inline Butterfly* createArrayButterflyWithExactLength(VM& vm, JSCell* intendedOwner, unsigned initialLength)
-{
-    Butterfly* butterfly = Butterfly::create(
-        vm, intendedOwner, 0, 0, true, indexingHeaderForArray(initialLength, initialLength),
-        ArrayStorage::sizeFor(initialLength));
-    ArrayStorage* storage = butterfly->arrayStorage();
-    storage->m_indexBias = 0;
-    storage->m_sparseMap.clear();
-    storage->m_numValuesInVector = 0;
-    return butterfly;
-}
-
 inline Butterfly* createArrayButterfly(VM& vm, JSCell* intendedOwner, unsigned initialLength)
 {
     Butterfly* butterfly = Butterfly::create(
index a68c78e..f823061 100644 (file)
@@ -288,8 +288,8 @@ void JSGlobalObject::init(VM& vm)
     m_originalArrayStructureForIndexingShape[SlowPutArrayStorageShape >> IndexingShapeShift].set(vm, this, JSArray::createStructure(vm, this, m_arrayPrototype.get(), ArrayWithSlowPutArrayStorage));
     for (unsigned i = 0; i < NumberOfIndexingShapes; ++i)
         m_arrayStructureForIndexingShapeDuringAllocation[i] = m_originalArrayStructureForIndexingShape[i];
-    
-    m_regExpMatchesArrayStructure.set(vm, this, RegExpMatchesArray::createStructure(vm, this, m_arrayPrototype.get()));
+
+    m_regExpMatchesArrayStructure.set(vm, this, Structure::create(vm, this, m_arrayPrototype.get(), TypeInfo(ObjectType, StructureFlags), JSArray::info(), ArrayWithSlowPutArrayStorage));
     
     RegExp* emptyRegex = RegExp::create(vm, "", NoFlags);
     
index 276ba33..671de4c 100644 (file)
@@ -37,18 +37,40 @@ void RegExpCachedResult::visitChildren(SlotVisitor& visitor)
     visitor.append(&m_lastRegExp);
     visitor.append(&m_reifiedInput);
     visitor.append(&m_reifiedResult);
+    visitor.append(&m_reifiedLeftContext);
+    visitor.append(&m_reifiedRightContext);
 }
 
-RegExpMatchesArray* RegExpCachedResult::lastResult(ExecState* exec, JSObject* owner)
+JSArray* RegExpCachedResult::lastResult(ExecState* exec, JSObject* owner)
 {
-    if (m_result) {
+    if (!m_reified) {
         m_reifiedInput.set(exec->vm(), owner, m_lastInput.get());
-        m_reifiedResult.set(exec->vm(), owner, RegExpMatchesArray::create(exec, m_lastInput.get(), m_lastRegExp.get(), m_result));
-        m_result = MatchResult::failed();
+        m_reifiedResult.set(exec->vm(), owner, createRegExpMatchesArray(exec, m_lastInput.get(), m_lastRegExp.get(), m_result));
+        m_reified = true;
     }
     return m_reifiedResult.get();
 }
 
+JSString* RegExpCachedResult::leftContext(ExecState* exec, JSObject* owner)
+{
+    // Make sure we're reified.
+    lastResult(exec, owner);
+    if (!m_reifiedLeftContext)
+        m_reifiedLeftContext.set(exec->vm(), owner, m_result.start ? jsSubstring(exec, m_reifiedInput.get(), 0, m_result.start) : jsEmptyString(exec));
+    return m_reifiedLeftContext.get();
+}
+
+JSString* RegExpCachedResult::rightContext(ExecState* exec, JSObject* owner)
+{
+    // Make sure we're reified.
+    lastResult(exec, owner);
+    if (!m_reifiedRightContext) {
+        unsigned length = m_reifiedInput->length();
+        m_reifiedRightContext.set(exec->vm(), owner, m_result.end != length ? jsSubstring(exec, m_reifiedInput.get(), m_result.end, length - m_result.end) : jsEmptyString(exec));
+    }
+    return m_reifiedRightContext.get();
+}
+
 void RegExpCachedResult::setInput(ExecState* exec, JSObject* owner, JSString* input)
 {
     // Make sure we're reified, otherwise m_reifiedInput will be ignored.
index 20a525c..bf6c0b8 100644 (file)
@@ -30,8 +30,8 @@
 
 namespace JSC {
 
+class JSArray;
 class JSString;
-class RegExpMatchesArray;
 
 // RegExpCachedResult is used to track the cached results of the last
 // match, stores on the RegExp constructor (e.g. $&, $_, $1, $2 ...).
@@ -46,6 +46,7 @@ class RegExpCachedResult {
 public:
     RegExpCachedResult(VM& vm, JSObject* owner, RegExp* emptyRegExp)
         : m_result(0, 0)
+        , m_reified(false)
     {
         m_lastInput.set(vm, owner, jsEmptyString(&vm));
         m_lastRegExp.set(vm, owner, emptyRegExp);
@@ -55,28 +56,34 @@ public:
     {
         m_lastRegExp.set(vm, owner, regExp);
         m_lastInput.set(vm, owner, input);
+        m_reifiedLeftContext.clear();
+        m_reifiedRightContext.clear();
         m_result = result;
+        m_reified = false;
     }
 
-    RegExpMatchesArray* lastResult(ExecState*, JSObject* owner);
+    JSArray* lastResult(ExecState*, JSObject* owner);
     void setInput(ExecState*, JSObject* owner, JSString*);
 
+    JSString* leftContext(ExecState*, JSObject* owner);
+    JSString* rightContext(ExecState*, JSObject* owner);
+
     JSString* input()
     {
-        // If m_result showas a match then we're in a lazy state, so m_lastInput
-        // is the most recent value of the input property. If not then we have
-        // reified, in which case m_reifiedInput will contain the correct value.
-        return m_result ? m_lastInput.get() : m_reifiedInput.get();
+        return m_reified ? m_reifiedInput.get() : m_lastInput.get();
     }
 
     void visitChildren(SlotVisitor&);
 
 private:
     MatchResult m_result;
+    bool m_reified;
     WriteBarrier<JSString> m_lastInput;
     WriteBarrier<RegExp> m_lastRegExp;
-    WriteBarrier<RegExpMatchesArray> m_reifiedResult;
+    WriteBarrier<JSArray> m_reifiedResult;
     WriteBarrier<JSString> m_reifiedInput;
+    WriteBarrier<JSString> m_reifiedLeftContext;
+    WriteBarrier<JSString> m_reifiedRightContext;
 };
 
 } // namespace JSC
index 46d853b..45e80f5 100644 (file)
@@ -116,7 +116,7 @@ void RegExpConstructor::visitChildren(JSCell* cell, SlotVisitor& visitor)
 
 JSValue RegExpConstructor::getBackref(ExecState* exec, unsigned i)
 {
-    RegExpMatchesArray* array = m_cachedResult.lastResult(exec, this);
+    JSArray* array = m_cachedResult.lastResult(exec, this);
 
     if (i < array->length()) {
         JSValue result = JSValue(array).get(exec, i);
@@ -129,7 +129,7 @@ JSValue RegExpConstructor::getBackref(ExecState* exec, unsigned i)
 
 JSValue RegExpConstructor::getLastParen(ExecState* exec)
 {
-    RegExpMatchesArray* array = m_cachedResult.lastResult(exec, this);
+    JSArray* array = m_cachedResult.lastResult(exec, this);
     unsigned length = array->length();
     if (length > 1) {
         JSValue result = JSValue(array).get(exec, length - 1);
@@ -142,12 +142,12 @@ JSValue RegExpConstructor::getLastParen(ExecState* exec)
 
 JSValue RegExpConstructor::getLeftContext(ExecState* exec)
 {
-    return m_cachedResult.lastResult(exec, this)->leftContext(exec);
+    return m_cachedResult.leftContext(exec, this);
 }
 
 JSValue RegExpConstructor::getRightContext(ExecState* exec)
 {
-    return m_cachedResult.lastResult(exec, this)->rightContext(exec);
+    return m_cachedResult.rightContext(exec, this);
 }
     
 bool RegExpConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
index 8cec4ea..3461cf0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 namespace JSC {
 
-const ClassInfo RegExpMatchesArray::s_info = {"Array", &JSArray::s_info, 0, CREATE_METHOD_TABLE(RegExpMatchesArray)};
-
-RegExpMatchesArray::RegExpMatchesArray(VM& vm, Butterfly* butterfly, JSGlobalObject* globalObject, JSString* input, RegExp* regExp, MatchResult result)
-    : JSArray(vm, globalObject->regExpMatchesArrayStructure(), butterfly)
-    , m_result(result)
-    , m_state(ReifiedNone)
-{
-    m_input.set(vm, this, input);
-    m_regExp.set(vm, this, regExp);
-}
-
-RegExpMatchesArray* RegExpMatchesArray::create(ExecState* exec, JSString* input, RegExp* regExp, MatchResult result)
+JSArray* createRegExpMatchesArray(ExecState* exec, JSString* input, RegExp* regExp, MatchResult result)
 {
     ASSERT(result);
     VM& vm = exec->vm();
-    Butterfly* butterfly = createArrayButterflyWithExactLength(vm, 0, regExp->numSubpatterns() + 1);
-    RegExpMatchesArray* array = new (NotNull, allocateCell<RegExpMatchesArray>(vm.heap)) RegExpMatchesArray(vm, butterfly, exec->lexicalGlobalObject(), input, regExp, result);
-    array->finishCreation(vm);
-    return array;
-}
-
-void RegExpMatchesArray::finishCreation(VM& vm)
-{
-    Base::finishCreation(vm);
-}
-
-void RegExpMatchesArray::visitChildren(JSCell* cell, SlotVisitor& visitor)
-{
-    RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell);
-    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
-    Base::visitChildren(thisObject, visitor);
-    visitor.append(&thisObject->m_input);
-    visitor.append(&thisObject->m_regExp);
-}
+    JSArray* array = JSArray::tryCreateUninitialized(vm, exec->lexicalGlobalObject()->regExpMatchesArrayStructure(), regExp->numSubpatterns() + 1);
+    RELEASE_ASSERT(array);
 
-void RegExpMatchesArray::reifyAllProperties(ExecState* exec)
-{
-    ASSERT(m_state != ReifiedAll);
-    ASSERT(m_result);
     SamplingRegion samplingRegion("Reifying substring properties");
-    
-    reifyMatchPropertyIfNecessary(exec);
 
-    if (unsigned numSubpatterns = m_regExp->numSubpatterns()) {
+    array->putDirectIndex(exec, 0, jsSubstring(exec, input, result.start, result.end - result.start));
+
+    if (unsigned numSubpatterns = regExp->numSubpatterns()) {
         Vector<int, 32> subpatternResults;
-        int position = m_regExp->match(exec->vm(), m_input->value(exec), m_result.start, subpatternResults);
-        ASSERT_UNUSED(position, position >= 0 && static_cast<size_t>(position) == m_result.start);
-        ASSERT(m_result.start == static_cast<size_t>(subpatternResults[0]));
-        ASSERT(m_result.end == static_cast<size_t>(subpatternResults[1]));
+        int position = regExp->match(exec->vm(), input->value(exec), result.start, subpatternResults);
+        ASSERT_UNUSED(position, position >= 0 && static_cast<size_t>(position) == result.start);
+        ASSERT(result.start == static_cast<size_t>(subpatternResults[0]));
+        ASSERT(result.end == static_cast<size_t>(subpatternResults[1]));
 
         for (unsigned i = 1; i <= numSubpatterns; ++i) {
             int start = subpatternResults[2 * i];
             if (start >= 0)
-                putDirectIndex(exec, i, jsSubstring(exec, m_input.get(), start, subpatternResults[2 * i + 1] - start));
+                array->putDirectIndex(exec, i, jsSubstring(exec, input, start, subpatternResults[2 * i + 1] - start));
             else
-                putDirectIndex(exec, i, jsUndefined());
+                array->putDirectIndex(exec, i, jsUndefined());
         }
     }
 
-    putDirect(exec->vm(), exec->propertyNames().index, jsNumber(m_result.start));
-    putDirect(exec->vm(), exec->propertyNames().input, m_input.get());
-
-    m_state = ReifiedAll;
-}
-
-void RegExpMatchesArray::reifyMatchProperty(ExecState* exec)
-{
-    ASSERT(m_state == ReifiedNone);
-    ASSERT(m_result);
-    putDirectIndex(exec, 0, jsSubstring(exec, m_input.get(), m_result.start, m_result.end - m_result.start));
-    m_state = ReifiedMatch;
-}
-
-JSString* RegExpMatchesArray::leftContext(ExecState* exec)
-{
-    if (!m_result.start)
-        return jsEmptyString(exec);
-    return jsSubstring(exec, m_input.get(), 0, m_result.start);
-}
+    array->putDirect(exec->vm(), exec->propertyNames().index, jsNumber(result.start));
+    array->putDirect(exec->vm(), exec->propertyNames().input, input);
 
-JSString* RegExpMatchesArray::rightContext(ExecState* exec)
-{
-    unsigned length = m_input->length();
-    if (m_result.end == length)
-        return jsEmptyString(exec);
-    return jsSubstring(exec, m_input.get(), m_result.end, length - m_result.end);
+    return array;
 }
 
 } // namespace JSC
index ac7f895..df72fae 100644 (file)
 
 namespace JSC {
 
-class RegExpMatchesArray : public JSArray {
-private:
-    RegExpMatchesArray(VM&, Butterfly*, JSGlobalObject*, JSString*, RegExp*, MatchResult);
-
-    enum ReifiedState { ReifiedNone, ReifiedMatch, ReifiedAll };
-
-public:
-    typedef JSArray Base;
-
-    static RegExpMatchesArray* create(ExecState*, JSString*, RegExp*, MatchResult);
-
-    JSString* leftContext(ExecState*);
-    JSString* rightContext(ExecState*);
-
-    DECLARE_INFO;
-
-    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
-    {
-        return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info(), ArrayWithSlowPutArrayStorage);
-    }
-
-    static void visitChildren(JSCell*, SlotVisitor&);
-
-protected:
-    void finishCreation(VM&);
-
-    static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | Base::StructureFlags;
-
-private:
-    ALWAYS_INLINE void reifyAllPropertiesIfNecessary(ExecState* exec)
-    {
-        if (m_state != ReifiedAll)
-            reifyAllProperties(exec);
-    }
-
-    ALWAYS_INLINE void reifyMatchPropertyIfNecessary(ExecState* exec)
-    {
-        if (m_state == ReifiedNone)
-            reifyMatchProperty(exec);
-    }
-
-    static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
-    {
-        RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(object);
-        thisObject->reifyAllPropertiesIfNecessary(exec);
-        return JSArray::getOwnPropertySlot(thisObject, exec, propertyName, slot);
-    }
-
-    static bool getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned propertyName, PropertySlot& slot)
-    {
-        RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(object);
-        if (propertyName)
-            thisObject->reifyAllPropertiesIfNecessary(exec);
-        else
-            thisObject->reifyMatchPropertyIfNecessary(exec);
-        return JSArray::getOwnPropertySlotByIndex(thisObject, exec, propertyName, slot);
-    }
-
-    static void put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue v, PutPropertySlot& slot)
-    {
-        RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell);
-        thisObject->reifyAllPropertiesIfNecessary(exec);
-        JSArray::put(thisObject, exec, propertyName, v, slot);
-    }
-
-    static void putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue v, bool shouldThrow)
-    {
-        RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell);
-        thisObject->reifyAllPropertiesIfNecessary(exec);
-        JSArray::putByIndex(thisObject, exec, propertyName, v, shouldThrow);
-    }
-
-    static bool deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
-    {
-        RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell);
-        thisObject->reifyAllPropertiesIfNecessary(exec);
-        return JSArray::deleteProperty(thisObject, exec, propertyName);
-    }
-
-    static bool deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned propertyName)
-    {
-        RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell);
-        thisObject->reifyAllPropertiesIfNecessary(exec);
-        return JSArray::deletePropertyByIndex(thisObject, exec, propertyName);
-    }
-
-    static void getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& arr, EnumerationMode mode = ExcludeDontEnumProperties)
-    {
-        RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(object);
-        thisObject->reifyAllPropertiesIfNecessary(exec);
-        JSArray::getOwnPropertyNames(thisObject, exec, arr, mode);
-    }
-
-    static bool defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow)
-    {
-        RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(object);
-        thisObject->reifyAllPropertiesIfNecessary(exec);
-        return JSArray::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow);
-    }
-
-    void reifyAllProperties(ExecState*);
-    void reifyMatchProperty(ExecState*);
-
-    WriteBarrier<JSString> m_input;
-    WriteBarrier<RegExp> m_regExp;
-    MatchResult m_result;
-    ReifiedState m_state;
-};
-
-inline bool isRegExpMatchesArray(JSValue value)
-{
-    return value.isCell() && value.asCell()->classInfo() == RegExpMatchesArray::info();
-}
+JSArray* createRegExpMatchesArray(ExecState*, JSString*, RegExp*, MatchResult);
 
 }
 
index 9b173fc..5b91ac2 100644 (file)
@@ -302,7 +302,7 @@ void RegExpObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName,
 JSValue RegExpObject::exec(ExecState* exec, JSString* string)
 {
     if (MatchResult result = match(exec, string))
-        return RegExpMatchesArray::create(exec, string, regExp(), result);
+        return createRegExpMatchesArray(exec, string, regExp(), result);
     return jsNull();
 }
 
index 0e39a39..04d2bdc 100644 (file)
@@ -864,7 +864,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec)
     MatchResult result = regExpConstructor->performMatch(*vm, regExp, string, s, 0);
     // case without 'g' flag is handled like RegExp.prototype.exec
     if (!global)
-        return JSValue::encode(result ? RegExpMatchesArray::create(exec, string, regExp, result) : jsNull());
+        return JSValue::encode(result ? createRegExpMatchesArray(exec, string, regExp, result) : jsNull());
 
     // return array of matches
     MarkedArgumentBuffer list;