Closed
Bug 623435
Opened 14 years ago
Closed 14 years ago
Rip out deprecated |RegExp.compile| builtin method
Categories
(Core :: JavaScript Engine, defect)
Core
JavaScript Engine
Tracking
()
RESOLVED
FIXED
| Tracking | Status | |
|---|---|---|
| status2.0 | --- | ? |
People
(Reporter: cdleary, Assigned: cdleary)
References
Details
(Whiteboard: fixed-in-tracemonkey)
Attachments
(2 files, 1 obsolete file)
|
8.02 KB,
patch
|
brendan
:
review+
|
Details | Diff | Splinter Review |
|
7.99 KB,
patch
|
brendan
:
review+
|
Details | Diff | Splinter Review |
See bug 587288 comment 18 and bug 587288 comment 21. Small excerpt:
As a side note, the |RegExp.compile| builtin method is insidious! Swaps out the
guts of a regexp object, so you have to be really careful when holding
js::RegExp temporaries, a la bug 327170, because further code execution can
drop your refcount underneath you.
This is wanted 2.0 so we can have it removed on a nice big release.
| Assignee | ||
Updated•14 years ago
|
| Assignee | ||
Comment 1•14 years ago
|
||
brendan, do you think it's too late in the release timeline to do this? If not, I can whip it up.
| Assignee | ||
Comment 2•14 years ago
|
||
Attachment #506343 -
Flags: review?(brendan)
| Assignee | ||
Comment 3•14 years ago
|
||
Attachment #506344 -
Flags: review?(brendan)
| Assignee | ||
Comment 4•14 years ago
|
||
Sorry, forgotten qref.
Attachment #506344 -
Attachment is obsolete: true
Attachment #506345 -
Flags: review?(brendan)
Attachment #506344 -
Flags: review?(brendan)
Comment 5•14 years ago
|
||
Comment on attachment 506343 [details] [diff] [review]
0. Remove |RegExp.compile|
>diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp
>--- a/js/src/jsregexp.cpp
>+++ b/js/src/jsregexp.cpp
>@@ -659,92 +659,28 @@ EscapeNakedForwardSlashes(JSContext *cx,
> if (!escaped)
> cx->free(chars);
> return escaped;
> }
> return unescaped;
> }
>
> static bool
>-regexp_compile_sub_tail(JSContext *cx, JSObject *obj, Value *rval, JSString *str, uint32 flags = 0)
>+SwapRegExpInternals(JSContext *cx, JSObject *obj, Value *rval, JSString *str, uint32 flags = 0)
> {
> flags |= cx->regExpStatics()->getFlags();
> AlreadyIncRefed<RegExp> re = RegExp::create(cx, str, flags);
> if (!re)
> return false;
> SwapObjectRegExp(cx, obj, re);
> *rval = ObjectValue(*obj);
> return true;
> }
>
> static JSBool
>-regexp_compile_sub(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval)
>-{
>- if (!InstanceOf(cx, obj, &js_RegExpClass, argv))
>- return false;
>-
>- if (argc == 0)
>- return regexp_compile_sub_tail(cx, obj, rval, cx->runtime->emptyString);
>-
>- Value sourceValue = argv[0];
>- if (sourceValue.isObject() && sourceValue.toObject().getClass() == &js_RegExpClass) {
>- /*
>- * If we get passed in a RegExp object we construct a new
>- * RegExp that is a duplicate of it by re-compiling the
>- * original source code. ECMA requires that it be an error
>- * here if the flags are specified. (We must use the flags
>- * from the original RegExp also).
>- */
>- JSObject &sourceObj = sourceValue.toObject();
>- if (argc >= 2 && !argv[1].isUndefined()) {
>- JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NEWREGEXP_FLAGGED);
>- return false;
>- }
>- RegExp *re = RegExp::extractFrom(&sourceObj);
>- if (!re)
>- return false;
>- AlreadyIncRefed<RegExp> clone = RegExp::clone(cx, *re);
>- if (!clone)
>- return false;
>- SwapObjectRegExp(cx, obj, clone);
>- *rval = ObjectValue(*obj);
>- return true;
>- }
>-
>- /* Coerce to string and compile. */
>- JSString *sourceStr = js_ValueToString(cx, sourceValue);
>- if (!sourceStr)
>- return false;
>- argv[0] = StringValue(sourceStr);
>- uint32 flags = 0;
>- if (argc > 1 && !argv[1].isUndefined()) {
>- JSString *flagStr = js_ValueToString(cx, argv[1]);
>- if (!flagStr)
>- return false;
>- argv[1] = StringValue(flagStr);
>- if (!RegExp::parseFlags(cx, flagStr, flags))
>- return false;
>- }
>-
>- JSString *escapedSourceStr = EscapeNakedForwardSlashes(cx, sourceStr);
>- if (!escapedSourceStr)
>- return false;
>- argv[0] = StringValue(escapedSourceStr);
>-
>- return regexp_compile_sub_tail(cx, obj, rval, escapedSourceStr, flags);
>-}
>-
>-static JSBool
>-regexp_compile(JSContext *cx, uintN argc, Value *vp)
>-{
>- JSObject *obj = JS_THIS_OBJECT(cx, Jsvalify(vp));
>- return obj && regexp_compile_sub(cx, obj, argc, vp + 2, vp);
>-}
>-
>-static JSBool
> regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, Value *argv, JSBool test, Value *rval)
> {
> if (!InstanceOf(cx, obj, &js_RegExpClass, argv))
> return false;
>
> RegExp *re = RegExp::extractFrom(obj);
> if (!re)
> return true;
>@@ -833,49 +769,97 @@ js_regexp_test(JSContext *cx, uintN argc
> return true;
> }
>
> static JSFunctionSpec regexp_methods[] = {
> #if JS_HAS_TOSOURCE
> JS_FN(js_toSource_str, regexp_toString, 0,0),
> #endif
> JS_FN(js_toString_str, regexp_toString, 0,0),
>- JS_FN("compile", regexp_compile, 2,0),
> JS_FN("exec", js_regexp_exec, 1,0),
> JS_FN("test", js_regexp_test, 1,0),
> JS_FS_END
> };
>
> static JSBool
> regexp_construct(JSContext *cx, uintN argc, Value *vp)
> {
> Value *argv = JS_ARGV(cx, vp);
>+ Value *rval = &JS_RVAL(cx, vp);
>+
> if (!IsConstructing(vp)) {
> /*
> * If first arg is regexp and no flags are given, just return the arg.
>- * (regexp_compile_sub detects the regexp + flags case and throws a
>- * TypeError.) See 15.10.3.1.
>+ * Otherwise, delegate to the standard constructor.
>+ * See ECMAv5 15.10.3.1.
> */
> if (argc >= 1 && argv[0].isObject() && argv[0].toObject().isRegExp() &&
>- (argc == 1 || argv[1].isUndefined()))
>- {
>+ (argc == 1 || argv[1].isUndefined())) {
> *vp = argv[0];
> return true;
> }
> }
>
> /* Otherwise, replace obj with a new RegExp object. */
> JSObject *obj = NewBuiltinClassInstance(cx, &js_RegExpClass);
> if (!obj)
> return false;
>
>- return regexp_compile_sub(cx, obj, argc, argv, vp);
>+ if (argc == 0)
>+ return SwapRegExpInternals(cx, obj, rval, cx->runtime->emptyString);
>+
>+ Value sourceValue = argv[0];
>+ if (sourceValue.isObject() && sourceValue.toObject().getClass() == &js_RegExpClass) {
>+ /*
>+ * If we get passed in a RegExp object we construct a new
>+ * RegExp that is a duplicate of it by re-compiling the
>+ * original source code. ECMA requires that it be an error
>+ * here if the flags are specified. (We must use the flags
>+ * from the original RegExp also).
>+ */
>+ JSObject &sourceObj = sourceValue.toObject();
>+ if (argc >= 2 && !argv[1].isUndefined()) {
>+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NEWREGEXP_FLAGGED);
>+ return false;
>+ }
>+ RegExp *re = RegExp::extractFrom(&sourceObj);
>+ if (!re)
>+ return false;
>+ AlreadyIncRefed<RegExp> clone = RegExp::clone(cx, *re);
>+ if (!clone)
>+ return false;
>+ SwapObjectRegExp(cx, obj, clone);
>+ *rval = ObjectValue(*obj);
>+ return true;
>+ }
>+
>+ /* Coerce to string and compile. */
>+ JSString *sourceStr = js_ValueToString(cx, sourceValue);
>+ if (!sourceStr)
>+ return false;
>+ argv[0] = StringValue(sourceStr);
>+ uint32 flags = 0;
>+ if (argc > 1 && !argv[1].isUndefined()) {
>+ JSString *flagStr = js_ValueToString(cx, argv[1]);
>+ if (!flagStr)
>+ return false;
>+ argv[1] = StringValue(flagStr);
>+ if (!RegExp::parseFlags(cx, flagStr, flags))
>+ return false;
>+ }
>+
>+ JSString *escapedSourceStr = EscapeNakedForwardSlashes(cx, sourceStr);
>+ if (!escapedSourceStr)
>+ return false;
>+ argv[0] = StringValue(escapedSourceStr);
>+
>+ return SwapRegExpInternals(cx, obj, rval, escapedSourceStr, flags);
> }
>
>-/* Similar to regexp_compile_sub_tail. */
>+/* Similar to SwapRegExpInternals. */
> static bool
> InitRegExpClassCompile(JSContext *cx, JSObject *obj)
> {
> AlreadyIncRefed<RegExp> re = RegExp::create(cx, cx->runtime->emptyString, 0);
> if (!re)
> return false;
> SwapObjectRegExp(cx, obj, re);
> return true;
>diff --git a/js/src/tests/ecma_3/extensions/jstests.list b/js/src/tests/ecma_3/extensions/jstests.list
>--- a/js/src/tests/ecma_3/extensions/jstests.list
>+++ b/js/src/tests/ecma_3/extensions/jstests.list
>@@ -3,13 +3,13 @@ script 10.1.3-2.js
> script 7.9.1.js
> script regress-103087.js
> script regress-188206-01.js
> script regress-188206-02.js
> script regress-220367-002.js
> script regress-228087.js
> script regress-274152.js
> script regress-320854.js
>-script regress-327170.js
>+skip script regress-327170.js # RegExp.compile removed.
> script regress-368516.js
> script regress-385393-03.js
> script regress-429248.js
> script regress-430740.js
>diff --git a/js/src/tests/js1_2/regexp/jstests.list b/js/src/tests/js1_2/regexp/jstests.list
>--- a/js/src/tests/js1_2/regexp/jstests.list
>+++ b/js/src/tests/js1_2/regexp/jstests.list
>@@ -15,17 +15,17 @@ script RegExp_object.js
> script RegExp_rightContext.js
> script RegExp_rightContext_as_array.js
> script alphanumeric.js
> script asterisk.js
> script backslash.js
> script backspace.js
> script beginLine.js
> script character_class.js
>-script compile.js
>+skip script compile.js # RegExp.compile removed.
> script control_characters.js
> script digit.js
> script dot.js
> script endLine.js
> script everything.js
> script exec.js
> script flags.js
> script global.js
Attachment #506343 -
Flags: review?(brendan) → review+
Comment 6•14 years ago
|
||
Comment on attachment 506345 [details] [diff] [review]
1. Clean regexp constructor.
> #define HANDLE_FLAG(__name) \
..12345678901234567890123456789012345678901234567890123456789012345678901234567890
Pre-existing nits: house style puts \ in column 79...
> JS_BEGIN_MACRO \
>- if (flagsOut & (__name)) \
... and wants name_ not __name.
>+ /*
>+ * Per ECMAv5 15.10.4.1, we act on combinations of (pattern, flags):
>+ * RegExp, undefined => flags := pattern.flags
>+ * RegExp, _ => throw TypeError
>+ * _ => pattern := ToString(pattern) if defined(pattern) else ''
>+ * flags := ToString(flags) if defined(flags) else ''
>+ */
Love the pseudo-ML, but why := instead of =?
>+ if (!flagStr ||
>+ !RegExp::parseFlags(cx, flagStr, &flags))
> return false;
Nit: (||) fits on one line, if it didn't you'd want to brace the consequent.
r=me, thanks.
/be
Attachment #506345 -
Flags: review?(brendan) → review+
Comment 7•14 years ago
|
||
Filed comment 5 disaster against bugzilla as bug 628471.
/be
| Assignee | ||
Comment 8•14 years ago
|
||
(In reply to comment #6)
> Love the pseudo-ML, but why := instead of =?
I sure yearn for pattern matching sometimes! Wanted to emphasize it was a rebinding of the original (pattern, flags) we were casing on.
| Assignee | ||
Comment 9•14 years ago
|
||
Whiteboard: fixed-in-tracemonkey
| Assignee | ||
Comment 10•14 years ago
|
||
http://hg.mozilla.org/tracemonkey/rev/4bc54aa1e566 (using js::Anchor)
http://hg.mozilla.org/tracemonkey/rev/4003aacbc675 (using JSStack-rooting)
The js::Anchor ends up with one two C-stack stores on non-GCC builds, so brendan asked to switch it back to use JSStack rooting.
| Assignee | ||
Comment 11•14 years ago
|
||
cdleary-bot mozilla-central merge info:
http://hg.mozilla.org/mozilla-central/rev/a23e97df1b9f
http://hg.mozilla.org/mozilla-central/rev/4bc54aa1e566
http://hg.mozilla.org/mozilla-central/rev/4003aacbc675
| Assignee | ||
Updated•14 years ago
|
Status: ASSIGNED → RESOLVED
Closed: 14 years ago
Resolution: --- → FIXED
Keywords: dev-doc-needed
| Assignee | ||
Comment 12•14 years ago
|
||
Why are dev docs needed for a method that should no longer exist? Removing until there's justification.
Keywords: dev-doc-needed
| Assignee | ||
Comment 13•14 years ago
|
||
Oh, I see the potential confusion. We had to back this out in bug 630284, see comment 12. Unfortunately, it lives on, but we shouldn't document it more. :-)
You need to log in
before you can comment on or make changes to this bug.
Description
•