RegExpMatchesArray doesn't know how to have a bad time
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 6 Mar 2016 20:11:09 +0000 (20:11 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 6 Mar 2016 20:11:09 +0000 (20:11 +0000)
https://bugs.webkit.org/show_bug.cgi?id=155069

Reviewed by Yusuke Suzuki.

Source/JavaScriptCore:

In trunk if we are having a bad time, the regexp matches array is still allocated with a
non-slow-put indexing shape, which makes it have the wrong behavior on indexed setters on
the prototype chain.

Getting this to work right requires introducing bad time code paths into the regexp matches
array. It also requires something more drastic: making this code not play games with the
global object. The code that creates the matches array needs to have the actual global
object of the regexp native function that it's logically created by.

This is totally different from how we've handled global objects in the past because it means
that the global object is not a constant. Normally we can make it a constant because a
script executable will know its global object. But with native functions, it's the function
instance that knows the global object - not the native executable. When we inline a native
intrinsic, we are guaranteed to know the native executable but we're not guaranteed to know
the functon instance. This means that the global object may be a variable that gets computed
by looking at the instance at run-time. So, the RegExpExec/RegExpTest nodes in DFG IR now
take a global object child. That also meant adding a new node type, GetGlobalObject, which
does the thing to the callee that CallFrame::lexicalGlobalObject() would have done.
Eventually, we'll probably have to make other native intrinsics also use GetGlobalObject. It
turns out that this really isn't so bad because usually it's constant-folded anyway, since
although the intrinsic code supports executable-based inlining (which leaves the callee
instance as an unknown), it happens rarely for intrinsics. So, conveying the global object
via a child isn't any worse than conveying it via meta-data, and it's probably better than
telling the inliner not to do executable-based inlining of native intrinsics. That would
have been a confusing special-case.

This is perf-neutral on my machines but it fixes a bug and it unlocks some interesting
possibilities. For example, RegExpExec can now make a firm promise about the type of array
it's creating.

This also contains some other changes:

- We are now using Structure::addPropertyTransition() in a lot of places even though it was
  meant to be an internal method with a quirky contract - for example if only works if you
  know that there is not existing transition. This relaxes this constraint.

- Restores the use of "*" for heap references in JSString.h. It's very unusual to have heap
  references pointed at with "&", since we don't currently do that anywhere. The fact that
  it was using the wrong reference type also meant that the code couldn't elegantly make use
  of some our GC pointer helpers like jsCast<>.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::attemptToInlineCall):
(JSC::DFG::ByteCodeParser::handleMinMax):
(JSC::DFG::ByteCodeParser::handleIntrinsicCall):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileSkipScope):
(JSC::DFG::SpeculativeJIT::compileGetGlobalObject):
(JSC::DFG::SpeculativeJIT::compileGetArrayLength):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* 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::compileSkipScope):
(JSC::FTL::DFG::LowerDFGToB3::compileGetGlobalObject):
(JSC::FTL::DFG::LowerDFGToB3::compileGetClosureVar):
(JSC::FTL::DFG::LowerDFGToB3::compileRegExpExec):
(JSC::FTL::DFG::LowerDFGToB3::compileRegExpTest):
(JSC::FTL::DFG::LowerDFGToB3::compileNewRegexp):
* jit/JITOperations.h:
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::haveABadTime):
(JSC::JSGlobalObject::visitChildren):
* runtime/JSGlobalObject.h:
* runtime/JSObject.h:
(JSC::JSObject::putDirectInternal):
* runtime/JSString.h:
(JSC::jsString):
(JSC::jsSubstring):
* runtime/RegExpCachedResult.cpp:
(JSC::RegExpCachedResult::lastResult):
* runtime/RegExpMatchesArray.cpp:
(JSC::tryCreateUninitializedRegExpMatchesArray):
(JSC::createRegExpMatchesArray):
(JSC::createStructureImpl):
(JSC::createRegExpMatchesArrayStructure):
(JSC::createRegExpMatchesArraySlowPutStructure):
* runtime/RegExpMatchesArray.h:
* runtime/RegExpObject.cpp:
(JSC::RegExpObject::put):
(JSC::RegExpObject::exec):
(JSC::RegExpObject::match):
* runtime/RegExpObject.h:
(JSC::RegExpObject::getLastIndex):
(JSC::RegExpObject::test):
* runtime/RegExpPrototype.cpp:
(JSC::regExpProtoFuncTest):
(JSC::regExpProtoFuncExec):
(JSC::regExpProtoFuncCompile):
* runtime/StringPrototype.cpp:
(JSC::stringProtoFuncMatch):
* runtime/Structure.cpp:
(JSC::Structure::suggestedArrayStorageTransition):
(JSC::Structure::addPropertyTransition):
(JSC::Structure::addNewPropertyTransition):
* runtime/Structure.h:
* tests/stress/regexp-matches-array-bad-time.js: Added.
* tests/stress/regexp-matches-array-slow-put.js: Added.

LayoutTests:

* js/regress/regexp-exec-expected.txt: Added.
* js/regress/regexp-exec.html: Added.
* js/regress/script-tests/regexp-exec.js: Added.

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

38 files changed:
LayoutTests/ChangeLog
LayoutTests/js/regress/regexp-exec-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/regexp-exec.html [new file with mode: 0644]
LayoutTests/js/regress/script-tests/regexp-exec.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
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/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/dfg/DFGStructureRegistrationPhase.cpp
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
Source/JavaScriptCore/jit/JITOperations.h
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.h
Source/JavaScriptCore/runtime/JSObject.h
Source/JavaScriptCore/runtime/JSString.h
Source/JavaScriptCore/runtime/RegExpCachedResult.cpp
Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp
Source/JavaScriptCore/runtime/RegExpMatchesArray.h
Source/JavaScriptCore/runtime/RegExpObject.cpp
Source/JavaScriptCore/runtime/RegExpObject.h
Source/JavaScriptCore/runtime/RegExpPrototype.cpp
Source/JavaScriptCore/runtime/StringPrototype.cpp
Source/JavaScriptCore/runtime/Structure.cpp
Source/JavaScriptCore/runtime/Structure.h
Source/JavaScriptCore/tests/stress/regexp-matches-array-bad-time.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/regexp-matches-array-slow-put.js [new file with mode: 0644]

index e26e2f8..9d124e1 100644 (file)
@@ -1,3 +1,14 @@
+2016-03-06  Filip Pizlo  <fpizlo@apple.com>
+
+        RegExpMatchesArray doesn't know how to have a bad time
+        https://bugs.webkit.org/show_bug.cgi?id=155069
+
+        Reviewed by Yusuke Suzuki.
+
+        * js/regress/regexp-exec-expected.txt: Added.
+        * js/regress/regexp-exec.html: Added.
+        * js/regress/script-tests/regexp-exec.js: Added.
+
 2016-03-06  Zalan Bujtas  <zalan@apple.com>
 
         [iOS] Gardening after r197627.
diff --git a/LayoutTests/js/regress/regexp-exec-expected.txt b/LayoutTests/js/regress/regexp-exec-expected.txt
new file mode 100644 (file)
index 0000000..cf4bec2
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/regexp-exec
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/regexp-exec.html b/LayoutTests/js/regress/regexp-exec.html
new file mode 100644 (file)
index 0000000..c74095a
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/regexp-exec.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/script-tests/regexp-exec.js b/LayoutTests/js/regress/script-tests/regexp-exec.js
new file mode 100644 (file)
index 0000000..052d05f
--- /dev/null
@@ -0,0 +1,9 @@
+(function() {
+    var result = 0;
+    var n = 1000000;
+    var re = /foo/;
+    for (var i = 0; i < n; ++i)
+        result += re.exec("foo").length;
+    if (result != n)
+        throw "Error: bad result: " + result;
+})();
index 0c065d9..6c86922 100644 (file)
@@ -1,3 +1,131 @@
+2016-03-06  Filip Pizlo  <fpizlo@apple.com>
+
+        RegExpMatchesArray doesn't know how to have a bad time
+        https://bugs.webkit.org/show_bug.cgi?id=155069
+
+        Reviewed by Yusuke Suzuki.
+
+        In trunk if we are having a bad time, the regexp matches array is still allocated with a
+        non-slow-put indexing shape, which makes it have the wrong behavior on indexed setters on
+        the prototype chain.
+
+        Getting this to work right requires introducing bad time code paths into the regexp matches
+        array. It also requires something more drastic: making this code not play games with the
+        global object. The code that creates the matches array needs to have the actual global
+        object of the regexp native function that it's logically created by.
+
+        This is totally different from how we've handled global objects in the past because it means
+        that the global object is not a constant. Normally we can make it a constant because a
+        script executable will know its global object. But with native functions, it's the function
+        instance that knows the global object - not the native executable. When we inline a native
+        intrinsic, we are guaranteed to know the native executable but we're not guaranteed to know
+        the functon instance. This means that the global object may be a variable that gets computed
+        by looking at the instance at run-time. So, the RegExpExec/RegExpTest nodes in DFG IR now
+        take a global object child. That also meant adding a new node type, GetGlobalObject, which
+        does the thing to the callee that CallFrame::lexicalGlobalObject() would have done.
+        Eventually, we'll probably have to make other native intrinsics also use GetGlobalObject. It
+        turns out that this really isn't so bad because usually it's constant-folded anyway, since
+        although the intrinsic code supports executable-based inlining (which leaves the callee
+        instance as an unknown), it happens rarely for intrinsics. So, conveying the global object
+        via a child isn't any worse than conveying it via meta-data, and it's probably better than
+        telling the inliner not to do executable-based inlining of native intrinsics. That would
+        have been a confusing special-case.
+
+        This is perf-neutral on my machines but it fixes a bug and it unlocks some interesting
+        possibilities. For example, RegExpExec can now make a firm promise about the type of array
+        it's creating.
+
+        This also contains some other changes:
+        
+        - We are now using Structure::addPropertyTransition() in a lot of places even though it was
+          meant to be an internal method with a quirky contract - for example if only works if you
+          know that there is not existing transition. This relaxes this constraint.
+        
+        - Restores the use of "*" for heap references in JSString.h. It's very unusual to have heap
+          references pointed at with "&", since we don't currently do that anywhere. The fact that
+          it was using the wrong reference type also meant that the code couldn't elegantly make use
+          of some our GC pointer helpers like jsCast<>.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::attemptToInlineCall):
+        (JSC::DFG::ByteCodeParser::handleMinMax):
+        (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileSkipScope):
+        (JSC::DFG::SpeculativeJIT::compileGetGlobalObject):
+        (JSC::DFG::SpeculativeJIT::compileGetArrayLength):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::callOperation):
+        * 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::compileSkipScope):
+        (JSC::FTL::DFG::LowerDFGToB3::compileGetGlobalObject):
+        (JSC::FTL::DFG::LowerDFGToB3::compileGetClosureVar):
+        (JSC::FTL::DFG::LowerDFGToB3::compileRegExpExec):
+        (JSC::FTL::DFG::LowerDFGToB3::compileRegExpTest):
+        (JSC::FTL::DFG::LowerDFGToB3::compileNewRegexp):
+        * jit/JITOperations.h:
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        (JSC::JSGlobalObject::haveABadTime):
+        (JSC::JSGlobalObject::visitChildren):
+        * runtime/JSGlobalObject.h:
+        * runtime/JSObject.h:
+        (JSC::JSObject::putDirectInternal):
+        * runtime/JSString.h:
+        (JSC::jsString):
+        (JSC::jsSubstring):
+        * runtime/RegExpCachedResult.cpp:
+        (JSC::RegExpCachedResult::lastResult):
+        * runtime/RegExpMatchesArray.cpp:
+        (JSC::tryCreateUninitializedRegExpMatchesArray):
+        (JSC::createRegExpMatchesArray):
+        (JSC::createStructureImpl):
+        (JSC::createRegExpMatchesArrayStructure):
+        (JSC::createRegExpMatchesArraySlowPutStructure):
+        * runtime/RegExpMatchesArray.h:
+        * runtime/RegExpObject.cpp:
+        (JSC::RegExpObject::put):
+        (JSC::RegExpObject::exec):
+        (JSC::RegExpObject::match):
+        * runtime/RegExpObject.h:
+        (JSC::RegExpObject::getLastIndex):
+        (JSC::RegExpObject::test):
+        * runtime/RegExpPrototype.cpp:
+        (JSC::regExpProtoFuncTest):
+        (JSC::regExpProtoFuncExec):
+        (JSC::regExpProtoFuncCompile):
+        * runtime/StringPrototype.cpp:
+        (JSC::stringProtoFuncMatch):
+        * runtime/Structure.cpp:
+        (JSC::Structure::suggestedArrayStorageTransition):
+        (JSC::Structure::addPropertyTransition):
+        (JSC::Structure::addNewPropertyTransition):
+        * runtime/Structure.h:
+        * tests/stress/regexp-matches-array-bad-time.js: Added.
+        * tests/stress/regexp-matches-array-slow-put.js: Added.
+
 2016-03-06  Yusuke Suzuki  <utatane.tea@gmail.com>
 
         [JSC] RegExp#lastIndex should handle writable attribute when defining in defineOwnProperty path
index 3e72cda..9cfb03f 100644 (file)
@@ -1554,17 +1554,29 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
     }
             
     case RegExpExec:
-        if (node->child1().useKind() == RegExpObjectUse
-            && node->child2().useKind() == StringUse) {
+        if (node->child2().useKind() == RegExpObjectUse
+            && node->child3().useKind() == StringUse) {
             // This doesn't clobber the world since there are no conversions to perform.
         } else
             clobberWorld(node->origin.semantic, clobberLimit);
-        forNode(node).makeHeapTop();
+        if (JSValue globalObjectValue = forNode(node->child1()).m_value) {
+            if (JSGlobalObject* globalObject = jsDynamicCast<JSGlobalObject*>(globalObjectValue)) {
+                if (!globalObject->isHavingABadTime()) {
+                    m_graph.watchpoints().addLazily(globalObject->havingABadTimeWatchpoint());
+                    Structure* structure = globalObject->regExpMatchesArrayStructure();
+                    m_graph.registerStructure(structure);
+                    forNode(node).set(m_graph, structure);
+                    forNode(node).merge(SpecOther);
+                    break;
+                }
+            }
+        }
+        forNode(node).setType(m_graph, SpecOther | SpecArray);
         break;
 
     case RegExpTest:
-        if (node->child1().useKind() == RegExpObjectUse
-            && node->child2().useKind() == StringUse) {
+        if (node->child2().useKind() == RegExpObjectUse
+            && node->child3().useKind() == StringUse) {
             // This doesn't clobber the world since there are no conversions to perform.
         } else
             clobberWorld(node->origin.semantic, clobberLimit);
@@ -1882,6 +1894,33 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         break;
     }
 
+    case GetGlobalObject: {
+        JSValue child = forNode(node->child1()).value();
+        if (child) {
+            setConstant(node, *m_graph.freeze(JSValue(asObject(child)->globalObject())));
+            break;
+        }
+
+        if (forNode(node->child1()).m_structure.isFinite()) {
+            JSGlobalObject* globalObject = nullptr;
+            bool ok = true;
+            forNode(node->child1()).m_structure.forEach(
+                [&] (Structure* structure) {
+                    if (!globalObject)
+                        globalObject = structure->globalObject();
+                    else if (globalObject != structure->globalObject())
+                        ok = false;
+                });
+            if (globalObject && ok) {
+                setConstant(node, *m_graph.freeze(JSValue(globalObject)));
+                break;
+            }
+        }
+
+        forNode(node).setType(m_graph, SpecObjectOther);
+        break;
+    }
+
     case GetClosureVar:
         if (JSValue value = m_graph.tryGetConstantClosureVar(forNode(node->child1()), node->scopeOffset())) {
             setConstant(node, *m_graph.freeze(value));
index 0826a83..6cadf89 100644 (file)
@@ -202,7 +202,7 @@ private:
     void cancelLinkingForBlock(InlineStackEntry*, BasicBlock*); // Only works when the given block is the last one to have been added for that inline stack entry.
     // Handle intrinsic functions. Return true if it succeeded, false if we need to plant a call.
     template<typename ChecksFunctor>
-    bool handleIntrinsicCall(int resultOperand, Intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, const ChecksFunctor& insertChecks);
+    bool handleIntrinsicCall(Node* callee, int resultOperand, Intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, const ChecksFunctor& insertChecks);
     template<typename ChecksFunctor>
     bool handleIntrinsicGetter(int resultOperand, const GetByIdVariant& intrinsicVariant, Node* thisNode, const ChecksFunctor& insertChecks);
     template<typename ChecksFunctor>
@@ -1601,7 +1601,7 @@ bool ByteCodeParser::attemptToInlineCall(Node* callTargetNode, int resultOperand
     
         Intrinsic intrinsic = callee.intrinsicFor(specializationKind);
         if (intrinsic != NoIntrinsic) {
-            if (handleIntrinsicCall(resultOperand, intrinsic, registerOffset, argumentCountIncludingThis, prediction, insertChecksWithAccounting)) {
+            if (handleIntrinsicCall(callTargetNode, resultOperand, intrinsic, registerOffset, argumentCountIncludingThis, prediction, insertChecksWithAccounting)) {
                 RELEASE_ASSERT(didInsertChecks);
                 addToGraph(Phantom, callTargetNode);
                 emitArgumentPhantoms(registerOffset, argumentCountIncludingThis);
@@ -1991,7 +1991,7 @@ bool ByteCodeParser::handleMinMax(int resultOperand, NodeType op, int registerOf
 }
 
 template<typename ChecksFunctor>
-bool ByteCodeParser::handleIntrinsicCall(int resultOperand, Intrinsic intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, const ChecksFunctor& insertChecks)
+bool ByteCodeParser::handleIntrinsicCall(Node* callee, int resultOperand, Intrinsic intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, const ChecksFunctor& insertChecks)
 {
     switch (intrinsic) {
 
@@ -2172,7 +2172,7 @@ bool ByteCodeParser::handleIntrinsicCall(int resultOperand, Intrinsic intrinsic,
             return false;
         
         insertChecks();
-        Node* regExpExec = addToGraph(RegExpExec, OpInfo(0), OpInfo(prediction), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset)));
+        Node* regExpExec = addToGraph(RegExpExec, OpInfo(0), OpInfo(prediction), addToGraph(GetGlobalObject, callee), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset)));
         set(VirtualRegister(resultOperand), regExpExec);
         
         return true;
@@ -2183,7 +2183,7 @@ bool ByteCodeParser::handleIntrinsicCall(int resultOperand, Intrinsic intrinsic,
             return false;
         
         insertChecks();
-        Node* regExpExec = addToGraph(RegExpTest, OpInfo(0), OpInfo(prediction), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset)));
+        Node* regExpExec = addToGraph(RegExpTest, OpInfo(0), OpInfo(prediction), addToGraph(GetGlobalObject, callee), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset)));
         set(VirtualRegister(resultOperand), regExpExec);
         
         return true;
index 40cce0f..d0f07d9 100644 (file)
@@ -134,6 +134,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
     case ArithLog:
     case GetScope:
     case SkipScope:
+    case GetGlobalObject:
     case StringCharCodeAt:
     case CompareStrictEq:
     case IsUndefined:
@@ -1078,8 +1079,8 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
 
     case RegExpExec:
     case RegExpTest:
-        if (node->child1().useKind() == RegExpObjectUse
-            && node->child2().useKind() == StringUse) {
+        if (node->child2().useKind() == RegExpObjectUse
+            && node->child3().useKind() == StringUse) {
             read(RegExpState);
             write(RegExpState);
             return;
index 7004323..49e8e9f 100644 (file)
@@ -111,6 +111,7 @@ bool doesGC(Graph& graph, Node* node)
     case CheckArray:
     case GetScope:
     case SkipScope:
+    case GetGlobalObject:
     case GetClosureVar:
     case PutClosureVar:
     case GetRegExpObjectLastIndex:
index 234045f..e119bcd 100644 (file)
@@ -879,11 +879,13 @@ private:
             
         case RegExpExec:
         case RegExpTest: {
-            if (node->child1()->shouldSpeculateRegExpObject()) {
-                fixEdge<RegExpObjectUse>(node->child1());
+            fixEdge<KnownCellUse>(node->child1());
+            
+            if (node->child2()->shouldSpeculateRegExpObject()) {
+                fixEdge<RegExpObjectUse>(node->child2());
 
-                if (node->child2()->shouldSpeculateString())
-                    fixEdge<StringUse>(node->child2());
+                if (node->child3()->shouldSpeculateString())
+                    fixEdge<StringUse>(node->child3());
             }
             break;
         }
@@ -1049,7 +1051,8 @@ private:
         case SkipScope:
         case GetScope:
         case GetGetter:
-        case GetSetter: {
+        case GetSetter:
+        case GetGlobalObject: {
             fixEdge<KnownCellUse>(node->child1());
             break;
         }
index 5200c4d..0131538 100644 (file)
@@ -212,6 +212,7 @@ namespace JSC { namespace DFG {
     macro(GetTypedArrayByteOffset, NodeResultInt32) \
     macro(GetScope, NodeResultJS) \
     macro(SkipScope, NodeResultJS) \
+    macro(GetGlobalObject, NodeResultJS) \
     macro(GetClosureVar, NodeResultJS) \
     macro(PutClosureVar, NodeMustGenerate) \
     macro(GetGlobalVar, NodeResultJS) \
index d7a22eb..d2c1447 100644 (file)
@@ -619,17 +619,17 @@ EncodedJSValue JIT_OPERATION operationArrayPopAndRecoverLength(ExecState* exec,
     return JSValue::encode(array->pop(exec));
 }
         
-EncodedJSValue JIT_OPERATION operationRegExpExecString(ExecState* exec, RegExpObject* regExpObject, JSString* argument)
+EncodedJSValue JIT_OPERATION operationRegExpExecString(ExecState* exec, JSGlobalObject* globalObject, RegExpObject* regExpObject, JSString* argument)
 {
-    VM& vm = exec->vm();
+    VM& vm = globalObject->vm();
     NativeCallFrameTracer tracer(&vm, exec);
     
-    return JSValue::encode(regExpObject->exec(exec, argument));
+    return JSValue::encode(regExpObject->exec(exec, globalObject, argument));
 }
         
-EncodedJSValue JIT_OPERATION operationRegExpExec(ExecState* exec, RegExpObject* regExpObject, EncodedJSValue encodedArgument)
+EncodedJSValue JIT_OPERATION operationRegExpExec(ExecState* exec, JSGlobalObject* globalObject, RegExpObject* regExpObject, EncodedJSValue encodedArgument)
 {
-    VM& vm = exec->vm();
+    VM& vm = globalObject->vm();
     NativeCallFrameTracer tracer(&vm, exec);
     
     JSValue argument = JSValue::decode(encodedArgument);
@@ -637,12 +637,12 @@ EncodedJSValue JIT_OPERATION operationRegExpExec(ExecState* exec, RegExpObject*
     JSString* input = argument.toStringOrNull(exec);
     if (!input)
         return JSValue::encode(jsUndefined());
-    return JSValue::encode(regExpObject->exec(exec, input));
+    return JSValue::encode(regExpObject->exec(exec, globalObject, input));
 }
         
-EncodedJSValue JIT_OPERATION operationRegExpExecGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedArgument)
+EncodedJSValue JIT_OPERATION operationRegExpExecGeneric(ExecState* exec, JSGlobalObject* globalObject, EncodedJSValue encodedBase, EncodedJSValue encodedArgument)
 {
-    VM& vm = exec->vm();
+    VM& vm = globalObject->vm();
     NativeCallFrameTracer tracer(&vm, exec);
 
     JSValue base = JSValue::decode(encodedBase);
@@ -654,20 +654,20 @@ EncodedJSValue JIT_OPERATION operationRegExpExecGeneric(ExecState* exec, Encoded
     JSString* input = argument.toStringOrNull(exec);
     if (!input)
         return JSValue::encode(jsUndefined());
-    return JSValue::encode(asRegExpObject(base)->exec(exec, input));
+    return JSValue::encode(asRegExpObject(base)->exec(exec, globalObject, input));
 }
         
-size_t JIT_OPERATION operationRegExpTestString(ExecState* exec, RegExpObject* regExpObject, JSString* input)
+size_t JIT_OPERATION operationRegExpTestString(ExecState* exec, JSGlobalObject* globalObject, RegExpObject* regExpObject, JSString* input)
 {
-    VM& vm = exec->vm();
+    VM& vm = globalObject->vm();
     NativeCallFrameTracer tracer(&vm, exec);
 
-    return regExpObject->test(exec, input);
+    return regExpObject->test(exec, globalObject, input);
 }
 
-size_t JIT_OPERATION operationRegExpTest(ExecState* exec, RegExpObject* regExpObject, EncodedJSValue encodedArgument)
+size_t JIT_OPERATION operationRegExpTest(ExecState* exec, JSGlobalObject* globalObject, RegExpObject* regExpObject, EncodedJSValue encodedArgument)
 {
-    VM& vm = exec->vm();
+    VM& vm = globalObject->vm();
     NativeCallFrameTracer tracer(&vm, exec);
 
     JSValue argument = JSValue::decode(encodedArgument);
@@ -675,12 +675,12 @@ size_t JIT_OPERATION operationRegExpTest(ExecState* exec, RegExpObject* regExpOb
     JSString* input = argument.toStringOrNull(exec);
     if (!input)
         return false;
-    return regExpObject->test(exec, input);
+    return regExpObject->test(exec, globalObject, input);
 }
 
-size_t JIT_OPERATION operationRegExpTestGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedArgument)
+size_t JIT_OPERATION operationRegExpTestGeneric(ExecState* exec, JSGlobalObject* globalObject, EncodedJSValue encodedBase, EncodedJSValue encodedArgument)
 {
-    VM& vm = exec->vm();
+    VM& vm = globalObject->vm();
     NativeCallFrameTracer tracer(&vm, exec);
 
     JSValue base = JSValue::decode(encodedBase);
@@ -694,7 +694,7 @@ size_t JIT_OPERATION operationRegExpTestGeneric(ExecState* exec, EncodedJSValue
     JSString* input = argument.toStringOrNull(exec);
     if (!input)
         return false;
-    return asRegExpObject(base)->test(exec, input);
+    return asRegExpObject(base)->test(exec, globalObject, input);
 }
 
 size_t JIT_OPERATION operationCompareStrictEqCell(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
index 7247f2b..d3c56df 100644 (file)
@@ -101,13 +101,13 @@ EncodedJSValue JIT_OPERATION operationArrayPush(ExecState*, EncodedJSValue encod
 EncodedJSValue JIT_OPERATION operationArrayPushDouble(ExecState*, double value, JSArray*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationArrayPop(ExecState*, JSArray*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationArrayPopAndRecoverLength(ExecState*, JSArray*) WTF_INTERNAL;
-EncodedJSValue JIT_OPERATION operationRegExpExecString(ExecState*, RegExpObject*, JSString*) WTF_INTERNAL;
-EncodedJSValue JIT_OPERATION operationRegExpExec(ExecState*, RegExpObject*, EncodedJSValue) WTF_INTERNAL;
-EncodedJSValue JIT_OPERATION operationRegExpExecGeneric(ExecState*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
+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;
 // 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*, RegExpObject*, JSString*) WTF_INTERNAL;
-size_t JIT_OPERATION operationRegExpTest(ExecState*, RegExpObject*, EncodedJSValue) WTF_INTERNAL;
-size_t JIT_OPERATION operationRegExpTestGeneric(ExecState*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
+size_t JIT_OPERATION operationRegExpTestString(ExecState*, JSGlobalObject*, RegExpObject*, JSString*) WTF_INTERNAL;
+size_t JIT_OPERATION operationRegExpTest(ExecState*, JSGlobalObject*, RegExpObject*, EncodedJSValue) WTF_INTERNAL;
+size_t JIT_OPERATION operationRegExpTestGeneric(ExecState*, JSGlobalObject*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
 size_t JIT_OPERATION operationCompareStrictEqCell(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
 size_t JIT_OPERATION operationCompareStrictEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationCreateActivationDirect(ExecState*, Structure*, JSScope*, SymbolTable*, EncodedJSValue);
index 666ad62..e492610 100644 (file)
@@ -550,7 +550,8 @@ private:
             break;
         }
             
-        case SkipScope: {
+        case SkipScope:
+        case GetGlobalObject: {
             changed |= setPrediction(SpecObjectOther);
             break;
         }
index b8735bb..a0dc5cb 100644 (file)
@@ -207,6 +207,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
     case ArrayifyToStructure:
     case GetScope:
     case SkipScope:
+    case GetGlobalObject:
     case GetClosureVar:
     case PutClosureVar:
     case GetGlobalVar:
index 6c24942..09913ea 100644 (file)
@@ -5342,6 +5342,16 @@ void SpeculativeJIT::compileSkipScope(Node* node)
     cellResult(result.gpr(), node);
 }
 
+void SpeculativeJIT::compileGetGlobalObject(Node* node)
+{
+    SpeculateCellOperand object(this, node->child1());
+    GPRTemporary result(this);
+    GPRTemporary scratch(this);
+    m_jit.emitLoadStructure(object.gpr(), result.gpr(), scratch.gpr());
+    m_jit.loadPtr(JITCompiler::Address(result.gpr(), Structure::globalObjectOffset()), result.gpr());
+    cellResult(result.gpr(), node);
+}
+
 void SpeculativeJIT::compileGetArrayLength(Node* node)
 {
     switch (node->arrayMode().type()) {
index 59d5b2a..2a81c1e 100644 (file)
@@ -1217,15 +1217,15 @@ public:
         return appendCallSetResult(operation, result);
     }
 
-    JITCompiler::Call callOperation(J_JITOperation_EReoJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
+    JITCompiler::Call callOperation(J_JITOperation_EGReoJ operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
     {
-        m_jit.setupArgumentsWithExecState(arg1, arg2);
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
         return appendCallSetResult(operation, result);
     }
 
-    JITCompiler::Call callOperation(J_JITOperation_EReoJss operation, GPRReg result, GPRReg arg1, GPRReg arg2)
+    JITCompiler::Call callOperation(J_JITOperation_EGReoJss operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
     {
-        m_jit.setupArgumentsWithExecState(arg1, arg2);
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
         return appendCallSetResult(operation, result);
     }
 
@@ -1446,14 +1446,19 @@ public:
         m_jit.setupArgumentsWithExecState(arg1, arg2);
         return appendCallSetResult(operation, result);
     }
-    JITCompiler::Call callOperation(S_JITOperation_EReoJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
+    JITCompiler::Call callOperation(S_JITOperation_EGJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
     {
-        m_jit.setupArgumentsWithExecState(arg1, arg2);
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
         return appendCallSetResult(operation, result);
     }
-    JITCompiler::Call callOperation(S_JITOperation_EReoJss operation, GPRReg result, GPRReg arg1, GPRReg arg2)
+    JITCompiler::Call callOperation(S_JITOperation_EGReoJ operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
     {
-        m_jit.setupArgumentsWithExecState(arg1, arg2);
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
+        return appendCallSetResult(operation, result);
+    }
+    JITCompiler::Call callOperation(S_JITOperation_EGReoJss operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
         return appendCallSetResult(operation, result);
     }
 
@@ -1467,6 +1472,11 @@ public:
         m_jit.setupArgumentsWithExecState(arg1, arg2);
         return appendCallSetResult(operation, result);
     }
+    JITCompiler::Call callOperation(J_JITOperation_EGJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
+        return appendCallSetResult(operation, result);
+    }
     JITCompiler::Call callOperation(J_JITOperation_EJJ operation, GPRReg result, GPRReg arg1, int32_t imm)
     {
         m_jit.setupArgumentsWithExecState(arg1, MacroAssembler::TrustedImm64(JSValue::encode(jsNumber(imm))));
@@ -1722,14 +1732,14 @@ public:
         m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(cell), EABI_32BIT_DUMMY_ARG arg2Payload, arg2Tag);
         return appendCallSetResult(operation, result);
     }
-    JITCompiler::Call callOperation(J_JITOperation_EReoJ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, GPRReg arg2Tag, GPRReg arg2Payload)
+    JITCompiler::Call callOperation(J_JITOperation_EGReoJ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, GPRReg arg2, GPRReg arg3Tag, GPRReg arg3Payload)
     {
-        m_jit.setupArgumentsWithExecState(arg1, arg2Payload, arg2Tag);
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3Payload, arg3Tag);
         return appendCallSetResult(operation, resultPayload, resultTag);
     }
-    JITCompiler::Call callOperation(J_JITOperation_EReoJss operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, GPRReg arg2)
+    JITCompiler::Call callOperation(J_JITOperation_EGReoJss operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, GPRReg arg2, GPRReg arg3)
     {
-        m_jit.setupArgumentsWithExecState(arg1, arg2);
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
         return appendCallSetResult(operation, resultPayload, resultTag);
     }
     JITCompiler::Call callOperation(J_JITOperation_ESsiCI operation, GPRReg resultTag, GPRReg resultPayload, StructureStubInfo* stubInfo, GPRReg arg1, const UniquedStringImpl* uid)
@@ -1829,14 +1839,19 @@ public:
         m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, SH4_32BIT_DUMMY_ARG arg2Payload, arg2Tag);
         return appendCallSetResult(operation, result);
     }
-    JITCompiler::Call callOperation(S_JITOperation_EReoJ operation, GPRReg result, GPRReg arg1, GPRReg arg2Tag, GPRReg arg2Payload)
+    JITCompiler::Call callOperation(S_JITOperation_EGJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2Tag, GPRReg arg2Payload, GPRReg arg3Tag, GPRReg arg3Payload)
     {
-        m_jit.setupArgumentsWithExecState(arg1, arg2Payload, arg2Tag);
+        m_jit.setupArgumentsWithExecState(arg1, arg2Payload, arg2Tag, SH4_32BIT_DUMMY_ARG arg3Payload, arg3Tag);
         return appendCallSetResult(operation, result);
     }
-    JITCompiler::Call callOperation(S_JITOperation_EReoJss operation, GPRReg result, GPRReg arg1, GPRReg arg2)
+    JITCompiler::Call callOperation(S_JITOperation_EGReoJ operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3Tag, GPRReg arg3Payload)
     {
-        m_jit.setupArgumentsWithExecState(arg1, arg2);
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3Payload, arg3Tag);
+        return appendCallSetResult(operation, result);
+    }
+    JITCompiler::Call callOperation(S_JITOperation_EGReoJss operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
         return appendCallSetResult(operation, result);
     }
     JITCompiler::Call callOperation(J_JITOperation_EJJ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2Tag, GPRReg arg2Payload)
@@ -1844,6 +1859,11 @@ public:
         m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, SH4_32BIT_DUMMY_ARG arg2Payload, arg2Tag);
         return appendCallSetResult(operation, resultPayload, resultTag);
     }
+    JITCompiler::Call callOperation(J_JITOperation_EGJJ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, GPRReg arg2Tag, GPRReg arg2Payload, GPRReg arg3Tag, GPRReg arg3Payload)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2Payload, arg2Tag, SH4_32BIT_DUMMY_ARG arg3Payload, arg3Tag);
+        return appendCallSetResult(operation, resultPayload, resultTag);
+    }
     JITCompiler::Call callOperation(J_JITOperation_EJJ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload, MacroAssembler::TrustedImm32 imm)
     {
         m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, SH4_32BIT_DUMMY_ARG imm, TrustedImm32(JSValue::Int32Tag));
@@ -2309,6 +2329,7 @@ public:
     
     void compileGetScope(Node*);
     void compileSkipScope(Node*);
+    void compileGetGlobalObject(Node*);
 
     void compileGetArrayLength(Node*);
 
index 3377c11..6ad47c1 100644 (file)
@@ -2836,48 +2836,51 @@ void SpeculativeJIT::compile(Node* node)
     }
 
     case RegExpExec: {
-        if (node->child1().useKind() == RegExpObjectUse) {
-            if (node->child2().useKind() == StringUse) {
-                SpeculateCellOperand base(this, node->child1());
-                SpeculateCellOperand argument(this, node->child2());
+        SpeculateCellOperand globalObject(this, node->child1());
+        GPRReg globalObjectGPR = globalObject.gpr();
+        
+        if (node->child2().useKind() == RegExpObjectUse) {
+            if (node->child3().useKind() == StringUse) {
+                SpeculateCellOperand base(this, node->child2());
+                SpeculateCellOperand argument(this, node->child3());
                 GPRReg baseGPR = base.gpr();
                 GPRReg argumentGPR = argument.gpr();
-                speculateRegExpObject(node->child1(), baseGPR);
-                speculateString(node->child2(), argumentGPR);
+                speculateRegExpObject(node->child2(), baseGPR);
+                speculateString(node->child3(), argumentGPR);
                 
                 flushRegisters();
                 GPRFlushedCallResult2 resultTag(this);
                 GPRFlushedCallResult resultPayload(this);
                 callOperation(
-                    operationRegExpExecString, resultTag.gpr(), resultPayload.gpr(), baseGPR,
-                    argumentGPR);
+                    operationRegExpExecString, resultTag.gpr(), resultPayload.gpr(),
+                    globalObjectGPR, baseGPR, argumentGPR);
                 m_jit.exceptionCheck();
                 
                 jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
                 break;
             }
             
-            SpeculateCellOperand base(this, node->child1());
-            JSValueOperand argument(this, node->child2());
+            SpeculateCellOperand base(this, node->child2());
+            JSValueOperand argument(this, node->child3());
             GPRReg baseGPR = base.gpr();
             GPRReg argumentTagGPR = argument.tagGPR();
             GPRReg argumentPayloadGPR = argument.payloadGPR();
-            speculateRegExpObject(node->child1(), baseGPR);
+            speculateRegExpObject(node->child2(), baseGPR);
         
             flushRegisters();
             GPRFlushedCallResult2 resultTag(this);
             GPRFlushedCallResult resultPayload(this);
             callOperation(
-                operationRegExpExec, resultTag.gpr(), resultPayload.gpr(), baseGPR, argumentTagGPR,
-                argumentPayloadGPR);
+                operationRegExpExec, resultTag.gpr(), resultPayload.gpr(), globalObjectGPR, baseGPR,
+                argumentTagGPR, argumentPayloadGPR);
             m_jit.exceptionCheck();
         
             jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
             break;
         }
         
-        JSValueOperand base(this, node->child1());
-        JSValueOperand argument(this, node->child2());
+        JSValueOperand base(this, node->child2());
+        JSValueOperand argument(this, node->child3());
         GPRReg baseTagGPR = base.tagGPR();
         GPRReg basePayloadGPR = base.payloadGPR();
         GPRReg argumentTagGPR = argument.tagGPR();
@@ -2886,7 +2889,9 @@ void SpeculativeJIT::compile(Node* node)
         flushRegisters();
         GPRFlushedCallResult2 resultTag(this);
         GPRFlushedCallResult resultPayload(this);
-        callOperation(operationRegExpExecGeneric, resultTag.gpr(), resultPayload.gpr(), baseTagGPR, basePayloadGPR, argumentTagGPR, argumentPayloadGPR);
+        callOperation(
+            operationRegExpExecGeneric, resultTag.gpr(), resultPayload.gpr(), globalObjectGPR,
+            baseTagGPR, basePayloadGPR, argumentTagGPR, argumentPayloadGPR);
         m_jit.exceptionCheck();
         
         jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
@@ -2894,43 +2899,48 @@ void SpeculativeJIT::compile(Node* node)
     }
         
     case RegExpTest: {
-        if (node->child1().useKind() == RegExpObjectUse) {
-            if (node->child2().useKind() == StringUse) {
-                SpeculateCellOperand base(this, node->child1());
-                SpeculateCellOperand argument(this, node->child2());
+        SpeculateCellOperand globalObject(this, node->child1());
+        GPRReg globalObjectGPR = globalObject.gpr();
+        
+        if (node->child2().useKind() == RegExpObjectUse) {
+            if (node->child3().useKind() == StringUse) {
+                SpeculateCellOperand base(this, node->child2());
+                SpeculateCellOperand argument(this, node->child3());
                 GPRReg baseGPR = base.gpr();
                 GPRReg argumentGPR = argument.gpr();
-                speculateRegExpObject(node->child1(), baseGPR);
-                speculateString(node->child2(), argumentGPR);
+                speculateRegExpObject(node->child2(), baseGPR);
+                speculateString(node->child3(), argumentGPR);
                 
                 flushRegisters();
                 GPRFlushedCallResult result(this);
-                callOperation(operationRegExpTestString, result.gpr(), baseGPR, argumentGPR);
+                callOperation(
+                    operationRegExpTestString, result.gpr(), globalObjectGPR, baseGPR, argumentGPR);
                 m_jit.exceptionCheck();
                 
                 booleanResult(result.gpr(), node);
                 break;
             }
             
-            SpeculateCellOperand base(this, node->child1());
-            JSValueOperand argument(this, node->child2());
+            SpeculateCellOperand base(this, node->child2());
+            JSValueOperand argument(this, node->child3());
             GPRReg baseGPR = base.gpr();
             GPRReg argumentTagGPR = argument.tagGPR();
             GPRReg argumentPayloadGPR = argument.payloadGPR();
-            speculateRegExpObject(node->child1(), baseGPR);
+            speculateRegExpObject(node->child2(), baseGPR);
         
             flushRegisters();
             GPRFlushedCallResult result(this);
             callOperation(
-                operationRegExpTest, result.gpr(), baseGPR, argumentTagGPR, argumentPayloadGPR);
+                operationRegExpTest, result.gpr(), globalObjectGPR, baseGPR, argumentTagGPR,
+                argumentPayloadGPR);
             m_jit.exceptionCheck();
         
             booleanResult(result.gpr(), node);
             break;
         }
         
-        JSValueOperand base(this, node->child1());
-        JSValueOperand argument(this, node->child2());
+        JSValueOperand base(this, node->child2());
+        JSValueOperand argument(this, node->child3());
         GPRReg baseTagGPR = base.tagGPR();
         GPRReg basePayloadGPR = base.payloadGPR();
         GPRReg argumentTagGPR = argument.tagGPR();
@@ -2938,7 +2948,9 @@ void SpeculativeJIT::compile(Node* node)
         
         flushRegisters();
         GPRFlushedCallResult result(this);
-        callOperation(operationRegExpTestGeneric, result.gpr(), baseTagGPR, basePayloadGPR, argumentTagGPR, argumentPayloadGPR);
+        callOperation(
+            operationRegExpTestGeneric, result.gpr(), globalObjectGPR, baseTagGPR, basePayloadGPR,
+            argumentTagGPR, argumentPayloadGPR);
         m_jit.exceptionCheck();
         
         booleanResult(result.gpr(), node);
@@ -3901,6 +3913,10 @@ void SpeculativeJIT::compile(Node* node)
         compileSkipScope(node);
         break;
         
+    case GetGlobalObject:
+        compileGetGlobalObject(node);
+        break;
+        
     case GetClosureVar: {
         SpeculateCellOperand base(this, node->child1());
         GPRTemporary resultTag(this);
index 4e326be..51ba32c 100644 (file)
@@ -2962,47 +2962,50 @@ void SpeculativeJIT::compile(Node* node)
     }
 
     case RegExpExec: {
-        if (node->child1().useKind() == RegExpObjectUse) {
-            if (node->child2().useKind() == StringUse) {
-                SpeculateCellOperand base(this, node->child1());
-                SpeculateCellOperand argument(this, node->child2());
+        SpeculateCellOperand globalObject(this, node->child1());
+        GPRReg globalObjectGPR = globalObject.gpr();
+        
+        if (node->child2().useKind() == RegExpObjectUse) {
+            if (node->child3().useKind() == StringUse) {
+                SpeculateCellOperand base(this, node->child2());
+                SpeculateCellOperand argument(this, node->child3());
                 GPRReg baseGPR = base.gpr();
                 GPRReg argumentGPR = argument.gpr();
-                speculateRegExpObject(node->child1(), baseGPR);
-                speculateString(node->child2(), argumentGPR);
+                speculateRegExpObject(node->child2(), baseGPR);
+                speculateString(node->child3(), argumentGPR);
                 
                 flushRegisters();
                 GPRFlushedCallResult result(this);
-                callOperation(operationRegExpExecString, result.gpr(), baseGPR, argumentGPR);
+                callOperation(operationRegExpExecString, result.gpr(), globalObjectGPR, baseGPR, argumentGPR);
                 m_jit.exceptionCheck();
                 
                 jsValueResult(result.gpr(), node);
                 break;
             }
             
-            SpeculateCellOperand base(this, node->child1());
-            JSValueOperand argument(this, node->child2());
+            SpeculateCellOperand base(this, node->child2());
+            JSValueOperand argument(this, node->child3());
             GPRReg baseGPR = base.gpr();
             GPRReg argumentGPR = argument.gpr();
-            speculateRegExpObject(node->child1(), baseGPR);
+            speculateRegExpObject(node->child2(), baseGPR);
         
             flushRegisters();
             GPRFlushedCallResult result(this);
-            callOperation(operationRegExpExec, result.gpr(), baseGPR, argumentGPR);
+            callOperation(operationRegExpExec, result.gpr(), globalObjectGPR, baseGPR, argumentGPR);
             m_jit.exceptionCheck();
         
             jsValueResult(result.gpr(), node);
             break;
         }
         
-        JSValueOperand base(this, node->child1());
-        JSValueOperand argument(this, node->child2());
+        JSValueOperand base(this, node->child2());
+        JSValueOperand argument(this, node->child3());
         GPRReg baseGPR = base.gpr();
         GPRReg argumentGPR = argument.gpr();
         
         flushRegisters();
         GPRFlushedCallResult result(this);
-        callOperation(operationRegExpExecGeneric, result.gpr(), baseGPR, argumentGPR);
+        callOperation(operationRegExpExecGeneric, result.gpr(), globalObjectGPR, baseGPR, argumentGPR);
         m_jit.exceptionCheck();
         
         jsValueResult(result.gpr(), node);
@@ -3010,18 +3013,21 @@ void SpeculativeJIT::compile(Node* node)
     }
 
     case RegExpTest: {
-        if (node->child1().useKind() == RegExpObjectUse) {
-            if (node->child2().useKind() == StringUse) {
-                SpeculateCellOperand base(this, node->child1());
-                SpeculateCellOperand argument(this, node->child2());
+        SpeculateCellOperand globalObject(this, node->child1());
+        GPRReg globalObjectGPR = globalObject.gpr();
+        
+        if (node->child2().useKind() == RegExpObjectUse) {
+            if (node->child3().useKind() == StringUse) {
+                SpeculateCellOperand base(this, node->child2());
+                SpeculateCellOperand argument(this, node->child3());
                 GPRReg baseGPR = base.gpr();
                 GPRReg argumentGPR = argument.gpr();
-                speculateRegExpObject(node->child1(), baseGPR);
-                speculateString(node->child2(), argumentGPR);
+                speculateRegExpObject(node->child2(), baseGPR);
+                speculateString(node->child3(), argumentGPR);
                 
                 flushRegisters();
                 GPRFlushedCallResult result(this);
-                callOperation(operationRegExpTestString, result.gpr(), baseGPR, argumentGPR);
+                callOperation(operationRegExpTestString, result.gpr(), globalObjectGPR, baseGPR, argumentGPR);
                 m_jit.exceptionCheck();
                 
                 m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
@@ -3029,15 +3035,15 @@ void SpeculativeJIT::compile(Node* node)
                 break;
             }
             
-            SpeculateCellOperand base(this, node->child1());
-            JSValueOperand argument(this, node->child2());
+            SpeculateCellOperand base(this, node->child2());
+            JSValueOperand argument(this, node->child3());
             GPRReg baseGPR = base.gpr();
             GPRReg argumentGPR = argument.gpr();
-            speculateRegExpObject(node->child1(), baseGPR);
+            speculateRegExpObject(node->child2(), baseGPR);
         
             flushRegisters();
             GPRFlushedCallResult result(this);
-            callOperation(operationRegExpTest, result.gpr(), baseGPR, argumentGPR);
+            callOperation(operationRegExpTest, result.gpr(), globalObjectGPR, baseGPR, argumentGPR);
             m_jit.exceptionCheck();
         
             m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
@@ -3045,14 +3051,14 @@ void SpeculativeJIT::compile(Node* node)
             break;
         }
         
-        JSValueOperand base(this, node->child1());
-        JSValueOperand argument(this, node->child2());
+        JSValueOperand base(this, node->child2());
+        JSValueOperand argument(this, node->child3());
         GPRReg baseGPR = base.gpr();
         GPRReg argumentGPR = argument.gpr();
         
         flushRegisters();
         GPRFlushedCallResult result(this);
-        callOperation(operationRegExpTestGeneric, result.gpr(), baseGPR, argumentGPR);
+        callOperation(operationRegExpTestGeneric, result.gpr(), globalObjectGPR, baseGPR, argumentGPR);
         m_jit.exceptionCheck();
         
         m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
@@ -3930,6 +3936,10 @@ void SpeculativeJIT::compile(Node* node)
     case SkipScope:
         compileSkipScope(node);
         break;
+
+    case GetGlobalObject:
+        compileGetGlobalObject(node);
+        break;
         
     case GetClosureVar: {
         SpeculateCellOperand base(this, node->child1());
index 2c05598..0081a10 100644 (file)
@@ -149,7 +149,7 @@ public:
                 case NewGeneratorFunction:
                     registerStructure(m_graph.globalObjectFor(node->origin.semantic)->generatorFunctionStructure());
                     break;
-                    
+
                 default:
                     break;
                 }
index d5371fa..7840e7c 100644 (file)
@@ -111,6 +111,7 @@ inline CapabilityLevel canCompile(Node* node)
     case ExtractOSREntryLocal:
     case LoopHint:
     case SkipScope:
+    case GetGlobalObject:
     case CreateActivation:
     case NewArrowFunction:
     case NewFunction:
index 9249708..0d3db0b 100644 (file)
@@ -748,6 +748,9 @@ private:
         case SkipScope:
             compileSkipScope();
             break;
+        case GetGlobalObject:
+            compileGetGlobalObject();
+            break;
         case GetClosureVar:
             compileGetClosureVar();
             break;
@@ -4475,6 +4478,12 @@ private:
     {
         setJSValue(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.JSScope_next));
     }
+
+    void compileGetGlobalObject()
+    {
+        LValue structure = loadStructure(lowCell(m_node->child1()));
+        setJSValue(m_out.loadPtr(structure, m_heaps.Structure_globalObject));
+    }
     
     void compileGetClosureVar()
     {
@@ -6440,52 +6449,66 @@ private:
 
     void compileRegExpExec()
     {
-        if (m_node->child1().useKind() == RegExpObjectUse) {
-            LValue base = lowRegExpObject(m_node->child1());
+        LValue globalObject = lowCell(m_node->child1());
+        
+        if (m_node->child2().useKind() == RegExpObjectUse) {
+            LValue base = lowRegExpObject(m_node->child2());
             
-            if (m_node->child2().useKind() == StringUse) {
-                LValue argument = lowString(m_node->child2());
+            if (m_node->child3().useKind() == StringUse) {
+                LValue argument = lowString(m_node->child3());
                 LValue result = vmCall(
-                    Int64, m_out.operation(operationRegExpExecString), m_callFrame, base, argument);
+                    Int64, m_out.operation(operationRegExpExecString), m_callFrame, globalObject,
+                    base, argument);
                 setJSValue(result);
                 return;
             }
             
-            LValue argument = lowJSValue(m_node->child2());
-            setJSValue(
-                vmCall(Int64, m_out.operation(operationRegExpExec), m_callFrame, base, argument));
+            LValue argument = lowJSValue(m_node->child3());
+            LValue result = vmCall(
+                Int64, m_out.operation(operationRegExpExec), m_callFrame, globalObject, base,
+                argument);
+            setJSValue(result);
             return;
         }
         
-        LValue base = lowJSValue(m_node->child1());
-        LValue argument = lowJSValue(m_node->child2());
-        setJSValue(
-            vmCall(Int64, m_out.operation(operationRegExpExecGeneric), m_callFrame, base, argument));
+        LValue base = lowJSValue(m_node->child2());
+        LValue argument = lowJSValue(m_node->child3());
+        LValue result = vmCall(
+            Int64, m_out.operation(operationRegExpExecGeneric), m_callFrame, globalObject, base,
+            argument);
+        setJSValue(result);
     }
 
     void compileRegExpTest()
     {
-        if (m_node->child1().useKind() == RegExpObjectUse) {
-            LValue base = lowRegExpObject(m_node->child1());
+        LValue globalObject = lowCell(m_node->child1());
+        
+        if (m_node->child2().useKind() == RegExpObjectUse) {
+            LValue base = lowRegExpObject(m_node->child2());
             
-            if (m_node->child2().useKind() == StringUse) {
-                LValue argument = lowString(m_node->child2());
+            if (m_node->child3().useKind() == StringUse) {
+                LValue argument = lowString(m_node->child3());
                 LValue result = vmCall(
-                    Int32, m_out.operation(operationRegExpTestString), m_callFrame, base, argument);
+                    Int32, m_out.operation(operationRegExpTestString), m_callFrame, globalObject,
+                    base, argument);
                 setBoolean(result);
                 return;
             }
 
-            LValue argument = lowJSValue(m_node->child2());
-            setBoolean(
-                vmCall(Int32, m_out.operation(operationRegExpTest), m_callFrame, base, argument));
+            LValue argument = lowJSValue(m_node->child3());
+            LValue result = vmCall(
+                Int32, m_out.operation(operationRegExpTest), m_callFrame, globalObject, base,
+                argument);
+            setBoolean(result);
             return;
         }
 
-        LValue base = lowJSValue(m_node->child1());
-        LValue argument = lowJSValue(m_node->child2());
-        setBoolean(
-            vmCall(Int32, m_out.operation(operationRegExpTestGeneric), m_callFrame, base, argument));
+        LValue base = lowJSValue(m_node->child2());
+        LValue argument = lowJSValue(m_node->child3());
+        LValue result = vmCall(
+            Int32, m_out.operation(operationRegExpTestGeneric), m_callFrame, globalObject, base,
+            argument);
+        setBoolean(result);
     }
 
     void compileNewRegexp()
index 60c7ae7..1c4c1a6 100644 (file)
@@ -122,6 +122,9 @@ typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_ECJ)(ExecState*, JSCell*,
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_ECZ)(ExecState*, JSCell*, int32_t);
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EDA)(ExecState*, double, JSArray*);
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EE)(ExecState*, ExecState*);
+typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EGReoJ)(ExecState*, JSGlobalObject*, RegExpObject*, EncodedJSValue);
+typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EGReoJss)(ExecState*, JSGlobalObject*, RegExpObject*, JSString*);
+typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EGJJ)(ExecState*, JSGlobalObject*, EncodedJSValue, EncodedJSValue);
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EI)(ExecState*, UniquedStringImpl*);
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJ)(ExecState*, EncodedJSValue);
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJZ)(ExecState*, EncodedJSValue, int32_t);
@@ -201,6 +204,9 @@ typedef int32_t JIT_OPERATION (*Z_JITOperation_EJZ)(ExecState*, EncodedJSValue,
 typedef int32_t JIT_OPERATION (*Z_JITOperation_EJZZ)(ExecState*, EncodedJSValue, int32_t, int32_t);
 typedef size_t JIT_OPERATION (*S_JITOperation_ECC)(ExecState*, JSCell*, JSCell*);
 typedef size_t JIT_OPERATION (*S_JITOperation_EGC)(ExecState*, JSGlobalObject*, JSCell*);
+typedef size_t JIT_OPERATION (*S_JITOperation_EGJJ)(ExecState*, JSGlobalObject*, EncodedJSValue, EncodedJSValue);
+typedef size_t JIT_OPERATION (*S_JITOperation_EGReoJ)(ExecState*, JSGlobalObject*, RegExpObject*, EncodedJSValue);
+typedef size_t JIT_OPERATION (*S_JITOperation_EGReoJss)(ExecState*, JSGlobalObject*, RegExpObject*, JSString*);
 typedef size_t JIT_OPERATION (*S_JITOperation_EJ)(ExecState*, EncodedJSValue);
 typedef size_t JIT_OPERATION (*S_JITOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue);
 typedef size_t JIT_OPERATION (*S_JITOperation_EOJss)(ExecState*, JSObject*, JSString*);
index 1982cb3..2f60f16 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, 2008, 2009, 2014, 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009, 2014-2016 Apple Inc. All rights reserved.
  * Copyright (C) 2008 Cameron Zwarich (cwzwarich@uwaterloo.ca)
  *
  * Redistribution and use in source and binary forms, with or without
@@ -364,7 +364,8 @@ void JSGlobalObject::init(VM& vm)
     
     m_regExpPrototype.set(vm, this, RegExpPrototype::create(vm, this, RegExpPrototype::createStructure(vm, this, m_objectPrototype.get()), emptyRegex));
     m_regExpStructure.set(vm, this, RegExpObject::createStructure(vm, this, m_regExpPrototype.get()));
-    m_regExpMatchesArrayStructure.set(vm, this, createRegExpMatchesArrayStructure(vm, *this));
+    m_regExpMatchesArrayStructure.set(vm, this, createRegExpMatchesArrayStructure(vm, this));
+    m_regExpMatchesArraySlowPutStructure.set(vm, this, createRegExpMatchesArraySlowPutStructure(vm, this));
 
     m_moduleRecordStructure.set(vm, this, JSModuleRecord::createStructure(vm, this, m_objectPrototype.get()));
     m_moduleNamespaceObjectStructure.set(vm, this, JSModuleNamespaceObject::createStructure(vm, this, jsNull()));
@@ -761,6 +762,9 @@ void JSGlobalObject::haveABadTime(VM& vm)
     // this object now load a structure that uses SlowPut.
     for (unsigned i = 0; i < NumberOfIndexingShapes; ++i)
         m_arrayStructureForIndexingShapeDuringAllocation[i].set(vm, this, originalArrayStructureForIndexingType(ArrayWithSlowPutArrayStorage));
+
+    // Same for any special array structures.
+    m_regExpMatchesArrayStructure.set(vm, this, m_regExpMatchesArraySlowPutStructure.get());
     
     // Make sure that all objects that have indexed storage switch to the slow kind of
     // indexed storage.
@@ -900,6 +904,7 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
     visitor.append(&thisObject->m_generatorFunctionStructure);
     visitor.append(&thisObject->m_iteratorResultObjectStructure);
     visitor.append(&thisObject->m_regExpMatchesArrayStructure);
+    visitor.append(&thisObject->m_regExpMatchesArraySlowPutStructure);
     visitor.append(&thisObject->m_moduleRecordStructure);
     visitor.append(&thisObject->m_moduleNamespaceObjectStructure);
     visitor.append(&thisObject->m_consoleStructure);
index 9fc6597..af54e5f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Copyright (C) 2007 Eric Seidel <eric@webkit.org>
- *  Copyright (C) 2007, 2008, 2009, 2014, 2015 Apple Inc. All rights reserved.
+ *  Copyright (C) 2007, 2008, 2009, 2014-2016 Apple Inc. All rights reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Library General Public
@@ -278,6 +278,7 @@ protected:
     WriteBarrier<Structure> m_internalFunctionStructure;
     WriteBarrier<Structure> m_iteratorResultObjectStructure;
     WriteBarrier<Structure> m_regExpMatchesArrayStructure;
+    WriteBarrier<Structure> m_regExpMatchesArraySlowPutStructure;
     WriteBarrier<Structure> m_moduleRecordStructure;
     WriteBarrier<Structure> m_moduleNamespaceObjectStructure;
     WriteBarrier<Structure> m_proxyObjectStructure;
index d606278..9da05da 100644 (file)
@@ -1376,7 +1376,7 @@ ALWAYS_INLINE bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName
     // we want.
     DeferredStructureTransitionWatchpointFire deferredWatchpointFire;
     
-    newStructure = Structure::addPropertyTransition(
+    newStructure = Structure::addNewPropertyTransition(
         vm, structure, propertyName, attributes, offset, slot.context(), &deferredWatchpointFire);
     newStructure->willStoreValueForNewTransition(
         vm, propertyName, value, slot.context() == PutPropertySlot::PutById);
index 6dba786..c98052e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
- *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2014 Apple Inc. All rights reserved.
+ *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2014, 2016 Apple Inc. All rights reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Library General Public
@@ -293,28 +293,27 @@ private:
         fiber(2).set(vm, this, s3);
     }
 
-    void finishCreation(ExecState& exec, JSString& base, unsigned offset, unsigned length)
+    void finishCreation(VM& vm, ExecState* exec, JSString* base, unsigned offset, unsigned length)
     {
-        VM& vm = exec.vm();
         Base::finishCreation(vm);
         ASSERT(!sumOverflows<int32_t>(offset, length));
-        ASSERT(offset + length <= base.length());
+        ASSERT(offset + length <= base->length());
         m_length = length;
-        setIs8Bit(base.is8Bit());
+        setIs8Bit(base->is8Bit());
         setIsSubstring(true);
-        if (base.isSubstring()) {
-            JSRopeString& baseRope = static_cast<JSRopeString&>(base);
-            substringBase().set(vm, this, baseRope.substringBase().get());
-            substringOffset() = baseRope.substringOffset() + offset;
+        if (base->isSubstring()) {
+            JSRopeString* baseRope = jsCast<JSRopeString*>(base);
+            substringBase().set(vm, this, baseRope->substringBase().get());
+            substringOffset() = baseRope->substringOffset() + offset;
         } else {
-            substringBase().set(vm, this, &base);
+            substringBase().set(vm, this, base);
             substringOffset() = offset;
 
             // For now, let's not allow substrings with a rope base.
             // Resolve non-substring rope bases so we don't have to deal with it.
             // FIXME: Evaluate if this would be worth adding more branches.
-            if (base.isRope())
-                static_cast<JSRopeString&>(base).resolveRope(&exec);
+            if (base->isRope())
+                jsCast<JSRopeString*>(base)->resolveRope(exec);
         }
     }
 
@@ -356,10 +355,10 @@ public:
         return newString;
     }
 
-    static JSString* create(ExecState& exec, JSString& base, unsigned offset, unsigned length)
+    static JSString* create(VM& vm, ExecState* exec, JSString* base, unsigned offset, unsigned length)
     {
-        JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(exec.vm().heap)) JSRopeString(exec.vm());
-        newString->finishCreation(exec, base, offset, length);
+        JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm);
+        newString->finishCreation(vm, exec, base, offset, length);
         return newString;
     }
 
@@ -542,17 +541,21 @@ inline JSString* jsString(VM* vm, const String& s)
     return JSString::create(*vm, s.impl());
 }
 
-inline JSString* jsSubstring(ExecState* exec, JSString* s, unsigned offset, unsigned length)
+inline JSString* jsSubstring(VM& vm, ExecState* exec, JSString* s, unsigned offset, unsigned length)
 {
     ASSERT(offset <= static_cast<unsigned>(s->length()));
     ASSERT(length <= static_cast<unsigned>(s->length()));
     ASSERT(offset + length <= static_cast<unsigned>(s->length()));
-    VM& vm = exec->vm();
     if (!length)
         return vm.smallStrings.emptyString();
     if (!offset && length == s->length())
         return s;
-    return JSRopeString::create(*exec, *s, offset, length);
+    return JSRopeString::create(vm, exec, s, offset, length);
+}
+
+inline JSString* jsSubstring(ExecState* exec, JSString* s, unsigned offset, unsigned length)
+{
+    return jsSubstring(exec->vm(), exec, s, offset, length);
 }
 
 inline JSString* jsSubstring(VM* vm, const String& s, unsigned offset, unsigned length)
index e930618..5938c68 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -45,7 +45,7 @@ JSArray* RegExpCachedResult::lastResult(ExecState* exec, JSObject* owner)
 {
     if (!m_reified) {
         m_reifiedInput.set(exec->vm(), owner, m_lastInput.get());
-        m_reifiedResult.set(exec->vm(), owner, createRegExpMatchesArray(exec, m_lastInput.get(), m_lastRegExp.get(), m_result));
+        m_reifiedResult.set(exec->vm(), owner, createRegExpMatchesArray(exec, exec->lexicalGlobalObject(), m_lastInput.get(), m_lastRegExp.get(), m_result));
         m_reified = true;
     }
     return m_reifiedResult.get();
index 440cc95..8d56832 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -50,30 +50,56 @@ static JSArray* tryCreateUninitializedRegExpMatchesArray(VM& vm, Structure* stru
     return JSArray::createWithButterfly(vm, structure, butterfly);
 }
 
-JSArray* createRegExpMatchesArray(ExecState* exec, JSString* input, RegExp* regExp, MatchResult result)
+JSArray* createRegExpMatchesArray(
+    ExecState* exec, JSGlobalObject* globalObject, JSString* input, RegExp* regExp,
+    MatchResult result)
 {
+    SamplingRegion samplingRegion("createRegExpMatchesArray");
+    
     ASSERT(result);
-    VM& vm = exec->vm();
-    JSArray* array = tryCreateUninitializedRegExpMatchesArray(vm, exec->lexicalGlobalObject()->regExpMatchesArrayStructure(), regExp->numSubpatterns() + 1);
-    RELEASE_ASSERT(array);
-
-    SamplingRegion samplingRegion("Reifying substring properties");
-
-    array->initializeIndex(vm, 0, jsSubstring(exec, input, result.start, result.end - result.start), ArrayWithContiguous);
-
-    if (unsigned numSubpatterns = regExp->numSubpatterns()) {
-        Vector<int, 32> subpatternResults;
-        int position = regExp->match(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)
-                array->initializeIndex(vm, i, jsSubstring(exec, input, start, subpatternResults[2 * i + 1] - start), ArrayWithContiguous);
-            else
-                array->initializeIndex(vm, i, jsUndefined(), ArrayWithContiguous);
+    VM& vm = globalObject->vm();
+
+    JSArray* array;
+    if (UNLIKELY(globalObject->isHavingABadTime())) {
+        array = JSArray::tryCreateUninitialized(vm, globalObject->regExpMatchesArrayStructure(), regExp->numSubpatterns() + 1);
+        
+        array->initializeIndex(vm, 0, jsSubstring(vm, exec, input, result.start, result.end - result.start));
+        
+        if (unsigned numSubpatterns = regExp->numSubpatterns()) {
+            Vector<int, 32> subpatternResults;
+            int position = regExp->match(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)
+                    array->initializeIndex(vm, i, jsSubstring(vm, exec, input, start, subpatternResults[2 * i + 1] - start));
+                else
+                    array->initializeIndex(vm, i, jsUndefined());
+            }
+        }
+    } else {
+        array = tryCreateUninitializedRegExpMatchesArray(vm, globalObject->regExpMatchesArrayStructure(), regExp->numSubpatterns() + 1);
+        RELEASE_ASSERT(array);
+        
+        array->initializeIndex(vm, 0, jsSubstring(vm, exec, input, result.start, result.end - result.start), ArrayWithContiguous);
+        
+        if (unsigned numSubpatterns = regExp->numSubpatterns()) {
+            Vector<int, 32> subpatternResults;
+            int position = regExp->match(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)
+                    array->initializeIndex(vm, i, jsSubstring(vm, exec, input, start, subpatternResults[2 * i + 1] - start), ArrayWithContiguous);
+                else
+                    array->initializeIndex(vm, i, jsUndefined(), ArrayWithContiguous);
+            }
         }
     }
 
@@ -83,15 +109,25 @@ JSArray* createRegExpMatchesArray(ExecState* exec, JSString* input, RegExp* regE
     return array;
 }
 
-Structure* createRegExpMatchesArrayStructure(VM& vm, JSGlobalObject& globalObject)
+static Structure* createStructureImpl(VM& vm, JSGlobalObject* globalObject, IndexingType indexingType)
 {
-    Structure* structure = globalObject.arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous);
+    Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType);
     PropertyOffset offset;
-    structure = structure->addPropertyTransition(vm, structure, vm.propertyNames->index, 0, offset);
+    structure = Structure::addPropertyTransition(vm, structure, vm.propertyNames->index, 0, offset);
     ASSERT(offset == indexPropertyOffset);
-    structure = structure->addPropertyTransition(vm, structure, vm.propertyNames->input, 0, offset);
+    structure = Structure::addPropertyTransition(vm, structure, vm.propertyNames->input, 0, offset);
     ASSERT(offset == inputPropertyOffset);
     return structure;
 }
 
+Structure* createRegExpMatchesArrayStructure(VM& vm, JSGlobalObject* globalObject)
+{
+    return createStructureImpl(vm, globalObject, ArrayWithContiguous);
+}
+
+Structure* createRegExpMatchesArraySlowPutStructure(VM& vm, JSGlobalObject* globalObject)
+{
+    return createStructureImpl(vm, globalObject, ArrayWithSlowPutArrayStorage);
+}
+
 } // namespace JSC
index 669dd39..32f24c2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *  Copyright (C) 2008, 2016 Apple Inc. All Rights Reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -26,8 +26,9 @@
 
 namespace JSC {
 
-JSArray* createRegExpMatchesArray(ExecState*, JSString*, RegExp*, MatchResult);
-Structure* createRegExpMatchesArrayStructure(VM&, JSGlobalObject&);
+JSArray* createRegExpMatchesArray(ExecState*, JSGlobalObject*, JSString*, RegExp*, MatchResult);
+Structure* createRegExpMatchesArrayStructure(VM&, JSGlobalObject*);
+Structure* createRegExpMatchesArraySlowPutStructure(VM&, JSGlobalObject*);
 
 }
 
index d61ec74..1bbe720 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- *  Copyright (C) 2003, 2007, 2008, 2012 Apple Inc. All Rights Reserved.
+ *  Copyright (C) 2003, 2007, 2008, 2012, 2016 Apple Inc. All Rights Reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -159,20 +159,20 @@ void RegExpObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName,
     Base::put(cell, exec, propertyName, value, slot);
 }
 
-JSValue RegExpObject::exec(ExecState* exec, JSString* string)
+JSValue RegExpObject::exec(ExecState* exec, JSGlobalObject* globalObject, JSString* string)
 {
-    if (MatchResult result = match(exec, string))
-        return createRegExpMatchesArray(exec, string, regExp(), result);
+    if (MatchResult result = match(exec, globalObject, string))
+        return createRegExpMatchesArray(exec, globalObject, string, regExp(), result);
     return jsNull();
 }
 
 // Shared implementation used by test and exec.
-MatchResult RegExpObject::match(ExecState* exec, JSString* string)
+MatchResult RegExpObject::match(ExecState* exec, JSGlobalObject* globalObject, JSString* string)
 {
     RegExp* regExp = this->regExp();
-    RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
+    RegExpConstructor* regExpConstructor = globalObject->regExpConstructor();
     String input = string->value(exec);
-    VM& vm = exec->vm();
+    VM& vm = globalObject->vm();
     if (!regExp->global())
         return regExpConstructor->performMatch(vm, regExp, string, input, 0);
 
index 6535c58..4256801 100644 (file)
@@ -66,8 +66,8 @@ public:
         return m_lastIndex.get();
     }
 
-    bool test(ExecState* exec, JSString* string) { return match(exec, string); }
-    JSValue exec(ExecState*, JSString*);
+    bool test(ExecState* exec, JSGlobalObject* globalObject, JSString* string) { return match(exec, globalObject, string); }
+    JSValue exec(ExecState*, JSGlobalObject*, JSString*);
 
     static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
     static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
@@ -102,7 +102,7 @@ protected:
     JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
 
 private:
-    MatchResult match(ExecState*, JSString*);
+    MatchResult match(ExecState*, JSGlobalObject*, JSString*);
 
     WriteBarrier<RegExp> m_regExp;
     WriteBarrier<Unknown> m_lastIndex;
index db3c16f..8ecec1b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- *  Copyright (C) 2003, 2007, 2008 Apple Inc. All Rights Reserved.
+ *  Copyright (C) 2003, 2007, 2008, 2016 Apple Inc. All Rights Reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -102,7 +102,7 @@ EncodedJSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState* exec)
     JSString* string = exec->argument(0).toStringOrNull(exec);
     if (!string)
         return JSValue::encode(jsUndefined());
-    return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->test(exec, string)));
+    return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->test(exec, exec->lexicalGlobalObject(), string)));
 }
 
 EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState* exec)
@@ -113,7 +113,7 @@ EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState* exec)
     JSString* string = exec->argument(0).toStringOrNull(exec);
     if (!string)
         return JSValue::encode(jsUndefined());
-    return JSValue::encode(asRegExpObject(thisValue)->exec(exec, string));
+    return JSValue::encode(asRegExpObject(thisValue)->exec(exec, exec->lexicalGlobalObject(), string));
 }
 
 EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec)
index c8f9301..889d40c 100644 (file)
@@ -1035,7 +1035,8 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec)
         return throwVMTypeError(exec);
     JSString* string = thisValue.toString(exec);
     String s = string->value(exec);
-    VM* vm = &exec->vm();
+    JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+    VM* vm = &globalObject->vm();
 
     JSValue a0 = exec->argument(0);
 
@@ -1067,11 +1068,11 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec)
         if (!regExp->isValid())
             return throwVMError(exec, createSyntaxError(exec, regExp->errorMessage()));
     }
-    RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
+    RegExpConstructor* regExpConstructor = globalObject->regExpConstructor();
     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 ? createRegExpMatchesArray(exec, string, regExp, result) : jsNull());
+        return JSValue::encode(result ? createRegExpMatchesArray(exec, globalObject, string, regExp, result) : jsNull());
 
     // return array of matches
     MarkedArgumentBuffer list;
index 8a031aa..5bc663d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008, 2009, 2013-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009, 2013-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -443,7 +443,18 @@ NonPropertyTransition Structure::suggestedArrayStorageTransition() const
     return AllocateArrayStorage;
 }
 
-Structure* Structure::addPropertyTransition(VM& vm, Structure* structure, PropertyName propertyName, unsigned attributes, PropertyOffset& offset, PutPropertySlot::Context context, DeferredStructureTransitionWatchpointFire* deferred)
+Structure* Structure::addPropertyTransition(VM& vm, Structure* structure, PropertyName propertyName, unsigned attributes, PropertyOffset& offset)
+{
+    Structure* newStructure = addPropertyTransitionToExistingStructure(
+        structure, propertyName, attributes, offset);
+    if (newStructure)
+        return newStructure;
+
+    return addNewPropertyTransition(
+        vm, structure, propertyName, attributes, offset, PutPropertySlot::UnknownContext);
+}
+
+Structure* Structure::addNewPropertyTransition(VM& vm, Structure* structure, PropertyName propertyName, unsigned attributes, PropertyOffset& offset, PutPropertySlot::Context context, DeferredStructureTransitionWatchpointFire* deferred)
 {
     ASSERT(!structure->isDictionary());
     ASSERT(structure->isObject());
index ad559a4..c268480 100644 (file)
@@ -168,7 +168,8 @@ public:
 
     static void dumpStatistics();
 
-    JS_EXPORT_PRIVATE static Structure* addPropertyTransition(VM&, Structure*, PropertyName, unsigned attributes, PropertyOffset&, PutPropertySlot::Context = PutPropertySlot::UnknownContext, DeferredStructureTransitionWatchpointFire* = nullptr);
+    JS_EXPORT_PRIVATE static Structure* addPropertyTransition(VM&, Structure*, PropertyName, unsigned attributes, PropertyOffset&);
+    JS_EXPORT_PRIVATE static Structure* addNewPropertyTransition(VM&, Structure*, PropertyName, unsigned attributes, PropertyOffset&, PutPropertySlot::Context = PutPropertySlot::UnknownContext, DeferredStructureTransitionWatchpointFire* = nullptr);
     static Structure* addPropertyTransitionToExistingStructureConcurrently(Structure*, UniquedStringImpl* uid, unsigned attributes, PropertyOffset&);
     JS_EXPORT_PRIVATE static Structure* addPropertyTransitionToExistingStructure(Structure*, PropertyName, unsigned attributes, PropertyOffset&);
     static Structure* removePropertyTransition(VM&, Structure*, PropertyName, PropertyOffset&);
@@ -245,6 +246,9 @@ public:
     NonPropertyTransition suggestedArrayStorageTransition() const;
         
     JSGlobalObject* globalObject() const { return m_globalObject.get(); }
+
+    // NOTE: This method should only be called during the creation of structures, since the global
+    // object of a structure is presumed to be immutable in a bunch of places.
     void setGlobalObject(VM& vm, JSGlobalObject* globalObject) { m_globalObject.set(vm, this, globalObject); }
         
     JSValue storedPrototype() const { return m_prototype.get(); }
diff --git a/Source/JavaScriptCore/tests/stress/regexp-matches-array-bad-time.js b/Source/JavaScriptCore/tests/stress/regexp-matches-array-bad-time.js
new file mode 100644 (file)
index 0000000..538e6f7
--- /dev/null
@@ -0,0 +1,19 @@
+(function() {
+    var count = 11;
+
+    var array;
+    for (var i = 0; i < 10000; ++i) {
+        array = /foo/.exec("foo");
+        if (array[0] != "foo")
+            throw "Error: bad result: " + array[0];
+    }
+
+    delete array[0];
+
+    Array.prototype.__defineSetter__("0", function(value) { count += value; });
+    
+    array[0] = 42;
+    if (count != 53)
+        throw "Error: bad count: " + count;
+})();
+
diff --git a/Source/JavaScriptCore/tests/stress/regexp-matches-array-slow-put.js b/Source/JavaScriptCore/tests/stress/regexp-matches-array-slow-put.js
new file mode 100644 (file)
index 0000000..b7a1fc1
--- /dev/null
@@ -0,0 +1,15 @@
+(function() {
+    var count = 0;
+    Array.prototype.__defineSetter__("0", function(value) { count += value; });
+    
+    for (var i = 0; i < 10000; ++i) {
+        var array = /foo/.exec("foo");
+        if (array[0] != "foo")
+            throw "Error: bad result: " + array[0];
+        delete array[0];
+        array[0] = 42;
+        if (count != (i + 1) * 42)
+            throw "Error: bad count at i = " + i + ": " + count;
+    }
+})();