Changeset 51964 in webkit for trunk/JavaScriptCore
- Timestamp:
- Dec 10, 2009, 2:13:15 PM (15 years ago)
- Location:
- trunk/JavaScriptCore
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/ChangeLog
r51955 r51964 1 2009-12-10 Gavin Barraclough <[email protected]> 2 3 Reviewed by Oliver Hunt & Mark Rowe. 4 5 https://bugs.webkit.org/show_bug.cgi?id=32367 6 Add support for short Ropes (up to 3 entries) inline within JSString. 7 (rather than externally allocating an object to hold the rope). 8 Switch jsAdd of (JSString* + JSString*) to now make use of Ropes. 9 10 ~1% progression on Sunspidey. 11 12 * interpreter/Interpreter.cpp: 13 (JSC::Interpreter::privateExecute): 14 * jit/JITOpcodes.cpp: 15 (JSC::JIT::privateCompileCTIMachineTrampolines): 16 * jit/JITStubs.cpp: 17 (JSC::DEFINE_STUB_FUNCTION): 18 * runtime/JSString.cpp: 19 (JSC::JSString::resolveRope): 20 (JSC::JSString::toBoolean): 21 (JSC::JSString::getStringPropertyDescriptor): 22 * runtime/JSString.h: 23 (JSC::JSString::Rope::Fiber::deref): 24 (JSC::JSString::Rope::Fiber::ref): 25 (JSC::JSString::Rope::Fiber::refAndGetLength): 26 (JSC::JSString::Rope::append): 27 (JSC::JSString::JSString): 28 (JSC::JSString::~JSString): 29 (JSC::JSString::value): 30 (JSC::JSString::tryGetValue): 31 (JSC::JSString::length): 32 (JSC::JSString::canGetIndex): 33 (JSC::JSString::appendStringInConstruct): 34 (JSC::JSString::appendValueInConstructAndIncrementLength): 35 (JSC::JSString::isRope): 36 (JSC::JSString::string): 37 (JSC::JSString::ropeLength): 38 (JSC::JSString::getStringPropertySlot): 39 * runtime/Operations.h: 40 (JSC::jsString): 41 (JSC::jsAdd): 42 (JSC::resolveBase): 43 1 44 2009-12-09 Anders Carlsson <[email protected]> 2 45 -
trunk/JavaScriptCore/interpreter/Interpreter.cpp
r51801 r51964 3531 3531 int count = vPC[3].u.operand; 3532 3532 3533 callFrame->r(dst) = concatenateStrings(callFrame, &callFrame->registers()[src], count);3533 callFrame->r(dst) = jsString(callFrame, &callFrame->registers()[src], count); 3534 3534 CHECK_FOR_EXCEPTION(); 3535 3535 vPC += OPCODE_LENGTH(op_strcat); -
trunk/JavaScriptCore/jit/JITOpcodes.cpp
r51765 r51964 53 53 54 54 // Checks out okay! - get the length from the Ustring. 55 load32(Address(regT0, OBJECT_OFFSETOF(JSString, m_ length)), regT2);55 load32(Address(regT0, OBJECT_OFFSETOF(JSString, m_stringLength)), regT2); 56 56 57 57 Jump string_failureCases3 = branch32(Above, regT2, Imm32(INT_MAX)); … … 1637 1637 1638 1638 // Checks out okay! - get the length from the Ustring. 1639 load32(Address(regT0, OBJECT_OFFSETOF(JSString, m_ length)), regT0);1639 load32(Address(regT0, OBJECT_OFFSETOF(JSString, m_stringLength)), regT0); 1640 1640 1641 1641 Jump string_failureCases3 = branch32(Above, regT0, Imm32(JSImmediate::maxImmediateInt)); -
trunk/JavaScriptCore/jit/JITStubs.cpp
r51801 r51964 1044 1044 bool leftIsString = v1.isString(); 1045 1045 if (leftIsString && v2.isString()) { 1046 if (asString(v1)->isRope() || asString(v2)->isRope()) { 1047 RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(2); 1048 if (UNLIKELY(!rope)) { 1049 throwOutOfMemoryError(callFrame); 1050 VM_THROW_EXCEPTION(); 1051 } 1052 rope->initializeFiber(0, asString(v1)); 1053 rope->initializeFiber(1, asString(v2)); 1054 JSGlobalData* globalData = &callFrame->globalData(); 1055 return JSValue::encode(new (globalData) JSString(globalData, rope.release())); 1056 } 1057 1058 RefPtr<UString::Rep> value = concatenate(asString(v1)->value(callFrame).rep(), asString(v2)->value(callFrame).rep()); 1059 if (UNLIKELY(!value)) { 1060 throwOutOfMemoryError(callFrame); 1061 VM_THROW_EXCEPTION(); 1062 } 1063 1064 return JSValue::encode(jsString(stackFrame.globalData, value.release())); 1046 JSValue result = jsString(callFrame, asString(v1), asString(v2)); 1047 CHECK_FOR_EXCEPTION_AT_END(); 1048 return JSValue::encode(result); 1065 1049 } 1066 1050 … … 2852 2836 STUB_INIT_STACK_FRAME(stackFrame); 2853 2837 2854 JSValue result = concatenateStrings(stackFrame.callFrame, &stackFrame.callFrame->registers()[stackFrame.args[0].int32()], stackFrame.args[1].int32());2838 JSValue result = jsString(stackFrame.callFrame, &stackFrame.callFrame->registers()[stackFrame.args[0].int32()], stackFrame.args[1].int32()); 2855 2839 CHECK_FOR_EXCEPTION_AT_END(); 2856 2840 return JSValue::encode(result); -
trunk/JavaScriptCore/runtime/JSString.cpp
r51933 r51964 97 97 // Allocate the buffer to hold the final string, position initially points to the end. 98 98 UChar* buffer; 99 if (!tryFastMalloc(m_length * sizeof(UChar)).getValue(buffer)) { 100 m_rope.clear(); 99 if (!tryFastMalloc(m_stringLength * sizeof(UChar)).getValue(buffer)) { 100 for (unsigned i = 0; i < m_ropeLength; ++i) 101 m_fibers[i].deref(); 102 m_ropeLength = 0; 101 103 ASSERT(!isRope()); 102 104 ASSERT(m_value == UString()); … … 105 107 return; 106 108 } 107 UChar* position = buffer + m_ length;109 UChar* position = buffer + m_stringLength; 108 110 109 111 // Start with the current Rope. 110 112 Vector<Rope::Fiber, 32> workQueue; 111 Rope* rope = m_rope.get(); 113 Rope::Fiber currentFiber; 114 for (unsigned i = 0; i < (m_ropeLength - 1); ++i) 115 workQueue.append(m_fibers[i]); 116 currentFiber = m_fibers[m_ropeLength - 1]; 112 117 while (true) { 113 // Copy the contents of the current rope into the workQueue, with the last item in 'currentFiber' 114 // (we will be working backwards over the rope). 115 unsigned ropeLengthMinusOne = rope->ropeLength() - 1; 116 for (unsigned i = 0; i < ropeLengthMinusOne; ++i) 117 workQueue.append(rope->fibers(i)); 118 Rope::Fiber currentFiber = rope->fibers(ropeLengthMinusOne); 119 120 // Spin backwards over the workQueue (starting with currentFiber), 121 // writing the strings into the buffer. 122 while (currentFiber.isString()) { 118 if (currentFiber.isRope()) { 119 Rope* rope = currentFiber.rope(); 120 // Copy the contents of the current rope into the workQueue, with the last item in 'currentFiber' 121 // (we will be working backwards over the rope). 122 unsigned ropeLengthMinusOne = rope->ropeLength() - 1; 123 for (unsigned i = 0; i < ropeLengthMinusOne; ++i) 124 workQueue.append(rope->fibers(i)); 125 currentFiber = rope->fibers(ropeLengthMinusOne); 126 } else { 123 127 UString::Rep* string = currentFiber.string(); 124 128 unsigned length = string->len; … … 130 134 // Create a string from the UChar buffer, clear the rope RefPtr. 131 135 ASSERT(buffer == position); 132 m_value = UString(buffer, m_length, false); 133 m_rope.clear(); 136 m_value = UString::Rep::create(buffer, m_stringLength); 137 for (unsigned i = 0; i < m_ropeLength; ++i) 138 m_fibers[i].deref(); 139 m_ropeLength = 0; 134 140 135 141 ASSERT(!isRope()); … … 141 147 workQueue.removeLast(); 142 148 } 143 144 // If we get here we fell out of the loop concatenating strings - currentFiber is a rope.145 // set the 'rope' variable, and continue around the loop.146 ASSERT(currentFiber.isRope());147 rope = currentFiber.rope();148 149 } 149 150 } … … 163 164 bool JSString::toBoolean(ExecState*) const 164 165 { 165 return m_ length;166 return m_stringLength; 166 167 } 167 168 … … 225 226 { 226 227 if (propertyName == exec->propertyNames().length) { 227 descriptor.setDescriptor(jsNumber(exec, m_ length), DontEnum | DontDelete | ReadOnly);228 descriptor.setDescriptor(jsNumber(exec, m_stringLength), DontEnum | DontDelete | ReadOnly); 228 229 return true; 229 230 } … … 231 232 bool isStrictUInt32; 232 233 unsigned i = propertyName.toStrictUInt32(&isStrictUInt32); 233 if (isStrictUInt32 && i < m_ length) {234 if (isStrictUInt32 && i < m_stringLength) { 234 235 descriptor.setDescriptor(jsSingleCharacterSubstring(exec, value(exec), i), DontDelete | ReadOnly); 235 236 return true; -
trunk/JavaScriptCore/runtime/JSString.h
r51933 r51964 76 76 Fiber(Rope* rope) : m_value(reinterpret_cast<intptr_t>(rope) | 1) {} 77 77 78 void deref() 79 { 80 if (isRope()) 81 rope()->deref(); 82 else 83 string()->deref(); 84 } 85 86 Fiber& ref() 87 { 88 if (isString()) 89 string()->ref(); 90 else 91 rope()->ref(); 92 return *this; 93 } 94 95 unsigned refAndGetLength() 96 { 97 if (isString()) { 98 UString::Rep* rep = string(); 99 return rep->ref()->len; 100 } else { 101 Rope* r = rope(); 102 r->ref(); 103 return r->stringLength(); 104 } 105 } 106 78 107 bool isRope() { return m_value & 1; } 79 108 Rope* rope() { return reinterpret_cast<Rope*>(m_value & ~1); } … … 98 127 void destructNonRecursive(); 99 128 100 void initializeFiber(unsigned index, const UString& string) 129 void append(unsigned &index, Fiber& fiber) 130 { 131 m_fibers[index++] = fiber; 132 m_stringLength += fiber.refAndGetLength(); 133 } 134 void append(unsigned &index, const UString& string) 101 135 { 102 136 UString::Rep* rep = string.rep(); 103 rep->ref(); 104 m_fibers[index] = Fiber(rep); 105 m_stringLength += rep->len; 137 m_fibers[index++] = Fiber(rep); 138 m_stringLength += rep->ref()->len; 106 139 } 107 void initializeFiber(unsigned index, Rope* rope)140 void append(unsigned& index, JSString* jsString) 108 141 { 109 rope->ref(); 110 m_fibers[index] = Fiber(rope); 111 m_stringLength += rope->stringLength(); 112 } 113 void initializeFiber(unsigned index, JSString* jsString) 114 { 115 if (jsString->isRope()) 116 initializeFiber(index, jsString->rope()); 117 else 118 initializeFiber(index, jsString->string()); 142 if (jsString->isRope()) { 143 for (unsigned i = 0; i < jsString->m_ropeLength; ++i) 144 append(index, jsString->m_fibers[i]); 145 } else 146 append(index, jsString->string()); 119 147 } 120 148 … … 134 162 JSString(JSGlobalData* globalData, const UString& value) 135 163 : JSCell(globalData->stringStructure.get()) 136 , m_ length(value.size())164 , m_stringLength(value.size()) 137 165 , m_value(value) 166 , m_ropeLength(0) 138 167 { 139 168 Heap::heap(this)->reportExtraMemoryCost(value.cost()); … … 143 172 JSString(JSGlobalData* globalData, const UString& value, HasOtherOwnerType) 144 173 : JSCell(globalData->stringStructure.get()) 145 , m_ length(value.size())174 , m_stringLength(value.size()) 146 175 , m_value(value) 176 , m_ropeLength(0) 147 177 { 148 178 } 149 179 JSString(JSGlobalData* globalData, PassRefPtr<UString::Rep> value, HasOtherOwnerType) 150 180 : JSCell(globalData->stringStructure.get()) 151 , m_ length(value->size())181 , m_stringLength(value->size()) 152 182 , m_value(value) 183 , m_ropeLength(0) 153 184 { 154 185 } 155 186 JSString(JSGlobalData* globalData, PassRefPtr<JSString::Rope> rope) 156 187 : JSCell(globalData->stringStructure.get()) 157 , m_length(rope->stringLength()) 158 , m_rope(rope) 159 { 188 , m_stringLength(rope->stringLength()) 189 , m_ropeLength(1) 190 { 191 m_fibers[0] = rope.releaseRef(); 192 } 193 // This constructor constructs a new string by concatenating s1 & s2. 194 // This should only be called with ropeLength <= 3. 195 JSString(JSGlobalData* globalData, unsigned ropeLength, JSString* s1, JSString* s2) 196 : JSCell(globalData->stringStructure.get()) 197 , m_stringLength(s1->length() + s2->length()) 198 , m_ropeLength(ropeLength) 199 { 200 ASSERT(ropeLength <= s_maxInternalRopeLength); 201 unsigned index = 0; 202 appendStringInConstruct(index, s1); 203 appendStringInConstruct(index, s2); 204 ASSERT(ropeLength == index); 205 } 206 // This constructor constructs a new string by concatenating v1, v2 & v3. 207 // This should only be called with ropeLength <= 3 ... which since every 208 // value must require a ropeLength of at least one implies that the length 209 // for each value must be exactly 1! 210 JSString(ExecState* exec, JSValue v1, JSValue v2, JSValue v3) 211 : JSCell(exec->globalData().stringStructure.get()) 212 , m_stringLength(0) 213 , m_ropeLength(s_maxInternalRopeLength) 214 { 215 unsigned index = 0; 216 appendValueInConstructAndIncrementLength(exec, index, v1); 217 appendValueInConstructAndIncrementLength(exec, index, v2); 218 appendValueInConstructAndIncrementLength(exec, index, v3); 219 ASSERT(index == s_maxInternalRopeLength); 220 } 221 222 ~JSString() 223 { 224 for (unsigned i = 0; i < m_ropeLength; ++i) 225 m_fibers[i].deref(); 160 226 } 161 227 162 228 const UString& value(ExecState* exec) const 163 229 { 164 if ( m_rope)230 if (isRope()) 165 231 resolveRope(exec); 166 232 return m_value; … … 168 234 const UString tryGetValue() const 169 235 { 170 if ( m_rope)236 if (isRope()) 171 237 UString(); 172 238 return m_value; 173 239 } 174 unsigned length() { return m_length; } 175 176 bool isRope() const { return m_rope; } 177 Rope* rope() { ASSERT(isRope()); return m_rope.get(); } 178 UString& string() { ASSERT(!isRope()); return m_value; } 240 unsigned length() { return m_stringLength; } 179 241 180 242 bool getStringPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); … … 182 244 bool getStringPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&); 183 245 184 bool canGetIndex(unsigned i) { return i < m_ length; }246 bool canGetIndex(unsigned i) { return i < m_stringLength; } 185 247 JSString* getIndex(ExecState*, unsigned); 186 248 … … 191 253 JSString(VPtrStealingHackType) 192 254 : JSCell(0) 255 , m_ropeLength(0) 193 256 { 194 257 } 195 258 196 259 void resolveRope(ExecState*) const; 260 261 void appendStringInConstruct(unsigned& index, JSString* jsString) 262 { 263 if (jsString->isRope()) { 264 for (unsigned i = 0; i < jsString->m_ropeLength; ++i) 265 m_fibers[index++] = jsString->m_fibers[i].ref(); 266 } else 267 m_fibers[index++] = Rope::Fiber(jsString->string().rep()->ref()); 268 } 269 270 void appendValueInConstructAndIncrementLength(ExecState* exec, unsigned& index, JSValue v) 271 { 272 if (v.isString()) { 273 ASSERT(asCell(v)->isString()); 274 JSString* s = static_cast<JSString*>(asCell(v)); 275 ASSERT(s->ropeLength() == 1); 276 appendStringInConstruct(index, s); 277 m_stringLength += s->length(); 278 } else { 279 UString u(v.toString(exec)); 280 m_fibers[index++] = Rope::Fiber(u.rep()->ref()); 281 m_stringLength += u.size(); 282 } 283 } 197 284 198 285 virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; … … 212 299 virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); 213 300 301 static const unsigned s_maxInternalRopeLength = 3; 302 214 303 // A string is represented either by a UString or a Rope. 215 unsigned m_ length;304 unsigned m_stringLength; 216 305 mutable UString m_value; 217 mutable RefPtr<Rope> m_rope; 306 mutable unsigned m_ropeLength; 307 mutable Rope::Fiber m_fibers[s_maxInternalRopeLength]; 308 309 bool isRope() const { return m_ropeLength; } 310 UString& string() { ASSERT(!isRope()); return m_value; } 311 unsigned ropeLength() { return m_ropeLength ? m_ropeLength : 1; } 312 313 friend JSValue jsString(ExecState* exec, JSString* s1, JSString* s2); 314 friend JSValue jsString(ExecState* exec, Register* strings, unsigned count); 218 315 }; 219 316 … … 279 376 return new (globalData) JSString(globalData, s); 280 377 } 281 378 282 379 inline JSString* jsSubstring(JSGlobalData* globalData, const UString& s, unsigned offset, unsigned length) 283 380 { … … 320 417 { 321 418 if (propertyName == exec->propertyNames().length) { 322 slot.setValue(jsNumber(exec, m_ length));419 slot.setValue(jsNumber(exec, m_stringLength)); 323 420 return true; 324 421 } … … 326 423 bool isStrictUInt32; 327 424 unsigned i = propertyName.toStrictUInt32(&isStrictUInt32); 328 if (isStrictUInt32 && i < m_ length) {425 if (isStrictUInt32 && i < m_stringLength) { 329 426 slot.setValue(jsSingleCharacterSubstring(exec, value(exec), i)); 330 427 return true; … … 336 433 ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) 337 434 { 338 if (propertyName < m_ length) {435 if (propertyName < m_stringLength) { 339 436 slot.setValue(jsSingleCharacterSubstring(exec, value(exec), propertyName)); 340 437 return true; -
trunk/JavaScriptCore/runtime/Operations.h
r51933 r51964 36 36 bool jsIsFunctionType(JSValue); 37 37 38 ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, JSString* s2) 39 { 40 unsigned ropeLength = s1->ropeLength() + s2->ropeLength(); 41 JSGlobalData* globalData = &exec->globalData(); 42 43 if (ropeLength <= JSString::s_maxInternalRopeLength) 44 return new (globalData) JSString(globalData, ropeLength, s1, s2); 45 46 unsigned index = 0; 47 RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength); 48 if (UNLIKELY(!rope)) 49 return throwOutOfMemoryError(exec); 50 rope->append(index, s1); 51 rope->append(index, s2); 52 ASSERT(index == ropeLength); 53 return new (globalData) JSString(globalData, rope.release()); 54 } 55 56 ALWAYS_INLINE JSValue jsString(ExecState* exec, Register* strings, unsigned count) 57 { 58 ASSERT(count >= 3); 59 60 unsigned ropeLength = 0; 61 for (unsigned i = 0; i < count; ++i) { 62 JSValue v = strings[i].jsValue(); 63 if (LIKELY(v.isString())) 64 ropeLength += asString(v)->ropeLength(); 65 else 66 ++ropeLength; 67 } 68 69 JSGlobalData* globalData = &exec->globalData(); 70 if (ropeLength == 3) 71 return new (globalData) JSString(exec, strings[0].jsValue(), strings[1].jsValue(), strings[2].jsValue()); 72 73 RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength); 74 if (UNLIKELY(!rope)) 75 return throwOutOfMemoryError(exec); 76 77 unsigned index = 0; 78 for (unsigned i = 0; i < count; ++i) { 79 JSValue v = strings[i].jsValue(); 80 if (LIKELY(v.isString())) 81 rope->append(index, asString(v)); 82 else 83 rope->append(index, v.toString(exec)); 84 } 85 86 ASSERT(index == ropeLength); 87 return new (globalData) JSString(globalData, rope.release()); 88 } 89 38 90 // ECMA 11.9.3 39 91 inline bool JSValue::equal(ExecState* exec, JSValue v1, JSValue v2) … … 205 257 bool leftIsString = v1.isString(); 206 258 if (leftIsString && v2.isString()) { 207 if (asString(v1)->isRope() || asString(v2)->isRope()) { 208 RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(2); 209 if (UNLIKELY(!rope)) 210 return throwOutOfMemoryError(callFrame); 211 rope->initializeFiber(0, asString(v1)); 212 rope->initializeFiber(1, asString(v2)); 213 JSGlobalData* globalData = &callFrame->globalData(); 214 return new (globalData) JSString(globalData, rope.release()); 215 } 216 217 RefPtr<UString::Rep> value = concatenate(asString(v1)->value(callFrame).rep(), asString(v2)->value(callFrame).rep()); 218 if (!value) 219 return throwOutOfMemoryError(callFrame); 220 return jsString(callFrame, value.release()); 259 if (!asString(v1)->length()) 260 return asString(v2); 261 if (!asString(v2)->length()) 262 return asString(v1); 263 return jsString(callFrame, asString(v1), asString(v2)); 221 264 } 222 265 … … 304 347 return JSValue(); 305 348 } 306 307 ALWAYS_INLINE JSValue concatenateStrings(CallFrame* callFrame, Register* strings, unsigned count)308 {309 ASSERT(count >= 3);310 311 RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(count);312 if (UNLIKELY(!rope))313 return throwOutOfMemoryError(callFrame);314 315 for (unsigned i = 0; i < count; ++i) {316 JSValue v = strings[i].jsValue();317 if (LIKELY(v.isString()))318 rope->initializeFiber(i, asString(v));319 else320 rope->initializeFiber(i, v.toString(callFrame));321 }322 323 JSGlobalData* globalData = &callFrame->globalData();324 return new (globalData) JSString(globalData, rope.release());325 }326 349 } // namespace JSC 327 350
Note:
See TracChangeset
for help on using the changeset viewer.