mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-19 00:05:36 +00:00
Merge mozilla central and tracemonkey.
This commit is contained in:
commit
f3dfc40bb7
@ -891,13 +891,6 @@ nsChromeRegistryChrome::ManifestContent(ManifestProcessingContext& cx, int linen
|
||||
entry->flags |= PLATFORM_PACKAGE;
|
||||
if (contentaccessible)
|
||||
entry->flags |= CONTENT_ACCESSIBLE;
|
||||
if (cx.GetXPConnect()) {
|
||||
nsCAutoString urlp("chrome://");
|
||||
urlp.Append(package);
|
||||
urlp.Append('/');
|
||||
|
||||
cx.GetXPConnect()->FlagSystemFilenamePrefix(urlp.get(), true);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -70,7 +70,7 @@ def run(args, stdin=None):
|
||||
|
||||
def get_js_files():
|
||||
(out, err, exit) = run('find ../jit-test/tests -name "*.js"')
|
||||
if (err, exit) == ("", 0):
|
||||
if (err, exit) != ("", 0):
|
||||
sys.exit("Wrong directory, run from an objdir")
|
||||
return out.split()
|
||||
|
||||
@ -191,12 +191,12 @@ whitelist.add(r"('', 'out of memory\nout of memory\n', -11)")
|
||||
# Options
|
||||
parser = OptionParser(usage=usage)
|
||||
parser.add_option("-r", "--regression", action="store", metavar="REGRESSION_COUNT", help=help,
|
||||
type="int", dest="regression", default=0) # TODO: support a value of zero, eventually
|
||||
type="int", dest="regression", default=None)
|
||||
|
||||
(OPTIONS, args) = parser.parse_args()
|
||||
|
||||
|
||||
if OPTIONS.regression:
|
||||
if OPTIONS.regression != None:
|
||||
# TODO: This should be expanded as we get a better hang of the OOM problems.
|
||||
# For now, we'll just check that the number of OOMs in one short file does not
|
||||
# increase.
|
||||
@ -209,7 +209,7 @@ else:
|
||||
files = [f for f in files if f.find(args[0]) != -1]
|
||||
|
||||
|
||||
if OPTIONS.regression:
|
||||
if OPTIONS.regression == None:
|
||||
# Don't use a logfile, this is automated for tinderbox.
|
||||
log = file("../OOM_log", "w")
|
||||
|
||||
@ -229,6 +229,8 @@ for f in files:
|
||||
|
||||
if OPTIONS.regression == None:
|
||||
print "Testing allocation %d/%d in %s" % (i,max,f)
|
||||
else:
|
||||
sys.stdout.write('.') # something short for tinderbox, no space or \n
|
||||
|
||||
command = (command_template + ' -A %d') % (f, i)
|
||||
out, err, exit = run(command)
|
||||
@ -240,7 +242,7 @@ for f in files:
|
||||
# Failure
|
||||
else:
|
||||
|
||||
if OPTIONS.regression:
|
||||
if OPTIONS.regression != None:
|
||||
# Just count them
|
||||
num_failures += 1
|
||||
continue
|
||||
@ -314,12 +316,13 @@ for f in files:
|
||||
log.write ("\n")
|
||||
log.flush()
|
||||
|
||||
if not OPTIONS.regression == None:
|
||||
if OPTIONS.regression == None:
|
||||
count_lines()
|
||||
|
||||
print '\n',
|
||||
|
||||
# Do the actual regression check
|
||||
if OPTIONS.regression:
|
||||
if OPTIONS.regression != None:
|
||||
expected_num_failures = OPTIONS.regression
|
||||
|
||||
if num_failures != expected_num_failures:
|
||||
|
@ -253,13 +253,11 @@ nsFrameMessageManager::SendSyncMessage()
|
||||
continue;
|
||||
|
||||
jsval ret = JSVAL_VOID;
|
||||
JSONParser* parser = JS_BeginJSONParse(ctx, &ret);
|
||||
JSBool ok = JS_ConsumeJSONText(ctx, parser, (jschar*)retval[i].get(),
|
||||
(uint32)retval[i].Length());
|
||||
ok = JS_FinishJSONParse(ctx, parser, JSVAL_NULL) && ok;
|
||||
if (ok) {
|
||||
NS_ENSURE_TRUE(JS_SetElement(ctx, dataArray, i, &ret), NS_ERROR_OUT_OF_MEMORY);
|
||||
if (!JS_ParseJSON(ctx, (jschar*)retval[i].get(),
|
||||
(uint32)retval[i].Length(), &ret)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
NS_ENSURE_TRUE(JS_SetElement(ctx, dataArray, i, &ret), NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
jsval* retvalPtr;
|
||||
@ -380,15 +378,9 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
|
||||
|
||||
jsval json = JSVAL_NULL;
|
||||
if (!aJSON.IsEmpty()) {
|
||||
JSONParser* parser = JS_BeginJSONParse(ctx, &json);
|
||||
if (parser) {
|
||||
JSBool ok = JS_ConsumeJSONText(ctx, parser,
|
||||
(jschar*)nsString(aJSON).get(),
|
||||
(uint32)aJSON.Length());
|
||||
ok = JS_FinishJSONParse(ctx, parser, JSVAL_NULL) && ok;
|
||||
if (!ok) {
|
||||
json = JSVAL_NULL;
|
||||
}
|
||||
if (!JS_ParseJSON(ctx, (jschar*)nsString(aJSON).get(),
|
||||
(uint32)aJSON.Length(), &json)) {
|
||||
json = JSVAL_NULL;
|
||||
}
|
||||
}
|
||||
JSString* jsMessage =
|
||||
@ -667,7 +659,6 @@ nsFrameScriptExecutor::LoadFrameScriptInternal(const nsAString& aURL)
|
||||
if (global) {
|
||||
JSPrincipals* jsprin = nsnull;
|
||||
mPrincipal->GetJSPrincipals(mCx, &jsprin);
|
||||
nsContentUtils::XPConnect()->FlagSystemFilenamePrefix(url.get(), PR_TRUE);
|
||||
|
||||
uint32 oldopts = JS_GetOptions(mCx);
|
||||
JS_SetOptions(mCx, oldopts | JSOPTION_NO_SCRIPT_RVAL);
|
||||
|
@ -314,11 +314,9 @@ nsJSScriptTimeoutHandler::Init(nsGlobalWindow *aWindow, PRBool *aIsInterval,
|
||||
|
||||
mExpr = expr;
|
||||
|
||||
nsIPrincipal *prin = aWindow->GetPrincipal();
|
||||
|
||||
// Get the calling location.
|
||||
const char *filename;
|
||||
if (nsJSUtils::GetCallingLocation(cx, &filename, &mLineNo, prin)) {
|
||||
if (nsJSUtils::GetCallingLocation(cx, &filename, &mLineNo)) {
|
||||
mFileName.Assign(filename);
|
||||
}
|
||||
} else if (funobj) {
|
||||
|
@ -62,7 +62,7 @@
|
||||
|
||||
JSBool
|
||||
nsJSUtils::GetCallingLocation(JSContext* aContext, const char* *aFilename,
|
||||
PRUint32* aLineno, nsIPrincipal* aPrincipal)
|
||||
PRUint32* aLineno)
|
||||
{
|
||||
// Get the current filename and line number
|
||||
JSStackFrame* frame = nsnull;
|
||||
@ -76,29 +76,6 @@ nsJSUtils::GetCallingLocation(JSContext* aContext, const char* *aFilename,
|
||||
} while (frame && !script);
|
||||
|
||||
if (script) {
|
||||
// If aPrincipals is non-null then our caller is asking us to ensure
|
||||
// that the filename we return does not have elevated privileges.
|
||||
if (aPrincipal) {
|
||||
uint32 flags = JS_GetScriptFilenameFlags(script);
|
||||
|
||||
// Use the principal for the filename if it shouldn't be receiving
|
||||
// implicit XPCNativeWrappers.
|
||||
PRBool system;
|
||||
if (flags & JSFILENAME_PROTECTED) {
|
||||
nsIScriptSecurityManager *ssm = nsContentUtils::GetSecurityManager();
|
||||
|
||||
if (NS_FAILED(ssm->IsSystemPrincipal(aPrincipal, &system)) || !system) {
|
||||
JSPrincipals* jsprins;
|
||||
aPrincipal->GetJSPrincipals(aContext, &jsprins);
|
||||
|
||||
*aFilename = jsprins->codebase;
|
||||
*aLineno = 0;
|
||||
JSPRINCIPALS_DROP(aContext, jsprins);
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char* filename = ::JS_GetScriptFilename(aContext, script);
|
||||
|
||||
if (filename) {
|
||||
|
@ -58,7 +58,7 @@ class nsJSUtils
|
||||
{
|
||||
public:
|
||||
static JSBool GetCallingLocation(JSContext* aContext, const char* *aFilename,
|
||||
PRUint32* aLineno, nsIPrincipal* aPrincipal);
|
||||
PRUint32* aLineno);
|
||||
|
||||
static nsIScriptGlobalObject *GetStaticScriptGlobal(JSContext* aContext,
|
||||
JSObject* aObj);
|
||||
|
@ -424,19 +424,8 @@ nsJSON::DecodeToJSVal(const nsAString &str, JSContext *cx, jsval *result)
|
||||
{
|
||||
JSAutoRequest ar(cx);
|
||||
|
||||
JSONParser *parser = JS_BeginJSONParse(cx, result);
|
||||
NS_ENSURE_TRUE(parser, NS_ERROR_UNEXPECTED);
|
||||
|
||||
JSBool ok = JS_ConsumeJSONText(cx, parser,
|
||||
(jschar*)PromiseFlatString(str).get(),
|
||||
(uint32)str.Length());
|
||||
|
||||
// Since we've called JS_BeginJSONParse, we have to call JS_FinishJSONParse,
|
||||
// even if JS_ConsumeJSONText fails. But if either fails, we'll report an
|
||||
// error.
|
||||
ok &= JS_FinishJSONParse(cx, parser, JSVAL_NULL);
|
||||
|
||||
if (!ok) {
|
||||
if (!JS_ParseJSON(cx, (jschar*)PromiseFlatString(str).get(),
|
||||
(uint32)str.Length(), result)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
@ -558,20 +547,9 @@ nsJSON::LegacyDecodeToJSVal(const nsAString &str, JSContext *cx, jsval *result)
|
||||
{
|
||||
JSAutoRequest ar(cx);
|
||||
|
||||
JSONParser *parser = JS_BeginJSONParse(cx, result);
|
||||
NS_ENSURE_TRUE(parser, NS_ERROR_UNEXPECTED);
|
||||
|
||||
JSBool ok = js_ConsumeJSONText(cx, parser,
|
||||
(jschar*)PromiseFlatString(str).get(),
|
||||
(uint32)str.Length(),
|
||||
LEGACY);
|
||||
|
||||
// Since we've called JS_BeginJSONParse, we have to call JS_FinishJSONParse,
|
||||
// even if js_ConsumeJSONText fails. But if either fails, we'll report an
|
||||
// error.
|
||||
ok &= JS_FinishJSONParse(cx, parser, JSVAL_NULL);
|
||||
|
||||
if (!ok) {
|
||||
if (!js::ParseJSONWithReviver(cx, (jschar*)PromiseFlatString(str).get(),
|
||||
(uint32)str.Length(), js::NullValue(),
|
||||
js::Valueify(result), LEGACY)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
@ -595,7 +573,6 @@ nsJSONListener::nsJSONListener(JSContext *cx, jsval *rootVal,
|
||||
PRBool needsConverter,
|
||||
DecodingMode mode /* = STRICT */)
|
||||
: mNeedsConverter(needsConverter),
|
||||
mJSONParser(nsnull),
|
||||
mCx(cx),
|
||||
mRootVal(rootVal),
|
||||
mDecodingMode(mode)
|
||||
@ -604,7 +581,6 @@ nsJSONListener::nsJSONListener(JSContext *cx, jsval *rootVal,
|
||||
|
||||
nsJSONListener::~nsJSONListener()
|
||||
{
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsJSONListener)
|
||||
@ -621,9 +597,6 @@ nsJSONListener::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
|
||||
{
|
||||
mSniffBuffer.Truncate();
|
||||
mDecoder = nsnull;
|
||||
mJSONParser = JS_BeginJSONParse(mCx, mRootVal);
|
||||
if (!mJSONParser)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -640,13 +613,13 @@ nsJSONListener::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
JSBool ok = JS_FinishJSONParse(mCx, mJSONParser, JSVAL_NULL);
|
||||
mJSONParser = nsnull;
|
||||
|
||||
if (!ok)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
return NS_OK;
|
||||
const jschar* chars = reinterpret_cast<const jschar*>(mBufferedChars.Elements());
|
||||
JSBool ok = js::ParseJSONWithReviver(mCx, chars,
|
||||
(uint32) mBufferedChars.Length(),
|
||||
js::NullValue(), js::Valueify(mRootVal),
|
||||
mDecodingMode);
|
||||
mBufferedChars.TruncateLength(0);
|
||||
return ok ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -743,34 +716,23 @@ nsJSONListener::ConsumeConverted(const char* aBuffer, PRUint32 aByteLength)
|
||||
|
||||
rv = mDecoder->GetMaxLength(aBuffer, srcLen, &unicharLength);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsAutoArrayPtr<PRUnichar> ustr(new PRUnichar[unicharLength]);
|
||||
NS_ENSURE_TRUE(ustr, NS_ERROR_OUT_OF_MEMORY);
|
||||
rv = mDecoder->Convert(aBuffer, &srcLen, ustr, &unicharLength);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = Consume(ustr.get(), unicharLength);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void nsJSONListener::Cleanup()
|
||||
{
|
||||
if (mJSONParser)
|
||||
JS_FinishJSONParse(mCx, mJSONParser, JSVAL_NULL);
|
||||
mJSONParser = nsnull;
|
||||
PRUnichar* endelems = mBufferedChars.AppendElements(unicharLength);
|
||||
PRInt32 preLength = unicharLength;
|
||||
rv = mDecoder->Convert(aBuffer, &srcLen, endelems, &unicharLength);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
NS_ABORT_IF_FALSE(preLength >= unicharLength, "GetMaxLength lied");
|
||||
if (preLength > unicharLength)
|
||||
mBufferedChars.TruncateLength(mBufferedChars.Length() - (preLength - unicharLength));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsJSONListener::Consume(const PRUnichar* aBuffer, PRUint32 aByteLength)
|
||||
{
|
||||
if (!mJSONParser)
|
||||
if (!mBufferedChars.AppendElements(aBuffer, aByteLength))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (!js_ConsumeJSONText(mCx, mJSONParser, (jschar*) aBuffer, aByteLength,
|
||||
mDecodingMode)) {
|
||||
Cleanup();
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -111,16 +111,15 @@ public:
|
||||
|
||||
protected:
|
||||
PRBool mNeedsConverter;
|
||||
JSONParser *mJSONParser;
|
||||
JSContext *mCx;
|
||||
jsval *mRootVal;
|
||||
nsCOMPtr<nsIUnicodeDecoder> mDecoder;
|
||||
nsCString mSniffBuffer;
|
||||
nsTArray<PRUnichar> mBufferedChars;
|
||||
DecodingMode mDecodingMode;
|
||||
nsresult ProcessBytes(const char* aBuffer, PRUint32 aByteLength);
|
||||
nsresult ConsumeConverted(const char* aBuffer, PRUint32 aByteLength);
|
||||
nsresult Consume(const PRUnichar *data, PRUint32 len);
|
||||
void Cleanup();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1 +0,0 @@
|
||||
"Unterminated string literal
|
@ -1 +0,0 @@
|
||||
{"Extra value after close": true} "misplaced quoted value"
|
@ -1 +0,0 @@
|
||||
{"Illegal expression": 1 + 2}
|
@ -1 +0,0 @@
|
||||
{"Illegal invocation": alert()}
|
@ -1 +0,0 @@
|
||||
{"Numbers cannot have leading zeroes": 013}
|
@ -1 +0,0 @@
|
||||
{"Numbers cannot be hex": 0x14}
|
@ -1 +0,0 @@
|
||||
["Illegal backslash escape: \x15"]
|
@ -1 +0,0 @@
|
||||
[\naked]
|
@ -1 +0,0 @@
|
||||
["Illegal backslash escape: \017"]
|
@ -1 +0,0 @@
|
||||
[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]
|
@ -1 +0,0 @@
|
||||
{"Missing colon" null}
|
@ -1 +0,0 @@
|
||||
["Unclosed array"
|
@ -1 +0,0 @@
|
||||
{"Double colon":: null}
|
@ -1 +0,0 @@
|
||||
{"Comma instead of colon", null}
|
@ -1 +0,0 @@
|
||||
["Colon instead of comma": false]
|
@ -1 +0,0 @@
|
||||
["Bad value", truth]
|
@ -1 +0,0 @@
|
||||
['single quote']
|
@ -1 +0,0 @@
|
||||
[" tab character in string "]
|
@ -1 +0,0 @@
|
||||
["tab\ character\ in\ string\ "]
|
@ -1,2 +0,0 @@
|
||||
["line
|
||||
break"]
|
@ -1,2 +0,0 @@
|
||||
["line\
|
||||
break"]
|
@ -1 +0,0 @@
|
||||
[0e]
|
@ -1 +0,0 @@
|
||||
{unquoted_key: "keys must be quoted"}
|
@ -1 +0,0 @@
|
||||
[0e+]
|
@ -1 +0,0 @@
|
||||
[0e+-1]
|
@ -1 +0,0 @@
|
||||
{"Comma instead if closing brace": true,
|
@ -1 +0,0 @@
|
||||
["mismatch"}
|
@ -1 +0,0 @@
|
||||
0{
|
@ -1 +0,0 @@
|
||||
["extra comma",]
|
@ -1 +0,0 @@
|
||||
["double extra comma",,]
|
@ -1 +0,0 @@
|
||||
[ , "<-- missing value"]
|
@ -1 +0,0 @@
|
||||
["Comma after the close"],
|
@ -1 +0,0 @@
|
||||
["Extra close"]]
|
@ -1 +0,0 @@
|
||||
{"Extra comma": true,}
|
@ -1,19 +0,0 @@
|
||||
var Ci = Components.interfaces;
|
||||
var Cc = Components.classes;
|
||||
|
||||
var nativeJSON = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
|
||||
var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
|
||||
var workingDir = dirSvc.get("TmpD", Ci.nsIFile);
|
||||
|
||||
var outputName = "json-test-output";
|
||||
var outputDir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
||||
outputDir.initWithFile(workingDir);
|
||||
outputDir.append(outputName);
|
||||
|
||||
if (!outputDir.exists()) {
|
||||
outputDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0777);
|
||||
} else if (!outputDir.isDirectory()) {
|
||||
do_throw(outputName + " is not a directory?")
|
||||
}
|
||||
var crockfordJSON = null;
|
||||
load("json2.js");
|
@ -1,479 +0,0 @@
|
||||
/*
|
||||
http://www.JSON.org/json2.js
|
||||
2008-11-19
|
||||
|
||||
Public Domain.
|
||||
|
||||
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
||||
|
||||
See http://www.JSON.org/js.html
|
||||
|
||||
This file creates a global JSON object containing two methods: stringify
|
||||
and parse.
|
||||
|
||||
JSON.stringify(value, replacer, space)
|
||||
value any JavaScript value, usually an object or array.
|
||||
|
||||
replacer an optional parameter that determines how object
|
||||
values are stringified for objects. It can be a
|
||||
function or an array of strings.
|
||||
|
||||
space an optional parameter that specifies the indentation
|
||||
of nested structures. If it is omitted, the text will
|
||||
be packed without extra whitespace. If it is a number,
|
||||
it will specify the number of spaces to indent at each
|
||||
level. If it is a string (such as '\t' or ' '),
|
||||
it contains the characters used to indent at each level.
|
||||
|
||||
This method produces a JSON text from a JavaScript value.
|
||||
|
||||
When an object value is found, if the object contains a toJSON
|
||||
method, its toJSON method will be called and the result will be
|
||||
stringified. A toJSON method does not serialize: it returns the
|
||||
value represented by the name/value pair that should be serialized,
|
||||
or undefined if nothing should be serialized. The toJSON method
|
||||
will be passed the key associated with the value, and this will be
|
||||
bound to the object holding the key.
|
||||
|
||||
For example, this would serialize Dates as ISO strings.
|
||||
|
||||
Date.prototype.toJSON = function (key) {
|
||||
function f(n) {
|
||||
// Format integers to have at least two digits.
|
||||
return n < 10 ? '0' + n : n;
|
||||
}
|
||||
|
||||
return this.getUTCFullYear() + '-' +
|
||||
f(this.getUTCMonth() + 1) + '-' +
|
||||
f(this.getUTCDate()) + 'T' +
|
||||
f(this.getUTCHours()) + ':' +
|
||||
f(this.getUTCMinutes()) + ':' +
|
||||
f(this.getUTCSeconds()) + 'Z';
|
||||
};
|
||||
|
||||
You can provide an optional replacer method. It will be passed the
|
||||
key and value of each member, with this bound to the containing
|
||||
object. The value that is returned from your method will be
|
||||
serialized. If your method returns undefined, then the member will
|
||||
be excluded from the serialization.
|
||||
|
||||
If the replacer parameter is an array of strings, then it will be
|
||||
used to select the members to be serialized. It filters the results
|
||||
such that only members with keys listed in the replacer array are
|
||||
stringified.
|
||||
|
||||
Values that do not have JSON representations, such as undefined or
|
||||
functions, will not be serialized. Such values in objects will be
|
||||
dropped; in arrays they will be replaced with null. You can use
|
||||
a replacer function to replace those with JSON values.
|
||||
JSON.stringify(undefined) returns undefined.
|
||||
|
||||
The optional space parameter produces a stringification of the
|
||||
value that is filled with line breaks and indentation to make it
|
||||
easier to read.
|
||||
|
||||
If the space parameter is a non-empty string, then that string will
|
||||
be used for indentation. If the space parameter is a number, then
|
||||
the indentation will be that many spaces.
|
||||
|
||||
Example:
|
||||
|
||||
text = JSON.stringify(['e', {pluribus: 'unum'}]);
|
||||
// text is '["e",{"pluribus":"unum"}]'
|
||||
|
||||
|
||||
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
|
||||
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
|
||||
|
||||
text = JSON.stringify([new Date()], function (key, value) {
|
||||
return this[key] instanceof Date ?
|
||||
'Date(' + this[key] + ')' : value;
|
||||
});
|
||||
// text is '["Date(---current time---)"]'
|
||||
|
||||
|
||||
JSON.parse(text, reviver)
|
||||
This method parses a JSON text to produce an object or array.
|
||||
It can throw a SyntaxError exception.
|
||||
|
||||
The optional reviver parameter is a function that can filter and
|
||||
transform the results. It receives each of the keys and values,
|
||||
and its return value is used instead of the original value.
|
||||
If it returns what it received, then the structure is not modified.
|
||||
If it returns undefined then the member is deleted.
|
||||
|
||||
Example:
|
||||
|
||||
// Parse the text. Values that look like ISO date strings will
|
||||
// be converted to Date objects.
|
||||
|
||||
myData = JSON.parse(text, function (key, value) {
|
||||
var a;
|
||||
if (typeof value === 'string') {
|
||||
a =
|
||||
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
|
||||
if (a) {
|
||||
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
|
||||
+a[5], +a[6]));
|
||||
}
|
||||
}
|
||||
return value;
|
||||
});
|
||||
|
||||
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
|
||||
var d;
|
||||
if (typeof value === 'string' &&
|
||||
value.slice(0, 5) === 'Date(' &&
|
||||
value.slice(-1) === ')') {
|
||||
d = new Date(value.slice(5, -1));
|
||||
if (d) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
});
|
||||
|
||||
|
||||
This is a reference implementation. You are free to copy, modify, or
|
||||
redistribute.
|
||||
|
||||
This code should be minified before deployment.
|
||||
See http://javascript.crockford.com/jsmin.html
|
||||
|
||||
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
|
||||
NOT CONTROL.
|
||||
*/
|
||||
|
||||
/*jslint evil: true */
|
||||
|
||||
/*global JSON */
|
||||
|
||||
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
|
||||
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
|
||||
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
|
||||
lastIndex, length, parse, prototype, push, replace, slice, stringify,
|
||||
test, toJSON, toString, valueOf
|
||||
*/
|
||||
|
||||
// Create a JSON object only if one does not already exist. We create the
|
||||
// methods in a closure to avoid creating global variables.
|
||||
|
||||
if (!this.crockfordJSON) {
|
||||
crockfordJSON = {};
|
||||
crockfordJSON.window = this;
|
||||
}
|
||||
(function () {
|
||||
|
||||
function f(n) {
|
||||
// Format integers to have at least two digits.
|
||||
return n < 10 ? '0' + n : n;
|
||||
}
|
||||
|
||||
if (typeof Date.prototype.toJSON !== 'function') {
|
||||
|
||||
Date.prototype.toJSON = function (key) {
|
||||
|
||||
return this.getUTCFullYear() + '-' +
|
||||
f(this.getUTCMonth() + 1) + '-' +
|
||||
f(this.getUTCDate()) + 'T' +
|
||||
f(this.getUTCHours()) + ':' +
|
||||
f(this.getUTCMinutes()) + ':' +
|
||||
f(this.getUTCSeconds()) + 'Z';
|
||||
};
|
||||
|
||||
String.prototype.toJSON =
|
||||
Number.prototype.toJSON =
|
||||
Boolean.prototype.toJSON = function (key) {
|
||||
return this.valueOf();
|
||||
};
|
||||
}
|
||||
|
||||
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||
gap,
|
||||
indent,
|
||||
meta = { // table of character substitutions
|
||||
'\b': '\\b',
|
||||
'\t': '\\t',
|
||||
'\n': '\\n',
|
||||
'\f': '\\f',
|
||||
'\r': '\\r',
|
||||
'"' : '\\"',
|
||||
'\\': '\\\\'
|
||||
},
|
||||
rep;
|
||||
|
||||
|
||||
function quote(string) {
|
||||
|
||||
// If the string contains no control characters, no quote characters, and no
|
||||
// backslash characters, then we can safely slap some quotes around it.
|
||||
// Otherwise we must also replace the offending characters with safe escape
|
||||
// sequences.
|
||||
|
||||
escapable.lastIndex = 0;
|
||||
return escapable.test(string) ?
|
||||
'"' + string.replace(escapable, function (a) {
|
||||
var c = meta[a];
|
||||
return typeof c === 'string' ? c :
|
||||
'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
||||
}) + '"' :
|
||||
'"' + string + '"';
|
||||
}
|
||||
|
||||
|
||||
function str(key, holder) {
|
||||
|
||||
// Produce a string from holder[key].
|
||||
|
||||
var i, // The loop counter.
|
||||
k, // The member key.
|
||||
v, // The member value.
|
||||
length,
|
||||
mind = gap,
|
||||
partial,
|
||||
value = holder[key];
|
||||
|
||||
// If the value has a toJSON method, call it to obtain a replacement value.
|
||||
|
||||
if (value && typeof value === 'object' &&
|
||||
typeof value.toJSON === 'function') {
|
||||
value = value.toJSON(key);
|
||||
}
|
||||
|
||||
// If we were called with a replacer function, then call the replacer to
|
||||
// obtain a replacement value.
|
||||
|
||||
if (typeof rep === 'function') {
|
||||
value = rep.call(holder, key, value);
|
||||
}
|
||||
|
||||
// What happens next depends on the value's type.
|
||||
|
||||
switch (typeof value) {
|
||||
case 'string':
|
||||
return quote(value);
|
||||
|
||||
case 'number':
|
||||
|
||||
// JSON numbers must be finite. Encode non-finite numbers as null.
|
||||
|
||||
return isFinite(value) ? String(value) : 'null';
|
||||
|
||||
case 'boolean':
|
||||
case 'null':
|
||||
|
||||
// If the value is a boolean or null, convert it to a string. Note:
|
||||
// typeof null does not produce 'null'. The case is included here in
|
||||
// the remote chance that this gets fixed someday.
|
||||
|
||||
return String(value);
|
||||
|
||||
// If the type is 'object', we might be dealing with an object or an array or
|
||||
// null.
|
||||
|
||||
case 'object':
|
||||
|
||||
// Due to a specification blunder in ECMAScript, typeof null is 'object',
|
||||
// so watch out for that case.
|
||||
|
||||
if (!value) {
|
||||
return 'null';
|
||||
}
|
||||
|
||||
// Make an array to hold the partial results of stringifying this object value.
|
||||
|
||||
gap += indent;
|
||||
partial = [];
|
||||
|
||||
// Is the value an array?
|
||||
|
||||
if (Object.prototype.toString.apply(value) === '[object Array]') {
|
||||
|
||||
// The value is an array. Stringify every element. Use null as a placeholder
|
||||
// for non-JSON values.
|
||||
|
||||
length = value.length;
|
||||
for (i = 0; i < length; i += 1) {
|
||||
partial[i] = str(i, value) || 'null';
|
||||
}
|
||||
|
||||
// Join all of the elements together, separated with commas, and wrap them in
|
||||
// brackets.
|
||||
|
||||
v = partial.length === 0 ? '[]' :
|
||||
gap ? '[\n' + gap +
|
||||
partial.join(',\n' + gap) + '\n' +
|
||||
mind + ']' :
|
||||
'[' + partial.join(',') + ']';
|
||||
gap = mind;
|
||||
return v;
|
||||
}
|
||||
|
||||
// If the replacer is an array, use it to select the members to be stringified.
|
||||
|
||||
if (rep && typeof rep === 'object') {
|
||||
length = rep.length;
|
||||
for (i = 0; i < length; i += 1) {
|
||||
k = rep[i];
|
||||
if (typeof k === 'string') {
|
||||
v = str(k, value);
|
||||
if (v) {
|
||||
partial.push(quote(k) + (gap ? ': ' : ':') + v);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
// Otherwise, iterate through all of the keys in the object.
|
||||
|
||||
for (k in value) {
|
||||
if (Object.hasOwnProperty.call(value, k)) {
|
||||
v = str(k, value);
|
||||
if (v) {
|
||||
partial.push(quote(k) + (gap ? ': ' : ':') + v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Join all of the member texts together, separated with commas,
|
||||
// and wrap them in braces.
|
||||
|
||||
v = partial.length === 0 ? '{}' :
|
||||
gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
|
||||
mind + '}' : '{' + partial.join(',') + '}';
|
||||
gap = mind;
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
// If the JSON object does not yet have a stringify method, give it one.
|
||||
|
||||
if (typeof crockfordJSON.stringify !== 'function') {
|
||||
crockfordJSON.stringify = function (value, replacer, space) {
|
||||
|
||||
// The stringify method takes a value and an optional replacer, and an optional
|
||||
// space parameter, and returns a JSON text. The replacer can be a function
|
||||
// that can replace values, or an array of strings that will select the keys.
|
||||
// A default replacer method can be provided. Use of the space parameter can
|
||||
// produce text that is more easily readable.
|
||||
|
||||
var i;
|
||||
gap = '';
|
||||
indent = '';
|
||||
|
||||
// If the space parameter is a number, make an indent string containing that
|
||||
// many spaces.
|
||||
|
||||
if (typeof space === 'number') {
|
||||
for (i = 0; i < space; i += 1) {
|
||||
indent += ' ';
|
||||
}
|
||||
|
||||
// If the space parameter is a string, it will be used as the indent string.
|
||||
|
||||
} else if (typeof space === 'string') {
|
||||
indent = space;
|
||||
}
|
||||
|
||||
// If there is a replacer, it must be a function or an array.
|
||||
// Otherwise, throw an error.
|
||||
|
||||
rep = replacer;
|
||||
if (replacer && typeof replacer !== 'function' &&
|
||||
(typeof replacer !== 'object' ||
|
||||
typeof replacer.length !== 'number')) {
|
||||
throw new Error('JSON.stringify');
|
||||
}
|
||||
|
||||
// Make a fake root object containing our value under the key of ''.
|
||||
// Return the result of stringifying the value.
|
||||
|
||||
return str('', {'': value});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// If the JSON object does not yet have a parse method, give it one.
|
||||
|
||||
if (typeof crockfordJSON.parse !== 'function') {
|
||||
crockfordJSON.parse = function (text, reviver) {
|
||||
|
||||
// The parse method takes a text and an optional reviver function, and returns
|
||||
// a JavaScript value if the text is a valid JSON text.
|
||||
|
||||
var j;
|
||||
|
||||
function walk(holder, key) {
|
||||
|
||||
// The walk method is used to recursively walk the resulting structure so
|
||||
// that modifications can be made.
|
||||
|
||||
var k, v, value = holder[key];
|
||||
if (value && typeof value === 'object') {
|
||||
for (k in value) {
|
||||
if (Object.hasOwnProperty.call(value, k)) {
|
||||
v = walk(value, k);
|
||||
if (v !== undefined) {
|
||||
value[k] = v;
|
||||
} else {
|
||||
delete value[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return reviver.call(holder, key, value);
|
||||
}
|
||||
|
||||
|
||||
// Parsing happens in four stages. In the first stage, we replace certain
|
||||
// Unicode characters with escape sequences. JavaScript handles many characters
|
||||
// incorrectly, either silently deleting them, or treating them as line endings.
|
||||
|
||||
cx.lastIndex = 0;
|
||||
if (cx.test(text)) {
|
||||
text = text.replace(cx, function (a) {
|
||||
return '\\u' +
|
||||
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
||||
});
|
||||
}
|
||||
|
||||
// In the second stage, we run the text against regular expressions that look
|
||||
// for non-JSON patterns. We are especially concerned with '()' and 'new'
|
||||
// because they can cause invocation, and '=' because it can cause mutation.
|
||||
// But just to be safe, we want to reject all unexpected forms.
|
||||
|
||||
// We split the second stage into 4 regexp operations in order to work around
|
||||
// crippling inefficiencies in IE's and Safari's regexp engines. First we
|
||||
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
|
||||
// replace all simple value tokens with ']' characters. Third, we delete all
|
||||
// open brackets that follow a colon or comma or that begin the text. Finally,
|
||||
// we look to see that the remaining characters are only whitespace or ']' or
|
||||
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
|
||||
|
||||
if (/^[\],:{}\s]*$/.
|
||||
test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
|
||||
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
|
||||
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
|
||||
|
||||
// In the third stage we use the eval function to compile the text into a
|
||||
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
|
||||
// in JavaScript: it can begin a block or an object literal. We wrap the text
|
||||
// in parens to eliminate the ambiguity.
|
||||
|
||||
j = eval('(' + text + ')');
|
||||
|
||||
// In the optional fourth stage, we recursively walk the new structure, passing
|
||||
// each name/value pair to a reviver function for possible transformation.
|
||||
|
||||
return typeof reviver === 'function' ?
|
||||
walk({'': j}, '') : j;
|
||||
}
|
||||
|
||||
// If the text is not JSON parseable, then a SyntaxError is thrown.
|
||||
|
||||
throw new SyntaxError('JSON.parse');
|
||||
};
|
||||
}
|
||||
})();
|
@ -1,58 +0,0 @@
|
||||
[
|
||||
"JSON Test Pattern pass1",
|
||||
{"object with 1 member":["array with 1 element"]},
|
||||
{},
|
||||
[],
|
||||
-42,
|
||||
true,
|
||||
false,
|
||||
null,
|
||||
{
|
||||
"integer": 1234567890,
|
||||
"real": -9876.543210,
|
||||
"e": 0.123456789e-12,
|
||||
"E": 1.234567890E+34,
|
||||
"": 23456789012E66,
|
||||
"zero": 0,
|
||||
"one": 1,
|
||||
"space": " ",
|
||||
"quote": "\"",
|
||||
"backslash": "\\",
|
||||
"controls": "\b\f\n\r\t",
|
||||
"slash": "/ & \/",
|
||||
"alpha": "abcdefghijklmnopqrstuvwyz",
|
||||
"ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
|
||||
"digit": "0123456789",
|
||||
"0123456789": "digit",
|
||||
"special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
|
||||
"hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
|
||||
"true": true,
|
||||
"false": false,
|
||||
"null": null,
|
||||
"array":[ ],
|
||||
"object":{ },
|
||||
"address": "50 St. James Street",
|
||||
"url": "http://www.JSON.org/",
|
||||
"comment": "// /* <!-- --",
|
||||
"# -- --> */": " ",
|
||||
" s p a c e d " :[1,2 , 3
|
||||
|
||||
,
|
||||
|
||||
4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7],
|
||||
"jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
|
||||
"quotes": "" \u0022 %22 0x22 034 "",
|
||||
"\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
|
||||
: "A key can be any string"
|
||||
},
|
||||
0.5 ,98.6
|
||||
,
|
||||
99.44
|
||||
,
|
||||
|
||||
1066,
|
||||
1e1,
|
||||
0.1e1,
|
||||
1e-1,
|
||||
1e00,2e+00,2e-00
|
||||
,"rosebud"]
|
@ -1,196 +0,0 @@
|
||||
function decode_strings() {
|
||||
// empty object
|
||||
var x = nativeJSON.decode("{}");
|
||||
do_check_eq(typeof x, "object");
|
||||
|
||||
// empty array
|
||||
x = nativeJSON.decode("[]");
|
||||
do_check_eq(typeof x, "object");
|
||||
do_check_eq(x.length, 0);
|
||||
do_check_eq(x.constructor, Array);
|
||||
|
||||
// one element array
|
||||
x = nativeJSON.decode("[[]]");
|
||||
do_check_eq(typeof x, "object");
|
||||
do_check_eq(x.length, 1);
|
||||
do_check_eq(x.constructor, Array);
|
||||
do_check_eq(x[0].constructor, Array);
|
||||
|
||||
// multiple arrays
|
||||
x = nativeJSON.decode("[[],[],[]]");
|
||||
do_check_eq(typeof x, "object");
|
||||
do_check_eq(x.length, 3);
|
||||
do_check_eq(x.constructor, Array);
|
||||
do_check_eq(x[0].constructor, Array);
|
||||
do_check_eq(x[1].constructor, Array);
|
||||
do_check_eq(x[2].constructor, Array);
|
||||
|
||||
// array key/value
|
||||
x = nativeJSON.decode('{"foo":[]}');
|
||||
do_check_eq(typeof x, "object");
|
||||
do_check_eq(typeof x.foo, "object");
|
||||
do_check_eq(x.foo.constructor, Array);
|
||||
x = nativeJSON.decode('{"foo":[], "bar":[]}');
|
||||
do_check_eq(typeof x, "object");
|
||||
do_check_eq(typeof x.foo, "object");
|
||||
do_check_eq(x.foo.constructor, Array);
|
||||
do_check_eq(typeof x.bar, "object");
|
||||
do_check_eq(x.bar.constructor, Array);
|
||||
|
||||
// nesting
|
||||
x = nativeJSON.decode('{"foo":[{}]}');
|
||||
do_check_eq(x.foo.constructor, Array);
|
||||
do_check_eq(x.foo.length, 1);
|
||||
do_check_eq(typeof x.foo[0], "object");
|
||||
x = nativeJSON.decode('{"foo":[{"foo":[{"foo":{}}]}]}');
|
||||
do_check_eq(x.foo[0].foo[0].foo.constructor, Object);
|
||||
x = nativeJSON.decode('{"foo":[{"foo":[{"foo":[]}]}]}');
|
||||
do_check_eq(x.foo[0].foo[0].foo.constructor, Array);
|
||||
|
||||
// strings
|
||||
x = nativeJSON.decode('{"foo":"bar"}');
|
||||
do_check_eq(x.foo, "bar");
|
||||
x = nativeJSON.decode('["foo", "bar", "baz"]');
|
||||
do_check_eq(x[0], "foo");
|
||||
do_check_eq(x[1], "bar");
|
||||
do_check_eq(x[2], "baz");
|
||||
|
||||
// numbers
|
||||
x = nativeJSON.decode('{"foo":5.5, "bar":5}');
|
||||
do_check_eq(x.foo, 5.5);
|
||||
do_check_eq(x.bar, 5);
|
||||
|
||||
// keywords
|
||||
x = nativeJSON.decode('{"foo": true, "bar":false, "baz":null}');
|
||||
do_check_eq(x.foo, true);
|
||||
do_check_eq(x.bar, false);
|
||||
do_check_eq(x.baz, null);
|
||||
|
||||
// short escapes
|
||||
x = nativeJSON.decode('{"foo": "\\"", "bar":"\\\\", "baz":"\\b","qux":"\\f", "quux":"\\n", "quuux":"\\r","quuuux":"\\t"}');
|
||||
do_check_eq(x.foo, '"');
|
||||
do_check_eq(x.bar, '\\');
|
||||
do_check_eq(x.baz, '\b');
|
||||
do_check_eq(x.qux, '\f');
|
||||
do_check_eq(x.quux, "\n");
|
||||
do_check_eq(x.quuux, "\r");
|
||||
do_check_eq(x.quuuux, "\t");
|
||||
|
||||
// unicode escape
|
||||
x = nativeJSON.decode('{"foo":"hmm\\u006dmm"}');
|
||||
do_check_eq("hmm\u006dmm", x.foo);
|
||||
|
||||
x = nativeJSON.decode('{"JSON Test Pattern pass3": {"The outermost value": "must be an object or array.","In this test": "It is an object." }}');
|
||||
}
|
||||
|
||||
function test_files() {
|
||||
function read_file(path) {
|
||||
try {
|
||||
var f = do_get_file(path);
|
||||
var istream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
|
||||
istream.init(f, -1, -1, false);
|
||||
var x = nativeJSON.decodeFromStream(istream, istream.available());
|
||||
} finally {
|
||||
istream.close();
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
var x = read_file("pass3.json");
|
||||
do_check_eq(x["JSON Test Pattern pass3"]["The outermost value"], "must be an object or array.");
|
||||
do_check_eq(x["JSON Test Pattern pass3"]["In this test"], "It is an object.");
|
||||
|
||||
x = read_file("pass1.json");
|
||||
do_check_eq(x[0], "JSON Test Pattern pass1");
|
||||
do_check_eq(x[1]["object with 1 member"][0], "array with 1 element");
|
||||
do_check_eq(x[2].constructor, Object);
|
||||
do_check_eq(x[3].constructor, Array);
|
||||
do_check_eq(x[4], -42);
|
||||
do_check_eq(x[5], true);
|
||||
do_check_eq(x[6], false);
|
||||
do_check_eq(x[7], null);
|
||||
do_check_eq(x[8].constructor, Object);
|
||||
do_check_eq(x[8]["integer"], 1234567890);
|
||||
do_check_eq(x[8]["real"], -9876.543210);
|
||||
do_check_eq(x[8]["e"], 0.123456789e-12);
|
||||
do_check_eq(x[8]["E"], 1.234567890E+34);
|
||||
do_check_eq(x[8][""], 23456789012E66);
|
||||
do_check_eq(x[8]["zero"], 0);
|
||||
do_check_eq(x[8]["one"], 1);
|
||||
do_check_eq(x[8]["space"], " ");
|
||||
do_check_eq(x[8]["quote"], "\"");
|
||||
do_check_eq(x[8]["backslash"], "\\");
|
||||
do_check_eq(x[8]["controls"], "\b\f\n\r\t");
|
||||
do_check_eq(x[8]["slash"], "/ & /");
|
||||
do_check_eq(x[8]["alpha"], "abcdefghijklmnopqrstuvwyz");
|
||||
do_check_eq(x[8]["ALPHA"], "ABCDEFGHIJKLMNOPQRSTUVWYZ");
|
||||
do_check_eq(x[8]["digit"], "0123456789");
|
||||
do_check_eq(x[8]["0123456789"], "digit");
|
||||
do_check_eq(x[8]["special"], "`1~!@#$%^&*()_+-={':[,]}|;.</>?");
|
||||
do_check_eq(x[8]["hex"], "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A");
|
||||
do_check_eq(x[8]["true"], true);
|
||||
do_check_eq(x[8]["false"], false);
|
||||
do_check_eq(x[8]["null"], null);
|
||||
do_check_eq(x[8]["array"].length, 0);
|
||||
do_check_eq(x[8]["object"].constructor, Object);
|
||||
do_check_eq(x[8]["address"], "50 St. James Street");
|
||||
do_check_eq(x[8]["url"], "http://www.JSON.org/");
|
||||
do_check_eq(x[8]["comment"], "// /* <!-- --");
|
||||
do_check_eq(x[8]["# -- --> */"], " ");
|
||||
do_check_eq(x[8][" s p a c e d "].length, 7);
|
||||
do_check_eq(x[8]["compact"].length, 7);
|
||||
do_check_eq(x[8]["jsontext"], "{\"object with 1 member\":[\"array with 1 element\"]}");
|
||||
do_check_eq(x[8]["quotes"], "" \u0022 %22 0x22 034 "");
|
||||
do_check_eq(x[8]["\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"], "A key can be any string");
|
||||
do_check_eq(x[9], 0.5);
|
||||
do_check_eq(x[10], 98.6);
|
||||
do_check_eq(x[11], 99.44);
|
||||
do_check_eq(x[12], 1066);
|
||||
do_check_eq(x[13], 1e1);
|
||||
do_check_eq(x[14], 0.1e1);
|
||||
do_check_eq(x[15], 1e-1);
|
||||
do_check_eq(x[16], 1e00);
|
||||
do_check_eq(x[17], 2e+00);
|
||||
do_check_eq(x[18], 2e-00);
|
||||
do_check_eq(x[19], "rosebud");
|
||||
|
||||
// test invalid input
|
||||
//
|
||||
// We allow some minor JSON infractions, like trailing commas
|
||||
// Those are special-cased below, leaving the original sequence
|
||||
// of failure's from Crockford intact.
|
||||
//
|
||||
// Section 4 of RFC 4627 allows this tolerance.
|
||||
//
|
||||
for (var i = 1; i <= 34; ++i) {
|
||||
var path = "fail" + i + ".json";
|
||||
try {
|
||||
dump(path +"\n");
|
||||
x = read_file(path);
|
||||
if (i == 13) {
|
||||
// {"Numbers cannot have leading zeroes": 013}
|
||||
do_check_eq(x["Numbers cannot have leading zeroes"], 13);
|
||||
} else if (i == 18) {
|
||||
// [[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]
|
||||
var t = x[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0];
|
||||
do_check_eq(t, "Too deep");
|
||||
} else {
|
||||
|
||||
do_throw("UNREACHED");
|
||||
|
||||
}
|
||||
|
||||
} catch (ex) {
|
||||
// expected from parsing invalid JSON
|
||||
if (i == 13 || i == 18) {
|
||||
do_throw("Unexpected pass in " + path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
decode_strings();
|
||||
test_files();
|
||||
}
|
26
dom/src/json/test/unit/test_decodeFromStream.js
Normal file
26
dom/src/json/test/unit/test_decodeFromStream.js
Normal file
@ -0,0 +1,26 @@
|
||||
var Ci = Components.interfaces;
|
||||
var Cc = Components.classes;
|
||||
|
||||
var nativeJSON = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
|
||||
|
||||
function run_test()
|
||||
{
|
||||
function read_file(path)
|
||||
{
|
||||
try
|
||||
{
|
||||
var f = do_get_file(path);
|
||||
var istream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
|
||||
istream.init(f, -1, -1, false);
|
||||
return nativeJSON.decodeFromStream(istream, istream.available());
|
||||
}
|
||||
finally
|
||||
{
|
||||
istream.close();
|
||||
}
|
||||
}
|
||||
|
||||
var x = read_file("decodeFromStream-01.json");
|
||||
do_check_eq(x["JSON Test Pattern pass3"]["The outermost value"], "must be an object or array.");
|
||||
do_check_eq(x["JSON Test Pattern pass3"]["In this test"], "It is an object.");
|
||||
}
|
@ -1,4 +1,8 @@
|
||||
// This tests breaking long input across parser buffers
|
||||
var Ci = Components.interfaces;
|
||||
var Cc = Components.classes;
|
||||
|
||||
var nativeJSON = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
|
||||
|
||||
var x = {"Lorem ipsum his ponderum delicatissimi ne, at noster dolores urbanitas pro, cibo elaboraret no his. Ea dicunt maiorum usu. Ad appareat facilisis mediocritatem eos. Tale graeci mentitum in eos, hinc insolens at nam. Graecis nominavi aliquyam eu vix.":"Id solet assentior sadipscing pro. Et per atqui graecis, usu quot viris repudiandae ei, mollis evertitur an nam. At nam dolor ignota, liber labore omnesque ea mei, has movet voluptaria in. Vel an impetus omittantur. Vim movet option salutandi ex, ne mei ignota corrumpit. Mucius comprehensam id per. Est ea putant maiestatis.",
|
||||
"2Lorem ipsum his ponderum delicatissimi ne, at noster dolores urbanitas pro, cibo elaboraret no his. Ea dicunt maiorum usu. Ad appareat facilisis mediocritatem eos. Tale graeci mentitum in eos, hinc insolens at nam. Graecis nominavi aliquyam eu vix.":"Id solet assentior sadipscing pro. Et per atqui graecis, usu quot viris repudiandae ei, mollis evertitur an nam. At nam dolor ignota, liber labore omnesque ea mei, has movet voluptaria in. Vel an impetus omittantur. Vim movet option salutandi ex, ne mei ignota corrumpit. Mucius comprehensam id per. Est ea putant maiestatis.",
|
||||
@ -21,8 +25,8 @@ var x = {"Lorem ipsum his ponderum delicatissimi ne, at noster dolores urbanitas
|
||||
var y = nativeJSON.encode(x);
|
||||
var z = nativeJSON.decode(y);
|
||||
|
||||
function run_test() {
|
||||
for (var i in x) {
|
||||
do_check_eq(x[i], z[i]);
|
||||
}
|
||||
function run_test()
|
||||
{
|
||||
for (var i in x)
|
||||
do_check_eq(x[i], z[i]);
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
function parse_primitives() {
|
||||
|
||||
print("parse object");
|
||||
// check an empty object, just for sanity
|
||||
var emptyObject = "{}";
|
||||
var x = nativeJSON.decode(emptyObject);
|
||||
do_check_eq(typeof x, "object");
|
||||
print("parse object 2");
|
||||
|
||||
x = JSON.parse(emptyObject);
|
||||
do_check_eq(typeof x, "object");
|
||||
|
||||
print("parse object 3");
|
||||
x = crockfordJSON.parse(emptyObject);
|
||||
do_check_eq(typeof x, "object");
|
||||
|
||||
// booleans and null
|
||||
print("parse bool");
|
||||
x = JSON.parse("true");
|
||||
do_check_eq(typeof x, "boolean");
|
||||
do_check_eq(x, true);
|
||||
|
||||
print("parse bool with space")
|
||||
x = JSON.parse("true ");
|
||||
do_check_eq(typeof x, "boolean");
|
||||
do_check_eq(x, true);
|
||||
|
||||
print("parse false");
|
||||
x = JSON.parse("false");
|
||||
do_check_eq(typeof x, "boolean");
|
||||
do_check_eq(x, false);
|
||||
|
||||
print("parse null");
|
||||
x = JSON.parse(" null ");
|
||||
do_check_eq(typeof x, "object");
|
||||
do_check_eq(x, null);
|
||||
|
||||
// numbers
|
||||
print("parse numbers")
|
||||
x = JSON.parse("1234567890");
|
||||
do_check_eq(typeof x, "number");
|
||||
do_check_eq(x, 1234567890);
|
||||
|
||||
x = JSON.parse("-9876.543210");
|
||||
do_check_eq(typeof x, "number");
|
||||
do_check_eq(x, -9876.543210);
|
||||
|
||||
x = JSON.parse("0.123456789e-12");
|
||||
do_check_eq(typeof x, "number");
|
||||
do_check_eq(x, 0.123456789e-12);
|
||||
|
||||
x = JSON.parse("1.234567890E+34");
|
||||
do_check_eq(typeof x, "number");
|
||||
do_check_eq(x, 1.234567890E+34);
|
||||
|
||||
x = JSON.parse(" 23456789012E66 \r\r\r\r \n\n\n\n ");
|
||||
do_check_eq(typeof x, "number");
|
||||
do_check_eq(x, 23456789012E66);
|
||||
|
||||
// strings
|
||||
x = crockfordJSON.parse('"foo"');
|
||||
do_check_eq(typeof x, "string");
|
||||
do_check_eq(x, "foo");
|
||||
x = JSON.parse('"foo"');
|
||||
do_check_eq(typeof x, "string");
|
||||
do_check_eq(x, "foo");
|
||||
|
||||
x = JSON.parse('"\\r\\n"');
|
||||
do_check_eq(typeof x, "string");
|
||||
do_check_eq(x, "\r\n");
|
||||
|
||||
x = JSON.parse('"\\uabcd\uef4A"');
|
||||
do_check_eq(typeof x, "string");
|
||||
do_check_eq(x, "\uabcd\uef4A");
|
||||
|
||||
x = JSON.parse('"\\uabcd"');
|
||||
do_check_eq(typeof x, "string");
|
||||
do_check_eq(x, "\uabcd");
|
||||
|
||||
x = JSON.parse('"\\f"');
|
||||
do_check_eq(typeof x, "string");
|
||||
do_check_eq(x, "\f");
|
||||
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
parse_primitives();
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
var w = {foo: 123};
|
||||
var x = {foo: 123, bar: function () {}};
|
||||
var y = {foo: 123, bar: function () {}, baz: 123};
|
||||
var z = {foo: 123, bar: <x><y></y></x>, baz: 123};
|
||||
|
||||
function run_test() {
|
||||
do_check_eq('{"foo":123}', JSON.stringify(w));
|
||||
do_check_eq('{"foo":123}', JSON.stringify(x));
|
||||
do_check_eq('{"foo":123,"baz":123}', JSON.stringify(y));
|
||||
do_check_eq('{"foo":123,"baz":123}', JSON.stringify(z));
|
||||
}
|
@ -1,111 +1,36 @@
|
||||
var Ci = Components.interfaces;
|
||||
var Cc = Components.classes;
|
||||
|
||||
// returns a list of [string, object] pairs to test encoding
|
||||
function getTestPairs() {
|
||||
var testPairs = [
|
||||
["{}", {}],
|
||||
["[]", []],
|
||||
['{"foo":"bar"}', {"foo":"bar"}],
|
||||
['{"null":null}', {"null":null}],
|
||||
['{"five":5}', {"five":5}],
|
||||
['{"five":5,"six":6}', {"five":5, "six":6}],
|
||||
['{"x":{"y":"z"}}', {"x":{"y":"z"}}],
|
||||
['{"w":{"x":{"y":"z"}}}', {"w":{"x":{"y":"z"}}}],
|
||||
['[1,2,3]', [1,2,3]],
|
||||
['{"w":{"x":{"y":[1,2,3]}}}', {"w":{"x":{"y":[1,2,3]}}}],
|
||||
['{"false":false}', {"false":false}],
|
||||
['{"true":true}', {"true":true}],
|
||||
['{"child has two members":{"this":"one","2":"and this one"}}',
|
||||
{"child has two members": {"this":"one", 2:"and this one"}}],
|
||||
['{"x":{"a":"b","c":{"y":"z"},"f":"g"}}',
|
||||
{"x":{"a":"b","c":{"y":"z"},"f":"g"}}],
|
||||
['{"x":[1,{"y":"z"},3]}', {"x":[1,{"y":"z"},3]}],
|
||||
['["hmm"]', [new String("hmm")]],
|
||||
['[true]', [new Boolean(true)]],
|
||||
['[42]', [new Number(42)]],
|
||||
['["1978-09-13T12:24:34.023Z"]', [new Date(Date.UTC(1978, 8, 13, 12, 24, 34, 23))]],
|
||||
['[1,null,3]',[1,,3]],
|
||||
[null, function test(){}],
|
||||
[null, dump],
|
||||
['{"mm\\\"mm":"hmm"}',{"mm\"mm":"hmm"}],
|
||||
['{"mm\\\"mm\\\"mm":"hmm"}',{"mm\"mm\"mm":"hmm"}],
|
||||
['{"\\\"":"hmm"}',{'"':"hmm"}],
|
||||
['{"\\\\":"hmm"}',{'\\':"hmm"}],
|
||||
['{"mmm\\\\mmm":"hmm"}',{'mmm\\mmm':"hmm"}],
|
||||
['{"mmm\\\\mmm\\\\mmm":"hmm"}',{'mmm\\mmm\\mmm':"hmm"}],
|
||||
['{"mm\\u000bmm":"hmm"}',{"mm\u000bmm":"hmm"}],
|
||||
['{"mm\\u0000mm":"hmm"}',{"mm\u0000mm":"hmm"}]
|
||||
];
|
||||
var nativeJSON = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
|
||||
|
||||
var x = {"free":"variable"}
|
||||
testPairs.push(['{"free":"variable"}', x]);
|
||||
testPairs.push(['{"y":{"free":"variable"}}', {"y":x}]);
|
||||
var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
|
||||
var workingDir = dirSvc.get("TmpD", Ci.nsIFile);
|
||||
|
||||
// array prop
|
||||
var x = {
|
||||
a: [1,2,3]
|
||||
}
|
||||
testPairs.push(['{"a":[1,2,3]}', x])
|
||||
var outputName = "json-test-output";
|
||||
var outputDir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
||||
outputDir.initWithFile(workingDir);
|
||||
outputDir.append(outputName);
|
||||
|
||||
var y = {
|
||||
foo: function(hmm) { return hmm; }
|
||||
}
|
||||
testPairs.push(['{"y":{}}',{"y":y}]);
|
||||
|
||||
// test toJSON
|
||||
var hmm = {
|
||||
toJSON: function() { return {"foo":"bar"}}
|
||||
}
|
||||
testPairs.push(['{"hmm":{"foo":"bar"}}', {"hmm":hmm}]);
|
||||
testPairs.push(['{"foo":"bar"}', hmm]); // on the root
|
||||
|
||||
// toJSON on prototype
|
||||
var Y = function() {
|
||||
this.d = "e";
|
||||
}
|
||||
Y.prototype = {
|
||||
not:"there?",
|
||||
toJSON: function() { return {"foo":"bar"}}
|
||||
};
|
||||
var y = new Y();
|
||||
testPairs.push(['{"foo":"bar"}', y.toJSON()]);
|
||||
testPairs.push(['{"foo":"bar"}', y]);
|
||||
|
||||
// return undefined from toJSON
|
||||
var hmm = {
|
||||
toJSON: function() { return; }
|
||||
}
|
||||
testPairs.push(['{}', {"hmm":hmm}]);
|
||||
|
||||
// array with named prop
|
||||
var x= new Array();
|
||||
x[0] = 1;
|
||||
x.foo = "bar";
|
||||
//testPairs.push(['[1]', x]);
|
||||
|
||||
// prototype
|
||||
var X = function() { this.foo = "b" }
|
||||
X.prototype = {c:"d"}
|
||||
var y = new X();
|
||||
testPairs.push(['{"foo":"b"}', y]);
|
||||
|
||||
// useless roots will be dropped
|
||||
testPairs.push([null, null]);
|
||||
testPairs.push([null, ""]);
|
||||
testPairs.push([null, undefined]);
|
||||
testPairs.push([null, 5]);
|
||||
|
||||
return testPairs;
|
||||
if (!outputDir.exists()) {
|
||||
outputDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0777);
|
||||
} else if (!outputDir.isDirectory()) {
|
||||
do_throw(outputName + " is not a directory?")
|
||||
}
|
||||
|
||||
function testStringEncode() {
|
||||
// test empty arg
|
||||
do_check_eq(null, nativeJSON.encode());
|
||||
function testStringEncode()
|
||||
{
|
||||
do_check_eq(nativeJSON.encode(), null);
|
||||
|
||||
var pairs = getTestPairs();
|
||||
for each(pair in pairs) {
|
||||
var nativeResult = nativeJSON.encode(pair[1]);
|
||||
do_check_eq(pair[0], nativeResult);
|
||||
}
|
||||
// useless roots are dropped
|
||||
do_check_eq(nativeJSON.encode(null), null);
|
||||
do_check_eq(nativeJSON.encode(""), null);
|
||||
do_check_eq(nativeJSON.encode(undefined), null);
|
||||
do_check_eq(nativeJSON.encode(5), null);
|
||||
do_check_eq(nativeJSON.encode(function(){}), null);
|
||||
do_check_eq(nativeJSON.encode(dump), null);
|
||||
|
||||
// All other testing should occur in js/src/tests/ecma_5/JSON/ using
|
||||
// the otherwise-exactly-identical JSON.stringify.
|
||||
}
|
||||
|
||||
function testOutputStreams() {
|
||||
@ -124,8 +49,21 @@ function testOutputStreams() {
|
||||
return jsonFile;
|
||||
}
|
||||
|
||||
var pairs = getTestPairs();
|
||||
for each(pair in pairs) {
|
||||
var pairs = [
|
||||
["{}", {}],
|
||||
['{"foo":"bar"}', {"foo":"bar"}],
|
||||
['{"null":null}', {"null":null}],
|
||||
['{"five":5}', {"five":5}],
|
||||
['{"true":true}', {"true":true}],
|
||||
['{"x":{"y":"z"}}', {"x":{"y":"z"}}],
|
||||
['{"w":{"x":{"y":"z"}}}', {"w":{"x":{"y":"z"}}}],
|
||||
["[]", []],
|
||||
['[1,2,3]', [1,2,3]],
|
||||
['[1,null,3]',[1,,3]],
|
||||
];
|
||||
for (var i = 0; i < pairs.length; i++)
|
||||
{
|
||||
var pair = pairs[i];
|
||||
if (pair[1] && (typeof pair[1] == "object")) {
|
||||
var utf8File = writeToFile(pair[1], "UTF-8", false);
|
||||
var utf16LEFile = writeToFile(pair[1], "UTF-16LE", false);
|
||||
@ -157,10 +95,14 @@ function throwingToJSON() {
|
||||
}
|
||||
try {
|
||||
var y = nativeJSON.encode(a);
|
||||
} catch (ex) {}
|
||||
throw "didn't throw";
|
||||
} catch (ex) {
|
||||
do_check_eq(ex, "uh oh");
|
||||
}
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
function run_test()
|
||||
{
|
||||
testStringEncode();
|
||||
throwingToJSON();
|
||||
|
||||
|
@ -1,34 +0,0 @@
|
||||
function stringify_primitives() {
|
||||
// sanity
|
||||
var x = JSON.stringify({});
|
||||
do_check_eq(x, "{}");
|
||||
|
||||
// booleans and null
|
||||
x = JSON.stringify(true);
|
||||
do_check_eq(x, "true");
|
||||
|
||||
x = JSON.stringify(false);
|
||||
do_check_eq(x, "false");
|
||||
|
||||
x = JSON.stringify(new Boolean(false));
|
||||
do_check_eq(x, "false");
|
||||
|
||||
x = JSON.stringify(null);
|
||||
do_check_eq(x, "null");
|
||||
|
||||
x = JSON.stringify(1234);
|
||||
do_check_eq(x, "1234");
|
||||
|
||||
x = JSON.stringify(new Number(1234));
|
||||
do_check_eq(x, "1234");
|
||||
|
||||
x = JSON.stringify("asdf");
|
||||
do_check_eq(x, '"asdf"');
|
||||
|
||||
x = JSON.stringify(new String("asdf"));
|
||||
do_check_eq(x, '"asdf"');
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
stringify_primitives();
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
function tooDeep() {
|
||||
var arr = [];
|
||||
var root = [arr];
|
||||
var tail;
|
||||
for (var i = 0; i < 5000; i++) {
|
||||
tail = [];
|
||||
arr.push(tail);
|
||||
arr = tail;
|
||||
}
|
||||
JSON.stringify(root);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
do_check_eq(undefined, JSON.stringify(undefined));
|
||||
do_check_eq(undefined, JSON.stringify(function(){}));
|
||||
do_check_eq(undefined, JSON.stringify(<x><y></y></x>));
|
||||
|
||||
var ok = false;
|
||||
try {
|
||||
tooDeep();
|
||||
} catch (e) {
|
||||
do_check_true(e instanceof Error);
|
||||
ok = true;
|
||||
}
|
||||
do_check_true(ok);
|
||||
}
|
||||
|
@ -1,129 +0,0 @@
|
||||
/**
|
||||
* These return* functions are used by the
|
||||
* replacer tests taken from bug 512447
|
||||
*/
|
||||
function returnObjectFor1(k, v) {
|
||||
if (k == "1")
|
||||
return {};
|
||||
return v;
|
||||
}
|
||||
function returnArrayFor1(k, v) {
|
||||
if (k == "1")
|
||||
return [];
|
||||
return v;
|
||||
}
|
||||
function returnNullFor1(k, v) {
|
||||
if (k == "1")
|
||||
return null;
|
||||
return v;
|
||||
}
|
||||
function returnStringForUndefined(k, v) {
|
||||
if (v === undefined)
|
||||
return "undefined value";
|
||||
return v;
|
||||
}
|
||||
function returnCycleObjectFor1(k, v) {
|
||||
if (k == "1")
|
||||
return object;
|
||||
return v;
|
||||
}
|
||||
function returnCycleArrayFor1(k, v) {
|
||||
if (k == "1")
|
||||
return array;
|
||||
return v;
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
var x = JSON.stringify({key:2},function(k,v){return k?undefined:v;})
|
||||
do_check_eq("{}", x);
|
||||
|
||||
var x = JSON.stringify(["hmm", "hmm"],function(k,v){return k!==""?undefined:v;})
|
||||
do_check_eq("[null,null]", x);
|
||||
|
||||
var foo = ["hmm"];
|
||||
function censor(k, v) {
|
||||
if (v !== foo)
|
||||
return "XXX";
|
||||
return v;
|
||||
}
|
||||
var x = JSON.stringify(foo, censor);
|
||||
do_check_eq(x, '["XXX"]');
|
||||
|
||||
foo = ["bar", ["baz"], "qux"];
|
||||
var x = JSON.stringify(foo, censor);
|
||||
do_check_eq(x, '["XXX","XXX","XXX"]');
|
||||
|
||||
function censor2(k, v) {
|
||||
if (typeof(v) == "string")
|
||||
return "XXX";
|
||||
return v;
|
||||
}
|
||||
|
||||
foo = ["bar", ["baz"], "qux"];
|
||||
var x = JSON.stringify(foo, censor2);
|
||||
do_check_eq(x, '["XXX",["XXX"],"XXX"]');
|
||||
|
||||
foo = {bar: 42, qux: 42, quux: 42};
|
||||
var x = JSON.stringify(foo, ["bar"]);
|
||||
do_check_eq(x, '{"bar":42}');
|
||||
|
||||
foo = {bar: {bar: 42, schmoo:[]}, qux: 42, quux: 42};
|
||||
var x = JSON.stringify(foo, ["bar", "schmoo"]);
|
||||
do_check_eq(x, '{"bar":{"bar":42,"schmoo":[]}}');
|
||||
|
||||
var x = JSON.stringify(foo, null, "");
|
||||
do_check_eq(x, '{"bar":{"bar":42,"schmoo":[]},"qux":42,"quux":42}');
|
||||
|
||||
var x = JSON.stringify(foo, null, " ");
|
||||
do_check_eq(x, '{\n "bar": {\n "bar": 42,\n "schmoo": []\n },\n "qux": 42,\n "quux": 42\n}');
|
||||
|
||||
foo = {bar:{bar:{}}}
|
||||
var x = JSON.stringify(foo, null, " ");
|
||||
do_check_eq(x, '{\n "bar": {\n "bar": {}\n }\n}');
|
||||
|
||||
var x = JSON.stringify({x:1,arr:[1]}, function (k,v) { return typeof v === 'number' ? 3 : v; });
|
||||
do_check_eq(x, '{"x":3,"arr":[3]}');
|
||||
|
||||
foo = ['e'];
|
||||
var x = JSON.stringify(foo, null, '\t');
|
||||
do_check_eq(x, '[\n\t"e"\n]');
|
||||
|
||||
foo = {0:0, 1:1, 2:2, 3:undefined};
|
||||
var x = JSON.stringify(foo, returnObjectFor1);
|
||||
do_check_eq(x, '{"0":0,"1":{},"2":2}');
|
||||
|
||||
var x = JSON.stringify(foo, returnArrayFor1);
|
||||
do_check_eq(x, '{"0":0,"1":[],"2":2}');
|
||||
|
||||
var x = JSON.stringify(foo, returnNullFor1);
|
||||
do_check_eq(x, '{"0":0,"1":null,"2":2}');
|
||||
|
||||
var x = JSON.stringify(foo, returnStringForUndefined);
|
||||
do_check_eq(x, '{"0":0,"1":1,"2":2,"3":"undefined value"}');
|
||||
|
||||
var thrown = false;
|
||||
try {
|
||||
var x = JSON.stringify(foo, returnCycleObjectFor1);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
do_check_eq(thrown, true);
|
||||
|
||||
var thrown = false;
|
||||
try {
|
||||
var x = JSON.stringify(foo, returnCycleArrayFor1);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
do_check_eq(thrown, true);
|
||||
|
||||
var thrown = false;
|
||||
foo = [0, 1, 2, undefined];
|
||||
try {
|
||||
var x = JSON.stringify(foo, returnCycleObjectFor1);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
do_check_eq(thrown, true);
|
||||
}
|
||||
|
@ -1,36 +0,0 @@
|
||||
function doubler(k, v) {
|
||||
do_check_true("string" == typeof k);
|
||||
|
||||
if ((typeof v) == "number")
|
||||
return 2 * v;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
var x = JSON.parse('{"a":5,"b":6}', doubler);
|
||||
do_check_true(x.hasOwnProperty('a'));
|
||||
do_check_true(x.hasOwnProperty('b'));
|
||||
do_check_eq(x.a, 10);
|
||||
do_check_eq(x.b, 12);
|
||||
|
||||
x = JSON.parse('[3, 4, 5]', doubler);
|
||||
do_check_eq(x[0], 6);
|
||||
do_check_eq(x[1], 8);
|
||||
do_check_eq(x[2], 10);
|
||||
|
||||
// make sure reviver isn't called after a failed parse
|
||||
var called = false;
|
||||
function dontCallMe(k, v) {
|
||||
called = true;
|
||||
}
|
||||
|
||||
try {
|
||||
x = JSON.parse('{{{{{{{}}}}', dontCallMe);
|
||||
} catch (e) {
|
||||
if (! (e instanceof SyntaxError))
|
||||
throw("wrong exception");
|
||||
}
|
||||
|
||||
do_check_false(called);
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
function checkForSyntaxErrors(s) {
|
||||
var crockfordErrored = false;
|
||||
try {
|
||||
crockfordJSON.parse(s)
|
||||
} catch (e) {
|
||||
var crockfordErrored = true;
|
||||
do_check_true(e instanceof crockfordJSON.window.SyntaxError);
|
||||
}
|
||||
do_check_true(crockfordErrored);
|
||||
|
||||
var JSONErrored = false;
|
||||
try {
|
||||
JSON.parse(s)
|
||||
} catch (e) {
|
||||
var JSONErrored = true;
|
||||
do_check_true(e instanceof SyntaxError);
|
||||
}
|
||||
do_check_true(JSONErrored);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
checkForSyntaxErrors("{}...");
|
||||
checkForSyntaxErrors('{"foo": truBBBB}');
|
||||
checkForSyntaxErrors('{foo: truBBBB}');
|
||||
checkForSyntaxErrors('{"foo": undefined}');
|
||||
checkForSyntaxErrors('{"foo": ]');
|
||||
checkForSyntaxErrors('{"foo');
|
||||
}
|
@ -1,190 +0,0 @@
|
||||
|
||||
// returns a list of [string, object] pairs to test encoding
|
||||
function getTestPairs() {
|
||||
var testPairs = [
|
||||
["{}", {}],
|
||||
["[]", []],
|
||||
['{"foo":"bar"}', {"foo":"bar"}],
|
||||
['{"null":null}', {"null":null}],
|
||||
['{"five":5}', {"five":5}],
|
||||
['{"five":5,"six":6}', {"five":5, "six":6}],
|
||||
['{"x":{"y":"z"}}', {"x":{"y":"z"}}],
|
||||
['{"w":{"x":{"y":"z"}}}', {"w":{"x":{"y":"z"}}}],
|
||||
['[1,2,3]', [1,2,3]],
|
||||
['{"w":{"x":{"y":[1,2,3]}}}', {"w":{"x":{"y":[1,2,3]}}}],
|
||||
['{"false":false}', {"false":false}],
|
||||
['{"true":true}', {"true":true}],
|
||||
['{"child has two members":{"this":"one","2":"and this one"}}',
|
||||
{"child has two members": {"this":"one", 2:"and this one"}}],
|
||||
['{"x":{"a":"b","c":{"y":"z"},"f":"g"}}',
|
||||
{"x":{"a":"b","c":{"y":"z"},"f":"g"}}],
|
||||
['{"x":[1,{"y":"z"},3]}', {"x":[1,{"y":"z"},3]}],
|
||||
['["hmm"]', [new String("hmm")]],
|
||||
['[true]', [new Boolean(true)]],
|
||||
['[42]', [new Number(42)]],
|
||||
['["1978-09-13T12:24:34.023Z"]', [new Date(Date.UTC(1978, 8, 13, 12, 24, 34, 23))]],
|
||||
['[1,null,3]',[1,,3]],
|
||||
['{"mm\\\"mm":"hmm"}',{"mm\"mm":"hmm"}],
|
||||
['{"mm\\\"mm\\\"mm":"hmm"}',{"mm\"mm\"mm":"hmm"}],
|
||||
['{"\\\"":"hmm"}',{'"':"hmm"}],
|
||||
['{"\\\\":"hmm"}',{'\\':"hmm"}],
|
||||
['{"mmm\\\\mmm":"hmm"}',{'mmm\\mmm':"hmm"}],
|
||||
['{"mmm\\\\mmm\\\\mmm":"hmm"}',{'mmm\\mmm\\mmm':"hmm"}],
|
||||
['{"mm\\u000bmm":"hmm"}',{"mm\u000bmm":"hmm"}],
|
||||
['{"mm\\u0000mm":"hmm"}',{"mm\u0000mm":"hmm"}]
|
||||
];
|
||||
|
||||
var x = {"free":"variable"}
|
||||
testPairs.push(['{"free":"variable"}', x]);
|
||||
testPairs.push(['{"y":{"free":"variable"}}', {"y":x}]);
|
||||
|
||||
// array prop
|
||||
var x = {
|
||||
a: [1,2,3]
|
||||
}
|
||||
testPairs.push(['{"a":[1,2,3]}', x])
|
||||
|
||||
var y = {
|
||||
foo: function(hmm) { return hmm; }
|
||||
}
|
||||
testPairs.push(['{"y":{}}',{"y":y}]);
|
||||
|
||||
// test toJSON
|
||||
var hmm = {
|
||||
toJSON: function() { return {"foo":"bar"}}
|
||||
}
|
||||
testPairs.push(['{"hmm":{"foo":"bar"}}', {"hmm":hmm}]);
|
||||
testPairs.push(['{"foo":"bar"}', hmm]); // on the root
|
||||
|
||||
// toJSON on prototype
|
||||
var Y = function() {
|
||||
this.not = "there?";
|
||||
this.d = "e";
|
||||
}
|
||||
Y.prototype = {
|
||||
not:"there?",
|
||||
toJSON: function() { return {"foo":"bar"}}
|
||||
};
|
||||
var y = new Y();
|
||||
testPairs.push(['{"foo":"bar"}', y.toJSON()]);
|
||||
testPairs.push(['{"foo":"bar"}', y]);
|
||||
|
||||
// return undefined from toJSON
|
||||
var hmm = {
|
||||
toJSON: function() { return; }
|
||||
}
|
||||
testPairs.push(['{}', {"hmm":hmm}]);
|
||||
|
||||
// array with named prop
|
||||
var x= new Array();
|
||||
x[0] = 1;
|
||||
x.foo = "bar";
|
||||
testPairs.push(['[1]', x]);
|
||||
|
||||
// prototype
|
||||
var X = function() { this.a = "b" }
|
||||
X.prototype = {c:"d"}
|
||||
var y = new X();
|
||||
testPairs.push(['{"a":"b"}', y]);
|
||||
|
||||
return testPairs;
|
||||
}
|
||||
|
||||
function testStringEncode() {
|
||||
var pairs = getTestPairs();
|
||||
for each(pair in pairs) {
|
||||
print(pair)
|
||||
var nativeResult = JSON.stringify(pair[1]);
|
||||
do_check_eq(pair[0], nativeResult);
|
||||
}
|
||||
}
|
||||
|
||||
function decode_strings() {
|
||||
// empty object
|
||||
var x = JSON.parse("{}");
|
||||
do_check_eq(typeof x, "object");
|
||||
|
||||
// empty array
|
||||
x = JSON.parse("[]");
|
||||
do_check_eq(typeof x, "object");
|
||||
do_check_eq(x.length, 0);
|
||||
do_check_eq(x.constructor, Array);
|
||||
|
||||
// one element array
|
||||
x = JSON.parse("[[]]");
|
||||
do_check_eq(typeof x, "object");
|
||||
do_check_eq(x.length, 1);
|
||||
do_check_eq(x.constructor, Array);
|
||||
do_check_eq(x[0].constructor, Array);
|
||||
|
||||
// multiple arrays
|
||||
x = JSON.parse("[[],[],[]]");
|
||||
do_check_eq(typeof x, "object");
|
||||
do_check_eq(x.length, 3);
|
||||
do_check_eq(x.constructor, Array);
|
||||
do_check_eq(x[0].constructor, Array);
|
||||
do_check_eq(x[1].constructor, Array);
|
||||
do_check_eq(x[2].constructor, Array);
|
||||
|
||||
// array key/value
|
||||
x = JSON.parse('{"foo":[]}');
|
||||
do_check_eq(typeof x, "object");
|
||||
do_check_eq(typeof x.foo, "object");
|
||||
do_check_eq(x.foo.constructor, Array);
|
||||
x = JSON.parse('{"foo":[], "bar":[]}');
|
||||
do_check_eq(typeof x, "object");
|
||||
do_check_eq(typeof x.foo, "object");
|
||||
do_check_eq(x.foo.constructor, Array);
|
||||
do_check_eq(typeof x.bar, "object");
|
||||
do_check_eq(x.bar.constructor, Array);
|
||||
|
||||
// nesting
|
||||
x = JSON.parse('{"foo":[{}]}');
|
||||
do_check_eq(x.foo.constructor, Array);
|
||||
do_check_eq(x.foo.length, 1);
|
||||
do_check_eq(typeof x.foo[0], "object");
|
||||
x = JSON.parse('{"foo":[{"foo":[{"foo":{}}]}]}');
|
||||
do_check_eq(x.foo[0].foo[0].foo.constructor, Object);
|
||||
x = JSON.parse('{"foo":[{"foo":[{"foo":[]}]}]}');
|
||||
do_check_eq(x.foo[0].foo[0].foo.constructor, Array);
|
||||
|
||||
// strings
|
||||
x = JSON.parse('{"foo":"bar"}');
|
||||
do_check_eq(x.foo, "bar");
|
||||
x = JSON.parse('["foo", "bar", "baz"]');
|
||||
do_check_eq(x[0], "foo");
|
||||
do_check_eq(x[1], "bar");
|
||||
do_check_eq(x[2], "baz");
|
||||
|
||||
// numbers
|
||||
x = JSON.parse('{"foo":5.5, "bar":5}');
|
||||
do_check_eq(x.foo, 5.5);
|
||||
do_check_eq(x.bar, 5);
|
||||
|
||||
// keywords
|
||||
x = JSON.parse('{"foo": true, "bar":false, "baz":null}');
|
||||
do_check_eq(x.foo, true);
|
||||
do_check_eq(x.bar, false);
|
||||
do_check_eq(x.baz, null);
|
||||
|
||||
// short escapes
|
||||
x = JSON.parse('{"foo": "\\"", "bar":"\\\\", "baz":"\\b","qux":"\\f", "quux":"\\n", "quuux":"\\r","quuuux":"\\t"}');
|
||||
do_check_eq(x.foo, '"');
|
||||
do_check_eq(x.bar, '\\');
|
||||
do_check_eq(x.baz, '\b');
|
||||
do_check_eq(x.qux, '\f');
|
||||
do_check_eq(x.quux, "\n");
|
||||
do_check_eq(x.quuux, "\r");
|
||||
do_check_eq(x.quuuux, "\t");
|
||||
|
||||
// unicode escape
|
||||
x = JSON.parse('{"foo":"hmm\\u006dmm"}');
|
||||
do_check_eq("hmm\u006dmm", x.foo);
|
||||
|
||||
x = JSON.parse('{"JSON Test Pattern pass3": {"The outermost value": "must be an object or array.","In this test": "It is an object." }}');
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
testStringEncode();
|
||||
decode_strings();
|
||||
}
|
@ -170,7 +170,7 @@ nsDOMWorkerTimeout::ExpressionCallback::ExpressionCallback(PRUint32 aArgc,
|
||||
// Get the calling location.
|
||||
const char* fileName;
|
||||
PRUint32 lineNumber;
|
||||
if (nsJSUtils::GetCallingLocation(aCx, &fileName, &lineNumber, nsnull)) {
|
||||
if (nsJSUtils::GetCallingLocation(aCx, &fileName, &lineNumber)) {
|
||||
mFileName.Assign(fileName);
|
||||
mLineNumber = lineNumber;
|
||||
}
|
||||
|
@ -76,8 +76,8 @@ interface jsdIProperty;
|
||||
interface jsdIActivationCallback;
|
||||
|
||||
/**
|
||||
* Debugger service. It's not a good idea to have more than one active client of
|
||||
* the debugger service.
|
||||
* Debugger service. It is not a good idea to have more than one active client
|
||||
* of the debugger service.
|
||||
*/
|
||||
[scriptable, uuid(aa232c7f-855f-4488-a92c-6f89adc668cc)]
|
||||
interface jsdIDebuggerService : nsISupports
|
||||
@ -116,11 +116,11 @@ interface jsdIDebuggerService : nsISupports
|
||||
/**
|
||||
* Called before and after a toplevel script is evaluated.
|
||||
*/
|
||||
attribute jsdICallHook topLevelHook;
|
||||
attribute jsdICallHook topLevelHook;
|
||||
/**
|
||||
* Called before and after a function is called.
|
||||
*/
|
||||
attribute jsdICallHook functionHook;
|
||||
attribute jsdICallHook functionHook;
|
||||
|
||||
|
||||
/**
|
||||
@ -151,13 +151,13 @@ interface jsdIDebuggerService : nsISupports
|
||||
const unsigned long ENABLE_NATIVE_FRAMES = 0x01;
|
||||
/**
|
||||
* Normally, if a script has a 0 in JSD_SCRIPT_PROFILE_BIT it is included in
|
||||
* profile data, otherwise it is not profiled. Setting the
|
||||
* profile data, otherwise it is not profiled. Setting the
|
||||
* PROFILE_WHEN_SET flag reverses this convention.
|
||||
*/
|
||||
const unsigned long PROFILE_WHEN_SET = 0x02;
|
||||
/**
|
||||
* Normally, when the script in the top frame of a thread state has a 1 in
|
||||
* JSD_SCRIPT_DEBUG_BIT, the execution hook is ignored. Setting the
|
||||
* JSD_SCRIPT_DEBUG_BIT, the execution hook is ignored. Setting the
|
||||
* DEBUG_WHEN_SET flag reverses this convention.
|
||||
*/
|
||||
const unsigned long DEBUG_WHEN_SET = 0x04;
|
||||
@ -172,7 +172,7 @@ interface jsdIDebuggerService : nsISupports
|
||||
const unsigned long HIDE_DISABLED_FRAMES = 0x10;
|
||||
/**
|
||||
* When this flag is set, the debugger will only check the
|
||||
* JSD_SCRIPT_DEBUG_BIT on the top (most recent) stack frame. This
|
||||
* JSD_SCRIPT_DEBUG_BIT on the top (most recent) stack frame. This
|
||||
* makes it possible to stop in an enabled frame which was called from
|
||||
* a stack that contains a disabled frame.
|
||||
*
|
||||
@ -180,7 +180,7 @@ interface jsdIDebuggerService : nsISupports
|
||||
* will not be debugged (the execution hook will not be invoked.)
|
||||
*
|
||||
* This only applies when the reason for calling the hook would have
|
||||
* been TYPE_INTERRUPTED or TYPE_THROW. TYPE_BREAKPOINT,
|
||||
* been TYPE_INTERRUPTED or TYPE_THROW. TYPE_BREAKPOINT,
|
||||
* TYPE_DEBUG_REQUESTED, and TYPE_DEBUGGER_KEYWORD always stop, regardless
|
||||
* of this setting, as long as the top frame is not disabled.
|
||||
*
|
||||
@ -212,7 +212,7 @@ interface jsdIDebuggerService : nsISupports
|
||||
readonly attribute AUTF8String implementationString;
|
||||
|
||||
/**
|
||||
* |true| if the debugger service has been turned on. This does not
|
||||
* |true| if the debugger service has been turned on. This does not
|
||||
* necessarily mean another app is actively using the service, as the
|
||||
* autostart pref may have turned the service on.
|
||||
*/
|
||||
@ -223,17 +223,17 @@ interface jsdIDebuggerService : nsISupports
|
||||
* Synchronous activation of the debugger is no longer supported,
|
||||
* and will throw an exception.
|
||||
*/
|
||||
void on ();
|
||||
void on();
|
||||
|
||||
/**
|
||||
* Turn on the debugger. This function should only be called from JavaScript
|
||||
* code. The debugger will be enabled on the runtime the call is made on,
|
||||
* as determined by nsIXPCNativeCallContext.
|
||||
* Turn on the debugger. This function should only be called from
|
||||
* JavaScript code. The debugger will be enabled on the runtime the call is
|
||||
* made on, as determined by nsIXPCNativeCallContext.
|
||||
*
|
||||
* The debugger will be activated asynchronously, because there can be no JS
|
||||
* on the stack when code is to be re-compiled for debug mode.
|
||||
* The debugger will be activated asynchronously, because there can be no
|
||||
* JS on the stack when code is to be re-compiled for debug mode.
|
||||
*/
|
||||
void asyncOn (in jsdIActivationCallback callback);
|
||||
void asyncOn(in jsdIActivationCallback callback);
|
||||
|
||||
/**
|
||||
* Called by nsIXPConnect after it's had a chance to recompile for
|
||||
@ -252,10 +252,8 @@ interface jsdIDebuggerService : nsISupports
|
||||
[noscript] void recompileForDebugMode(in JSContext cx, in JSCompartment comp, in PRBool mode);
|
||||
|
||||
/**
|
||||
* Turn the debugger off. This will invalidate all of your jsdIEphemeral
|
||||
* derived objects, and clear all of your breakpoints. In theory you
|
||||
* should be able to turn the debugger back on at some later time without
|
||||
* any problems.
|
||||
* Turn the debugger off. This will invalidate all of your jsdIEphemeral
|
||||
* derived objects, and clear all of your breakpoints.
|
||||
*/
|
||||
void off ();
|
||||
|
||||
@ -266,8 +264,8 @@ interface jsdIDebuggerService : nsISupports
|
||||
*/
|
||||
readonly attribute unsigned long pauseDepth;
|
||||
/**
|
||||
* Temporarily disable the debugger. Hooks will not be called while the
|
||||
* debugger is paused. Multiple calls to pause will increase the "pause
|
||||
* Temporarily disable the debugger. Hooks will not be called while the
|
||||
* debugger is paused. Multiple calls to pause will increase the "pause
|
||||
* depth", and equal number of unPause calles must be made to resume
|
||||
* normal debugging.
|
||||
*
|
||||
@ -293,33 +291,33 @@ interface jsdIDebuggerService : nsISupports
|
||||
void clearProfileData();
|
||||
|
||||
/**
|
||||
* Adds an execution hook filter. These filters are consulted each time one
|
||||
* of the jsdIExecutionHooks is about to be called. Filters are matched in
|
||||
* a first in, first compared fashion. The first filter to match determines
|
||||
* whether or not the hook is called. Use swapFilter to reorder existing
|
||||
* Adds an execution hook filter. These filters are consulted each time one
|
||||
* of the jsdIExecutionHooks is about to be called. Filters are matched in
|
||||
* a first in, first compared fashion. The first filter to match determines
|
||||
* whether or not the hook is called. Use swapFilter to reorder existing
|
||||
* filters, and removeFilter to remove them.
|
||||
*
|
||||
* If |filter| is already present this method throws NS_ERROR_INVALID_ARG.
|
||||
*
|
||||
* @param filter Object representing the filter to add.
|
||||
* @param after Insert |filter| after this one. Pass null to insert at
|
||||
* @param after Insert |filter| after this one. Pass null to insert at
|
||||
* the beginning.
|
||||
*/
|
||||
void insertFilter (in jsdIFilter filter, in jsdIFilter after);
|
||||
void insertFilter(in jsdIFilter filter, in jsdIFilter after);
|
||||
/**
|
||||
* Same as insertFilter, except always add to the end of the list.
|
||||
*/
|
||||
void appendFilter (in jsdIFilter filter);
|
||||
void appendFilter(in jsdIFilter filter);
|
||||
/**
|
||||
* Remove a filter.
|
||||
*
|
||||
* If |filter| is not present this method throws NS_ERROR_INVALID_ARG.
|
||||
*
|
||||
* @param filter Object representing the filter to remove. Must be the exact
|
||||
* @param filter Object representing the filter to remove. Must be the exact
|
||||
* object passed to addFilter, not just a new object with the same
|
||||
* properties.
|
||||
*/
|
||||
void removeFilter (in jsdIFilter filter);
|
||||
void removeFilter(in jsdIFilter filter);
|
||||
/**
|
||||
* Swap position of two filters.
|
||||
*
|
||||
@ -327,23 +325,23 @@ interface jsdIDebuggerService : nsISupports
|
||||
* If |filter_b| is not present, filter_a is replaced by filter_b.
|
||||
* If |filter_a| == |filter_b|, then filter is refreshed.
|
||||
*/
|
||||
void swapFilters (in jsdIFilter filter_a, in jsdIFilter filter_b);
|
||||
void swapFilters(in jsdIFilter filter_a, in jsdIFilter filter_b);
|
||||
/**
|
||||
* Enumerate registered filters. This routine refreshes each filter before
|
||||
* passing them on to the enumeration function. Calling this with a null
|
||||
* Enumerate registered filters. This routine refreshes each filter before
|
||||
* passing them on to the enumeration function. Calling this with a null
|
||||
* |enumerator| is equivalent to jsdIService::refreshFilters.
|
||||
*
|
||||
* @param enumerator jsdIFilterEnumerator instance to be called back for the
|
||||
* enumeration.
|
||||
*/
|
||||
void enumerateFilters (in jsdIFilterEnumerator enumerator);
|
||||
void enumerateFilters(in jsdIFilterEnumerator enumerator);
|
||||
/**
|
||||
* Force the debugger to resync its internal filter cache with the
|
||||
* actual values in the jsdIFilter objects. To refresh a single filter
|
||||
* use jsdIService::swapFilters. This method is equivalent to
|
||||
* actual values in the jsdIFilter objects. To refresh a single filter
|
||||
* use jsdIService::swapFilters. This method is equivalent to
|
||||
* jsdIService::enumerateFilters with a null enumerator.
|
||||
*/
|
||||
void refreshFilters ();
|
||||
void refreshFilters();
|
||||
/**
|
||||
* Clear the list of filters.
|
||||
*/
|
||||
@ -352,36 +350,36 @@ interface jsdIDebuggerService : nsISupports
|
||||
/**
|
||||
* Enumerate all known contexts.
|
||||
*/
|
||||
void enumerateContexts (in jsdIContextEnumerator enumerator);
|
||||
void enumerateContexts(in jsdIContextEnumerator enumerator);
|
||||
|
||||
/**
|
||||
* Enumerate all scripts the debugger knows about. Any scripts created
|
||||
* Enumerate all scripts the debugger knows about. Any scripts created
|
||||
* before you turned the debugger on, or after turning the debugger off
|
||||
* will not be available unless the autostart perf is set.
|
||||
*
|
||||
* @param enumerator jsdIScriptEnumerator instance to be called back for
|
||||
* the enumeration.
|
||||
*/
|
||||
void enumerateScripts (in jsdIScriptEnumerator enumerator);
|
||||
void enumerateScripts(in jsdIScriptEnumerator enumerator);
|
||||
/**
|
||||
* Clear all breakpoints in all scripts.
|
||||
*/
|
||||
void clearAllBreakpoints ();
|
||||
void clearAllBreakpoints();
|
||||
|
||||
/**
|
||||
* When called from JavaScript, this method returns the jsdIValue wrapper
|
||||
* for the given value. If a wrapper does not exist one will be created.
|
||||
* for the given value. If a wrapper does not exist one will be created.
|
||||
* When called from another language this method returns an xpconnect
|
||||
* defined error code.
|
||||
*/
|
||||
jsdIValue wrapValue (/*in jsvalue value*/);
|
||||
jsdIValue wrapValue(/*in jsvalue value*/);
|
||||
|
||||
/**
|
||||
* The same as above but to be called from C++.
|
||||
*/
|
||||
[noscript] jsdIValue wrapJSValue (in jsval value);
|
||||
[noscript] jsdIValue wrapJSValue(in jsval value);
|
||||
|
||||
/* XXX these two routines are candidates for refactoring. The only problem
|
||||
/* XXX these two routines are candidates for refactoring. The only problem
|
||||
* is that it is not clear where and how they should land.
|
||||
*/
|
||||
|
||||
@ -391,31 +389,31 @@ interface jsdIDebuggerService : nsISupports
|
||||
* network queue has been pushed, but before the
|
||||
* UI loop starts.
|
||||
* @return depth returns the current number of times the event loop has been
|
||||
* nested. your code can use it for sanity checks.
|
||||
* nested. your code can use it for sanity checks.
|
||||
*/
|
||||
unsigned long enterNestedEventLoop (in jsdINestCallback callback);
|
||||
unsigned long enterNestedEventLoop(in jsdINestCallback callback);
|
||||
/**
|
||||
* Exit the current nested event loop after the current iteration completes,
|
||||
* and pop the network event queue.
|
||||
*
|
||||
* @return depth returns the current number of times the event loop has been
|
||||
* nested. your code can use it for sanity checks.
|
||||
* nested. your code can use it for sanity checks.
|
||||
*/
|
||||
unsigned long exitNestedEventLoop ();
|
||||
unsigned long exitNestedEventLoop();
|
||||
|
||||
/**
|
||||
* Output dump of JS heap.
|
||||
*
|
||||
* @param fileName Filename to dump the heap into.
|
||||
*/
|
||||
void dumpHeap (in AUTF8String fileName);
|
||||
void dumpHeap(in AUTF8String fileName);
|
||||
};
|
||||
|
||||
/* callback interfaces */
|
||||
|
||||
/**
|
||||
* Object representing a pattern of global object and/or url the debugger should
|
||||
* ignore. The debugger service itself will not modify properties of these
|
||||
* ignore. The debugger service itself will not modify properties of these
|
||||
* objects.
|
||||
*/
|
||||
[scriptable, uuid(0c9189d9-4287-47a4-bca6-6ed65aaf737f)]
|
||||
@ -423,7 +421,7 @@ interface jsdIFilter : nsISupports
|
||||
{
|
||||
/**
|
||||
* These two bytes of the flags attribute are reserved for interpretation
|
||||
* by the jsdService implementation. You can do what you like with the
|
||||
* by the jsdService implementation. You can do what you like with the
|
||||
* remaining flags.
|
||||
*/
|
||||
const unsigned long FLAG_RESERVED_MASK = 0xFF;
|
||||
@ -433,7 +431,7 @@ interface jsdIFilter : nsISupports
|
||||
const unsigned long FLAG_ENABLED = 0x01;
|
||||
/**
|
||||
* Filters with this flag set are "pass" filters, they allow matching hooks
|
||||
* to continue. Filters without this flag block matching hooks.
|
||||
* to continue. Filters without this flag block matching hooks.
|
||||
*/
|
||||
const unsigned long FLAG_PASS = 0x02;
|
||||
|
||||
@ -443,8 +441,8 @@ interface jsdIFilter : nsISupports
|
||||
attribute unsigned long flags;
|
||||
|
||||
/**
|
||||
* An nsISupports version of the global object to be filtered. A null glob
|
||||
* matches all hooks. This attribute must be QI'able to the
|
||||
* An nsISupports version of the global object to be filtered. A null glob
|
||||
* matches all hooks. This attribute must be QI'able to the
|
||||
* (non-scriptable) nsIScriptGlobalObject interface.
|
||||
*
|
||||
* The jsdIService caches this value internally, so if it changes you must
|
||||
@ -453,11 +451,11 @@ interface jsdIFilter : nsISupports
|
||||
attribute nsISupports globalObject;
|
||||
|
||||
/**
|
||||
* String representing the url pattern to be filtered. Supports limited
|
||||
* glob matching, at the beginning and end of the pattern only. For example,
|
||||
* String representing the url pattern to be filtered. Supports limited
|
||||
* glob matching, at the beginning and end of the pattern only. For example,
|
||||
* "chrome://venkman*" filters all urls that start with chrome/venkman,
|
||||
* "*.cgi" filters all cgi's, and "http://myserver/utils.js" filters only
|
||||
* the utils.js file on "myserver". A null urlPattern matches all urls.
|
||||
* the utils.js file on "myserver". A null urlPattern matches all urls.
|
||||
*
|
||||
* The jsdIService caches this value internally, to if it changes you must
|
||||
* swap the filter with itself using jsdIService::swapFilters.
|
||||
@ -465,14 +463,14 @@ interface jsdIFilter : nsISupports
|
||||
attribute AUTF8String urlPattern;
|
||||
|
||||
/**
|
||||
* Line number for the start of this filter. Line numbers are one based.
|
||||
* Line number for the start of this filter. Line numbers are one based.
|
||||
* Assigning a 0 to this attribute will tell the debugger to ignore the
|
||||
* entire file.
|
||||
*/
|
||||
attribute unsigned long startLine;
|
||||
|
||||
/**
|
||||
* Line number for the end of this filter. Line numbers are one based.
|
||||
* Line number for the end of this filter. Line numbers are one based.
|
||||
* Assigning a 0 to this attribute will tell the debugger to ignore from
|
||||
* |startLine| to the end of the file.
|
||||
*/
|
||||
@ -485,7 +483,7 @@ interface jsdIFilter : nsISupports
|
||||
[scriptable, function, uuid(6da7f5fb-3a84-4abe-9e23-8b2045960732)]
|
||||
interface jsdIActivationCallback : nsISupports
|
||||
{
|
||||
void onDebuggerActivated ();
|
||||
void onDebuggerActivated();
|
||||
};
|
||||
|
||||
/**
|
||||
@ -499,7 +497,7 @@ interface jsdINestCallback : nsISupports
|
||||
* as pushing the js context and network event queue, but before the new
|
||||
* event loop starts.
|
||||
*/
|
||||
void onNest ();
|
||||
void onNest();
|
||||
};
|
||||
|
||||
/**
|
||||
@ -512,7 +510,7 @@ interface jsdIFilterEnumerator : nsISupports
|
||||
* The enumerateFilter method will be called once for every filter the
|
||||
* debugger knows about.
|
||||
*/
|
||||
void enumerateFilter (in jsdIFilter filter);
|
||||
void enumerateFilter(in jsdIFilter filter);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -525,7 +523,7 @@ interface jsdIScriptEnumerator : nsISupports
|
||||
* The enumerateScript method will be called once for every script the
|
||||
* debugger knows about.
|
||||
*/
|
||||
void enumerateScript (in jsdIScript script);
|
||||
void enumerateScript(in jsdIScript script);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -538,7 +536,7 @@ interface jsdIContextEnumerator : nsISupports
|
||||
* The enumerateContext method will be called once for every context
|
||||
* currently in use.
|
||||
*/
|
||||
void enumerateContext (in jsdIContext executionContext);
|
||||
void enumerateContext(in jsdIContext executionContext);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -550,12 +548,12 @@ interface jsdIScriptHook : nsISupports
|
||||
/**
|
||||
* Called when scripts are created.
|
||||
*/
|
||||
void onScriptCreated (in jsdIScript script);
|
||||
void onScriptCreated(in jsdIScript script);
|
||||
/**
|
||||
* Called when the JavaScript engine destroys a script. The jsdIScript
|
||||
* Called when the JavaScript engine destroys a script. The jsdIScript
|
||||
* object passed in will already be invalidated.
|
||||
*/
|
||||
void onScriptDestroyed (in jsdIScript script);
|
||||
void onScriptDestroyed(in jsdIScript script);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -591,7 +589,7 @@ interface jsdICallHook : nsISupports
|
||||
* Called before the JavaScript engine executes a top level script or calls
|
||||
* a function.
|
||||
*/
|
||||
void onCall (in jsdIStackFrame frame, in unsigned long type);
|
||||
void onCall(in jsdIStackFrame frame, in unsigned long type);
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(e6b45eee-d974-4d85-9d9e-f5a67218deb4)]
|
||||
@ -620,13 +618,13 @@ interface jsdIErrorHook : nsISupports
|
||||
const unsigned long REPORT_STRICT = 0x04;
|
||||
|
||||
/**
|
||||
* Called when the JavaScript engine encounters an error. Return |true|
|
||||
* Called when the JavaScript engine encounters an error. Return |true|
|
||||
* to pass the error along, |false| to invoke the debugHook.
|
||||
*/
|
||||
boolean onError (in AUTF8String message, in AUTF8String fileName,
|
||||
in unsigned long line, in unsigned long pos,
|
||||
in unsigned long flags, in unsigned long errnum,
|
||||
in jsdIValue exc);
|
||||
boolean onError(in AUTF8String message, in AUTF8String fileName,
|
||||
in unsigned long line, in unsigned long pos,
|
||||
in unsigned long flags, in unsigned long errnum,
|
||||
in jsdIValue exc);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -668,15 +666,15 @@ interface jsdIExecutionHook : nsISupports
|
||||
*/
|
||||
|
||||
/**
|
||||
* Indicates unrecoverable error processing the hook. This will cause
|
||||
* Indicates unrecoverable error processing the hook. This will cause
|
||||
* the script being executed to be aborted without raising a JavaScript
|
||||
* exception.
|
||||
*/
|
||||
const unsigned long RETURN_HOOK_ERROR = 0;
|
||||
/**
|
||||
* Continue processing normally. This is the "do nothing special" return
|
||||
* value for all hook types *except* TYPE_THROW. Returning RETURN_CONTINUE
|
||||
* from TYPE_THROW cause the exception to be ignored. Return
|
||||
* Continue processing normally. This is the "do nothing special" return
|
||||
* value for all hook types *except* TYPE_THROW. Returning RETURN_CONTINUE
|
||||
* from TYPE_THROW cause the exception to be ignored. Return
|
||||
* RETURN_CONTINUE_THROW to continue exception processing from TYPE_THROW
|
||||
* hooks.
|
||||
*/
|
||||
@ -708,20 +706,20 @@ interface jsdIExecutionHook : nsISupports
|
||||
* All other return values, not significant.
|
||||
* @retval One of the jsdIExecutionHook::RETURN_* constants.
|
||||
*/
|
||||
unsigned long onExecute (in jsdIStackFrame frame,
|
||||
in unsigned long type, inout jsdIValue val);
|
||||
unsigned long onExecute(in jsdIStackFrame frame,
|
||||
in unsigned long type, inout jsdIValue val);
|
||||
};
|
||||
|
||||
/**
|
||||
* Objects which inherit this interface may go away, with (jsdIScript) or
|
||||
* without (all others) notification. These objects are generally wrappers
|
||||
* without (all others) notification. These objects are generally wrappers
|
||||
* around JSD structures that go away when you call jsdService::Off().
|
||||
*/
|
||||
[scriptable, uuid(46f1e23e-1dd2-11b2-9ceb-8285f2e95e69)]
|
||||
interface jsdIEphemeral : nsISupports
|
||||
{
|
||||
/**
|
||||
* |true| if this object is still valid. If not, many or all of the methods
|
||||
* |true| if this object is still valid. If not, many or all of the methods
|
||||
* and/or properties of the inheritor may no longer be callable.
|
||||
*/
|
||||
readonly attribute boolean isValid;
|
||||
@ -734,7 +732,7 @@ interface jsdIEphemeral : nsISupports
|
||||
/* handle objects */
|
||||
|
||||
/**
|
||||
* Context object. Only context's which are also nsISupports objects can be
|
||||
* Context object. Only context's which are also nsISupports objects can be
|
||||
* reflected by this interface.
|
||||
*/
|
||||
[scriptable, uuid(3e5c934d-6863-4d81-96f5-76a3b962fc2b)]
|
||||
@ -761,7 +759,7 @@ interface jsdIContext : jsdIEphemeral
|
||||
*/
|
||||
const long OPT_VAROBJFIX = 0x04;
|
||||
/**
|
||||
* Private data for this object is an nsISupports object. Attempting to
|
||||
* Private data for this object is an nsISupports object. Attempting to
|
||||
* alter this bit will result in an NS_ERROR_ILLEGAL_VALUE.
|
||||
*/
|
||||
const long OPT_ISUPPORTS = 0x08;
|
||||
@ -799,18 +797,18 @@ interface jsdIContext : jsdIEphemeral
|
||||
|
||||
/**
|
||||
* |true| if this context should be allowed to run scripts, |false|
|
||||
* otherwise. This attribute is only valid for contexts which implement
|
||||
* nsIScriptContext. Setting or getting this attribute on any other
|
||||
* otherwise. This attribute is only valid for contexts which implement
|
||||
* nsIScriptContext. Setting or getting this attribute on any other
|
||||
* context will throw a NS_ERROR_NO_INTERFACE exception.
|
||||
*/
|
||||
attribute boolean scriptsEnabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stack frame objects. These are only valid inside the jsdIExecutionHook which
|
||||
* gave it to you. After you return from that handler the bottom frame, and any
|
||||
* Stack frame objects. These are only valid inside the jsdIExecutionHook which
|
||||
* gave it to you. After you return from that handler the bottom frame, and any
|
||||
* frame you found attached through it, are invalidated via the jsdIEphemeral
|
||||
* interface. Once a jsdIStackFrame has been invalidated all method and
|
||||
* interface. Once a jsdIStackFrame has been invalidated all method and
|
||||
* property accesses will throw a NS_ERROR_NOT_AVAILABLE exception.
|
||||
*/
|
||||
[scriptable, uuid(0633ca73-105e-4e8e-bcc5-13405d61754a)]
|
||||
@ -872,18 +870,18 @@ interface jsdIStackFrame : jsdIEphemeral
|
||||
/**
|
||||
* Evaluate arbitrary JavaScript in this stack frame.
|
||||
* @param bytes Script to be evaluated.
|
||||
* @param fileName Filename to compile this script under. This is the
|
||||
* @param fileName Filename to compile this script under. This is the
|
||||
* filename you'll see in error messages, etc.
|
||||
* @param line Starting line number for this script. One based.
|
||||
* @param line Starting line number for this script. One based.
|
||||
* @retval Result of evaluating the script.
|
||||
*/
|
||||
boolean eval (in AString bytes, in AUTF8String fileName,
|
||||
in unsigned long line, out jsdIValue result);
|
||||
boolean eval(in AString bytes, in AUTF8String fileName,
|
||||
in unsigned long line, out jsdIValue result);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Script object. In JavaScript engine terms, there's a single script for each
|
||||
* Script object. In JavaScript engine terms, there's a single script for each
|
||||
* function, and one for the top level script.
|
||||
*/
|
||||
[scriptable, uuid(e7935220-7def-4c8e-832f-fbc948a97490)]
|
||||
@ -902,7 +900,7 @@ interface jsdIScript : jsdIEphemeral
|
||||
readonly attribute long version;
|
||||
|
||||
/**
|
||||
* Tag value guaranteed unique among jsdIScript objects. Useful as a
|
||||
* Tag value guaranteed unique among jsdIScript objects. Useful as a
|
||||
* hash key in script.
|
||||
*/
|
||||
readonly attribute unsigned long tag;
|
||||
@ -914,7 +912,7 @@ interface jsdIScript : jsdIEphemeral
|
||||
|
||||
/**
|
||||
* Determines whether or not to collect profile information for this
|
||||
* script. The context flag FLAG_PROFILE_WHEN_SET decides the logic.
|
||||
* script. The context flag FLAG_PROFILE_WHEN_SET decides the logic.
|
||||
*/
|
||||
const unsigned long FLAG_PROFILE = 0x01;
|
||||
/**
|
||||
@ -936,7 +934,7 @@ interface jsdIScript : jsdIEphemeral
|
||||
*/
|
||||
readonly attribute AUTF8String fileName;
|
||||
/**
|
||||
* Function name for this script. "anonymous" for unnamed functions (or
|
||||
* Function name for this script. "anonymous" for unnamed functions (or
|
||||
* a function actually named anonymous), empty for top level scripts.
|
||||
* This data is copied from the underlying structure when the jsdIScript
|
||||
* instance is created and is therefore available even after the script is
|
||||
@ -1020,39 +1018,39 @@ interface jsdIScript : jsdIEphemeral
|
||||
* Get the closest line number to a given PC.
|
||||
* The |pcmap| argument specifies which pc to source line map to use.
|
||||
*/
|
||||
unsigned long pcToLine (in unsigned long pc, in unsigned long pcmap);
|
||||
unsigned long pcToLine(in unsigned long pc, in unsigned long pcmap);
|
||||
/**
|
||||
* Get the first PC associated with a line.
|
||||
* The |pcmap| argument specifies which pc to source line map to use.
|
||||
*/
|
||||
unsigned long lineToPc (in unsigned long line, in unsigned long pcmap);
|
||||
unsigned long lineToPc(in unsigned long line, in unsigned long pcmap);
|
||||
/**
|
||||
* Determine is a particular line is executable, like checking that
|
||||
* lineToPc == pcToLine, except in one call.
|
||||
* The |pcmap| argument specifies which pc to source line map to use.
|
||||
*/
|
||||
boolean isLineExecutable (in unsigned long line, in unsigned long pcmap);
|
||||
boolean isLineExecutable(in unsigned long line, in unsigned long pcmap);
|
||||
/**
|
||||
* Set a breakpoint at a PC in this script.
|
||||
*/
|
||||
void setBreakpoint (in unsigned long pc);
|
||||
void setBreakpoint(in unsigned long pc);
|
||||
/**
|
||||
* Clear a breakpoint at a PC in this script.
|
||||
*/
|
||||
void clearBreakpoint (in unsigned long pc);
|
||||
void clearBreakpoint(in unsigned long pc);
|
||||
/**
|
||||
* Clear all breakpoints set in this script.
|
||||
*/
|
||||
void clearAllBreakpoints ();
|
||||
void clearAllBreakpoints();
|
||||
/**
|
||||
* Call interrupt hook at least once per source line
|
||||
*/
|
||||
void enableSingleStepInterrupts (in PRBool mode);
|
||||
void enableSingleStepInterrupts(in PRBool mode);
|
||||
};
|
||||
|
||||
/**
|
||||
* Value objects. Represents typeless JavaScript values (jsval in SpiderMonkey
|
||||
* terminology.) These are valid until the debugger is turned off. Holding a
|
||||
* Value objects. Represents typeless JavaScript values (jsval in SpiderMonkey
|
||||
* terminology.) These are valid until the debugger is turned off. Holding a
|
||||
* jsdIValue adds a root for the underlying JavaScript value, so don't keep it
|
||||
* if you don't need to.
|
||||
*/
|
||||
@ -1111,75 +1109,75 @@ interface jsdIValue : jsdIEphemeral
|
||||
*/
|
||||
readonly attribute jsdIValue jsParent;
|
||||
/**
|
||||
* Class name if this value represents an object. Empty AUTF8String if the value
|
||||
* Class name if this value represents an object. Empty AUTF8String if the value
|
||||
* is not an object.
|
||||
*/
|
||||
readonly attribute AUTF8String jsClassName;
|
||||
/**
|
||||
* Constructor name if this value represents an object. Empty AUTF8String if the
|
||||
* Constructor name if this value represents an object. Empty AUTF8String if the
|
||||
* value is not an object.
|
||||
*/
|
||||
readonly attribute jsdIValue jsConstructor;
|
||||
/**
|
||||
* Function name if this value represents a function. Empty AUTF8String if the
|
||||
* Function name if this value represents a function. Empty AUTF8String if the
|
||||
* value is not a function.
|
||||
*/
|
||||
readonly attribute AUTF8String jsFunctionName;
|
||||
|
||||
/**
|
||||
* Value if interpreted as a boolean. Converts if necessary.
|
||||
* Value if interpreted as a boolean. Converts if necessary.
|
||||
*/
|
||||
readonly attribute boolean booleanValue;
|
||||
readonly attribute boolean booleanValue;
|
||||
/**
|
||||
* Value if interpreted as a double. Converts if necessary.
|
||||
* Value if interpreted as a double. Converts if necessary.
|
||||
*/
|
||||
readonly attribute double doubleValue;
|
||||
readonly attribute double doubleValue;
|
||||
/**
|
||||
* Value if interpreted as an integer. Converts if necessary.
|
||||
* Value if interpreted as an integer. Converts if necessary.
|
||||
*/
|
||||
readonly attribute long intValue;
|
||||
readonly attribute long intValue;
|
||||
/**
|
||||
* Value if interpreted as an object.
|
||||
*/
|
||||
readonly attribute jsdIObject objectValue;
|
||||
readonly attribute jsdIObject objectValue;
|
||||
/**
|
||||
* Value if interpreted as a AUTF8String. Converts if necessary.
|
||||
* Value if interpreted as a AUTF8String. Converts if necessary.
|
||||
*/
|
||||
readonly attribute AUTF8String stringValue;
|
||||
readonly attribute AUTF8String stringValue;
|
||||
|
||||
/**
|
||||
* Number of properties. 0 if the value is not an object, or the value is
|
||||
* Number of properties. 0 if the value is not an object, or the value is
|
||||
* an object but has no properties.
|
||||
*/
|
||||
readonly attribute long propertyCount;
|
||||
|
||||
/**
|
||||
* Retrieves all properties if this value represents an object. If this
|
||||
* Retrieves all properties if this value represents an object. If this
|
||||
* value is not an object a 0 element array is returned.
|
||||
* @param propArray Array of jsdIProperty values for this value.
|
||||
* @param length Size of array.
|
||||
*/
|
||||
void getProperties ([array, size_is(length)] out jsdIProperty propArray,
|
||||
out unsigned long length);
|
||||
void getProperties([array, size_is(length)] out jsdIProperty propArray,
|
||||
out unsigned long length);
|
||||
/**
|
||||
* Retrieves a single property from the value. Only valid if the value
|
||||
* Retrieves a single property from the value. Only valid if the value
|
||||
* represents an object.
|
||||
* @param name Name of the property to retrieve.
|
||||
* @retval jsdIProperty for the requested property name or null if no
|
||||
* property exists for the requested name.
|
||||
*/
|
||||
jsdIProperty getProperty (in AUTF8String name);
|
||||
jsdIProperty getProperty(in AUTF8String name);
|
||||
|
||||
/**
|
||||
* jsdIValues are wrappers around JavaScript engine structures. Much of the
|
||||
* data is copied instead of shared. The refresh method is used to resync
|
||||
* jsdIValues are wrappers around JavaScript engine structures. Much of the
|
||||
* data is copied instead of shared. The refresh method is used to resync
|
||||
* the jsdIValue with the underlying structure.
|
||||
*/
|
||||
void refresh();
|
||||
|
||||
/**
|
||||
* When called from JavaScript, this method returns the JavaScript value
|
||||
* wrapped by this jsdIValue. The calling script is free to use the result
|
||||
* wrapped by this jsdIValue. The calling script is free to use the result
|
||||
* as it would any other JavaScript value.
|
||||
* When called from another language this method returns an xpconnect
|
||||
* defined error code.
|
||||
@ -1199,7 +1197,7 @@ interface jsdIValue : jsdIEphemeral
|
||||
* jsdIValue from whence your jsdIObject instance came for at least as long as
|
||||
* you hold the jsdIObject.
|
||||
* XXX Maybe the jsClassName, jsConstructorName, and property related attribute/
|
||||
* functions from jsdIValue should move to this interface. We could inherit from
|
||||
* functions from jsdIValue should move to this interface. We could inherit from
|
||||
* jsdIValue or use interface flattening or something.
|
||||
*/
|
||||
[scriptable, uuid(87d86308-7a27-4255-b23c-ce2394f02473)]
|
||||
@ -1235,7 +1233,7 @@ interface jsdIObject : nsISupports
|
||||
};
|
||||
|
||||
/**
|
||||
* Representation of a property of an object. When an instance is invalid, all
|
||||
* Representation of a property of an object. When an instance is invalid, all
|
||||
* method and property access will result in a NS_UNAVAILABLE error.
|
||||
*/
|
||||
[scriptable, uuid(09332485-1419-42bc-ba1f-070815ed4b82)]
|
||||
@ -1279,25 +1277,4 @@ interface jsdIProperty : jsdIEphemeral
|
||||
readonly attribute jsdIValue value;
|
||||
/** slot number if this property is a local variable or parameter. */
|
||||
readonly attribute unsigned long varArgSlot;
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
[scriptable, uuid(a47adad2-1dd1-11b2-b9e9-8e67a47beca5)]
|
||||
interface jsdISourceText : nsISupports
|
||||
{};
|
||||
|
||||
[scriptable, uuid(b6d1c006-1dd1-11b2-b9d8-b4d1ccfb74d8)]
|
||||
interface jsdIThreadState : nsISupports
|
||||
{
|
||||
[noscript] readonly attribute JSDContext JSDContext;
|
||||
[noscript] readonly attribute JSDThreadState JSDThreadState;
|
||||
|
||||
readonly attribute unsigned long frameCount;
|
||||
readonly attribute jsdIStackFrame topFrame;
|
||||
|
||||
attribute jsdIValue pendingException;
|
||||
};
|
||||
|
||||
*/
|
||||
|
||||
|
@ -680,7 +680,7 @@ jsd_GetValueFunction(JSDContext* jsdc, JSDValue* jsdval)
|
||||
return NULL;
|
||||
if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
|
||||
return NULL;
|
||||
obj = JS_UnwrapObject(jsdc->dumbContext, obj);
|
||||
obj = JS_UnwrapObject(obj);
|
||||
|
||||
call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, obj);
|
||||
if (!call)
|
||||
|
@ -59,9 +59,8 @@ ifndef JS_DISABLE_SHELL
|
||||
DIRS += shell
|
||||
endif
|
||||
|
||||
# FIXME: bug 515383 covers getting these working on wince
|
||||
# bug 530688 covers Android
|
||||
ifneq (,$(filter-out WINCE ANDROID,$(OS_ARCH)))
|
||||
# FIXME: bug 530688 covers getting these working on Android
|
||||
ifneq (,$(filter-out ANDROID,$(OS_ARCH)))
|
||||
ifdef ENABLE_TESTS
|
||||
DIRS += jsapi-tests
|
||||
endif
|
||||
@ -88,7 +87,6 @@ MODULE_OPTIMIZE_FLAGS = -O2 -ip
|
||||
endif
|
||||
else # not INTEL_CXX
|
||||
|
||||
#FAIL_ON_WARNINGS = 1
|
||||
MODULE_OPTIMIZE_FLAGS = -O3 -fstrict-aliasing -fno-stack-protector
|
||||
|
||||
# We normally want -fomit-frame-pointer, but we want an explicit
|
||||
@ -158,6 +156,7 @@ CPPSRCS = \
|
||||
jsnum.cpp \
|
||||
jsobj.cpp \
|
||||
json.cpp \
|
||||
jsonparser.cpp \
|
||||
jsopcode.cpp \
|
||||
jsparse.cpp \
|
||||
jsproxy.cpp \
|
||||
@ -215,9 +214,11 @@ INSTALLED_HEADERS = \
|
||||
jslock.h \
|
||||
jslong.h \
|
||||
jsmath.h \
|
||||
jsnum.h \
|
||||
jsobj.h \
|
||||
jsobjinlines.h \
|
||||
json.h \
|
||||
jsonparser.h \
|
||||
jsopcode.tbl \
|
||||
jsopcode.h \
|
||||
jsopcodeinlines.h \
|
||||
@ -314,13 +315,6 @@ CPPSRCS += \
|
||||
Writer.cpp \
|
||||
$(NULL)
|
||||
|
||||
ifdef WINCE
|
||||
# don't need -c
|
||||
AS_DASH_C_FLAG =
|
||||
ASFLAGS += -arch 6
|
||||
ASFILES += jswince.asm
|
||||
endif
|
||||
|
||||
endif # ENABLE_TRACEJIT
|
||||
ifdef ENABLE_METHODJIT
|
||||
|
||||
@ -501,7 +495,7 @@ else
|
||||
CPPSRCS += pm_stub.cpp
|
||||
endif
|
||||
|
||||
ifeq (,$(filter-out WINNT WINCE,$(OS_ARCH)))
|
||||
ifeq (,$(filter-out WINNT,$(OS_ARCH)))
|
||||
INSTALLED_HEADERS += jscpucfg.h
|
||||
endif
|
||||
|
||||
@ -509,7 +503,7 @@ EXPORTS = $(INSTALLED_HEADERS)
|
||||
|
||||
DASH_R = -r
|
||||
|
||||
ifneq (,$(filter OS2 WINCE WINNT,$(OS_ARCH)))
|
||||
ifneq (,$(filter OS2 WINNT,$(OS_ARCH)))
|
||||
SDK_LIBRARY = $(IMPORT_LIBRARY)
|
||||
else
|
||||
SDK_LIBRARY = $(SHARED_LIBRARY)
|
||||
@ -543,7 +537,7 @@ endif
|
||||
default::
|
||||
|
||||
ifneq (,$(CROSS_COMPILE)$(filter-out WINNT OS2,$(OS_ARCH)))
|
||||
ifneq (,$(filter-out SYMBIAN WINCE,$(OS_ARCH)))
|
||||
ifneq (,$(filter-out SYMBIAN,$(OS_ARCH)))
|
||||
# nsinstall doesn't get built until we enter config/ in the exports phase,
|
||||
# so we'll have to manually ensure it gets built here if we want to use
|
||||
# $(EXPORTS)
|
||||
@ -567,7 +561,6 @@ distclean clean::
|
||||
$(call SUBMAKE,$@,ctypes/libffi)
|
||||
endif
|
||||
|
||||
ifdef MOZ_SYNC_BUILD_FILES
|
||||
# Because the SpiderMonkey can be distributed and built independently
|
||||
# of the Mozilla source tree, it contains its own copies of many of
|
||||
# the files used by the top-level Mozilla build process, from the
|
||||
@ -582,32 +575,33 @@ ifdef MOZ_SYNC_BUILD_FILES
|
||||
# Some files are reasonable to diverge; for example,
|
||||
# js/config/autoconf.mk.in doesn't need most of the stuff in
|
||||
# config/autoconf.mk.in.
|
||||
check-sync-dirs = $(PYTHON) $(srcdir)/config/check-sync-dirs.py
|
||||
check::
|
||||
$(check-sync-dirs) $(srcdir)/config $(MOZ_SYNC_BUILD_FILES)/config
|
||||
$(check-sync-dirs) $(srcdir)/build $(MOZ_SYNC_BUILD_FILES)/build
|
||||
check-sync-dirs-cmd = $(PYTHON) $(srcdir)/config/check-sync-dirs.py
|
||||
check-sync-dirs:
|
||||
$(check-sync-dirs-cmd) $(srcdir)/config $(MOZ_SYNC_BUILD_FILES)/config
|
||||
$(check-sync-dirs-cmd) $(srcdir)/build $(MOZ_SYNC_BUILD_FILES)/build
|
||||
|
||||
check-valgrind::
|
||||
$(check-sync-dirs) $(srcdir)/config $(MOZ_SYNC_BUILD_FILES)/config
|
||||
$(check-sync-dirs) $(srcdir)/build $(MOZ_SYNC_BUILD_FILES)/build
|
||||
ifdef MOZ_SYNC_BUILD_FILES
|
||||
check:: check-sync-dirs
|
||||
endif
|
||||
|
||||
# The "find any vanilla new/new[] calls" script is tailored to Linux, so
|
||||
# only run it there. That should be enough to catch any such calls that
|
||||
# creep in.
|
||||
ifeq ($(OS_ARCH),Linux)
|
||||
check::
|
||||
check-vanilla-new:
|
||||
$(srcdir)/config/find_vanilla_new_calls $(LIBRARY)
|
||||
|
||||
ifeq ($(OS_ARCH),Linux)
|
||||
check:: check-vanilla-new
|
||||
endif
|
||||
|
||||
# Help ensure that the number of OOM errors in SpiderMonkey doesn't increase.
|
||||
# If the number of OOM errors changes, update the number below. We intend this
|
||||
# number to go down over time, by fixing OOMs.
|
||||
ifdef DEBUG
|
||||
check-ooms:
|
||||
$(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/config/find_OOM_errors.py --regression 125
|
||||
|
||||
check:: check-ooms
|
||||
ifeq ($(MOZ_DEBUG),1)
|
||||
#check:: check-ooms
|
||||
endif
|
||||
|
||||
## Prevent regressing in our deprecation of non-preferred memory management functions.
|
||||
@ -615,7 +609,6 @@ endif
|
||||
# don't give different results. We skip the contents of objdirs using |find|
|
||||
# (it can't be done with %-expansion, because the files we want to skip aren't
|
||||
# in the vpath).
|
||||
ifneq ($(OS_ARCH),WINNT) # FIXME: this should be made work on Windows too.
|
||||
ALL_FILES=$(shell find $(srcdir) \( -name "*.cpp" -o -name "*.h" \) -not -path "*/dist/*")
|
||||
check-malloc-function-usage: $(filter-out %jsutil.h %jscntxt.h, $(ALL_FILES))
|
||||
|
||||
@ -635,22 +628,45 @@ check-malloc-function-usage: $(filter-out %jsutil.h %jscntxt.h, $(ALL_FILES))
|
||||
$(srcdir)/config/check_source_count.py OffTheBooks:: 54 \
|
||||
"in Makefile.in" "{cx,rt}->{new_,new_array,malloc_,calloc_,realloc_}" $^
|
||||
# This should go to zero, if possible.
|
||||
$(srcdir)/config/check_source_count.py UnwantedForeground:: 36 \
|
||||
$(srcdir)/config/check_source_count.py UnwantedForeground:: 35 \
|
||||
"in Makefile.in" "{cx,rt}->{free_,delete_,array_delete}" $^
|
||||
|
||||
ifneq ($(OS_ARCH),WINNT) # FIXME: this should be made work on Windows too.
|
||||
check:: check-malloc-function-usage
|
||||
endif
|
||||
|
||||
ifndef WINCE
|
||||
JITFLAGS = ,m,j,mj,mjp,am,amj,amjp,amd
|
||||
check::
|
||||
check-jit-test::
|
||||
$(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/jit-test/jit_test.py \
|
||||
--no-slow --no-progress --tinderbox --jitflags=$(JITFLAGS) $(DIST)/bin/js$(BIN_SUFFIX)
|
||||
|
||||
check-valgrind::
|
||||
check-jit-test-valgrind::
|
||||
$(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/jit-test/jit_test.py \
|
||||
--valgrind --no-slow --no-progress --tinderbox --jitflags=$(JITFLAGS) $(DIST)/bin/js$(BIN_SUFFIX)
|
||||
endif
|
||||
|
||||
|
||||
# jstests doesn't have a --jitflags option, so we need to loop, updating the
|
||||
# exit code (RC) after each invocation.
|
||||
# FIXME: MethodJIT doesn't work for 1 test case (bug 644393), so
|
||||
# --no-extensions is set to skip that test. Remove as soon as possible.
|
||||
check-jstests:
|
||||
RC=0; \
|
||||
for f in `echo "$(JITFLAGS)" | tr ',' '\n'`; \
|
||||
do \
|
||||
$(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/tests/jstests.py \
|
||||
--tinderbox --no-progress \
|
||||
--no-extensions \
|
||||
--timeout 300 \
|
||||
--args="`echo $$f | sed 's/\(.\)/ -\1/g'`" \
|
||||
$(DIST)/bin/js$(BIN_SUFFIX); \
|
||||
RC=$$(( $$RC || $$?)); \
|
||||
done; \
|
||||
exit $$RC
|
||||
|
||||
|
||||
check:: check-jit-test
|
||||
#check:: check-jstests
|
||||
check-valgrind:: check-jit-test-valgrind
|
||||
|
||||
DIST_GARBAGE = config.cache config.log config.status \
|
||||
config/autoconf.mk \
|
||||
@ -710,7 +726,7 @@ LIBS += C:/Program\ Files/Intel/VTune/Analyzer/Lib/VtuneApi.lib
|
||||
endif
|
||||
|
||||
# HP-UX does not require the extra linking of "-lm"
|
||||
ifeq (,$(filter HP-UX WINNT WINCE OS2,$(OS_ARCH)))
|
||||
ifeq (,$(filter HP-UX WINNT OS2,$(OS_ARCH)))
|
||||
EXTRA_LIBS += -lm
|
||||
endif
|
||||
|
||||
@ -819,16 +835,11 @@ ifeq (,$(CROSS_COMPILE)$(GNU_CC)$(filter-out WINNT,$(OS_ARCH)))
|
||||
jsautocfg.h:
|
||||
$(TOUCH) $@
|
||||
else
|
||||
ifeq ($(OS_ARCH),WINCE)
|
||||
jsautocfg.h:
|
||||
$(TOUCH) $@
|
||||
else
|
||||
jsautocfg.h: jscpucfg$(HOST_BIN_SUFFIX)
|
||||
@$(RM) $@ jsautocfg.tmp
|
||||
./jscpucfg > jsautocfg.tmp
|
||||
mv jsautocfg.tmp $@
|
||||
endif
|
||||
endif
|
||||
|
||||
# jscpucfg is a strange target
|
||||
# Needs to be built with the host compiler but needs to include
|
||||
@ -853,14 +864,9 @@ jscpucfg: jscpucfg.o
|
||||
$(HOST_CXX) $(HOST_CXXFLAGS) $(JSCPUCFG_DEFINES) $(DEFINES) -o $@ $<
|
||||
endif
|
||||
else
|
||||
ifeq ($(OS_ARCH),WINCE)
|
||||
jscpucfg$(HOST_BIN_SUFFIX):
|
||||
echo no need to build jscpucfg $<
|
||||
else
|
||||
jscpucfg$(HOST_BIN_SUFFIX): jscpucfg.cpp Makefile.in
|
||||
$(HOST_CXX) $(HOST_CXXFLAGS) $(JSCPUCFG_DEFINES) $(DEFINES) $(NSPR_CFLAGS) $(HOST_OUTOPTION)$@ $<
|
||||
endif
|
||||
endif
|
||||
|
||||
# Compute the linker flags that programs linking against SpiderMonkey should
|
||||
# pass to get SpiderMonkey and its dependencies, beyond just the -L and -l
|
||||
|
@ -142,6 +142,7 @@ OS_LIBS = @LIBS@
|
||||
ACDEFINES = @MOZ_DEFINES@
|
||||
|
||||
WARNINGS_AS_ERRORS = @WARNINGS_AS_ERRORS@
|
||||
FAIL_ON_WARNINGS = @FAIL_ON_WARNINGS@
|
||||
|
||||
MOZ_OPTIMIZE = @MOZ_OPTIMIZE@
|
||||
MOZ_OPTIMIZE_FLAGS = @MOZ_OPTIMIZE_FLAGS@
|
||||
|
@ -70,7 +70,7 @@ def run(args, stdin=None):
|
||||
|
||||
def get_js_files():
|
||||
(out, err, exit) = run('find ../jit-test/tests -name "*.js"')
|
||||
if (err, exit) == ("", 0):
|
||||
if (err, exit) != ("", 0):
|
||||
sys.exit("Wrong directory, run from an objdir")
|
||||
return out.split()
|
||||
|
||||
@ -191,12 +191,12 @@ whitelist.add(r"('', 'out of memory\nout of memory\n', -11)")
|
||||
# Options
|
||||
parser = OptionParser(usage=usage)
|
||||
parser.add_option("-r", "--regression", action="store", metavar="REGRESSION_COUNT", help=help,
|
||||
type="int", dest="regression", default=0) # TODO: support a value of zero, eventually
|
||||
type="int", dest="regression", default=None)
|
||||
|
||||
(OPTIONS, args) = parser.parse_args()
|
||||
|
||||
|
||||
if OPTIONS.regression:
|
||||
if OPTIONS.regression != None:
|
||||
# TODO: This should be expanded as we get a better hang of the OOM problems.
|
||||
# For now, we'll just check that the number of OOMs in one short file does not
|
||||
# increase.
|
||||
@ -209,7 +209,7 @@ else:
|
||||
files = [f for f in files if f.find(args[0]) != -1]
|
||||
|
||||
|
||||
if OPTIONS.regression:
|
||||
if OPTIONS.regression == None:
|
||||
# Don't use a logfile, this is automated for tinderbox.
|
||||
log = file("../OOM_log", "w")
|
||||
|
||||
@ -229,6 +229,8 @@ for f in files:
|
||||
|
||||
if OPTIONS.regression == None:
|
||||
print "Testing allocation %d/%d in %s" % (i,max,f)
|
||||
else:
|
||||
sys.stdout.write('.') # something short for tinderbox, no space or \n
|
||||
|
||||
command = (command_template + ' -A %d') % (f, i)
|
||||
out, err, exit = run(command)
|
||||
@ -240,7 +242,7 @@ for f in files:
|
||||
# Failure
|
||||
else:
|
||||
|
||||
if OPTIONS.regression:
|
||||
if OPTIONS.regression != None:
|
||||
# Just count them
|
||||
num_failures += 1
|
||||
continue
|
||||
@ -314,12 +316,13 @@ for f in files:
|
||||
log.write ("\n")
|
||||
log.flush()
|
||||
|
||||
if not OPTIONS.regression == None:
|
||||
if OPTIONS.regression == None:
|
||||
count_lines()
|
||||
|
||||
print '\n',
|
||||
|
||||
# Do the actual regression check
|
||||
if OPTIONS.regression:
|
||||
if OPTIONS.regression != None:
|
||||
expected_num_failures = OPTIONS.regression
|
||||
|
||||
if num_failures != expected_num_failures:
|
||||
|
@ -4783,6 +4783,17 @@ if test "$MOZ_DISABLE_WARNINGS_AS_ERRORS"; then
|
||||
WARNINGS_AS_ERRORS=''
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable treating compile warnings as errors
|
||||
dnl ========================================================
|
||||
MOZ_ARG_ENABLE_BOOL(sm-fail-on-warnings,
|
||||
[ --enable-sm-fail-on-warnings
|
||||
Enable warnings as errors],
|
||||
FAIL_ON_WARNINGS=1,
|
||||
FAIL_ON_WARNINGS= )
|
||||
|
||||
AC_SUBST(FAIL_ON_WARNINGS)
|
||||
|
||||
dnl = Enable trace malloc
|
||||
dnl ========================================================
|
||||
NS_TRACE_MALLOC=${MOZ_TRACE_MALLOC}
|
||||
@ -5997,9 +6008,6 @@ if test "$JS_HAS_CTYPES"; then
|
||||
fi
|
||||
if test "$CROSS_COMPILE"; then
|
||||
case "$target" in
|
||||
*-mingw*)
|
||||
ac_configure_args="$ac_configure_args --build=$build --host=${target_cpu}-${target_os} HOST_CC=\"$HOST_CC\" CC=\"$CC\""
|
||||
;;
|
||||
*-android*)
|
||||
CFLAGS="$ANDROID_CFLAGS"
|
||||
CPPFLAGS="$ANDROID_CPPFLAGS"
|
||||
|
@ -215,6 +215,13 @@ def check_output(out, err, rc, allow_oom, expectedError):
|
||||
|
||||
return True
|
||||
|
||||
def print_tinderbox(label, test, message=None):
|
||||
jitflags = " ".join(test.jitflags)
|
||||
result = "%s | jit_test.py %-15s| %s" % (label, jitflags, test.path)
|
||||
if message:
|
||||
result += ": " + message
|
||||
print result
|
||||
|
||||
def run_tests(tests, test_dir, lib_dir):
|
||||
pb = None
|
||||
if not OPTIONS.hide_progress and not OPTIONS.show_cmd:
|
||||
@ -238,7 +245,7 @@ def run_tests(tests, test_dir, lib_dir):
|
||||
|
||||
if OPTIONS.tinderbox:
|
||||
if ok:
|
||||
print('TEST-PASS | jit_test.py | %s'%test.path)
|
||||
print_tinderbox("TEST-PASS", test);
|
||||
else:
|
||||
lines = [ _ for _ in out.split('\n') + err.split('\n')
|
||||
if _ != '' ]
|
||||
@ -246,8 +253,7 @@ def run_tests(tests, test_dir, lib_dir):
|
||||
msg = lines[-1]
|
||||
else:
|
||||
msg = ''
|
||||
print('TEST-UNEXPECTED-FAIL | jit_test.py | %s: %s'%
|
||||
(test.path, msg))
|
||||
print_tinderbox("TEST-UNEXPECTED-FAIL", test, msg);
|
||||
|
||||
n = i + 1
|
||||
if pb:
|
||||
@ -255,7 +261,7 @@ def run_tests(tests, test_dir, lib_dir):
|
||||
pb.update(n)
|
||||
complete = True
|
||||
except KeyboardInterrupt:
|
||||
print('TEST-UNEXPECTED_FAIL | jit_test.py | %s'%test.path)
|
||||
print_tinderbox("TEST-UNEXPECTED-FAIL", test);
|
||||
|
||||
if pb:
|
||||
pb.finish()
|
||||
|
@ -307,7 +307,7 @@ MSG_DEF(JSMSG_BAD_OBJECT_INIT, 224, 0, JSEXN_SYNTAXERR, "invalid object i
|
||||
MSG_DEF(JSMSG_CANT_SET_ARRAY_ATTRS, 225, 0, JSEXN_INTERNALERR, "can't set attributes on indexed array properties")
|
||||
MSG_DEF(JSMSG_EVAL_ARITY, 226, 0, JSEXN_TYPEERR, "eval accepts only one parameter")
|
||||
MSG_DEF(JSMSG_MISSING_FUN_ARG, 227, 2, JSEXN_TYPEERR, "missing argument {0} when calling function {1}")
|
||||
MSG_DEF(JSMSG_JSON_BAD_PARSE, 228, 0, JSEXN_SYNTAXERR, "JSON.parse")
|
||||
MSG_DEF(JSMSG_JSON_BAD_PARSE, 228, 1, JSEXN_SYNTAXERR, "JSON.parse: {0}")
|
||||
MSG_DEF(JSMSG_JSON_BAD_STRINGIFY, 229, 0, JSEXN_ERR, "JSON.stringify")
|
||||
MSG_DEF(JSMSG_XDR_CLOSURE_WRAPPER, 230, 1, JSEXN_INTERNALERR, "can't XDR closure wrapper for function {0}")
|
||||
MSG_DEF(JSMSG_NOT_NONNULL_OBJECT, 231, 0, JSEXN_TYPEERR, "value is not a non-null object")
|
||||
|
@ -67,8 +67,8 @@ CPPSRCS = \
|
||||
testLooselyEqual.cpp \
|
||||
testNewObject.cpp \
|
||||
testOps.cpp \
|
||||
testParseJSON.cpp \
|
||||
testPropCache.cpp \
|
||||
testRegExpInstanceProperties.cpp \
|
||||
testResolveRecursion.cpp \
|
||||
testSameValue.cpp \
|
||||
testScriptObject.cpp \
|
||||
@ -83,18 +83,26 @@ CPPSRCS = \
|
||||
testCustomIterator.cpp \
|
||||
$(NULL)
|
||||
|
||||
# Disabled: an entirely unrelated test seems to cause this to fail. Moreover,
|
||||
# given the test's dependence on interactions between the compiler, the GC, and
|
||||
# conservative stack scanning, the fix isn't obvious: more investigation
|
||||
# needed.
|
||||
#CPPSRCS += \
|
||||
# testRegExpInstanceProperties.cpp \
|
||||
# $(NULL)
|
||||
|
||||
DEFINES += -DEXPORT_JS_API
|
||||
|
||||
# Some platforms that have stdint.h include it in system headers. So
|
||||
# to reliably get limit macros defined, we'd always have to define the
|
||||
# one below before including any header, but that's obscure and
|
||||
# fragile, so we do it here.
|
||||
DEFINES += -D__STDC_LIMIT_MACROS
|
||||
|
||||
LIBS = $(DEPTH)/$(LIB_PREFIX)js_static.$(LIB_SUFFIX) $(NSPR_LIBS)
|
||||
|
||||
LOCAL_INCLUDES += -I$(topsrcdir) -I..
|
||||
|
||||
ifdef _MSC_VER
|
||||
ifdef WINCE
|
||||
WIN32_EXE_LDFLAGS += -ENTRY:mainACRTStartup
|
||||
endif
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
check::
|
||||
|
203
js/src/jsapi-tests/testParseJSON.cpp
Normal file
203
js/src/jsapi-tests/testParseJSON.cpp
Normal file
@ -0,0 +1,203 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=99:
|
||||
*/
|
||||
|
||||
#include <limits>
|
||||
#include <math.h>
|
||||
|
||||
#include "tests.h"
|
||||
#include "jsstr.h"
|
||||
|
||||
class AutoInflatedString {
|
||||
JSContext * const cx;
|
||||
jschar *chars_;
|
||||
size_t length_;
|
||||
|
||||
public:
|
||||
AutoInflatedString(JSContext *cx) : cx(cx), chars_(NULL), length_(0) { }
|
||||
~AutoInflatedString() {
|
||||
JS_free(cx, chars_);
|
||||
}
|
||||
|
||||
template<size_t N> void operator=(const char (&str)[N]) {
|
||||
length_ = N - 1;
|
||||
chars_ = js_InflateString(cx, str, &length_);
|
||||
if (!chars_)
|
||||
abort();
|
||||
}
|
||||
|
||||
const jschar *chars() const { return chars_; }
|
||||
size_t length() const { return length_; }
|
||||
};
|
||||
|
||||
template<size_t N> JSFlatString *
|
||||
NewString(JSContext *cx, const jschar (&chars)[N])
|
||||
{
|
||||
return js_NewStringCopyN(cx, chars, N);
|
||||
}
|
||||
|
||||
BEGIN_TEST(testParseJSON_success)
|
||||
{
|
||||
// Primitives
|
||||
CHECK(TryParse(cx, "true", JSVAL_TRUE));
|
||||
CHECK(TryParse(cx, "false", JSVAL_FALSE));
|
||||
CHECK(TryParse(cx, "null", JSVAL_NULL));
|
||||
CHECK(TryParse(cx, "0", INT_TO_JSVAL(0)));
|
||||
CHECK(TryParse(cx, "1", INT_TO_JSVAL(1)));
|
||||
CHECK(TryParse(cx, "-1", INT_TO_JSVAL(-1)));
|
||||
CHECK(TryParse(cx, "1", DOUBLE_TO_JSVAL(1)));
|
||||
CHECK(TryParse(cx, "1.75", DOUBLE_TO_JSVAL(1.75)));
|
||||
CHECK(TryParse(cx, "9e9", DOUBLE_TO_JSVAL(9e9)));
|
||||
CHECK(TryParse(cx, "9e99999", DOUBLE_TO_JSVAL(std::numeric_limits<jsdouble>::infinity())));
|
||||
|
||||
JSFlatString *str;
|
||||
|
||||
const jschar emptystr[] = { '\0' };
|
||||
str = js_NewStringCopyN(cx, emptystr, 0);
|
||||
CHECK(str);
|
||||
CHECK(TryParse(cx, "\"\"", STRING_TO_JSVAL(str)));
|
||||
|
||||
const jschar nullstr[] = { '\0' };
|
||||
str = NewString(cx, nullstr);
|
||||
CHECK(str);
|
||||
CHECK(TryParse(cx, "\"\\u0000\"", STRING_TO_JSVAL(str)));
|
||||
|
||||
const jschar backstr[] = { '\b' };
|
||||
str = NewString(cx, backstr);
|
||||
CHECK(str);
|
||||
CHECK(TryParse(cx, "\"\\b\"", STRING_TO_JSVAL(str)));
|
||||
CHECK(TryParse(cx, "\"\\u0008\"", STRING_TO_JSVAL(str)));
|
||||
|
||||
const jschar newlinestr[] = { '\n', };
|
||||
str = NewString(cx, newlinestr);
|
||||
CHECK(str);
|
||||
CHECK(TryParse(cx, "\"\\n\"", STRING_TO_JSVAL(str)));
|
||||
CHECK(TryParse(cx, "\"\\u000A\"", STRING_TO_JSVAL(str)));
|
||||
|
||||
|
||||
// Arrays
|
||||
jsval v, v2;
|
||||
JSObject *obj;
|
||||
|
||||
CHECK(Parse(cx, "[]", &v));
|
||||
CHECK(!JSVAL_IS_PRIMITIVE(v));
|
||||
obj = JSVAL_TO_OBJECT(v);
|
||||
CHECK(JS_IsArrayObject(cx, obj));
|
||||
CHECK(JS_GetProperty(cx, obj, "length", &v2));
|
||||
CHECK_SAME(v2, JSVAL_ZERO);
|
||||
|
||||
CHECK(Parse(cx, "[1]", &v));
|
||||
CHECK(!JSVAL_IS_PRIMITIVE(v));
|
||||
obj = JSVAL_TO_OBJECT(v);
|
||||
CHECK(JS_IsArrayObject(cx, obj));
|
||||
CHECK(JS_GetProperty(cx, obj, "0", &v2));
|
||||
CHECK_SAME(v2, JSVAL_ONE);
|
||||
CHECK(JS_GetProperty(cx, obj, "length", &v2));
|
||||
CHECK_SAME(v2, JSVAL_ONE);
|
||||
|
||||
|
||||
// Objects
|
||||
CHECK(Parse(cx, "{}", &v));
|
||||
CHECK(!JSVAL_IS_PRIMITIVE(v));
|
||||
obj = JSVAL_TO_OBJECT(v);
|
||||
CHECK(!JS_IsArrayObject(cx, obj));
|
||||
|
||||
CHECK(Parse(cx, "{ \"f\": 17 }", &v));
|
||||
CHECK(!JSVAL_IS_PRIMITIVE(v));
|
||||
obj = JSVAL_TO_OBJECT(v);
|
||||
CHECK(!JS_IsArrayObject(cx, obj));
|
||||
CHECK(JS_GetProperty(cx, obj, "f", &v2));
|
||||
CHECK_SAME(v2, INT_TO_JSVAL(17));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<size_t N> inline bool
|
||||
Parse(JSContext *cx, const char (&input)[N], jsval *vp)
|
||||
{
|
||||
AutoInflatedString str(cx);
|
||||
str = input;
|
||||
CHECK(JS_ParseJSON(cx, str.chars(), str.length(), vp));
|
||||
return true;
|
||||
}
|
||||
|
||||
template<size_t N> inline bool
|
||||
TryParse(JSContext *cx, const char (&input)[N], const jsval &expected)
|
||||
{
|
||||
AutoInflatedString str(cx);
|
||||
jsval v;
|
||||
str = input;
|
||||
CHECK(JS_ParseJSON(cx, str.chars(), str.length(), &v));
|
||||
CHECK_SAME(v, expected);
|
||||
return true;
|
||||
}
|
||||
END_TEST(testParseJSON_success)
|
||||
|
||||
BEGIN_TEST(testParseJSON_error)
|
||||
{
|
||||
CHECK(Error(cx, "["));
|
||||
CHECK(Error(cx, "[,]"));
|
||||
CHECK(Error(cx, "[1,]"));
|
||||
CHECK(Error(cx, "{a:2}"));
|
||||
CHECK(Error(cx, "{\"a\":2,}"));
|
||||
CHECK(Error(cx, "]"));
|
||||
CHECK(Error(cx, "'bad string'"));
|
||||
CHECK(Error(cx, "\""));
|
||||
CHECK(Error(cx, "{]"));
|
||||
CHECK(Error(cx, "[}"));
|
||||
return true;
|
||||
}
|
||||
|
||||
template<size_t N> inline bool
|
||||
Error(JSContext *cx, const char (&input)[N])
|
||||
{
|
||||
AutoInflatedString str(cx);
|
||||
jsval dummy;
|
||||
str = input;
|
||||
CHECK(!JS_ParseJSON(cx, str.chars(), str.length(), &dummy));
|
||||
JS_ClearPendingException(cx);
|
||||
return true;
|
||||
}
|
||||
END_TEST(testParseJSON_error)
|
||||
|
||||
static JSBool
|
||||
Censor(JSContext *cx, uintN argc, jsval *vp)
|
||||
{
|
||||
JS_ASSERT(argc == 2);
|
||||
#ifdef DEBUG
|
||||
jsval *argv = JS_ARGV(cx, vp);
|
||||
JS_ASSERT(JSVAL_IS_STRING(argv[0]));
|
||||
#endif
|
||||
JS_SET_RVAL(cx, vp, JSVAL_NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
BEGIN_TEST(testParseJSON_reviver)
|
||||
{
|
||||
JSFunction *fun = JS_NewFunction(cx, Censor, 0, 0, global, "censor");
|
||||
CHECK(fun);
|
||||
|
||||
jsval filter = OBJECT_TO_JSVAL(JS_GetFunctionObject(fun));
|
||||
|
||||
CHECK(TryParse(cx, "true", filter));
|
||||
CHECK(TryParse(cx, "false", filter));
|
||||
CHECK(TryParse(cx, "null", filter));
|
||||
CHECK(TryParse(cx, "1", filter));
|
||||
CHECK(TryParse(cx, "1.75", filter));
|
||||
CHECK(TryParse(cx, "[]", filter));
|
||||
CHECK(TryParse(cx, "[1]", filter));
|
||||
CHECK(TryParse(cx, "{}", filter));
|
||||
return true;
|
||||
}
|
||||
|
||||
template<size_t N> inline bool
|
||||
TryParse(JSContext *cx, const char (&input)[N], jsval filter)
|
||||
{
|
||||
AutoInflatedString str(cx);
|
||||
jsval v;
|
||||
str = input;
|
||||
CHECK(JS_ParseJSONWithReviver(cx, str.chars(), str.length(), filter, &v));
|
||||
CHECK_SAME(v, JSVAL_NULL);
|
||||
return true;
|
||||
}
|
||||
END_TEST(testParseJSON_reviver)
|
@ -136,10 +136,10 @@ class AutoVersionAPI
|
||||
oldHasVersionOverride(cx->isVersionOverridden()),
|
||||
oldVersionOverride(oldHasVersionOverride ? cx->findVersion() : JSVERSION_UNKNOWN)
|
||||
#ifdef DEBUG
|
||||
, oldCompileOptions(cx->getCompileOptions())
|
||||
, oldCompileOptions(cx->getCompileOptions())
|
||||
#endif
|
||||
{
|
||||
/*
|
||||
/*
|
||||
* Note: ANONFUNFIX in newVersion is ignored for backwards
|
||||
* compatibility, must be set via JS_SetOptions. (Because of this, we
|
||||
* inherit the current ANONFUNFIX setting from the options.
|
||||
@ -1233,7 +1233,7 @@ JS_EnterCrossCompartmentCallScript(JSContext *cx, JSScript *target)
|
||||
SwitchToCompartment sc(cx, target->compartment);
|
||||
scriptObject = JS_NewGlobalObject(cx, &dummy_class);
|
||||
if (!scriptObject)
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
return JS_EnterCrossCompartmentCall(cx, scriptObject);
|
||||
}
|
||||
@ -1276,7 +1276,7 @@ AutoEnterScriptCompartment::enter(JSContext *cx, JSScript *target)
|
||||
return true;
|
||||
}
|
||||
call = JS_EnterCrossCompartmentCallScript(cx, target);
|
||||
return call != NULL;
|
||||
return call != NULL;
|
||||
}
|
||||
|
||||
} /* namespace JS */
|
||||
@ -2932,8 +2932,18 @@ JS_PUBLIC_API(JSBool)
|
||||
JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj);
|
||||
return InstanceOf(cx, obj, Valueify(clasp), Valueify(argv));
|
||||
#ifdef DEBUG
|
||||
if (argv) {
|
||||
assertSameCompartment(cx, obj);
|
||||
assertSameCompartment(cx, JSValueArray(argv - 2, 2));
|
||||
}
|
||||
#endif
|
||||
if (!obj || obj->getJSClass() != clasp) {
|
||||
if (argv)
|
||||
ReportIncompatibleMethod(cx, Valueify(argv - 2), Valueify(clasp));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
@ -2959,7 +2969,7 @@ JS_SetPrivate(JSContext *cx, JSObject *obj, void *data)
|
||||
JS_PUBLIC_API(void *)
|
||||
JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
|
||||
{
|
||||
if (!InstanceOf(cx, obj, Valueify(clasp), Valueify(argv)))
|
||||
if (!JS_InstanceOf(cx, obj, clasp, argv))
|
||||
return NULL;
|
||||
return obj->getPrivate();
|
||||
}
|
||||
@ -4712,7 +4722,7 @@ CompileFileHelper(JSContext *cx, JSObject *obj, JSPrincipals *principals,
|
||||
JSObject *scriptObj = js_NewScriptObject(cx, script);
|
||||
if (!scriptObj)
|
||||
js_DestroyScript(cx, script);
|
||||
|
||||
|
||||
return scriptObj;
|
||||
}
|
||||
|
||||
@ -4741,7 +4751,7 @@ JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
|
||||
if (fp != stdin)
|
||||
fclose(fp);
|
||||
} while (false);
|
||||
|
||||
|
||||
LAST_FRAME_CHECKS(cx, scriptObj);
|
||||
return scriptObj;
|
||||
}
|
||||
@ -5612,6 +5622,22 @@ JS_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver)
|
||||
return js_FinishJSONParse(cx, jp, Valueify(reviver));
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_ParseJSON(JSContext *cx, const jschar *chars, uint32 len, jsval *vp)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
return ParseJSONWithReviver(cx, chars, len, NullValue(), Valueify(vp));
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_ParseJSONWithReviver(JSContext *cx, const jschar *chars, uint32 len, jsval reviver, jsval *vp)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
return ParseJSONWithReviver(cx, chars, len, Valueify(reviver), Valueify(vp));
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_ReadStructuredClone(JSContext *cx, const uint64 *buf, size_t nbytes,
|
||||
uint32 version, jsval *vp,
|
||||
@ -6155,7 +6181,7 @@ JS_SetGCZeal(JSContext *cx, uint8 zeal)
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
#if !defined(STATIC_EXPORTABLE_JS_API) && !defined(STATIC_JS_API) && defined(XP_WIN) && !defined (WINCE)
|
||||
#if !defined(STATIC_EXPORTABLE_JS_API) && !defined(STATIC_JS_API) && defined(XP_WIN)
|
||||
|
||||
#include "jswin.h"
|
||||
|
||||
|
@ -3309,6 +3309,12 @@ JS_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver);
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_ParseJSON(JSContext *cx, const jschar *chars, uint32 len, jsval *vp);
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_ParseJSONWithReviver(JSContext *cx, const jschar *chars, uint32 len, jsval reviver, jsval *vp);
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
/* API for the HTML5 internal structured cloning algorithm. */
|
||||
|
@ -172,7 +172,7 @@ js_StringIsIndex(JSLinearString *str, jsuint *indexp)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
static bool
|
||||
ValueToLength(JSContext *cx, Value* vp, jsuint* plength)
|
||||
{
|
||||
if (vp->isInt32()) {
|
||||
@ -303,7 +303,7 @@ JSObject::willBeSparseDenseArray(uintN requiredCapacity, uintN newElementsHint)
|
||||
|
||||
if (requiredCapacity >= JSObject::NSLOTS_LIMIT)
|
||||
return true;
|
||||
|
||||
|
||||
uintN minimalDenseCount = requiredCapacity / 4;
|
||||
if (newElementsHint >= minimalDenseCount)
|
||||
return false;
|
||||
@ -311,7 +311,7 @@ JSObject::willBeSparseDenseArray(uintN requiredCapacity, uintN newElementsHint)
|
||||
|
||||
if (minimalDenseCount > cap)
|
||||
return true;
|
||||
|
||||
|
||||
Value *elems = getDenseArrayElements();
|
||||
for (uintN i = 0; i < cap; i++) {
|
||||
if (!elems[i].isMagic(JS_ARRAY_HOLE) && !--minimalDenseCount)
|
||||
@ -485,7 +485,7 @@ JSBool JS_FASTCALL
|
||||
js_EnsureDenseArrayCapacity(JSContext *cx, JSObject *obj, jsint i)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
Class *origObjClasp = obj->clasp;
|
||||
Class *origObjClasp = obj->clasp;
|
||||
#endif
|
||||
jsuint u = jsuint(i);
|
||||
JSBool ret = (obj->ensureDenseArrayElements(cx, u, 1) == JSObject::ED_OK);
|
||||
@ -1100,18 +1100,57 @@ JSObject::makeDenseArraySlow(JSContext *cx)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Transfer ownership of buffer to returned string. */
|
||||
static inline JSBool
|
||||
BufferToString(JSContext *cx, StringBuffer &sb, Value *rval)
|
||||
{
|
||||
JSString *str = sb.finishString();
|
||||
if (!str)
|
||||
return false;
|
||||
rval->setString(str);
|
||||
return true;
|
||||
}
|
||||
|
||||
#if JS_HAS_TOSOURCE
|
||||
class ArraySharpDetector
|
||||
{
|
||||
JSContext *cx;
|
||||
jschar *chars;
|
||||
JSHashEntry *he;
|
||||
bool sharp;
|
||||
|
||||
public:
|
||||
ArraySharpDetector(JSContext *cx)
|
||||
: cx(cx),
|
||||
chars(NULL),
|
||||
he(NULL),
|
||||
sharp(false)
|
||||
{}
|
||||
|
||||
bool init(JSObject *obj) {
|
||||
he = js_EnterSharpObject(cx, obj, NULL, &chars);
|
||||
if (!he)
|
||||
return false;
|
||||
sharp = IS_SHARP(he);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool initiallySharp() const {
|
||||
JS_ASSERT_IF(sharp, hasSharpChars());
|
||||
return sharp;
|
||||
}
|
||||
|
||||
void makeSharp() {
|
||||
MAKE_SHARP(he);
|
||||
}
|
||||
|
||||
bool hasSharpChars() const {
|
||||
return chars != NULL;
|
||||
}
|
||||
|
||||
jschar *takeSharpChars() {
|
||||
jschar *ret = chars;
|
||||
chars = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
~ArraySharpDetector() {
|
||||
if (chars)
|
||||
cx->free_(chars);
|
||||
if (he && !sharp)
|
||||
js_LeaveSharpObject(cx, NULL);
|
||||
}
|
||||
};
|
||||
|
||||
static JSBool
|
||||
array_toSource(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
@ -1120,58 +1159,48 @@ array_toSource(JSContext *cx, uintN argc, Value *vp)
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
if (!obj->isSlowArray() && !InstanceOf(cx, obj, &js_ArrayClass, vp + 2))
|
||||
if (!obj->isArray()) {
|
||||
ReportIncompatibleMethod(cx, vp, &js_ArrayClass);
|
||||
return false;
|
||||
}
|
||||
|
||||
ArraySharpDetector detector(cx);
|
||||
if (!detector.init(obj))
|
||||
return false;
|
||||
|
||||
/* Find joins or cycles in the reachable object graph. */
|
||||
jschar *sharpchars;
|
||||
JSHashEntry *he = js_EnterSharpObject(cx, obj, NULL, &sharpchars);
|
||||
if (!he)
|
||||
return false;
|
||||
bool initiallySharp = IS_SHARP(he);
|
||||
|
||||
/* After this point, all paths exit through the 'out' label. */
|
||||
MUST_FLOW_THROUGH("out");
|
||||
bool ok = false;
|
||||
|
||||
/*
|
||||
* This object will take responsibility for the jschar buffer until the
|
||||
* buffer is transferred to the returned JSString.
|
||||
*/
|
||||
StringBuffer sb(cx);
|
||||
|
||||
/* Cycles/joins are indicated by sharp objects. */
|
||||
#if JS_HAS_SHARP_VARS
|
||||
if (IS_SHARP(he)) {
|
||||
JS_ASSERT(sharpchars != 0);
|
||||
sb.replaceRawBuffer(sharpchars, js_strlen(sharpchars));
|
||||
if (detector.initiallySharp()) {
|
||||
jschar *chars = detector.takeSharpChars();
|
||||
sb.replaceRawBuffer(chars, js_strlen(chars));
|
||||
goto make_string;
|
||||
} else if (sharpchars) {
|
||||
MAKE_SHARP(he);
|
||||
sb.replaceRawBuffer(sharpchars, js_strlen(sharpchars));
|
||||
} else if (detector.hasSharpChars()) {
|
||||
detector.makeSharp();
|
||||
jschar *chars = detector.takeSharpChars();
|
||||
sb.replaceRawBuffer(chars, js_strlen(chars));
|
||||
}
|
||||
#else
|
||||
if (IS_SHARP(he)) {
|
||||
if (detector.initiallySharp()) {
|
||||
if (!sb.append("[]"))
|
||||
goto out;
|
||||
cx->free_(sharpchars);
|
||||
return false;
|
||||
goto make_string;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!sb.append('['))
|
||||
goto out;
|
||||
return false;
|
||||
|
||||
jsuint length;
|
||||
if (!js_GetLengthProperty(cx, obj, &length))
|
||||
goto out;
|
||||
return false;
|
||||
|
||||
for (jsuint index = 0; index < length; index++) {
|
||||
/* Use vp to locally root each element value. */
|
||||
JSBool hole;
|
||||
Value tmp;
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
||||
!GetElement(cx, obj, index, &hole, vp)) {
|
||||
goto out;
|
||||
!GetElement(cx, obj, index, &hole, &tmp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get element's character string. */
|
||||
@ -1179,52 +1208,89 @@ array_toSource(JSContext *cx, uintN argc, Value *vp)
|
||||
if (hole) {
|
||||
str = cx->runtime->emptyString;
|
||||
} else {
|
||||
str = js_ValueToSource(cx, *vp);
|
||||
str = js_ValueToSource(cx, tmp);
|
||||
if (!str)
|
||||
goto out;
|
||||
return false;
|
||||
}
|
||||
vp->setString(str);
|
||||
|
||||
const jschar *chars = str->getChars(cx);
|
||||
if (!chars)
|
||||
goto out;
|
||||
|
||||
/* Append element to buffer. */
|
||||
if (!sb.append(chars, chars + str->length()))
|
||||
goto out;
|
||||
if (!sb.append(str))
|
||||
return false;
|
||||
if (index + 1 != length) {
|
||||
if (!sb.append(", "))
|
||||
goto out;
|
||||
return false;
|
||||
} else if (hole) {
|
||||
if (!sb.append(','))
|
||||
goto out;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Finalize the buffer. */
|
||||
if (!sb.append(']'))
|
||||
goto out;
|
||||
return false;
|
||||
|
||||
make_string:
|
||||
if (!BufferToString(cx, sb, vp))
|
||||
goto out;
|
||||
JSString *str = sb.finishString();
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
ok = true;
|
||||
|
||||
out:
|
||||
if (!initiallySharp)
|
||||
js_LeaveSharpObject(cx, NULL);
|
||||
return ok;
|
||||
JS_SET_RVAL(cx, vp, StringValue(str));
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
class AutoArrayCycleDetector
|
||||
{
|
||||
JSContext *cx;
|
||||
JSObject *obj;
|
||||
uint32 genBefore;
|
||||
BusyArraysSet::AddPtr hashPointer;
|
||||
bool cycle;
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
|
||||
public:
|
||||
AutoArrayCycleDetector(JSContext *cx, JSObject *obj JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: cx(cx),
|
||||
obj(obj),
|
||||
cycle(true)
|
||||
{
|
||||
JS_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
|
||||
bool init()
|
||||
{
|
||||
BusyArraysSet &set = cx->busyArrays;
|
||||
hashPointer = set.lookupForAdd(obj);
|
||||
if (!hashPointer) {
|
||||
if (!set.add(hashPointer, obj))
|
||||
return false;
|
||||
cycle = false;
|
||||
genBefore = set.generation();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
~AutoArrayCycleDetector()
|
||||
{
|
||||
if (!cycle) {
|
||||
if (genBefore == cx->busyArrays.generation())
|
||||
cx->busyArrays.remove(hashPointer);
|
||||
else
|
||||
cx->busyArrays.remove(obj);
|
||||
}
|
||||
}
|
||||
|
||||
bool foundCycle() { return cycle; }
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
static JSBool
|
||||
array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
|
||||
JSString *sepstr, Value *rval)
|
||||
{
|
||||
JS_CHECK_RECURSION(cx, return false);
|
||||
|
||||
/* Get characters to use for the separator. */
|
||||
static const jschar comma = ',';
|
||||
const jschar *sep;
|
||||
size_t seplen;
|
||||
@ -1238,84 +1304,68 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
|
||||
seplen = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use HashTable entry as the cycle indicator. On first visit, create the
|
||||
* entry, and, when leaving, remove the entry.
|
||||
*/
|
||||
BusyArraysMap::AddPtr hashp = cx->busyArrays.lookupForAdd(obj);
|
||||
uint32 genBefore;
|
||||
if (!hashp) {
|
||||
/* Not in hash table, so not a cycle. */
|
||||
if (!cx->busyArrays.add(hashp, obj))
|
||||
return false;
|
||||
genBefore = cx->busyArrays.generation();
|
||||
} else {
|
||||
/* Cycle, so return empty string. */
|
||||
AutoArrayCycleDetector detector(cx, obj);
|
||||
if (!detector.init())
|
||||
return false;
|
||||
|
||||
if (detector.foundCycle()) {
|
||||
rval->setString(cx->runtime->atomState.emptyAtom);
|
||||
return true;
|
||||
}
|
||||
|
||||
AutoObjectRooter tvr(cx, obj);
|
||||
|
||||
/* After this point, all paths exit through the 'out' label. */
|
||||
MUST_FLOW_THROUGH("out");
|
||||
bool ok = false;
|
||||
|
||||
/*
|
||||
* This object will take responsibility for the jschar buffer until the
|
||||
* buffer is transferred to the returned JSString.
|
||||
*/
|
||||
StringBuffer sb(cx);
|
||||
|
||||
jsuint length;
|
||||
if (!js_GetLengthProperty(cx, obj, &length))
|
||||
goto out;
|
||||
return false;
|
||||
|
||||
for (jsuint index = 0; index < length; index++) {
|
||||
/* Use rval to locally root each element value. */
|
||||
JSBool hole;
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
||||
!GetElement(cx, obj, index, &hole, rval)) {
|
||||
goto out;
|
||||
StringBuffer sb(cx);
|
||||
|
||||
if (!locale && !seplen && obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj)) {
|
||||
/* Elements beyond 'capacity' are 'undefined' and thus can be ignored. */
|
||||
Value *beg = obj->getDenseArrayElements();
|
||||
Value *end = beg + Min(length, obj->getDenseArrayCapacity());
|
||||
for (Value *vp = beg; vp != end; ++vp) {
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx))
|
||||
return false;
|
||||
|
||||
if (!vp->isMagic(JS_ARRAY_HOLE) && !vp->isNullOrUndefined()) {
|
||||
if (!ValueToStringBuffer(cx, *vp, sb))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (jsuint index = 0; index < length; index++) {
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx))
|
||||
return false;
|
||||
|
||||
/* Get element's character string. */
|
||||
if (!(hole || rval->isNullOrUndefined())) {
|
||||
if (locale) {
|
||||
/* Work on obj.toLocalString() instead. */
|
||||
JSObject *robj;
|
||||
JSBool hole;
|
||||
if (!GetElement(cx, obj, index, &hole, rval))
|
||||
return false;
|
||||
|
||||
if (!js_ValueToObjectOrNull(cx, *rval, &robj))
|
||||
goto out;
|
||||
rval->setObjectOrNull(robj);
|
||||
JSAtom *atom = cx->runtime->atomState.toLocaleStringAtom;
|
||||
if (!js_TryMethod(cx, robj, atom, 0, NULL, rval))
|
||||
goto out;
|
||||
if (!hole && !rval->isNullOrUndefined()) {
|
||||
if (locale) {
|
||||
JSObject *robj = ToObject(cx, rval);
|
||||
if (!robj)
|
||||
return false;
|
||||
jsid id = ATOM_TO_JSID(cx->runtime->atomState.toLocaleStringAtom);
|
||||
if (!robj->callMethod(cx, id, 0, NULL, rval))
|
||||
return false;
|
||||
}
|
||||
if (!ValueToStringBuffer(cx, *rval, sb))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ValueToStringBuffer(cx, *rval, sb))
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Append the separator. */
|
||||
if (index + 1 != length) {
|
||||
if (!sb.append(sep, seplen))
|
||||
goto out;
|
||||
if (index + 1 != length) {
|
||||
if (!sb.append(sep, seplen))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Finalize the buffer. */
|
||||
if (!BufferToString(cx, sb, rval))
|
||||
goto out;
|
||||
|
||||
ok = true;
|
||||
|
||||
out:
|
||||
if (genBefore == cx->busyArrays.generation())
|
||||
cx->busyArrays.remove(hashp);
|
||||
else
|
||||
cx->busyArrays.remove(obj);
|
||||
return ok;
|
||||
JSString *str = sb.finishString();
|
||||
if (!str)
|
||||
return false;
|
||||
rval->setString(str);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ES5 15.4.4.2. NB: The algorithm here differs from the one in ES3. */
|
||||
@ -1485,7 +1535,7 @@ array_reverse(JSContext *cx, uintN argc, Value *vp)
|
||||
break;
|
||||
if (js_PrototypeHasIndexedProperties(cx, obj))
|
||||
break;
|
||||
|
||||
|
||||
/* An empty array or an array with no elements is already reversed. */
|
||||
if (len == 0 || obj->getDenseArrayCapacity() == 0)
|
||||
return true;
|
||||
|
@ -363,10 +363,8 @@ js_FinishAtomState(JSRuntime *rt)
|
||||
return;
|
||||
}
|
||||
|
||||
for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront()) {
|
||||
JSString *str = AtomEntryToKey(r.front());
|
||||
js_FinalizeStringRT(rt, str);
|
||||
}
|
||||
for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront())
|
||||
AtomEntryToKey(r.front())->finalize(rt);
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
js_FinishLock(&state->lock);
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "jsprvtd.h"
|
||||
#include "jshash.h"
|
||||
#include "jshashtable.h"
|
||||
#include "jsnum.h"
|
||||
#include "jspubtd.h"
|
||||
#include "jsstr.h"
|
||||
#include "jslock.h"
|
||||
@ -114,6 +115,16 @@ IdToJsval(jsid id)
|
||||
return Jsvalify(IdToValue(id));
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSString *
|
||||
IdToString(JSContext *cx, jsid id)
|
||||
{
|
||||
if (JSID_IS_STRING(id))
|
||||
return JSID_TO_STRING(id);
|
||||
if (JS_LIKELY(JSID_IS_INT(id)))
|
||||
return js_IntToString(cx, JSID_TO_INT(id));
|
||||
return js_ValueToString(cx, IdToValue(id));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if JS_BYTES_PER_WORD == 4
|
||||
|
@ -108,12 +108,6 @@
|
||||
using namespace js;
|
||||
using namespace js::gc;
|
||||
|
||||
static const size_t ARENA_HEADER_SIZE_HACK = 40;
|
||||
static const size_t TEMP_POOL_CHUNK_SIZE = 4096 - ARENA_HEADER_SIZE_HACK;
|
||||
|
||||
static void
|
||||
FreeContext(JSContext *cx);
|
||||
|
||||
#ifdef DEBUG
|
||||
JS_REQUIRES_STACK bool
|
||||
StackSegment::contains(const JSStackFrame *fp) const
|
||||
@ -151,6 +145,21 @@ StackSegment::computeNextFrame(JSStackFrame *fp) const
|
||||
return next;
|
||||
}
|
||||
|
||||
StackSpace::StackSpace()
|
||||
: base(NULL),
|
||||
#ifdef XP_WIN
|
||||
commitEnd(NULL),
|
||||
#endif
|
||||
end(NULL),
|
||||
currentSegment(NULL),
|
||||
#ifdef DEBUG
|
||||
invokeSegment(NULL),
|
||||
invokeFrame(NULL),
|
||||
#endif
|
||||
invokeArgEnd(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
StackSpace::init()
|
||||
{
|
||||
@ -182,9 +191,10 @@ StackSpace::init()
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
StackSpace::finish()
|
||||
StackSpace::~StackSpace()
|
||||
{
|
||||
if (!base)
|
||||
return;
|
||||
#ifdef XP_WIN
|
||||
VirtualFree(base, (commitEnd - base) * sizeof(Value), MEM_DECOMMIT);
|
||||
VirtualFree(base, 0, MEM_RELEASE);
|
||||
@ -508,90 +518,61 @@ AllFramesIter::operator++()
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
JSThreadData::init()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
/* The data must be already zeroed. */
|
||||
for (size_t i = 0; i != sizeof(*this); ++i)
|
||||
JS_ASSERT(reinterpret_cast<uint8*>(this)[i] == 0);
|
||||
#endif
|
||||
if (!stackSpace.init())
|
||||
return false;
|
||||
dtoaState = js_NewDtoaState();
|
||||
if (!dtoaState) {
|
||||
finish();
|
||||
return false;
|
||||
}
|
||||
nativeStackBase = GetNativeStackBase();
|
||||
namespace js {
|
||||
|
||||
ThreadData::ThreadData()
|
||||
: interruptFlags(0),
|
||||
#ifdef JS_THREADSAFE
|
||||
requestDepth(0),
|
||||
#endif
|
||||
#ifdef JS_TRACER
|
||||
/* Set the default size for the code cache to 16MB. */
|
||||
maxCodeCacheBytes = 16 * 1024 * 1024;
|
||||
onTraceCompartment(NULL),
|
||||
recordingCompartment(NULL),
|
||||
profilingCompartment(NULL),
|
||||
maxCodeCacheBytes(DEFAULT_JIT_CACHE_SIZE),
|
||||
#endif
|
||||
|
||||
return true;
|
||||
waiveGCQuota(false),
|
||||
dtoaState(NULL),
|
||||
nativeStackBase(GetNativeStackBase()),
|
||||
pendingProxyOperation(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
JSThreadData::finish()
|
||||
ThreadData::~ThreadData()
|
||||
{
|
||||
if (dtoaState)
|
||||
js_DestroyDtoaState(dtoaState);
|
||||
}
|
||||
|
||||
js_FinishGSNCache(&gsnCache);
|
||||
propertyCache.~PropertyCache();
|
||||
stackSpace.finish();
|
||||
bool
|
||||
ThreadData::init()
|
||||
{
|
||||
return stackSpace.init() && !!(dtoaState = js_NewDtoaState());
|
||||
}
|
||||
|
||||
void
|
||||
JSThreadData::mark(JSTracer *trc)
|
||||
ThreadData::triggerOperationCallback(JSRuntime *rt)
|
||||
{
|
||||
stackSpace.mark(trc);
|
||||
}
|
||||
|
||||
void
|
||||
JSThreadData::purge(JSContext *cx)
|
||||
{
|
||||
js_PurgeGSNCache(&gsnCache);
|
||||
|
||||
/* FIXME: bug 506341. */
|
||||
propertyCache.purge(cx);
|
||||
}
|
||||
/*
|
||||
* Use JS_ATOMIC_SET and JS_ATOMIC_INCREMENT in the hope that it ensures
|
||||
* the write will become immediately visible to other processors polling
|
||||
* the flag. Note that we only care about visibility here, not read/write
|
||||
* ordering: this field can only be written with the GC lock held.
|
||||
*/
|
||||
if (interruptFlags)
|
||||
return;
|
||||
JS_ATOMIC_SET(&interruptFlags, 1);
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
|
||||
static JSThread *
|
||||
NewThread(void *id)
|
||||
{
|
||||
JS_ASSERT(js_CurrentThreadId() == id);
|
||||
JSThread *thread = (JSThread *) OffTheBooks::calloc_(sizeof(JSThread));
|
||||
if (!thread)
|
||||
return NULL;
|
||||
JS_INIT_CLIST(&thread->contextList);
|
||||
thread->id = id;
|
||||
if (!thread->data.init()) {
|
||||
Foreground::free_(thread);
|
||||
return NULL;
|
||||
}
|
||||
return thread;
|
||||
/* rt->interruptCounter does not reflect suspended threads. */
|
||||
if (requestDepth != 0)
|
||||
JS_ATOMIC_INCREMENT(&rt->interruptCounter);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
DestroyThread(JSThread *thread)
|
||||
{
|
||||
/* The thread must have zero contexts. */
|
||||
JS_ASSERT(JS_CLIST_IS_EMPTY(&thread->contextList));
|
||||
} /* namespace js */
|
||||
|
||||
/*
|
||||
* The conservative GC scanner should be disabled when the thread leaves
|
||||
* the last request.
|
||||
*/
|
||||
JS_ASSERT(!thread->data.conservativeGC.hasStackToScan());
|
||||
|
||||
thread->data.finish();
|
||||
Foreground::free_(thread);
|
||||
}
|
||||
#ifdef JS_THREADSAFE
|
||||
|
||||
JSThread *
|
||||
js_CurrentThread(JSRuntime *rt)
|
||||
@ -618,14 +599,17 @@ js_CurrentThread(JSRuntime *rt)
|
||||
thread->data.nativeStackBase = GetNativeStackBase();
|
||||
} else {
|
||||
JS_UNLOCK_GC(rt);
|
||||
thread = NewThread(id);
|
||||
if (!thread)
|
||||
|
||||
thread = OffTheBooks::new_<JSThread>(id);
|
||||
if (!thread || !thread->init()) {
|
||||
Foreground::delete_(thread);
|
||||
return NULL;
|
||||
}
|
||||
JS_LOCK_GC(rt);
|
||||
js_WaitForGC(rt);
|
||||
if (!rt->threads.relookupOrAdd(p, id, thread)) {
|
||||
JS_UNLOCK_GC(rt);
|
||||
DestroyThread(thread);
|
||||
Foreground::delete_(thread);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -668,7 +652,7 @@ js_ClearContextThread(JSContext *cx)
|
||||
|
||||
#endif /* JS_THREADSAFE */
|
||||
|
||||
JSThreadData *
|
||||
ThreadData *
|
||||
js_CurrentThreadData(JSRuntime *rt)
|
||||
{
|
||||
#ifdef JS_THREADSAFE
|
||||
@ -686,13 +670,10 @@ JSBool
|
||||
js_InitThreads(JSRuntime *rt)
|
||||
{
|
||||
#ifdef JS_THREADSAFE
|
||||
if (!rt->threads.init(4))
|
||||
return false;
|
||||
return rt->threads.init(4);
|
||||
#else
|
||||
if (!rt->threadData.init())
|
||||
return false;
|
||||
return rt->threadData.init();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
@ -703,12 +684,9 @@ js_FinishThreads(JSRuntime *rt)
|
||||
return;
|
||||
for (JSThread::Map::Range r = rt->threads.all(); !r.empty(); r.popFront()) {
|
||||
JSThread *thread = r.front().value;
|
||||
JS_ASSERT(JS_CLIST_IS_EMPTY(&thread->contextList));
|
||||
DestroyThread(thread);
|
||||
Foreground::delete_(thread);
|
||||
}
|
||||
rt->threads.clear();
|
||||
#else
|
||||
rt->threadData.finish();
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -723,8 +701,7 @@ js_PurgeThreads(JSContext *cx)
|
||||
|
||||
if (JS_CLIST_IS_EMPTY(&thread->contextList)) {
|
||||
JS_ASSERT(cx->thread != thread);
|
||||
|
||||
DestroyThread(thread);
|
||||
Foreground::delete_(thread);
|
||||
e.removeFront();
|
||||
} else {
|
||||
thread->data.purge(cx);
|
||||
@ -735,6 +712,9 @@ js_PurgeThreads(JSContext *cx)
|
||||
#endif
|
||||
}
|
||||
|
||||
static const size_t ARENA_HEADER_SIZE_HACK = 40;
|
||||
static const size_t TEMP_POOL_CHUNK_SIZE = 4096 - ARENA_HEADER_SIZE_HACK;
|
||||
|
||||
JSContext *
|
||||
js_NewContext(JSRuntime *rt, size_t stackChunkSize)
|
||||
{
|
||||
@ -769,13 +749,13 @@ js_NewContext(JSRuntime *rt, size_t stackChunkSize)
|
||||
JS_ASSERT(cx->resolveFlags == 0);
|
||||
|
||||
if (!cx->busyArrays.init()) {
|
||||
FreeContext(cx);
|
||||
Foreground::delete_(cx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
if (!js_InitContextThread(cx)) {
|
||||
FreeContext(cx);
|
||||
Foreground::delete_(cx);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
@ -1107,35 +1087,6 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
|
||||
cx->dstOffsetCache.dumpStats();
|
||||
#endif
|
||||
JS_UNLOCK_GC(rt);
|
||||
FreeContext(cx);
|
||||
}
|
||||
|
||||
static void
|
||||
FreeContext(JSContext *cx)
|
||||
{
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_ASSERT(!cx->thread);
|
||||
#endif
|
||||
|
||||
/* Free the stuff hanging off of cx. */
|
||||
VOUCH_DOES_NOT_REQUIRE_STACK();
|
||||
JS_FinishArenaPool(&cx->tempPool);
|
||||
JS_FinishArenaPool(&cx->regExpPool);
|
||||
|
||||
if (cx->lastMessage)
|
||||
cx->free_(cx->lastMessage);
|
||||
|
||||
/* Remove any argument formatters. */
|
||||
JSArgumentFormatMap *map = cx->argumentFormatMap;
|
||||
while (map) {
|
||||
JSArgumentFormatMap *temp = map;
|
||||
map = map->next;
|
||||
cx->free_(temp);
|
||||
}
|
||||
|
||||
JS_ASSERT(!cx->resolvingList);
|
||||
|
||||
/* Finally, free cx itself. */
|
||||
Foreground::delete_(cx);
|
||||
}
|
||||
|
||||
@ -1720,7 +1671,7 @@ JSBool
|
||||
js_InvokeOperationCallback(JSContext *cx)
|
||||
{
|
||||
JSRuntime *rt = cx->runtime;
|
||||
JSThreadData *td = JS_THREAD_DATA(cx);
|
||||
ThreadData *td = JS_THREAD_DATA(cx);
|
||||
|
||||
JS_ASSERT_REQUEST_DEPTH(cx);
|
||||
JS_ASSERT(td->interruptFlags != 0);
|
||||
@ -1799,7 +1750,7 @@ TriggerOperationCallback(JSContext *cx)
|
||||
* assume that the calling thread is in a request so JSThread cannot be
|
||||
* GC-ed.
|
||||
*/
|
||||
JSThreadData *td;
|
||||
ThreadData *td;
|
||||
#ifdef JS_THREADSAFE
|
||||
JSThread *thread = cx->thread;
|
||||
if (!thread)
|
||||
@ -1915,6 +1866,31 @@ JSContext::JSContext(JSRuntime *rt)
|
||||
busyArrays()
|
||||
{}
|
||||
|
||||
JSContext::~JSContext()
|
||||
{
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_ASSERT(!thread);
|
||||
#endif
|
||||
|
||||
/* Free the stuff hanging off of cx. */
|
||||
VOUCH_DOES_NOT_REQUIRE_STACK();
|
||||
JS_FinishArenaPool(&tempPool);
|
||||
JS_FinishArenaPool(®ExpPool);
|
||||
|
||||
if (lastMessage)
|
||||
Foreground::free_(lastMessage);
|
||||
|
||||
/* Remove any argument formatters. */
|
||||
JSArgumentFormatMap *map = argumentFormatMap;
|
||||
while (map) {
|
||||
JSArgumentFormatMap *temp = map;
|
||||
map = map->next;
|
||||
Foreground::free_(temp);
|
||||
}
|
||||
|
||||
JS_ASSERT(!resolvingList);
|
||||
}
|
||||
|
||||
void
|
||||
JSContext::resetCompartment()
|
||||
{
|
||||
|
230
js/src/jscntxt.h
230
js/src/jscntxt.h
@ -74,35 +74,6 @@
|
||||
#pragma warning(disable:4355) /* Silence warning about "this" used in base member initializer list */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* js_GetSrcNote cache to avoid O(n^2) growth in finding a source note for a
|
||||
* given pc in a script. We use the script->code pointer to tag the cache,
|
||||
* instead of the script address itself, so that source notes are always found
|
||||
* by offset from the bytecode with which they were generated.
|
||||
*/
|
||||
typedef struct JSGSNCache {
|
||||
jsbytecode *code;
|
||||
JSDHashTable table;
|
||||
#ifdef JS_GSNMETER
|
||||
uint32 hits;
|
||||
uint32 misses;
|
||||
uint32 fills;
|
||||
uint32 purges;
|
||||
# define GSN_CACHE_METER(cache,cnt) (++(cache)->cnt)
|
||||
#else
|
||||
# define GSN_CACHE_METER(cache,cnt) /* nothing */
|
||||
#endif
|
||||
} JSGSNCache;
|
||||
|
||||
#define js_FinishGSNCache(cache) js_PurgeGSNCache(cache)
|
||||
|
||||
extern void
|
||||
js_PurgeGSNCache(JSGSNCache *cache);
|
||||
|
||||
/* These helper macros take a cx as parameter and operate on its GSN cache. */
|
||||
#define JS_PURGE_GSN_CACHE(cx) js_PurgeGSNCache(&JS_GSN_CACHE(cx))
|
||||
#define JS_METER_GSN_CACHE(cx,cnt) GSN_CACHE_METER(&JS_GSN_CACHE(cx), cnt)
|
||||
|
||||
/* Forward declarations of nanojit types. */
|
||||
namespace nanojit {
|
||||
|
||||
@ -498,7 +469,7 @@ class GeneratorFrameGuard : public FrameGuard
|
||||
/*
|
||||
* Stack layout
|
||||
*
|
||||
* Each JSThreadData has one associated StackSpace object which allocates all
|
||||
* Each ThreadData has one associated StackSpace object which allocates all
|
||||
* segments for the thread. StackSpace performs all such allocations in a
|
||||
* single, fixed-size buffer using a specific layout scheme that allows some
|
||||
* associations between segments, frames, and slots to be implicit, rather
|
||||
@ -648,9 +619,10 @@ class StackSpace
|
||||
static const size_t STACK_QUOTA = (VALUES_PER_STACK_FRAME + 18) *
|
||||
JS_MAX_INLINE_CALL_COUNT;
|
||||
|
||||
/* Kept as a member of JSThreadData; cannot use constructor/destructor. */
|
||||
StackSpace();
|
||||
~StackSpace();
|
||||
|
||||
bool init();
|
||||
void finish();
|
||||
|
||||
#ifdef DEBUG
|
||||
template <class T>
|
||||
@ -807,36 +779,54 @@ private:
|
||||
JSStackFrame *curfp;
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
/*
|
||||
* GetSrcNote cache to avoid O(n^2) growth in finding a source note for a
|
||||
* given pc in a script. We use the script->code pointer to tag the cache,
|
||||
* instead of the script address itself, so that source notes are always found
|
||||
* by offset from the bytecode with which they were generated.
|
||||
*/
|
||||
struct GSNCache {
|
||||
typedef HashMap<jsbytecode *,
|
||||
jssrcnote *,
|
||||
PointerHasher<jsbytecode *, 0>,
|
||||
SystemAllocPolicy> Map;
|
||||
|
||||
#ifdef DEBUG
|
||||
# define FUNCTION_KIND_METER_LIST(_) \
|
||||
_(allfun), _(heavy), _(nofreeupvar), _(onlyfreevar), \
|
||||
_(flat), _(badfunarg), \
|
||||
_(joinedsetmethod), _(joinedinitmethod), \
|
||||
_(joinedreplace), _(joinedsort), _(joinedmodulepat), \
|
||||
_(mreadbarrier), _(mwritebarrier), _(mwslotbarrier), \
|
||||
_(unjoined), _(indynamicscope)
|
||||
# define identity(x) x
|
||||
jsbytecode *code;
|
||||
Map map;
|
||||
#ifdef JS_GSNMETER
|
||||
struct Stats {
|
||||
uint32 hits;
|
||||
uint32 misses;
|
||||
uint32 fills;
|
||||
uint32 purges;
|
||||
|
||||
struct JSFunctionMeter {
|
||||
int32 FUNCTION_KIND_METER_LIST(identity);
|
||||
};
|
||||
Stats() : hits(0), misses(0), fills(0), purges(0) { }
|
||||
};
|
||||
|
||||
# undef identity
|
||||
|
||||
# define JS_FUNCTION_METER(cx,x) JS_RUNTIME_METER((cx)->runtime, functionMeter.x)
|
||||
#else
|
||||
# define JS_FUNCTION_METER(cx,x) ((void)0)
|
||||
Stats stats;
|
||||
#endif
|
||||
|
||||
GSNCache() : code(NULL) { }
|
||||
|
||||
struct JSPendingProxyOperation {
|
||||
JSPendingProxyOperation *next;
|
||||
JSObject *object;
|
||||
void purge();
|
||||
};
|
||||
|
||||
inline GSNCache *
|
||||
GetGSNCache(JSContext *cx);
|
||||
|
||||
struct PendingProxyOperation {
|
||||
PendingProxyOperation *next;
|
||||
JSObject *object;
|
||||
};
|
||||
|
||||
struct JSThreadData {
|
||||
struct ThreadData {
|
||||
/*
|
||||
* If non-zero, we were been asked to call the operation callback as soon
|
||||
* as possible. If the thread has an active request, this contributes
|
||||
* towards rt->interruptCounter.
|
||||
*/
|
||||
volatile int32 interruptFlags;
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
/* The request depth for this thread. */
|
||||
unsigned requestDepth;
|
||||
@ -854,17 +844,15 @@ struct JSThreadData {
|
||||
JSCompartment *onTraceCompartment;
|
||||
JSCompartment *recordingCompartment;
|
||||
JSCompartment *profilingCompartment;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If non-zero, we were been asked to call the operation callback as soon
|
||||
* as possible. If the thread has an active request, this contributes
|
||||
* towards rt->interruptCounter.
|
||||
*/
|
||||
volatile int32 interruptFlags;
|
||||
/* Maximum size of the tracer's code cache before we start flushing. */
|
||||
uint32 maxCodeCacheBytes;
|
||||
|
||||
static const uint32 DEFAULT_JIT_CACHE_SIZE = 16 * 1024 * 1024;
|
||||
#endif
|
||||
|
||||
/* Keeper of the contiguous stack used by all contexts in this thread. */
|
||||
js::StackSpace stackSpace;
|
||||
StackSpace stackSpace;
|
||||
|
||||
/*
|
||||
* Flag indicating that we are waiving any soft limits on the GC heap
|
||||
@ -876,15 +864,10 @@ struct JSThreadData {
|
||||
* The GSN cache is per thread since even multi-cx-per-thread embeddings
|
||||
* do not interleave js_GetSrcNote calls.
|
||||
*/
|
||||
JSGSNCache gsnCache;
|
||||
GSNCache gsnCache;
|
||||
|
||||
/* Property cache for faster call/get/set invocation. */
|
||||
js::PropertyCache propertyCache;
|
||||
|
||||
#ifdef JS_TRACER
|
||||
/* Maximum size of the tracer's code cache before we start flushing. */
|
||||
uint32 maxCodeCacheBytes;
|
||||
#endif
|
||||
PropertyCache propertyCache;
|
||||
|
||||
/* State used by dtoa.c. */
|
||||
DtoaState *dtoaState;
|
||||
@ -893,19 +876,32 @@ struct JSThreadData {
|
||||
jsuword *nativeStackBase;
|
||||
|
||||
/* List of currently pending operations on proxies. */
|
||||
JSPendingProxyOperation *pendingProxyOperation;
|
||||
PendingProxyOperation *pendingProxyOperation;
|
||||
|
||||
js::ConservativeGCThreadData conservativeGC;
|
||||
ConservativeGCThreadData conservativeGC;
|
||||
|
||||
ThreadData();
|
||||
~ThreadData();
|
||||
|
||||
bool init();
|
||||
void finish();
|
||||
void mark(JSTracer *trc);
|
||||
void purge(JSContext *cx);
|
||||
|
||||
void mark(JSTracer *trc) {
|
||||
stackSpace.mark(trc);
|
||||
}
|
||||
|
||||
void purge(JSContext *cx) {
|
||||
gsnCache.purge();
|
||||
|
||||
/* FIXME: bug 506341. */
|
||||
propertyCache.purge(cx);
|
||||
}
|
||||
|
||||
/* This must be called with the GC lock held. */
|
||||
inline void triggerOperationCallback(JSRuntime *rt);
|
||||
void triggerOperationCallback(JSRuntime *rt);
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
|
||||
/*
|
||||
@ -932,7 +928,26 @@ struct JSThread {
|
||||
# endif
|
||||
|
||||
/* Factored out of JSThread for !JS_THREADSAFE embedding in JSRuntime. */
|
||||
JSThreadData data;
|
||||
js::ThreadData data;
|
||||
|
||||
JSThread(void *id)
|
||||
: id(id),
|
||||
suspendCount(0)
|
||||
# ifdef DEBUG
|
||||
, checkRequestDepth(0)
|
||||
# endif
|
||||
{
|
||||
JS_INIT_CLIST(&contextList);
|
||||
}
|
||||
|
||||
~JSThread() {
|
||||
/* The thread must have zero contexts. */
|
||||
JS_ASSERT(JS_CLIST_IS_EMPTY(&contextList));
|
||||
}
|
||||
|
||||
bool init() {
|
||||
return data.init();
|
||||
}
|
||||
};
|
||||
|
||||
#define JS_THREAD_DATA(cx) (&(cx)->thread->data)
|
||||
@ -956,6 +971,27 @@ js_ClearContextThread(JSContext *cx);
|
||||
|
||||
#endif /* JS_THREADSAFE */
|
||||
|
||||
#ifdef DEBUG
|
||||
# define FUNCTION_KIND_METER_LIST(_) \
|
||||
_(allfun), _(heavy), _(nofreeupvar), _(onlyfreevar), \
|
||||
_(flat), _(badfunarg), \
|
||||
_(joinedsetmethod), _(joinedinitmethod), \
|
||||
_(joinedreplace), _(joinedsort), _(joinedmodulepat), \
|
||||
_(mreadbarrier), _(mwritebarrier), _(mwslotbarrier), \
|
||||
_(unjoined), _(indynamicscope)
|
||||
# define identity(x) x
|
||||
|
||||
struct JSFunctionMeter {
|
||||
int32 FUNCTION_KIND_METER_LIST(identity);
|
||||
};
|
||||
|
||||
# undef identity
|
||||
|
||||
# define JS_FUNCTION_METER(cx,x) JS_RUNTIME_METER((cx)->runtime, functionMeter.x)
|
||||
#else
|
||||
# define JS_FUNCTION_METER(cx,x) ((void)0)
|
||||
#endif
|
||||
|
||||
typedef enum JSDestroyContextMode {
|
||||
JSDCM_NO_GC,
|
||||
JSDCM_MAYBE_GC,
|
||||
@ -1182,7 +1218,6 @@ struct JSRuntime {
|
||||
|
||||
/* Script filename table. */
|
||||
struct JSHashTable *scriptFilenameTable;
|
||||
JSCList scriptFilenamePrefixes;
|
||||
#ifdef JS_THREADSAFE
|
||||
PRLock *scriptFilenameTableLock;
|
||||
#endif
|
||||
@ -1206,7 +1241,7 @@ struct JSRuntime {
|
||||
/* Number of threads with active requests and unhandled interrupts. */
|
||||
volatile int32 interruptCounter;
|
||||
#else
|
||||
JSThreadData threadData;
|
||||
js::ThreadData threadData;
|
||||
|
||||
#define JS_THREAD_DATA(cx) (&(cx)->runtime->threadData)
|
||||
#endif
|
||||
@ -1431,7 +1466,6 @@ struct JSRuntime {
|
||||
};
|
||||
|
||||
/* Common macros to access thread-local caches in JSThread or JSRuntime. */
|
||||
#define JS_GSN_CACHE(cx) (JS_THREAD_DATA(cx)->gsnCache)
|
||||
#define JS_PROPERTY_CACHE(cx) (JS_THREAD_DATA(cx)->propertyCache)
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -1584,15 +1618,16 @@ VersionIsKnown(JSVersion version)
|
||||
return VersionNumber(version) != JSVERSION_UNKNOWN;
|
||||
}
|
||||
|
||||
typedef js::HashSet<JSObject *,
|
||||
js::DefaultHasher<JSObject *>,
|
||||
js::SystemAllocPolicy> BusyArraysMap;
|
||||
typedef HashSet<JSObject *,
|
||||
DefaultHasher<JSObject *>,
|
||||
SystemAllocPolicy> BusyArraysSet;
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
struct JSContext
|
||||
{
|
||||
explicit JSContext(JSRuntime *rt);
|
||||
~JSContext();
|
||||
|
||||
/* JSRuntime contextList linkage. */
|
||||
JSCList link;
|
||||
@ -1679,7 +1714,7 @@ struct JSContext
|
||||
|
||||
/* State for object and array toSource conversion. */
|
||||
JSSharpObjectMap sharpObjectMap;
|
||||
js::BusyArraysMap busyArrays;
|
||||
js::BusyArraysSet busyArrays;
|
||||
|
||||
/* Argument formatter support for JS_{Convert,Push}Arguments{,VA}. */
|
||||
JSArgumentFormatMap *argumentFormatMap;
|
||||
@ -2857,7 +2892,7 @@ class JSAutoResolveFlags
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
extern JSThreadData *
|
||||
extern js::ThreadData *
|
||||
js_CurrentThreadData(JSRuntime *rt);
|
||||
|
||||
extern JSBool
|
||||
@ -2873,13 +2908,13 @@ namespace js {
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
|
||||
/* Iterator over JSThreadData from all JSThread instances. */
|
||||
/* Iterator over ThreadData from all JSThread instances. */
|
||||
class ThreadDataIter : public JSThread::Map::Range
|
||||
{
|
||||
public:
|
||||
ThreadDataIter(JSRuntime *rt) : JSThread::Map::Range(rt->threads.all()) {}
|
||||
|
||||
JSThreadData *threadData() const {
|
||||
ThreadData *threadData() const {
|
||||
return &front().value->data;
|
||||
}
|
||||
};
|
||||
@ -2902,7 +2937,7 @@ class ThreadDataIter
|
||||
done = true;
|
||||
}
|
||||
|
||||
JSThreadData *threadData() const {
|
||||
ThreadData *threadData() const {
|
||||
JS_ASSERT(!done);
|
||||
return &runtime->threadData;
|
||||
}
|
||||
@ -3060,26 +3095,6 @@ extern JSErrorFormatString js_ErrorFormatString[JSErr_Limit];
|
||||
(JS_ASSERT_REQUEST_DEPTH(cx), \
|
||||
(!JS_THREAD_DATA(cx)->interruptFlags || js_InvokeOperationCallback(cx)))
|
||||
|
||||
JS_ALWAYS_INLINE void
|
||||
JSThreadData::triggerOperationCallback(JSRuntime *rt)
|
||||
{
|
||||
/*
|
||||
* Use JS_ATOMIC_SET and JS_ATOMIC_INCREMENT in the hope that it ensures
|
||||
* the write will become immediately visible to other processors polling
|
||||
* the flag. Note that we only care about visibility here, not read/write
|
||||
* ordering: this field can only be written with the GC lock held.
|
||||
*/
|
||||
if (interruptFlags)
|
||||
return;
|
||||
JS_ATOMIC_SET(&interruptFlags, 1);
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
/* rt->interruptCounter does not reflect suspended threads. */
|
||||
if (requestDepth != 0)
|
||||
JS_ATOMIC_INCREMENT(&rt->interruptCounter);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Invoke the operation callback and return false if the current execution
|
||||
* is to be terminated.
|
||||
@ -3201,6 +3216,7 @@ class AutoVectorRooter : protected AutoGCRooter
|
||||
void infallibleAppend(const T &v) { vector.infallibleAppend(v); }
|
||||
|
||||
void popBack() { vector.popBack(); }
|
||||
T popCopy() { return vector.popCopy(); }
|
||||
|
||||
bool growBy(size_t inc) {
|
||||
size_t oldLength = vector.length();
|
||||
|
@ -496,6 +496,12 @@ FrameRegsIter::operator++()
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline GSNCache *
|
||||
GetGSNCache(JSContext *cx)
|
||||
{
|
||||
return &JS_THREAD_DATA(cx)->gsnCache;
|
||||
}
|
||||
|
||||
class AutoNamespaceArray : protected AutoGCRooter {
|
||||
public:
|
||||
AutoNamespaceArray(JSContext *cx) : AutoGCRooter(cx, NAMESPACES) {
|
||||
@ -735,12 +741,12 @@ CallJSNativeConstructor(JSContext *cx, js::Native native, uintN argc, js::Value
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE bool
|
||||
CallJSPropertyOp(JSContext *cx, js::PropertyOp op, JSObject *obj, jsid id, js::Value *vp)
|
||||
CallJSPropertyOp(JSContext *cx, js::PropertyOp op, JSObject *receiver, jsid id, js::Value *vp)
|
||||
{
|
||||
assertSameCompartment(cx, obj, id, *vp);
|
||||
JSBool ok = op(cx, obj, id, vp);
|
||||
assertSameCompartment(cx, receiver, id, *vp);
|
||||
JSBool ok = op(cx, receiver, id, vp);
|
||||
if (ok)
|
||||
assertSameCompartment(cx, obj, *vp);
|
||||
assertSameCompartment(cx, receiver, *vp);
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
@ -81,6 +81,7 @@ JSCompartment::JSCompartment(JSRuntime *rt)
|
||||
emptyEnumeratorShape(NULL),
|
||||
emptyWithShape(NULL),
|
||||
initialRegExpShape(NULL),
|
||||
initialStringShape(NULL),
|
||||
debugMode(rt->debugMode),
|
||||
#if ENABLE_YARR_JIT
|
||||
regExpAllocator(NULL),
|
||||
@ -488,6 +489,8 @@ JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
|
||||
|
||||
if (initialRegExpShape && IsAboutToBeFinalized(cx, initialRegExpShape))
|
||||
initialRegExpShape = NULL;
|
||||
if (initialStringShape && IsAboutToBeFinalized(cx, initialStringShape))
|
||||
initialStringShape = NULL;
|
||||
|
||||
#ifdef JS_TRACER
|
||||
traceMonitor.sweep(cx);
|
||||
|
@ -438,15 +438,16 @@ struct JS_FRIEND_API(JSCompartment) {
|
||||
EmptyShapeSet emptyShapes;
|
||||
|
||||
/*
|
||||
* Initial shape given to RegExp objects, encoding the initial set of
|
||||
* built-in instance properties and the fixed slots where they must be
|
||||
* stored (see JSObject::JSSLOT_REGEXP_*). Later property additions may
|
||||
* cause this shape to not be used by a regular expression (even along the
|
||||
* entire shape parent chain, should the object go into dictionary mode).
|
||||
* But because all the initial properties are non-configurable, they will
|
||||
* always map to fixed slots.
|
||||
* Initial shapes given to RegExp and String objects, encoding the initial
|
||||
* sets of built-in instance properties and the fixed slots where they must
|
||||
* be stored (see JSObject::JSSLOT_(REGEXP|STRING)_*). Later property
|
||||
* additions may cause these shapes to not be used by a RegExp or String
|
||||
* (even along the entire shape parent chain, should the object go into
|
||||
* dictionary mode). But because all the initial properties are
|
||||
* non-configurable, they will always map to fixed slots.
|
||||
*/
|
||||
const js::Shape *initialRegExpShape;
|
||||
const js::Shape *initialStringShape;
|
||||
|
||||
bool debugMode; // true iff debug mode on
|
||||
JSCList scripts; // scripts in this compartment
|
||||
|
@ -42,7 +42,7 @@
|
||||
|
||||
#define JS_HAVE_LONG_LONG
|
||||
|
||||
#if defined(XP_WIN) || defined(XP_OS2) || defined(WINCE)
|
||||
#if defined(XP_WIN) || defined(XP_OS2)
|
||||
|
||||
#if defined(_WIN64)
|
||||
|
||||
@ -57,7 +57,7 @@
|
||||
#error "CPU type is unknown"
|
||||
#endif /* !(defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)) */
|
||||
|
||||
#elif defined(_WIN32) || defined(XP_OS2) || defined(WINCE)
|
||||
#elif defined(_WIN32) || defined(XP_OS2)
|
||||
|
||||
#ifdef __WATCOMC__
|
||||
#define HAVE_VA_LIST_AS_ARRAY 1
|
||||
@ -70,7 +70,7 @@
|
||||
#define JS_BITS_PER_WORD_LOG2 5
|
||||
#define JS_ALIGN_OF_POINTER 4L
|
||||
|
||||
#endif /* _WIN32 || XP_OS2 || WINCE*/
|
||||
#endif /* _WIN32 || XP_OS2 */
|
||||
|
||||
#elif defined(XP_UNIX)
|
||||
|
||||
|
@ -195,7 +195,7 @@ IsLeapYear(jsint year)
|
||||
}
|
||||
|
||||
static inline jsint
|
||||
DaysInYear(jsint year)
|
||||
DaysInYear(jsint year)
|
||||
{
|
||||
return IsLeapYear(year) ? 366 : 365;
|
||||
}
|
||||
@ -632,8 +632,8 @@ date_UTC(JSContext *cx, uintN argc, Value *vp)
|
||||
|
||||
/*
|
||||
* Read and convert decimal digits from s[*i] into *result
|
||||
* while *i < limit.
|
||||
*
|
||||
* while *i < limit.
|
||||
*
|
||||
* Succeed if any digits are converted. Advance *i only
|
||||
* as digits are consumed.
|
||||
*/
|
||||
@ -642,7 +642,7 @@ digits(size_t *result, const jschar *s, size_t *i, size_t limit)
|
||||
{
|
||||
size_t init = *i;
|
||||
*result = 0;
|
||||
while (*i < limit &&
|
||||
while (*i < limit &&
|
||||
('0' <= s[*i] && s[*i] <= '9')) {
|
||||
*result *= 10;
|
||||
*result += (s[*i] - '0');
|
||||
@ -651,11 +651,11 @@ digits(size_t *result, const jschar *s, size_t *i, size_t limit)
|
||||
return (*i != init);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* Read and convert decimal digits to the right of a decimal point,
|
||||
* representing a fractional integer, from s[*i] into *result
|
||||
* while *i < limit.
|
||||
*
|
||||
* while *i < limit.
|
||||
*
|
||||
* Succeed if any digits are converted. Advance *i only
|
||||
* as digits are consumed.
|
||||
*/
|
||||
@ -665,7 +665,7 @@ fractional(jsdouble *result, const jschar *s, size_t *i, size_t limit)
|
||||
jsdouble factor = 0.1;
|
||||
size_t init = *i;
|
||||
*result = 0.0;
|
||||
while (*i < limit &&
|
||||
while (*i < limit &&
|
||||
('0' <= s[*i] && s[*i] <= '9')) {
|
||||
*result += (s[*i] - '0') * factor;
|
||||
factor *= 0.1;
|
||||
@ -674,9 +674,9 @@ fractional(jsdouble *result, const jschar *s, size_t *i, size_t limit)
|
||||
return (*i != init);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read and convert exactly n decimal digits from s[*i]
|
||||
* to s[min(*i+n,limit)] into *result.
|
||||
/*
|
||||
* Read and convert exactly n decimal digits from s[*i]
|
||||
* to s[min(*i+n,limit)] into *result.
|
||||
*
|
||||
* Succeed if exactly n digits are converted. Advance *i only
|
||||
* on success.
|
||||
@ -688,12 +688,12 @@ ndigits(size_t n, size_t *result, const jschar *s, size_t* i, size_t limit)
|
||||
|
||||
if (digits(result, s, i, JS_MIN(limit, init+n)))
|
||||
return ((*i - init) == n);
|
||||
|
||||
|
||||
*i = init;
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* Parse a string in one of the date-time formats given by the W3C
|
||||
* "NOTE-datetime" specification. These formats make up a restricted
|
||||
* profile of the ISO 8601 format. Quoted here:
|
||||
@ -714,7 +714,7 @@ ndigits(size_t n, size_t *result, const jschar *s, size_t* i, size_t limit)
|
||||
* be aded to a date later. If the time is missing then we assume
|
||||
* 00:00 UTC. If the time is present but the time zone field is
|
||||
* missing then we use local time.
|
||||
*
|
||||
*
|
||||
* Date part:
|
||||
*
|
||||
* Year:
|
||||
@ -730,7 +730,7 @@ ndigits(size_t n, size_t *result, const jschar *s, size_t* i, size_t limit)
|
||||
*
|
||||
* Hours and minutes:
|
||||
* Thh:mmTZD (eg T19:20+01:00)
|
||||
*
|
||||
*
|
||||
* Hours, minutes and seconds:
|
||||
* Thh:mm:ssTZD (eg T19:20:30+01:00)
|
||||
*
|
||||
@ -775,22 +775,22 @@ date_parseISOString(JSLinearString *str, jsdouble *result, JSContext *cx)
|
||||
#define NEED(ch) \
|
||||
JS_BEGIN_MACRO \
|
||||
if (i >= limit || s[i] != ch) { goto syntax; } else { ++i; } \
|
||||
JS_END_MACRO
|
||||
JS_END_MACRO
|
||||
|
||||
#define DONE_DATE_UNLESS(ch) \
|
||||
JS_BEGIN_MACRO \
|
||||
if (i >= limit || s[i] != ch) { goto done_date; } else { ++i; } \
|
||||
JS_END_MACRO
|
||||
JS_END_MACRO
|
||||
|
||||
#define DONE_UNLESS(ch) \
|
||||
JS_BEGIN_MACRO \
|
||||
if (i >= limit || s[i] != ch) { goto done; } else { ++i; } \
|
||||
JS_END_MACRO
|
||||
JS_END_MACRO
|
||||
|
||||
#define NEED_NDIGITS(n, field) \
|
||||
JS_BEGIN_MACRO \
|
||||
if (!ndigits(n, &field, s, &i, limit)) { goto syntax; } \
|
||||
JS_END_MACRO
|
||||
JS_END_MACRO
|
||||
|
||||
s = str->chars();
|
||||
limit = str->length();
|
||||
@ -841,12 +841,12 @@ date_parseISOString(JSLinearString *str, jsdouble *result, JSContext *cx)
|
||||
if (year > 275943 // ceil(1e8/365) + 1970
|
||||
|| (month == 0 || month > 12)
|
||||
|| (day == 0 || day > size_t(DaysInMonth(year,month)))
|
||||
|| hour > 24
|
||||
|| hour > 24
|
||||
|| ((hour == 24) && (min > 0 || sec > 0))
|
||||
|| min > 59
|
||||
|| min > 59
|
||||
|| sec > 59
|
||||
|| tzHour > 23
|
||||
|| tzMin > 59)
|
||||
|| tzMin > 59)
|
||||
goto syntax;
|
||||
|
||||
if (i != limit)
|
||||
@ -861,7 +861,7 @@ date_parseISOString(JSLinearString *str, jsdouble *result, JSContext *cx)
|
||||
if (isLocalTime) {
|
||||
msec = UTC(msec, cx);
|
||||
} else {
|
||||
msec -= ((tzMul) * ((tzHour * msPerHour)
|
||||
msec -= ((tzMul) * ((tzHour * msPerHour)
|
||||
+ (tzMin * msPerMinute)));
|
||||
}
|
||||
|
||||
@ -1211,10 +1211,13 @@ date_now_tn(JSContext*)
|
||||
static JSBool
|
||||
GetUTCTime(JSContext *cx, JSObject *obj, Value *vp, jsdouble *dp)
|
||||
{
|
||||
if (!InstanceOf(cx, obj, &js_DateClass, vp ? vp + 2 : NULL))
|
||||
return JS_FALSE;
|
||||
if (!obj->isDate()) {
|
||||
if (vp)
|
||||
ReportIncompatibleMethod(cx, vp, &js_DateClass);
|
||||
return false;
|
||||
}
|
||||
*dp = obj->getDateUTCTime().toNumber();
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1388,8 +1391,13 @@ FillLocalTimes(JSContext *cx, JSObject *obj)
|
||||
static inline JSBool
|
||||
GetAndCacheLocalTime(JSContext *cx, JSObject *obj, Value *vp, jsdouble *time = NULL)
|
||||
{
|
||||
if (!obj || !InstanceOf(cx, obj, &js_DateClass, vp ? vp + 2 : NULL))
|
||||
if (!obj)
|
||||
return false;
|
||||
if (!obj->isDate()) {
|
||||
if (vp)
|
||||
ReportIncompatibleMethod(cx, vp, &js_DateClass);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If the local time is undefined, we need to fill in the cached values. */
|
||||
if (obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_TIME).isUndefined()) {
|
||||
@ -1679,8 +1687,10 @@ date_setTime(JSContext *cx, uintN argc, Value *vp)
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
if (!InstanceOf(cx, obj, &js_DateClass, vp + 2))
|
||||
if (!obj->isDate()) {
|
||||
ReportIncompatibleMethod(cx, vp, &js_DateClass);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (argc == 0) {
|
||||
SetDateToNaN(cx, obj, vp);
|
||||
|
@ -325,7 +325,7 @@ js_UntrapScriptCode(JSContext *cx, JSScript *script)
|
||||
if (!code)
|
||||
break;
|
||||
memcpy(code, script->code, nbytes);
|
||||
JS_PURGE_GSN_CACHE(cx);
|
||||
GetGSNCache(cx)->purge();
|
||||
}
|
||||
code[trap->pc - script->code] = trap->op;
|
||||
}
|
||||
@ -1989,36 +1989,6 @@ JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(uint32)
|
||||
JS_GetTopScriptFilenameFlags(JSContext *cx, JSStackFrame *fp)
|
||||
{
|
||||
if (!fp)
|
||||
fp = js_GetTopStackFrame(cx);
|
||||
while (fp) {
|
||||
if (fp->isScriptFrame())
|
||||
return JS_GetScriptFilenameFlags(fp->script());
|
||||
fp = fp->prev();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(uint32)
|
||||
JS_GetScriptFilenameFlags(JSScript *script)
|
||||
{
|
||||
JS_ASSERT(script);
|
||||
if (!script->filename)
|
||||
return JSFILENAME_NULL;
|
||||
return js_GetScriptFilenameFlags(script->filename);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_FlagScriptFilenamePrefix(JSRuntime *rt, const char *prefix, uint32 flags)
|
||||
{
|
||||
if (!js_SaveScriptFilenameRT(rt, prefix, flags))
|
||||
return JS_FALSE;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_IsSystemObject(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
@ -2034,14 +2004,6 @@ JS_MakeSystemObject(JSContext *cx, JSObject *obj)
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
JS_PUBLIC_API(JSObject *)
|
||||
JS_UnwrapObject(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
return obj->unwrap();
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
js_RevertVersion(JSContext *cx)
|
||||
{
|
||||
|
@ -481,40 +481,6 @@ JS_GetFunctionTotalSize(JSContext *cx, JSFunction *fun);
|
||||
extern JS_PUBLIC_API(size_t)
|
||||
JS_GetScriptTotalSize(JSContext *cx, JSScript *script);
|
||||
|
||||
/*
|
||||
* Get the top-most running script on cx starting from fp, or from the top of
|
||||
* cx's frame stack if fp is null, and return its script filename flags. If
|
||||
* the script has a null filename member, return JSFILENAME_NULL.
|
||||
*/
|
||||
extern JS_PUBLIC_API(uint32)
|
||||
JS_GetTopScriptFilenameFlags(JSContext *cx, JSStackFrame *fp);
|
||||
|
||||
/*
|
||||
* Get the script filename flags for the script. If the script doesn't have a
|
||||
* filename, return JSFILENAME_NULL.
|
||||
*/
|
||||
extern JS_PUBLIC_API(uint32)
|
||||
JS_GetScriptFilenameFlags(JSScript *script);
|
||||
|
||||
/*
|
||||
* Associate flags with a script filename prefix in rt, so that any subsequent
|
||||
* script compilation will inherit those flags if the script's filename is the
|
||||
* same as prefix, or if prefix is a substring of the script's filename.
|
||||
*
|
||||
* The API defines only one flag bit, JSFILENAME_SYSTEM, leaving the remaining
|
||||
* 31 bits up to the API client to define. The union of all 32 bits must not
|
||||
* be a legal combination, however, in order to preserve JSFILENAME_NULL as a
|
||||
* unique value. API clients may depend on JSFILENAME_SYSTEM being a set bit
|
||||
* in JSFILENAME_NULL -- a script with a null filename member is presumed to
|
||||
* be a "system" script.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_FlagScriptFilenamePrefix(JSRuntime *rt, const char *prefix, uint32 flags);
|
||||
|
||||
#define JSFILENAME_NULL 0xffffffff /* null script filename */
|
||||
#define JSFILENAME_SYSTEM 0x00000001 /* "system" script, see below */
|
||||
#define JSFILENAME_PROTECTED 0x00000002 /* scripts need protection */
|
||||
|
||||
/*
|
||||
* Return true if obj is a "system" object, that is, one created by
|
||||
* JS_NewSystemObject with the system flag set and not JS_NewObject.
|
||||
@ -536,11 +502,6 @@ JS_MakeSystemObject(JSContext *cx, JSObject *obj);
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
extern JS_PUBLIC_API(JSObject *)
|
||||
JS_UnwrapObject(JSContext *cx, JSObject *obj);
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
extern JS_FRIEND_API(void)
|
||||
js_RevertVersion(JSContext *cx);
|
||||
|
||||
|
@ -38,11 +38,39 @@
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "jscntxt.h"
|
||||
#include "jscompartment.h"
|
||||
#include "jsfriendapi.h"
|
||||
|
||||
using namespace js;
|
||||
|
||||
JS_FRIEND_API(JSString *)
|
||||
JS_GetAnonymousString(JSRuntime *rt)
|
||||
{
|
||||
JS_ASSERT(rt->state == JSRTS_UP);
|
||||
return rt->atomState.anonymousAtom;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSObject *)
|
||||
JS_FindCompilationScope(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
/*
|
||||
* We unwrap wrappers here. This is a little weird, but it's what's being
|
||||
* asked of us.
|
||||
*/
|
||||
if (obj->isWrapper())
|
||||
obj = obj->unwrap();
|
||||
|
||||
/*
|
||||
* Innerize the target_obj so that we compile in the correct (inner)
|
||||
* scope.
|
||||
*/
|
||||
if (JSObjectOp op = obj->getClass()->ext.innerObject)
|
||||
obj = op(cx, obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSObject *)
|
||||
JS_UnwrapObject(JSObject *obj)
|
||||
{
|
||||
return obj->unwrap();
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
@ -48,6 +48,12 @@ JS_BEGIN_EXTERN_C
|
||||
extern JS_FRIEND_API(JSString *)
|
||||
JS_GetAnonymousString(JSRuntime *rt);
|
||||
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_FindCompilationScope(JSContext *cx, JSObject *obj);
|
||||
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_UnwrapObject(JSObject *obj);
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#endif /* jsfriendapi_h___ */
|
||||
|
@ -513,7 +513,7 @@ ArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
{
|
||||
LeaveTrace(cx);
|
||||
|
||||
if (!InstanceOf(cx, obj, &js_ArgumentsClass, NULL))
|
||||
if (!obj->isNormalArguments())
|
||||
return true;
|
||||
|
||||
if (JSID_IS_INT(id)) {
|
||||
@ -566,7 +566,8 @@ ArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
||||
LeaveTrace(cx);
|
||||
#endif
|
||||
|
||||
if (!InstanceOf(cx, obj, &js_ArgumentsClass, NULL))
|
||||
|
||||
if (!obj->isNormalArguments())
|
||||
return true;
|
||||
|
||||
if (JSID_IS_INT(id)) {
|
||||
@ -662,7 +663,7 @@ StrictArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
{
|
||||
LeaveTrace(cx);
|
||||
|
||||
if (!InstanceOf(cx, obj, &StrictArgumentsClass, NULL))
|
||||
if (!obj->isStrictArguments())
|
||||
return true;
|
||||
|
||||
if (JSID_IS_INT(id)) {
|
||||
@ -688,7 +689,7 @@ static JSBool
|
||||
|
||||
StrictArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
||||
{
|
||||
if (!InstanceOf(cx, obj, &StrictArgumentsClass, NULL))
|
||||
if (!obj->isStrictArguments())
|
||||
return true;
|
||||
|
||||
if (JSID_IS_INT(id)) {
|
||||
@ -1570,15 +1571,15 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
* the non-standard properties when the directly addressed object (obj)
|
||||
* is a function object (i.e., when this loop does not iterate).
|
||||
*/
|
||||
JSFunction *fun;
|
||||
while (!(fun = (JSFunction *)
|
||||
GetInstancePrivate(cx, obj, &js_FunctionClass, NULL))) {
|
||||
|
||||
while (!obj->isFunction()) {
|
||||
if (slot != FUN_LENGTH)
|
||||
return true;
|
||||
obj = obj->getProto();
|
||||
if (!obj)
|
||||
return true;
|
||||
}
|
||||
JSFunction *fun = obj->getFunctionPrivate();
|
||||
|
||||
/* Find fun's top-most activation record. */
|
||||
JSStackFrame *fp;
|
||||
@ -2117,15 +2118,7 @@ js_fun_call(JSContext *cx, uintN argc, Value *vp)
|
||||
Value fval = vp[1];
|
||||
|
||||
if (!js_IsCallable(fval)) {
|
||||
if (JSString *str = js_ValueToString(cx, fval)) {
|
||||
JSAutoByteString bytes(cx, str);
|
||||
if (!!bytes) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_INCOMPATIBLE_PROTO,
|
||||
js_Function_str, js_call_str,
|
||||
bytes.ptr());
|
||||
}
|
||||
}
|
||||
ReportIncompatibleMethod(cx, vp, &js_FunctionClass);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2162,15 +2155,7 @@ js_fun_apply(JSContext *cx, uintN argc, Value *vp)
|
||||
/* Step 1. */
|
||||
Value fval = vp[1];
|
||||
if (!js_IsCallable(fval)) {
|
||||
if (JSString *str = js_ValueToString(cx, fval)) {
|
||||
JSAutoByteString bytes(cx, str);
|
||||
if (!!bytes) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_INCOMPATIBLE_PROTO,
|
||||
js_Function_str, js_apply_str,
|
||||
bytes.ptr());
|
||||
}
|
||||
}
|
||||
ReportIncompatibleMethod(cx, vp, &js_FunctionClass);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2336,6 +2321,30 @@ CallOrConstructBoundFunction(JSContext *cx, uintN argc, Value *vp)
|
||||
|
||||
}
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
static JSBool
|
||||
fun_isGenerator(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *funobj;
|
||||
if (!IsFunctionObject(vp[1], &funobj)) {
|
||||
JS_SET_RVAL(cx, vp, BooleanValue(false));
|
||||
return true;
|
||||
}
|
||||
|
||||
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
|
||||
|
||||
bool result = false;
|
||||
if (fun->isInterpreted()) {
|
||||
JSScript *script = fun->u.i.script;
|
||||
JS_ASSERT(script->length != 0);
|
||||
result = script->code[0] == JSOP_GENERATOR;
|
||||
}
|
||||
|
||||
JS_SET_RVAL(cx, vp, BooleanValue(result));
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ES5 15.3.4.5. */
|
||||
static JSBool
|
||||
fun_bind(JSContext *cx, uintN argc, Value *vp)
|
||||
@ -2345,14 +2354,7 @@ fun_bind(JSContext *cx, uintN argc, Value *vp)
|
||||
|
||||
/* Step 2. */
|
||||
if (!js_IsCallable(thisv)) {
|
||||
if (JSString *str = js_ValueToString(cx, thisv)) {
|
||||
JSAutoByteString bytes(cx, str);
|
||||
if (!!bytes) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_INCOMPATIBLE_PROTO,
|
||||
js_Function_str, "bind", bytes.ptr());
|
||||
}
|
||||
}
|
||||
ReportIncompatibleMethod(cx, vp, &js_FunctionClass);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2405,6 +2407,9 @@ static JSFunctionSpec function_methods[] = {
|
||||
JS_FN(js_apply_str, js_fun_apply, 2,0),
|
||||
JS_FN(js_call_str, js_fun_call, 1,0),
|
||||
JS_FN("bind", fun_bind, 1,0),
|
||||
#if JS_HAS_GENERATORS
|
||||
JS_FN("isGenerator", fun_isGenerator,0,0),
|
||||
#endif
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
|
@ -218,7 +218,7 @@ Arena<T>::mark(T *thing, JSTracer *trc)
|
||||
if (alignedThing > &t.things[ThingsPerArena-1] || alignedThing < &t.things[0])
|
||||
return CGCT_NOTARENA;
|
||||
|
||||
if (!aheader.compartment || inFreeList(alignedThing))
|
||||
if (inFreeList(alignedThing))
|
||||
return CGCT_NOTLIVE;
|
||||
|
||||
JS_ASSERT(sizeof(T) == aheader.thingSize);
|
||||
@ -243,7 +243,7 @@ checkArenaListsForThing(JSCompartment *comp, void *thing)
|
||||
comp->arenas[FINALIZE_OBJECT12].arenasContainThing<JSObject_Slots12>(thing) ||
|
||||
comp->arenas[FINALIZE_OBJECT16].arenasContainThing<JSObject_Slots16>(thing) ||
|
||||
comp->arenas[FINALIZE_FUNCTION].arenasContainThing<JSFunction>(thing) ||
|
||||
comp->arenas[FINALIZE_FUNCTION].arenasContainThing<Shape>(thing) ||
|
||||
comp->arenas[FINALIZE_SHAPE].arenasContainThing<Shape>(thing) ||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
comp->arenas[FINALIZE_XML].arenasContainThing<JSXML>(thing) ||
|
||||
#endif
|
||||
@ -644,6 +644,9 @@ MarkIfGCThingWord(JSTracer *trc, jsuword w, uint32 &thingKind)
|
||||
|
||||
ArenaHeader *aheader = cell->arena()->header();
|
||||
|
||||
if (!aheader->compartment)
|
||||
return CGCT_NOTLIVE;
|
||||
|
||||
ConservativeGCTest test;
|
||||
thingKind = aheader->thingKind;
|
||||
|
||||
@ -753,7 +756,7 @@ MarkRangeConservatively(JSTracer *trc, const jsuword *begin, const jsuword *end)
|
||||
}
|
||||
|
||||
static void
|
||||
MarkThreadDataConservatively(JSTracer *trc, JSThreadData *td)
|
||||
MarkThreadDataConservatively(JSTracer *trc, ThreadData *td)
|
||||
{
|
||||
ConservativeGCThreadData *ctd = &td->conservativeGC;
|
||||
JS_ASSERT(ctd->hasStackToScan());
|
||||
@ -1782,36 +1785,6 @@ js_DestroyScriptsToGC(JSContext *cx, JSCompartment *comp)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called from js_FinishAtomState to force the finalization
|
||||
* of the permanently interned strings when cx is not available.
|
||||
*/
|
||||
void
|
||||
js_FinalizeStringRT(JSRuntime *rt, JSString *str)
|
||||
{
|
||||
JS_RUNTIME_UNMETER(rt, liveStrings);
|
||||
JS_ASSERT(str->isLinear() && !str->isStaticAtom());
|
||||
|
||||
if (str->isDependent()) {
|
||||
/* A dependent string can not be external and must be valid. */
|
||||
JS_ASSERT(str->arena()->header()->thingKind == FINALIZE_STRING);
|
||||
JS_ASSERT(str->asDependent().base());
|
||||
JS_RUNTIME_UNMETER(rt, liveDependentStrings);
|
||||
} else {
|
||||
unsigned thingKind = str->arena()->header()->thingKind;
|
||||
JS_ASSERT(unsigned(FINALIZE_SHORT_STRING) <= thingKind &&
|
||||
thingKind <= unsigned(FINALIZE_EXTERNAL_STRING));
|
||||
|
||||
jschar *chars = const_cast<jschar *>(str->asFlat().chars());
|
||||
if (thingKind == FINALIZE_STRING) {
|
||||
rt->stringMemoryUsed -= str->length() * 2;
|
||||
rt->free_(chars);
|
||||
} else if (thingKind == FINALIZE_EXTERNAL_STRING) {
|
||||
((JSExternalString *)str)->finalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void
|
||||
FinalizeArenaList(JSCompartment *comp, JSContext *cx, unsigned thingKind)
|
||||
|
@ -520,7 +520,7 @@ GetArena(Cell *cell)
|
||||
const size_t GC_ARENA_ALLOCATION_TRIGGER = 30 * js::GC_CHUNK_SIZE;
|
||||
|
||||
/*
|
||||
* A GC is triggered once the number of newly allocated arenas
|
||||
* A GC is triggered once the number of newly allocated arenas
|
||||
* is GC_HEAP_GROWTH_FACTOR times the number of live arenas after
|
||||
* the last GC starting after the lower limit of
|
||||
* GC_ARENA_ALLOCATION_TRIGGER.
|
||||
@ -697,7 +697,7 @@ typedef js::HashMap<void *,
|
||||
|
||||
/* If HashNumber grows, need to change WrapperHasher. */
|
||||
JS_STATIC_ASSERT(sizeof(HashNumber) == 4);
|
||||
|
||||
|
||||
struct WrapperHasher
|
||||
{
|
||||
typedef Value Lookup;
|
||||
@ -915,16 +915,16 @@ class GCHelperThread {
|
||||
sweeping(false),
|
||||
freeCursor(NULL),
|
||||
freeCursorEnd(NULL) { }
|
||||
|
||||
|
||||
bool init(JSRuntime *rt);
|
||||
void finish(JSRuntime *rt);
|
||||
|
||||
|
||||
/* Must be called with GC lock taken. */
|
||||
void startBackgroundSweep(JSRuntime *rt);
|
||||
|
||||
|
||||
/* Must be called outside the GC lock. */
|
||||
void waitBackgroundSweepEnd(JSRuntime *rt);
|
||||
|
||||
|
||||
void freeLater(void *ptr) {
|
||||
JS_ASSERT(!sweeping);
|
||||
if (freeCursor != freeCursorEnd)
|
||||
@ -960,7 +960,7 @@ typedef HashSet<js::gc::Chunk *, GCChunkHasher, SystemAllocPolicy> GCChunkSet;
|
||||
struct ConservativeGCThreadData {
|
||||
|
||||
/*
|
||||
* The GC scans conservatively between JSThreadData::nativeStackBase and
|
||||
* The GC scans conservatively between ThreadData::nativeStackBase and
|
||||
* nativeStackTop unless the latter is NULL.
|
||||
*/
|
||||
jsuword *nativeStackTop;
|
||||
@ -977,6 +977,21 @@ struct ConservativeGCThreadData {
|
||||
*/
|
||||
unsigned requestThreshold;
|
||||
|
||||
ConservativeGCThreadData()
|
||||
: nativeStackTop(NULL), requestThreshold(0)
|
||||
{
|
||||
}
|
||||
|
||||
~ConservativeGCThreadData() {
|
||||
#ifdef JS_THREADSAFE
|
||||
/*
|
||||
* The conservative GC scanner should be disabled when the thread leaves
|
||||
* the last request.
|
||||
*/
|
||||
JS_ASSERT(!hasStackToScan());
|
||||
#endif
|
||||
}
|
||||
|
||||
JS_NEVER_INLINE void recordStackTop();
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
|
@ -69,82 +69,6 @@
|
||||
|
||||
#ifdef XP_WIN
|
||||
|
||||
/*
|
||||
* On Windows CE < 6 we must use separated MEM_RESERVE and MEM_COMMIT
|
||||
* VirtualAlloc calls and we cannot use MEM_RESERVE to allocate at the given
|
||||
* address. So we use a workaround based on oversized allocation.
|
||||
*/
|
||||
# if defined(WINCE) && !defined(MOZ_MEMORY_WINCE6)
|
||||
|
||||
# define JS_GC_HAS_MAP_ALIGN
|
||||
|
||||
static void
|
||||
UnmapPagesAtBase(void *p)
|
||||
{
|
||||
JS_ALWAYS_TRUE(VirtualFree(p, 0, MEM_RELEASE));
|
||||
}
|
||||
|
||||
static void *
|
||||
MapAlignedPages(size_t size, size_t alignment)
|
||||
{
|
||||
JS_ASSERT(size % alignment == 0);
|
||||
JS_ASSERT(size >= alignment);
|
||||
|
||||
void *reserve = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS);
|
||||
if (!reserve)
|
||||
return NULL;
|
||||
|
||||
void *p = VirtualAlloc(reserve, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
JS_ASSERT(p == reserve);
|
||||
|
||||
size_t mask = alignment - 1;
|
||||
size_t offset = (uintptr_t) p & mask;
|
||||
if (!offset)
|
||||
return p;
|
||||
|
||||
/* Try to extend the initial allocation. */
|
||||
UnmapPagesAtBase(reserve);
|
||||
reserve = VirtualAlloc(NULL, size + alignment - offset, MEM_RESERVE,
|
||||
PAGE_NOACCESS);
|
||||
if (!reserve)
|
||||
return NULL;
|
||||
if (offset == ((uintptr_t) reserve & mask)) {
|
||||
void *aligned = (void *) ((uintptr_t) reserve + alignment - offset);
|
||||
p = VirtualAlloc(aligned, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
JS_ASSERT(p == aligned);
|
||||
return p;
|
||||
}
|
||||
|
||||
/* over allocate to ensure we have an aligned region */
|
||||
UnmapPagesAtBase(reserve);
|
||||
reserve = VirtualAlloc(NULL, size + alignment, MEM_RESERVE, PAGE_NOACCESS);
|
||||
if (!reserve)
|
||||
return NULL;
|
||||
|
||||
offset = (uintptr_t) reserve & mask;
|
||||
void *aligned = (void *) ((uintptr_t) reserve + alignment - offset);
|
||||
p = VirtualAlloc(aligned, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
JS_ASSERT(p == aligned);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static void
|
||||
UnmapPages(void *p, size_t size)
|
||||
{
|
||||
if (VirtualFree(p, 0, MEM_RELEASE))
|
||||
return;
|
||||
|
||||
/* We could have used the over allocation. */
|
||||
JS_ASSERT(GetLastError() == ERROR_INVALID_PARAMETER);
|
||||
MEMORY_BASIC_INFORMATION info;
|
||||
VirtualQuery(p, &info, sizeof(info));
|
||||
|
||||
UnmapPagesAtBase(info.AllocationBase);
|
||||
}
|
||||
|
||||
# else /* WINCE */
|
||||
|
||||
static void *
|
||||
MapPages(void *addr, size_t size)
|
||||
{
|
||||
@ -159,8 +83,6 @@ UnmapPages(void *addr, size_t size)
|
||||
JS_ALWAYS_TRUE(VirtualFree(addr, 0, MEM_RELEASE));
|
||||
}
|
||||
|
||||
# endif /* !WINCE */
|
||||
|
||||
#elif defined(XP_OS2)
|
||||
|
||||
#define JS_GC_HAS_MAP_ALIGN 1
|
||||
|
@ -45,12 +45,7 @@
|
||||
|
||||
namespace js {
|
||||
|
||||
#if defined(WINCE) && !defined(MOZ_MEMORY_WINCE6)
|
||||
const size_t GC_CHUNK_SHIFT = 21;
|
||||
#else
|
||||
const size_t GC_CHUNK_SHIFT = 20;
|
||||
#endif
|
||||
|
||||
const size_t GC_CHUNK_SIZE = size_t(1) << GC_CHUNK_SHIFT;
|
||||
const size_t GC_CHUNK_MASK = GC_CHUNK_SIZE - 1;
|
||||
|
||||
|
@ -120,6 +120,13 @@ class HashTable : private AllocPolicy
|
||||
Ptr(Entry &entry) : entry(&entry) {}
|
||||
|
||||
public:
|
||||
/* Leaves Ptr uninitialized. */
|
||||
Ptr() {
|
||||
#ifdef DEBUG
|
||||
entry = (Entry *)0xbad;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool found() const { return entry->isLive(); }
|
||||
operator ConvertibleToBool() const { return found() ? &Ptr::nonNull : 0; }
|
||||
bool operator==(const Ptr &rhs) const { JS_ASSERT(found() && rhs.found()); return entry == rhs.entry; }
|
||||
@ -142,6 +149,9 @@ class HashTable : private AllocPolicy
|
||||
#else
|
||||
AddPtr(Entry &entry, HashNumber hn) : Ptr(entry), keyHash(hn) {}
|
||||
#endif
|
||||
public:
|
||||
/* Leaves AddPtr uninitialized. */
|
||||
AddPtr() {}
|
||||
};
|
||||
|
||||
/*
|
||||
@ -571,6 +581,23 @@ class HashTable : private AllocPolicy
|
||||
#endif
|
||||
}
|
||||
|
||||
void finish()
|
||||
{
|
||||
JS_ASSERT(!entered);
|
||||
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
destroyTable(*this, table, tableCapacity);
|
||||
table = NULL;
|
||||
gen++;
|
||||
entryCount = 0;
|
||||
removedCount = 0;
|
||||
#ifdef DEBUG
|
||||
mutationCount++;
|
||||
#endif
|
||||
}
|
||||
|
||||
Range all() const {
|
||||
return Range(table, table + tableCapacity);
|
||||
}
|
||||
@ -738,24 +765,36 @@ struct DefaultHasher
|
||||
}
|
||||
};
|
||||
|
||||
/* Specialized hashing policy for pointer types. */
|
||||
template <class T>
|
||||
struct DefaultHasher<T *>
|
||||
/*
|
||||
* Pointer hashing policy that strips the lowest zeroBits when calculating the
|
||||
* hash to improve key distribution.
|
||||
*/
|
||||
template <typename Key, size_t zeroBits>
|
||||
struct PointerHasher
|
||||
{
|
||||
typedef T *Lookup;
|
||||
static HashNumber hash(T *l) {
|
||||
/*
|
||||
* Strip often-0 lower bits for better distribution after multiplying
|
||||
* by the sGoldenRatio.
|
||||
*/
|
||||
return HashNumber(reinterpret_cast<size_t>(l) >>
|
||||
tl::FloorLog2<sizeof(void *)>::result);
|
||||
typedef Key Lookup;
|
||||
static HashNumber hash(const Lookup &l) {
|
||||
size_t word = reinterpret_cast<size_t>(l) >> zeroBits;
|
||||
JS_STATIC_ASSERT(sizeof(HashNumber) == 4);
|
||||
#if JS_BYTES_PER_WORD == 4
|
||||
return HashNumber(word);
|
||||
#else
|
||||
JS_STATIC_ASSERT(sizeof word == 8);
|
||||
return HashNumber((word >> 32) ^ word);
|
||||
#endif
|
||||
}
|
||||
static bool match(T *k, T *l) {
|
||||
static bool match(const Key &k, const Lookup &l) {
|
||||
return k == l;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Specialized hashing policy for pointer types. It assumes that the type is
|
||||
* at least word-aligned. For types with smaller size use PointerHasher.
|
||||
*/
|
||||
template <class T>
|
||||
struct DefaultHasher<T *>: PointerHasher<T *, tl::FloorLog2<sizeof(void *)>::result> { };
|
||||
|
||||
/*
|
||||
* JS-friendly, STL-like container providing a hash-based map from keys to
|
||||
* values. In particular, HashMap calls constructors and destructors of all
|
||||
@ -929,10 +968,19 @@ class HashMap
|
||||
*/
|
||||
typedef typename Impl::Enum Enum;
|
||||
|
||||
/* Remove all entries. */
|
||||
/*
|
||||
* Remove all entries. This does not shrink the table. For that consider
|
||||
* using the finish() method.
|
||||
*/
|
||||
void clear() { impl.clear(); }
|
||||
|
||||
/* Does the table contain any entries? */
|
||||
/*
|
||||
* Remove all the entries and release all internal buffers. The map must
|
||||
* be initialized again before any use.
|
||||
*/
|
||||
void finish() { impl.finish(); }
|
||||
|
||||
/* Does the table contain any entries? */
|
||||
bool empty() const { return impl.empty(); }
|
||||
|
||||
/*
|
||||
@ -1118,9 +1166,18 @@ class HashSet
|
||||
*/
|
||||
typedef typename Impl::Enum Enum;
|
||||
|
||||
/* Remove all entries. */
|
||||
/*
|
||||
* Remove all entries. This does not shrink the table. For that consider
|
||||
* using the finish() method.
|
||||
*/
|
||||
void clear() { impl.clear(); }
|
||||
|
||||
/*
|
||||
* Remove all the entries and release all internal buffers. The set must
|
||||
* be initialized again before any use.
|
||||
*/
|
||||
void finish() { impl.finish(); }
|
||||
|
||||
/* Does the table contain any entries? */
|
||||
bool empty() const { return impl.empty(); }
|
||||
|
||||
|
@ -1027,7 +1027,7 @@ CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs)
|
||||
/* Allow redeclaration of variables and functions. */
|
||||
if (!(attrs & (JSPROP_GETTER | JSPROP_SETTER)))
|
||||
return true;
|
||||
|
||||
|
||||
/*
|
||||
* Allow adding a getter only if a property already has a setter
|
||||
* but no getter and similarly for adding a setter. That is, we
|
||||
@ -1100,13 +1100,13 @@ LooselyEqual(JSContext *cx, const Value &lval, const Value &rval, JSBool *result
|
||||
JSString *r = rval.toString();
|
||||
return EqualStrings(cx, l, r, result);
|
||||
}
|
||||
|
||||
|
||||
if (lval.isDouble()) {
|
||||
double l = lval.toDouble(), r = rval.toDouble();
|
||||
*result = JSDOUBLE_COMPARE(l, ==, r, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (lval.isObject()) {
|
||||
JSObject *l = &lval.toObject();
|
||||
JSObject *r = &rval.toObject();
|
||||
@ -1128,7 +1128,7 @@ LooselyEqual(JSContext *cx, const Value &lval, const Value &rval, JSBool *result
|
||||
*result = rval.isNullOrUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (rval.isNullOrUndefined()) {
|
||||
*result = false;
|
||||
return true;
|
||||
@ -1246,24 +1246,6 @@ TypeOfValue(JSContext *cx, const Value &vref)
|
||||
return JSTYPE_BOOLEAN;
|
||||
}
|
||||
|
||||
bool
|
||||
InstanceOfSlow(JSContext *cx, JSObject *obj, Class *clasp, Value *argv)
|
||||
{
|
||||
JS_ASSERT(!obj || obj->getClass() != clasp);
|
||||
if (argv) {
|
||||
JSFunction *fun = js_ValueToFunction(cx, &argv[-2], 0);
|
||||
if (fun) {
|
||||
JSAutoByteString funNameBytes;
|
||||
if (const char *funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
|
||||
clasp->name, funName,
|
||||
obj ? obj->getClass()->name : js_null_str);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK bool
|
||||
InvokeConstructor(JSContext *cx, const CallArgs &argsRef)
|
||||
{
|
||||
@ -2370,7 +2352,7 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
|
||||
(dbl = script->getConst(GET_FULL_INDEX(PCOFF)).toDouble())
|
||||
|
||||
bool useMethodJIT = false;
|
||||
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
|
||||
#define RESET_USE_METHODJIT() \
|
||||
|
@ -1087,26 +1087,9 @@ SameValue(JSContext *cx, const Value &v1, const Value &v2, JSBool *same);
|
||||
extern JSType
|
||||
TypeOfValue(JSContext *cx, const Value &v);
|
||||
|
||||
inline bool
|
||||
InstanceOf(JSContext *cx, JSObject *obj, Class *clasp, Value *argv)
|
||||
{
|
||||
if (obj && obj->getClass() == clasp)
|
||||
return true;
|
||||
extern bool InstanceOfSlow(JSContext *, JSObject *, Class *, Value *);
|
||||
return InstanceOfSlow(cx, obj, clasp, argv);
|
||||
}
|
||||
|
||||
extern JSBool
|
||||
HasInstance(JSContext *cx, JSObject *obj, const js::Value *v, JSBool *bp);
|
||||
|
||||
inline void *
|
||||
GetInstancePrivate(JSContext *cx, JSObject *obj, Class *clasp, Value *argv)
|
||||
{
|
||||
if (!InstanceOf(cx, obj, clasp, argv))
|
||||
return NULL;
|
||||
return obj->getPrivate();
|
||||
}
|
||||
|
||||
extern bool
|
||||
ValueToId(JSContext *cx, const Value &v, jsid *idp);
|
||||
|
||||
|
@ -124,12 +124,6 @@ typedef unsigned JS_INT64_TYPE JSUint64;
|
||||
typedef intptr_t JSIntPtr;
|
||||
typedef uintptr_t JSUintPtr;
|
||||
|
||||
/* Windows Mobile defines intptr_t and uintptr_t in <crtdefs.h>. Why not? */
|
||||
#elif defined(JS_CRTDEFS_H_HAS_INTPTR_T)
|
||||
#include <crtdefs.h>
|
||||
typedef intptr_t JSIntPtr;
|
||||
typedef uintptr_t JSUintPtr;
|
||||
|
||||
/* Failing that, the configure script will have found something. */
|
||||
#elif defined(JS_INTPTR_TYPE)
|
||||
typedef signed JS_INTPTR_TYPE JSIntPtr;
|
||||
|
@ -593,9 +593,9 @@ GetIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp)
|
||||
if (last) {
|
||||
NativeIterator *lastni = last->getNativeIterator();
|
||||
if (!(lastni->flags & (JSITER_ACTIVE|JSITER_UNREUSABLE)) &&
|
||||
obj->isNative() &&
|
||||
obj->isNative() &&
|
||||
obj->shape() == lastni->shapes_array[0] &&
|
||||
proto && proto->isNative() &&
|
||||
proto && proto->isNative() &&
|
||||
proto->shape() == lastni->shapes_array[1] &&
|
||||
!proto->getProto()) {
|
||||
vp->setObject(*last);
|
||||
@ -713,8 +713,12 @@ static JSBool
|
||||
iterator_next(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj || !InstanceOf(cx, obj, &js_IteratorClass, vp + 2))
|
||||
if (!obj)
|
||||
return false;
|
||||
if (obj->getClass() != &js_IteratorClass) {
|
||||
ReportIncompatibleMethod(cx, vp, &js_IteratorClass);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!js_IteratorMore(cx, obj, vp))
|
||||
return false;
|
||||
@ -814,7 +818,7 @@ js_CloseIterator(JSContext *cx, JSObject *obj)
|
||||
|
||||
/*
|
||||
* Suppress enumeration of deleted properties. This function must be called
|
||||
* when a property is deleted and there might be active enumerators.
|
||||
* when a property is deleted and there might be active enumerators.
|
||||
*
|
||||
* We maintain a list of active non-escaping for-in enumerators. To suppress
|
||||
* a property, we check whether each active enumerator contains the (obj, id)
|
||||
@ -919,7 +923,7 @@ class IndexRangePredicate {
|
||||
public:
|
||||
IndexRangePredicate(jsint begin, jsint end) : begin(begin), end(end) {}
|
||||
|
||||
bool operator()(jsid id) {
|
||||
bool operator()(jsid id) {
|
||||
return JSID_IS_INT(id) && begin <= JSID_TO_INT(id) && JSID_TO_INT(id) < end;
|
||||
}
|
||||
bool matchesAtMostOne() { return false; }
|
||||
@ -1356,8 +1360,12 @@ generator_op(JSContext *cx, JSGeneratorOp op, Value *vp, uintN argc)
|
||||
LeaveTrace(cx);
|
||||
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj || !InstanceOf(cx, obj, &js_GeneratorClass, vp + 2))
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
if (obj->getClass() != &js_GeneratorClass) {
|
||||
ReportIncompatibleMethod(cx, vp, &js_GeneratorClass);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
JSGenerator *gen = (JSGenerator *) obj->getPrivate();
|
||||
if (!gen) {
|
||||
|
@ -53,8 +53,6 @@
|
||||
/* The right copysign function is not always named the same thing. */
|
||||
#if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
|
||||
#define js_copysign __builtin_copysign
|
||||
#elif defined WINCE
|
||||
#define js_copysign _copysign
|
||||
#elif defined _WIN32
|
||||
#if _MSC_VER < 1400
|
||||
/* Try to work around apparent _copysign bustage in VC7.x. */
|
||||
|
@ -50,8 +50,6 @@
|
||||
# include "prthread.h"
|
||||
#endif
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
|
||||
#if (defined(_WIN32) && defined(_M_IX86)) || \
|
||||
@ -217,13 +215,10 @@ js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
|
||||
#define JS_ATOMIC_SET_MASK(w, mask) (*(w) |= (mask))
|
||||
#define JS_ATOMIC_CLEAR_MASK(w, mask) (*(w) &= ~(mask))
|
||||
|
||||
#endif /* JS_THREADSAFE */
|
||||
#endif
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#if defined JS_THREADSAFE && defined __cplusplus
|
||||
#ifdef JS_THREADSAFE
|
||||
namespace js {
|
||||
|
||||
class AutoLock {
|
||||
private:
|
||||
JSLock *lock;
|
||||
@ -232,8 +227,10 @@ class AutoLock {
|
||||
AutoLock(JSLock *lock) : lock(lock) { JS_ACQUIRE_LOCK(lock); }
|
||||
~AutoLock() { JS_RELEASE_LOCK(lock); }
|
||||
};
|
||||
|
||||
}
|
||||
} /* namespace js */
|
||||
# define JS_AUTO_LOCK_GUARD(name, l) AutoLock name((l));
|
||||
#else
|
||||
# define JS_AUTO_LOCK_GUARD(name, l)
|
||||
#endif
|
||||
|
||||
#endif /* jslock_h___ */
|
||||
|
@ -565,7 +565,7 @@ math_random(JSContext *cx, uintN argc, Value *vp)
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
#if defined _WIN32 && !defined WINCE && _MSC_VER < 1400
|
||||
#if defined _WIN32 && _MSC_VER < 1400
|
||||
/* Try to work around apparent _copysign bustage in VC7.x. */
|
||||
double
|
||||
js_copysign(double x, double y)
|
||||
|
@ -61,63 +61,7 @@
|
||||
|
||||
namespace js {
|
||||
|
||||
#if defined(XP_WIN) && defined(WINCE)
|
||||
|
||||
inline bool
|
||||
isPageWritable(void *page)
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION memoryInformation;
|
||||
jsuword result = VirtualQuery(page, &memoryInformation, sizeof(memoryInformation));
|
||||
|
||||
/* return false on error, including ptr outside memory */
|
||||
if (result != sizeof(memoryInformation))
|
||||
return false;
|
||||
|
||||
jsuword protect = memoryInformation.Protect & ~(PAGE_GUARD | PAGE_NOCACHE);
|
||||
return protect == PAGE_READWRITE ||
|
||||
protect == PAGE_WRITECOPY ||
|
||||
protect == PAGE_EXECUTE_READWRITE ||
|
||||
protect == PAGE_EXECUTE_WRITECOPY;
|
||||
}
|
||||
|
||||
void *
|
||||
GetNativeStackBase()
|
||||
{
|
||||
/* find the address of this stack frame by taking the address of a local variable */
|
||||
bool isGrowingDownward = JS_STACK_GROWTH_DIRECTION < 0;
|
||||
void *thisFrame = (void *)(&isGrowingDownward);
|
||||
|
||||
static jsuword pageSize = 0;
|
||||
if (!pageSize) {
|
||||
SYSTEM_INFO systemInfo;
|
||||
GetSystemInfo(&systemInfo);
|
||||
pageSize = systemInfo.dwPageSize;
|
||||
}
|
||||
|
||||
/* scan all of memory starting from this frame, and return the last writeable page found */
|
||||
register char *currentPage = (char *)((jsuword)thisFrame & ~(pageSize - 1));
|
||||
if (isGrowingDownward) {
|
||||
while (currentPage > 0) {
|
||||
/* check for underflow */
|
||||
if (currentPage >= (char *)pageSize)
|
||||
currentPage -= pageSize;
|
||||
else
|
||||
currentPage = 0;
|
||||
if (!isPageWritable(currentPage))
|
||||
return currentPage + pageSize;
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
while (true) {
|
||||
/* guaranteed to complete because isPageWritable returns false at end of memory */
|
||||
currentPage += pageSize;
|
||||
if (!isPageWritable(currentPage))
|
||||
return currentPage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(XP_WIN)
|
||||
#if defined(XP_WIN)
|
||||
|
||||
void *
|
||||
GetNativeStackBaseImpl()
|
||||
|
120
js/src/jsobj.cpp
120
js/src/jsobj.cpp
@ -66,6 +66,7 @@
|
||||
#include "jslock.h"
|
||||
#include "jsnum.h"
|
||||
#include "jsobj.h"
|
||||
#include "jsonparser.h"
|
||||
#include "jsopcode.h"
|
||||
#include "jsparse.h"
|
||||
#include "jsproxy.h"
|
||||
@ -983,20 +984,6 @@ const char *
|
||||
js_ComputeFilename(JSContext *cx, JSStackFrame *caller,
|
||||
JSPrincipals *principals, uintN *linenop)
|
||||
{
|
||||
uint32 flags;
|
||||
#ifdef DEBUG
|
||||
JSSecurityCallbacks *callbacks = JS_GetSecurityCallbacks(cx);
|
||||
#endif
|
||||
|
||||
JS_ASSERT(principals || !(callbacks && callbacks->findObjectPrincipals));
|
||||
flags = JS_GetScriptFilenameFlags(caller->script());
|
||||
if ((flags & JSFILENAME_PROTECTED) &&
|
||||
principals &&
|
||||
strcmp(principals->codebase, "[System Principal]")) {
|
||||
*linenop = 0;
|
||||
return principals->codebase;
|
||||
}
|
||||
|
||||
jsbytecode *pc = caller->pc(cx);
|
||||
if (pc && js_GetOpcode(cx, caller->script(), pc) == JSOP_EVAL) {
|
||||
JS_ASSERT(js_GetOpcode(cx, caller->script(), pc + JSOP_EVAL_LENGTH) == JSOP_LINENO);
|
||||
@ -1229,6 +1216,7 @@ EvalKernel(JSContext *cx, uintN argc, Value *vp, EvalType evalType, JSStackFrame
|
||||
* will be lost.
|
||||
*/
|
||||
if (length > 2 && chars[0] == '(' && chars[length - 1] == ')') {
|
||||
#if USE_OLD_AND_BUSTED_JSON_PARSER
|
||||
JSONParser *jp = js_BeginJSONParse(cx, vp, /* suppressErrors = */true);
|
||||
if (jp != NULL) {
|
||||
/* Run JSON-parser on string inside ( and ). */
|
||||
@ -1237,6 +1225,14 @@ EvalKernel(JSContext *cx, uintN argc, Value *vp, EvalType evalType, JSStackFrame
|
||||
if (ok)
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
JSONSourceParser parser(cx, chars + 1, length - 2, JSONSourceParser::StrictJSON,
|
||||
JSONSourceParser::NoError);
|
||||
if (!parser.parse(vp))
|
||||
return false;
|
||||
if (!vp->isUndefined())
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2950,10 +2946,10 @@ JSObject* FASTCALL
|
||||
js_String_tn(JSContext* cx, JSObject* proto, JSString* str)
|
||||
{
|
||||
JS_ASSERT(JS_ON_TRACE(cx));
|
||||
JS_ASSERT(FINALIZE_OBJECT2 == gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(&js_StringClass)));
|
||||
JSObject *obj = NewObjectWithClassProto(cx, &js_StringClass, proto, FINALIZE_OBJECT2);
|
||||
if (!obj)
|
||||
if (!obj || !obj->initString(cx, str))
|
||||
return NULL;
|
||||
obj->setPrimitiveThis(StringValue(str));
|
||||
return obj;
|
||||
}
|
||||
JS_DEFINE_CALLINFO_3(extern, OBJECT, js_String_tn, CONTEXT, CALLEE_PROTOTYPE, STRING, 0,
|
||||
@ -5480,6 +5476,14 @@ JSObject::reportNotExtensible(JSContext *cx, uintN report)
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
bool
|
||||
JSObject::callMethod(JSContext *cx, jsid id, uintN argc, Value *argv, Value *vp)
|
||||
{
|
||||
Value fval;
|
||||
return js_GetMethod(cx, this, id, JSGET_NO_METHOD_BARRIER, &fval) &&
|
||||
ExternalInvoke(cx, ObjectValue(*this), fval, argc, argv, vp);
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
||||
Value *vp, JSBool strict)
|
||||
@ -5899,12 +5903,21 @@ DefaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!js_TryMethod(cx, obj, cx->runtime->atomState.toStringAtom, 0, NULL, &v))
|
||||
Value fval;
|
||||
jsid id = ATOM_TO_JSID(cx->runtime->atomState.toStringAtom);
|
||||
if (!js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, &fval))
|
||||
return false;
|
||||
if (!v.isPrimitive()) {
|
||||
if (!obj->getClass()->convert(cx, obj, hint, &v))
|
||||
if (js_IsCallable(fval)) {
|
||||
if (!ExternalInvoke(cx, ObjectValue(*obj), fval, 0, NULL, &v))
|
||||
return false;
|
||||
if (v.isPrimitive()) {
|
||||
*vp = v;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!obj->getClass()->convert(cx, obj, hint, &v))
|
||||
return false;
|
||||
} else {
|
||||
/* Optimize (new String(...)).valueOf(). */
|
||||
Class *clasp = obj->getClass();
|
||||
@ -5924,8 +5937,18 @@ DefaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp)
|
||||
return false;
|
||||
if (v.isObject()) {
|
||||
JS_ASSERT(hint != TypeOfValue(cx, v));
|
||||
if (!js_TryMethod(cx, obj, cx->runtime->atomState.toStringAtom, 0, NULL, &v))
|
||||
Value fval;
|
||||
jsid id = ATOM_TO_JSID(cx->runtime->atomState.toStringAtom);
|
||||
if (!js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, &fval))
|
||||
return false;
|
||||
if (js_IsCallable(fval)) {
|
||||
if (!ExternalInvoke(cx, ObjectValue(*obj), fval, 0, NULL, &v))
|
||||
return false;
|
||||
if (v.isPrimitive()) {
|
||||
*vp = v;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (v.isObject()) {
|
||||
@ -6156,18 +6179,15 @@ js_SetClassPrototype(JSContext *cx, JSObject *ctor, JSObject *proto, uintN attrs
|
||||
JSObject *
|
||||
PrimitiveToObject(JSContext *cx, const Value &v)
|
||||
{
|
||||
JS_ASSERT(v.isPrimitive());
|
||||
|
||||
Class *clasp;
|
||||
if (v.isNumber()) {
|
||||
clasp = &js_NumberClass;
|
||||
} else if (v.isString()) {
|
||||
clasp = &js_StringClass;
|
||||
} else {
|
||||
JS_ASSERT(v.isBoolean());
|
||||
clasp = &js_BooleanClass;
|
||||
if (v.isString()) {
|
||||
JSObject *obj = NewBuiltinClassInstance(cx, &js_StringClass);
|
||||
if (!obj || !obj->initString(cx, v.toString()))
|
||||
return NULL;
|
||||
return obj;
|
||||
}
|
||||
|
||||
JS_ASSERT(v.isNumber() || v.isBoolean());
|
||||
Class *clasp = v.isNumber() ? &js_NumberClass : &js_BooleanClass;
|
||||
JSObject *obj = NewBuiltinClassInstance(cx, clasp);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
@ -6243,35 +6263,21 @@ js_ValueToNonNullObject(JSContext *cx, const Value &v)
|
||||
JSBool
|
||||
js_TryValueOf(JSContext *cx, JSObject *obj, JSType type, Value *rval)
|
||||
{
|
||||
Value argv[1];
|
||||
|
||||
argv[0].setString(cx->runtime->atomState.typeAtoms[type]);
|
||||
return js_TryMethod(cx, obj, cx->runtime->atomState.valueOfAtom,
|
||||
1, argv, rval);
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_TryMethod(JSContext *cx, JSObject *obj, JSAtom *atom,
|
||||
uintN argc, Value *argv, Value *rval)
|
||||
{
|
||||
JS_CHECK_RECURSION(cx, return JS_FALSE);
|
||||
|
||||
/*
|
||||
* Report failure only if an appropriate method was found, and calling it
|
||||
* returned failure. We propagate failure in this case to make exceptions
|
||||
* behave properly.
|
||||
*/
|
||||
JSErrorReporter older = JS_SetErrorReporter(cx, NULL);
|
||||
jsid id = ATOM_TO_JSID(atom);
|
||||
Value fval;
|
||||
JSBool ok = js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, &fval);
|
||||
JS_SetErrorReporter(cx, older);
|
||||
if (!ok)
|
||||
jsid id = ATOM_TO_JSID(cx->runtime->atomState.valueOfAtom);
|
||||
if (!js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, &fval))
|
||||
return false;
|
||||
|
||||
if (fval.isPrimitive())
|
||||
return JS_TRUE;
|
||||
return ExternalInvoke(cx, ObjectValue(*obj), fval, argc, argv, rval);
|
||||
if (js_IsCallable(fval)) {
|
||||
Value v;
|
||||
Value argv[] = { StringValue(cx->runtime->atomState.typeAtoms[type]) };
|
||||
if (!ExternalInvoke(cx, ObjectValue(*obj), fval, JS_ARRAY_LENGTH(argv), argv, &v))
|
||||
return false;
|
||||
if (v.isPrimitive()) {
|
||||
*rval = v;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#if JS_HAS_XDR
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user