diff options
Diffstat (limited to 'JavaScriptCore/runtime/Operations.h')
| -rw-r--r-- | JavaScriptCore/runtime/Operations.h | 209 |
1 files changed, 141 insertions, 68 deletions
diff --git a/JavaScriptCore/runtime/Operations.h b/JavaScriptCore/runtime/Operations.h index 9b27074..1252345 100644 --- a/JavaScriptCore/runtime/Operations.h +++ b/JavaScriptCore/runtime/Operations.h @@ -37,132 +37,203 @@ namespace JSC { ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, JSString* s2) { - if (!s1->length()) + unsigned length1 = s1->length(); + if (!length1) return s2; - if (!s2->length()) + unsigned length2 = s2->length(); + if (!length2) return s1; + if ((length1 + length2) < length1) + return throwOutOfMemoryError(exec); - unsigned ropeLength = s1->ropeLength() + s2->ropeLength(); + unsigned fiberCount = s1->fiberCount() + s2->fiberCount(); JSGlobalData* globalData = &exec->globalData(); - if (ropeLength <= JSString::s_maxInternalRopeLength) - return new (globalData) JSString(globalData, ropeLength, s1, s2); + if (fiberCount <= JSString::s_maxInternalRopeLength) + return new (globalData) JSString(globalData, fiberCount, s1, s2); - unsigned index = 0; - RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength); - if (UNLIKELY(!rope)) + JSString::RopeBuilder ropeBuilder(fiberCount); + if (UNLIKELY(ropeBuilder.isOutOfMemory())) return throwOutOfMemoryError(exec); - rope->append(index, s1); - rope->append(index, s2); - ASSERT(index == ropeLength); - return new (globalData) JSString(globalData, rope.release()); + ropeBuilder.append(s1); + ropeBuilder.append(s2); + return new (globalData) JSString(globalData, ropeBuilder.release()); } ALWAYS_INLINE JSValue jsString(ExecState* exec, const UString& u1, JSString* s2) { - unsigned ropeLength = 1 + s2->ropeLength(); + unsigned length1 = u1.length(); + if (!length1) + return s2; + unsigned length2 = s2->length(); + if (!length2) + return jsString(exec, u1); + if ((length1 + length2) < length1) + return throwOutOfMemoryError(exec); + + unsigned fiberCount = 1 + s2->fiberCount(); JSGlobalData* globalData = &exec->globalData(); - if (ropeLength <= JSString::s_maxInternalRopeLength) - return new (globalData) JSString(globalData, ropeLength, u1, s2); + if (fiberCount <= JSString::s_maxInternalRopeLength) + return new (globalData) JSString(globalData, fiberCount, u1, s2); - unsigned index = 0; - RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength); - if (UNLIKELY(!rope)) + JSString::RopeBuilder ropeBuilder(fiberCount); + if (UNLIKELY(ropeBuilder.isOutOfMemory())) return throwOutOfMemoryError(exec); - rope->append(index, u1); - rope->append(index, s2); - ASSERT(index == ropeLength); - return new (globalData) JSString(globalData, rope.release()); + ropeBuilder.append(u1); + ropeBuilder.append(s2); + return new (globalData) JSString(globalData, ropeBuilder.release()); } ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, const UString& u2) { - unsigned ropeLength = s1->ropeLength() + 1; + unsigned length1 = s1->length(); + if (!length1) + return jsString(exec, u2); + unsigned length2 = u2.length(); + if (!length2) + return s1; + if ((length1 + length2) < length1) + return throwOutOfMemoryError(exec); + + unsigned fiberCount = s1->fiberCount() + 1; JSGlobalData* globalData = &exec->globalData(); - if (ropeLength <= JSString::s_maxInternalRopeLength) - return new (globalData) JSString(globalData, ropeLength, s1, u2); + if (fiberCount <= JSString::s_maxInternalRopeLength) + return new (globalData) JSString(globalData, fiberCount, s1, u2); - unsigned index = 0; - RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength); - if (UNLIKELY(!rope)) + JSString::RopeBuilder ropeBuilder(fiberCount); + if (UNLIKELY(ropeBuilder.isOutOfMemory())) return throwOutOfMemoryError(exec); - rope->append(index, s1); - rope->append(index, u2); - ASSERT(index == ropeLength); - return new (globalData) JSString(globalData, rope.release()); + ropeBuilder.append(s1); + ropeBuilder.append(u2); + return new (globalData) JSString(globalData, ropeBuilder.release()); + } + + ALWAYS_INLINE JSValue jsString(ExecState* exec, const UString& u1, const UString& u2) + { + unsigned length1 = u1.length(); + if (!length1) + return jsString(exec, u2); + unsigned length2 = u2.length(); + if (!length2) + return jsString(exec, u1); + if ((length1 + length2) < length1) + return throwOutOfMemoryError(exec); + + JSGlobalData* globalData = &exec->globalData(); + return new (globalData) JSString(globalData, u1, u2); + } + + ALWAYS_INLINE JSValue jsString(ExecState* exec, const UString& u1, const UString& u2, const UString& u3) + { + unsigned length1 = u1.length(); + unsigned length2 = u2.length(); + unsigned length3 = u3.length(); + if (!length1) + return jsString(exec, u2, u3); + if (!length2) + return jsString(exec, u1, u3); + if (!length3) + return jsString(exec, u1, u2); + + if ((length1 + length2) < length1) + return throwOutOfMemoryError(exec); + if ((length1 + length2 + length3) < length3) + return throwOutOfMemoryError(exec); + + JSGlobalData* globalData = &exec->globalData(); + return new (globalData) JSString(globalData, u1, u2, u3); } ALWAYS_INLINE JSValue jsString(ExecState* exec, Register* strings, unsigned count) { ASSERT(count >= 3); - unsigned ropeLength = 0; + unsigned fiberCount = 0; for (unsigned i = 0; i < count; ++i) { JSValue v = strings[i].jsValue(); if (LIKELY(v.isString())) - ropeLength += asString(v)->ropeLength(); + fiberCount += asString(v)->fiberCount(); else - ++ropeLength; + ++fiberCount; } JSGlobalData* globalData = &exec->globalData(); - if (ropeLength == 3) + if (fiberCount == 3) return new (globalData) JSString(exec, strings[0].jsValue(), strings[1].jsValue(), strings[2].jsValue()); - RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength); - if (UNLIKELY(!rope)) + JSString::RopeBuilder ropeBuilder(fiberCount); + if (UNLIKELY(ropeBuilder.isOutOfMemory())) return throwOutOfMemoryError(exec); - unsigned index = 0; + unsigned length = 0; + bool overflow = false; + for (unsigned i = 0; i < count; ++i) { JSValue v = strings[i].jsValue(); if (LIKELY(v.isString())) - rope->append(index, asString(v)); + ropeBuilder.append(asString(v)); else - rope->append(index, v.toString(exec)); + ropeBuilder.append(v.toString(exec)); + + unsigned newLength = ropeBuilder.length(); + if (newLength < length) + overflow = true; + length = newLength; } - ASSERT(index == ropeLength); - return new (globalData) JSString(globalData, rope.release()); + if (overflow) + return throwOutOfMemoryError(exec); + + return new (globalData) JSString(globalData, ropeBuilder.release()); } - ALWAYS_INLINE JSValue jsString(ExecState* exec, JSValue thisValue, const ArgList& args) + ALWAYS_INLINE JSValue jsString(ExecState* exec, JSValue thisValue) { - unsigned ropeLength = 0; + unsigned fiberCount = 0; if (LIKELY(thisValue.isString())) - ropeLength += asString(thisValue)->ropeLength(); + fiberCount += asString(thisValue)->fiberCount(); else - ++ropeLength; - for (unsigned i = 0; i < args.size(); ++i) { - JSValue v = args.at(i); + ++fiberCount; + for (unsigned i = 0; i < exec->argumentCount(); ++i) { + JSValue v = exec->argument(i); if (LIKELY(v.isString())) - ropeLength += asString(v)->ropeLength(); + fiberCount += asString(v)->fiberCount(); else - ++ropeLength; + ++fiberCount; } - RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength); - if (UNLIKELY(!rope)) + JSString::RopeBuilder ropeBuilder(fiberCount); + if (UNLIKELY(ropeBuilder.isOutOfMemory())) return throwOutOfMemoryError(exec); - unsigned index = 0; if (LIKELY(thisValue.isString())) - rope->append(index, asString(thisValue)); + ropeBuilder.append(asString(thisValue)); else - rope->append(index, thisValue.toString(exec)); - for (unsigned i = 0; i < args.size(); ++i) { - JSValue v = args.at(i); + ropeBuilder.append(thisValue.toString(exec)); + + unsigned length = 0; + bool overflow = false; + + for (unsigned i = 0; i < exec->argumentCount(); ++i) { + JSValue v = exec->argument(i); if (LIKELY(v.isString())) - rope->append(index, asString(v)); + ropeBuilder.append(asString(v)); else - rope->append(index, v.toString(exec)); + ropeBuilder.append(v.toString(exec)); + + unsigned newLength = ropeBuilder.length(); + if (newLength < length) + overflow = true; + length = newLength; } - ASSERT(index == ropeLength); + + if (overflow) + return throwOutOfMemoryError(exec); JSGlobalData* globalData = &exec->globalData(); - return new (globalData) JSString(globalData, rope.release()); + return new (globalData) JSString(globalData, ropeBuilder.release()); } // ECMA 11.9.3 @@ -327,7 +398,7 @@ namespace JSC { { double left = 0.0, right; if (v1.getNumber(left) && v2.getNumber(right)) - return jsNumber(callFrame, left + right); + return jsNumber(left + right); if (v1.isString()) { return v2.isString() @@ -341,7 +412,7 @@ namespace JSC { inline size_t normalizePrototypeChain(CallFrame* callFrame, JSValue base, JSValue slotBase, const Identifier& propertyName, size_t& slotOffset) { - JSCell* cell = asCell(base); + JSCell* cell = base.asCell(); size_t count = 0; while (slotBase != cell) { @@ -353,7 +424,7 @@ namespace JSC { if (v.isNull()) return 0; - cell = asCell(v); + cell = v.asCell(); // Since we're accessing a prototype in a loop, it's a good bet that it // should not be treated as a dictionary. @@ -378,7 +449,7 @@ namespace JSC { if (v.isNull()) return count; - base = asCell(v); + base = v.asCell(); // Since we're accessing a prototype in a loop, it's a good bet that it // should not be treated as a dictionary. @@ -389,7 +460,7 @@ namespace JSC { } } - ALWAYS_INLINE JSValue resolveBase(CallFrame* callFrame, Identifier& property, ScopeChainNode* scopeChain) + ALWAYS_INLINE JSValue resolveBase(CallFrame* callFrame, Identifier& property, ScopeChainNode* scopeChain, bool isStrictPut) { ScopeChainIterator iter = scopeChain->begin(); ScopeChainIterator next = iter; @@ -401,7 +472,9 @@ namespace JSC { JSObject* base; while (true) { base = *iter; - if (next == end || base->getPropertySlot(callFrame, property, slot)) + if (next == end) + return isStrictPut ? JSValue() : base; + if (base->getPropertySlot(callFrame, property, slot)) return base; iter = next; |
