From 3ac2b5d76a91fa08ebbeab33eb89354bc6f849bd Mon Sep 17 00:00:00 2001 From: "utatane.tea@gmail.com" Date: Thu, 1 Jun 2017 05:18:25 +0000 Subject: [PATCH] [JSC] Implement String.prototype.concat in JS builtins https://bugs.webkit.org/show_bug.cgi?id=172798 Reviewed by Sam Weinig. JSTests: * microbenchmarks/string-concat-convert.js: Added. (test): * microbenchmarks/string-concat-long-convert.js: Added. (test): * microbenchmarks/string-concat-long.js: Added. (test): * microbenchmarks/string-concat.js: Added. (test): Source/JavaScriptCore: Since we have highly effective + operation for strings, implementing String.prototype.concat in JS simplifies the implementation and improves performance by using speculated types. Added microbenchmarks show performance improvement. string-concat-long-convert 1063.2787+-12.9101 ^ 109.0855+-2.8083 ^ definitely 9.7472x faster string-concat-convert 1111.1366+-12.2363 ^ 99.3402+-1.9874 ^ definitely 11.1852x faster string-concat 131.7377+-3.8359 ^ 54.3949+-0.9580 ^ definitely 2.4219x faster string-concat-long 79.4726+-1.9644 ^ 64.6301+-1.4941 ^ definitely 1.2297x faster * builtins/StringPrototype.js: (globalPrivate.stringConcatSlowPath): (concat): * runtime/StringPrototype.cpp: (JSC::StringPrototype::finishCreation): (JSC::stringProtoFuncConcat): Deleted. git-svn-id: https://svn.webkit.org/repository/webkit/trunk@217648 268f45cc-cd09-0410-ab3c-d52691b4dbfc --- JSTests/ChangeLog | 16 +++++++++++++ JSTests/microbenchmarks/string-concat-convert.js | 8 +++++++ .../microbenchmarks/string-concat-long-convert.js | 8 +++++++ JSTests/microbenchmarks/string-concat-long.js | 8 +++++++ JSTests/microbenchmarks/string-concat.js | 8 +++++++ Source/JavaScriptCore/ChangeLog | 26 ++++++++++++++++++++++ Source/JavaScriptCore/builtins/StringPrototype.js | 23 +++++++++++++++++++ Source/JavaScriptCore/runtime/StringPrototype.cpp | 22 +----------------- 8 files changed, 98 insertions(+), 21 deletions(-) create mode 100644 JSTests/microbenchmarks/string-concat-convert.js create mode 100644 JSTests/microbenchmarks/string-concat-long-convert.js create mode 100644 JSTests/microbenchmarks/string-concat-long.js create mode 100644 JSTests/microbenchmarks/string-concat.js diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog index 90fc782..f03c936 100644 --- a/JSTests/ChangeLog +++ b/JSTests/ChangeLog @@ -1,3 +1,19 @@ +2017-05-31 Yusuke Suzuki + + [JSC] Implement String.prototype.concat in JS builtins + https://bugs.webkit.org/show_bug.cgi?id=172798 + + Reviewed by Sam Weinig. + + * microbenchmarks/string-concat-convert.js: Added. + (test): + * microbenchmarks/string-concat-long-convert.js: Added. + (test): + * microbenchmarks/string-concat-long.js: Added. + (test): + * microbenchmarks/string-concat.js: Added. + (test): + 2017-05-31 Oleksandr Skachkov Rolling out: Prevent async methods named 'function' diff --git a/JSTests/microbenchmarks/string-concat-convert.js b/JSTests/microbenchmarks/string-concat-convert.js new file mode 100644 index 0000000..02d690b --- /dev/null +++ b/JSTests/microbenchmarks/string-concat-convert.js @@ -0,0 +1,8 @@ +function test(a, b, c, d, e) +{ + return a.concat(b).concat(c).concat(d).concat(e); +} +noInline(test); + +for (var i = 0; i < 1e6; ++i) + test(new String("Cocoa"), new String("Cappuccino"), new String("Matcha"), new String("Rize"), new String("Kilimanjaro")); diff --git a/JSTests/microbenchmarks/string-concat-long-convert.js b/JSTests/microbenchmarks/string-concat-long-convert.js new file mode 100644 index 0000000..44a9cf8 --- /dev/null +++ b/JSTests/microbenchmarks/string-concat-long-convert.js @@ -0,0 +1,8 @@ +function test(a, b, c, d, e) +{ + return a.concat(b, c, d, e); +} +noInline(test); + +for (var i = 0; i < 1e6; ++i) + test(new String("Cocoa"), new String("Cappuccino"), new String("Matcha"), new String("Rize"), new String("Kilimanjaro")); diff --git a/JSTests/microbenchmarks/string-concat-long.js b/JSTests/microbenchmarks/string-concat-long.js new file mode 100644 index 0000000..d805e9b --- /dev/null +++ b/JSTests/microbenchmarks/string-concat-long.js @@ -0,0 +1,8 @@ +function test(a, b, c, d, e) +{ + return a.concat(b, c, d, e); +} +noInline(test); + +for (var i = 0; i < 1e6; ++i) + test("Cocoa", "Cappuccino", "Matcha", "Rize", "Kilimanjaro"); diff --git a/JSTests/microbenchmarks/string-concat.js b/JSTests/microbenchmarks/string-concat.js new file mode 100644 index 0000000..920abdb --- /dev/null +++ b/JSTests/microbenchmarks/string-concat.js @@ -0,0 +1,8 @@ +function test(a, b, c, d, e) +{ + return a.concat(b).concat(c).concat(d).concat(e); +} +noInline(test); + +for (var i = 0; i < 1e6; ++i) + test("Cocoa", "Cappuccino", "Matcha", "Rize", "Kilimanjaro"); diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog index 3bcc7ec..604d5da 100644 --- a/Source/JavaScriptCore/ChangeLog +++ b/Source/JavaScriptCore/ChangeLog @@ -1,3 +1,29 @@ +2017-05-31 Yusuke Suzuki + + [JSC] Implement String.prototype.concat in JS builtins + https://bugs.webkit.org/show_bug.cgi?id=172798 + + Reviewed by Sam Weinig. + + Since we have highly effective + operation for strings, + implementing String.prototype.concat in JS simplifies the + implementation and improves performance by using speculated + types. + + Added microbenchmarks show performance improvement. + + string-concat-long-convert 1063.2787+-12.9101 ^ 109.0855+-2.8083 ^ definitely 9.7472x faster + string-concat-convert 1111.1366+-12.2363 ^ 99.3402+-1.9874 ^ definitely 11.1852x faster + string-concat 131.7377+-3.8359 ^ 54.3949+-0.9580 ^ definitely 2.4219x faster + string-concat-long 79.4726+-1.9644 ^ 64.6301+-1.4941 ^ definitely 1.2297x faster + + * builtins/StringPrototype.js: + (globalPrivate.stringConcatSlowPath): + (concat): + * runtime/StringPrototype.cpp: + (JSC::StringPrototype::finishCreation): + (JSC::stringProtoFuncConcat): Deleted. + 2017-05-31 Mark Lam Remove overrides of visitChildren() that do not add any functionality. diff --git a/Source/JavaScriptCore/builtins/StringPrototype.js b/Source/JavaScriptCore/builtins/StringPrototype.js index 144ed1a..68d6376a 100644 --- a/Source/JavaScriptCore/builtins/StringPrototype.js +++ b/Source/JavaScriptCore/builtins/StringPrototype.js @@ -306,6 +306,29 @@ function split(separator, limit) } @globalPrivate +function stringConcatSlowPath() +{ + "use strict"; + + var result = @toString(this); + for (var i = 0, length = arguments.length; i < length; ++i) + result += @toString(arguments[i]); + return result; +} + +function concat(arg /* ... */) +{ + "use strict"; + + if (this == null) + @throwTypeError("String.prototype.concat requires that |this| not be null or undefined"); + + if (@argumentCount() === 1) + return @toString(this) + @toString(arg); + return @tailCallForwardArguments(@stringConcatSlowPath, this); +} + +@globalPrivate function createHTML(func, string, tag, attribute, value) { "use strict"; diff --git a/Source/JavaScriptCore/runtime/StringPrototype.cpp b/Source/JavaScriptCore/runtime/StringPrototype.cpp index 46b56a2..5ab4aa7 100644 --- a/Source/JavaScriptCore/runtime/StringPrototype.cpp +++ b/Source/JavaScriptCore/runtime/StringPrototype.cpp @@ -63,7 +63,6 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncToString(ExecState*); EncodedJSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState*); EncodedJSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState*); EncodedJSValue JSC_HOST_CALL stringProtoFuncCodePointAt(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState*); EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState*); EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState*); EncodedJSValue JSC_HOST_CALL stringProtoFuncReplaceUsingRegExp(ExecState*); @@ -95,6 +94,7 @@ const ClassInfo StringPrototype::s_info = { "String", &StringObject::s_info, &st /* Source for StringConstructor.lut.h @begin stringPrototypeTable + concat JSBuiltin DontEnum|Function 1 match JSBuiltin DontEnum|Function 1 padStart JSBuiltin DontEnum|Function 1 padEnd JSBuiltin DontEnum|Function 1 @@ -134,7 +134,6 @@ void StringPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject, JSStr JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION("charAt", stringProtoFuncCharAt, DontEnum, 1, CharAtIntrinsic); JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION("charCodeAt", stringProtoFuncCharCodeAt, DontEnum, 1, CharCodeAtIntrinsic); JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("codePointAt", stringProtoFuncCodePointAt, DontEnum, 1); - JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("concat", stringProtoFuncConcat, DontEnum, 1); JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("indexOf", stringProtoFuncIndexOf, DontEnum, 1); JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("lastIndexOf", stringProtoFuncLastIndexOf, DontEnum, 1); JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().replaceUsingRegExpPrivateName(), stringProtoFuncReplaceUsingRegExp, DontEnum, 2, StringPrototypeReplaceRegExpIntrinsic); @@ -994,25 +993,6 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncCodePointAt(ExecState* exec) return JSValue::encode(jsUndefined()); } -EncodedJSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState* exec) -{ - VM& vm = exec->vm(); - auto scope = DECLARE_THROW_SCOPE(vm); - - JSValue thisValue = exec->thisValue(); - if (thisValue.isString() && exec->argumentCount() == 1) { - JSString* str = exec->uncheckedArgument(0).toString(exec); - RETURN_IF_EXCEPTION(scope, encodedJSValue()); - scope.release(); - return JSValue::encode(jsString(exec, asString(thisValue), str)); - } - - if (!checkObjectCoercible(thisValue)) - return throwVMTypeError(exec, scope); - scope.release(); - return JSValue::encode(jsStringFromArguments(exec, thisValue)); -} - EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState* exec) { VM& vm = exec->vm(); -- 1.8.3.1