Changeset 241230 in webkit
- Timestamp:
- Feb 8, 2019 7:56:32 PM (5 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r241228 r241230 1 2019-02-08 Keith Miller <keith_miller@apple.com> 2 3 We should only make rope strings when concatenating strings long enough. 4 https://bugs.webkit.org/show_bug.cgi?id=194465 5 6 Reviewed by Saam Barati. 7 8 This patch stops us from allocating a rope string if the resulting 9 rope would be smaller than the size of the JSRopeString object we 10 would need to allocate. 11 12 This patch also adds paths so that we don't unnecessarily allocate 13 JSString cells for primitives we are going to concatenate with a 14 string anyway. 15 16 * dfg/DFGOperations.cpp: 17 * runtime/CommonSlowPaths.cpp: 18 (JSC::SLOW_PATH_DECL): 19 * runtime/JSString.h: 20 * runtime/Operations.cpp: 21 (JSC::jsAddSlowCase): 22 * runtime/Operations.h: 23 (JSC::jsString): 24 (JSC::jsAdd): 25 1 26 2019-02-08 Saam barati <sbarati@apple.com> 2 27 -
trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp
r241222 r241230 504 504 JSValue op2 = JSValue::decode(encodedOp2); 505 505 506 ASSERT(!op1.isNumber() || !op2.isNumber()); 507 508 if (op1.isString() && !op2.isObject()) 509 return JSValue::encode(jsString(exec, asString(op1), op2.toString(exec))); 510 511 return JSValue::encode(jsAddSlowCase(exec, op1, op2)); 506 return JSValue::encode(jsAddNonNumber(exec, op1, op2)); 512 507 } 513 508 -
trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
r240254 r241230 518 518 JSValue v1 = GET_C(bytecode.m_lhs).jsValue(); 519 519 JSValue v2 = GET_C(bytecode.m_rhs).jsValue(); 520 JSValue result;521 520 522 521 ArithProfile& arithProfile = *exec->codeBlock()->arithProfileForPC(pc); 523 522 arithProfile.observeLHSAndRHS(v1, v2); 524 523 525 if (v1.isString() && !v2.isObject()) { 526 JSString* v2String = v2.toString(exec); 527 if (LIKELY(!throwScope.exception())) 528 result = jsString(exec, asString(v1), v2String); 529 } else if (v1.isNumber() && v2.isNumber()) 530 result = jsNumber(v1.asNumber() + v2.asNumber()); 531 else 532 result = jsAddSlowCase(exec, v1, v2); 524 JSValue result = jsAdd(exec, v1, v2); 533 525 534 526 RETURN_WITH_PROFILING(result, { -
trunk/Source/JavaScriptCore/runtime/JSString.h
r240965 r241230 487 487 488 488 friend JSString* jsString(ExecState*, JSString*, JSString*); 489 friend JSString* jsString(ExecState*, const String&, JSString*); 490 friend JSString* jsString(ExecState*, JSString*, const String&); 489 491 friend JSString* jsString(ExecState*, JSString*, JSString*, JSString*); 490 492 friend JSString* jsString(ExecState*, const String&, const String&, const String&); -
trunk/Source/JavaScriptCore/runtime/Operations.cpp
r238425 r241230 53 53 54 54 if (p1.isString()) { 55 JSString* p2String = p2.toString(callFrame); 55 if (p2.isCell()) { 56 JSString* p2String = p2.toString(callFrame); 57 RETURN_IF_EXCEPTION(scope, { }); 58 RELEASE_AND_RETURN(scope, jsString(callFrame, asString(p1), p2String)); 59 } 60 String p2String = p2.toWTFString(callFrame); 56 61 RETURN_IF_EXCEPTION(scope, { }); 57 62 RELEASE_AND_RETURN(scope, jsString(callFrame, asString(p1), p2String)); … … 59 64 60 65 if (p2.isString()) { 61 JSString* p1String = p1.toString(callFrame); 66 if (p2.isCell()) { 67 JSString* p1String = p1.toString(callFrame); 68 RETURN_IF_EXCEPTION(scope, { }); 69 RELEASE_AND_RETURN(scope, jsString(callFrame, p1String, asString(p2))); 70 } 71 String p1String = p1.toWTFString(callFrame); 62 72 RETURN_IF_EXCEPTION(scope, { }); 63 73 RELEASE_AND_RETURN(scope, jsString(callFrame, p1String, asString(p2))); -
trunk/Source/JavaScriptCore/runtime/Operations.h
r238425 r241230 38 38 size_t normalizePrototypeChain(CallFrame*, JSCell*, bool& sawPolyProto); 39 39 40 // This is a lower bound on the extra memory we expect to write if we were to allocate a rope instead of copying. 41 // Note, it doesn't differentiate between 8 and 16-bit strings because 16-bit strings are relatively rare. 42 constexpr unsigned minRopeStringLength = sizeof(JSRopeString); 43 44 ALWAYS_INLINE JSString* jsString(ExecState* exec, const String& u1, JSString* s2) 45 { 46 VM& vm = exec->vm(); 47 auto scope = DECLARE_THROW_SCOPE(vm); 48 49 unsigned length1 = u1.length(); 50 if (!length1) 51 return s2; 52 unsigned length2 = s2->length(); 53 if (!length2) 54 return jsString(&vm, u1); 55 56 if (length1 + length2 >= minRopeStringLength) 57 return jsString(exec, jsString(&vm, u1), s2); 58 59 const String& u2 = s2->value(exec); 60 RETURN_IF_EXCEPTION(scope, { }); 61 return JSString::create(vm, makeString(u1, u2).releaseImpl().releaseNonNull()); 62 } 63 64 ALWAYS_INLINE JSString* jsString(ExecState* exec, JSString* s1, const String& u2) 65 { 66 VM& vm = exec->vm(); 67 auto scope = DECLARE_THROW_SCOPE(vm); 68 69 unsigned length1 = s1->length(); 70 if (!length1) 71 return jsString(&vm, u2); 72 unsigned length2 = u2.length(); 73 if (!length2) 74 return s1; 75 76 if (length1 + length2 >= minRopeStringLength) 77 return jsString(exec, s1, jsString(&vm, u2)); 78 79 const String& u1 = s1->value(exec); 80 RETURN_IF_EXCEPTION(scope, { }); 81 return JSString::create(vm, makeString(u1, u2).releaseImpl().releaseNonNull()); 82 } 83 40 84 ALWAYS_INLINE JSString* jsString(ExecState* exec, JSString* s1, JSString* s2) 41 85 { … … 55 99 } 56 100 57 return JSRopeString::create(vm, s1, s2); 101 if (length1 + length2 >= minRopeStringLength) 102 return JSRopeString::create(vm, s1, s2); 103 104 const String& u1 = s1->value(exec); 105 RETURN_IF_EXCEPTION(scope, { }); 106 const String& u2 = s2->value(exec); 107 RETURN_IF_EXCEPTION(scope, { }); 108 return JSString::create(vm, makeString(u1, u2).releaseImpl().releaseNonNull()); 58 109 } 59 110 … … 80 131 return nullptr; 81 132 } 82 return JSRopeString::create(vm, s1, s2, s3); 133 134 if (length1 + length2 + length3 >= minRopeStringLength) 135 return JSRopeString::create(vm, s1, s2, s3); 136 137 const String& u1 = s1->value(exec); 138 RETURN_IF_EXCEPTION(scope, { }); 139 const String& u2 = s2->value(exec); 140 RETURN_IF_EXCEPTION(scope, { }); 141 const String& u3 = s3->value(exec); 142 RETURN_IF_EXCEPTION(scope, { }); 143 return JSString::create(vm, makeString(u1, u2, u3).releaseImpl().releaseNonNull()); 83 144 } 84 145 … … 110 171 } 111 172 112 return JSRopeString::create(*vm, jsString(vm, u1), jsString(vm, u2), jsString(vm, u3)); 173 if (length1 + length2 + length3 >= minRopeStringLength) 174 return JSRopeString::create(*vm, jsString(vm, u1), jsString(vm, u2), jsString(vm, u3)); 175 176 return JSString::create(*vm, makeString(u1, u2, u3).releaseImpl().releaseNonNull()); 113 177 } 114 178 … … 326 390 // 4000 Add case: 3 5 327 391 392 393 ALWAYS_INLINE JSValue jsAddNonNumber(CallFrame* callFrame, JSValue v1, JSValue v2) 394 { 395 VM& vm = callFrame->vm(); 396 auto scope = DECLARE_THROW_SCOPE(vm); 397 ASSERT(!v1.isNumber() || !v2.isNumber()); 398 399 if (v1.isString() && !v2.isObject()) { 400 if (v2.isString()) 401 RELEASE_AND_RETURN(scope, jsString(callFrame, asString(v1), asString(v2))); 402 String s2 = v2.toWTFString(callFrame); 403 RETURN_IF_EXCEPTION(scope, { }); 404 RELEASE_AND_RETURN(scope, jsString(callFrame, asString(v1), s2)); 405 } 406 407 // All other cases are pretty uncommon 408 RELEASE_AND_RETURN(scope, jsAddSlowCase(callFrame, v1, v2)); 409 } 410 328 411 ALWAYS_INLINE JSValue jsAdd(CallFrame* callFrame, JSValue v1, JSValue v2) 329 412 { … … 331 414 return jsNumber(v1.asNumber() + v2.asNumber()); 332 415 333 if (v1.isString() && !v2.isObject()) 334 return jsString(callFrame, asString(v1), v2.toString(callFrame)); 335 336 // All other cases are pretty uncommon 337 return jsAddSlowCase(callFrame, v1, v2); 416 return jsAddNonNumber(callFrame, v1, v2); 338 417 } 339 418
Note: See TracChangeset
for help on using the changeset viewer.