mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 851064: Allow one-level deep ropes when flattening for substr, r=evilpies
This commit is contained in:
parent
dbebffe87c
commit
6a37df8ca1
@ -367,14 +367,10 @@ ArrayConcatDense(JSContext *cx, HandleObject obj1, HandleObject obj2, HandleObje
|
||||
bool
|
||||
CharCodeAt(JSContext *cx, HandleString str, int32_t index, uint32_t *code)
|
||||
{
|
||||
JS_ASSERT(index >= 0 &&
|
||||
static_cast<uint32_t>(index) < str->length());
|
||||
|
||||
const jschar *chars = str->getChars(cx);
|
||||
if (!chars)
|
||||
jschar c;
|
||||
if (!str->getChar(cx, index, &c))
|
||||
return false;
|
||||
|
||||
*code = chars[index];
|
||||
*code = c;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
13
js/src/jit-test/tests/ion/bug851064.js
Normal file
13
js/src/jit-test/tests/ion/bug851064.js
Normal file
@ -0,0 +1,13 @@
|
||||
var base = "azertyuiopqsdfghjklmwxcvbn";
|
||||
function createRopedString() {
|
||||
var test = "";
|
||||
for (var i=0; i<2; i++) {
|
||||
test += base;
|
||||
}
|
||||
return test;
|
||||
}
|
||||
|
||||
assertEq(createRopedString().substr(0,10), base.substr(0,10));
|
||||
assertEq(createRopedString().substr(0,26), base.substr(0,26));
|
||||
assertEq(createRopedString().substr(26,10), base.substr(0,10));
|
||||
assertEq(createRopedString().substr(24,10), base.substr(24,2) + base.substr(0,8));
|
@ -570,6 +570,59 @@ ValueToIntegerRange(JSContext *cx, const Value &v, int32_t *out)
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSString *
|
||||
DoSubstr(JSContext *cx, JSString *str, size_t begin, size_t len)
|
||||
{
|
||||
/*
|
||||
* Optimization for one level deep ropes.
|
||||
* This is common for the following pattern:
|
||||
*
|
||||
* while() {
|
||||
* text = text.substr(0, x) + "bla" + text.substr(x)
|
||||
* test.charCodeAt(x + 1)
|
||||
* }
|
||||
*/
|
||||
if (str->isRope()) {
|
||||
JSRope *rope = &str->asRope();
|
||||
|
||||
/* Substring is totally in leftChild of rope. */
|
||||
if (begin + len <= rope->leftChild()->length()) {
|
||||
str = rope->leftChild();
|
||||
return js_NewDependentString(cx, str, begin, len);
|
||||
}
|
||||
|
||||
/* Substring is totally in rightChild of rope. */
|
||||
if (begin >= rope->leftChild()->length()) {
|
||||
str = rope->rightChild();
|
||||
begin -= rope->leftChild()->length();
|
||||
return js_NewDependentString(cx, str, begin, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Requested substring is partly in the left and partly in right child.
|
||||
* Create a rope of substrings for both childs.
|
||||
*/
|
||||
JS_ASSERT (begin < rope->leftChild()->length() &&
|
||||
begin + len > rope->leftChild()->length());
|
||||
|
||||
size_t lhsLength = rope->leftChild()->length() - begin;
|
||||
size_t rhsLength = begin + len - rope->leftChild()->length();
|
||||
|
||||
RootedString lhs(cx, js_NewDependentString(cx, rope->leftChild(),
|
||||
begin, lhsLength));
|
||||
if (!lhs)
|
||||
return NULL;
|
||||
|
||||
RootedString rhs(cx, js_NewDependentString(cx, rope->rightChild(), 0, rhsLength));
|
||||
if (!rhs)
|
||||
return NULL;
|
||||
|
||||
return JSRope::new_<CanGC>(cx, lhs, rhs, len);
|
||||
}
|
||||
|
||||
return js_NewDependentString(cx, str, begin, len);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
str_substring(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
@ -620,7 +673,7 @@ str_substring(JSContext *cx, unsigned argc, Value *vp)
|
||||
}
|
||||
}
|
||||
|
||||
str = js_NewDependentString(cx, str, size_t(begin), size_t(end - begin));
|
||||
str = DoSubstr(cx, str, size_t(begin), size_t(end - begin));
|
||||
if (!str)
|
||||
return false;
|
||||
}
|
||||
@ -859,12 +912,10 @@ js_str_charCodeAt(JSContext *cx, unsigned argc, Value *vp)
|
||||
i = size_t(d);
|
||||
}
|
||||
|
||||
const jschar *chars;
|
||||
chars = str->getChars(cx);
|
||||
if (!chars)
|
||||
jschar c;
|
||||
if (!str->getChar(cx, i, &c))
|
||||
return false;
|
||||
|
||||
args.rval().setInt32(chars[i]);
|
||||
args.rval().setInt32(c);
|
||||
return true;
|
||||
|
||||
out_of_range:
|
||||
@ -3109,7 +3160,7 @@ str_substr(JSContext *cx, unsigned argc, Value *vp)
|
||||
len = length - begin;
|
||||
}
|
||||
|
||||
str = js_NewDependentString(cx, str, size_t(begin), size_t(len));
|
||||
str = DoSubstr(cx, str, size_t(begin), size_t(len));
|
||||
if (!str)
|
||||
return false;
|
||||
}
|
||||
|
@ -404,10 +404,10 @@ inline JSLinearString *
|
||||
js::StaticStrings::getUnitStringForElement(JSContext *cx, JSString *str, size_t index)
|
||||
{
|
||||
JS_ASSERT(index < str->length());
|
||||
const jschar *chars = str->getChars(cx);
|
||||
if (!chars)
|
||||
|
||||
jschar c;
|
||||
if (!str->getChar(cx, index, &c))
|
||||
return NULL;
|
||||
jschar c = chars[index];
|
||||
if (c < UNIT_STATIC_LIMIT)
|
||||
return getUnit(c);
|
||||
return js_NewDependentString(cx, str, index, 1);
|
||||
|
@ -204,15 +204,36 @@ JSRope::flattenInternal(JSContext *maybecx)
|
||||
jschar *pos;
|
||||
JSRuntime *rt = runtime();
|
||||
|
||||
if (this->leftChild()->isExtensible()) {
|
||||
JSExtensibleString &left = this->leftChild()->asExtensible();
|
||||
/* Find the left most string, containing the first string. */
|
||||
JSRope *leftMostRope = this;
|
||||
while (leftMostRope->leftChild()->isRope())
|
||||
leftMostRope = &leftMostRope->leftChild()->asRope();
|
||||
|
||||
if (leftMostRope->leftChild()->isExtensible()) {
|
||||
JSExtensibleString &left = leftMostRope->leftChild()->asExtensible();
|
||||
size_t capacity = left.capacity();
|
||||
if (capacity >= wholeLength) {
|
||||
if (b == WithIncrementalBarrier) {
|
||||
JSString::writeBarrierPre(d.u1.left);
|
||||
JSString::writeBarrierPre(d.s.u2.right);
|
||||
/*
|
||||
* Simulate a left-most traversal from the root to leftMost->leftChild()
|
||||
* via first_visit_node
|
||||
*/
|
||||
while (str != leftMostRope) {
|
||||
JS_ASSERT(str->isRope());
|
||||
if (b == WithIncrementalBarrier) {
|
||||
JSString::writeBarrierPre(str->d.u1.left);
|
||||
JSString::writeBarrierPre(str->d.s.u2.right);
|
||||
}
|
||||
JSString *child = str->d.u1.left;
|
||||
str->d.u1.chars = left.chars();
|
||||
child->d.s.u3.parent = str;
|
||||
child->d.lengthAndFlags = 0x200;
|
||||
str = child;
|
||||
}
|
||||
str->d.u1.chars = left.chars();
|
||||
if (b == WithIncrementalBarrier) {
|
||||
JSString::writeBarrierPre(str->d.u1.left);
|
||||
JSString::writeBarrierPre(str->d.s.u2.right);
|
||||
}
|
||||
|
||||
wholeCapacity = capacity;
|
||||
wholeChars = const_cast<jschar *>(left.chars());
|
||||
size_t bits = left.d.lengthAndFlags;
|
||||
|
@ -269,6 +269,7 @@ class JSString : public js::gc::Cell
|
||||
|
||||
inline const jschar *getChars(JSContext *cx);
|
||||
inline const jschar *getCharsZ(JSContext *cx);
|
||||
inline bool getChar(JSContext *cx, size_t index, jschar *code);
|
||||
|
||||
/* Fallible conversions to more-derived string types. */
|
||||
|
||||
@ -891,6 +892,40 @@ JSString::getChars(JSContext *cx)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE bool
|
||||
JSString::getChar(JSContext *cx, size_t index, jschar *code)
|
||||
{
|
||||
JS_ASSERT(index < length());
|
||||
|
||||
/*
|
||||
* Optimization for one level deep ropes.
|
||||
* This is common for the following pattern:
|
||||
*
|
||||
* while() {
|
||||
* text = text.substr(0, x) + "bla" + text.substr(x)
|
||||
* test.charCodeAt(x + 1)
|
||||
* }
|
||||
*/
|
||||
const jschar *chars;
|
||||
if (isRope()) {
|
||||
JSRope *rope = &asRope();
|
||||
if (uint32_t(index) < rope->leftChild()->length()) {
|
||||
chars = rope->leftChild()->getChars(cx);
|
||||
} else {
|
||||
chars = rope->rightChild()->getChars(cx);
|
||||
index -= rope->leftChild()->length();
|
||||
}
|
||||
} else {
|
||||
chars = getChars(cx);
|
||||
}
|
||||
|
||||
if (!chars)
|
||||
return false;
|
||||
|
||||
*code = chars[index];
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE const jschar *
|
||||
JSString::getCharsZ(JSContext *cx)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user