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,17 +378,11 @@ 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) {
if (!JS_ParseJSON(ctx, (jschar*)nsString(aJSON).get(),
(uint32)aJSON.Length(), &json)) {
json = JSVAL_NULL;
}
}
}
JSString* jsMessage =
JS_NewUCStringCopyN(ctx,
reinterpret_cast<const jschar *>(nsString(aMessage).get()),
@ -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);
PRUnichar* endelems = mBufferedChars.AppendElements(unicharLength);
PRInt32 preLength = unicharLength;
rv = mDecoder->Convert(aBuffer, &srcLen, endelems, &unicharLength);
if (NS_FAILED(rv))
return rv;
}
void nsJSONListener::Cleanup()
{
if (mJSONParser)
JS_FinishJSONParse(mCx, mJSONParser, JSVAL_NULL);
mJSONParser = nsnull;
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) {
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
@ -226,12 +226,12 @@ interface jsdIDebuggerService : nsISupports
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);
@ -253,9 +253,7 @@ interface jsdIDebuggerService : nsISupports
/**
* 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.
* derived objects, and clear all of your breakpoints.
*/
void off ();
@ -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

@ -2932,8 +2932,18 @@ JS_PUBLIC_API(JSBool)
JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
{
CHECK_REQUEST(cx);
#ifdef DEBUG
if (argv) {
assertSameCompartment(cx, obj);
return InstanceOf(cx, obj, Valueify(clasp), Valueify(argv));
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();
}
@ -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

@ -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)
#if JS_HAS_TOSOURCE
class ArraySharpDetector
{
JSString *str = sb.finishString();
if (!str)
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;
rval->setString(str);
sharp = IS_SHARP(he);
return true;
}
#if JS_HAS_TOSOURCE
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))
AutoArrayCycleDetector detector(cx, obj);
if (!detector.init())
return false;
genBefore = cx->busyArrays.generation();
} else {
/* Cycle, so return empty string. */
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;
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++) {
/* Use rval to locally root each element value. */
if (!JS_CHECK_OPERATION_LIMIT(cx))
return false;
JSBool hole;
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetElement(cx, obj, index, &hole, rval)) {
goto out;
}
if (!GetElement(cx, obj, index, &hole, rval))
return false;
/* Get element's character string. */
if (!(hole || rval->isNullOrUndefined())) {
if (!hole && !rval->isNullOrUndefined()) {
if (locale) {
/* Work on obj.toLocalString() instead. */
JSObject *robj;
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;
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))
goto out;
return false;
}
/* Append the separator. */
if (index + 1 != length) {
if (!sb.append(sep, seplen))
goto out;
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. */

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

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

@ -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 *>
{
typedef T *Lookup;
static HashNumber hash(T *l) {
/*
* Strip often-0 lower bits for better distribution after multiplying
* by the sGoldenRatio.
* Pointer hashing policy that strips the lowest zeroBits when calculating the
* hash to improve key distribution.
*/
return HashNumber(reinterpret_cast<size_t>(l) >>
tl::FloorLog2<sizeof(void *)>::result);
template <typename Key, size_t zeroBits>
struct PointerHasher
{
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,9 +968,18 @@ 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(); }
/*
* 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

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

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

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