Propagate compilation errors to our caller to make syntax errors easier to debug. bug 408412, r=shaver sr=brendan

This commit is contained in:
Blake Kaplan 2008-08-04 10:03:34 -07:00
parent c0bc5e6e03
commit c1ae312d79
4 changed files with 108 additions and 9 deletions

View File

@ -637,7 +637,8 @@ mozJSComponentLoader::LoadModule(nsILocalFile* aComponentFile,
if (!entry)
return NS_ERROR_OUT_OF_MEMORY;
rv = GlobalForLocation(aComponentFile, &entry->global, &entry->location);
rv = GlobalForLocation(aComponentFile, &entry->global, &entry->location,
nsnull);
if (NS_FAILED(rv)) {
#ifdef DEBUG_shaver
fprintf(stderr, "GlobalForLocation failed!\n");
@ -1060,7 +1061,8 @@ mozJSComponentLoader::WriteScript(nsIFastLoadService *flSvc, JSScript *script,
nsresult
mozJSComponentLoader::GlobalForLocation(nsILocalFile *aComponent,
JSObject **aGlobal,
char **aLocation)
char **aLocation,
jsval *exception)
{
nsresult rv;
@ -1190,22 +1192,37 @@ mozJSComponentLoader::GlobalForLocation(nsILocalFile *aComponent,
// The script wasn't in the fastload cache, so compile it now.
LOG(("Slow loading %s\n", nativePath.get()));
// If |exception| is non-null, then our caller wants to propagate any
// exceptions out to our caller. Ensure that the engine doesn't
// eagerly report the exception.
uint32 oldopts = 0;
if (exception) {
oldopts = JS_GetOptions(cx);
JS_SetOptions(cx, oldopts | JSOPTION_DONT_REPORT_UNCAUGHT);
}
#ifdef HAVE_PR_MEMMAP
PRInt64 fileSize;
rv = aComponent->GetFileSize(&fileSize);
if (NS_FAILED(rv))
if (NS_FAILED(rv)) {
JS_SetOptions(cx, oldopts);
return rv;
}
PRInt64 maxSize;
LL_UI2L(maxSize, PR_UINT32_MAX);
if (LL_CMP(fileSize, >, maxSize)) {
NS_ERROR("file too large");
JS_SetOptions(cx, oldopts);
return NS_ERROR_FAILURE;
}
PRFileDesc *fileHandle;
rv = aComponent->OpenNSPRFileDesc(PR_RDONLY, 0, &fileHandle);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_FAILED(rv)) {
JS_SetOptions(cx, oldopts);
return NS_ERROR_FILE_NOT_FOUND;
}
// Make sure the file is closed, no matter how we return.
FileAutoCloser fileCloser(fileHandle);
@ -1214,6 +1231,7 @@ mozJSComponentLoader::GlobalForLocation(nsILocalFile *aComponent,
PR_PROT_READONLY);
if (!map) {
NS_ERROR("Failed to create file map");
JS_SetOptions(cx, oldopts);
return NS_ERROR_FAILURE;
}
@ -1226,6 +1244,7 @@ mozJSComponentLoader::GlobalForLocation(nsILocalFile *aComponent,
char *buf = static_cast<char*>(PR_MemMap(map, 0, fileSize32));
if (!buf) {
NS_WARNING("Failed to map file");
JS_SetOptions(cx, oldopts);
return NS_ERROR_FAILURE;
}
@ -1244,15 +1263,29 @@ mozJSComponentLoader::GlobalForLocation(nsILocalFile *aComponent,
FILE *fileHandle;
rv = aComponent->OpenANSIFileDesc("r", &fileHandle);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_FAILED(rv)) {
JS_SetOptions(cx, oldopts);
return NS_ERROR_FILE_NOT_FOUND;
}
script = JS_CompileFileHandleForPrincipals(cx, global,
nativePath.get(),
fileHandle, jsPrincipals);
/* JS will close the filehandle after compilation is complete. */
#endif /* HAVE_PR_MEMMAP */
// Propagate the exception, if one exists. Also, don't leave the stale
// exception on this context.
// NB: The caller must stick exception into a rooted slot (probably on
// its context) as soon as possible to avoid GC hazards.
if (exception) {
JS_SetOptions(cx, oldopts);
if (!script) {
JS_GetPendingException(cx, exception);
JS_ClearPendingException(cx);
}
}
}
if (!script) {
@ -1474,14 +1507,27 @@ mozJSComponentLoader::ImportInto(const nsACString & aLocation,
if (!newEntry || !mInProgressImports.Put(lfhash, newEntry))
return NS_ERROR_OUT_OF_MEMORY;
jsval exception = JSVAL_VOID;
rv = GlobalForLocation(componentFile, &newEntry->global,
&newEntry->location);
&newEntry->location, &exception);
mInProgressImports.Remove(lfhash);
if (NS_FAILED(rv)) {
*_retval = nsnull;
return NS_ERROR_FILE_NOT_FOUND;
if (!JSVAL_IS_VOID(exception)) {
// An exception was thrown during compilation. Propagate it
// out to our caller so they can report it.
JSContext *callercx;
cc->GetJSContext(&callercx);
JS_SetPendingException(callercx, exception);
cc->SetExceptionWasThrown(PR_TRUE);
return NS_OK;
}
// Something failed, but we don't know what it is, guess.
return rv;
}
mod = newEntry;

View File

@ -110,7 +110,8 @@ class mozJSComponentLoader : public nsIModuleLoader,
nsresult GlobalForLocation(nsILocalFile *aComponent,
JSObject **aGlobal,
char **location);
char **location,
jsval *exception);
nsresult StartFastLoad(nsIFastLoadService *flSvc);
nsresult ReadScript(nsIFastLoadService *flSvc, const char *nativePath,

View File

@ -0,0 +1 @@
bogusjs)(

View File

@ -0,0 +1,51 @@
/*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dave Townsend <dtownsend@oxymoronical.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
function run_test() {
var file = do_get_file("js/src/xpconnect/tests/unit/syntax_error.jsm");
var ios = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var uri = ios.newFileURI(file);
try {
Components.utils.import(uri.spec);
do_throw("Failed to report any error at all");
} catch (e) {
do_check_neq(/^SyntaxError:/(e + ''), null);
}
}