}
}
+
+function repeatCharactersSlowPath(string, count)
+{
+ "use strict";
+ var repeatCount = (count / string.length) | 0;
+ var remainingCharacters = count - repeatCount * string.length;
+ var result = "";
+ var operand = string;
+ // Bit operation onto |repeatCount| is safe because |repeatCount| should be within Int32 range,
+ // Repeat log N times to generate the repeated string rope.
+ while (true) {
+ if (repeatCount & 1)
+ result += operand;
+ repeatCount >>= 1;
+ if (!repeatCount)
+ break;
+ operand += operand;
+ }
+ if (remainingCharacters)
+ result += @stringSubstrInternal.@call(string, 0, remainingCharacters);
+ return result;
+}
+
+
function repeat(count)
{
"use strict";
return @repeatSlowPath(string, count);
}
+function padStart(maxLength/*, fillString*/)
+{
+ "use strict";
+
+ if (this === null)
+ throw new @TypeError("String.prototype.padStart requires that |this| not be null");
+
+ if (this === @undefined)
+ throw new @TypeError("String.prototype.padStart requires that |this| not be undefined");
+
+ var string = @toString(this);
+ maxLength = @toLength(maxLength);
+ var fillString = arguments[1];
+
+ var stringLength = string.length;
+ if (maxLength <= stringLength)
+ return string;
+
+ var filler;
+ if (arguments[1] === @undefined)
+ filler = " ";
+ else {
+ filler = @toString(arguments[1]);
+ if (filler === "")
+ return string;
+ }
+
+ var fillLength = maxLength - stringLength;
+ var truncatedStringFiller;
+
+ if (filler.length === 1)
+ truncatedStringFiller = @repeatCharacter(filler, fillLength);
+ else
+ truncatedStringFiller = @repeatCharactersSlowPath(filler, fillLength);
+ return truncatedStringFiller + string;
+}
+
+function padEnd(maxLength/*, fillString*/)
+{
+ "use strict";
+
+ if (this === null)
+ throw new @TypeError("String.prototype.padEnd requires that |this| not be null");
+
+ if (this === @undefined)
+ throw new @TypeError("String.prototype.padEnd requires that |this| not be undefined");
+
+ var string = @toString(this);
+ maxLength = @toLength(maxLength);
+
+ var stringLength = string.length;
+ if (maxLength <= stringLength)
+ return string;
+
+ var filler;
+ if (arguments[1] === @undefined)
+ filler = " ";
+ else {
+ filler = @toString(arguments[1]);
+ if (filler === "")
+ return string;
+ }
+
+ var fillLength = maxLength - stringLength;
+ var truncatedStringFiller;
+
+ if (filler.length === 1)
+ truncatedStringFiller = @repeatCharacter(filler, fillLength);
+ else
+ truncatedStringFiller = @repeatCharactersSlowPath(filler, fillLength);
+ return string + truncatedStringFiller;
+}
+
function hasObservableSideEffectsForStringReplace(regexp, replacer) {
if (replacer !== @regExpPrototypeSymbolReplace)
return true;
EncodedJSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState*);
EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState*);
EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState*);
-EncodedJSValue JSC_HOST_CALL stringProtoFuncPadEnd(ExecState*);
-EncodedJSValue JSC_HOST_CALL stringProtoFuncPadStart(ExecState*);
EncodedJSValue JSC_HOST_CALL stringProtoFuncReplaceUsingRegExp(ExecState*);
EncodedJSValue JSC_HOST_CALL stringProtoFuncReplaceUsingStringSearch(ExecState*);
EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState*);
/* Source for StringConstructor.lut.h
@begin stringPrototypeTable
match JSBuiltin DontEnum|Function 1
+ padStart JSBuiltin DontEnum|Function 1
+ padEnd JSBuiltin DontEnum|Function 1
repeat JSBuiltin DontEnum|Function 1
replace JSBuiltin DontEnum|Function 2
search JSBuiltin DontEnum|Function 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_FUNCTION_WITHOUT_TRANSITION("padEnd", stringProtoFuncPadEnd, DontEnum, 1);
- JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("padStart", stringProtoFuncPadStart, DontEnum, 1);
JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->replaceUsingRegExpPrivateName, stringProtoFuncReplaceUsingRegExp, DontEnum, 2, StringPrototypeReplaceRegExpIntrinsic);
JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->replaceUsingStringSearchPrivateName, stringProtoFuncReplaceUsingStringSearch, DontEnum, 2);
JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("slice", stringProtoFuncSlice, DontEnum, 2);
return JSValue::encode(repeatCharacter(*exec, character, repeatCount));
}
-static inline bool repeatStringPattern(ExecState& exec, unsigned maxLength, JSString* string, JSRopeString::RopeBuilder& ropeBuilder)
-{
- unsigned repeatCount = maxLength / string->length();
- unsigned remainingCharacters = maxLength - repeatCount * string->length();
- for (unsigned i = 0; i < repeatCount; ++i) {
- if (!ropeBuilder.append(string)) {
- throwOutOfMemoryError(&exec);
- return false;
- }
- }
- if (remainingCharacters) {
- JSString* substr = jsSubstring(&exec, string, 0, remainingCharacters);
- if (!substr || !ropeBuilder.append(substr)) {
- throwOutOfMemoryError(&exec);
- return false;
- }
- }
- return true;
-}
-
-enum class StringPaddingLocation { Start, End };
-
-static EncodedJSValue padString(ExecState& exec, StringPaddingLocation paddingLocation)
-{
- JSValue thisValue = exec.thisValue();
- if (!thisValue.requireObjectCoercible(&exec))
- return JSValue::encode(jsUndefined());
- JSString* thisString = thisValue.toString(&exec);
- if (exec.hadException())
- return JSValue::encode(jsUndefined());
-
- double maxLengthAsDouble = exec.argument(0).toLength(&exec);
- if (exec.hadException())
- return JSValue::encode(jsUndefined());
- ASSERT(maxLengthAsDouble >= 0.0);
- ASSERT(maxLengthAsDouble == std::trunc(maxLengthAsDouble));
-
- if (maxLengthAsDouble <= thisString->length())
- return JSValue::encode(thisString);
-
- if (maxLengthAsDouble > JSString::MaxLength)
- return JSValue::encode(throwOutOfMemoryError(&exec));
-
- unsigned maxLength = static_cast<unsigned>(maxLengthAsDouble);
-
- JSValue fillString = exec.argument(1);
- JSString* filler = nullptr;
- if (!fillString.isUndefined()) {
- filler = fillString.toString(&exec);
- if (!filler)
- return JSValue::encode(jsUndefined());
- if (!filler->length())
- return JSValue::encode(thisString);
- }
-
- unsigned fillLength = static_cast<unsigned>(maxLength) - thisString->length();
-
- JSRopeString::RopeBuilder ropeBuilder(exec.vm());
- if (paddingLocation == StringPaddingLocation::End) {
- if (!ropeBuilder.append(thisString))
- return JSValue::encode(throwOutOfMemoryError(&exec));
- }
-
- if (!filler || filler->length() == 1) {
- UChar character = filler && filler->length() ? filler->view(&exec)[0] : ' ';
- if (!(character & ~0xff))
- filler = repeatCharacter(exec, static_cast<LChar>(character), fillLength);
- else
- filler = repeatCharacter(exec, character, fillLength);
- if (!filler || !ropeBuilder.append(filler))
- return JSValue::encode(throwOutOfMemoryError(&exec));
- ASSERT(filler->length() == fillLength);
- } else {
- if (!repeatStringPattern(exec, fillLength, filler, ropeBuilder))
- return JSValue::encode(throwOutOfMemoryError(&exec));
- }
-
- if (paddingLocation == StringPaddingLocation::Start) {
- if (!ropeBuilder.append(thisString))
- return JSValue::encode(throwOutOfMemoryError(&exec));
- }
- ASSERT(!exec.hadException());
- return JSValue::encode(ropeBuilder.release());
-}
-
-EncodedJSValue JSC_HOST_CALL stringProtoFuncPadEnd(ExecState* exec)
-{
- return padString(*exec, StringPaddingLocation::End);
-}
-
-EncodedJSValue JSC_HOST_CALL stringProtoFuncPadStart(ExecState* exec)
-{
- return padString(*exec, StringPaddingLocation::Start);
-}
-
ALWAYS_INLINE EncodedJSValue replace(
VM& vm, ExecState* exec, JSString* string, JSValue searchValue, JSValue replaceValue)
{