summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--browser/base/content/browser-media.js58
-rw-r--r--browser/modules/ContentWebRTC.jsm1
-rw-r--r--browser/modules/webrtcUI.jsm8
-rw-r--r--chrome/nsChromeRegistry.cpp5
-rw-r--r--devtools/client/inspector/markup/test/browser_markup_events3.js4
-rw-r--r--devtools/client/webconsole/test/browser_webconsole_jsterm.js1
-rw-r--r--devtools/server/actors/errordocs.js1
-rw-r--r--devtools/shared/webconsole/test/test_page_errors.html10
-rw-r--r--dom/events/EventListenerManager.cpp5
-rw-r--r--dom/html/nsHTMLDocument.cpp12
-rw-r--r--dom/media/GraphDriver.cpp1
-rwxr-xr-xdom/performance/PerformanceTiming.cpp27
-rwxr-xr-xdom/performance/PerformanceTiming.h2
-rw-r--r--dom/performance/tests/test_performance_user_timing.js2
-rw-r--r--js/src/builtin/Intl.cpp102
-rw-r--r--js/src/builtin/TypedArray.js75
-rw-r--r--js/src/frontend/BytecodeCompiler.cpp127
-rw-r--r--js/src/frontend/BytecodeCompiler.h41
-rw-r--r--js/src/frontend/Parser.cpp55
-rw-r--r--js/src/frontend/Parser.h16
-rw-r--r--js/src/frontend/TokenStream.cpp149
-rw-r--r--js/src/frontend/TokenStream.h1
-rw-r--r--js/src/jit-test/tests/basic/destructuring-default.js5
-rw-r--r--js/src/jit-test/tests/basic/destructuring-rest.js7
-rw-r--r--js/src/jit-test/tests/debug/Script-gc-02.js2
-rw-r--r--js/src/jit-test/tests/debug/Script-gc-03.js2
-rw-r--r--js/src/jit-test/tests/debug/Script-sourceStart-04.js4
-rw-r--r--js/src/jit-test/tests/proxy/testWrapWithProtoIter.js1
-rw-r--r--js/src/jit-test/tests/proxy/testWrapWithProtoTypedArray.js19
-rw-r--r--js/src/js.msg1
-rw-r--r--js/src/jsapi.cpp70
-rw-r--r--js/src/jsfun.cpp308
-rw-r--r--js/src/jsfun.h5
-rw-r--r--js/src/jsscript.cpp27
-rw-r--r--js/src/jsscript.h28
-rw-r--r--js/src/tests/Intl/Collator/construct-newtarget.js81
-rw-r--r--js/src/tests/Intl/DateTimeFormat/construct-newtarget.js81
-rw-r--r--js/src/tests/Intl/NumberFormat/construct-newtarget.js81
-rw-r--r--js/src/tests/ecma_2017/AsyncFunctions/construct-newtarget.js79
-rw-r--r--js/src/tests/ecma_2017/AsyncFunctions/subclass.js31
-rw-r--r--js/src/tests/ecma_5/Function/arguments-caller-callee.js12
-rw-r--r--js/src/tests/ecma_5/Function/arguments-property-attributes.js8
-rw-r--r--js/src/tests/ecma_6/Function/invalid-parameter-list.js27
-rw-r--r--js/src/tests/ecma_6/Generators/construct-newtarget.js79
-rw-r--r--js/src/tests/ecma_6/Generators/subclass.js33
-rw-r--r--js/src/tests/ecma_6/Syntax/identifiers-with-extended-unicode-escape.js18
-rw-r--r--js/src/tests/jstests.list10
-rw-r--r--js/src/vm/ArgumentsObject.cpp6
-rw-r--r--js/src/vm/AsyncFunction.cpp19
-rw-r--r--js/src/vm/AsyncFunction.h3
-rw-r--r--js/src/vm/Debugger.cpp9
-rw-r--r--js/src/vm/Unicode.cpp879
-rw-r--r--js/src/vm/Unicode.h28
-rw-r--r--js/src/vm/UnicodeNonBMP.h10
-rwxr-xr-xjs/src/vm/make_unicode.py111
-rw-r--r--js/src/wasm/AsmJS.cpp75
-rw-r--r--js/xpconnect/loader/mozJSSubScriptLoader.cpp4
-rw-r--r--mozglue/android/NSSBridge.cpp114
-rw-r--r--mozglue/android/NSSBridge.h4
-rw-r--r--netwerk/sctp/datachannel/DataChannel.cpp5
60 files changed, 2271 insertions, 718 deletions
diff --git a/browser/base/content/browser-media.js b/browser/base/content/browser-media.js
index f721be74d..bd5c5b227 100644
--- a/browser/base/content/browser-media.js
+++ b/browser/base/content/browser-media.js
@@ -45,11 +45,23 @@ var gEMEHandler = {
}
return true;
},
- getLearnMoreLink: function(msgId) {
- let text = gNavigatorBundle.getString("emeNotifications." + msgId + ".learnMoreLabel");
+ getEMEDisabledFragment: function(msgId) {
+ let mainMessage = gNavigatorBundle.getString("emeNotifications.drmContentDisabled.message");
+ let [prefix, suffix] = mainMessage.split(/%(?:\$\d)?S/).map(s => document.createTextNode(s));
+ let text = gNavigatorBundle.getString("emeNotifications.drmContentDisabled.learnMoreLabel");
let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL");
- return "<label class='text-link' href='" + baseURL + "drm-content'>" +
- text + "</label>";
+ let link = document.createElement("label");
+ link.className = "text-link";
+ link.setAttribute("href", baseURL + "drm-content");
+ link.textContent = text;
+
+ let fragment = document.createDocumentFragment();
+ [prefix, link, suffix].forEach(n => fragment.appendChild(n));
+ return fragment;
+ },
+ getMessageWithBrandName: function(notificationId) {
+ let msgId = "emeNotifications." + notificationId + ".message";
+ return gNavigatorBundle.getFormattedString(msgId, [this._brandShortName]);
},
receiveMessage: function({target: browser, data: data}) {
let parsedData;
@@ -67,7 +79,8 @@ var gEMEHandler = {
let notificationId;
let buttonCallback;
- let params = [];
+ // Notification message can be either a string or a DOM fragment.
+ let notificationMessage;
switch (status) {
case "available":
case "cdm-created":
@@ -82,17 +95,17 @@ var gEMEHandler = {
case "cdm-disabled":
notificationId = "drmContentDisabled";
buttonCallback = gEMEHandler.ensureEMEEnabled.bind(gEMEHandler, browser, keySystem)
- params = [this.getLearnMoreLink(notificationId)];
+ notificationMessage = this.getEMEDisabledFragment();
break;
case "cdm-insufficient-version":
notificationId = "drmContentCDMInsufficientVersion";
- params = [this._brandShortName];
+ notificationMessage = this.getMessageWithBrandName(notificationId);
break;
case "cdm-not-installed":
notificationId = "drmContentCDMInstalling";
- params = [this._brandShortName];
+ notificationMessage = this.getMessageWithBrandName(notificationId);
break;
case "cdm-not-supported":
@@ -104,44 +117,29 @@ var gEMEHandler = {
return;
}
- this.showNotificationBar(browser, notificationId, keySystem, params, buttonCallback);
- },
- showNotificationBar: function(browser, notificationId, keySystem, labelParams, callback) {
+ // Now actually create the notification
+
let box = gBrowser.getNotificationBox(browser);
if (box.getNotificationWithValue(notificationId)) {
return;
}
- let msgPrefix = "emeNotifications." + notificationId + ".";
- let msgId = msgPrefix + "message";
-
- let message = labelParams.length ?
- gNavigatorBundle.getFormattedString(msgId, labelParams) :
- gNavigatorBundle.getString(msgId);
-
let buttons = [];
- if (callback) {
+ if (buttonCallback) {
+ let msgPrefix = "emeNotifications." + notificationId + ".";
let btnLabelId = msgPrefix + "button.label";
let btnAccessKeyId = msgPrefix + "button.accesskey";
buttons.push({
label: gNavigatorBundle.getString(btnLabelId),
accessKey: gNavigatorBundle.getString(btnAccessKeyId),
- callback: callback
+ callback: buttonCallback
});
}
let iconURL = "chrome://browser/skin/drm-icon.svg#chains-black";
- // Do a little dance to get rich content into the notification:
- let fragment = document.createDocumentFragment();
- let descriptionContainer = document.createElement("description");
- descriptionContainer.innerHTML = message;
- while (descriptionContainer.childNodes.length) {
- fragment.appendChild(descriptionContainer.childNodes[0]);
- }
-
- box.appendNotification(fragment, notificationId, iconURL, box.PRIORITY_WARNING_MEDIUM,
- buttons);
+ box.appendNotification(notificationMessage, notificationId, iconURL,
+ box.PRIORITY_WARNING_MEDIUM, buttons);
},
showPopupNotificationForSuccess: function(browser, keySystem) {
// We're playing EME content! Remove any "we can't play because..." messages.
diff --git a/browser/modules/ContentWebRTC.jsm b/browser/modules/ContentWebRTC.jsm
index bfb98a868..fd50176a0 100644
--- a/browser/modules/ContentWebRTC.jsm
+++ b/browser/modules/ContentWebRTC.jsm
@@ -208,6 +208,7 @@ function prompt(aContentWindow, aWindowID, aCallID, aConstraints, aDevices, aSec
let request = {
callID: aCallID,
windowID: aWindowID,
+ origin: aContentWindow.origin,
documentURI: aContentWindow.document.documentURI,
secure: aSecure,
requestTypes: requestTypes,
diff --git a/browser/modules/webrtcUI.jsm b/browser/modules/webrtcUI.jsm
index b24135bfc..08de46bb3 100644
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -290,7 +290,13 @@ function prompt(aBrowser, aRequest) {
let {audioDevices: audioDevices, videoDevices: videoDevices,
sharingScreen: sharingScreen, sharingAudio: sharingAudio,
requestTypes: requestTypes} = aRequest;
- let uri = Services.io.newURI(aRequest.documentURI, null, null);
+ let uri;
+ try {
+ // This fails for principals that serialize to "null", e.g. file URIs.
+ uri = Services.io.newURI(aRequest.origin, null, null);
+ } catch (e) {
+ uri = Services.io.newURI(aRequest.documentURI, null, null);
+ }
let host = getHost(uri);
let chromeDoc = aBrowser.ownerDocument;
let chromeWin = chromeDoc.defaultView;
diff --git a/chrome/nsChromeRegistry.cpp b/chrome/nsChromeRegistry.cpp
index 0aa7f3f14..0302b9997 100644
--- a/chrome/nsChromeRegistry.cpp
+++ b/chrome/nsChromeRegistry.cpp
@@ -234,15 +234,18 @@ nsChromeRegistry::Canonify(nsIURL* aChromeURL)
aChromeURL->SetPath(path);
}
else {
- // prevent directory traversals ("..")
// path is already unescaped once, but uris can get unescaped twice
const char* pos = path.BeginReading();
const char* end = path.EndReading();
+ if (*pos == '/' || *pos == ' ') {
+ return NS_ERROR_DOM_BAD_URI;
+ }
while (pos < end) {
switch (*pos) {
case ':':
return NS_ERROR_DOM_BAD_URI;
case '.':
+ // prevent directory traversals ("..")
if (pos[1] == '.')
return NS_ERROR_DOM_BAD_URI;
break;
diff --git a/devtools/client/inspector/markup/test/browser_markup_events3.js b/devtools/client/inspector/markup/test/browser_markup_events3.js
index a9dc2a499..a38e9a011 100644
--- a/devtools/client/inspector/markup/test/browser_markup_events3.js
+++ b/devtools/client/inspector/markup/test/browser_markup_events3.js
@@ -115,7 +115,7 @@ const TEST_DATA = [ // eslint-disable-line
expected: [
{
type: "click",
- filename: TEST_URL + ":1",
+ filename: TEST_URL + ":0",
attributes: [
"Bubbling",
"DOM2"
@@ -129,7 +129,7 @@ const TEST_DATA = [ // eslint-disable-line
expected: [
{
type: "click",
- filename: TEST_URL + ":1",
+ filename: TEST_URL + ":0",
attributes: [
"Bubbling",
"DOM2"
diff --git a/devtools/client/webconsole/test/browser_webconsole_jsterm.js b/devtools/client/webconsole/test/browser_webconsole_jsterm.js
index 221c96fa6..ae5dc71fe 100644
--- a/devtools/client/webconsole/test/browser_webconsole_jsterm.js
+++ b/devtools/client/webconsole/test/browser_webconsole_jsterm.js
@@ -175,7 +175,6 @@ function* testJSTerm(hud) {
"JSMSG_BAD_RADIX": "(42).toString(0);",
"JSMSG_BAD_ARRAY_LENGTH": "([]).length = -1",
"JSMSG_NEGATIVE_REPETITION_COUNT": "'abc'.repeat(-1);",
- "JSMSG_BAD_FORMAL": "var f = Function('x y', 'return x + y;');",
"JSMSG_PRECISION_RANGE": "77.1234.toExponential(-1);",
};
diff --git a/devtools/server/actors/errordocs.js b/devtools/server/actors/errordocs.js
index 27f687dc7..7c4b3acff 100644
--- a/devtools/server/actors/errordocs.js
+++ b/devtools/server/actors/errordocs.js
@@ -18,7 +18,6 @@ const ErrorDocs = {
JSMSG_RESULTING_STRING_TOO_LARGE: "Resulting_string_too_large",
JSMSG_BAD_RADIX: "Bad_radix",
JSMSG_PRECISION_RANGE: "Precision_range",
- JSMSG_BAD_FORMAL: "Malformed_formal_parameter",
JSMSG_STMT_AFTER_RETURN: "Stmt_after_return",
JSMSG_NOT_A_CODEPOINT: "Not_a_codepoint",
JSMSG_BAD_SORT_ARG: "Array_sort_argument",
diff --git a/devtools/shared/webconsole/test/test_page_errors.html b/devtools/shared/webconsole/test/test_page_errors.html
index 19e5ba4b4..78138856e 100644
--- a/devtools/shared/webconsole/test/test_page_errors.html
+++ b/devtools/shared/webconsole/test/test_page_errors.html
@@ -102,16 +102,6 @@ function doPageErrors()
warning: false,
exception: true,
},
- "var f = Function('x y', 'return x + y;');": {
- errorMessage: /malformed formal/,
- errorMessageName: "JSMSG_BAD_FORMAL",
- sourceName: /test_page_errors/,
- category: "chrome javascript",
- timeStamp: /^\d+$/,
- error: false,
- warning: false,
- exception: true,
- },
"function a() { return; 1 + 1; }": {
errorMessage: /unreachable code/,
errorMessageName: "JSMSG_STMT_AFTER_RETURN",
diff --git a/dom/events/EventListenerManager.cpp b/dom/events/EventListenerManager.cpp
index c8db4f2a1..a8c48ede8 100644
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -996,14 +996,12 @@ EventListenerManager::CompileEventHandlerInternal(Listener* aListener,
}
aListener = nullptr;
- uint32_t lineNo = 0;
nsAutoCString url (NS_LITERAL_CSTRING("-moz-evil:lying-event-listener"));
MOZ_ASSERT(body);
MOZ_ASSERT(aElement);
nsIURI *uri = aElement->OwnerDoc()->GetDocumentURI();
if (uri) {
uri->GetSpec(url);
- lineNo = 1;
}
nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(mTarget);
@@ -1073,8 +1071,9 @@ EventListenerManager::CompileEventHandlerInternal(Listener* aListener,
return NS_ERROR_FAILURE;
}
JS::CompileOptions options(cx);
+ // Use line 0 to make the function body starts from line 1.
options.setIntroductionType("eventHandler")
- .setFileAndLine(url.get(), lineNo)
+ .setFileAndLine(url.get(), 0)
.setVersion(JSVERSION_DEFAULT)
.setElement(&v.toObject())
.setElementAttributeName(jsStr);
diff --git a/dom/html/nsHTMLDocument.cpp b/dom/html/nsHTMLDocument.cpp
index fea78dc37..be5a34d41 100644
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -1536,6 +1536,18 @@ nsHTMLDocument::Open(JSContext* cx,
nsCOMPtr<nsIDocument> ret = this;
return ret.forget();
}
+
+ // Now double-check that our invariants still hold.
+ if (!mScriptGlobalObject) {
+ nsCOMPtr<nsIDocument> ret = this;
+ return ret.forget();
+ }
+
+ nsPIDOMWindowOuter* outer = GetWindow();
+ if (!outer || (GetInnerWindow() != outer->GetCurrentInnerWindow())) {
+ nsCOMPtr<nsIDocument> ret = this;
+ return ret.forget();
+ }
}
nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(shell));
diff --git a/dom/media/GraphDriver.cpp b/dom/media/GraphDriver.cpp
index 9b74bd58c..40e3b72cf 100644
--- a/dom/media/GraphDriver.cpp
+++ b/dom/media/GraphDriver.cpp
@@ -1055,6 +1055,7 @@ AudioCallbackDriver::StateCallback(cubeb_state aState)
{
STREAM_LOG(LogLevel::Debug, ("AudioCallbackDriver State: %d", aState));
if (aState == CUBEB_STATE_ERROR && mShouldFallbackIfError) {
+ mShouldFallbackIfError = false;
MonitorAutoLock lock(GraphImpl()->GetMonitor());
// Fall back to a driver using a normal thread. If needed,
// the graph will try to re-open an audio stream later.
diff --git a/dom/performance/PerformanceTiming.cpp b/dom/performance/PerformanceTiming.cpp
index 5f771f0aa..e2f76a21f 100755
--- a/dom/performance/PerformanceTiming.cpp
+++ b/dom/performance/PerformanceTiming.cpp
@@ -46,6 +46,23 @@ PerformanceTiming::PerformanceTiming(Performance* aPerformance,
mReportCrossOriginRedirect = mTimingAllowed && redirectsPassCheck;
}
+ mSecureConnection = false;
+ nsCOMPtr<nsIURI> uri;
+ if (aHttpChannel) {
+ aHttpChannel->GetURI(getter_AddRefs(uri));
+ } else {
+ nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
+ if (httpChannel) {
+ httpChannel->GetURI(getter_AddRefs(uri));
+ }
+ }
+
+ if (uri) {
+ nsresult rv = uri->SchemeIs("https", &mSecureConnection);
+ if (NS_FAILED(rv)) {
+ mSecureConnection = false;
+ }
+ }
InitializeTimingInfo(aChannel);
}
@@ -89,7 +106,8 @@ PerformanceTiming::InitializeTimingInfo(nsITimedChannel* aChannel)
mConnectStart = mAsyncOpen;
}
- if (!mSecureConnectionStart.IsNull() && mSecureConnectionStart < mAsyncOpen) {
+ if (mSecureConnection && !mSecureConnectionStart.IsNull() &&
+ mSecureConnectionStart < mAsyncOpen) {
mSecureConnectionStart = mAsyncOpen;
}
@@ -307,8 +325,11 @@ PerformanceTiming::SecureConnectionStartHighRes()
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
return mZeroTime;
}
- return mSecureConnectionStart.IsNull() ? mZeroTime
- : TimerClamping::ReduceMsTimeValue(TimeStampToDOMHighRes(mSecureConnectionStart));
+ return !mSecureConnection
+ ? 0 // We use 0 here, because mZeroTime is sometimes set to the navigation
+ // start time.
+ : (mSecureConnectionStart.IsNull() ? mZeroTime
+ : TimerClamping::ReduceMsTimeValue(TimeStampToDOMHighRes(mSecureConnectionStart)));
}
DOMTimeMilliSec
diff --git a/dom/performance/PerformanceTiming.h b/dom/performance/PerformanceTiming.h
index edfac8d02..fc7e7d5bd 100755
--- a/dom/performance/PerformanceTiming.h
+++ b/dom/performance/PerformanceTiming.h
@@ -274,6 +274,8 @@ private:
// redirectEnd attributes. It is false if there were no redirects, or if
// any of the responses didn't pass the timing-allow-check
bool mReportCrossOriginRedirect;
+
+ bool mSecureConnection;
};
} // namespace dom
diff --git a/dom/performance/tests/test_performance_user_timing.js b/dom/performance/tests/test_performance_user_timing.js
index 3d05ebb77..cd8261bbd 100644
--- a/dom/performance/tests/test_performance_user_timing.js
+++ b/dom/performance/tests/test_performance_user_timing.js
@@ -263,7 +263,7 @@ var steps = [
performance.measure("test", n);
ok(true, "Measure created from reserved name as starting time: " + n);
} catch (e) {
- ok(["redirectStart", "redirectEnd", "unloadEventStart", "unloadEventEnd", "loadEventEnd"].indexOf(n) >= 0,
+ ok(["redirectStart", "redirectEnd", "unloadEventStart", "unloadEventEnd", "loadEventEnd", "secureConnectionStart"].indexOf(n) >= 0,
"Measure created from reserved name as starting time: " + n + " and threw expected error");
}
};
diff --git a/js/src/builtin/Intl.cpp b/js/src/builtin/Intl.cpp
index 990a4acdb..3a20c487b 100644
--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -765,42 +765,53 @@ static const JSFunctionSpec collator_methods[] = {
};
/**
- * Collator constructor.
- * Spec: ECMAScript Internationalization API Specification, 10.1
+ * 10.1.2 Intl.Collator([ locales [, options]])
+ *
+ * ES2017 Intl draft rev 94045d234762ad107a3d09bb6f7381a65f1a2f9b
*/
static bool
Collator(JSContext* cx, const CallArgs& args, bool construct)
{
RootedObject obj(cx);
+ // We're following ECMA-402 1st Edition when Collator is called because of
+ // backward compatibility issues.
+ // See https://github.com/tc39/ecma402/issues/57
if (!construct) {
- // 10.1.2.1 step 3
+ // ES Intl 1st ed., 10.1.2.1 step 3
JSObject* intl = cx->global()->getOrCreateIntlObject(cx);
if (!intl)
return false;
RootedValue self(cx, args.thisv());
if (!self.isUndefined() && (!self.isObject() || self.toObject() != *intl)) {
- // 10.1.2.1 step 4
+ // ES Intl 1st ed., 10.1.2.1 step 4
obj = ToObject(cx, self);
if (!obj)
return false;
- // 10.1.2.1 step 5
+ // ES Intl 1st ed., 10.1.2.1 step 5
bool extensible;
if (!IsExtensible(cx, obj, &extensible))
return false;
if (!extensible)
return Throw(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE);
} else {
- // 10.1.2.1 step 3.a
+ // ES Intl 1st ed., 10.1.2.1 step 3.a
construct = true;
}
}
if (construct) {
- // 10.1.3.1 paragraph 2
- RootedObject proto(cx, cx->global()->getOrCreateCollatorPrototype(cx));
- if (!proto)
+ // Steps 2-5 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
+ RootedObject proto(cx);
+ if (args.isConstructing() && !GetPrototypeFromCallableConstructor(cx, args, &proto))
return false;
+
+ if (!proto) {
+ proto = cx->global()->getOrCreateCollatorPrototype(cx);
+ if (!proto)
+ return false;
+ }
+
obj = NewObjectWithGivenProto(cx, &CollatorClass, proto);
if (!obj)
return false;
@@ -808,15 +819,13 @@ Collator(JSContext* cx, const CallArgs& args, bool construct)
obj->as<NativeObject>().setReservedSlot(UCOLLATOR_SLOT, PrivateValue(nullptr));
}
- // 10.1.2.1 steps 1 and 2; 10.1.3.1 steps 1 and 2
RootedValue locales(cx, args.length() > 0 ? args[0] : UndefinedValue());
RootedValue options(cx, args.length() > 1 ? args[1] : UndefinedValue());
- // 10.1.2.1 step 6; 10.1.3.1 step 3
+ // Step 6.
if (!IntlInitialize(cx, obj, cx->names().InitializeCollator, locales, options))
return false;
- // 10.1.2.1 steps 3.a and 7
args.rval().setObject(*obj);
return true;
}
@@ -833,6 +842,7 @@ js::intl_Collator(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2);
+ MOZ_ASSERT(!args.isConstructing());
// intl_Collator is an intrinsic for self-hosted JavaScript, so it cannot
// be used with "new", but it still has to be treated as a constructor.
return Collator(cx, args, true);
@@ -1257,42 +1267,53 @@ static const JSFunctionSpec numberFormat_methods[] = {
};
/**
- * NumberFormat constructor.
- * Spec: ECMAScript Internationalization API Specification, 11.1
+ * 11.2.1 Intl.NumberFormat([ locales [, options]])
+ *
+ * ES2017 Intl draft rev 94045d234762ad107a3d09bb6f7381a65f1a2f9b
*/
static bool
NumberFormat(JSContext* cx, const CallArgs& args, bool construct)
{
RootedObject obj(cx);
+ // We're following ECMA-402 1st Edition when NumberFormat is called
+ // because of backward compatibility issues.
+ // See https://github.com/tc39/ecma402/issues/57
if (!construct) {
- // 11.1.2.1 step 3
+ // ES Intl 1st ed., 11.1.2.1 step 3
JSObject* intl = cx->global()->getOrCreateIntlObject(cx);
if (!intl)
return false;
RootedValue self(cx, args.thisv());
if (!self.isUndefined() && (!self.isObject() || self.toObject() != *intl)) {
- // 11.1.2.1 step 4
+ // ES Intl 1st ed., 11.1.2.1 step 4
obj = ToObject(cx, self);
if (!obj)
return false;
- // 11.1.2.1 step 5
+ // ES Intl 1st ed., 11.1.2.1 step 5
bool extensible;
if (!IsExtensible(cx, obj, &extensible))
return false;
if (!extensible)
return Throw(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE);
} else {
- // 11.1.2.1 step 3.a
+ // ES Intl 1st ed., 11.1.2.1 step 3.a
construct = true;
}
}
if (construct) {
- // 11.1.3.1 paragraph 2
- RootedObject proto(cx, cx->global()->getOrCreateNumberFormatPrototype(cx));
- if (!proto)
+ // Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
+ RootedObject proto(cx);
+ if (args.isConstructing() && !GetPrototypeFromCallableConstructor(cx, args, &proto))
return false;
+
+ if (!proto) {
+ proto = cx->global()->getOrCreateNumberFormatPrototype(cx);
+ if (!proto)
+ return false;
+ }
+
obj = NewObjectWithGivenProto(cx, &NumberFormatClass, proto);
if (!obj)
return false;
@@ -1300,15 +1321,13 @@ NumberFormat(JSContext* cx, const CallArgs& args, bool construct)
obj->as<NativeObject>().setReservedSlot(UNUMBER_FORMAT_SLOT, PrivateValue(nullptr));
}
- // 11.1.2.1 steps 1 and 2; 11.1.3.1 steps 1 and 2
RootedValue locales(cx, args.length() > 0 ? args[0] : UndefinedValue());
RootedValue options(cx, args.length() > 1 ? args[1] : UndefinedValue());
- // 11.1.2.1 step 6; 11.1.3.1 step 3
+ // Step 3.
if (!IntlInitialize(cx, obj, cx->names().InitializeNumberFormat, locales, options))
return false;
- // 11.1.2.1 steps 3.a and 7
args.rval().setObject(*obj);
return true;
}
@@ -1325,6 +1344,7 @@ js::intl_NumberFormat(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2);
+ MOZ_ASSERT(!args.isConstructing());
// intl_NumberFormat is an intrinsic for self-hosted JavaScript, so it
// cannot be used with "new", but it still has to be treated as a
// constructor.
@@ -1725,42 +1745,53 @@ static const JSFunctionSpec dateTimeFormat_methods[] = {
};
/**
- * DateTimeFormat constructor.
- * Spec: ECMAScript Internationalization API Specification, 12.1
+ * 12.2.1 Intl.DateTimeFormat([ locales [, options]])
+ *
+ * ES2017 Intl draft rev 94045d234762ad107a3d09bb6f7381a65f1a2f9b
*/
static bool
DateTimeFormat(JSContext* cx, const CallArgs& args, bool construct)
{
RootedObject obj(cx);
+ // We're following ECMA-402 1st Edition when DateTimeFormat is called
+ // because of backward compatibility issues.
+ // See https://github.com/tc39/ecma402/issues/57
if (!construct) {
- // 12.1.2.1 step 3
+ // ES Intl 1st ed., 12.1.2.1 step 3
JSObject* intl = cx->global()->getOrCreateIntlObject(cx);
if (!intl)
return false;
RootedValue self(cx, args.thisv());
if (!self.isUndefined() && (!self.isObject() || self.toObject() != *intl)) {
- // 12.1.2.1 step 4
+ // ES Intl 1st ed., 12.1.2.1 step 4
obj = ToObject(cx, self);
if (!obj)
return false;
- // 12.1.2.1 step 5
+ // ES Intl 1st ed., 12.1.2.1 step 5
bool extensible;
if (!IsExtensible(cx, obj, &extensible))
return false;
if (!extensible)
return Throw(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE);
} else {
- // 12.1.2.1 step 3.a
+ // ES Intl 1st ed., 12.1.2.1 step 3.a
construct = true;
}
}
if (construct) {
- // 12.1.3.1 paragraph 2
- RootedObject proto(cx, cx->global()->getOrCreateDateTimeFormatPrototype(cx));
- if (!proto)
+ // Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
+ RootedObject proto(cx);
+ if (args.isConstructing() && !GetPrototypeFromCallableConstructor(cx, args, &proto))
return false;
+
+ if (!proto) {
+ proto = cx->global()->getOrCreateDateTimeFormatPrototype(cx);
+ if (!proto)
+ return false;
+ }
+
obj = NewObjectWithGivenProto(cx, &DateTimeFormatClass, proto);
if (!obj)
return false;
@@ -1768,15 +1799,13 @@ DateTimeFormat(JSContext* cx, const CallArgs& args, bool construct)
obj->as<NativeObject>().setReservedSlot(UDATE_FORMAT_SLOT, PrivateValue(nullptr));
}
- // 12.1.2.1 steps 1 and 2; 12.1.3.1 steps 1 and 2
RootedValue locales(cx, args.length() > 0 ? args[0] : UndefinedValue());
RootedValue options(cx, args.length() > 1 ? args[1] : UndefinedValue());
- // 12.1.2.1 step 6; 12.1.3.1 step 3
+ // Step 3.
if (!IntlInitialize(cx, obj, cx->names().InitializeDateTimeFormat, locales, options))
return false;
- // 12.1.2.1 steps 3.a and 7
args.rval().setObject(*obj);
return true;
}
@@ -1793,6 +1822,7 @@ js::intl_DateTimeFormat(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2);
+ MOZ_ASSERT(!args.isConstructing());
// intl_DateTimeFormat is an intrinsic for self-hosted JavaScript, so it
// cannot be used with "new", but it still has to be treated as a
// constructor.
diff --git a/js/src/builtin/TypedArray.js b/js/src/builtin/TypedArray.js
index 4d2d6488f..4a3f38365 100644
--- a/js/src/builtin/TypedArray.js
+++ b/js/src/builtin/TypedArray.js
@@ -35,6 +35,10 @@ function IsDetachedBuffer(buffer) {
return (flags & JS_ARRAYBUFFER_DETACHED_FLAG) !== 0;
}
+function TypedArrayLengthMethod() {
+ return TypedArrayLength(this);
+}
+
function GetAttachedArrayBuffer(tarray) {
var buffer = ViewedArrayBufferIfReified(tarray);
if (IsDetachedBuffer(buffer))
@@ -42,6 +46,10 @@ function GetAttachedArrayBuffer(tarray) {
return buffer;
}
+function GetAttachedArrayBufferMethod() {
+ return GetAttachedArrayBuffer(this);
+}
+
// A function which ensures that the argument is either a typed array or a
// cross-compartment wrapper for a typed array and that the typed array involved
// has an attached array buffer. If one of those conditions doesn't hold (wrong
@@ -54,10 +62,7 @@ function IsTypedArrayEnsuringArrayBuffer(arg) {
return true;
}
- // This is a bit hacky but gets the job done: the first `arg` is used to
- // test for a wrapped typed array, the second as an argument to
- // GetAttachedArrayBuffer.
- callFunction(CallTypedArrayMethodIfWrapped, arg, arg, "GetAttachedArrayBuffer");
+ callFunction(CallTypedArrayMethodIfWrapped, arg, "GetAttachedArrayBufferMethod");
return false;
}
@@ -98,8 +103,8 @@ function TypedArrayCreateWithLength(constructor, length) {
if (isTypedArray) {
len = TypedArrayLength(newTypedArray);
} else {
- len = callFunction(CallTypedArrayMethodIfWrapped, newTypedArray, newTypedArray,
- "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, newTypedArray,
+ "TypedArrayLengthMethod");
}
if (len < length)
@@ -259,15 +264,14 @@ function TypedArrayEvery(callbackfn/*, thisArg*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Steps 3-5.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 6.
if (arguments.length === 0)
@@ -348,15 +352,14 @@ function TypedArrayFilter(callbackfn/*, thisArg*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Step 3.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 4.
if (arguments.length === 0)
@@ -410,15 +413,14 @@ function TypedArrayFind(predicate/*, thisArg*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Steps 3-5.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 6.
if (arguments.length === 0)
@@ -452,15 +454,14 @@ function TypedArrayFindIndex(predicate/*, thisArg*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Steps 3-5.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 6.
if (arguments.length === 0)
@@ -492,15 +493,14 @@ function TypedArrayForEach(callbackfn/*, thisArg*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Step 3-4.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 5.
if (arguments.length === 0)
@@ -686,15 +686,14 @@ function TypedArrayMap(callbackfn/*, thisArg*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Step 3.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 4.
if (arguments.length === 0)
@@ -730,15 +729,14 @@ function TypedArrayReduce(callbackfn/*, initialValue*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Steps 3-5.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 6.
if (arguments.length === 0)
@@ -776,15 +774,14 @@ function TypedArrayReduceRight(callbackfn/*, initialValue*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Steps 3-5.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 6.
if (arguments.length === 0)
@@ -1034,15 +1031,14 @@ function TypedArraySome(callbackfn/*, thisArg*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Steps 3-5.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 6.
if (arguments.length === 0)
@@ -1137,7 +1133,7 @@ function TypedArraySort(comparefn) {
if (isTypedArray) {
buffer = GetAttachedArrayBuffer(obj);
} else {
- buffer = callFunction(CallTypedArrayMethodIfWrapped, obj, obj, "GetAttachedArrayBuffer");
+ buffer = callFunction(CallTypedArrayMethodIfWrapped, obj, "GetAttachedArrayBufferMethod");
}
// Step 3.
@@ -1145,7 +1141,7 @@ function TypedArraySort(comparefn) {
if (isTypedArray) {
len = TypedArrayLength(obj);
} else {
- len = callFunction(CallTypedArrayMethodIfWrapped, obj, obj, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, obj, "TypedArrayLengthMethod");
}
if (comparefn === undefined) {
@@ -1181,8 +1177,8 @@ function TypedArraySort(comparefn) {
if (isTypedArray) {
buffer = GetAttachedArrayBuffer(obj);
} else {
- buffer = callFunction(CallTypedArrayMethodIfWrapped, obj, obj,
- "GetAttachedArrayBuffer");
+ buffer = callFunction(CallTypedArrayMethodIfWrapped, obj,
+ "GetAttachedArrayBufferMethod");
}
}
var bufferDetached;
@@ -1217,15 +1213,14 @@ function TypedArrayToLocaleString(locales = undefined, options = undefined) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(array);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Step 2.
var len;
if (isTypedArray)
len = TypedArrayLength(array);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, array, array, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, array, "TypedArrayLengthMethod");
// Step 4.
if (len === 0)
diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp
index d4c758b6c..3fbfdaa1a 100644
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -7,6 +7,7 @@
#include "frontend/BytecodeCompiler.h"
#include "mozilla/IntegerPrintfMacros.h"
+#include "mozilla/Maybe.h"
#include "jscntxt.h"
#include "jsscript.h"
@@ -28,6 +29,7 @@
using namespace js;
using namespace js::frontend;
using mozilla::Maybe;
+using mozilla::Nothing;
class MOZ_STACK_CLASS AutoCompilationTraceLogger
{
@@ -57,24 +59,24 @@ class MOZ_STACK_CLASS BytecodeCompiler
// Call setters for optional arguments.
void maybeSetSourceCompressor(SourceCompressionTask* sourceCompressor);
- void setSourceArgumentsNotIncluded();
JSScript* compileGlobalScript(ScopeKind scopeKind);
JSScript* compileEvalScript(HandleObject environment, HandleScope enclosingScope);
ModuleObject* compileModule();
- bool compileFunctionBody(MutableHandleFunction fun, Handle<PropertyNameVector> formals,
- GeneratorKind generatorKind, FunctionAsyncKind asyncKind);
+ bool compileStandaloneFunction(MutableHandleFunction fun, GeneratorKind generatorKind,
+ FunctionAsyncKind asyncKind,
+ Maybe<uint32_t> parameterListEnd);
ScriptSourceObject* sourceObjectPtr() const;
private:
JSScript* compileScript(HandleObject environment, SharedContext* sc);
bool checkLength();
- bool createScriptSource();
+ bool createScriptSource(Maybe<uint32_t> parameterListEnd);
bool maybeCompressSource();
bool canLazilyParse();
bool createParser();
- bool createSourceAndParser();
+ bool createSourceAndParser(Maybe<uint32_t> parameterListEnd = Nothing());
bool createScript();
bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter, SharedContext* sharedContext);
bool handleParseFailure(const Directives& newDirectives);
@@ -90,7 +92,6 @@ class MOZ_STACK_CLASS BytecodeCompiler
SourceBufferHolder& sourceBuffer;
RootedScope enclosingScope;
- bool sourceArgumentsNotIncluded;
RootedScriptSource sourceObject;
ScriptSource* scriptSource;
@@ -130,7 +131,6 @@ BytecodeCompiler::BytecodeCompiler(ExclusiveContext* cx,
options(options),
sourceBuffer(sourceBuffer),
enclosingScope(cx, enclosingScope),
- sourceArgumentsNotIncluded(false),
sourceObject(cx),
scriptSource(nullptr),
sourceCompressor(nullptr),
@@ -147,12 +147,6 @@ BytecodeCompiler::maybeSetSourceCompressor(SourceCompressionTask* sourceCompress
this->sourceCompressor = sourceCompressor;
}
-void
-BytecodeCompiler::setSourceArgumentsNotIncluded()
-{
- sourceArgumentsNotIncluded = true;
-}
-
bool
BytecodeCompiler::checkLength()
{
@@ -169,12 +163,12 @@ BytecodeCompiler::checkLength()
}
bool
-BytecodeCompiler::createScriptSource()
+BytecodeCompiler::createScriptSource(Maybe<uint32_t> parameterListEnd)
{
if (!checkLength())
return false;
- sourceObject = CreateScriptSourceObject(cx, options);
+ sourceObject = CreateScriptSourceObject(cx, options, parameterListEnd);
if (!sourceObject)
return false;
@@ -193,9 +187,7 @@ BytecodeCompiler::maybeCompressSource()
if (!cx->compartment()->behaviors().discardSource()) {
if (options.sourceIsLazy) {
scriptSource->setSourceRetrievable();
- } else if (!scriptSource->setSourceCopy(cx, sourceBuffer, sourceArgumentsNotIncluded,
- sourceCompressor))
- {
+ } else if (!scriptSource->setSourceCopy(cx, sourceBuffer, sourceCompressor)) {
return false;
}
}
@@ -242,9 +234,9 @@ BytecodeCompiler::createParser()
}
bool
-BytecodeCompiler::createSourceAndParser()
+BytecodeCompiler::createSourceAndParser(Maybe<uint32_t> parameterListEnd /* = Nothing() */)
{
- return createScriptSource() &&
+ return createScriptSource(parameterListEnd) &&
maybeCompressSource() &&
createParser();
}
@@ -432,18 +424,19 @@ BytecodeCompiler::compileModule()
return module;
}
+// Compile a standalone JS function, which might appear as the value of an
+// event handler attribute in an HTML <INPUT> tag, or in a Function()
+// constructor.
bool
-BytecodeCompiler::compileFunctionBody(MutableHandleFunction fun,
- Handle<PropertyNameVector> formals,
- GeneratorKind generatorKind,
- FunctionAsyncKind asyncKind)
+BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun,
+ GeneratorKind generatorKind,
+ FunctionAsyncKind asyncKind,
+ Maybe<uint32_t> parameterListEnd)
{
MOZ_ASSERT(fun);
MOZ_ASSERT(fun->isTenured());
- fun->setArgCount(formals.length());
-
- if (!createSourceAndParser())
+ if (!createSourceAndParser(parameterListEnd))
return false;
// Speculatively parse using the default directives implied by the context.
@@ -454,8 +447,8 @@ BytecodeCompiler::compileFunctionBody(MutableHandleFunction fun,
ParseNode* fn;
do {
Directives newDirectives = directives;
- fn = parser->standaloneFunctionBody(fun, enclosingScope, formals, generatorKind, asyncKind,
- directives, &newDirectives);
+ fn = parser->standaloneFunction(fun, enclosingScope, parameterListEnd, generatorKind,
+ asyncKind, directives, &newDirectives);
if (!fn && !handleParseFailure(newDirectives))
return false;
} while (!fn);
@@ -492,14 +485,15 @@ BytecodeCompiler::sourceObjectPtr() const
}
ScriptSourceObject*
-frontend::CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOptions& options)
+frontend::CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
+ Maybe<uint32_t> parameterListEnd /* = Nothing() */)
{
ScriptSource* ss = cx->new_<ScriptSource>();
if (!ss)
return nullptr;
ScriptSourceHolder ssHolder(ss);
- if (!ss->initFromOptions(cx, options))
+ if (!ss->initFromOptions(cx, options, parameterListEnd))
return nullptr;
RootedScriptSource sso(cx, ScriptSourceObject::create(cx, ss));
@@ -676,63 +670,44 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
return bce.emitFunctionScript(pn->pn_body);
}
-// Compile a JS function body, which might appear as the value of an event
-// handler attribute in an HTML <INPUT> tag, or in a Function() constructor.
-static bool
-CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyCompileOptions& options,
- Handle<PropertyNameVector> formals, SourceBufferHolder& srcBuf,
- HandleScope enclosingScope, GeneratorKind generatorKind,
- FunctionAsyncKind asyncKind)
+bool
+frontend::CompileStandaloneFunction(JSContext* cx, MutableHandleFunction fun,
+ const ReadOnlyCompileOptions& options,
+ JS::SourceBufferHolder& srcBuf,
+ Maybe<uint32_t> parameterListEnd,
+ HandleScope enclosingScope /* = nullptr */)
{
- MOZ_ASSERT(!options.isRunOnce);
-
- // FIXME: make Function pass in two strings and parse them as arguments and
- // ProgramElements respectively.
+ RootedScope scope(cx, enclosingScope);
+ if (!scope)
+ scope = &cx->global()->emptyGlobalScope();
- BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, enclosingScope,
+ BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, scope,
TraceLogger_ParserCompileFunction);
- compiler.setSourceArgumentsNotIncluded();
- return compiler.compileFunctionBody(fun, formals, generatorKind, asyncKind);
+ return compiler.compileStandaloneFunction(fun, NotGenerator, SyncFunction, parameterListEnd);
}
bool
-frontend::CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
- const ReadOnlyCompileOptions& options,
- Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf,
- HandleScope enclosingScope)
-{
- return CompileFunctionBody(cx, fun, options, formals, srcBuf, enclosingScope, NotGenerator,
- SyncFunction);
-}
-
-bool
-frontend::CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
- const ReadOnlyCompileOptions& options,
- Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf)
+frontend::CompileStandaloneGenerator(JSContext* cx, MutableHandleFunction fun,
+ const ReadOnlyCompileOptions& options,
+ JS::SourceBufferHolder& srcBuf,
+ Maybe<uint32_t> parameterListEnd)
{
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
- return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
- NotGenerator, SyncFunction);
-}
-bool
-frontend::CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun,
- const ReadOnlyCompileOptions& options,
- Handle<PropertyNameVector> formals,
- JS::SourceBufferHolder& srcBuf)
-{
- RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
- return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
- StarGenerator, SyncFunction);
+ BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, emptyGlobalScope,
+ TraceLogger_ParserCompileFunction);
+ return compiler.compileStandaloneFunction(fun, StarGenerator, SyncFunction, parameterListEnd);
}
bool
-frontend::CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
- const ReadOnlyCompileOptions& options,
- Handle<PropertyNameVector> formals,
- JS::SourceBufferHolder& srcBuf)
+frontend::CompileStandaloneAsyncFunction(JSContext* cx, MutableHandleFunction fun,
+ const ReadOnlyCompileOptions& options,
+ JS::SourceBufferHolder& srcBuf,
+ Maybe<uint32_t> parameterListEnd)
{
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
- return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
- StarGenerator, AsyncFunction);
+
+ BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, emptyGlobalScope,
+ TraceLogger_ParserCompileFunction);
+ return compiler.compileStandaloneFunction(fun, StarGenerator, AsyncFunction, parameterListEnd);
}
diff --git a/js/src/frontend/BytecodeCompiler.h b/js/src/frontend/BytecodeCompiler.h
index 1d86f1160..72e967639 100644
--- a/js/src/frontend/BytecodeCompiler.h
+++ b/js/src/frontend/BytecodeCompiler.h
@@ -7,6 +7,8 @@
#ifndef frontend_BytecodeCompiler_h
#define frontend_BytecodeCompiler_h
+#include "mozilla/Maybe.h"
+
#include "NamespaceImports.h"
#include "vm/Scope.h"
@@ -51,22 +53,36 @@ CompileModule(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
MOZ_MUST_USE bool
CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const char16_t* chars, size_t length);
+//
+// Compile a single function. The source in srcBuf must match the ECMA-262
+// FunctionExpression production.
+//
+// If nonzero, parameterListEnd is the offset within srcBuf where the parameter
+// list is expected to end. During parsing, if we find that it ends anywhere
+// else, it's a SyntaxError. This is used to implement the Function constructor;
+// it's how we detect that these weird cases are SyntaxErrors:
+//
+// Function("/*", "*/x) {")
+// Function("x){ if (3", "return x;}")
+//
MOZ_MUST_USE bool
-CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
- const ReadOnlyCompileOptions& options,
- Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf,
- HandleScope enclosingScope);
+CompileStandaloneFunction(JSContext* cx, MutableHandleFunction fun,
+ const ReadOnlyCompileOptions& options,
+ JS::SourceBufferHolder& srcBuf,
+ mozilla::Maybe<uint32_t> parameterListEnd,
+ HandleScope enclosingScope = nullptr);
-// As above, but defaults to the global lexical scope as the enclosing scope.
MOZ_MUST_USE bool
-CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
- const ReadOnlyCompileOptions& options,
- Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
+CompileStandaloneGenerator(JSContext* cx, MutableHandleFunction fun,
+ const ReadOnlyCompileOptions& options,
+ JS::SourceBufferHolder& srcBuf,
+ mozilla::Maybe<uint32_t> parameterListEnd);
MOZ_MUST_USE bool
-CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun,
- const ReadOnlyCompileOptions& options,
- Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
+CompileStandaloneAsyncFunction(JSContext* cx, MutableHandleFunction fun,
+ const ReadOnlyCompileOptions& options,
+ JS::SourceBufferHolder& srcBuf,
+ mozilla::Maybe<uint32_t> parameterListEnd);
MOZ_MUST_USE bool
CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
@@ -74,7 +90,8 @@ CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
ScriptSourceObject*
-CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOptions& options);
+CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
+ mozilla::Maybe<uint32_t> parameterListEnd = mozilla::Nothing());
/*
* True if str consists of an IdentifierStart character, followed by one or
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index 49fef2bf9..f42546eb5 100644
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -2245,13 +2245,13 @@ GetYieldHandling(GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
template <>
ParseNode*
-Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
- HandleScope enclosingScope,
- Handle<PropertyNameVector> formals,
- GeneratorKind generatorKind,
- FunctionAsyncKind asyncKind,
- Directives inheritedDirectives,
- Directives* newDirectives)
+Parser<FullParseHandler>::standaloneFunction(HandleFunction fun,
+ HandleScope enclosingScope,
+ Maybe<uint32_t> parameterListEnd,
+ GeneratorKind generatorKind,
+ FunctionAsyncKind asyncKind,
+ Directives inheritedDirectives,
+ Directives* newDirectives)
{
MOZ_ASSERT(checkOptionsCalled);
@@ -2274,25 +2274,14 @@ Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
if (!funpc.init())
return null();
funpc.setIsStandaloneFunctionBody();
- funpc.functionScope().useAsVarScope(&funpc);
-
- if (formals.length() >= ARGNO_LIMIT) {
- report(ParseError, false, null(), JSMSG_TOO_MANY_FUN_ARGS);
- return null();
- }
-
- bool duplicatedParam = false;
- for (uint32_t i = 0; i < formals.length(); i++) {
- if (!notePositionalFormalParameter(fn, formals[i], false, &duplicatedParam))
- return null();
- }
- funbox->hasDuplicateParameters = duplicatedParam;
YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
AutoAwaitIsKeyword awaitIsKeyword(&tokenStream, asyncKind == AsyncFunction);
- ParseNode* pn = functionBody(InAllowed, yieldHandling, Statement, StatementListBody);
- if (!pn)
+ if (!functionFormalParametersAndBody(InAllowed, yieldHandling, fn, Statement,
+ parameterListEnd))
+ {
return null();
+ }
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand))
@@ -2303,15 +2292,7 @@ Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
return null();
}
- if (!FoldConstants(context, &pn, this))
- return null();
-
- fn->pn_pos.end = pos().end;
-
- MOZ_ASSERT(fn->pn_body->isKind(PNK_PARAMSBODY));
- fn->pn_body->append(pn);
-
- if (!finishFunction())
+ if (!FoldConstants(context, &fn, this))
return null();
return fn;
@@ -3415,7 +3396,8 @@ template <typename ParseHandler>
bool
Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
YieldHandling yieldHandling,
- Node pn, FunctionSyntaxKind kind)
+ Node pn, FunctionSyntaxKind kind,
+ Maybe<uint32_t> parameterListEnd /* = Nothing() */)
{
// Given a properly initialized parse context, try to parse an actual
// function without concern for conversion to strict mode, use of lazy
@@ -3447,6 +3429,13 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
}
}
+ // When parsing something for new Function() we have to make sure to
+ // only treat a certain part of the source as a parameter list.
+ if (parameterListEnd.isSome() && parameterListEnd.value() != pos().begin) {
+ report(ParseError, false, null(), JSMSG_UNEXPECTED_PARAMLIST_END);
+ return false;
+ }
+
// Parse the function body.
FunctionBodyType bodyType = StatementListBody;
TokenKind tt;
@@ -3502,7 +3491,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
report(ParseError, false, null(), JSMSG_CURLY_AFTER_BODY);
return false;
}
- funbox->bufEnd = pos().begin + 1;
+ funbox->bufEnd = pos().end;
} else {
#if !JS_HAS_EXPR_CLOSURES
MOZ_ASSERT(kind == Arrow);
diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h
index 0ad4d56a0..b58b021cd 100644
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -1020,12 +1020,12 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
// Parse a module.
Node moduleBody(ModuleSharedContext* modulesc);
- // Parse a function, given only its body. Used for the Function and
- // Generator constructors.
- Node standaloneFunctionBody(HandleFunction fun, HandleScope enclosingScope,
- Handle<PropertyNameVector> formals,
- GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
- Directives inheritedDirectives, Directives* newDirectives);
+ // Parse a function, used for the Function, GeneratorFunction, and
+ // AsyncFunction constructors.
+ Node standaloneFunction(HandleFunction fun, HandleScope enclosingScope,
+ mozilla::Maybe<uint32_t> parameterListEnd,
+ GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
+ Directives inheritedDirectives, Directives* newDirectives);
// Parse a function, given only its arguments and body. Used for lazily
// parsed functions.
@@ -1041,7 +1041,9 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
// Parse a function's formal parameters and its body assuming its function
// ParseContext is already on the stack.
bool functionFormalParametersAndBody(InHandling inHandling, YieldHandling yieldHandling,
- Node pn, FunctionSyntaxKind kind);
+ Node pn, FunctionSyntaxKind kind,
+ mozilla::Maybe<uint32_t> parameterListEnd = mozilla::Nothing());
+
// Determine whether |yield| is a valid name in the current context, or
// whether it's prohibited due to strictness, JS version, or occurrence
diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
index c166ed414..179a7c244 100644
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -118,13 +118,57 @@ IsIdentifier(const CharT* chars, size_t length)
return true;
}
+static uint32_t
+GetSingleCodePoint(const char16_t** p, const char16_t* end)
+{
+ uint32_t codePoint;
+ if (MOZ_UNLIKELY(unicode::IsLeadSurrogate(**p)) && *p + 1 < end) {
+ char16_t lead = **p;
+ char16_t maybeTrail = *(*p + 1);
+ if (unicode::IsTrailSurrogate(maybeTrail)) {
+ *p += 2;
+ return unicode::UTF16Decode(lead, maybeTrail);
+ }
+ }
+
+ codePoint = **p;
+ (*p)++;
+ return codePoint;
+}
+
+static bool
+IsIdentifierMaybeNonBMP(const char16_t* chars, size_t length)
+{
+ if (IsIdentifier(chars, length))
+ return true;
+
+ if (length == 0)
+ return false;
+
+ const char16_t* p = chars;
+ const char16_t* end = chars + length;
+ uint32_t codePoint;
+
+ codePoint = GetSingleCodePoint(&p, end);
+ if (!unicode::IsIdentifierStart(codePoint))
+ return false;
+
+ while (p < end) {
+ codePoint = GetSingleCodePoint(&p, end);
+ if (!unicode::IsIdentifierPart(codePoint))
+ return false;
+ }
+
+ return true;
+}
+
bool
frontend::IsIdentifier(JSLinearString* str)
{
JS::AutoCheckCannotGC nogc;
return str->hasLatin1Chars()
? ::IsIdentifier(str->latin1Chars(nogc), str->length())
- : ::IsIdentifier(str->twoByteChars(nogc), str->length());
+ : ::IsIdentifierMaybeNonBMP(str->twoByteChars(nogc), str->length());
}
bool
@@ -993,6 +1037,21 @@ IsTokenSane(Token* tp)
#endif
bool
+TokenStream::matchTrailForLeadSurrogate(char16_t lead, char16_t* trail, uint32_t* codePoint)
+{
+ int32_t maybeTrail = getCharIgnoreEOL();
+ if (!unicode::IsTrailSurrogate(maybeTrail)) {
+ ungetCharIgnoreEOL(maybeTrail);
+ return false;
+ }
+
+ if (trail)
+ *trail = maybeTrail;
+ *codePoint = unicode::UTF16Decode(lead, maybeTrail);
+ return true;
+}
+
+bool
TokenStream::putIdentInTokenbuf(const char16_t* identStart)
{
int32_t c;
@@ -1003,11 +1062,39 @@ TokenStream::putIdentInTokenbuf(const char16_t* identStart)
tokenbuf.clear();
for (;;) {
c = getCharIgnoreEOL();
+
+ if (MOZ_UNLIKELY(unicode::IsLeadSurrogate(c))) {
+ char16_t trail;
+ uint32_t codePoint;
+ if (matchTrailForLeadSurrogate(c, &trail, &codePoint)) {
+ if (!unicode::IsIdentifierPart(codePoint))
+ break;
+
+ if (!tokenbuf.append(c) || !tokenbuf.append(trail)) {
+ userbuf.setAddressOfNextRawChar(tmp);
+ return false;
+ }
+ continue;
+ }
+ }
+
if (!unicode::IsIdentifierPart(char16_t(c))) {
if (c != '\\' || !matchUnicodeEscapeIdent(&qc))
break;
+
+ if (MOZ_UNLIKELY(unicode::IsSupplementary(qc))) {
+ char16_t lead, trail;
+ unicode::UTF16Encode(qc, &lead, &trail);
+ if (!tokenbuf.append(lead) || !tokenbuf.append(trail)) {
+ userbuf.setAddressOfNextRawChar(tmp);
+ return false;
+ }
+ continue;
+ }
+
c = qc;
}
+
if (!tokenbuf.append(c)) {
userbuf.setAddressOfNextRawChar(tmp);
return false;
@@ -1168,12 +1255,23 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
static_assert('_' < 128,
"IdentifierStart contains '_', but as !IsUnicodeIDStart('_'), "
"ensure that '_' is never handled here");
- if (unicode::IsUnicodeIDStart(c)) {
+ if (unicode::IsUnicodeIDStart(char16_t(c))) {
identStart = userbuf.addressOfNextRawChar() - 1;
hadUnicodeEscape = false;
goto identifier;
}
+ if (MOZ_UNLIKELY(unicode::IsLeadSurrogate(c))) {
+ uint32_t codePoint;
+ if (matchTrailForLeadSurrogate(c, nullptr, &codePoint) &&
+ unicode::IsUnicodeIDStart(codePoint))
+ {
+ identStart = userbuf.addressOfNextRawChar() - 2;
+ hadUnicodeEscape = false;
+ goto identifier;
+ }
+ }
+
goto badchar;
}
@@ -1224,6 +1322,17 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
c = getCharIgnoreEOL();
if (c == EOF)
break;
+
+ if (MOZ_UNLIKELY(unicode::IsLeadSurrogate(c))) {
+ uint32_t codePoint;
+ if (matchTrailForLeadSurrogate(c, nullptr, &codePoint)) {
+ if (!unicode::IsIdentifierPart(codePoint))
+ break;
+
+ continue;
+ }
+ }
+
if (!unicode::IsIdentifierPart(char16_t(c))) {
if (c != '\\' || !matchUnicodeEscapeIdent(&qc))
break;
@@ -1318,9 +1427,21 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
}
ungetCharIgnoreEOL(c);
- if (c != EOF && unicode::IsIdentifierStart(char16_t(c))) {
- reportError(JSMSG_IDSTART_AFTER_NUMBER);
- goto error;
+ if (c != EOF) {
+ if (unicode::IsIdentifierStart(char16_t(c))) {
+ reportError(JSMSG_IDSTART_AFTER_NUMBER);
+ goto error;
+ }
+
+ if (MOZ_UNLIKELY(unicode::IsLeadSurrogate(c))) {
+ uint32_t codePoint;
+ if (matchTrailForLeadSurrogate(c, nullptr, &codePoint) &&
+ unicode::IsIdentifierStart(codePoint))
+ {
+ reportError(JSMSG_IDSTART_AFTER_NUMBER);
+ goto error;
+ }
+ }
}
// Unlike identifiers and strings, numbers cannot contain escaped
@@ -1425,9 +1546,21 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
}
ungetCharIgnoreEOL(c);
- if (c != EOF && unicode::IsIdentifierStart(char16_t(c))) {
- reportError(JSMSG_IDSTART_AFTER_NUMBER);
- goto error;
+ if (c != EOF) {
+ if (unicode::IsIdentifierStart(char16_t(c))) {
+ reportError(JSMSG_IDSTART_AFTER_NUMBER);
+ goto error;
+ }
+
+ if (MOZ_UNLIKELY(unicode::IsLeadSurrogate(c))) {
+ uint32_t codePoint;
+ if (matchTrailForLeadSurrogate(c, nullptr, &codePoint) &&
+ unicode::IsIdentifierStart(codePoint))
+ {
+ reportError(JSMSG_IDSTART_AFTER_NUMBER);
+ goto error;
+ }
+ }
}
double dval;
diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
index 29dcead62..5d6b4b795 100644
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -952,6 +952,7 @@ class MOZ_STACK_CLASS TokenStream
uint32_t peekExtendedUnicodeEscape(uint32_t* codePoint);
uint32_t matchUnicodeEscapeIdStart(uint32_t* codePoint);
bool matchUnicodeEscapeIdent(uint32_t* codePoint);
+ bool matchTrailForLeadSurrogate(char16_t lead, char16_t* trail, uint32_t* codePoint);
bool peekChars(int n, char16_t* cp);
MOZ_MUST_USE bool getDirectives(bool isMultiline, bool shouldWarnDeprecated);
diff --git a/js/src/jit-test/tests/basic/destructuring-default.js b/js/src/jit-test/tests/basic/destructuring-default.js
index 168977e80..49a908b8a 100644
--- a/js/src/jit-test/tests/basic/destructuring-default.js
+++ b/js/src/jit-test/tests/basic/destructuring-default.js
@@ -84,10 +84,7 @@ function testArgumentFunction(pattern, input) {
'return [a, b, c, d, e, f];'
)(input);
}
-// XXX: ES6 requires the `Function` constructor to accept arbitrary
-// `BindingElement`s as formal parameters. See Bug 1037939.
-// Once fixed, please update the assertions below.
-assertThrowsInstanceOf(() => testAll(testArgumentFunction), SyntaxError);
+testAll(testArgumentFunction);
function testThrow(pattern, input) {
return new Function('input',
diff --git a/js/src/jit-test/tests/basic/destructuring-rest.js b/js/src/jit-test/tests/basic/destructuring-rest.js
index f53f07e03..fcb7b79bb 100644
--- a/js/src/jit-test/tests/basic/destructuring-rest.js
+++ b/js/src/jit-test/tests/basic/destructuring-rest.js
@@ -132,10 +132,9 @@ function testArgumentFunction(pattern, input, binding) {
'return ' + binding
)(input);
}
-// XXX: ES6 requires the `Function` constructor to accept arbitrary
-// `BindingElement`s as formal parameters. See Bug 1037939.
-// Once fixed, please update the assertions below.
-assertThrowsInstanceOf(() => testDeclaration(testArgumentFunction), SyntaxError);
+// ES6 requires the `Function` constructor to accept arbitrary
+// `BindingElement`s as formal parameters.
+testDeclaration(testArgumentFunction);
function testThrow(pattern, input, binding) {
binding = binding || 'rest';
diff --git a/js/src/jit-test/tests/debug/Script-gc-02.js b/js/src/jit-test/tests/debug/Script-gc-02.js
index 33d33dfc1..04dd4b220 100644
--- a/js/src/jit-test/tests/debug/Script-gc-02.js
+++ b/js/src/jit-test/tests/debug/Script-gc-02.js
@@ -10,5 +10,5 @@ assertEq(arr.length, 10);
gc();
for (var i = 0; i < arr.length; i++)
- assertEq(arr[i].lineCount, 1);
+ assertEq(arr[i].lineCount, 3);
diff --git a/js/src/jit-test/tests/debug/Script-gc-03.js b/js/src/jit-test/tests/debug/Script-gc-03.js
index b2cb70232..30c3e8dbc 100644
--- a/js/src/jit-test/tests/debug/Script-gc-03.js
+++ b/js/src/jit-test/tests/debug/Script-gc-03.js
@@ -10,6 +10,6 @@ assertEq(arr.length, 100);
gc(g);
for (var i = 0; i < arr.length; i++)
- assertEq(arr[i].lineCount, 1);
+ assertEq(arr[i].lineCount, 3);
gc();
diff --git a/js/src/jit-test/tests/debug/Script-sourceStart-04.js b/js/src/jit-test/tests/debug/Script-sourceStart-04.js
index c12e669bf..2aa382b7b 100644
--- a/js/src/jit-test/tests/debug/Script-sourceStart-04.js
+++ b/js/src/jit-test/tests/debug/Script-sourceStart-04.js
@@ -20,6 +20,6 @@ function test(string, range) {
}
test("eval('2 * 3')", [0, 5]);
-test("new Function('2 * 3')", [0, 5]);
-test("new Function('x', 'x * x')", [0, 5]);
+test("new Function('2 * 3')", [0, 12]);
+test("new Function('x', 'x * x')", [0, 13]);
assertEq(count, 6);
diff --git a/js/src/jit-test/tests/proxy/testWrapWithProtoIter.js b/js/src/jit-test/tests/proxy/testWrapWithProtoIter.js
new file mode 100644
index 000000000..c6854b206
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testWrapWithProtoIter.js
@@ -0,0 +1 @@
+[...wrapWithProto(new Int8Array(), new Int8Array())]
diff --git a/js/src/jit-test/tests/proxy/testWrapWithProtoTypedArray.js b/js/src/jit-test/tests/proxy/testWrapWithProtoTypedArray.js
new file mode 100644
index 000000000..1b805d30a
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testWrapWithProtoTypedArray.js
@@ -0,0 +1,19 @@
+let a = wrapWithProto(new Int8Array([1, 3, 5, 6, 9]), new Int8Array());
+
+assertEq([...a].toString(), "1,3,5,6,9");
+assertEq(a.every(e => e < 100), true);
+assertEq(a.filter(e => e % 2 == 1).toString(), "1,3,5,9");
+assertEq(a.find(e => e > 3), 5);
+assertEq(a.findIndex(e => e % 2 == 0), 3);
+assertEq(a.map(e => e * 10).toString(), "10,30,50,60,90");
+assertEq(a.reduce((a, b) => a + b, ""), "13569");
+assertEq(a.reduceRight((acc, e) => "(" + e + acc + ")", ""), "(1(3(5(6(9)))))");
+assertEq(a.some(e => e % 2 == 0), true);
+
+let s = "";
+assertEq(a.forEach(e => s += e), undefined);
+assertEq(s, "13569");
+
+a.sort((a, b) => b - a);
+assertEq(a.toString(), "9,6,5,3,1");
+
diff --git a/js/src/js.msg b/js/src/js.msg
index 2a818056f..8766bfbf5 100644
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -329,6 +329,7 @@ MSG_DEF(JSMSG_TOO_MANY_LOCALS, 0, JSEXN_SYNTAXERR, "too many local varia
MSG_DEF(JSMSG_TOO_MANY_YIELDS, 0, JSEXN_SYNTAXERR, "too many yield expressions")
MSG_DEF(JSMSG_TOUGH_BREAK, 0, JSEXN_SYNTAXERR, "unlabeled break must be inside loop or switch")
MSG_DEF(JSMSG_UNEXPECTED_TOKEN, 2, JSEXN_SYNTAXERR, "expected {0}, got {1}")
+MSG_DEF(JSMSG_UNEXPECTED_PARAMLIST_END,0, JSEXN_SYNTAXERR, "unexpected end of function parameter list")
MSG_DEF(JSMSG_UNNAMED_CLASS_STMT, 0, JSEXN_SYNTAXERR, "class statement requires a name")
MSG_DEF(JSMSG_UNNAMED_FUNCTION_STMT, 0, JSEXN_SYNTAXERR, "function statement requires a name")
MSG_DEF(JSMSG_UNTERMINATED_COMMENT, 0, JSEXN_SYNTAXERR, "unterminated comment")
diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
index ee9c61059..e6fc1f98b 100644
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -11,6 +11,7 @@
#include "jsapi.h"
#include "mozilla/FloatingPoint.h"
+#include "mozilla/Maybe.h"
#include "mozilla/PodOperations.h"
#include "mozilla/Sprintf.h"
@@ -107,6 +108,7 @@ using namespace js::gc;
using mozilla::Maybe;
using mozilla::PodCopy;
using mozilla::PodZero;
+using mozilla::Some;
using JS::AutoGCRooter;
using JS::ToInt32;
@@ -4232,15 +4234,15 @@ JS_GetFunctionScript(JSContext* cx, HandleFunction fun)
}
/*
- * enclosingScope is a static enclosing scope, if any (e.g. a WithScope). If
- * the enclosing scope is the global scope, this must be null.
+ * enclosingScope is a scope, if any (e.g. a WithScope). If the scope is the
+ * global scope, this must be null.
*
- * enclosingDynamicScope is a dynamic scope to use, if it's not the global.
+ * enclosingEnv is an environment to use, if it's not the global.
*/
static bool
CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
- const char* name, unsigned nargs, const char* const* argnames,
- SourceBufferHolder& srcBuf,
+ const char* name,
+ SourceBufferHolder& srcBuf, uint32_t parameterListEnd,
HandleObject enclosingEnv, HandleScope enclosingScope,
MutableHandleFunction fun)
{
@@ -4256,13 +4258,6 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
return false;
}
- Rooted<PropertyNameVector> formals(cx, PropertyNameVector(cx));
- for (unsigned i = 0; i < nargs; i++) {
- RootedAtom argAtom(cx, Atomize(cx, argnames[i], strlen(argnames[i])));
- if (!argAtom || !formals.append(argAtom->asPropertyName()))
- return false;
- }
-
fun.set(NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL, funAtom,
/* proto = */ nullptr,
gc::AllocKind::FUNCTION, TenuredObject,
@@ -4275,7 +4270,45 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
MOZ_ASSERT_IF(!IsGlobalLexicalEnvironment(enclosingEnv),
enclosingScope->hasOnChain(ScopeKind::NonSyntactic));
- if (!frontend::CompileFunctionBody(cx, fun, optionsArg, formals, srcBuf, enclosingScope))
+ if (!frontend::CompileStandaloneFunction(cx, fun, optionsArg, srcBuf,
+ Some(parameterListEnd), enclosingScope))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+static MOZ_MUST_USE bool
+BuildFunctionString(unsigned nargs, const char* const* argnames,
+ const SourceBufferHolder& srcBuf, StringBuffer* out,
+ uint32_t* parameterListEnd)
+{
+ MOZ_ASSERT(out);
+ MOZ_ASSERT(parameterListEnd);
+
+ if (!out->ensureTwoByteChars())
+ return false;
+ if (!out->append("("))
+ return false;
+ for (unsigned i = 0; i < nargs; i++) {
+ if (i != 0) {
+ if (!out->append(", "))
+ return false;
+ }
+ if (!out->append(argnames[i], strlen(argnames[i])))
+ return false;
+ }
+
+ // Remember the position of ")".
+ *parameterListEnd = out->length();
+ MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')');
+
+ if (!out->append(FunctionConstructorMedialSigils))
+ return false;
+ if (!out->append(srcBuf.get(), srcBuf.length()))
+ return false;
+ if (!out->append(FunctionConstructorFinalBrace))
return false;
return true;
@@ -4291,7 +4324,16 @@ JS::CompileFunction(JSContext* cx, AutoObjectVector& envChain,
RootedScope scope(cx);
if (!CreateNonSyntacticEnvironmentChain(cx, envChain, &env, &scope))
return false;
- return CompileFunction(cx, options, name, nargs, argnames, srcBuf, env, scope, fun);
+
+ uint32_t parameterListEnd;
+ StringBuffer funStr(cx);
+ if (!BuildFunctionString(nargs, argnames, srcBuf, &funStr, &parameterListEnd))
+ return false;
+
+ size_t newLen = funStr.length();
+ SourceBufferHolder newSrcBuf(funStr.stealChars(), newLen, SourceBufferHolder::GiveOwnership);
+
+ return CompileFunction(cx, options, name, newSrcBuf, parameterListEnd, env, scope, fun);
}
JS_PUBLIC_API(bool)
diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp
index c952441ad..1e1b76d5d 100644
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -12,6 +12,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/CheckedInt.h"
+#include "mozilla/Maybe.h"
#include "mozilla/PodOperations.h"
#include "mozilla/Range.h"
@@ -60,8 +61,10 @@ using namespace js::gc;
using namespace js::frontend;
using mozilla::ArrayLength;
+using mozilla::Maybe;
using mozilla::PodCopy;
using mozilla::RangedPtr;
+using mozilla::Some;
static bool
fun_enumerate(JSContext* cx, HandleObject obj)
@@ -985,19 +988,19 @@ js::FindBody(JSContext* cx, HandleFunction fun, HandleLinearString src, size_t*
}
JSString*
-js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
+js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
{
if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
return nullptr;
if (IsAsmJSModule(fun))
- return AsmJSModuleToString(cx, fun, !lambdaParen);
+ return AsmJSModuleToString(cx, fun, !prettyPrint);
if (IsAsmJSFunction(fun))
return AsmJSFunctionToString(cx, fun);
if (IsWrappedAsyncFunction(fun)) {
RootedFunction unwrapped(cx, GetUnwrappedAsyncFunction(fun));
- return FunctionToString(cx, unwrapped, lambdaParen);
+ return FunctionToString(cx, unwrapped, prettyPrint);
}
StringBuffer out(cx);
@@ -1023,11 +1026,10 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
bool funIsMethodOrNonArrowLambda = (fun->isLambda() && !fun->isArrow()) || fun->isMethod() ||
fun->isGetter() || fun->isSetter();
+ bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin();
// If we're not in pretty mode, put parentheses around lambda functions and methods.
- if (fun->isInterpreted() && !lambdaParen && funIsMethodOrNonArrowLambda &&
- !fun->isSelfHostedBuiltin())
- {
+ if (haveSource && !prettyPrint && funIsMethodOrNonArrowLambda) {
if (!out.append("("))
return nullptr;
}
@@ -1045,7 +1047,6 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
return nullptr;
}
- bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin();
if (haveSource && !script->scriptSource()->hasSourceData() &&
!JSScript::loadSource(cx, script->scriptSource(), &haveSource))
{
@@ -1056,54 +1057,10 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
if (!src)
return nullptr;
- // The source data for functions created by calling the Function
- // constructor is only the function's body. This depends on the fact,
- // asserted below, that in Function("function f() {}"), the inner
- // function's sourceStart points to the '(', not the 'f'.
- bool funCon = !fun->isArrow() &&
- script->sourceStart() == 0 &&
- script->sourceEnd() == script->scriptSource()->length() &&
- script->scriptSource()->argumentsNotIncluded();
-
- // Functions created with the constructor can't be arrow functions or
- // expression closures.
- MOZ_ASSERT_IF(funCon, !fun->isArrow());
- MOZ_ASSERT_IF(funCon, !fun->isExprBody());
- MOZ_ASSERT_IF(!funCon && !fun->isArrow(),
- src->length() > 0 && src->latin1OrTwoByteChar(0) == '(');
-
- bool buildBody = funCon;
- if (buildBody) {
- // This function was created with the Function constructor. We don't
- // have source for the arguments, so we have to generate that. Part
- // of bug 755821 should be cobbling the arguments passed into the
- // Function constructor into the source string.
- if (!out.append("("))
- return nullptr;
-
- // Fish out the argument names.
- MOZ_ASSERT(script->numArgs() == fun->nargs());
-
- BindingIter bi(script);
- for (unsigned i = 0; i < fun->nargs(); i++, bi++) {
- MOZ_ASSERT(bi.argumentSlot() == i);
- if (i && !out.append(", "))
- return nullptr;
- if (i == unsigned(fun->nargs() - 1) && fun->hasRest() && !out.append("..."))
- return nullptr;
- if (!out.append(bi.name()))
- return nullptr;
- }
- if (!out.append(") {\n"))
- return nullptr;
- }
if (!out.append(src))
return nullptr;
- if (buildBody) {
- if (!out.append("\n}"))
- return nullptr;
- }
- if (!lambdaParen && funIsMethodOrNonArrowLambda) {
+
+ if (!prettyPrint && funIsMethodOrNonArrowLambda) {
if (!out.append(")"))
return nullptr;
}
@@ -1114,8 +1071,6 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
{
return nullptr;
}
- if (!lambdaParen && fun->isLambda() && !fun->isArrow() && !out.append(")"))
- return nullptr;
} else {
MOZ_ASSERT(!fun->isExprBody());
@@ -1657,17 +1612,6 @@ fun_isGenerator(JSContext* cx, unsigned argc, Value* vp)
return true;
}
-/*
- * Report "malformed formal parameter" iff no illegal char or similar scanner
- * error was already reported.
- */
-static bool
-OnBadFormal(JSContext* cx)
-{
- JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_FORMAL);
- return false;
-}
-
const JSFunctionSpec js::function_methods[] = {
#if JS_HAS_TOSOURCE
JS_FN(js_toSource_str, fun_toSource, 0,0),
@@ -1681,13 +1625,12 @@ const JSFunctionSpec js::function_methods[] = {
JS_FS_END
};
+// ES 2017 draft rev 0f10dba4ad18de92d47d421f378233a2eae8f077 19.2.1.1.1.
static bool
-FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind generatorKind,
+FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generatorKind,
FunctionAsyncKind asyncKind)
{
- CallArgs args = CallArgsFromVp(argc, vp);
-
- /* Block this call if security callbacks forbid it. */
+ // Block this call if security callbacks forbid it.
Rooted<GlobalObject*> global(cx, &args.callee().global());
if (!GlobalObject::isRuntimeCodeGenEnabled(cx, global)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CSP_BLOCKED_FUNCTION);
@@ -1719,82 +1662,65 @@ FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind gener
introducerFilename = maybeScript->scriptSource()->introducerFilename();
CompileOptions options(cx);
+ // Use line 0 to make the function body starts from line 1.
options.setMutedErrors(mutedErrors)
- .setFileAndLine(filename, 1)
+ .setFileAndLine(filename, 0)
.setNoScriptRval(false)
.setIntroductionInfo(introducerFilename, introductionType, lineno, maybeScript, pcOffset);
- Vector<char16_t> paramStr(cx);
- RootedString bodyText(cx);
+ StringBuffer sb(cx);
- if (args.length() == 0) {
- bodyText = cx->names().empty;
- } else {
- // Collect the function-argument arguments into one string, separated
- // by commas, then make a tokenstream from that string, and scan it to
- // get the arguments. We need to throw the full scanner at the
- // problem because the argument string may contain comments, newlines,
- // destructuring arguments, and similar manner of insanities. ("I have
- // a feeling we're not in simple-comma-separated-parameters land any
- // more, Toto....")
- //
- // XXX It'd be better if the parser provided utility methods to parse
- // an argument list, and to parse a function body given a parameter
- // list. But our parser provides no such pleasant interface now.
- unsigned n = args.length() - 1;
+ if (!sb.append('('))
+ return false;
- // Convert the parameters-related arguments to strings, and determine
- // the length of the string containing the overall parameter list.
- mozilla::CheckedInt<uint32_t> paramStrLen = 0;
+ if (args.length() > 1) {
RootedString str(cx);
+
+ // Steps 5-6, 9.
+ unsigned n = args.length() - 1;
+
for (unsigned i = 0; i < n; i++) {
+ // Steps 9.a-b, 9.d.i-ii.
str = ToString<CanGC>(cx, args[i]);
if (!str)
return false;
- args[i].setString(str);
- paramStrLen += str->length();
- }
-
- // Tack in space for any combining commas.
- if (n > 0)
- paramStrLen += n - 1;
+ // Steps 9.b, 9.d.iii.
+ if (!sb.append(str))
+ return false;
- // Check for integer and string-size overflow.
- if (!paramStrLen.isValid() || paramStrLen.value() > JSString::MAX_LENGTH) {
- ReportAllocationOverflow(cx);
- return false;
+ if (i < args.length() - 2) {
+ // Step 9.d.iii.
+ if (!sb.append(", "))
+ return false;
+ }
}
+ }
- uint32_t paramsLen = paramStrLen.value();
+ // Remember the position of ")".
+ Maybe<uint32_t> parameterListEnd = Some(uint32_t(sb.length()));
+ MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')');
- // Fill a vector with the comma-joined arguments. Careful! This
- // string is *not* null-terminated!
- MOZ_ASSERT(paramStr.length() == 0);
- if (!paramStr.growBy(paramsLen)) {
- ReportOutOfMemory(cx);
- return false;
- }
-
- char16_t* cp = paramStr.begin();
- for (unsigned i = 0; i < n; i++) {
- JSLinearString* argLinear = args[i].toString()->ensureLinear(cx);
- if (!argLinear)
- return false;
+ if (!sb.append(FunctionConstructorMedialSigils))
+ return false;
- CopyChars(cp, *argLinear);
- cp += argLinear->length();
+ if (args.length() > 0) {
+ // Steps 7-8, 10.
+ RootedString body(cx, ToString<CanGC>(cx, args[args.length() - 1]));
+ if (!body || !sb.append(body))
+ return false;
+ }
- if (i + 1 < n)
- *cp++ = ',';
- }
+ if (!sb.append(FunctionConstructorFinalBrace))
+ return false;
- MOZ_ASSERT(cp == paramStr.end());
+ // The parser only accepts two byte strings.
+ if (!sb.ensureTwoByteChars())
+ return false;
- bodyText = ToString(cx, args[n]);
- if (!bodyText)
- return false;
- }
+ RootedString functionText(cx, sb.finishString());
+ if (!functionText)
+ return false;
/*
* NB: (new Function) is not lexically closed by its caller, it's just an
@@ -1803,18 +1729,23 @@ FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind gener
* and so would a call to f from another top-level's script or function.
*/
RootedAtom anonymousAtom(cx, cx->names().anonymous);
+
+ // Step 24.
RootedObject proto(cx);
- if (isStarGenerator) {
- // Unwrapped function of async function should use GeneratorFunction,
- // while wrapped function isn't generator.
+ if (!isAsync) {
+ if (!GetPrototypeFromCallableConstructor(cx, args, &proto))
+ return false;
+ }
+
+ // Step 4.d, use %Generator% as the fallback prototype.
+ // Also use %Generator% for the unwrapped function of async functions.
+ if (!proto && isStarGenerator) {
proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, global);
if (!proto)
return false;
- } else {
- if (!GetPrototypeFromCallableConstructor(cx, args, &proto))
- return false;
}
+ // Step 25-32 (reordered).
RootedObject globalLexical(cx, &global->lexicalEnvironment());
AllocKind allocKind = isAsync ? AllocKind::FUNCTION_EXTENDED : AllocKind::FUNCTION;
RootedFunction fun(cx, NewFunctionWithProto(cx, nullptr, 0,
@@ -1827,81 +1758,11 @@ FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind gener
if (!JSFunction::setTypeForScriptedFunction(cx, fun))
return false;
+ // Steps 2.a-b, 3.a-b, 4.a-b, 11-23.
AutoStableStringChars stableChars(cx);
- if (!stableChars.initTwoByte(cx, bodyText))
+ if (!stableChars.initTwoByte(cx, functionText))
return false;
- bool hasRest = false;
-
- Rooted<PropertyNameVector> formals(cx, PropertyNameVector(cx));
- if (args.length() > 1) {
- // Initialize a tokenstream to parse the new function's arguments. No
- // StrictModeGetter is needed because this TokenStream won't report any
- // strict mode errors. Strict mode errors that might be reported here
- // (duplicate argument names, etc.) will be detected when we compile
- // the function body.
- //
- // XXX Bug! We have to parse the body first to determine strictness.
- // We have to know strictness to parse arguments correctly, in case
- // arguments contains a strict mode violation. And we should be
- // using full-fledged arguments parsing here, in order to handle
- // destructuring and other exotic syntaxes.
- AutoKeepAtoms keepAtoms(cx->perThreadData);
- TokenStream ts(cx, options, paramStr.begin(), paramStr.length(),
- /* strictModeGetter = */ nullptr);
- bool yieldIsValidName = ts.versionNumber() < JSVERSION_1_7 && !isStarGenerator;
-
- // The argument string may be empty or contain no tokens.
- TokenKind tt;
- if (!ts.getToken(&tt))
- return false;
- if (tt != TOK_EOF) {
- while (true) {
- // Check that it's a name.
- if (hasRest) {
- ts.reportError(JSMSG_PARAMETER_AFTER_REST);
- return false;
- }
-
- if (tt == TOK_YIELD && yieldIsValidName)
- tt = TOK_NAME;
-
- if (tt != TOK_NAME) {
- if (tt == TOK_TRIPLEDOT) {
- hasRest = true;
- if (!ts.getToken(&tt))
- return false;
- if (tt == TOK_YIELD && yieldIsValidName)
- tt = TOK_NAME;
- if (tt != TOK_NAME) {
- ts.reportError(JSMSG_NO_REST_NAME);
- return false;
- }
- } else {
- return OnBadFormal(cx);
- }
- }
-
- if (!formals.append(ts.currentName()))
- return false;
-
- // Get the next token. Stop on end of stream. Otherwise
- // insist on a comma, get another name, and iterate.
- if (!ts.getToken(&tt))
- return false;
- if (tt == TOK_EOF)
- break;
- if (tt != TOK_COMMA)
- return OnBadFormal(cx);
- if (!ts.getToken(&tt))
- return false;
- }
- }
- }
-
- if (hasRest)
- fun->setHasRest();
-
mozilla::Range<const char16_t> chars = stableChars.twoByteRange();
SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller()
? SourceBufferHolder::GiveOwnership
@@ -1909,11 +1770,13 @@ FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind gener
bool ok;
SourceBufferHolder srcBuf(chars.begin().get(), chars.length(), ownership);
if (isAsync)
- ok = frontend::CompileAsyncFunctionBody(cx, &fun, options, formals, srcBuf);
+ ok = frontend::CompileStandaloneAsyncFunction(cx, &fun, options, srcBuf, parameterListEnd);
else if (isStarGenerator)
- ok = frontend::CompileStarGeneratorBody(cx, &fun, options, formals, srcBuf);
+ ok = frontend::CompileStandaloneGenerator(cx, &fun, options, srcBuf, parameterListEnd);
else
- ok = frontend::CompileFunctionBody(cx, &fun, options, formals, srcBuf);
+ ok = frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, parameterListEnd);
+
+ // Step 33.
args.rval().setObject(*fun);
return ok;
}
@@ -1921,24 +1784,47 @@ FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind gener
bool
js::Function(JSContext* cx, unsigned argc, Value* vp)
{
- return FunctionConstructor(cx, argc, vp, NotGenerator, SyncFunction);
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return FunctionConstructor(cx, args, NotGenerator, SyncFunction);
}
bool
js::Generator(JSContext* cx, unsigned argc, Value* vp)
{
- return FunctionConstructor(cx, argc, vp, StarGenerator, SyncFunction);
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return FunctionConstructor(cx, args, StarGenerator, SyncFunction);
}
bool
js::AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
- if (!FunctionConstructor(cx, argc, vp, StarGenerator, AsyncFunction))
+
+ // Save the callee before its reset in FunctionConstructor().
+ RootedObject newTarget(cx);
+ if (args.isConstructing())
+ newTarget = &args.newTarget().toObject();
+ else
+ newTarget = &args.callee();
+
+ if (!FunctionConstructor(cx, args, StarGenerator, AsyncFunction))
return false;
+ // ES2017, draft rev 0f10dba4ad18de92d47d421f378233a2eae8f077
+ // 19.2.1.1.1 Runtime Semantics: CreateDynamicFunction, step 24.
+ RootedObject proto(cx);
+ if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
+ return false;
+
+ // 19.2.1.1.1, step 4.d, use %AsyncFunctionPrototype% as the fallback.
+ if (!proto) {
+ proto = GlobalObject::getOrCreateAsyncFunctionPrototype(cx, cx->global());
+ if (!proto)
+ return false;
+ }
+
RootedFunction unwrapped(cx, &args.rval().toObject().as<JSFunction>());
- RootedObject wrapped(cx, WrapAsyncFunction(cx, unwrapped));
+ RootedObject wrapped(cx, WrapAsyncFunctionWithProto(cx, unwrapped, proto));
if (!wrapped)
return false;
diff --git a/js/src/jsfun.h b/js/src/jsfun.h
index ef4a603d0..88af5c22d 100644
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -28,6 +28,9 @@ static const uint32_t JSSLOT_BOUND_FUNCTION_TARGET = 2;
static const uint32_t JSSLOT_BOUND_FUNCTION_THIS = 3;
static const uint32_t JSSLOT_BOUND_FUNCTION_ARGS = 4;
+static const char FunctionConstructorMedialSigils[] = ") {\n";
+static const char FunctionConstructorFinalBrace[] = "\n}";
+
class JSFunction : public js::NativeObject
{
public:
@@ -816,7 +819,7 @@ JSFunction::getExtendedSlot(size_t which) const
namespace js {
-JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen);
+JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPring);
template<XDRMode mode>
bool
diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp
index 10821f26a..b568b4b30 100644
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1689,6 +1689,16 @@ ScriptSource::substringDontDeflate(JSContext* cx, size_t start, size_t stop)
return NewStringCopyNDontDeflate<CanGC>(cx, chars, len);
}
+JSFlatString*
+ScriptSource::functionBodyString(JSContext* cx)
+{
+ MOZ_ASSERT(isFunctionBody());
+
+ size_t start = parameterListEnd_ + (sizeof(FunctionConstructorMedialSigils) - 1);
+ size_t stop = length() - (sizeof(FunctionConstructorFinalBrace) - 1);
+ return substring(cx, start, stop);
+}
+
MOZ_MUST_USE bool
ScriptSource::setSource(ExclusiveContext* cx,
mozilla::UniquePtr<char16_t[], JS::FreePolicy>&& source,
@@ -1740,10 +1750,9 @@ ScriptSource::setCompressedSource(SharedImmutableString&& raw, size_t uncompress
bool
ScriptSource::setSourceCopy(ExclusiveContext* cx, SourceBufferHolder& srcBuf,
- bool argumentsNotIncluded, SourceCompressionTask* task)
+ SourceCompressionTask* task)
{
MOZ_ASSERT(!hasSourceData());
- argumentsNotIncluded_ = argumentsNotIncluded;
auto& cache = cx->zone()->runtimeFromAnyThread()->sharedImmutableStrings();
auto deduped = cache.getOrCreate(srcBuf.get(), srcBuf.length(), [&]() {
@@ -1940,16 +1949,6 @@ ScriptSource::performXDR(XDRState<mode>* xdr)
if (!xdr->codeUint32(&compressedLength))
return false;
- {
- uint8_t argumentsNotIncluded;
- if (mode == XDR_ENCODE)
- argumentsNotIncluded = argumentsNotIncluded_;
- if (!xdr->codeUint8(&argumentsNotIncluded))
- return false;
- if (mode == XDR_DECODE)
- argumentsNotIncluded_ = argumentsNotIncluded;
- }
-
size_t byteLen = compressedLength ? compressedLength : (len * sizeof(char16_t));
if (mode == XDR_DECODE) {
uint8_t* p = xdr->cx()->template pod_malloc<uint8_t>(Max<size_t>(byteLen, 1));
@@ -2074,7 +2073,8 @@ FormatIntroducedFilename(ExclusiveContext* cx, const char* filename, unsigned li
}
bool
-ScriptSource::initFromOptions(ExclusiveContext* cx, const ReadOnlyCompileOptions& options)
+ScriptSource::initFromOptions(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
+ Maybe<uint32_t> parameterListEnd)
{
MOZ_ASSERT(!filename_);
MOZ_ASSERT(!introducerFilename_);
@@ -2083,6 +2083,7 @@ ScriptSource::initFromOptions(ExclusiveContext* cx, const ReadOnlyCompileOptions
introductionType_ = options.introductionType;
setIntroductionOffset(options.introductionOffset);
+ parameterListEnd_ = parameterListEnd.isSome() ? parameterListEnd.value() : 0;
if (options.hasIntroductionInfo) {
MOZ_ASSERT(options.introductionType != nullptr);
diff --git a/js/src/jsscript.h b/js/src/jsscript.h
index bc8bda83d..ffd4b1e2e 100644
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -10,6 +10,7 @@
#define jsscript_h
#include "mozilla/Atomics.h"
+#include "mozilla/Maybe.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/PodOperations.h"
#include "mozilla/Variant.h"
@@ -399,6 +400,11 @@ class ScriptSource
// scripts.
uint32_t introductionOffset_;
+ // If this source is for Function constructor, the position of ")" after
+ // parameter list in the source. This is used to get function body.
+ // 0 for other cases.
+ uint32_t parameterListEnd_;
+
// If this ScriptSource was generated by a code-introduction mechanism such
// as |eval| or |new Function|, the debugger needs access to the "raw"
// filename of the top-level script that contains the eval-ing code. To
@@ -428,7 +434,6 @@ class ScriptSource
// demand. If sourceRetrievable_ and hasSourceData() are false, it is not
// possible to get source at all.
bool sourceRetrievable_:1;
- bool argumentsNotIncluded_:1;
bool hasIntroductionOffset_:1;
const char16_t* chunkChars(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& holder,
@@ -443,10 +448,10 @@ class ScriptSource
sourceMapURL_(nullptr),
mutedErrors_(false),
introductionOffset_(0),
+ parameterListEnd_(0),
introducerFilename_(nullptr),
introductionType_(nullptr),
sourceRetrievable_(false),
- argumentsNotIncluded_(false),
hasIntroductionOffset_(false)
{
}
@@ -461,10 +466,10 @@ class ScriptSource
if (--refs == 0)
js_delete(this);
}
- bool initFromOptions(ExclusiveContext* cx, const ReadOnlyCompileOptions& options);
+ bool initFromOptions(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
+ mozilla::Maybe<uint32_t> parameterListEnd = mozilla::Nothing());
bool setSourceCopy(ExclusiveContext* cx,
JS::SourceBufferHolder& srcBuf,
- bool argumentsNotIncluded,
SourceCompressionTask* tok);
void setSourceRetrievable() { sourceRetrievable_ = true; }
bool sourceRetrievable() const { return sourceRetrievable_; }
@@ -492,11 +497,6 @@ class ScriptSource
return data.match(LengthMatcher());
}
- bool argumentsNotIncluded() const {
- MOZ_ASSERT(hasSourceData());
- return argumentsNotIncluded_;
- }
-
// Return a string containing the chars starting at |begin| and ending at
// |begin + len|.
const char16_t* chars(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& asp,
@@ -504,6 +504,12 @@ class ScriptSource
JSFlatString* substring(JSContext* cx, size_t start, size_t stop);
JSFlatString* substringDontDeflate(JSContext* cx, size_t start, size_t stop);
+
+ bool isFunctionBody() {
+ return parameterListEnd_ != 0;
+ }
+ JSFlatString* functionBodyString(JSContext* cx);
+
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
JS::ScriptSourceInfo* info) const;
@@ -567,6 +573,10 @@ class ScriptSource
introductionOffset_ = offset;
hasIntroductionOffset_ = true;
}
+
+ uint32_t parameterListEnd() const {
+ return parameterListEnd_;
+ }
};
class ScriptSourceHolder
diff --git a/js/src/tests/Intl/Collator/construct-newtarget.js b/js/src/tests/Intl/Collator/construct-newtarget.js
new file mode 100644
index 000000000..5db1abf37
--- /dev/null
+++ b/js/src/tests/Intl/Collator/construct-newtarget.js
@@ -0,0 +1,81 @@
+// |reftest| skip-if(!this.hasOwnProperty("Intl"))
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+// Test subclassing %Intl.Collator% works correctly.
+class MyCollator extends Intl.Collator {}
+
+var obj = new MyCollator();
+assertEq(obj instanceof MyCollator, true);
+assertEq(obj instanceof Intl.Collator, true);
+assertEq(Object.getPrototypeOf(obj), MyCollator.prototype);
+
+obj = Reflect.construct(MyCollator, []);
+assertEq(obj instanceof MyCollator, true);
+assertEq(obj instanceof Intl.Collator, true);
+assertEq(Object.getPrototypeOf(obj), MyCollator.prototype);
+
+obj = Reflect.construct(MyCollator, [], MyCollator);
+assertEq(obj instanceof MyCollator, true);
+assertEq(obj instanceof Intl.Collator, true);
+assertEq(Object.getPrototypeOf(obj), MyCollator.prototype);
+
+obj = Reflect.construct(MyCollator, [], Intl.Collator);
+assertEq(obj instanceof MyCollator, false);
+assertEq(obj instanceof Intl.Collator, true);
+assertEq(Object.getPrototypeOf(obj), Intl.Collator.prototype);
+
+
+// Set a different constructor as NewTarget.
+obj = Reflect.construct(MyCollator, [], Array);
+assertEq(obj instanceof MyCollator, false);
+assertEq(obj instanceof Intl.Collator, false);
+assertEq(obj instanceof Array, true);
+assertEq(Object.getPrototypeOf(obj), Array.prototype);
+
+obj = Reflect.construct(Intl.Collator, [], Array);
+assertEq(obj instanceof Intl.Collator, false);
+assertEq(obj instanceof Array, true);
+assertEq(Object.getPrototypeOf(obj), Array.prototype);
+
+
+// The prototype defaults to %CollatorPrototype% if null.
+function NewTargetNullPrototype() {}
+NewTargetNullPrototype.prototype = null;
+
+obj = Reflect.construct(Intl.Collator, [], NewTargetNullPrototype);
+assertEq(obj instanceof Intl.Collator, true);
+assertEq(Object.getPrototypeOf(obj), Intl.Collator.prototype);
+
+obj = Reflect.construct(MyCollator, [], NewTargetNullPrototype);
+assertEq(obj instanceof MyCollator, false);
+assertEq(obj instanceof Intl.Collator, true);
+assertEq(Object.getPrototypeOf(obj), Intl.Collator.prototype);
+
+
+// "prototype" property is retrieved exactly once.
+var trapLog = [], getLog = [];
+var ProxiedConstructor = new Proxy(Intl.Collator, new Proxy({
+ get(target, propertyKey, receiver) {
+ getLog.push(propertyKey);
+ return Reflect.get(target, propertyKey, receiver);
+ }
+}, {
+ get(target, propertyKey, receiver) {
+ trapLog.push(propertyKey);
+ return Reflect.get(target, propertyKey, receiver);
+ }
+}));
+
+obj = Reflect.construct(Intl.Collator, [], ProxiedConstructor);
+assertEqArray(trapLog, ["get"]);
+assertEqArray(getLog, ["prototype"]);
+assertEq(obj instanceof Intl.Collator, true);
+assertEq(Object.getPrototypeOf(obj), Intl.Collator.prototype);
+
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/Intl/DateTimeFormat/construct-newtarget.js b/js/src/tests/Intl/DateTimeFormat/construct-newtarget.js
new file mode 100644
index 000000000..bbc08c79a
--- /dev/null
+++ b/js/src/tests/Intl/DateTimeFormat/construct-newtarget.js
@@ -0,0 +1,81 @@
+// |reftest| skip-if(!this.hasOwnProperty("Intl"))
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+// Test subclassing %Intl.DateTimeFormat% works correctly.
+class MyDateTimeFormat extends Intl.DateTimeFormat {}
+
+var obj = new MyDateTimeFormat();
+assertEq(obj instanceof MyDateTimeFormat, true);
+assertEq(obj instanceof Intl.DateTimeFormat, true);
+assertEq(Object.getPrototypeOf(obj), MyDateTimeFormat.prototype);
+
+obj = Reflect.construct(MyDateTimeFormat, []);
+assertEq(obj instanceof MyDateTimeFormat, true);
+assertEq(obj instanceof Intl.DateTimeFormat, true);
+assertEq(Object.getPrototypeOf(obj), MyDateTimeFormat.prototype);
+
+obj = Reflect.construct(MyDateTimeFormat, [], MyDateTimeFormat);
+assertEq(obj instanceof MyDateTimeFormat, true);
+assertEq(obj instanceof Intl.DateTimeFormat, true);
+assertEq(Object.getPrototypeOf(obj), MyDateTimeFormat.prototype);
+
+obj = Reflect.construct(MyDateTimeFormat, [], Intl.DateTimeFormat);
+assertEq(obj instanceof MyDateTimeFormat, false);
+assertEq(obj instanceof Intl.DateTimeFormat, true);
+assertEq(Object.getPrototypeOf(obj), Intl.DateTimeFormat.prototype);
+
+
+// Set a different constructor as NewTarget.
+obj = Reflect.construct(MyDateTimeFormat, [], Array);
+assertEq(obj instanceof MyDateTimeFormat, false);
+assertEq(obj instanceof Intl.DateTimeFormat, false);
+assertEq(obj instanceof Array, true);
+assertEq(Object.getPrototypeOf(obj), Array.prototype);
+
+obj = Reflect.construct(Intl.DateTimeFormat, [], Array);
+assertEq(obj instanceof Intl.DateTimeFormat, false);
+assertEq(obj instanceof Array, true);
+assertEq(Object.getPrototypeOf(obj), Array.prototype);
+
+
+// The prototype defaults to %DateTimeFormatPrototype% if null.
+function NewTargetNullPrototype() {}
+NewTargetNullPrototype.prototype = null;
+
+obj = Reflect.construct(Intl.DateTimeFormat, [], NewTargetNullPrototype);
+assertEq(obj instanceof Intl.DateTimeFormat, true);
+assertEq(Object.getPrototypeOf(obj), Intl.DateTimeFormat.prototype);
+
+obj = Reflect.construct(MyDateTimeFormat, [], NewTargetNullPrototype);
+assertEq(obj instanceof MyDateTimeFormat, false);
+assertEq(obj instanceof Intl.DateTimeFormat, true);
+assertEq(Object.getPrototypeOf(obj), Intl.DateTimeFormat.prototype);
+
+
+// "prototype" property is retrieved exactly once.
+var trapLog = [], getLog = [];
+var ProxiedConstructor = new Proxy(Intl.DateTimeFormat, new Proxy({
+ get(target, propertyKey, receiver) {
+ getLog.push(propertyKey);
+ return Reflect.get(target, propertyKey, receiver);
+ }
+}, {
+ get(target, propertyKey, receiver) {
+ trapLog.push(propertyKey);
+ return Reflect.get(target, propertyKey, receiver);
+ }
+}));
+
+obj = Reflect.construct(Intl.DateTimeFormat, [], ProxiedConstructor);
+assertEqArray(trapLog, ["get"]);
+assertEqArray(getLog, ["prototype"]);
+assertEq(obj instanceof Intl.DateTimeFormat, true);
+assertEq(Object.getPrototypeOf(obj), Intl.DateTimeFormat.prototype);
+
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/Intl/NumberFormat/construct-newtarget.js b/js/src/tests/Intl/NumberFormat/construct-newtarget.js
new file mode 100644
index 000000000..0053b2737
--- /dev/null
+++ b/js/src/tests/Intl/NumberFormat/construct-newtarget.js
@@ -0,0 +1,81 @@
+// |reftest| skip-if(!this.hasOwnProperty("Intl"))
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+// Test subclassing %Intl.NumberFormat% works correctly.
+class MyNumberFormat extends Intl.NumberFormat {}
+
+var obj = new MyNumberFormat();
+assertEq(obj instanceof MyNumberFormat, true);
+assertEq(obj instanceof Intl.NumberFormat, true);
+assertEq(Object.getPrototypeOf(obj), MyNumberFormat.prototype);
+
+obj = Reflect.construct(MyNumberFormat, []);
+assertEq(obj instanceof MyNumberFormat, true);
+assertEq(obj instanceof Intl.NumberFormat, true);
+assertEq(Object.getPrototypeOf(obj), MyNumberFormat.prototype);
+
+obj = Reflect.construct(MyNumberFormat, [], MyNumberFormat);
+assertEq(obj instanceof MyNumberFormat, true);
+assertEq(obj instanceof Intl.NumberFormat, true);
+assertEq(Object.getPrototypeOf(obj), MyNumberFormat.prototype);
+
+obj = Reflect.construct(MyNumberFormat, [], Intl.NumberFormat);
+assertEq(obj instanceof MyNumberFormat, false);
+assertEq(obj instanceof Intl.NumberFormat, true);
+assertEq(Object.getPrototypeOf(obj), Intl.NumberFormat.prototype);
+
+
+// Set a different constructor as NewTarget.
+obj = Reflect.construct(MyNumberFormat, [], Array);
+assertEq(obj instanceof MyNumberFormat, false);
+assertEq(obj instanceof Intl.NumberFormat, false);
+assertEq(obj instanceof Array, true);
+assertEq(Object.getPrototypeOf(obj), Array.prototype);
+
+obj = Reflect.construct(Intl.NumberFormat, [], Array);
+assertEq(obj instanceof Intl.NumberFormat, false);
+assertEq(obj instanceof Array, true);
+assertEq(Object.getPrototypeOf(obj), Array.prototype);
+
+
+// The prototype defaults to %NumberFormatPrototype% if null.
+function NewTargetNullPrototype() {}
+NewTargetNullPrototype.prototype = null;
+
+obj = Reflect.construct(Intl.NumberFormat, [], NewTargetNullPrototype);
+assertEq(obj instanceof Intl.NumberFormat, true);
+assertEq(Object.getPrototypeOf(obj), Intl.NumberFormat.prototype);
+
+obj = Reflect.construct(MyNumberFormat, [], NewTargetNullPrototype);
+assertEq(obj instanceof MyNumberFormat, false);
+assertEq(obj instanceof Intl.NumberFormat, true);
+assertEq(Object.getPrototypeOf(obj), Intl.NumberFormat.prototype);
+
+
+// "prototype" property is retrieved exactly once.
+var trapLog = [], getLog = [];
+var ProxiedConstructor = new Proxy(Intl.NumberFormat, new Proxy({
+ get(target, propertyKey, receiver) {
+ getLog.push(propertyKey);
+ return Reflect.get(target, propertyKey, receiver);
+ }
+}, {
+ get(target, propertyKey, receiver) {
+ trapLog.push(propertyKey);
+ return Reflect.get(target, propertyKey, receiver);
+ }
+}));
+
+obj = Reflect.construct(Intl.NumberFormat, [], ProxiedConstructor);
+assertEqArray(trapLog, ["get"]);
+assertEqArray(getLog, ["prototype"]);
+assertEq(obj instanceof Intl.NumberFormat, true);
+assertEq(Object.getPrototypeOf(obj), Intl.NumberFormat.prototype);
+
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/ecma_2017/AsyncFunctions/construct-newtarget.js b/js/src/tests/ecma_2017/AsyncFunctions/construct-newtarget.js
new file mode 100644
index 000000000..7d75d0c93
--- /dev/null
+++ b/js/src/tests/ecma_2017/AsyncFunctions/construct-newtarget.js
@@ -0,0 +1,79 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const AsyncFunction = async function(){}.constructor;
+
+
+// Test subclassing %AsyncFunction% works correctly.
+class MyAsync extends AsyncFunction {}
+
+var fn = new MyAsync();
+assertEq(fn instanceof MyAsync, true);
+assertEq(fn instanceof AsyncFunction, true);
+assertEq(Object.getPrototypeOf(fn), MyAsync.prototype);
+
+fn = Reflect.construct(MyAsync, []);
+assertEq(fn instanceof MyAsync, true);
+assertEq(fn instanceof AsyncFunction, true);
+assertEq(Object.getPrototypeOf(fn), MyAsync.prototype);
+
+fn = Reflect.construct(MyAsync, [], MyAsync);
+assertEq(fn instanceof MyAsync, true);
+assertEq(fn instanceof AsyncFunction, true);
+assertEq(Object.getPrototypeOf(fn), MyAsync.prototype);
+
+fn = Reflect.construct(MyAsync, [], AsyncFunction);
+assertEq(fn instanceof MyAsync, false);
+assertEq(fn instanceof AsyncFunction, true);
+assertEq(Object.getPrototypeOf(fn), AsyncFunction.prototype);
+
+
+// Set a different constructor as NewTarget.
+fn = Reflect.construct(MyAsync, [], Array);
+assertEq(fn instanceof MyAsync, false);
+assertEq(fn instanceof AsyncFunction, false);
+assertEq(Object.getPrototypeOf(fn), Array.prototype);
+
+fn = Reflect.construct(AsyncFunction, [], Array);
+assertEq(fn instanceof AsyncFunction, false);
+assertEq(Object.getPrototypeOf(fn), Array.prototype);
+
+
+// The prototype defaults to %AsyncFunctionPrototype% if null.
+function NewTargetNullPrototype() {}
+NewTargetNullPrototype.prototype = null;
+
+fn = Reflect.construct(AsyncFunction, [], NewTargetNullPrototype);
+assertEq(fn instanceof AsyncFunction, true);
+assertEq(Object.getPrototypeOf(fn), AsyncFunction.prototype);
+
+fn = Reflect.construct(MyAsync, [], NewTargetNullPrototype);
+assertEq(fn instanceof MyAsync, false);
+assertEq(fn instanceof AsyncFunction, true);
+assertEq(Object.getPrototypeOf(fn), AsyncFunction.prototype);
+
+
+// "prototype" property is retrieved exactly once.
+var trapLog = [], getLog = [];
+var ProxiedConstructor = new Proxy(AsyncFunction, new Proxy({
+ get(target, propertyKey, receiver) {
+ getLog.push(propertyKey);
+ return Reflect.get(target, propertyKey, receiver);
+ }
+}, {
+ get(target, propertyKey, receiver) {
+ trapLog.push(propertyKey);
+ return Reflect.get(target, propertyKey, receiver);
+ }
+}));
+
+fn = Reflect.construct(AsyncFunction, [], ProxiedConstructor);
+assertEqArray(trapLog, ["get"]);
+assertEqArray(getLog, ["prototype"]);
+assertEq(fn instanceof AsyncFunction, true);
+assertEq(Object.getPrototypeOf(fn), AsyncFunction.prototype);
+
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/ecma_2017/AsyncFunctions/subclass.js b/js/src/tests/ecma_2017/AsyncFunctions/subclass.js
new file mode 100644
index 000000000..da20ab19b
--- /dev/null
+++ b/js/src/tests/ecma_2017/AsyncFunctions/subclass.js
@@ -0,0 +1,31 @@
+// |reftest| skip-if(!xulRuntime.shell) -- needs drainJobQueue
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const AsyncFunction = async function(){}.constructor;
+
+class MyAsync extends AsyncFunction {}
+
+// MyGen inherits from %AsyncFunction%.
+assertEq(Object.getPrototypeOf(MyAsync), AsyncFunction);
+
+// MyGen.prototype inherits from %AsyncFunctionPrototype%.
+assertEq(Object.getPrototypeOf(MyAsync.prototype), AsyncFunction.prototype);
+
+var fn = new MyAsync("return await 'ok';");
+
+// fn inherits from MyAsync.prototype.
+assertEq(Object.getPrototypeOf(fn), MyAsync.prototype);
+
+// Ensure the new async function can be executed.
+var promise = fn();
+
+// promise inherits from %Promise.prototype%.
+assertEq(Object.getPrototypeOf(promise), Promise.prototype);
+
+// Computes the expected result.
+assertEventuallyEq(promise, "ok");
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/ecma_5/Function/arguments-caller-callee.js b/js/src/tests/ecma_5/Function/arguments-caller-callee.js
index 3eda27b49..57efd9eb9 100644
--- a/js/src/tests/ecma_5/Function/arguments-caller-callee.js
+++ b/js/src/tests/ecma_5/Function/arguments-caller-callee.js
@@ -5,7 +5,8 @@
var gTestfile = 'arguments-caller-callee.js';
var BUGNUMBER = 514563;
-var summary = "arguments.caller and arguments.callee are poison pills in ES5";
+var summary = "arguments.caller and arguments.callee are poison pills in ES5, " +
+ "later changed in ES2017 to only poison pill arguments.callee.";
print(BUGNUMBER + ": " + summary);
@@ -31,7 +32,7 @@ function expectTypeError(fun)
}
function bar() { "use strict"; return arguments; }
-expectTypeError(function barCaller() { bar().caller; });
+assertEq(bar().caller, undefined); // No error when accessing arguments.caller in ES2017+
expectTypeError(function barCallee() { bar().callee; });
function baz() { return arguments; }
@@ -41,15 +42,12 @@ assertEq(baz().callee, baz);
// accessor identity
function strictMode() { "use strict"; return arguments; }
-var canonicalTTE = Object.getOwnPropertyDescriptor(strictMode(), "caller").get;
+var canonicalTTE = Object.getOwnPropertyDescriptor(strictMode(), "callee").get;
var args = strictMode();
var argsCaller = Object.getOwnPropertyDescriptor(args, "caller");
-assertEq("get" in argsCaller, true);
-assertEq("set" in argsCaller, true);
-assertEq(argsCaller.get, canonicalTTE);
-assertEq(argsCaller.set, canonicalTTE);
+assertEq(argsCaller, undefined);
var argsCallee = Object.getOwnPropertyDescriptor(args, "callee");
assertEq("get" in argsCallee, true);
diff --git a/js/src/tests/ecma_5/Function/arguments-property-attributes.js b/js/src/tests/ecma_5/Function/arguments-property-attributes.js
index 994b97ca4..f50c1e6da 100644
--- a/js/src/tests/ecma_5/Function/arguments-property-attributes.js
+++ b/js/src/tests/ecma_5/Function/arguments-property-attributes.js
@@ -56,7 +56,7 @@ var sa = strictArgs(0, 1);
var strictArgProps = Object.getOwnPropertyNames(sa).sort();
assertEq(strictArgProps.indexOf("callee") >= 0, true);
-assertEq(strictArgProps.indexOf("caller") >= 0, true);
+assertEq(strictArgProps.indexOf("caller") >= 0, false);
assertEq(strictArgProps.indexOf("0") >= 0, true);
assertEq(strictArgProps.indexOf("1") >= 0, true);
assertEq(strictArgProps.indexOf("length") >= 0, true);
@@ -69,11 +69,7 @@ assertEq(strictCalleeDesc.enumerable, false);
assertEq(strictCalleeDesc.configurable, false);
var strictCallerDesc = Object.getOwnPropertyDescriptor(sa, "caller");
-assertEq(typeof strictCallerDesc.get, "function");
-assertEq(typeof strictCallerDesc.set, "function");
-assertEq(strictCallerDesc.get, strictCallerDesc.set);
-assertEq(strictCallerDesc.enumerable, false);
-assertEq(strictCallerDesc.configurable, false);
+assertEq(strictCallerDesc, undefined);
var strictZeroDesc = Object.getOwnPropertyDescriptor(sa, "0");
assertEq(strictZeroDesc.value, 0);
diff --git a/js/src/tests/ecma_6/Function/invalid-parameter-list.js b/js/src/tests/ecma_6/Function/invalid-parameter-list.js
new file mode 100644
index 000000000..8aae89ef1
--- /dev/null
+++ b/js/src/tests/ecma_6/Function/invalid-parameter-list.js
@@ -0,0 +1,27 @@
+// This constructor behaves like `Function` without checking
+// if the parameter list end is at the expected position.
+// We use this to make sure that the tests we use are otherwise
+// syntactically correct.
+function DumpFunction(...args) {
+ let code = "function anonymous(";
+ code += args.slice(0, -1).join(", ");
+ code += ") {\n";
+ code += args[args.length -1];
+ code += "\n}";
+ eval(code);
+}
+
+const tests = [
+ ["/*", "*/) {"],
+ ["//", ") {"],
+ ["a = `", "` ) {"],
+ [") { var x = function (", "} "],
+ ["x = function (", "}) {"]
+];
+
+for (const test of tests) {
+ DumpFunction(...test);
+ assertThrowsInstanceOf(() => new Function(...test), SyntaxError);
+}
+
+reportCompare(0, 0, 'ok');
diff --git a/js/src/tests/ecma_6/Generators/construct-newtarget.js b/js/src/tests/ecma_6/Generators/construct-newtarget.js
new file mode 100644
index 000000000..f2087852b
--- /dev/null
+++ b/js/src/tests/ecma_6/Generators/construct-newtarget.js
@@ -0,0 +1,79 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const GeneratorFunction = function*(){}.constructor;
+
+
+// Test subclassing %GeneratorFunction% works correctly.
+class MyGenerator extends GeneratorFunction {}
+
+var fn = new MyGenerator();
+assertEq(fn instanceof MyGenerator, true);
+assertEq(fn instanceof GeneratorFunction, true);
+assertEq(Object.getPrototypeOf(fn), MyGenerator.prototype);
+
+fn = Reflect.construct(MyGenerator, []);
+assertEq(fn instanceof MyGenerator, true);
+assertEq(fn instanceof GeneratorFunction, true);
+assertEq(Object.getPrototypeOf(fn), MyGenerator.prototype);
+
+fn = Reflect.construct(MyGenerator, [], MyGenerator);
+assertEq(fn instanceof MyGenerator, true);
+assertEq(fn instanceof GeneratorFunction, true);
+assertEq(Object.getPrototypeOf(fn), MyGenerator.prototype);
+
+fn = Reflect.construct(MyGenerator, [], GeneratorFunction);
+assertEq(fn instanceof MyGenerator, false);
+assertEq(fn instanceof GeneratorFunction, true);
+assertEq(Object.getPrototypeOf(fn), GeneratorFunction.prototype);
+
+
+// Set a different constructor as NewTarget.
+fn = Reflect.construct(MyGenerator, [], Array);
+assertEq(fn instanceof MyGenerator, false);
+assertEq(fn instanceof GeneratorFunction, false);
+assertEq(Object.getPrototypeOf(fn), Array.prototype);
+
+fn = Reflect.construct(GeneratorFunction, [], Array);
+assertEq(fn instanceof GeneratorFunction, false);
+assertEq(Object.getPrototypeOf(fn), Array.prototype);
+
+
+// The prototype defaults to %GeneratorFunctionPrototype% if null.
+function NewTargetNullPrototype() {}
+NewTargetNullPrototype.prototype = null;
+
+fn = Reflect.construct(GeneratorFunction, [], NewTargetNullPrototype);
+assertEq(fn instanceof GeneratorFunction, true);
+assertEq(Object.getPrototypeOf(fn), GeneratorFunction.prototype);
+
+fn = Reflect.construct(MyGenerator, [], NewTargetNullPrototype);
+assertEq(fn instanceof MyGenerator, false);
+assertEq(fn instanceof GeneratorFunction, true);
+assertEq(Object.getPrototypeOf(fn), GeneratorFunction.prototype);
+
+
+// "prototype" property is retrieved exactly once.
+var trapLog = [], getLog = [];
+var ProxiedConstructor = new Proxy(GeneratorFunction, new Proxy({
+ get(target, propertyKey, receiver) {
+ getLog.push(propertyKey);
+ return Reflect.get(target, propertyKey, receiver);
+ }
+}, {
+ get(target, propertyKey, receiver) {
+ trapLog.push(propertyKey);
+ return Reflect.get(target, propertyKey, receiver);
+ }
+}));
+
+fn = Reflect.construct(GeneratorFunction, [], ProxiedConstructor);
+assertEqArray(trapLog, ["get"]);
+assertEqArray(getLog, ["prototype"]);
+assertEq(fn instanceof GeneratorFunction, true);
+assertEq(Object.getPrototypeOf(fn), GeneratorFunction.prototype);
+
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/ecma_6/Generators/subclass.js b/js/src/tests/ecma_6/Generators/subclass.js
new file mode 100644
index 000000000..f93f4df4d
--- /dev/null
+++ b/js/src/tests/ecma_6/Generators/subclass.js
@@ -0,0 +1,33 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const GeneratorFunction = function*(){}.constructor;
+
+class MyGen extends GeneratorFunction {}
+
+// MyGen inherits from %GeneratorFunction%.
+assertEq(Object.getPrototypeOf(MyGen), GeneratorFunction);
+
+// MyGen.prototype inherits from %Generator%.
+assertEq(Object.getPrototypeOf(MyGen.prototype), GeneratorFunction.prototype);
+
+var fn = new MyGen("yield* [1, 2, 3]");
+
+// fn inherits from MyGen.prototype.
+assertEq(Object.getPrototypeOf(fn), MyGen.prototype);
+
+// fn.prototype inherits from %GeneratorPrototype%.
+assertEq(Object.getPrototypeOf(fn.prototype), GeneratorFunction.prototype.prototype);
+
+// Ensure the new generator function can be executed.
+var it = fn();
+
+// it inherits from fn.prototype.
+assertEq(Object.getPrototypeOf(it), fn.prototype);
+
+// Computes the expected result.
+assertEqArray([...it], [1, 2, 3]);
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/ecma_6/Syntax/identifiers-with-extended-unicode-escape.js b/js/src/tests/ecma_6/Syntax/identifiers-with-extended-unicode-escape.js
index 8e0a05fb5..e4b5f4602 100644
--- a/js/src/tests/ecma_6/Syntax/identifiers-with-extended-unicode-escape.js
+++ b/js/src/tests/ecma_6/Syntax/identifiers-with-extended-unicode-escape.js
@@ -98,7 +98,7 @@ const otherIdContinue = [
0x19DA, // NEW TAI LUE THAM DIGIT ONE, Gc=No
];
-for (let ident of [...idStart, ...otherIdStart]) {
+for (let ident of [...idStart, ...otherIdStart, ...idStartSupplemental]) {
for (let count of leadingZeros) {
let zeros = "0".repeat(count);
eval(`
@@ -108,20 +108,13 @@ for (let ident of [...idStart, ...otherIdStart]) {
}
}
-// Move this to the loop above when Bug 1197230 is fixed.
-for (let ident of [...idStartSupplemental]) {
- for (let zeros of leadingZeros) {
- assertThrowsInstanceOf(() => eval(`\\u{${zeros}${ident.toString(16)}}`), SyntaxError);
- }
-}
-
for (let ident of [...idContinue, ...idContinueSupplemental, ...otherIdContinue]) {
for (let zeros of leadingZeros) {
assertThrowsInstanceOf(() => eval(`\\u{${zeros}${ident.toString(16)}}`), SyntaxError);
}
}
-for (let ident of [...idStart, ...otherIdStart, ...idContinue, ...otherIdContinue]) {
+for (let ident of [...idStart, ...otherIdStart, ...idContinue, ...otherIdContinue, ...idStartSupplemental, ...idContinueSupplemental]) {
for (let zeros of leadingZeros) {
eval(`
let A\\u{${zeros}${ident.toString(16)}} = 123;
@@ -130,13 +123,6 @@ for (let ident of [...idStart, ...otherIdStart, ...idContinue, ...otherIdContinu
}
}
-// Move this to the loop above when Bug 1197230 is fixed.
-for (let ident of [...idStartSupplemental, ...idContinueSupplemental]) {
- for (let zeros of leadingZeros) {
- assertThrowsInstanceOf(() => eval(`\\u{${zeros}${ident.toString(16)}}`), SyntaxError);
- }
-}
-
const notIdentifiers = [
0x0000, // NULL, Gc=Cc
diff --git a/js/src/tests/jstests.list b/js/src/tests/jstests.list
index a0f2f08bd..1e23a3da3 100644
--- a/js/src/tests/jstests.list
+++ b/js/src/tests/jstests.list
@@ -46,6 +46,16 @@ skip script test262/ch09/9.3/9.3.1/S9.3.1_A2.js
skip script test262/ch09/9.3/9.3.1/S9.3.1_A3_T2.js
skip script test262/ch09/9.3/9.3.1/S9.3.1_A3_T1.js
+# ES2017 removed the strict arguments poison pill for the "caller" property
+# (bug 1324208).
+skip script test262/ch13/13.2/S13.2.3_A1.js
+skip script test262/ch10/10.6/10.6-14-1-s.js
+skip script test262/ch10/10.6/10.6-13-b-3-s.js
+skip script test262/ch10/10.6/10.6-14-b-1-s.js
+skip script test262/ch10/10.6/10.6-14-b-4-s.js
+skip script test262/ch10/10.6/10.6-13-b-1-s.js
+skip script test262/ch10/10.6/10.6-13-b-2-s.js
+
#######################################################################
# Tests disabled due to jstest limitations wrt imported test262 tests #
#######################################################################
diff --git a/js/src/vm/ArgumentsObject.cpp b/js/src/vm/ArgumentsObject.cpp
index d01121ef0..717aa1050 100644
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -676,7 +676,7 @@ UnmappedArgumentsObject::obj_resolve(JSContext* cx, HandleObject obj, HandleId i
if (argsobj->hasOverriddenLength())
return true;
} else {
- if (!JSID_IS_ATOM(id, cx->names().callee) && !JSID_IS_ATOM(id, cx->names().caller))
+ if (!JSID_IS_ATOM(id, cx->names().callee))
return true;
attrs = JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED;
@@ -709,10 +709,6 @@ UnmappedArgumentsObject::obj_enumerate(JSContext* cx, HandleObject obj)
if (!HasProperty(cx, argsobj, id, &found))
return false;
- id = NameToId(cx->names().caller);
- if (!HasProperty(cx, argsobj, id, &found))
- return false;
-
id = SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator);
if (!HasProperty(cx, argsobj, id, &found))
return false;
diff --git a/js/src/vm/AsyncFunction.cpp b/js/src/vm/AsyncFunction.cpp
index bd0b4f32a..1e0c7d7c2 100644
--- a/js/src/vm/AsyncFunction.cpp
+++ b/js/src/vm/AsyncFunction.cpp
@@ -107,18 +107,15 @@ WrappedAsyncFunction(JSContext* cx, unsigned argc, Value* vp)
// the async function's body, replacing `await` with `yield`. `wrapped` is a
// function that is visible to the outside, and handles yielded values.
JSObject*
-js::WrapAsyncFunction(JSContext* cx, HandleFunction unwrapped)
+js::WrapAsyncFunctionWithProto(JSContext* cx, HandleFunction unwrapped, HandleObject proto)
{
MOZ_ASSERT(unwrapped->isStarGenerator());
+ MOZ_ASSERT(proto, "We need an explicit prototype to avoid the default"
+ "%FunctionPrototype% fallback in NewFunctionWithProto().");
// Create a new function with AsyncFunctionPrototype, reusing the name and
// the length of `unwrapped`.
- // Step 1.
- RootedObject proto(cx, GlobalObject::getOrCreateAsyncFunctionPrototype(cx, cx->global()));
- if (!proto)
- return nullptr;
-
RootedAtom funName(cx, unwrapped->name());
uint16_t length;
if (!unwrapped->getLength(cx, &length))
@@ -141,6 +138,16 @@ js::WrapAsyncFunction(JSContext* cx, HandleFunction unwrapped)
return wrapped;
}
+JSObject*
+js::WrapAsyncFunction(JSContext* cx, HandleFunction unwrapped)
+{
+ RootedObject proto(cx, GlobalObject::getOrCreateAsyncFunctionPrototype(cx, cx->global()));
+ if (!proto)
+ return nullptr;
+
+ return WrapAsyncFunctionWithProto(cx, unwrapped, proto);
+}
+
enum class ResumeKind {
Normal,
Throw
diff --git a/js/src/vm/AsyncFunction.h b/js/src/vm/AsyncFunction.h
index ddf81a177..d7f2c1311 100644
--- a/js/src/vm/AsyncFunction.h
+++ b/js/src/vm/AsyncFunction.h
@@ -22,6 +22,9 @@ bool
IsWrappedAsyncFunction(JSFunction* fun);
JSObject*
+WrapAsyncFunctionWithProto(JSContext* cx, HandleFunction unwrapped, HandleObject proto);
+
+JSObject*
WrapAsyncFunction(JSContext* cx, HandleFunction unwrapped);
MOZ_MUST_USE bool
diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp
index b6bc7d62a..4d181545f 100644
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -6890,8 +6890,13 @@ class DebuggerSourceGetTextMatcher
bool hasSourceData = ss->hasSourceData();
if (!ss->hasSourceData() && !JSScript::loadSource(cx_, ss, &hasSourceData))
return nullptr;
- return hasSourceData ? ss->substring(cx_, 0, ss->length())
- : NewStringCopyZ<CanGC>(cx_, "[no source]");
+ if (!hasSourceData)
+ return NewStringCopyZ<CanGC>(cx_, "[no source]");
+
+ if (ss->isFunctionBody())
+ return ss->functionBodyString(cx_);
+
+ return ss->substring(cx_, 0, ss->length());
}
ReturnType match(Handle<WasmInstanceObject*> wasmInstance) {
diff --git a/js/src/vm/Unicode.cpp b/js/src/vm/Unicode.cpp
index f4acf8f31..82541c231 100644
--- a/js/src/vm/Unicode.cpp
+++ b/js/src/vm/Unicode.cpp
@@ -1748,3 +1748,882 @@ const uint8_t unicode::folding_index2[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
+bool
+js::unicode::IsIdentifierStartNonBMP(uint32_t codePoint)
+{
+ if (codePoint >= 0x10000 && codePoint <= 0x1000b)
+ return true;
+ if (codePoint >= 0x1000d && codePoint <= 0x10026)
+ return true;
+ if (codePoint >= 0x10028 && codePoint <= 0x1003a)
+ return true;
+ if (codePoint >= 0x1003c && codePoint <= 0x1003d)
+ return true;
+ if (codePoint >= 0x1003f && codePoint <= 0x1004d)
+ return true;
+ if (codePoint >= 0x10050 && codePoint <= 0x1005d)
+ return true;
+ if (codePoint >= 0x10080 && codePoint <= 0x100fa)
+ return true;
+ if (codePoint >= 0x10140 && codePoint <= 0x10174)
+ return true;
+ if (codePoint >= 0x10280 && codePoint <= 0x1029c)
+ return true;
+ if (codePoint >= 0x102a0 && codePoint <= 0x102d0)
+ return true;
+ if (codePoint >= 0x10300 && codePoint <= 0x1031f)
+ return true;
+ if (codePoint >= 0x10330 && codePoint <= 0x1034a)
+ return true;
+ if (codePoint >= 0x10350 && codePoint <= 0x10375)
+ return true;
+ if (codePoint >= 0x10380 && codePoint <= 0x1039d)
+ return true;
+ if (codePoint >= 0x103a0 && codePoint <= 0x103c3)
+ return true;
+ if (codePoint >= 0x103c8 && codePoint <= 0x103cf)
+ return true;
+ if (codePoint >= 0x103d1 && codePoint <= 0x103d5)
+ return true;
+ if (codePoint >= 0x10400 && codePoint <= 0x1049d)
+ return true;
+ if (codePoint >= 0x104b0 && codePoint <= 0x104d3)
+ return true;
+ if (codePoint >= 0x104d8 && codePoint <= 0x104fb)
+ return true;
+ if (codePoint >= 0x10500 && codePoint <= 0x10527)
+ return true;
+ if (codePoint >= 0x10530 && codePoint <= 0x10563)
+ return true;
+ if (codePoint >= 0x10600 && codePoint <= 0x10736)
+ return true;
+ if (codePoint >= 0x10740 && codePoint <= 0x10755)
+ return true;
+ if (codePoint >= 0x10760 && codePoint <= 0x10767)
+ return true;
+ if (codePoint >= 0x10800 && codePoint <= 0x10805)
+ return true;
+ if (codePoint >= 0x10808 && codePoint <= 0x10808)
+ return true;
+ if (codePoint >= 0x1080a && codePoint <= 0x10835)
+ return true;
+ if (codePoint >= 0x10837 && codePoint <= 0x10838)
+ return true;
+ if (codePoint >= 0x1083c && codePoint <= 0x1083c)
+ return true;
+ if (codePoint >= 0x1083f && codePoint <= 0x10855)
+ return true;
+ if (codePoint >= 0x10860 && codePoint <= 0x10876)
+ return true;
+ if (codePoint >= 0x10880 && codePoint <= 0x1089e)
+ return true;
+ if (codePoint >= 0x108e0 && codePoint <= 0x108f2)
+ return true;
+ if (codePoint >= 0x108f4 && codePoint <= 0x108f5)
+ return true;
+ if (codePoint >= 0x10900 && codePoint <= 0x10915)
+ return true;
+ if (codePoint >= 0x10920 && codePoint <= 0x10939)
+ return true;
+ if (codePoint >= 0x10980 && codePoint <= 0x109b7)
+ return true;
+ if (codePoint >= 0x109be && codePoint <= 0x109bf)
+ return true;
+ if (codePoint >= 0x10a00 && codePoint <= 0x10a00)
+ return true;
+ if (codePoint >= 0x10a10 && codePoint <= 0x10a13)
+ return true;
+ if (codePoint >= 0x10a15 && codePoint <= 0x10a17)
+ return true;
+ if (codePoint >= 0x10a19 && codePoint <= 0x10a33)
+ return true;
+ if (codePoint >= 0x10a60 && codePoint <= 0x10a7c)
+ return true;
+ if (codePoint >= 0x10a80 && codePoint <= 0x10a9c)
+ return true;
+ if (codePoint >= 0x10ac0 && codePoint <= 0x10ac7)
+ return true;
+ if (codePoint >= 0x10ac9 && codePoint <= 0x10ae4)
+ return true;
+ if (codePoint >= 0x10b00 && codePoint <= 0x10b35)
+ return true;
+ if (codePoint >= 0x10b40 && codePoint <= 0x10b55)
+ return true;
+ if (codePoint >= 0x10b60 && codePoint <= 0x10b72)
+ return true;
+ if (codePoint >= 0x10b80 && codePoint <= 0x10b91)
+ return true;
+ if (codePoint >= 0x10c00 && codePoint <= 0x10c48)
+ return true;
+ if (codePoint >= 0x10c80 && codePoint <= 0x10cb2)
+ return true;
+ if (codePoint >= 0x10cc0 && codePoint <= 0x10cf2)
+ return true;
+ if (codePoint >= 0x11003 && codePoint <= 0x11037)
+ return true;
+ if (codePoint >= 0x11083 && codePoint <= 0x110af)
+ return true;
+ if (codePoint >= 0x110d0 && codePoint <= 0x110e8)
+ return true;
+ if (codePoint >= 0x11103 && codePoint <= 0x11126)
+ return true;
+ if (codePoint >= 0x11150 && codePoint <= 0x11172)
+ return true;
+ if (codePoint >= 0x11176 && codePoint <= 0x11176)
+ return true;
+ if (codePoint >= 0x11183 && codePoint <= 0x111b2)
+ return true;
+ if (codePoint >= 0x111c1 && codePoint <= 0x111c4)
+ return true;
+ if (codePoint >= 0x111da && codePoint <= 0x111da)
+ return true;
+ if (codePoint >= 0x111dc && codePoint <= 0x111dc)
+ return true;
+ if (codePoint >= 0x11200 && codePoint <= 0x11211)
+ return true;
+ if (codePoint >= 0x11213 && codePoint <= 0x1122b)
+ return true;
+ if (codePoint >= 0x11280 && codePoint <= 0x11286)
+ return true;
+ if (codePoint >= 0x11288 && codePoint <= 0x11288)
+ return true;
+ if (codePoint >= 0x1128a && codePoint <= 0x1128d)
+ return true;
+ if (codePoint >= 0x1128f && codePoint <= 0x1129d)
+ return true;
+ if (codePoint >= 0x1129f && codePoint <= 0x112a8)
+ return true;
+ if (codePoint >= 0x112b0 && codePoint <= 0x112de)
+ return true;
+ if (codePoint >= 0x11305 && codePoint <= 0x1130c)
+ return true;
+ if (codePoint >= 0x1130f && codePoint <= 0x11310)
+ return true;
+ if (codePoint >= 0x11313 && codePoint <= 0x11328)
+ return true;
+ if (codePoint >= 0x1132a && codePoint <= 0x11330)
+ return true;
+ if (codePoint >= 0x11332 && codePoint <= 0x11333)
+ return true;
+ if (codePoint >= 0x11335 && codePoint <= 0x11339)
+ return true;
+ if (codePoint >= 0x1133d && codePoint <= 0x1133d)
+ return true;
+ if (codePoint >= 0x11350 && codePoint <= 0x11350)
+ return true;
+ if (codePoint >= 0x1135d && codePoint <= 0x11361)
+ return true;
+ if (codePoint >= 0x11400 && codePoint <= 0x11434)
+ return true;
+ if (codePoint >= 0x11447 && codePoint <= 0x1144a)
+ return true;
+ if (codePoint >= 0x11480 && codePoint <= 0x114af)
+ return true;
+ if (codePoint >= 0x114c4 && codePoint <= 0x114c5)
+ return true;
+ if (codePoint >= 0x114c7 && codePoint <= 0x114c7)
+ return true;
+ if (codePoint >= 0x11580 && codePoint <= 0x115ae)
+ return true;
+ if (codePoint >= 0x115d8 && codePoint <= 0x115db)
+ return true;
+ if (codePoint >= 0x11600 && codePoint <= 0x1162f)
+ return true;
+ if (codePoint >= 0x11644 && codePoint <= 0x11644)
+ return true;
+ if (codePoint >= 0x11680 && codePoint <= 0x116aa)
+ return true;
+ if (codePoint >= 0x11700 && codePoint <= 0x11719)
+ return true;
+ if (codePoint >= 0x118a0 && codePoint <= 0x118df)
+ return true;
+ if (codePoint >= 0x118ff && codePoint <= 0x118ff)
+ return true;
+ if (codePoint >= 0x11ac0 && codePoint <= 0x11af8)
+ return true;
+ if (codePoint >= 0x11c00 && codePoint <= 0x11c08)
+ return true;
+ if (codePoint >= 0x11c0a && codePoint <= 0x11c2e)
+ return true;
+ if (codePoint >= 0x11c40 && codePoint <= 0x11c40)
+ return true;
+ if (codePoint >= 0x11c72 && codePoint <= 0x11c8f)
+ return true;
+ if (codePoint >= 0x12000 && codePoint <= 0x12399)
+ return true;
+ if (codePoint >= 0x12400 && codePoint <= 0x1246e)
+ return true;
+ if (codePoint >= 0x12480 && codePoint <= 0x12543)
+ return true;
+ if (codePoint >= 0x13000 && codePoint <= 0x1342e)
+ return true;
+ if (codePoint >= 0x14400 && codePoint <= 0x14646)
+ return true;
+ if (codePoint >= 0x16800 && codePoint <= 0x16a38)
+ return true;
+ if (codePoint >= 0x16a40 && codePoint <= 0x16a5e)
+ return true;
+ if (codePoint >= 0x16ad0 && codePoint <= 0x16aed)
+ return true;
+ if (codePoint >= 0x16b00 && codePoint <= 0x16b2f)
+ return true;
+ if (codePoint >= 0x16b40 && codePoint <= 0x16b43)
+ return true;
+ if (codePoint >= 0x16b63 && codePoint <= 0x16b77)
+ return true;
+ if (codePoint >= 0x16b7d && codePoint <= 0x16b8f)
+ return true;
+ if (codePoint >= 0x16f00 && codePoint <= 0x16f44)
+ return true;
+ if (codePoint >= 0x16f50 && codePoint <= 0x16f50)
+ return true;
+ if (codePoint >= 0x16f93 && codePoint <= 0x16f9f)
+ return true;
+ if (codePoint >= 0x16fe0 && codePoint <= 0x16fe0)
+ return true;
+ if (codePoint >= 0x17000 && codePoint <= 0x187ec)
+ return true;
+ if (codePoint >= 0x18800 && codePoint <= 0x18af2)
+ return true;
+ if (codePoint >= 0x1b000 && codePoint <= 0x1b001)
+ return true;
+ if (codePoint >= 0x1bc00 && codePoint <= 0x1bc6a)
+ return true;
+ if (codePoint >= 0x1bc70 && codePoint <= 0x1bc7c)
+ return true;
+ if (codePoint >= 0x1bc80 && codePoint <= 0x1bc88)
+ return true;
+ if (codePoint >= 0x1bc90 && codePoint <= 0x1bc99)
+ return true;
+ if (codePoint >= 0x1d400 && codePoint <= 0x1d454)
+ return true;
+ if (codePoint >= 0x1d456 && codePoint <= 0x1d49c)
+ return true;
+ if (codePoint >= 0x1d49e && codePoint <= 0x1d49f)
+ return true;
+ if (codePoint >= 0x1d4a2 && codePoint <= 0x1d4a2)
+ return true;
+ if (codePoint >= 0x1d4a5 && codePoint <= 0x1d4a6)
+ return true;
+ if (codePoint >= 0x1d4a9 && codePoint <= 0x1d4ac)
+ return true;
+ if (codePoint >= 0x1d4ae && codePoint <= 0x1d4b9)
+ return true;
+ if (codePoint >= 0x1d4bb && codePoint <= 0x1d4bb)
+ return true;
+ if (codePoint >= 0x1d4bd && codePoint <= 0x1d4c3)
+ return true;
+ if (codePoint >= 0x1d4c5 && codePoint <= 0x1d505)
+ return true;
+ if (codePoint >= 0x1d507 && codePoint <= 0x1d50a)
+ return true;
+ if (codePoint >= 0x1d50d && codePoint <= 0x1d514)
+ return true;
+ if (codePoint >= 0x1d516 && codePoint <= 0x1d51c)
+ return true;
+ if (codePoint >= 0x1d51e && codePoint <= 0x1d539)
+ return true;
+ if (codePoint >= 0x1d53b && codePoint <= 0x1d53e)
+ return true;
+ if (codePoint >= 0x1d540 && codePoint <= 0x1d544)
+ return true;
+ if (codePoint >= 0x1d546 && codePoint <= 0x1d546)
+ return true;
+ if (codePoint >= 0x1d54a && codePoint <= 0x1d550)
+ return true;
+ if (codePoint >= 0x1d552 && codePoint <= 0x1d6a5)
+ return true;
+ if (codePoint >= 0x1d6a8 && codePoint <= 0x1d6c0)
+ return true;
+ if (codePoint >= 0x1d6c2 && codePoint <= 0x1d6da)
+ return true;
+ if (codePoint >= 0x1d6dc && codePoint <= 0x1d6fa)
+ return true;
+ if (codePoint >= 0x1d6fc && codePoint <= 0x1d714)
+ return true;
+ if (codePoint >= 0x1d716 && codePoint <= 0x1d734)
+ return true;
+ if (codePoint >= 0x1d736 && codePoint <= 0x1d74e)
+ return true;
+ if (codePoint >= 0x1d750 && codePoint <= 0x1d76e)
+ return true;
+ if (codePoint >= 0x1d770 && codePoint <= 0x1d788)
+ return true;
+ if (codePoint >= 0x1d78a && codePoint <= 0x1d7a8)
+ return true;
+ if (codePoint >= 0x1d7aa && codePoint <= 0x1d7c2)
+ return true;
+ if (codePoint >= 0x1d7c4 && codePoint <= 0x1d7cb)
+ return true;
+ if (codePoint >= 0x1e800 && codePoint <= 0x1e8c4)
+ return true;
+ if (codePoint >= 0x1e900 && codePoint <= 0x1e943)
+ return true;
+ if (codePoint >= 0x1ee00 && codePoint <= 0x1ee03)
+ return true;
+ if (codePoint >= 0x1ee05 && codePoint <= 0x1ee1f)
+ return true;
+ if (codePoint >= 0x1ee21 && codePoint <= 0x1ee22)
+ return true;
+ if (codePoint >= 0x1ee24 && codePoint <= 0x1ee24)
+ return true;
+ if (codePoint >= 0x1ee27 && codePoint <= 0x1ee27)
+ return true;
+ if (codePoint >= 0x1ee29 && codePoint <= 0x1ee32)
+ return true;
+ if (codePoint >= 0x1ee34 && codePoint <= 0x1ee37)
+ return true;
+ if (codePoint >= 0x1ee39 && codePoint <= 0x1ee39)
+ return true;
+ if (codePoint >= 0x1ee3b && codePoint <= 0x1ee3b)
+ return true;
+ if (codePoint >= 0x1ee42 && codePoint <= 0x1ee42)
+ return true;
+ if (codePoint >= 0x1ee47 && codePoint <= 0x1ee47)
+ return true;
+ if (codePoint >= 0x1ee49 && codePoint <= 0x1ee49)
+ return true;
+ if (codePoint >= 0x1ee4b && codePoint <= 0x1ee4b)
+ return true;
+ if (codePoint >= 0x1ee4d && codePoint <= 0x1ee4f)
+ return true;
+ if (codePoint >= 0x1ee51 && codePoint <= 0x1ee52)
+ return true;
+ if (codePoint >= 0x1ee54 && codePoint <= 0x1ee54)
+ return true;
+ if (codePoint >= 0x1ee57 && codePoint <= 0x1ee57)
+ return true;
+ if (codePoint >= 0x1ee59 && codePoint <= 0x1ee59)
+ return true;
+ if (codePoint >= 0x1ee5b && codePoint <= 0x1ee5b)
+ return true;
+ if (codePoint >= 0x1ee5d && codePoint <= 0x1ee5d)
+ return true;
+ if (codePoint >= 0x1ee5f && codePoint <= 0x1ee5f)
+ return true;
+ if (codePoint >= 0x1ee61 && codePoint <= 0x1ee62)
+ return true;
+ if (codePoint >= 0x1ee64 && codePoint <= 0x1ee64)
+ return true;
+ if (codePoint >= 0x1ee67 && codePoint <= 0x1ee6a)
+ return true;
+ if (codePoint >= 0x1ee6c && codePoint <= 0x1ee72)
+ return true;
+ if (codePoint >= 0x1ee74 && codePoint <= 0x1ee77)
+ return true;
+ if (codePoint >= 0x1ee79 && codePoint <= 0x1ee7c)
+ return true;
+ if (codePoint >= 0x1ee7e && codePoint <= 0x1ee7e)
+ return true;
+ if (codePoint >= 0x1ee80 && codePoint <= 0x1ee89)
+ return true;
+ if (codePoint >= 0x1ee8b && codePoint <= 0x1ee9b)
+ return true;
+ if (codePoint >= 0x1eea1 && codePoint <= 0x1eea3)
+ return true;
+ if (codePoint >= 0x1eea5 && codePoint <= 0x1eea9)
+ return true;
+ if (codePoint >= 0x1eeab && codePoint <= 0x1eebb)
+ return true;
+ if (codePoint >= 0x20000 && codePoint <= 0x2a6d6)
+ return true;
+ if (codePoint >= 0x2a700 && codePoint <= 0x2b734)
+ return true;
+ if (codePoint >= 0x2b740 && codePoint <= 0x2b81d)
+ return true;
+ if (codePoint >= 0x2b820 && codePoint <= 0x2cea1)
+ return true;
+ if (codePoint >= 0x2f800 && codePoint <= 0x2fa1d)
+ return true;
+ return false;
+}
+
+bool
+js::unicode::IsIdentifierPartNonBMP(uint32_t codePoint)
+{
+ if (codePoint >= 0x10000 && codePoint <= 0x1000b)
+ return true;
+ if (codePoint >= 0x1000d && codePoint <= 0x10026)
+ return true;
+ if (codePoint >= 0x10028 && codePoint <= 0x1003a)
+ return true;
+ if (codePoint >= 0x1003c && codePoint <= 0x1003d)
+ return true;
+ if (codePoint >= 0x1003f && codePoint <= 0x1004d)
+ return true;
+ if (codePoint >= 0x10050 && codePoint <= 0x1005d)
+ return true;
+ if (codePoint >= 0x10080 && codePoint <= 0x100fa)
+ return true;
+ if (codePoint >= 0x10140 && codePoint <= 0x10174)
+ return true;
+ if (codePoint >= 0x101fd && codePoint <= 0x101fd)
+ return true;
+ if (codePoint >= 0x10280 && codePoint <= 0x1029c)
+ return true;
+ if (codePoint >= 0x102a0 && codePoint <= 0x102d0)
+ return true;
+ if (codePoint >= 0x102e0 && codePoint <= 0x102e0)
+ return true;
+ if (codePoint >= 0x10300 && codePoint <= 0x1031f)
+ return true;
+ if (codePoint >= 0x10330 && codePoint <= 0x1034a)
+ return true;
+ if (codePoint >= 0x10350 && codePoint <= 0x1037a)
+ return true;
+ if (codePoint >= 0x10380 && codePoint <= 0x1039d)
+ return true;
+ if (codePoint >= 0x103a0 && codePoint <= 0x103c3)
+ return true;
+ if (codePoint >= 0x103c8 && codePoint <= 0x103cf)
+ return true;
+ if (codePoint >= 0x103d1 && codePoint <= 0x103d5)
+ return true;
+ if (codePoint >= 0x10400 && codePoint <= 0x1049d)
+ return true;
+ if (codePoint >= 0x104a0 && codePoint <= 0x104a9)
+ return true;
+ if (codePoint >= 0x104b0 && codePoint <= 0x104d3)
+ return true;
+ if (codePoint >= 0x104d8 && codePoint <= 0x104fb)
+ return true;
+ if (codePoint >= 0x10500 && codePoint <= 0x10527)
+ return true;
+ if (codePoint >= 0x10530 && codePoint <= 0x10563)
+ return true;
+ if (codePoint >= 0x10600 && codePoint <= 0x10736)
+ return true;
+ if (codePoint >= 0x10740 && codePoint <= 0x10755)
+ return true;
+ if (codePoint >= 0x10760 && codePoint <= 0x10767)
+ return true;
+ if (codePoint >= 0x10800 && codePoint <= 0x10805)
+ return true;
+ if (codePoint >= 0x10808 && codePoint <= 0x10808)
+ return true;
+ if (codePoint >= 0x1080a && codePoint <= 0x10835)
+ return true;
+ if (codePoint >= 0x10837 && codePoint <= 0x10838)
+ return true;
+ if (codePoint >= 0x1083c && codePoint <= 0x1083c)
+ return true;
+ if (codePoint >= 0x1083f && codePoint <= 0x10855)
+ return true;
+ if (codePoint >= 0x10860 && codePoint <= 0x10876)
+ return true;
+ if (codePoint >= 0x10880 && codePoint <= 0x1089e)
+ return true;
+ if (codePoint >= 0x108e0 && codePoint <= 0x108f2)
+ return true;
+ if (codePoint >= 0x108f4 && codePoint <= 0x108f5)
+ return true;
+ if (codePoint >= 0x10900 && codePoint <= 0x10915)
+ return true;
+ if (codePoint >= 0x10920 && codePoint <= 0x10939)
+ return true;
+ if (codePoint >= 0x10980 && codePoint <= 0x109b7)
+ return true;
+ if (codePoint >= 0x109be && codePoint <= 0x109bf)
+ return true;
+ if (codePoint >= 0x10a00 && codePoint <= 0x10a03)
+ return true;
+ if (codePoint >= 0x10a05 && codePoint <= 0x10a06)
+ return true;
+ if (codePoint >= 0x10a0c && codePoint <= 0x10a13)
+ return true;
+ if (codePoint >= 0x10a15 && codePoint <= 0x10a17)
+ return true;
+ if (codePoint >= 0x10a19 && codePoint <= 0x10a33)
+ return true;
+ if (codePoint >= 0x10a38 && codePoint <= 0x10a3a)
+ return true;
+ if (codePoint >= 0x10a3f && codePoint <= 0x10a3f)
+ return true;
+ if (codePoint >= 0x10a60 && codePoint <= 0x10a7c)
+ return true;
+ if (codePoint >= 0x10a80 && codePoint <= 0x10a9c)
+ return true;
+ if (codePoint >= 0x10ac0 && codePoint <= 0x10ac7)
+ return true;
+ if (codePoint >= 0x10ac9 && codePoint <= 0x10ae6)
+ return true;
+ if (codePoint >= 0x10b00 && codePoint <= 0x10b35)
+ return true;
+ if (codePoint >= 0x10b40 && codePoint <= 0x10b55)
+ return true;
+ if (codePoint >= 0x10b60 && codePoint <= 0x10b72)
+ return true;
+ if (codePoint >= 0x10b80 && codePoint <= 0x10b91)
+ return true;
+ if (codePoint >= 0x10c00 && codePoint <= 0x10c48)
+ return true;
+ if (codePoint >= 0x10c80 && codePoint <= 0x10cb2)
+ return true;
+ if (codePoint >= 0x10cc0 && codePoint <= 0x10cf2)
+ return true;
+ if (codePoint >= 0x11000 && codePoint <= 0x11046)
+ return true;
+ if (codePoint >= 0x11066 && codePoint <= 0x1106f)
+ return true;
+ if (codePoint >= 0x1107f && codePoint <= 0x110ba)
+ return true;
+ if (codePoint >= 0x110d0 && codePoint <= 0x110e8)
+ return true;
+ if (codePoint >= 0x110f0 && codePoint <= 0x110f9)
+ return true;
+ if (codePoint >= 0x11100 && codePoint <= 0x11134)
+ return true;
+ if (codePoint >= 0x11136 && codePoint <= 0x1113f)
+ return true;
+ if (codePoint >= 0x11150 && codePoint <= 0x11173)
+ return true;
+ if (codePoint >= 0x11176 && codePoint <= 0x11176)
+ return true;
+ if (codePoint >= 0x11180 && codePoint <= 0x111c4)
+ return true;
+ if (codePoint >= 0x111ca && codePoint <= 0x111cc)
+ return true;
+ if (codePoint >= 0x111d0 && codePoint <= 0x111da)
+ return true;
+ if (codePoint >= 0x111dc && codePoint <= 0x111dc)
+ return true;
+ if (codePoint >= 0x11200 && codePoint <= 0x11211)
+ return true;
+ if (codePoint >= 0x11213 && codePoint <= 0x11237)
+ return true;
+ if (codePoint >= 0x1123e && codePoint <= 0x1123e)
+ return true;
+ if (codePoint >= 0x11280 && codePoint <= 0x11286)
+ return true;
+ if (codePoint >= 0x11288 && codePoint <= 0x11288)
+ return true;
+ if (codePoint >= 0x1128a && codePoint <= 0x1128d)
+ return true;
+ if (codePoint >= 0x1128f && codePoint <= 0x1129d)
+ return true;
+ if (codePoint >= 0x1129f && codePoint <= 0x112a8)
+ return true;
+ if (codePoint >= 0x112b0 && codePoint <= 0x112ea)
+ return true;
+ if (codePoint >= 0x112f0 && codePoint <= 0x112f9)
+ return true;
+ if (codePoint >= 0x11300 && codePoint <= 0x11303)
+ return true;
+ if (codePoint >= 0x11305 && codePoint <= 0x1130c)
+ return true;
+ if (codePoint >= 0x1130f && codePoint <= 0x11310)
+ return true;
+ if (codePoint >= 0x11313 && codePoint <= 0x11328)
+ return true;
+ if (codePoint >= 0x1132a && codePoint <= 0x11330)
+ return true;
+ if (codePoint >= 0x11332 && codePoint <= 0x11333)
+ return true;
+ if (codePoint >= 0x11335 && codePoint <= 0x11339)
+ return true;
+ if (codePoint >= 0x1133c && codePoint <= 0x11344)
+ return true;
+ if (codePoint >= 0x11347 && codePoint <= 0x11348)
+ return true;
+ if (codePoint >= 0x1134b && codePoint <= 0x1134d)
+ return true;
+ if (codePoint >= 0x11350 && codePoint <= 0x11350)
+ return true;
+ if (codePoint >= 0x11357 && codePoint <= 0x11357)
+ return true;
+ if (codePoint >= 0x1135d && codePoint <= 0x11363)
+ return true;
+ if (codePoint >= 0x11366 && codePoint <= 0x1136c)
+ return true;
+ if (codePoint >= 0x11370 && codePoint <= 0x11374)
+ return true;
+ if (codePoint >= 0x11400 && codePoint <= 0x1144a)
+ return true;
+ if (codePoint >= 0x11450 && codePoint <= 0x11459)
+ return true;
+ if (codePoint >= 0x11480 && codePoint <= 0x114c5)
+ return true;
+ if (codePoint >= 0x114c7 && codePoint <= 0x114c7)
+ return true;
+ if (codePoint >= 0x114d0 && codePoint <= 0x114d9)
+ return true;
+ if (codePoint >= 0x11580 && codePoint <= 0x115b5)
+ return true;
+ if (codePoint >= 0x115b8 && codePoint <= 0x115c0)
+ return true;
+ if (codePoint >= 0x115d8 && codePoint <= 0x115dd)
+ return true;
+ if (codePoint >= 0x11600 && codePoint <= 0x11640)
+ return true;
+ if (codePoint >= 0x11644 && codePoint <= 0x11644)
+ return true;
+ if (codePoint >= 0x11650 && codePoint <= 0x11659)
+ return true;
+ if (codePoint >= 0x11680 && codePoint <= 0x116b7)
+ return true;
+ if (codePoint >= 0x116c0 && codePoint <= 0x116c9)
+ return true;
+ if (codePoint >= 0x11700 && codePoint <= 0x11719)
+ return true;
+ if (codePoint >= 0x1171d && codePoint <= 0x1172b)
+ return true;
+ if (codePoint >= 0x11730 && codePoint <= 0x11739)
+ return true;
+ if (codePoint >= 0x118a0 && codePoint <= 0x118e9)
+ return true;
+ if (codePoint >= 0x118ff && codePoint <= 0x118ff)
+ return true;
+ if (codePoint >= 0x11ac0 && codePoint <= 0x11af8)
+ return true;
+ if (codePoint >= 0x11c00 && codePoint <= 0x11c08)
+ return true;
+ if (codePoint >= 0x11c0a && codePoint <= 0x11c36)
+ return true;
+ if (codePoint >= 0x11c38 && codePoint <= 0x11c40)
+ return true;
+ if (codePoint >= 0x11c50 && codePoint <= 0x11c59)
+ return true;
+ if (codePoint >= 0x11c72 && codePoint <= 0x11c8f)
+ return true;
+ if (codePoint >= 0x11c92 && codePoint <= 0x11ca7)
+ return true;
+ if (codePoint >= 0x11ca9 && codePoint <= 0x11cb6)
+ return true;
+ if (codePoint >= 0x12000 && codePoint <= 0x12399)
+ return true;
+ if (codePoint >= 0x12400 && codePoint <= 0x1246e)
+ return true;
+ if (codePoint >= 0x12480 && codePoint <= 0x12543)
+ return true;
+ if (codePoint >= 0x13000 && codePoint <= 0x1342e)
+ return true;
+ if (codePoint >= 0x14400 && codePoint <= 0x14646)
+ return true;
+ if (codePoint >= 0x16800 && codePoint <= 0x16a38)
+ return true;
+ if (codePoint >= 0x16a40 && codePoint <= 0x16a5e)
+ return true;
+ if (codePoint >= 0x16a60 && codePoint <= 0x16a69)
+ return true;
+ if (codePoint >= 0x16ad0 && codePoint <= 0x16aed)
+ return true;
+ if (codePoint >= 0x16af0 && codePoint <= 0x16af4)
+ return true;
+ if (codePoint >= 0x16b00 && codePoint <= 0x16b36)
+ return true;
+ if (codePoint >= 0x16b40 && codePoint <= 0x16b43)
+ return true;
+ if (codePoint >= 0x16b50 && codePoint <= 0x16b59)
+ return true;
+ if (codePoint >= 0x16b63 && codePoint <= 0x16b77)
+ return true;
+ if (codePoint >= 0x16b7d && codePoint <= 0x16b8f)
+ return true;
+ if (codePoint >= 0x16f00 && codePoint <= 0x16f44)
+ return true;
+ if (codePoint >= 0x16f50 && codePoint <= 0x16f7e)
+ return true;
+ if (codePoint >= 0x16f8f && codePoint <= 0x16f9f)
+ return true;
+ if (codePoint >= 0x16fe0 && codePoint <= 0x16fe0)
+ return true;
+ if (codePoint >= 0x17000 && codePoint <= 0x187ec)
+ return true;
+ if (codePoint >= 0x18800 && codePoint <= 0x18af2)
+ return true;
+ if (codePoint >= 0x1b000 && codePoint <= 0x1b001)
+ return true;
+ if (codePoint >= 0x1bc00 && codePoint <= 0x1bc6a)
+ return true;
+ if (codePoint >= 0x1bc70 && codePoint <= 0x1bc7c)
+ return true;
+ if (codePoint >= 0x1bc80 && codePoint <= 0x1bc88)
+ return true;
+ if (codePoint >= 0x1bc90 && codePoint <= 0x1bc99)
+ return true;
+ if (codePoint >= 0x1bc9d && codePoint <= 0x1bc9e)
+ return true;
+ if (codePoint >= 0x1d165 && codePoint <= 0x1d169)
+ return true;
+ if (codePoint >= 0x1d16d && codePoint <= 0x1d172)
+ return true;
+ if (codePoint >= 0x1d17b && codePoint <= 0x1d182)
+ return true;
+ if (codePoint >= 0x1d185 && codePoint <= 0x1d18b)
+ return true;
+ if (codePoint >= 0x1d1aa && codePoint <= 0x1d1ad)
+ return true;
+ if (codePoint >= 0x1d242 && codePoint <= 0x1d244)
+ return true;
+ if (codePoint >= 0x1d400 && codePoint <= 0x1d454)
+ return true;
+ if (codePoint >= 0x1d456 && codePoint <= 0x1d49c)
+ return true;
+ if (codePoint >= 0x1d49e && codePoint <= 0x1d49f)
+ return true;
+ if (codePoint >= 0x1d4a2 && codePoint <= 0x1d4a2)
+ return true;
+ if (codePoint >= 0x1d4a5 && codePoint <= 0x1d4a6)
+ return true;
+ if (codePoint >= 0x1d4a9 && codePoint <= 0x1d4ac)
+ return true;
+ if (codePoint >= 0x1d4ae && codePoint <= 0x1d4b9)
+ return true;
+ if (codePoint >= 0x1d4bb && codePoint <= 0x1d4bb)
+ return true;
+ if (codePoint >= 0x1d4bd && codePoint <= 0x1d4c3)
+ return true;
+ if (codePoint >= 0x1d4c5 && codePoint <= 0x1d505)
+ return true;
+ if (codePoint >= 0x1d507 && codePoint <= 0x1d50a)
+ return true;
+ if (codePoint >= 0x1d50d && codePoint <= 0x1d514)
+ return true;
+ if (codePoint >= 0x1d516 && codePoint <= 0x1d51c)
+ return true;
+ if (codePoint >= 0x1d51e && codePoint <= 0x1d539)
+ return true;
+ if (codePoint >= 0x1d53b && codePoint <= 0x1d53e)
+ return true;
+ if (codePoint >= 0x1d540 && codePoint <= 0x1d544)
+ return true;
+ if (codePoint >= 0x1d546 && codePoint <= 0x1d546)
+ return true;
+ if (codePoint >= 0x1d54a && codePoint <= 0x1d550)
+ return true;
+ if (codePoint >= 0x1d552 && codePoint <= 0x1d6a5)
+ return true;
+ if (codePoint >= 0x1d6a8 && codePoint <= 0x1d6c0)
+ return true;
+ if (codePoint >= 0x1d6c2 && codePoint <= 0x1d6da)
+ return true;
+ if (codePoint >= 0x1d6dc && codePoint <= 0x1d6fa)
+ return true;
+ if (codePoint >= 0x1d6fc && codePoint <= 0x1d714)
+ return true;
+ if (codePoint >= 0x1d716 && codePoint <= 0x1d734)
+ return true;
+ if (codePoint >= 0x1d736 && codePoint <= 0x1d74e)
+ return true;
+ if (codePoint >= 0x1d750 && codePoint <= 0x1d76e)
+ return true;
+ if (codePoint >= 0x1d770 && codePoint <= 0x1d788)
+ return true;
+ if (codePoint >= 0x1d78a && codePoint <= 0x1d7a8)
+ return true;
+ if (codePoint >= 0x1d7aa && codePoint <= 0x1d7c2)
+ return true;
+ if (codePoint >= 0x1d7c4 && codePoint <= 0x1d7cb)
+ return true;
+ if (codePoint >= 0x1d7ce && codePoint <= 0x1d7ff)
+ return true;
+ if (codePoint >= 0x1da00 && codePoint <= 0x1da36)
+ return true;
+ if (codePoint >= 0x1da3b && codePoint <= 0x1da6c)
+ return true;
+ if (codePoint >= 0x1da75 && codePoint <= 0x1da75)
+ return true;
+ if (codePoint >= 0x1da84 && codePoint <= 0x1da84)
+ return true;
+ if (codePoint >= 0x1da9b && codePoint <= 0x1da9f)
+ return true;
+ if (codePoint >= 0x1daa1 && codePoint <= 0x1daaf)
+ return true;
+ if (codePoint >= 0x1e000 && codePoint <= 0x1e006)
+ return true;
+ if (codePoint >= 0x1e008 && codePoint <= 0x1e018)
+ return true;
+ if (codePoint >= 0x1e01b && codePoint <= 0x1e021)
+ return true;
+ if (codePoint >= 0x1e023 && codePoint <= 0x1e024)
+ return true;
+ if (codePoint >= 0x1e026 && codePoint <= 0x1e02a)
+ return true;
+ if (codePoint >= 0x1e800 && codePoint <= 0x1e8c4)
+ return true;
+ if (codePoint >= 0x1e8d0 && codePoint <= 0x1e8d6)
+ return true;
+ if (codePoint >= 0x1e900 && codePoint <= 0x1e94a)
+ return true;
+ if (codePoint >= 0x1e950 && codePoint <= 0x1e959)
+ return true;
+ if (codePoint >= 0x1ee00 && codePoint <= 0x1ee03)
+ return true;
+ if (codePoint >= 0x1ee05 && codePoint <= 0x1ee1f)
+ return true;
+ if (codePoint >= 0x1ee21 && codePoint <= 0x1ee22)
+ return true;
+ if (codePoint >= 0x1ee24 && codePoint <= 0x1ee24)
+ return true;
+ if (codePoint >= 0x1ee27 && codePoint <= 0x1ee27)
+ return true;
+ if (codePoint >= 0x1ee29 && codePoint <= 0x1ee32)
+ return true;
+ if (codePoint >= 0x1ee34 && codePoint <= 0x1ee37)
+ return true;
+ if (codePoint >= 0x1ee39 && codePoint <= 0x1ee39)
+ return true;
+ if (codePoint >= 0x1ee3b && codePoint <= 0x1ee3b)
+ return true;
+ if (codePoint >= 0x1ee42 && codePoint <= 0x1ee42)
+ return true;
+ if (codePoint >= 0x1ee47 && codePoint <= 0x1ee47)
+ return true;
+ if (codePoint >= 0x1ee49 && codePoint <= 0x1ee49)
+ return true;
+ if (codePoint >= 0x1ee4b && codePoint <= 0x1ee4b)
+ return true;
+ if (codePoint >= 0x1ee4d && codePoint <= 0x1ee4f)
+ return true;
+ if (codePoint >= 0x1ee51 && codePoint <= 0x1ee52)
+ return true;
+ if (codePoint >= 0x1ee54 && codePoint <= 0x1ee54)
+ return true;
+ if (codePoint >= 0x1ee57 && codePoint <= 0x1ee57)
+ return true;
+ if (codePoint >= 0x1ee59 && codePoint <= 0x1ee59)
+ return true;
+ if (codePoint >= 0x1ee5b && codePoint <= 0x1ee5b)
+ return true;
+ if (codePoint >= 0x1ee5d && codePoint <= 0x1ee5d)
+ return true;
+ if (codePoint >= 0x1ee5f && codePoint <= 0x1ee5f)
+ return true;
+ if (codePoint >= 0x1ee61 && codePoint <= 0x1ee62)
+ return true;
+ if (codePoint >= 0x1ee64 && codePoint <= 0x1ee64)
+ return true;
+ if (codePoint >= 0x1ee67 && codePoint <= 0x1ee6a)
+ return true;
+ if (codePoint >= 0x1ee6c && codePoint <= 0x1ee72)
+ return true;
+ if (codePoint >= 0x1ee74 && codePoint <= 0x1ee77)
+ return true;
+ if (codePoint >= 0x1ee79 && codePoint <= 0x1ee7c)
+ return true;
+ if (codePoint >= 0x1ee7e && codePoint <= 0x1ee7e)
+ return true;
+ if (codePoint >= 0x1ee80 && codePoint <= 0x1ee89)
+ return true;
+ if (codePoint >= 0x1ee8b && codePoint <= 0x1ee9b)
+ return true;
+ if (codePoint >= 0x1eea1 && codePoint <= 0x1eea3)
+ return true;
+ if (codePoint >= 0x1eea5 && codePoint <= 0x1eea9)
+ return true;
+ if (codePoint >= 0x1eeab && codePoint <= 0x1eebb)
+ return true;
+ if (codePoint >= 0x20000 && codePoint <= 0x2a6d6)
+ return true;
+ if (codePoint >= 0x2a700 && codePoint <= 0x2b734)
+ return true;
+ if (codePoint >= 0x2b740 && codePoint <= 0x2b81d)
+ return true;
+ if (codePoint >= 0x2b820 && codePoint <= 0x2cea1)
+ return true;
+ if (codePoint >= 0x2f800 && codePoint <= 0x2fa1d)
+ return true;
+ if (codePoint >= 0xe0100 && codePoint <= 0xe01ef)
+ return true;
+ return false;
+}
diff --git a/js/src/vm/Unicode.h b/js/src/vm/Unicode.h
index 8b538d06d..bdac848fb 100644
--- a/js/src/vm/Unicode.h
+++ b/js/src/vm/Unicode.h
@@ -143,11 +143,15 @@ IsIdentifierStart(char16_t ch)
return CharInfo(ch).isUnicodeIDStart();
}
+bool
+IsIdentifierStartNonBMP(uint32_t codePoint);
+
inline bool
IsIdentifierStart(uint32_t codePoint)
{
- // TODO: Supplemental code points not yet supported (bug 1197230).
- return codePoint <= UTF16Max && IsIdentifierStart(char16_t(codePoint));
+ if (MOZ_UNLIKELY(codePoint > UTF16Max))
+ return IsIdentifierStartNonBMP(codePoint);
+ return IsIdentifierStart(char16_t(codePoint));
}
inline bool
@@ -170,11 +174,16 @@ IsIdentifierPart(char16_t ch)
return CharInfo(ch).isUnicodeIDContinue();
}
+
+bool
+IsIdentifierPartNonBMP(uint32_t codePoint);
+
inline bool
IsIdentifierPart(uint32_t codePoint)
{
- // TODO: Supplemental code points not yet supported (bug 1197230).
- return codePoint <= UTF16Max && IsIdentifierPart(char16_t(codePoint));
+ if (MOZ_UNLIKELY(codePoint > UTF16Max))
+ return IsIdentifierPartNonBMP(codePoint);
+ return IsIdentifierPart(char16_t(codePoint));
}
inline bool
@@ -183,6 +192,17 @@ IsUnicodeIDStart(char16_t ch)
return CharInfo(ch).isUnicodeIDStart();
}
+bool
+IsUnicodeIDStartNonBMP(uint32_t codePoint);
+
+inline bool
+IsUnicodeIDStart(uint32_t codePoint)
+{
+ if (MOZ_UNLIKELY(codePoint > UTF16Max))
+ return IsIdentifierStartNonBMP(codePoint);
+ return IsUnicodeIDStart(char16_t(codePoint));
+}
+
inline bool
IsSpace(char16_t ch)
{
diff --git a/js/src/vm/UnicodeNonBMP.h b/js/src/vm/UnicodeNonBMP.h
index 6cc64cde4..f99e227cd 100644
--- a/js/src/vm/UnicodeNonBMP.h
+++ b/js/src/vm/UnicodeNonBMP.h
@@ -10,6 +10,16 @@
#ifndef vm_UnicodeNonBMP_h
#define vm_UnicodeNonBMP_h
+// |macro| receives the following arguments
+// macro(FROM, TO, LEAD, TRAIL_FROM, TRAIL_TO, DIFF)
+// FROM: code point where the range starts
+// TO: code point where the range ends
+// LEAD: common lead surrogate of FROM and TO
+// TRAIL_FROM: trail surrogate of FROM
+// TRAIL_FROM: trail surrogate of TO
+// DIFF: the difference between the code point in the range and
+// converted code point
+
#define FOR_EACH_NON_BMP_LOWERCASE(macro) \
macro(0x10400, 0x10427, 0xd801, 0xdc00, 0xdc27, 40) \
macro(0x104b0, 0x104d3, 0xd801, 0xdcb0, 0xdcd3, 40) \
diff --git a/js/src/vm/make_unicode.py b/js/src/vm/make_unicode.py
index 73c090ac9..83f0d004b 100755
--- a/js/src/vm/make_unicode.py
+++ b/js/src/vm/make_unicode.py
@@ -155,37 +155,65 @@ def utf16_encode(code):
return lead, trail
def make_non_bmp_convert_macro(out_file, name, convert_map):
+ # Find continuous range in convert_map.
convert_list = []
entry = None
for code in sorted(convert_map.keys()):
+ lead, trail = utf16_encode(code)
converted = convert_map[code]
diff = converted - code
- if entry and code == entry['code'] + entry['length'] and diff == entry['diff']:
+ if (entry and code == entry['code'] + entry['length'] and
+ diff == entry['diff'] and lead == entry['lead']):
+
entry['length'] += 1
continue
- entry = { 'code': code, 'diff': diff, 'length': 1 }
+ entry = {
+ 'code': code,
+ 'diff': diff,
+ 'length': 1,
+ 'lead': lead,
+ 'trail': trail,
+ }
convert_list.append(entry)
+ # Generate macro call for each range.
lines = []
for entry in convert_list:
from_code = entry['code']
to_code = entry['code'] + entry['length'] - 1
diff = entry['diff']
- from_lead, from_trail = utf16_encode(from_code)
- to_lead, to_trail = utf16_encode(to_code)
-
- assert from_lead == to_lead
+ lead = entry['lead']
+ from_trail = entry['trail']
+ to_trail = entry['trail'] + entry['length'] - 1
lines.append(' macro(0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, {:d})'.format(
- from_code, to_code, from_lead, from_trail, to_trail, diff))
+ from_code, to_code, lead, from_trail, to_trail, diff))
out_file.write('#define FOR_EACH_NON_BMP_{}(macro) \\\n'.format(name))
out_file.write(' \\\n'.join(lines))
out_file.write('\n')
+def for_each_non_bmp_group(group_set):
+ # Find continuous range in group_set.
+ group_list = []
+ entry = None
+ for code in sorted(group_set.keys()):
+ if entry and code == entry['code'] + entry['length']:
+ entry['length'] += 1
+ continue
+
+ entry = {
+ 'code': code,
+ 'length': 1
+ }
+ group_list.append(entry)
+
+ for entry in group_list:
+ yield (entry['code'], entry['code'] + entry['length'] - 1)
+
def process_derived_core_properties(derived_core_properties):
id_start = set()
id_continue = set()
@@ -214,6 +242,9 @@ def process_unicode_data(unicode_data, derived_core_properties):
non_bmp_lower_map = {}
non_bmp_upper_map = {}
+ non_bmp_id_start_set = {}
+ non_bmp_id_cont_set = {}
+ non_bmp_space_set = {}
(id_start, id_continue) = process_derived_core_properties(derived_core_properties)
@@ -246,6 +277,13 @@ def process_unicode_data(unicode_data, derived_core_properties):
non_bmp_lower_map[code] = lower
if code != upper:
non_bmp_upper_map[code] = upper
+ if category == 'Zs':
+ non_bmp_space_set[code] = 1
+ test_space_table.append(code)
+ if code in id_start:
+ non_bmp_id_start_set[code] = 1
+ if code in id_continue:
+ non_bmp_id_cont_set[code] = 1
continue
# we combine whitespace and lineterminators because in pratice we don't need them separated
@@ -315,6 +353,8 @@ def process_unicode_data(unicode_data, derived_core_properties):
table, index,
same_upper_table, same_upper_index,
non_bmp_lower_map, non_bmp_upper_map,
+ non_bmp_space_set,
+ non_bmp_id_start_set, non_bmp_id_cont_set,
test_table, test_space_table,
)
@@ -412,6 +452,16 @@ def make_non_bmp_file(version,
#ifndef vm_UnicodeNonBMP_h
#define vm_UnicodeNonBMP_h
+// |macro| receives the following arguments
+// macro(FROM, TO, LEAD, TRAIL_FROM, TRAIL_TO, DIFF)
+// FROM: code point where the range starts
+// TO: code point where the range ends
+// LEAD: common lead surrogate of FROM and TO
+// TRAIL_FROM: trail surrogate of FROM
+// TRAIL_FROM: trail surrogate of TO
+// DIFF: the difference between the code point in the range and
+// converted code point
+
""")
make_non_bmp_convert_macro(non_bmp_file, 'LOWERCASE', non_bmp_lower_map)
@@ -525,7 +575,9 @@ if (typeof reportCompare === "function")
def make_unicode_file(version,
table, index,
same_upper_table, same_upper_index,
- folding_table, folding_index):
+ folding_table, folding_index,
+ non_bmp_space_set,
+ non_bmp_id_start_set, non_bmp_id_cont_set):
index1, index2, shift = splitbins(index)
# Don't forget to update CharInfo in Unicode.h if you need to change this
@@ -682,6 +734,43 @@ def make_unicode_file(version,
dump(folding_index2, 'folding_index2', data_file)
data_file.write('\n')
+ # If the following assert fails, it means space character is added to
+ # non-BMP area. In that case the following code should be uncommented
+ # and the corresponding code should be added to frontend.
+ assert len(non_bmp_space_set.keys()) == 0
+
+ data_file.write("""\
+bool
+js::unicode::IsIdentifierStartNonBMP(uint32_t codePoint)
+{
+""")
+
+ for (from_code, to_code) in for_each_non_bmp_group(non_bmp_id_start_set):
+ data_file.write("""\
+ if (codePoint >= 0x{:x} && codePoint <= 0x{:x})
+ return true;
+""".format(from_code, to_code))
+
+ data_file.write("""\
+ return false;
+}
+
+bool
+js::unicode::IsIdentifierPartNonBMP(uint32_t codePoint)
+{
+""")
+
+ for (from_code, to_code) in for_each_non_bmp_group(non_bmp_id_cont_set):
+ data_file.write("""\
+ if (codePoint >= 0x{:x} && codePoint <= 0x{:x})
+ return true;
+""".format(from_code, to_code))
+
+ data_file.write("""\
+ return false;
+}
+""")
+
def getsize(data):
""" return smallest possible integer size for the given array """
maxdata = max(data)
@@ -1000,6 +1089,8 @@ def update_unicode(args):
table, index,
same_upper_table, same_upper_index,
non_bmp_lower_map, non_bmp_upper_map,
+ non_bmp_space_set,
+ non_bmp_id_start_set, non_bmp_id_cont_set,
test_table, test_space_table
) = process_unicode_data(unicode_data, derived_core_properties)
(
@@ -1012,7 +1103,9 @@ def update_unicode(args):
make_unicode_file(unicode_version,
table, index,
same_upper_table, same_upper_index,
- folding_table, folding_index)
+ folding_table, folding_index,
+ non_bmp_space_set,
+ non_bmp_id_start_set, non_bmp_id_cont_set)
make_non_bmp_file(unicode_version,
non_bmp_lower_map, non_bmp_upper_map,
non_bmp_folding_map, non_bmp_rev_folding_map)
diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp
index 34f5a8c0d..4dbc9b387 100644
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -21,6 +21,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/Compression.h"
#include "mozilla/MathAlgorithms.h"
+#include "mozilla/Maybe.h"
#include "jsmath.h"
#include "jsprf.h"
@@ -8033,21 +8034,6 @@ TryInstantiate(JSContext* cx, CallArgs args, Module& module, const AsmJSMetadata
return true;
}
-static MOZ_MUST_USE bool
-MaybeAppendUTF8Name(JSContext* cx, const char* utf8Chars, MutableHandle<PropertyNameVector> names)
-{
- if (!utf8Chars)
- return true;
-
- UTF8Chars utf8(utf8Chars, strlen(utf8Chars));
-
- JSAtom* atom = AtomizeUTF8Chars(cx, utf8Chars, strlen(utf8Chars));
- if (!atom)
- return false;
-
- return names.append(atom->asPropertyName());
-}
-
static bool
HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& metadata)
{
@@ -8068,8 +8054,8 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me
return false;
}
- uint32_t begin = metadata.srcBodyStart; // starts right after 'use asm'
- uint32_t end = metadata.srcEndBeforeCurly();
+ uint32_t begin = metadata.srcStart;
+ uint32_t end = metadata.srcEndAfterCurly();
Rooted<JSFlatString*> src(cx, source->substringDontDeflate(cx, begin, end));
if (!src)
return false;
@@ -8080,18 +8066,11 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me
if (!fun)
return false;
- Rooted<PropertyNameVector> formals(cx, PropertyNameVector(cx));
- if (!MaybeAppendUTF8Name(cx, metadata.globalArgumentName.get(), &formals))
- return false;
- if (!MaybeAppendUTF8Name(cx, metadata.importArgumentName.get(), &formals))
- return false;
- if (!MaybeAppendUTF8Name(cx, metadata.bufferArgumentName.get(), &formals))
- return false;
-
CompileOptions options(cx);
options.setMutedErrors(source->mutedErrors())
.setFile(source->filename())
.setNoScriptRval(false);
+ options.asmJSOption = AsmJSOption::Disabled;
// The exported function inherits an implicit strict context if the module
// also inherited it somehow.
@@ -8106,8 +8085,8 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me
SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller()
? SourceBufferHolder::GiveOwnership
: SourceBufferHolder::NoOwnership;
- SourceBufferHolder srcBuf(chars, end - begin, ownership);
- if (!frontend::CompileFunctionBody(cx, &fun, options, formals, srcBuf))
+ SourceBufferHolder srcBuf(chars, stableChars.twoByteRange().length(), ownership);
+ if (!frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, Nothing()))
return false;
// Call the function we just recompiled.
@@ -8849,23 +8828,6 @@ js::IsAsmJSModuleLoadedFromCache(JSContext* cx, unsigned argc, Value* vp)
/*****************************************************************************/
// asm.js toString/toSource support
-static MOZ_MUST_USE bool
-MaybeAppendUTF8Chars(JSContext* cx, const char* sep, const char* utf8Chars, StringBuffer* sb)
-{
- if (!utf8Chars)
- return true;
-
- UTF8Chars utf8(utf8Chars, strlen(utf8Chars));
-
- size_t length;
- UniqueTwoByteChars twoByteChars(UTF8CharsToNewTwoByteCharsZ(cx, utf8, &length).get());
- if (!twoByteChars)
- return false;
-
- return sb->append(sep, strlen(sep)) &&
- sb->append(twoByteChars.get(), length);
-}
-
JSString*
js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda)
{
@@ -8895,33 +8857,12 @@ js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda
if (!out.append("() {\n [sourceless code]\n}"))
return nullptr;
} else {
- // Whether the function has been created with a Function ctor
- bool funCtor = begin == 0 && end == source->length() && source->argumentsNotIncluded();
- if (funCtor) {
- // Functions created with the function constructor don't have arguments in their source.
- if (!out.append("("))
- return nullptr;
-
- if (!MaybeAppendUTF8Chars(cx, "", metadata.globalArgumentName.get(), &out))
- return nullptr;
- if (!MaybeAppendUTF8Chars(cx, ", ", metadata.importArgumentName.get(), &out))
- return nullptr;
- if (!MaybeAppendUTF8Chars(cx, ", ", metadata.bufferArgumentName.get(), &out))
- return nullptr;
-
- if (!out.append(") {\n"))
- return nullptr;
- }
-
Rooted<JSFlatString*> src(cx, source->substring(cx, begin, end));
if (!src)
return nullptr;
if (!out.append(src))
return nullptr;
-
- if (funCtor && !out.append("\n}"))
- return nullptr;
}
if (addParenToLambda && fun->isLambda() && !out.append(")"))
@@ -8959,10 +8900,6 @@ js::AsmJSFunctionToString(JSContext* cx, HandleFunction fun)
if (!out.append("() {\n [sourceless code]\n}"))
return nullptr;
} else {
- // asm.js functions cannot have been created with a Function constructor
- // as they belong within a module.
- MOZ_ASSERT(!(begin == 0 && end == source->length() && source->argumentsNotIncluded()));
-
Rooted<JSFlatString*> src(cx, source->substring(cx, begin, end));
if (!src)
return nullptr;
diff --git a/js/xpconnect/loader/mozJSSubScriptLoader.cpp b/js/xpconnect/loader/mozJSSubScriptLoader.cpp
index 824e9ab9e..9c8908ea4 100644
--- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp
+++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp
@@ -130,7 +130,9 @@ PrepareScript(nsIURI* uri,
MutableHandleFunction function)
{
JS::CompileOptions options(cx);
- options.setFileAndLine(uriStr, 1)
+ // Use line 0 to make the function body starts from line 1 when
+ // |reuseGlobal == true|.
+ options.setFileAndLine(uriStr, reuseGlobal ? 0 : 1)
.setVersion(JSVERSION_LATEST);
if (!charset.IsVoid()) {
char16_t* scriptBuf = nullptr;
diff --git a/mozglue/android/NSSBridge.cpp b/mozglue/android/NSSBridge.cpp
index 2a9b5771d..3343ad1b2 100644
--- a/mozglue/android/NSSBridge.cpp
+++ b/mozglue/android/NSSBridge.cpp
@@ -37,6 +37,10 @@ NSS_WRAPPER_INT(PL_Base64Encode)
NSS_WRAPPER_INT(PL_Base64Decode)
NSS_WRAPPER_INT(PL_strfree)
+SECStatus doCrypto(JNIEnv* jenv, const char *path, const char *value, char** result, bool doEncrypt);
+SECStatus encode(const uint8_t* data, uint32_t srclen, char** result);
+SECStatus decode(const char* data, uint8_t** result, uint32_t* length);
+
int
setup_nss_functions(void *nss_handle,
void *nspr_handle,
@@ -189,41 +193,40 @@ doCrypto(JNIEnv* jenv, const char *path, const char *value, char** result, bool
keyid.len = 0;
rv = f_PK11SDR_Encrypt(&keyid, &request, &reply, nullptr);
- if (rv != SECSuccess) {
+ if (rv == SECSuccess) {
+ rv = encode(reply.data, reply.len, result);
+ if (rv == SECSuccess) {
+ LOG("Encrypted: %s\n", *result);
+ } else {
+ throwError(jenv, "encode");
+ }
+ } else {
throwError(jenv, "PK11SDR_Encrypt");
- goto done;
}
- rv = encode(reply.data, reply.len, result);
- if (rv != SECSuccess) {
- throwError(jenv, "encode");
- goto done;
- }
- LOG("Encrypted: %s\n", *result);
} else {
LOG("Decoding: %s\n", value);
- rv = decode(value, &request.data, (int32_t*)&request.len);
+ rv = decode(value, &request.data, &request.len);
if (rv != SECSuccess) {
throwError(jenv, "decode");
return rv;
}
rv = f_PK11SDR_Decrypt(&request, &reply, nullptr);
- if (rv != SECSuccess) {
- throwError(jenv, "PK11SDR_Decrypt");
- goto done;
- }
- *result = (char *)malloc(reply.len+1);
- strncpy(*result, (char *)reply.data, reply.len);
- (*result)[reply.len] = '\0';
+ if (rv == SECSuccess) {
+ *result = static_cast<char*>(malloc(reply.len + 1));
+ strncpy(*result, reinterpret_cast<char*>(reply.data), reply.len);
+ (*result)[reply.len] = '\0';
- // This can print sensitive data. Uncomment if you need it.
- // LOG("Decoded %i letters: %s\n", reply.len, *result);
+ // This can print sensitive data. Uncomment if you need it.
+ // LOG("Decoded %i letters: %s\n", reply.len, *result);
+ } else {
+ throwError(jenv, "PK11SDR_Decrypt");
+ }
free(request.data);
}
-done:
f_SECITEM_ZfreeItem(&reply, false);
return rv;
}
@@ -232,64 +235,51 @@ done:
* Base64 encodes the data passed in. The caller must deallocate _retval using free();
*/
SECStatus
-encode(const unsigned char *data, int32_t dataLen, char **_retval)
+encode(const uint8_t* data, uint32_t srclen, char** result)
{
- SECStatus rv = SECSuccess;
- char *encoded = f_PL_Base64Encode((const char *)data, dataLen, nullptr);
- if (!encoded)
- rv = SECFailure;
- if (!*encoded)
- rv = SECFailure;
-
- if (rv == SECSuccess) {
- *_retval = (char *)malloc(strlen(encoded)+1);
- strcpy(*_retval, encoded);
+ if (srclen > (PR_UINT32_MAX / 4) * 3) {
+ return SECFailure;
}
- if (encoded) {
- f_PR_Free(encoded);
+ const uint32_t dstlen = ((srclen + 2) / 3) * 4;
+ char* const buffer = static_cast<char*>(malloc(dstlen + 1));
+
+ if (!buffer || !f_PL_Base64Encode(reinterpret_cast<const char*>(data), srclen, buffer)) {
+ free(buffer);
+ *result = nullptr;
+ return SECFailure;
}
- return rv;
+ buffer[dstlen] = '\0';
+ *result = buffer;
+ return SECSuccess;
}
/*
* Base64 decodes the data passed in. The caller must deallocate result using free();
*/
SECStatus
-decode(const char *data, unsigned char **result, int32_t *length)
+decode(const char* data, uint8_t** result, uint32_t* length)
{
- SECStatus rv = SECSuccess;
- uint32_t len = strlen(data);
- int adjust = 0;
-
- /* Compute length adjustment */
- if (len > 0 && data[len-1] == '=') {
- adjust++;
- if (data[len-2] == '=') adjust++;
+ uint32_t srclen = strlen(data);
+ while (srclen && data[srclen - 1] == '=') {
+ srclen--;
}
- char *decoded;
- decoded = f_PL_Base64Decode(data, len, nullptr);
- if (!decoded) {
- return SECFailure;
- }
- if (!*decoded) {
+ // Avoid overflow when calculating result length.
+ const uint32_t dstlen = (srclen / 4) * 3 + ((srclen % 4) * 3) / 4;
+ // At most 2 extra bytes due to padding in input.
+ uint8_t* const buffer = static_cast<uint8_t*>(malloc(dstlen + 2));
+
+ if (!buffer || !f_PL_Base64Decode(data, srclen, reinterpret_cast<char*>(buffer))) {
+ free(buffer);
+ *result = nullptr;
+ *length = 0;
return SECFailure;
}
- *length = (len*3)/4 - adjust;
- LOG("Decoded %i chars into %i chars\n", len, *length);
-
- *result = (unsigned char*)malloc((size_t)len);
-
- if (!*result) {
- rv = SECFailure;
- } else {
- memcpy((char*)*result, decoded, len);
- }
- f_PR_Free(decoded);
- return rv;
+ buffer[dstlen] = '\0';
+ *result = buffer;
+ *length = dstlen;
+ return SECSuccess;
}
-
-
diff --git a/mozglue/android/NSSBridge.h b/mozglue/android/NSSBridge.h
index 77bcd1172..83ec8d749 100644
--- a/mozglue/android/NSSBridge.h
+++ b/mozglue/android/NSSBridge.h
@@ -39,8 +39,4 @@ NSS_WRAPPER(PK11_GetInternalKeySlot, PK11SlotInfo *, void)
NSS_WRAPPER(PK11_NeedUserInit, PRBool, PK11SlotInfo *)
NSS_WRAPPER(PK11_InitPin, SECStatus, PK11SlotInfo*, const char*, const char*)
-bool setPassword(PK11SlotInfo *slot);
-SECStatus doCrypto(JNIEnv* jenv, const char *path, const char *value, char** result, bool doEncrypt);
-SECStatus encode(const unsigned char *data, int32_t dataLen, char **_retval);
-SECStatus decode(const char *data, unsigned char **result, int32_t * _retval);
#endif /* NSS_h */
diff --git a/netwerk/sctp/datachannel/DataChannel.cpp b/netwerk/sctp/datachannel/DataChannel.cpp
index bf7790f51..d47a9d5ea 100644
--- a/netwerk/sctp/datachannel/DataChannel.cpp
+++ b/netwerk/sctp/datachannel/DataChannel.cpp
@@ -646,6 +646,7 @@ DataChannelConnection::SctpDtlsInput(TransportFlow *flow,
}
}
// Pass the data to SCTP
+ MutexAutoLock lock(mLock);
usrsctp_conninput(static_cast<void *>(this), data, len, 0);
}
@@ -1016,7 +1017,7 @@ DataChannelConnection::SendDeferredMessages()
bool still_blocked = false;
// This may block while something is modifying channels, but should not block for IO
- MutexAutoLock lock(mLock);
+ mLock.AssertCurrentThreadOwns();
// XXX For total fairness, on a still_blocked we'd start next time at the
// same index. Sorry, not going to bother for now.
@@ -1923,7 +1924,7 @@ DataChannelConnection::ReceiveCallback(struct socket* sock, void *data, size_t d
if (!data) {
usrsctp_close(sock); // SCTP has finished shutting down
} else {
- MutexAutoLock lock(mLock);
+ mLock.AssertCurrentThreadOwns();
if (flags & MSG_NOTIFICATION) {
HandleNotification(static_cast<union sctp_notification *>(data), datalen);
} else {