Merge mozilla central and tracemonkey.

This commit is contained in:
Chris Leary 2011-04-11 20:38:35 -07:00
commit f3dfc40bb7
184 changed files with 5438 additions and 4082 deletions

View File

@ -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

View File

@ -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:

View File

@ -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);

View File

@ -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) {

View File

@ -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) {

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -1 +0,0 @@
"Unterminated string literal

View File

@ -1 +0,0 @@
{"Extra value after close": true} "misplaced quoted value"

View File

@ -1 +0,0 @@
{"Illegal expression": 1 + 2}

View File

@ -1 +0,0 @@
{"Illegal invocation": alert()}

View File

@ -1 +0,0 @@
{"Numbers cannot have leading zeroes": 013}

View File

@ -1 +0,0 @@
{"Numbers cannot be hex": 0x14}

View File

@ -1 +0,0 @@
["Illegal backslash escape: \x15"]

View File

@ -1 +0,0 @@
[\naked]

View File

@ -1 +0,0 @@
["Illegal backslash escape: \017"]

View File

@ -1 +0,0 @@
[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]

View File

@ -1 +0,0 @@
{"Missing colon" null}

View File

@ -1 +0,0 @@
["Unclosed array"

View File

@ -1 +0,0 @@
{"Double colon":: null}

View File

@ -1 +0,0 @@
{"Comma instead of colon", null}

View File

@ -1 +0,0 @@
["Colon instead of comma": false]

View File

@ -1 +0,0 @@
["Bad value", truth]

View File

@ -1 +0,0 @@
['single quote']

View File

@ -1 +0,0 @@
[" tab character in string "]

View File

@ -1 +0,0 @@
["tab\ character\ in\ string\ "]

View File

@ -1,2 +0,0 @@
["line
break"]

View File

@ -1,2 +0,0 @@
["line\
break"]

View File

@ -1 +0,0 @@
[0e]

View File

@ -1 +0,0 @@
{unquoted_key: "keys must be quoted"}

View File

@ -1 +0,0 @@
[0e+]

View File

@ -1 +0,0 @@
[0e+-1]

View File

@ -1 +0,0 @@
{"Comma instead if closing brace": true,

View File

@ -1 +0,0 @@
["mismatch"}

View File

@ -1 +0,0 @@
0{

View File

@ -1 +0,0 @@
["extra comma",]

View File

@ -1 +0,0 @@
["double extra comma",,]

View File

@ -1 +0,0 @@
[ , "<-- missing value"]

View File

@ -1 +0,0 @@
["Comma after the close"],

View File

@ -1 +0,0 @@
["Extra close"]]

View File

@ -1 +0,0 @@
{"Extra comma": true,}

View File

@ -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");

View File

@ -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 '&nbsp;'),
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');
};
}
})();

View File

@ -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": "&#34; \u0022 %22 0x22 034 &#x22;",
"\/\\\"\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"]

View File

@ -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"], "&#34; \u0022 %22 0x22 034 &#x22;");
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();
}

View 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.");
}

View File

@ -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]);
}

View File

@ -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();
}

View File

@ -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));
}

View File

@ -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();

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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');
}

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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;
};
*/

View File

@ -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)

View File

@ -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

View File

@ -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@

View File

@ -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:

View File

@ -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"

View File

@ -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()

View File

@ -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")

View File

@ -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::

View 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)

View File

@ -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"

View File

@ -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. */

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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(&regExpPool);
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()
{

View File

@ -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();

View File

@ -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;
}

View File

@ -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);

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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)
{

View File

@ -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);

View File

@ -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();
}

View File

@ -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___ */

View File

@ -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
};

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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(); }

View File

@ -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() \

View File

@ -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);

View File

@ -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;

View File

@ -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) {

View File

@ -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. */

View File

@ -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___ */

View File

@ -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)

View File

@ -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()

View File

@ -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