diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index 2f3ea0f25ed..758c39ed606 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -18,42 +18,19 @@ using namespace js::types; using mozilla::ArrayLength; -class RegExpMatchBuilder +static inline bool +DefinePropertyHelper(JSContext *cx, HandleObject obj, Handle name, HandleValue v) { - JSContext * const cx; - RootedObject array; - - bool setProperty(Handle name, HandleValue v) { - return !!baseops::DefineProperty(cx, array, name, v, - JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE); - } - - public: - RegExpMatchBuilder(JSContext *cx, HandleObject array) : cx(cx), array(cx, array) {} - - bool append(uint32_t index, HandleValue v) { - JS_ASSERT(!array->getOps()->getElement); - return !!baseops::DefineElement(cx, array, index, v, JS_PropertyStub, JS_StrictPropertyStub, - JSPROP_ENUMERATE); - } - - bool setIndex(int index) { - RootedValue value(cx, Int32Value(index)); - return setProperty(cx->names().index, value); - } - - bool setInput(HandleString str) { - JS_ASSERT(str); - RootedValue value(cx, StringValue(str)); - return setProperty(cx->names().input, value); - } -}; + return !!baseops::DefineProperty(cx, obj, name, v, + JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE); +} bool js::CreateRegExpMatchResult(JSContext *cx, HandleString input_, const jschar *chars, size_t length, MatchPairs &matches, MutableHandleValue rval) { RootedString input(cx, input_); + RootedValue undefinedValue(cx, UndefinedValue()); /* * Create the (slow) result array for a match. @@ -64,39 +41,47 @@ js::CreateRegExpMatchResult(JSContext *cx, HandleString input_, const jschar *ch * input: input string * index: start index for the match */ - RootedObject array(cx, NewDenseEmptyArray(cx)); - if (!array) - return false; - if (!input) { input = js_NewStringCopyN(cx, chars, length); if (!input) return false; } - RegExpMatchBuilder builder(cx, array); - RootedValue undefinedValue(cx, UndefinedValue()); - size_t numPairs = matches.length(); JS_ASSERT(numPairs > 0); + AutoValueVector elements(cx); + if (!elements.reserve(numPairs)) + return false; + + /* Accumulate a Value for each pair, in a rooted vector. */ for (size_t i = 0; i < numPairs; ++i) { const MatchPair &pair = matches[i]; - RootedString captured(cx); if (pair.isUndefined()) { JS_ASSERT(i != 0); /* Since we had a match, first pair must be present. */ - if (!builder.append(i, undefinedValue)) - return false; + elements.infallibleAppend(undefinedValue); } else { - captured = js_NewDependentString(cx, input, pair.start, pair.length()); - RootedValue value(cx, StringValue(captured)); - if (!captured || !builder.append(i, value)) + JSLinearString *str = js_NewDependentString(cx, input, pair.start, pair.length()); + if (!str) return false; + elements.infallibleAppend(StringValue(str)); } } - if (!builder.setIndex(matches[0].start) || !builder.setInput(input)) + /* Copy the rooted vector into the array object. */ + RootedObject array(cx, NewDenseCopiedArray(cx, elements.length(), elements.begin())); + if (!array) + return false; + + /* Set the |index| property. */ + RootedValue index(cx, Int32Value(matches[0].start)); + if (!DefinePropertyHelper(cx, array, cx->names().index, index)) + return false; + + /* Set the |input| property. */ + RootedValue inputVal(cx, StringValue(input)); + if (!DefinePropertyHelper(cx, array, cx->names().input, inputVal)) return false; rval.setObject(*array);