]> git.saurik.com Git - apple/javascriptcore.git/commitdiff
JavaScriptCore-1218.35.tar.gz ios-712 v1218.35
authorApple <opensource@apple.com>
Tue, 17 Feb 2015 05:00:49 +0000 (05:00 +0000)
committerApple <opensource@apple.com>
Tue, 17 Feb 2015 05:00:49 +0000 (05:00 +0000)
15 files changed:
assembler/MacroAssemblerARM64.h
assembler/MacroAssemblerARMv7.h
dfg/DFGAbstractState.cpp
dfg/DFGOperations.cpp
dfg/DFGSpeculativeJIT.cpp
jit/JITCall32_64.cpp
llint/LLIntSlowPaths.cpp
runtime/JSString.cpp
runtime/JSString.h
runtime/Operations.h
runtime/StringPrototype.cpp
tests/stress/make-large-string-jit-strcat.js [new file with mode: 0644]
tests/stress/make-large-string-jit.js [new file with mode: 0644]
tests/stress/make-large-string-strcat.js [new file with mode: 0644]
tests/stress/make-large-string.js [new file with mode: 0644]

index 7c9e9228cda45d2a223a215c442cb0a5434436e3..8d0e79c69d90c52201304893cfc96179958f6278 100644 (file)
@@ -1738,6 +1738,12 @@ public:
         return branchAdd32(cond, op1, dataTempRegister, dest);
     }
 
+    Jump branchAdd32(ResultCondition cond, Address src, RegisterID dest)
+    {
+        load32(src, getCachedDataTempRegisterIDAndInvalidate());
+        return branchAdd32(cond, dest, dataTempRegister, dest);
+    }
+
     Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
     {
         return branchAdd32(cond, dest, src, dest);
index 9cbb71c9f3408495cc9f0002093f159accfb33ff..f65b1cddd1bafb448339a7ee6aff824d4c8d9335 100644 (file)
@@ -1477,6 +1477,12 @@ public:
         return branchAdd32(cond, dest, src, dest);
     }
 
+    Jump branchAdd32(ResultCondition cond, Address src, RegisterID dest)
+    {
+        load32(src, dataTempRegister);
+        return branchAdd32(cond, dest, dataTempRegister, dest);
+    }
+
     Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
     {
         return branchAdd32(cond, dest, imm, dest);
index be83f69c362afa796decc449bdbb116fd0dea81b..78ebb4aa800680c756ffa64917619b92c593e2b5 100644 (file)
@@ -476,6 +476,7 @@ bool AbstractState::executeEffects(unsigned indexInBlock, Node* node)
     }
         
     case MakeRope: {
+        node->setCanExit(true);
         forNode(node).set(m_graph.m_vm.stringStructure.get());
         break;
     }
index 860c486fd5bdfc473464602ff6cd30398812e072..af8212dd37ad039ea2b62821059c573ffa477546 100644 (file)
@@ -1643,6 +1643,11 @@ JSCell* DFG_OPERATION operationMakeRope2(ExecState* exec, JSString* left, JSStri
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
 
+    if (sumOverflows<int32_t>(left->length(), right->length())) {
+        throwOutOfMemoryError(exec);
+        return nullptr;
+    }
+
     return JSRopeString::create(vm, left, right);
 }
 
@@ -1651,6 +1656,11 @@ JSCell* DFG_OPERATION operationMakeRope3(ExecState* exec, JSString* a, JSString*
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
 
+    if (sumOverflows<int32_t>(a->length(), b->length(), c->length())) {
+        throwOutOfMemoryError(exec);
+        return nullptr;
+    }
+
     return JSRopeString::create(vm, a, b, c);
 }
 
index 64f1b4bd2955a1589eb725d893696c3b033da33d..bffc37c41c8b2b3db896d42a2cfc72192d66d1d2 100644 (file)
@@ -3244,12 +3244,28 @@ void SpeculativeJIT::compileMakeRope(Node* node)
         m_jit.storePtr(TrustedImmPtr(0), JITCompiler::Address(resultGPR, JSRopeString::offsetOfFibers() + sizeof(WriteBarrier<JSString>) * i));
     m_jit.load32(JITCompiler::Address(opGPRs[0], JSString::offsetOfFlags()), scratchGPR);
     m_jit.load32(JITCompiler::Address(opGPRs[0], JSString::offsetOfLength()), allocatorGPR);
+    if (!ASSERT_DISABLED) {
+        JITCompiler::Jump ok = m_jit.branch32(
+            JITCompiler::GreaterThanOrEqual, allocatorGPR, TrustedImm32(0));
+        m_jit.breakpoint();
+        ok.link(&m_jit);
+    }
     for (unsigned i = 1; i < numOpGPRs; ++i) {
         m_jit.and32(JITCompiler::Address(opGPRs[i], JSString::offsetOfFlags()), scratchGPR);
-        m_jit.add32(JITCompiler::Address(opGPRs[i], JSString::offsetOfLength()), allocatorGPR);
+        speculationCheck(
+            Uncountable, JSValueSource(), nullptr,
+            m_jit.branchAdd32(
+                JITCompiler::Overflow,
+                JITCompiler::Address(opGPRs[i], JSString::offsetOfLength()), allocatorGPR));
     }
     m_jit.and32(JITCompiler::TrustedImm32(JSString::Is8Bit), scratchGPR);
     m_jit.store32(scratchGPR, JITCompiler::Address(resultGPR, JSString::offsetOfFlags()));
+    if (!ASSERT_DISABLED) {
+        JITCompiler::Jump ok = m_jit.branch32(
+            JITCompiler::GreaterThanOrEqual, allocatorGPR, TrustedImm32(0));
+        m_jit.breakpoint();
+        ok.link(&m_jit);
+    }
     m_jit.store32(allocatorGPR, JITCompiler::Address(resultGPR, JSString::offsetOfLength()));
     
     switch (numOpGPRs) {
index c8be312062544c60dfc83d6cd364e98aee9699a7..85bf3a91552b7bfaa18ef174dd07f79de4a2d7fa 100644 (file)
@@ -269,13 +269,14 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned ca
         return;
     }
 
+    addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)));
+
     DataLabelPtr addressOfLinkedFunctionCheck;
     BEGIN_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
     Jump slowCase = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, TrustedImmPtr(0));
     END_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
 
     addSlowCase(slowCase);
-    addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)));
 
     ASSERT(m_callStructureStubCompilationInfo.size() == callLinkInfoIndex);
     m_callStructureStubCompilationInfo.append(StructureStubCompilationInfo());
index cf8ded31a8a3cbd715c12725d2af73cded3102b9..49284cd9d7f309e6d5a626e941aefed5f47805b7 100644 (file)
@@ -117,6 +117,14 @@ namespace JSC { namespace LLInt {
         LLINT_END_IMPL();                       \
     } while (false)
 
+#define LLINT_RETURN_WITH_PC_ADJUSTMENT(value, pcAdjustment) do { \
+        JSValue __r_returnValue = (value);      \
+        LLINT_CHECK_EXCEPTION();                \
+        LLINT_OP(1) = __r_returnValue;          \
+        pc += (pcAdjustment);                   \
+        LLINT_END_IMPL();                       \
+    } while (false)
+
 #if ENABLE(VALUE_PROFILER)
 #define LLINT_RETURN_PROFILED(opcode, value) do {               \
         JSValue __rp_returnValue = (value);                     \
@@ -727,8 +735,8 @@ LLINT_SLOW_PATH_DECL(slow_path_check_has_instance)
         JSObject* baseObject = asObject(baseVal);
         ASSERT(!baseObject->structure()->typeInfo().implementsDefaultHasInstance());
         if (baseObject->structure()->typeInfo().implementsHasInstance()) {
-            pc += pc[4].u.operand;
-            LLINT_RETURN(jsBoolean(baseObject->methodTable()->customHasInstance(baseObject, exec, value)));
+            JSValue result = jsBoolean(baseObject->methodTable()->customHasInstance(baseObject, exec, value));
+            LLINT_RETURN_WITH_PC_ADJUSTMENT(result, pc[4].u.operand);
         }
     }
     LLINT_THROW(createInvalidParamError(exec, "instanceof", baseVal));
index 86704d715805cba8e6f12faeae66cc35173451dc..6f0b09d13b5e29da2673dbd149b123beb270a7bc 100644 (file)
@@ -40,6 +40,7 @@ void JSRopeString::RopeBuilder::expand()
 {
     ASSERT(m_index == JSRopeString::s_maxInternalRopeLength);
     JSString* jsString = m_jsString;
+    RELEASE_ASSERT(jsString);
     m_jsString = jsStringBuilder(&m_vm);
     m_index = 0;
     append(jsString);
index 855de974d03200fe6667294564ac4baec58b2a59..d913aff07501e51f04c1a248bd57fc7ac1e67793 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 Apple Inc. All rights reserved.
+ *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2014 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
@@ -121,7 +121,8 @@ public:
     static JSString* create(VM& vm, PassRefPtr<StringImpl> value)
     {
         ASSERT(value);
-        size_t length = value->length();
+        int32_t length = value->length();
+        RELEASE_ASSERT(length >= 0);
         size_t cost = value->cost();
         JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, value);
         newString->finishCreation(vm, length, cost);
@@ -226,15 +227,21 @@ class JSRopeString : public JSString {
         {
         }
 
-        void append(JSString* jsString)
+        bool append(JSString* jsString)
         {
             if (m_index == JSRopeString::s_maxInternalRopeLength)
                 expand();
+            if (static_cast<int32_t>(m_jsString->length() + jsString->length()) < 0) {
+                m_jsString = nullptr;
+                return false;
+            }
             m_jsString->append(m_vm, m_index++, jsString);
+            return true;
         }
 
         JSRopeString* release()
         {
+            RELEASE_ASSERT(m_jsString);
             JSRopeString* tmp = m_jsString;
             m_jsString = 0;
             return tmp;
@@ -284,6 +291,7 @@ private:
     {
         m_fibers[index].set(vm, this, jsString);
         m_length += jsString->m_length;
+        RELEASE_ASSERT(static_cast<int32_t>(m_length) >= 0);
         setIs8Bit(is8Bit() && jsString->is8Bit());
     }
 
index 14557c7fab3d6cb7e492ea73889a85ef2afea29a..95bd9c0c29a79fb4bf8bf8a00c0bb93d53dba61e 100644 (file)
@@ -41,13 +41,13 @@ ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, JSString* s2)
 {
     VM& vm = exec->vm();
 
-    unsigned length1 = s1->length();
+    int32_t length1 = s1->length();
     if (!length1)
         return s2;
-    unsigned length2 = s2->length();
+    int32_t length2 = s2->length();
     if (!length2)
         return s1;
-    if ((length1 + length2) < length1)
+    if (sumOverflows<int32_t>(length1, length2))
         return throwOutOfMemoryError(exec);
 
     return JSRopeString::create(vm, s1, s2);
@@ -57,9 +57,13 @@ ALWAYS_INLINE JSValue jsString(ExecState* exec, const String& u1, const String&
 {
     VM* vm = &exec->vm();
 
-    unsigned length1 = u1.length();
-    unsigned length2 = u2.length();
-    unsigned length3 = u3.length();
+    int32_t length1 = u1.length();
+    int32_t length2 = u2.length();
+    int32_t length3 = u3.length();
+    
+    if (length1 < 0 || length2 < 0 || length3 < 0)
+        return throwOutOfMemoryError(exec);
+    
     if (!length1)
         return jsString(exec, jsString(vm, u2), jsString(vm, u3));
     if (!length2)
@@ -67,9 +71,7 @@ ALWAYS_INLINE JSValue jsString(ExecState* exec, const String& u1, const String&
     if (!length3)
         return jsString(exec, jsString(vm, u1), jsString(vm, u2));
 
-    if ((length1 + length2) < length1)
-        return throwOutOfMemoryError(exec);
-    if ((length1 + length2 + length3) < length3)
+    if (sumOverflows<int32_t>(length1, length2, length3))
         return throwOutOfMemoryError(exec);
 
     return JSRopeString::create(exec->vm(), jsString(vm, u1), jsString(vm, u2), jsString(vm, u3));
@@ -80,15 +82,10 @@ ALWAYS_INLINE JSValue jsString(ExecState* exec, Register* strings, unsigned coun
     VM* vm = &exec->vm();
     JSRopeString::RopeBuilder ropeBuilder(*vm);
 
-    unsigned oldLength = 0;
-
     for (unsigned i = 0; i < count; ++i) {
         JSValue v = strings[i].jsValue();
-        ropeBuilder.append(v.toString(exec));
-
-        if (ropeBuilder.length() < oldLength) // True for overflow
+        if (!ropeBuilder.append(v.toString(exec)))
             return throwOutOfMemoryError(exec);
-        oldLength = ropeBuilder.length();
     }
 
     return ropeBuilder.release();
@@ -100,15 +97,10 @@ ALWAYS_INLINE JSValue jsStringFromArguments(ExecState* exec, JSValue thisValue)
     JSRopeString::RopeBuilder ropeBuilder(*vm);
     ropeBuilder.append(thisValue.toString(exec));
 
-    unsigned oldLength = 0;
-
     for (unsigned i = 0; i < exec->argumentCount(); ++i) {
         JSValue v = exec->argument(i);
-        ropeBuilder.append(v.toString(exec));
-
-        if (ropeBuilder.length() < oldLength) // True for overflow
+        if (!ropeBuilder.append(v.toString(exec)))
             return throwOutOfMemoryError(exec);
-        oldLength = ropeBuilder.length();
     }
 
     return ropeBuilder.release();
index c422fd17b47a9afb14a0ecb1f58e3c16ed3b1fa7..2e9baba73149767fc7e7eb0986651d7c56a25c94 100644 (file)
@@ -761,6 +761,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState* exec)
     else {
         unsigned pos;
         int len = s.length();
+        RELEASE_ASSERT(len >= 0);
         if (a1.isUInt32())
             pos = std::min<uint32_t>(a1.asUInt32(), len);
         else {
@@ -904,6 +905,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState* exec)
         return throwVMTypeError(exec);
     String s = thisValue.toString(exec)->value(exec);
     int len = s.length();
+    RELEASE_ASSERT(len >= 0);
 
     JSValue a0 = exec->argument(0);
     JSValue a1 = exec->argument(1);
@@ -1216,6 +1218,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState* exec)
     JSValue a0 = exec->argument(0);
     JSValue a1 = exec->argument(1);
     int len = jsString->length();
+    RELEASE_ASSERT(len >= 0);
 
     double start = a0.toNumber(exec);
     double end;
@@ -1253,6 +1256,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec)
     int sSize = s.length();
     if (!sSize)
         return JSValue::encode(sVal);
+    RELEASE_ASSERT(sSize >= 0);
 
     StringImpl* ourImpl = s.impl();
     RefPtr<StringImpl> lower = ourImpl->lower();
diff --git a/tests/stress/make-large-string-jit-strcat.js b/tests/stress/make-large-string-jit-strcat.js
new file mode 100644 (file)
index 0000000..a6aeb1d
--- /dev/null
@@ -0,0 +1,24 @@
+// Like make-large-string-jit.js, but tests MakeRope with three arguments and op_strcat
+// in the DFG and FTL JITs.
+
+var s = "s";
+
+function foo(a, b) {
+    return "t" + a + b;
+}
+
+noInline(foo);
+
+for (var i = 0; i < 100000; ++i)
+    foo("a", "b");
+
+try {
+    for (var i = 0; i < 31; ++i)
+        s = foo(s, s);
+    print("Should not have gotten here.");
+    print("String length: " + s.length);
+    throw "Should not have gotten here.";
+} catch (e) {
+    if (e.message != "Out of memory")
+        throw "Wrong error: " + e;
+}
diff --git a/tests/stress/make-large-string-jit.js b/tests/stress/make-large-string-jit.js
new file mode 100644 (file)
index 0000000..8ee8847
--- /dev/null
@@ -0,0 +1,23 @@
+// Like make-large-string.js, but tests MakeRope with two arguments in the DFG and FTL JITs.
+
+var s = "s";
+
+function foo(a, b) {
+    return a + b;
+}
+
+noInline(foo);
+
+for (var i = 0; i < 100000; ++i)
+    foo("a", "b");
+
+try {
+    for (var i = 0; i < 31; ++i)
+        s = foo(s, s);
+    print("Should not have gotten here.");
+    print("String length: " + s.length);
+    throw "Should not have gotten here.";
+} catch (e) {
+    if (e.message != "Out of memory")
+        throw "Wrong error: " + e;
+}
diff --git a/tests/stress/make-large-string-strcat.js b/tests/stress/make-large-string-strcat.js
new file mode 100644 (file)
index 0000000..f101228
--- /dev/null
@@ -0,0 +1,12 @@
+var s = "s";
+
+try {
+    for (var i = 0; i < 31; ++i)
+        s = "t" + s + s;
+    print("Should not have gotten here.");
+    print("String length: " + s.length);
+    throw "Should not have gotten here.";
+} catch (e) {
+    if (e.message != "Out of memory")
+        throw "Wrong error: " + e;
+}
diff --git a/tests/stress/make-large-string.js b/tests/stress/make-large-string.js
new file mode 100644 (file)
index 0000000..c3ad773
--- /dev/null
@@ -0,0 +1,12 @@
+var s = "s";
+
+try {
+    for (var i = 0; i < 31; ++i)
+        s = s + s;
+    print("Should not have gotten here.");
+    print("String length: " + s.length);
+    throw "Should not have gotten here.";
+} catch (e) {
+    if (e.message != "Out of memory")
+        throw "Wrong error: " + e;
+}