зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset 2e9f81c5d00c (bug 1052839
) for ggc bustage
This commit is contained in:
Родитель
eb4b088d8d
Коммит
7e2b2f67ef
|
@ -4,126 +4,6 @@
|
|||
|
||||
/*global intl_Collator: false, */
|
||||
|
||||
/* ES6 Draft Oct 14, 2014 21.1.3.19 */
|
||||
function String_substring(start, end) {
|
||||
// Steps 1-3.
|
||||
CheckObjectCoercible(this);
|
||||
var str = ToString(this);
|
||||
|
||||
// Step 4.
|
||||
var len = str.length;
|
||||
|
||||
// Step 5.
|
||||
var intStart = ToInteger(start);
|
||||
|
||||
// Step 6.
|
||||
var intEnd = (end === undefined) ? len : ToInteger(end);
|
||||
|
||||
// Step 7.
|
||||
var finalStart = std_Math_min(std_Math_max(intStart, 0), len);
|
||||
|
||||
// Step 8.
|
||||
var finalEnd = std_Math_min(std_Math_max(intEnd, 0), len);
|
||||
|
||||
// Steps 9-10.
|
||||
var from, to;
|
||||
if (finalStart < finalEnd) {
|
||||
from = finalStart;
|
||||
to = finalEnd;
|
||||
} else {
|
||||
from = finalEnd;
|
||||
to = finalStart;
|
||||
}
|
||||
|
||||
// Step 11.
|
||||
// While |from| and |to - from| are bounded to the length of |str| and this
|
||||
// and thus definitely in the int32 range, they can still be typed as
|
||||
// double. Eagerly truncate since SubstringKernel only accepts int32.
|
||||
return SubstringKernel(str, from | 0, (to - from) | 0);
|
||||
}
|
||||
|
||||
function String_static_substring(string, start, end) {
|
||||
if (arguments.length < 1)
|
||||
ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'String.substring');
|
||||
return callFunction(String_substring, string, start, end);
|
||||
}
|
||||
|
||||
/* ES6 Draft Oct 14, 2014 B.2.3.1 */
|
||||
function String_substr(start, length) {
|
||||
// Steps 1-2.
|
||||
CheckObjectCoercible(this);
|
||||
var str = ToString(this);
|
||||
|
||||
// Steps 3-4.
|
||||
var intStart = ToInteger(start);
|
||||
|
||||
// Steps 5-7.
|
||||
var size = str.length;
|
||||
// Use |size| instead of +Infinity to avoid performing calculations with
|
||||
// doubles. (The result is the same either way.)
|
||||
var end = (length === undefined) ? size : ToInteger(length);
|
||||
|
||||
// Step 8.
|
||||
if (intStart < 0)
|
||||
intStart = std_Math_max(intStart + size, 0);
|
||||
|
||||
// Step 9.
|
||||
var resultLength = std_Math_min(std_Math_max(end, 0), size - intStart)
|
||||
|
||||
// Step 10.
|
||||
if (resultLength <= 0)
|
||||
return "";
|
||||
|
||||
// Step 11.
|
||||
// While |intStart| and |resultLength| are bounded to the length of |str|
|
||||
// and thus definitely in the int32 range, they can still be typed as
|
||||
// double. Eagerly truncate since SubstringKernel only accepts int32.
|
||||
return SubstringKernel(str, intStart | 0, resultLength | 0);
|
||||
}
|
||||
|
||||
function String_static_substr(string, start, length) {
|
||||
if (arguments.length < 1)
|
||||
ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'String.substr');
|
||||
return callFunction(String_substr, string, start, length);
|
||||
}
|
||||
|
||||
/* ES6 Draft Oct 14, 2014 21.1.3.16 */
|
||||
function String_slice(start, end) {
|
||||
// Steps 1-3.
|
||||
CheckObjectCoercible(this);
|
||||
var str = ToString(this);
|
||||
|
||||
// Step 4.
|
||||
var len = str.length;
|
||||
|
||||
// Step 5.
|
||||
var intStart = ToInteger(start);
|
||||
|
||||
// Step 6.
|
||||
var intEnd = (end === undefined) ? len : ToInteger(end);
|
||||
|
||||
// Step 7.
|
||||
var from = (intStart < 0) ? std_Math_max(len + intStart, 0) : std_Math_min(intStart, len);
|
||||
|
||||
// Step 8.
|
||||
var to = (intEnd < 0) ? std_Math_max(len + intEnd, 0) : std_Math_min(intEnd, len);
|
||||
|
||||
// Step 9.
|
||||
var span = std_Math_max(to - from, 0);
|
||||
|
||||
// Step 10.
|
||||
// While |from| and |span| are bounded to the length of |str|
|
||||
// and thus definitely in the int32 range, they can still be typed as
|
||||
// double. Eagerly truncate since SubstringKernel only accepts int32.
|
||||
return SubstringKernel(str, from | 0, span | 0);
|
||||
}
|
||||
|
||||
function String_static_slice(string, start, end) {
|
||||
if (arguments.length < 1)
|
||||
ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'String.slice');
|
||||
return callFunction(String_slice, string, start, end);
|
||||
}
|
||||
|
||||
/* ES6 Draft September 5, 2013 21.1.3.3 */
|
||||
function String_codePointAt(pos) {
|
||||
// Steps 1-3.
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
// The few items below here are either self-hosted or installing them under a
|
||||
// std_Foo name would require ugly contortions, so they just get aliased here.
|
||||
var std_Array_indexOf = ArrayIndexOf;
|
||||
var std_String_substring = String_substring;
|
||||
// WeakMap is a bare constructor without properties or methods.
|
||||
var std_WeakMap = WeakMap;
|
||||
// StopIteration is a bare constructor without properties or methods.
|
||||
|
|
|
@ -6011,110 +6011,6 @@ ConcatFatInlineString(MacroAssembler &masm, Register lhs, Register rhs, Register
|
|||
masm.ret();
|
||||
}
|
||||
|
||||
typedef JSString *(*SubstringKernelFn)(JSContext *cx, HandleString str, int32_t begin, int32_t len);
|
||||
static const VMFunction SubstringKernelInfo =
|
||||
FunctionInfo<SubstringKernelFn>(SubstringKernel);
|
||||
|
||||
bool CodeGenerator::visitSubstr(LSubstr *lir)
|
||||
{
|
||||
Register string = ToRegister(lir->string());
|
||||
Register begin = ToRegister(lir->begin());
|
||||
Register length = ToRegister(lir->length());
|
||||
Register output = ToRegister(lir->output());
|
||||
Register temp = ToRegister(lir->temp());
|
||||
Address stringFlags(string, JSString::offsetOfFlags());
|
||||
|
||||
Label isLatin1, notInline, nonZero, isInlinedLatin1;
|
||||
|
||||
// For every edge case use the C++ variant.
|
||||
// Note: we also use this upon allocation failure in newGCString and
|
||||
// newGCFatInlineString. To squeeze out even more performance those failures
|
||||
// can be handled by allocate in ool code and returning to jit code to fill
|
||||
// in all data.
|
||||
OutOfLineCode *ool = oolCallVM(SubstringKernelInfo, lir,
|
||||
(ArgList(), string, begin, length),
|
||||
StoreRegisterTo(output));
|
||||
if (!ool)
|
||||
return false;
|
||||
Label *slowPath = ool->entry();
|
||||
Label *done = ool->rejoin();
|
||||
|
||||
// Zero length, return emptystring.
|
||||
masm.branchTest32(Assembler::NonZero, length, length, &nonZero);
|
||||
const JSAtomState &names = GetIonContext()->runtime->names();
|
||||
masm.movePtr(ImmGCPtr(names.empty), output);
|
||||
masm.jump(done);
|
||||
|
||||
// Use slow path for ropes.
|
||||
masm.bind(&nonZero);
|
||||
static_assert(JSString::ROPE_FLAGS == 0,
|
||||
"rope flags must be zero for (flags & TYPE_FLAGS_MASK) == 0 "
|
||||
"to be a valid is-rope check");
|
||||
masm.branchTest32(Assembler::Zero, stringFlags, Imm32(JSString::TYPE_FLAGS_MASK), slowPath);
|
||||
|
||||
// Handle inlined strings by creating a FatInlineString.
|
||||
masm.branchTest32(Assembler::Zero, stringFlags, Imm32(JSString::INLINE_CHARS_BIT), ¬Inline);
|
||||
masm.newGCFatInlineString(output, temp, slowPath);
|
||||
masm.store32(length, Address(output, JSString::offsetOfLength()));
|
||||
Address stringStorage(string, JSInlineString::offsetOfInlineStorage());
|
||||
Address outputStorage(output, JSInlineString::offsetOfInlineStorage());
|
||||
|
||||
masm.branchTest32(Assembler::NonZero, stringFlags, Imm32(JSString::LATIN1_CHARS_BIT),
|
||||
&isInlinedLatin1);
|
||||
{
|
||||
masm.store32(Imm32(JSString::INIT_FAT_INLINE_FLAGS),
|
||||
Address(output, JSString::offsetOfFlags()));
|
||||
masm.computeEffectiveAddress(stringStorage, temp);
|
||||
BaseIndex chars(temp, begin, ScaleFromElemWidth(sizeof(char16_t)));
|
||||
masm.computeEffectiveAddress(chars, begin);
|
||||
masm.computeEffectiveAddress(outputStorage, temp);
|
||||
CopyStringChars(masm, temp, begin, length, string, sizeof(char16_t), sizeof(char16_t));
|
||||
masm.store16(Imm32(0), Address(temp, 0));
|
||||
masm.jump(done);
|
||||
}
|
||||
masm.bind(&isInlinedLatin1);
|
||||
{
|
||||
masm.store32(Imm32(JSString::INIT_FAT_INLINE_FLAGS | JSString::LATIN1_CHARS_BIT),
|
||||
Address(output, JSString::offsetOfFlags()));
|
||||
masm.computeEffectiveAddress(stringStorage, temp);
|
||||
static_assert(sizeof(char) == 1, "begin index shouldn't need scaling");
|
||||
masm.addPtr(temp, begin);
|
||||
masm.computeEffectiveAddress(outputStorage, temp);
|
||||
CopyStringChars(masm, temp, begin, length, string, sizeof(char), sizeof(char));
|
||||
masm.store8(Imm32(0), Address(temp, 0));
|
||||
masm.jump(done);
|
||||
}
|
||||
|
||||
// Handle other cases with a DependentString.
|
||||
masm.bind(¬Inline);
|
||||
masm.newGCString(output, temp, slowPath);
|
||||
masm.store32(length, Address(output, JSString::offsetOfLength()));
|
||||
masm.storePtr(string, Address(output, JSDependentString::offsetOfBase()));
|
||||
|
||||
masm.branchTest32(Assembler::NonZero, stringFlags, Imm32(JSString::LATIN1_CHARS_BIT), &isLatin1);
|
||||
{
|
||||
masm.store32(Imm32(JSString::DEPENDENT_FLAGS), Address(output, JSString::offsetOfFlags()));
|
||||
masm.loadPtr(Address(string, JSString::offsetOfNonInlineChars()), temp);
|
||||
BaseIndex chars(temp, begin, ScaleFromElemWidth(sizeof(char16_t)));
|
||||
masm.computeEffectiveAddress(chars, temp);
|
||||
masm.storePtr(temp, Address(output, JSString::offsetOfNonInlineChars()));
|
||||
masm.jump(done);
|
||||
}
|
||||
masm.bind(&isLatin1);
|
||||
{
|
||||
masm.store32(Imm32(JSString::DEPENDENT_FLAGS | JSString::LATIN1_CHARS_BIT),
|
||||
Address(output, JSString::offsetOfFlags()));
|
||||
masm.loadPtr(Address(string, JSString::offsetOfNonInlineChars()), temp);
|
||||
static_assert(sizeof(char) == 1, "begin index shouldn't need scaling");
|
||||
masm.addPtr(begin, temp);
|
||||
masm.storePtr(temp, Address(output, JSString::offsetOfNonInlineChars()));
|
||||
masm.jump(done);
|
||||
}
|
||||
|
||||
masm.bind(done);
|
||||
return true;
|
||||
}
|
||||
|
||||
JitCode *
|
||||
JitCompartment::generateStringConcatStub(JSContext *cx, ExecutionMode mode)
|
||||
{
|
||||
|
|
|
@ -188,7 +188,6 @@ class CodeGenerator : public CodeGeneratorSpecific
|
|||
bool visitTypedObjectProto(LTypedObjectProto *ins);
|
||||
bool visitTypedObjectUnsizedLength(LTypedObjectUnsizedLength *ins);
|
||||
bool visitStringLength(LStringLength *lir);
|
||||
bool visitSubstr(LSubstr *lir);
|
||||
bool visitInitializedLength(LInitializedLength *lir);
|
||||
bool visitSetInitializedLength(LSetInitializedLength *lir);
|
||||
bool visitNotO(LNotO *ins);
|
||||
|
|
|
@ -781,7 +781,6 @@ class IonBuilder
|
|||
const Class *clasp3 = nullptr,
|
||||
const Class *clasp4 = nullptr);
|
||||
InliningStatus inlineIsConstructing(CallInfo &callInfo);
|
||||
InliningStatus inlineSubstringKernel(CallInfo &callInfo);
|
||||
|
||||
// Testing functions.
|
||||
InliningStatus inlineForceSequentialOrInParallelSection(CallInfo &callInfo);
|
||||
|
|
|
@ -3410,36 +3410,6 @@ class LStringSplit : public LCallInstructionHelper<1, 2, 0>
|
|||
}
|
||||
};
|
||||
|
||||
class LSubstr : public LInstructionHelper<1, 3, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(Substr)
|
||||
|
||||
LSubstr(const LAllocation &string, const LAllocation &begin, const LAllocation &length,
|
||||
const LDefinition &temp)
|
||||
{
|
||||
setOperand(0, string);
|
||||
setOperand(1, begin);
|
||||
setOperand(2, length);
|
||||
setTemp(0, temp);
|
||||
}
|
||||
const LAllocation *string() {
|
||||
return getOperand(0);
|
||||
}
|
||||
const LAllocation *begin() {
|
||||
return getOperand(1);
|
||||
}
|
||||
const LAllocation *length() {
|
||||
return getOperand(2);
|
||||
}
|
||||
const LDefinition *temp() {
|
||||
return getTemp(0);
|
||||
}
|
||||
const MStringSplit *mir() const {
|
||||
return mir_->toStringSplit();
|
||||
}
|
||||
};
|
||||
|
||||
// Convert a 32-bit integer to a double.
|
||||
class LInt32ToDouble : public LInstructionHelper<1, 1, 0>
|
||||
{
|
||||
|
|
|
@ -187,7 +187,6 @@
|
|||
_(RegExpTest) \
|
||||
_(RegExpReplace) \
|
||||
_(StringReplace) \
|
||||
_(Substr) \
|
||||
_(Lambda) \
|
||||
_(LambdaArrow) \
|
||||
_(LambdaForSingleton) \
|
||||
|
|
|
@ -2171,16 +2171,6 @@ LIRGenerator::visitStringReplace(MStringReplace *ins)
|
|||
return defineReturn(lir, ins) && assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGenerator::visitSubstr(MSubstr *ins)
|
||||
{
|
||||
LSubstr *lir = new (alloc()) LSubstr(useFixed(ins->string(), CallTempReg1),
|
||||
useRegister(ins->begin()),
|
||||
useRegister(ins->length()),
|
||||
temp());
|
||||
return define(lir, ins) && assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGenerator::visitLambda(MLambda *ins)
|
||||
{
|
||||
|
|
|
@ -145,7 +145,6 @@ class LIRGenerator : public LIRGeneratorSpecific
|
|||
bool visitCharCodeAt(MCharCodeAt *ins);
|
||||
bool visitFromCharCode(MFromCharCode *ins);
|
||||
bool visitStringSplit(MStringSplit *ins);
|
||||
bool visitSubstr(MSubstr *ins);
|
||||
bool visitStart(MStart *start);
|
||||
bool visitOsrEntry(MOsrEntry *entry);
|
||||
bool visitNop(MNop *nop);
|
||||
|
|
|
@ -197,8 +197,6 @@ IonBuilder::inlineNativeCall(CallInfo &callInfo, JSFunction *target)
|
|||
return inlineToString(callInfo);
|
||||
if (native == intrinsic_IsConstructing)
|
||||
return inlineIsConstructing(callInfo);
|
||||
if (native == intrinsic_SubstringKernel)
|
||||
return inlineSubstringKernel(callInfo);
|
||||
|
||||
// TypedObject intrinsics.
|
||||
if (native == intrinsic_ObjectIsTypedObject)
|
||||
|
@ -1552,38 +1550,6 @@ IonBuilder::inlineStrReplace(CallInfo &callInfo)
|
|||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineSubstringKernel(CallInfo &callInfo)
|
||||
{
|
||||
MOZ_ASSERT(callInfo.argc() == 3);
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
|
||||
// Return: String.
|
||||
if (getInlineReturnType() != MIRType_String)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
// Arg 0: String.
|
||||
if (callInfo.getArg(0)->type() != MIRType_String)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
// Arg 1: Int.
|
||||
if (callInfo.getArg(1)->type() != MIRType_Int32)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
// Arg 2: Int.
|
||||
if (callInfo.getArg(2)->type() != MIRType_Int32)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
|
||||
MSubstr *substr = MSubstr::New(alloc(), callInfo.getArg(0), callInfo.getArg(1),
|
||||
callInfo.getArg(2));
|
||||
current->add(substr);
|
||||
current->push(substr);
|
||||
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineUnsafePutElements(CallInfo &callInfo)
|
||||
{
|
||||
|
|
|
@ -6925,47 +6925,6 @@ class MStringReplace
|
|||
}
|
||||
};
|
||||
|
||||
class MSubstr
|
||||
: public MTernaryInstruction,
|
||||
public Mix3Policy<StringPolicy<0>, IntPolicy<1>, IntPolicy<2>>
|
||||
{
|
||||
private:
|
||||
|
||||
MSubstr(MDefinition *string, MDefinition *begin, MDefinition *length)
|
||||
: MTernaryInstruction(string, begin, length)
|
||||
{
|
||||
setResultType(MIRType_String);
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(Substr);
|
||||
|
||||
static MSubstr *New(TempAllocator &alloc, MDefinition *string, MDefinition *begin,
|
||||
MDefinition *length)
|
||||
{
|
||||
return new(alloc) MSubstr(string, begin, length);
|
||||
}
|
||||
|
||||
MDefinition *string() {
|
||||
return getOperand(0);
|
||||
}
|
||||
|
||||
MDefinition *begin() {
|
||||
return getOperand(1);
|
||||
}
|
||||
|
||||
MDefinition *length() {
|
||||
return getOperand(2);
|
||||
}
|
||||
|
||||
bool congruentTo(const MDefinition *ins) const {
|
||||
return congruentIfOperandsEqual(ins);
|
||||
}
|
||||
AliasSet getAliasSet() const {
|
||||
return AliasSet::None();
|
||||
}
|
||||
};
|
||||
|
||||
struct LambdaFunctionInfo
|
||||
{
|
||||
// The functions used in lambdas are the canonical original function in
|
||||
|
|
|
@ -95,7 +95,6 @@ namespace jit {
|
|||
_(CharCodeAt) \
|
||||
_(FromCharCode) \
|
||||
_(StringSplit) \
|
||||
_(Substr) \
|
||||
_(Return) \
|
||||
_(Throw) \
|
||||
_(Box) \
|
||||
|
|
|
@ -324,7 +324,6 @@ class ParallelSafetyVisitor : public MDefinitionVisitor
|
|||
UNSAFE_OP(CallInstanceOf)
|
||||
UNSAFE_OP(ProfilerStackOp)
|
||||
UNSAFE_OP(GuardString)
|
||||
UNSAFE_OP(Substr)
|
||||
UNSAFE_OP(NewDeclEnvObject)
|
||||
UNSAFE_OP(In)
|
||||
UNSAFE_OP(InArray)
|
||||
|
|
|
@ -977,7 +977,6 @@ bool intrinsic_IsCallable(JSContext *cx, unsigned argc, Value *vp);
|
|||
bool intrinsic_ThrowError(JSContext *cx, unsigned argc, Value *vp);
|
||||
bool intrinsic_NewDenseArray(JSContext *cx, unsigned argc, Value *vp);
|
||||
bool intrinsic_IsConstructing(JSContext *cx, unsigned argc, Value *vp);
|
||||
bool intrinsic_SubstringKernel(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
bool intrinsic_UnsafePutElements(JSContext *cx, unsigned argc, Value *vp);
|
||||
bool intrinsic_DefineDataProperty(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
|
211
js/src/jsstr.cpp
211
js/src/jsstr.cpp
|
@ -575,17 +575,9 @@ ValueToIntegerRange(JSContext *cx, HandleValue v, int32_t *out)
|
|||
return true;
|
||||
}
|
||||
|
||||
JSString *
|
||||
js::SubstringKernel(JSContext *cx, HandleString str, int32_t beginInt, int32_t lengthInt)
|
||||
static JSString *
|
||||
DoSubstr(JSContext *cx, JSString *str, size_t begin, size_t len)
|
||||
{
|
||||
MOZ_ASSERT(0 <= beginInt);
|
||||
MOZ_ASSERT(0 <= lengthInt);
|
||||
MOZ_ASSERT(beginInt <= str->length());
|
||||
MOZ_ASSERT(lengthInt <= str->length() - beginInt);
|
||||
|
||||
uint32_t begin = beginInt;
|
||||
uint32_t len = lengthInt;
|
||||
|
||||
/*
|
||||
* Optimization for one level deep ropes.
|
||||
* This is common for the following pattern:
|
||||
|
@ -599,13 +591,16 @@ js::SubstringKernel(JSContext *cx, HandleString str, int32_t beginInt, int32_t l
|
|||
JSRope *rope = &str->asRope();
|
||||
|
||||
/* Substring is totally in leftChild of rope. */
|
||||
if (begin + len <= rope->leftChild()->length())
|
||||
return NewDependentString(cx, rope->leftChild(), begin, len);
|
||||
if (begin + len <= rope->leftChild()->length()) {
|
||||
str = rope->leftChild();
|
||||
return NewDependentString(cx, str, begin, len);
|
||||
}
|
||||
|
||||
/* Substring is totally in rightChild of rope. */
|
||||
if (begin >= rope->leftChild()->length()) {
|
||||
str = rope->rightChild();
|
||||
begin -= rope->leftChild()->length();
|
||||
return NewDependentString(cx, rope->rightChild(), begin, len);
|
||||
return NewDependentString(cx, str, begin, len);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -633,6 +628,65 @@ js::SubstringKernel(JSContext *cx, HandleString str, int32_t beginInt, int32_t l
|
|||
return NewDependentString(cx, str, begin, len);
|
||||
}
|
||||
|
||||
bool
|
||||
js::str_substring(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
JSString *str = ThisToStringForStringProto(cx, args);
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
int32_t length, begin, end;
|
||||
if (args.length() > 0) {
|
||||
end = length = int32_t(str->length());
|
||||
|
||||
if (args[0].isInt32()) {
|
||||
begin = args[0].toInt32();
|
||||
} else {
|
||||
RootedString strRoot(cx, str);
|
||||
if (!ValueToIntegerRange(cx, args[0], &begin))
|
||||
return false;
|
||||
str = strRoot;
|
||||
}
|
||||
|
||||
if (begin < 0)
|
||||
begin = 0;
|
||||
else if (begin > length)
|
||||
begin = length;
|
||||
|
||||
if (args.hasDefined(1)) {
|
||||
if (args[1].isInt32()) {
|
||||
end = args[1].toInt32();
|
||||
} else {
|
||||
RootedString strRoot(cx, str);
|
||||
if (!ValueToIntegerRange(cx, args[1], &end))
|
||||
return false;
|
||||
str = strRoot;
|
||||
}
|
||||
|
||||
if (end > length) {
|
||||
end = length;
|
||||
} else {
|
||||
if (end < 0)
|
||||
end = 0;
|
||||
if (end < begin) {
|
||||
int32_t tmp = begin;
|
||||
begin = end;
|
||||
end = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
str = DoSubstr(cx, str, size_t(begin), size_t(end - begin));
|
||||
if (!str)
|
||||
return false;
|
||||
}
|
||||
|
||||
args.rval().setString(str);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
static JSString *
|
||||
ToLowerCase(JSContext *cx, JSLinearString *str)
|
||||
|
@ -3938,6 +3992,54 @@ js::str_split_string(JSContext *cx, HandleTypeObject type, HandleString str, Han
|
|||
return aobj;
|
||||
}
|
||||
|
||||
static bool
|
||||
str_substr(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
RootedString str(cx, ThisToStringForStringProto(cx, args));
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
int32_t length, len, begin;
|
||||
if (args.length() > 0) {
|
||||
length = int32_t(str->length());
|
||||
if (!ValueToIntegerRange(cx, args[0], &begin))
|
||||
return false;
|
||||
|
||||
if (begin >= length) {
|
||||
args.rval().setString(cx->runtime()->emptyString);
|
||||
return true;
|
||||
}
|
||||
if (begin < 0) {
|
||||
begin += length; /* length + INT_MIN will always be less than 0 */
|
||||
if (begin < 0)
|
||||
begin = 0;
|
||||
}
|
||||
|
||||
if (args.hasDefined(1)) {
|
||||
if (!ValueToIntegerRange(cx, args[1], &len))
|
||||
return false;
|
||||
|
||||
if (len <= 0) {
|
||||
args.rval().setString(cx->runtime()->emptyString);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (uint32_t(length) < uint32_t(begin + len))
|
||||
len = length - begin;
|
||||
} else {
|
||||
len = length - begin;
|
||||
}
|
||||
|
||||
str = DoSubstr(cx, str, size_t(begin), size_t(len));
|
||||
if (!str)
|
||||
return false;
|
||||
}
|
||||
|
||||
args.rval().setString(str);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Python-esque sequence operations.
|
||||
*/
|
||||
|
@ -3974,6 +4076,73 @@ str_concat(JSContext *cx, unsigned argc, Value *vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
str_slice(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
if (args.length() == 1 && args.thisv().isString() && args[0].isInt32()) {
|
||||
JSString *str = args.thisv().toString();
|
||||
size_t begin = args[0].toInt32();
|
||||
size_t end = str->length();
|
||||
if (begin <= end) {
|
||||
size_t length = end - begin;
|
||||
if (length == 0) {
|
||||
str = cx->runtime()->emptyString;
|
||||
} else {
|
||||
str = (length == 1)
|
||||
? cx->staticStrings().getUnitStringForElement(cx, str, begin)
|
||||
: NewDependentString(cx, str, begin, length);
|
||||
if (!str)
|
||||
return false;
|
||||
}
|
||||
args.rval().setString(str);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
RootedString str(cx, ThisToStringForStringProto(cx, args));
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
if (args.length() != 0) {
|
||||
double begin, end, length;
|
||||
|
||||
if (!ToInteger(cx, args[0], &begin))
|
||||
return false;
|
||||
length = str->length();
|
||||
if (begin < 0) {
|
||||
begin += length;
|
||||
if (begin < 0)
|
||||
begin = 0;
|
||||
} else if (begin > length) {
|
||||
begin = length;
|
||||
}
|
||||
|
||||
if (args.hasDefined(1)) {
|
||||
if (!ToInteger(cx, args[1], &end))
|
||||
return false;
|
||||
if (end < 0) {
|
||||
end += length;
|
||||
if (end < 0)
|
||||
end = 0;
|
||||
} else if (end > length) {
|
||||
end = length;
|
||||
}
|
||||
if (end < begin)
|
||||
end = begin;
|
||||
} else {
|
||||
end = length;
|
||||
}
|
||||
|
||||
str = NewDependentString(cx, str, size_t(begin), size_t(end - begin));
|
||||
if (!str)
|
||||
return false;
|
||||
}
|
||||
args.rval().setString(str);
|
||||
return true;
|
||||
}
|
||||
|
||||
static const JSFunctionSpec string_methods[] = {
|
||||
#if JS_HAS_TOSOURCE
|
||||
JS_FN("quote", str_quote, 0,JSFUN_GENERIC_NATIVE),
|
||||
|
@ -3983,11 +4152,11 @@ static const JSFunctionSpec string_methods[] = {
|
|||
/* Java-like methods. */
|
||||
JS_FN(js_toString_str, js_str_toString, 0,0),
|
||||
JS_FN(js_valueOf_str, js_str_toString, 0,0),
|
||||
JS_FN("substring", str_substring, 2,JSFUN_GENERIC_NATIVE),
|
||||
JS_FN("toLowerCase", str_toLowerCase, 0,JSFUN_GENERIC_NATIVE),
|
||||
JS_FN("toUpperCase", str_toUpperCase, 0,JSFUN_GENERIC_NATIVE),
|
||||
JS_FN("charAt", js_str_charAt, 1,JSFUN_GENERIC_NATIVE),
|
||||
JS_FN("charCodeAt", js_str_charCodeAt, 1,JSFUN_GENERIC_NATIVE),
|
||||
JS_SELF_HOSTED_FN("substring", "String_substring", 2,0),
|
||||
JS_SELF_HOSTED_FN("codePointAt", "String_codePointAt", 1,0),
|
||||
JS_FN("contains", str_contains, 1,JSFUN_GENERIC_NATIVE),
|
||||
JS_FN("indexOf", str_indexOf, 1,JSFUN_GENERIC_NATIVE),
|
||||
|
@ -4014,11 +4183,11 @@ static const JSFunctionSpec string_methods[] = {
|
|||
JS_FN("search", str_search, 1,JSFUN_GENERIC_NATIVE),
|
||||
JS_FN("replace", str_replace, 2,JSFUN_GENERIC_NATIVE),
|
||||
JS_FN("split", str_split, 2,JSFUN_GENERIC_NATIVE),
|
||||
JS_SELF_HOSTED_FN("substr", "String_substr", 2,0),
|
||||
JS_FN("substr", str_substr, 2,JSFUN_GENERIC_NATIVE),
|
||||
|
||||
/* Python-esque sequence methods. */
|
||||
JS_FN("concat", str_concat, 1,JSFUN_GENERIC_NATIVE),
|
||||
JS_SELF_HOSTED_FN("slice", "String_slice", 2,0),
|
||||
JS_FN("slice", str_slice, 2,JSFUN_GENERIC_NATIVE),
|
||||
|
||||
/* HTML string methods. */
|
||||
JS_SELF_HOSTED_FN("bold", "String_bold", 0,0),
|
||||
|
@ -4124,17 +4293,13 @@ js::str_fromCharCode_one_arg(JSContext *cx, HandleValue code, MutableHandleValue
|
|||
|
||||
static const JSFunctionSpec string_static_methods[] = {
|
||||
JS_FN("fromCharCode", js::str_fromCharCode, 1, 0),
|
||||
|
||||
JS_SELF_HOSTED_FN("fromCodePoint", "String_static_fromCodePoint", 1,0),
|
||||
JS_SELF_HOSTED_FN("raw", "String_static_raw", 2,0),
|
||||
JS_SELF_HOSTED_FN("substring", "String_static_substring", 3,0),
|
||||
JS_SELF_HOSTED_FN("substr", "String_static_substr", 3,0),
|
||||
JS_SELF_HOSTED_FN("slice", "String_static_slice", 3,0),
|
||||
JS_SELF_HOSTED_FN("fromCodePoint", "String_static_fromCodePoint", 1, 0),
|
||||
JS_SELF_HOSTED_FN("raw", "String_static_raw", 2, 0),
|
||||
|
||||
// This must be at the end because of bug 853075: functions listed after
|
||||
// self-hosted methods aren't available in self-hosted code.
|
||||
#if EXPOSE_INTL_API
|
||||
JS_SELF_HOSTED_FN("localeCompare", "String_static_localeCompare", 2,0),
|
||||
JS_SELF_HOSTED_FN("localeCompare", "String_static_localeCompare", 2,0),
|
||||
#endif
|
||||
JS_FS_END
|
||||
};
|
||||
|
|
|
@ -249,14 +249,6 @@ EqualChars(const Char1 *s1, const Char2 *s2, size_t len)
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Computes |str|'s substring for the range [beginInt, beginInt + lengthInt).
|
||||
* Negative, overlarge, swapped, etc. |beginInt| and |lengthInt| are forbidden
|
||||
* and constitute API misuse.
|
||||
*/
|
||||
JSString *
|
||||
SubstringKernel(JSContext *cx, HandleString str, int32_t beginInt, int32_t lengthInt);
|
||||
|
||||
/*
|
||||
* Inflate bytes in ASCII encoding to char16_t code units. Return null on error,
|
||||
* otherwise return the char16_t buffer that was malloc'ed. length is updated to
|
||||
|
@ -319,6 +311,9 @@ str_lastIndexOf(JSContext *cx, unsigned argc, Value *vp);
|
|||
extern bool
|
||||
str_startsWith(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
extern bool
|
||||
str_substring(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
extern bool
|
||||
str_toLowerCase(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
|
|
|
@ -120,26 +120,6 @@ intrinsic_IsConstructor(JSContext *cx, unsigned argc, Value *vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::intrinsic_SubstringKernel(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args[0].isString());
|
||||
MOZ_ASSERT(args[1].isInt32());
|
||||
MOZ_ASSERT(args[2].isInt32());
|
||||
|
||||
RootedString str(cx, args[0].toString());
|
||||
int32_t begin = args[1].toInt32();
|
||||
int32_t length = args[2].toInt32();
|
||||
|
||||
JSString *substr = SubstringKernel(cx, str, begin, length);
|
||||
if (!substr)
|
||||
return false;
|
||||
|
||||
args.rval().setString(substr);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
intrinsic_OwnPropertyKeys(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
|
@ -1036,6 +1016,7 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||
JS_FN("std_String_replace", str_replace, 2,0),
|
||||
JS_FN("std_String_split", str_split, 2,0),
|
||||
JS_FN("std_String_startsWith", str_startsWith, 1,0),
|
||||
JS_FN("std_String_substring", str_substring, 2,0),
|
||||
JS_FN("std_String_toLowerCase", str_toLowerCase, 0,0),
|
||||
JS_FN("std_String_toUpperCase", str_toUpperCase, 0,0),
|
||||
|
||||
|
@ -1060,7 +1041,6 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||
JS_FN("_IsConstructing", intrinsic_IsConstructing, 0,0),
|
||||
JS_FN("DecompileArg", intrinsic_DecompileArg, 2,0),
|
||||
JS_FN("RuntimeDefaultLocale", intrinsic_RuntimeDefaultLocale, 0,0),
|
||||
JS_FN("SubstringKernel", intrinsic_SubstringKernel, 3,0),
|
||||
|
||||
JS_FN("UnsafePutElements", intrinsic_UnsafePutElements, 3,0),
|
||||
JS_FN("_DefineDataProperty", intrinsic_DefineDataProperty, 4,0),
|
||||
|
|
|
@ -475,9 +475,6 @@ class JSString : public js::gc::TenuredCell
|
|||
}
|
||||
|
||||
static size_t offsetOfNonInlineChars() {
|
||||
static_assert(offsetof(JSString, d.s.u2.nonInlineCharsTwoByte) ==
|
||||
offsetof(JSString, d.s.u2.nonInlineCharsLatin1),
|
||||
"nonInlineCharsTwoByte and nonInlineCharsLatin1 must have same offset");
|
||||
return offsetof(JSString, d.s.u2.nonInlineCharsTwoByte);
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче