Skip to content

Commit

Permalink
Backed out changesets b08e57dbef4e and 1049cfbf3426 (bug 947044) for …
Browse files Browse the repository at this point in the history
…various regressions.
  • Loading branch information
rvandermeulen committed Sep 25, 2014
1 parent f1e8d5a commit 8a93157
Show file tree
Hide file tree
Showing 26 changed files with 41 additions and 283 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ function test() {
function test1(aCallback) {
gDebugger.once(gDebugger.EVENTS.FETCHED_WATCH_EXPRESSIONS, () => {
checkWatchExpressions(26, {
a: "ReferenceError: a is not defined, did you mean 'z'?",
a: "ReferenceError: a is not defined",
this: { type: "object", class: "Object" },
prop: { type: "object", class: "String" },
args: { type: "undefined" }
Expand Down
3 changes: 1 addition & 2 deletions content/base/test/test_bug461735.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@
</script>
<script type="application/javascript">
window.onerror = function(message, uri, line) {
ok(message.contains("ReferenceError: c is not defined"),
"Should have correct error message");
is(message, "ReferenceError: c is not defined", "Should have correct error message");
is(uri,
"http://mochi.test:8888/tests/content/base/test/bug461735-redirect2.sjs",
"Unexpected error location URI");
Expand Down
3 changes: 1 addition & 2 deletions content/base/test/test_bug696301-1.html
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@
errorFired = false;
global = "";
window.onerror = function(message, uri, line) {
ok(message.contains("ReferenceError: c is not defined"),
"Should have correct error message");
is(message, "ReferenceError: c is not defined", "Should have correct error message");
is(uri,
"http://example.com/tests/content/base/test/bug696301-script-1.js",
"Should also have correct script URI");
Expand Down
3 changes: 1 addition & 2 deletions content/base/test/test_bug696301-2.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@
errorFired = false;
global = "";
window.onerror = function(message, uri, line) {
ok(message.contains("ReferenceError: c is not defined"),
"Should have correct error message");
is(message, "ReferenceError: c is not defined", "Should have correct error message");
is(uri,
"http://example.com/tests/content/base/test/bug696301-script-1.js",
"Should also have correct script URI");
Expand Down
2 changes: 1 addition & 1 deletion dom/tests/mochitest/bugs/test_onerror_message.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
{ name: "", message: "uncaught exception: [object Object]" },
{ name: "InvalidStateError", message: "An attempt was made to use an object that is not, or is no longer, usable", filename: location, lineNumber: 60 },
{ name: "ReferenceError", message: "xxx is not defined", filename: location, lineNumber: 64 },
{ name: "ReferenceError", message: "xxx is not defined, did you mean 'x'?", filename: location, lineNumber: 66 }
{ name: "ReferenceError", message: "xxx is not defined", filename: location, lineNumber: 66 }
];

var counter = 0;
Expand Down
2 changes: 1 addition & 1 deletion dom/workers/test/test_simpleThread.html
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
worker.onerror = function(otherEvent) {
otherEvent.preventDefault();
is(otherEvent.target, worker);
ok(otherEvent.message.contains("ReferenceError: Components is not defined"));
is(otherEvent.message, "ReferenceError: Components is not defined");
gotErrors = true;

worker.onerror = function(oneMoreEvent) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ try {
test();
} catch(e) {
caught = true;
assertEq(e.toString().contains("ReferenceError: not_defined is not defined"), true);
assertEq(''+e, "ReferenceError: not_defined is not defined");
}

assertEq(finalizerRun, true);
Expand Down
15 changes: 0 additions & 15 deletions js/src/jit-test/tests/basic/testReferenceErrorNameSuggestion-01.js

This file was deleted.

16 changes: 0 additions & 16 deletions js/src/jit-test/tests/basic/testReferenceErrorNameSuggestion-02.js

This file was deleted.

23 changes: 0 additions & 23 deletions js/src/jit-test/tests/basic/testReferenceErrorNameSuggestion-03.js

This file was deleted.

2 changes: 1 addition & 1 deletion js/src/jit/BaselineIC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5833,7 +5833,7 @@ DoGetNameFallback(JSContext *cx, BaselineFrame *frame, ICGetName_Fallback *stub_
if (!GetScopeNameForTypeOf(cx, scopeChain, name, res))
return false;
} else {
if (!GetScopeName(cx, script, pc, scopeChain, name, res))
if (!GetScopeName(cx, scopeChain, name, res))
return false;
}

Expand Down
4 changes: 2 additions & 2 deletions js/src/jit/IonCaches.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4374,10 +4374,10 @@ NameIC::update(JSContext *cx, size_t cacheIndex, HandleObject scopeChain,
}

if (cache.isTypeOf()) {
if (!FetchName<true>(cx, script, pc, obj, holder, name, shape, vp))
if (!FetchName<true>(cx, obj, holder, name, shape, vp))
return false;
} else {
if (!FetchName<false>(cx, script, pc, obj, holder, name, shape, vp))
if (!FetchName<false>(cx, obj, holder, name, shape, vp))
return false;
}

Expand Down
1 change: 0 additions & 1 deletion js/src/js.msg
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@

MSG_DEF(JSMSG_NOT_AN_ERROR, 0, JSEXN_NONE, "<Error #0 is reserved>")
MSG_DEF(JSMSG_NOT_DEFINED, 1, JSEXN_REFERENCEERR, "{0} is not defined")
MSG_DEF(JSMSG_NOT_DEFINED_DID_YOU_MEAN, 2, JSEXN_REFERENCEERR, "{0} is not defined, did you mean '{1}'?")
MSG_DEF(JSMSG_MORE_ARGS_NEEDED, 3, JSEXN_TYPEERR, "{0} requires more than {1} argument{2}")
MSG_DEF(JSMSG_INCOMPATIBLE_PROTO, 3, JSEXN_TYPEERR, "{0}.prototype.{1} called on incompatible {2}")
MSG_DEF(JSMSG_NO_CONSTRUCTOR, 1, JSEXN_TYPEERR, "{0} has no constructor")
Expand Down
174 changes: 2 additions & 172 deletions js/src/jscntxt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/MemoryReporting.h"

#include <algorithm>
#include <ctype.h>
#include <stdarg.h>
#include <string.h>
Expand Down Expand Up @@ -50,7 +49,6 @@
#include "jsobjinlines.h"
#include "jsscriptinlines.h"

#include "vm/ScopeObject-inl.h"
#include "vm/Stack-inl.h"

using namespace js;
Expand Down Expand Up @@ -881,178 +879,10 @@ js::CallErrorReporter(JSContext *cx, const char *message, JSErrorReport *reportp
onError(cx, message, reportp);
}

static const size_t MAX_NAME_LENGTH_FOR_EDIT_DISTANCE = 1000;
static const size_t MAX_REFERENCE_ERROR_NAMES_TO_CHECK = 1000;

/*
* The edit distance between two strings is defined as the Levenshtein distance,
* which is described here: (http://en.wikipedia.org/wiki/Levenshtein_distance).
* Intuitively, this is the number of insert, delete, and/or substitution
* operations required to get from one string to the other.
*
* Given two atoms, this function computes their edit distance using dynamic
* programming. The resulting algorithm has O(m * n) complexity, but since it is
* only used for ReferenceError reporting, and the given atoms are expected to
* be small, its performance should be good enough. Despite that, we will only
* compute the edit distance for names whose length are shorter than
* MAX_NAME_LENGTH_FOR_EDIT_DISTANCE. We shouldn't ever find a pair with an edit
* distance of 0 (or else there wouldn't have been a ReferenceError), so we set
* the value presult points to to 0 and return true when a name is too long.
*/
static bool ComputeEditDistance(JSContext *cx, HandleAtom atom1,
HandleAtom atom2, size_t *presult)
{
*presult = 0;

const size_t m = atom1->length();
if (m >= MAX_NAME_LENGTH_FOR_EDIT_DISTANCE)
return true;
const size_t n = atom2->length();
if (m >= MAX_NAME_LENGTH_FOR_EDIT_DISTANCE)
return true;

Vector<size_t> d(cx);
if (!d.growBy((m + 1) * (n + 1)))
return false;

AutoStableStringChars aChars(cx);
AutoStableStringChars bChars(cx);
if (!aChars.initTwoByte(cx, atom1) || !bChars.initTwoByte(cx, atom2))
return false;

const char16_t *a = aChars.twoByteRange().start().get();
const char16_t *b = bChars.twoByteRange().start().get();

/*
* D(i, j) is defined as the edit distance between the i-length prefix
* of a and the m-length prefix of b.
*/
#define D(i, j) (d[(i) * ((n) + 1) + (j)])

/*
* Given the i-length prefix of a, the 0-length prefix of b can be
* obtained by deleting i characters.
*/
for (size_t i = 0; i <= m; ++i)
D(i, 0) = i;

/*
* Given the j-length prefix of b, the 0-length prefix of a can be
* obtained by inserting i characters.
*/
for (size_t j = 0; j <= n; ++j)
D(0, j) = j;

for (size_t i = 1; i <= m; ++i) {
for (size_t j = 1; j <= n; ++j) {
/*
* If the i-length prefix of a and the j-length prefix of b are
* equal in their last character, their edit distance equals
* that of the i-1-length and j-1-length prefix of a and b,
* respectively.
*/
if (a[i - 1] == b[j - 1])
D(i, j) = D(i - 1, j - 1); // No operation required
else {
D(i, j) = std::min(
D(i - 1, j) + 1, // Deletion
std::min(
D(i, j - 1) + 1, // Insertion
D(i - 1, j - 1) + 1 // Substitution
)
);
}
}
}

*presult = D(m, n);

#undef D

return true;
}

void
js_ReportIsNotDefined(JSContext *cx, HandleScript script, jsbytecode *pc, HandleAtom atom)
{
/*
* Walk the static scope chain and the global object to find the name that
* most closely matches the one we are looking for, so we can provide it as
* a hint to the user.
*
* To quantify how closely one name matches another, we define a metric on
* strings known as the edit distance (see ComputeEditDistance for details).
* We then pick the name with the shortest edit distance from the name we
* were trying to find.
*/
AutoIdVector ids(cx);
for (StaticScopeIter<CanGC> ssi(cx, InnermostStaticScope(script, pc)); !ssi.done(); ssi++) {
switch (ssi.type()) {
case StaticScopeIter<NoGC>::BLOCK:
if (!GetPropertyNames(cx, &ssi.block(), JSITER_OWNONLY, &ids)) {
/*
* If GetPropertyNames fails (due to overrecursion), we still
* want to act as if we had never called it, and report the
* reference error instead. Otherwise, we would break
* tests/gc/bug-886560.js.
*/
js_ReportIsNotDefined(cx, atom);
return;
}
break;

case StaticScopeIter<NoGC>::FUNCTION:
{
RootedScript script(cx, ssi.funScript());
for (BindingIter bi(script); !bi.done(); bi++)
ids.append(NameToId(bi->name()));
break;
}

case StaticScopeIter<CanGC>::NAMED_LAMBDA:
ids.append(NameToId(ssi.lambdaName()));
break;
}
}
if (!GetPropertyNames(cx, cx->global(), JSITER_OWNONLY, &ids)) {
// See comment above
js_ReportIsNotDefined(cx, atom);
return;
}

RootedAtom bestMatch(cx);
size_t minDistance = (size_t) -1;
size_t max = std::min(ids.length(), MAX_REFERENCE_ERROR_NAMES_TO_CHECK);
for (size_t i = 0; i < max; ++i) {
RootedAtom otherAtom(cx, JSID_TO_ATOM(ids[i]));
size_t distance;
if (!ComputeEditDistance(cx, atom, otherAtom, &distance))
return;
if (distance != 0 && distance < minDistance) {
bestMatch = JSID_TO_ATOM(ids[i]);
minDistance = distance;
}
}

if (!bestMatch) {
// We didn't find any suitable suggestions.
js_ReportIsNotDefined(cx, atom);
return;
}

JSAutoByteString bytes1(cx, atom);
JSAutoByteString bytes2(cx, bestMatch);
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
JSMSG_NOT_DEFINED_DID_YOU_MEAN, bytes1.ptr(),
bytes2.ptr());
}

void
js_ReportIsNotDefined(JSContext *cx, HandleAtom atom)
js_ReportIsNotDefined(JSContext *cx, const char *name)
{
JSAutoByteString bytes(cx, atom);
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_DEFINED,
bytes.ptr());
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_DEFINED, name);
}

bool
Expand Down
5 changes: 1 addition & 4 deletions js/src/jscntxt.h
Original file line number Diff line number Diff line change
Expand Up @@ -750,10 +750,7 @@ CallErrorReporter(JSContext *cx, const char *message, JSErrorReport *report);
} /* namespace js */

extern void
js_ReportIsNotDefined(JSContext *cx, js::HandleScript script, jsbytecode *pc, js::HandleAtom atom);

extern void
js_ReportIsNotDefined(JSContext *cx, js::HandleAtom atom);
js_ReportIsNotDefined(JSContext *cx, const char *name);

/*
* Report an attempt to access the property of a null or undefined value (v).
Expand Down
5 changes: 3 additions & 2 deletions js/src/jsobj.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5076,8 +5076,9 @@ GetPropertyHelperInline(JSContext *cx,

if (op == JSOP_GETXPROP) {
/* Undefined property during a name lookup, report an error. */
RootedAtom atom(cx, JSID_TO_ATOM(id));
js_ReportIsNotDefined(cx, atom);
JSAutoByteString printable;
if (js_ValueToPrintable(cx, IdToValue(id), &printable))
js_ReportIsNotDefined(cx, printable.ptr());
return false;
}

Expand Down
2 changes: 1 addition & 1 deletion js/src/tests/js1_5/Regress/regress-356693.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function test()
printBugNumber(BUGNUMBER);
printStatus (summary);

expect = "ReferenceError: x is not defined, did you mean 'gc'?";
expect = 'ReferenceError: x is not defined';
try
{
delete (0 ? 3 : x());
Expand Down
2 changes: 1 addition & 1 deletion js/src/tests/js1_5/Scope/regress-446026-01.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ var b = 45;
};
})();

expect = "ReferenceError: a is not defined, did you mean 'b'? | undefined | 45";
expect = 'ReferenceError: a is not defined | undefined | 45';
actual = '';

var foo;
Expand Down
Loading

0 comments on commit 8a93157

Please sign in to comment.