This commit is contained in:
Ryan VanderMeulen 2014-09-09 19:26:59 -04:00
Родитель 8777ff4fa0 2691734865
Коммит ca03f2d467
145 изменённых файлов: 5508 добавлений и 4384 удалений

Просмотреть файл

@ -3,5 +3,7 @@ skip-if = e10s # Bug 942707 - PDF viewer doesn't work with e10s.
support-files = file_pdfjs_test.pdf
[browser_pdfjs_main.js]
skip-if = debug # bug 1058695
[browser_pdfjs_savedialog.js]
[browser_pdfjs_views.js]
skip-if = debug # bug 1058695

Просмотреть файл

@ -1188,7 +1188,7 @@ public:
* Should only be called during MediaStreamListener callbacks or during
* ProcessedMediaStream::ProcessInput().
*/
void DispatchToMainThreadAfterStreamStateUpdate(already_AddRefed<nsIRunnable> aRunnable)
virtual void DispatchToMainThreadAfterStreamStateUpdate(already_AddRefed<nsIRunnable> aRunnable)
{
*mPendingUpdateRunnables.AppendElement() = aRunnable;
}

Просмотреть файл

@ -52,10 +52,13 @@
if (validStructuredMessage(message)) {
switch (message.action) {
case "test_status":
ok(message.expected === undefined, message.subtest, message.message);
break;
case "test_end":
ok(message.expected === undefined, message.test, message.message);
let test_tokens = message.test.split("/");
let test_name = test_tokens[test_tokens.length - 1];
if (message.subtest) {
test_name += " | " + message.subtest;
}
ok(message.expected === undefined, test_name, message.message);
break;
case "log":
info(message.message);

Просмотреть файл

@ -134,6 +134,7 @@ SVGSwitchElement::FindActiveChild() const
if (allowReorder && !acceptLangs.IsEmpty()) {
int32_t bestLanguagePreferenceRank = -1;
nsIContent *bestChild = nullptr;
nsIContent *defaultChild = nullptr;
for (nsIContent* child = nsINode::GetFirstChild();
child;
child = child->GetNextSibling()) {
@ -152,7 +153,12 @@ SVGSwitchElement::FindActiveChild() const
// best possible match
return child;
case -1:
// not found
// no match
break;
case -2:
// no systemLanguage attribute. If there's nothing better
// we'll use the last such child.
defaultChild = child;
break;
default:
if (bestLanguagePreferenceRank == -1 ||
@ -167,7 +173,7 @@ SVGSwitchElement::FindActiveChild() const
bestChild = child;
}
}
return bestChild;
return bestChild ? bestChild : defaultChild;
}
for (nsIContent* child = nsINode::GetFirstChild();

Просмотреть файл

@ -77,6 +77,10 @@ SVGTests::GetBestLanguagePreferenceRank(const nsSubstring& aAcceptLangs) const
{
const nsDefaultStringComparator defaultComparator;
if (!mStringListAttributes[LANGUAGE].IsExplicitlySet()) {
return -2;
}
int32_t lowestRank = -1;
for (uint32_t i = 0; i < mStringListAttributes[LANGUAGE].Length(); i++) {

Просмотреть файл

@ -42,7 +42,8 @@ public:
* exactly equals one of the language names or exactly equals a prefix of
* one of the language names in the systemLanguage attribute.
* @returns 2 * the lowest index in the aAcceptLangs that matches + 1
* if only the prefix matches, or -1 if no indices match.
* if only the prefix matches, -2 if there's no systemLanguage attribute,
* or -1 if no indices match.
* XXX This algorithm is O(M*N).
*/
int32_t GetBestLanguagePreferenceRank(const nsSubstring& aAcceptLangs) const;

Просмотреть файл

@ -7,6 +7,6 @@
<switch id="s">
<rect systemLanguage="fr" id="first" x="75" y="100" width="70" height="70" fill="yellow"/>
<rect id="second" x="75" y="100" width="50" height="50" fill="lime"/>
<rect x="75" y="100" width="80" height="80" fill="red"/>
<rect id="third" x="75" y="100" width="80" height="80" fill="red"/>
</switch>
</svg>

До

Ширина:  |  Высота:  |  Размер: 478 B

После

Ширина:  |  Высота:  |  Размер: 489 B

Просмотреть файл

@ -34,7 +34,7 @@ function checkBounds(element, x, y, w, h)
++test;
}
function checkWidth(element, x, y, w, h)
function checkWidth(element, w)
{
var bbox = element.getBBox();
var name = element.nodeName;
@ -56,6 +56,7 @@ function run1()
var s = doc.getElementById("s");
var first = doc.getElementById("first");
var second = doc.getElementById("second");
var third = doc.getElementById("third");
/* test for an exact match */
second.setAttribute("systemLanguage", "en-gb");
@ -63,11 +64,11 @@ function run1()
/* test for a close match i.e. the same language prefix */
second.setAttribute("systemLanguage", "en-us");
checkWidth(s, 75, 100, 50, 50);
checkWidth(s, 50);
/* test that we pick the first match */
first.setAttribute("systemLanguage", "it");
checkWidth(s, 75, 100, 70, 70);
checkWidth(s, 70);
/* this time with reordering */
first.setAttribute("systemLanguage", "fr");
@ -75,20 +76,33 @@ function run1()
/* test for an exact match */
second.setAttribute("systemLanguage", "en-gb");
checkWidth(s, 75, 100, 50, 50);
checkWidth(s, 50);
/* test for a close match i.e. the same language prefix */
second.setAttribute("systemLanguage", "en-us");
checkWidth(s, 75, 100, 50, 50);
checkWidth(s, 50);
/* test that we pick the best match */
second.setAttribute("systemLanguage", "it");
checkWidth(s, 75, 100, 50, 50);
checkWidth(s, 50);
/* test that we use the default if nothing matches */
second.setAttribute("systemLanguage", "fr");
checkWidth(s, 80);
/* test we still ignore non-matches */
second.removeAttribute("systemLanguage");
third.setAttribute("systemLanguage", "fr");
checkWidth(s, 50);
/* check what happens if nothing matches */
second.setAttribute("systemLanguage", "fr");
checkWidth(s, 0);
/* test that we pick the best match */
first.setAttribute("systemLanguage", "en");
second.setAttribute("systemLanguage", "en-gb");
checkWidth(s, 75, 100, 50, 50);
checkWidth(s, 50);
} finally {
SimpleTest.finish();

Просмотреть файл

@ -349,7 +349,7 @@ public:
(*p >= 0x61 && *p <= 0x7A)) {
mValue.Append(*p);
} else {
mValue.AppendPrintf("%%%X", *p);
mValue.AppendPrintf("%%%.2X", *p);
}
++p;

Просмотреть файл

@ -25,6 +25,7 @@ skip-if = buildapp == 'mulet'
[test_bug999456.html]
[test_bug1022229.html]
[test_bug1043106.html]
[test_bug1064481.html]
[test_clearTimeoutIntervalNoArg.html]
[test_consoleEmptyStack.html]
[test_constructor-assignment.html]

Просмотреть файл

@ -0,0 +1,24 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1064481
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1064481</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1064481">Mozilla Bug 1064481</a>
<iframe id="iframe"></iframe>
<script type="application/javascript">
var a = new URLSearchParams();
a.set('foobar', 'a\nb');
is(a.toString(), 'foobar=a%0Ab', "Bug fixed");
</script>
</body>
</html>

Просмотреть файл

@ -38,7 +38,7 @@ protected:
bool StringifyToJSON(JSContext* aCx,
JS::MutableHandle<JS::Value> aValue,
nsAString& aJSON);
nsAString& aJSON) const;
private:
// aString is expected to actually be an nsAString*. Should only be
// called from StringifyToJSON.

Просмотреть файл

@ -1635,7 +1635,7 @@ DictionaryBase::ParseJSON(JSContext* aCx,
bool
DictionaryBase::StringifyToJSON(JSContext* aCx,
JS::MutableHandle<JS::Value> aValue,
nsAString& aJSON)
nsAString& aJSON) const
{
return JS_Stringify(aCx, aValue, JS::NullPtr(), JS::NullHandleValue,
AppendJSONToString, &aJSON);

Просмотреть файл

@ -11240,7 +11240,7 @@ class CGDictionary(CGThing):
JSAutoCompartment ac(cx, xpc::UnprivilegedJunkScope()); // Usage approved by bholley
JS::Rooted<JS::Value> obj(cx);
return ToObjectInternal(cx, &obj) && StringifyToJSON(cx, &obj, aJSON);
"""))
"""), const=True)
def toObjectInternalMethod(self):
body = ""

Просмотреть файл

@ -19,6 +19,13 @@ using namespace mozilla::dom;
namespace mozilla {
void
FakeMediaStreamGraph::DispatchToMainThreadAfterStreamStateUpdate(already_AddRefed<nsIRunnable> aRunnable)
{
nsRefPtr<nsIRunnable> task = aRunnable;
NS_DispatchToMainThread(task);
}
CameraPreviewMediaStream::CameraPreviewMediaStream(DOMMediaStream* aWrapper)
: MediaStream(aWrapper)
, mMutex("mozilla::camera::CameraPreviewMediaStream")
@ -27,6 +34,7 @@ CameraPreviewMediaStream::CameraPreviewMediaStream(DOMMediaStream* aWrapper)
, mRateLimit(false)
{
SetGraphImpl(MediaStreamGraph::GetInstance());
mFakeMediaStreamGraph = new FakeMediaStreamGraph();
mIsConsumed = false;
}
@ -55,11 +63,10 @@ CameraPreviewMediaStream::AddVideoOutput(VideoFrameContainer* aContainer)
if (mVideoOutputs.Length() > 1) {
return;
}
MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
mIsConsumed = true;
for (uint32_t j = 0; j < mListeners.Length(); ++j) {
MediaStreamListener* l = mListeners[j];
l->NotifyConsumptionChanged(gm, MediaStreamListener::CONSUMED);
l->NotifyConsumptionChanged(mFakeMediaStreamGraph, MediaStreamListener::CONSUMED);
}
}
@ -72,11 +79,10 @@ CameraPreviewMediaStream::RemoveVideoOutput(VideoFrameContainer* aContainer)
if (!mVideoOutputs.IsEmpty()) {
return;
}
MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
mIsConsumed = false;
for (uint32_t j = 0; j < mListeners.Length(); ++j) {
MediaStreamListener* l = mListeners[j];
l->NotifyConsumptionChanged(gm, MediaStreamListener::NOT_CONSUMED);
l->NotifyConsumptionChanged(mFakeMediaStreamGraph, MediaStreamListener::NOT_CONSUMED);
}
}
@ -90,9 +96,9 @@ CameraPreviewMediaStream::AddListener(MediaStreamListener* aListener)
{
MutexAutoLock lock(mMutex);
MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
MediaStreamListener* listener = *mListeners.AppendElement() = aListener;
listener->NotifyBlockingChanged(gm, MediaStreamListener::UNBLOCKED);
listener->NotifyBlockingChanged(mFakeMediaStreamGraph, MediaStreamListener::UNBLOCKED);
listener->NotifyHasCurrentData(mFakeMediaStreamGraph);
}
void
@ -100,10 +106,9 @@ CameraPreviewMediaStream::RemoveListener(MediaStreamListener* aListener)
{
MutexAutoLock lock(mMutex);
MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
nsRefPtr<MediaStreamListener> listener(aListener);
mListeners.RemoveElement(aListener);
listener->NotifyEvent(gm, MediaStreamListener::EVENT_REMOVED);
listener->NotifyEvent(mFakeMediaStreamGraph, MediaStreamListener::EVENT_REMOVED);
}
void

Просмотреть файл

@ -11,6 +11,23 @@
namespace mozilla {
class FakeMediaStreamGraph : public MediaStreamGraph
{
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FakeMediaStreamGraph)
public:
FakeMediaStreamGraph()
: MediaStreamGraph()
{
}
virtual void
DispatchToMainThreadAfterStreamStateUpdate(already_AddRefed<nsIRunnable> aRunnable) MOZ_OVERRIDE;
protected:
~FakeMediaStreamGraph()
{}
};
/**
* This is a stream for camera preview.
*
@ -50,6 +67,7 @@ protected:
int32_t mInvalidatePending;
uint32_t mDiscardedFrames;
bool mRateLimit;
nsRefPtr<FakeMediaStreamGraph> mFakeMediaStreamGraph;
};
}

Просмотреть файл

@ -51,10 +51,13 @@
if (validStructuredMessage(message)) {
switch (message.action) {
case "test_status":
ok(message.expected === undefined, message.subtest, message.message);
break;
case "test_end":
ok(message.expected === undefined, message.test, message.message);
let test_tokens = message.test.split("/");
let test_name = test_tokens[test_tokens.length - 1];
if (message.subtest) {
test_name += " | " + message.subtest;
}
ok(message.expected === undefined, test_name, message.message);
break;
case "log":
info(message.message);

Просмотреть файл

@ -67,10 +67,13 @@
if (validStructuredMessage(message)) {
switch (message.action) {
case "test_status":
ok(message.expected === undefined, message.subtest, message.message);
break;
case "test_end":
ok(message.expected === undefined, message.test, message.message);
let test_tokens = message.test.split("/");
let test_name = test_tokens[test_tokens.length - 1];
if (message.subtest) {
test_name += " | " + message.subtest;
}
ok(message.expected === undefined, test_name, message.message);
break;
case "log":
info(message.message);

Просмотреть файл

@ -8,7 +8,7 @@
interface nsIDocument;
interface nsIURI;
[uuid(8d2f64db-5585-4876-a1c9-391e16549068)]
[builtinclass, uuid(79ad5b57-d65d-46d3-b5e9-32d27e16052d)]
interface nsIServiceWorkerManager : nsISupports
{
/**

Просмотреть файл

@ -2641,8 +2641,9 @@ ContentParent::Observe(nsISupports* aSubject,
MOZ_ASSERT(cmsg[identOffset - 1] == '=');
FileDescriptor dmdFileDesc;
#ifdef MOZ_DMD
FILE *dmdFile;
nsAutoString dmdIdent(Substring(msg, identOffset));
if (!dmdIdent.IsEmpty()) {
FILE *dmdFile = nullptr;
nsresult rv = nsMemoryInfoDumper::OpenDMDFile(dmdIdent, Pid(), &dmdFile);
if (NS_WARN_IF(NS_FAILED(rv))) {
// Proceed with the memory report as if DMD were disabled.
@ -2652,6 +2653,7 @@ ContentParent::Observe(nsISupports* aSubject,
dmdFileDesc = FILEToFileDescriptor(dmdFile);
fclose(dmdFile);
}
}
#endif
unused << SendPMemoryReportRequestConstructor(
generation, anonymize, minimize, dmdFileDesc);

Просмотреть файл

@ -555,7 +555,46 @@ RTCPeerConnection.prototype = {
},
createOffer: function(onSuccess, onError, options) {
options = options || {};
// TODO: Remove old constraint-like RTCOptions support soon (Bug 1064223).
function convertLegacyOptions(o) {
if (!(o.mandatory || o.optional) ||
Object.keys(o).length != ((o.mandatory && o.optional)? 2 : 1)) {
return false;
}
let old = o.mandatory || {};
if (o.mandatory) {
delete o.mandatory;
}
if (o.optional) {
o.optional.forEach(one => {
// The old spec had optional as an array of objects w/1 attribute each.
// Assumes our JS-webidl bindings only populate passed-in properties.
let key = Object.keys(one)[0];
if (key && old[key] === undefined) {
old[key] = one[key];
}
});
delete o.optional;
}
o.offerToReceiveAudio = old.OfferToReceiveAudio;
o.offerToReceiveVideo = old.OfferToReceiveVideo;
o.mozDontOfferDataChannel = old.MozDontOfferDataChannel;
o.mozBundleOnly = old.MozBundleOnly;
Object.keys(o).forEach(k => {
if (o[k] === undefined) {
delete o[k];
}
});
return true;
}
if (options && convertLegacyOptions(options)) {
this.logWarning(
"Mandatory/optional in createOffer options is deprecated! Use " +
JSON.stringify(options) + " instead (note the case difference)!",
null, 0);
}
this._queueOrRun({
func: this._createOffer,
args: [onSuccess, onError, options],
@ -598,6 +637,12 @@ RTCPeerConnection.prototype = {
},
setLocalDescription: function(desc, onSuccess, onError) {
if (!onSuccess || !onError) {
this.logWarning(
"setLocalDescription called without success/failure callbacks. This is deprecated, and will be an error in the future.",
null, 0);
}
this._localType = desc.type;
let type;
@ -629,6 +674,11 @@ RTCPeerConnection.prototype = {
},
setRemoteDescription: function(desc, onSuccess, onError) {
if (!onSuccess || !onError) {
this.logWarning(
"setRemoteDescription called without success/failure callbacks. This is deprecated, and will be an error in the future.",
null, 0);
}
this._remoteType = desc.type;
let type;
@ -765,6 +815,11 @@ RTCPeerConnection.prototype = {
},
addIceCandidate: function(cand, onSuccess, onError) {
if (!onSuccess || !onError) {
this.logWarning(
"addIceCandidate called without success/failure callbacks. This is deprecated, and will be an error in the future.",
null, 0);
}
if (!cand.candidate && !cand.sdpMLineIndex) {
throw new this._win.DOMError("",
"Invalid candidate passed to addIceCandidate!");

Просмотреть файл

@ -60,10 +60,13 @@
if (validStructuredMessage(message)) {
switch (message.action) {
case "test_status":
ok(message.expected === undefined, message.subtest, message.message);
break;
case "test_end":
ok(message.expected === undefined, message.test, message.message);
let test_tokens = message.test.split("/");
let test_name = test_tokens[test_tokens.length - 1];
if (message.subtest) {
test_name += " | " + message.subtest;
}
ok(message.expected === undefined, test_name, message.message);
break;
case "log":
info(message.message);

Просмотреть файл

@ -547,6 +547,8 @@ function PeerConnectionTest(options) {
else
this.pcRemote = null;
this.steeplechase = this.pcLocal === null || this.pcRemote === null;
// Create command chain instance and assign default commands
this.chain = new CommandChain(this, options.commands);
if (!options.is_local) {
@ -863,10 +865,109 @@ PCT_iceCandidateHandler(caller, candidate) {
target.storeOrAddIceCandidate(candidate);
} else {
info("sending ice candidate to signaling server");
send_message({"ice_candidate": candidate});
send_message({"type": "ice_candidate", "ice_candidate": candidate});
}
};
/**
* Installs a polling function for the socket.io client to read
* all messages from the chat room into a message queue.
*/
PeerConnectionTest.prototype.setupSignalingClient = function
PCT_setupSignalingClient() {
var self = this;
self.signalingMessageQueue = [];
self.signalingCallbacks = {};
self.signalingLoopRun = true;
function queueMessage(message) {
info("Received signaling message: " + JSON.stringify(message));
var fired = false;
Object.keys(self.signalingCallbacks).forEach(function(name) {
if (name === message.type) {
info("Invoking callback for message type: " + name);
self.signalingCallbacks[name](message);
fired = true;
}
});
if (!fired) {
self.signalingMessageQueue.push(message);
info("signalingMessageQueue.length: " + self.signalingMessageQueue.length);
}
if (self.signalingLoopRun) {
wait_for_message().then(queueMessage);
} else {
info("Exiting signaling message event loop");
}
}
wait_for_message().then(queueMessage);
}
/**
* Sets a flag to stop reading further messages from the chat room.
*/
PeerConnectionTest.prototype.signalingMessagesFinished = function
PCT_signalingMessagesFinished() {
this.signalingLoopRun = false;
}
/**
* Callback to stop reading message from chat room once trickle ICE
* on the far end is over.
*
* @param {string} caller
* The lable of the caller of the function
*/
PeerConnectionTest.prototype.signalEndOfTrickleIce = function
PCT_signalEndOfTrickleIce(caller) {
if (this.steeplechase) {
send_message({"type": "end_of_trickle_ice"});
}
};
/**
* Register a callback function to deliver messages from the chat room
* directly instead of storing them in the message queue.
*
* @param {string} messageType
* For which message types should the callback get invoked.
*
* @param {function} onMessage
* The function which gets invoked if a message of the messageType
* has been received from the chat room.
*/
PeerConnectionTest.prototype.registerSignalingCallback = function
PCT_registerSignalingCallback(messageType, onMessage) {
this.signalingCallbacks[messageType] = onMessage;
}
/**
* Searches the message queue for the first message of a given type
* and invokes the given callback function, or registers the callback
* function for future messages if the queue contains no such message.
*
* @param {string} messageType
* The type of message to search and register for.
*
* @param {function} onMessage
* The callback function which gets invoked with the messages
* of the given mesage type.
*/
PeerConnectionTest.prototype.getSignalingMessage = function
PCT_getSignalingMessage(messageType, onMessage) {
for(var i=0; i < this.signalingMessageQueue.length; i++) {
if (messageType === this.signalingMessageQueue[i].type) {
//FIXME
info("invoking callback on message " + i + " from message queue, for message type:" + messageType);
onMessage(this.signalingMessageQueue.splice(i, 1)[0]);
return;
}
}
this.registerSignalingCallback(messageType, onMessage);
}
/**
* This class handles tests for data channels.
*
@ -1991,6 +2092,7 @@ PeerConnectionWrapper.prototype = {
if (!anEvent.candidate) {
info(self.label + ": received end of trickle ICE event");
self.endOfTrickleIce = true;
test.signalEndOfTrickleIce(self.label);
} else {
if (self.endOfTrickleIce) {
ok(false, "received ICE candidate after end of trickle");
@ -2005,8 +2107,6 @@ PeerConnectionWrapper.prototype = {
}
}
//FIXME: in the steeplecase scenario we need to setup a permanent listener
// for ice candidates from the signaling server here
self._pc.onicecandidate = iceCandidateCallback;
},
@ -2041,7 +2141,18 @@ PeerConnectionWrapper.prototype = {
if (!options) {
return 0;
}
if (options.offerToReceiveAudio) {
var offerToReceiveAudio = options.offerToReceiveAudio;
// TODO: Remove tests of old constraint-like RTCOptions soon (Bug 1064223).
if (options.mandatory && options.mandatory.OfferToReceiveAudio !== undefined) {
offerToReceiveAudio = options.mandatory.OfferToReceiveAudio;
} else if (options.optional && options.optional[0] &&
options.optional[0].OfferToReceiveAudio !== undefined) {
offerToReceiveAudio = options.optional[0].OfferToReceiveAudio;
}
if (offerToReceiveAudio) {
return 1;
} else {
return 0;
@ -2079,7 +2190,18 @@ PeerConnectionWrapper.prototype = {
if (!options) {
return 0;
}
if (options.offerToReceiveVideo) {
var offerToReceiveVideo = options.offerToReceiveVideo;
// TODO: Remove tests of old constraint-like RTCOptions soon (Bug 1064223).
if (options.mandatory && options.mandatory.OfferToReceiveVideo !== undefined) {
offerToReceiveVideo = options.mandatory.OfferToReceiveVideo;
} else if (options.optional && options.optional[0] &&
options.optional[0].OfferToReceiveVideo !== undefined) {
offerToReceiveVideo = options.optional[0].OfferToReceiveVideo;
}
if (offerToReceiveVideo) {
return 1;
} else {
return 0;

Просмотреть файл

@ -24,24 +24,27 @@ function dumpSdp(test) {
dump("ERROR: SDP answer: " + test._remote_answer.sdp.replace(/[\r]/g, ''));
}
if (typeof test.pcLocal.iceConnectionLog !== 'undefined') {
if ((test.pcLocal) && (typeof test.pcLocal.iceConnectionLog !== 'undefined')) {
dump("pcLocal ICE connection state log: " + test.pcLocal.iceConnectionLog + "\n");
}
if (typeof test.pcRemote.iceConnectionLog !== 'undefined') {
if ((test.pcRemote) && (typeof test.pcRemote.iceConnectionLog !== 'undefined')) {
dump("pcRemote ICE connection state log: " + test.pcRemote.iceConnectionLog + "\n");
}
if ((typeof test.pcLocal.setRemoteDescDate !== 'undefined') &&
if ((test.pcLocal) && (test.pcRemote) &&
(typeof test.pcLocal.setRemoteDescDate !== 'undefined') &&
(typeof test.pcRemote.setLocalDescDate !== 'undefined')) {
var delta = deltaSeconds(test.pcLocal.setRemoteDescDate, test.pcRemote.setLocalDescDate);
dump("Delay between pcLocal.setRemote <-> pcRemote.setLocal: " + delta + "\n");
}
if ((typeof test.pcLocal.setRemoteDescDate !== 'undefined') &&
if ((test.pcLocal) && (test.pcRemote) &&
(typeof test.pcLocal.setRemoteDescDate !== 'undefined') &&
(typeof test.pcLocal.setRemoteDescStableEventDate !== 'undefined')) {
var delta = deltaSeconds(test.pcLocal.setRemoteDescDate, test.pcLocal.setRemoteDescStableEventDate);
dump("Delay between pcLocal.setRemote <-> pcLocal.signalingStateStable: " + delta + "\n");
}
if ((typeof test.pcRemote.setLocalDescDate !== 'undefined') &&
if ((test.pcLocal) && (test.pcRemote) &&
(typeof test.pcRemote.setLocalDescDate !== 'undefined') &&
(typeof test.pcRemote.setLocalDescStableEventDate !== 'undefined')) {
var delta = deltaSeconds(test.pcRemote.setLocalDescDate, test.pcRemote.setLocalDescStableEventDate);
dump("Delay between pcRemote.setLocal <-> pcRemote.signalingStateStable: " + delta + "\n");
@ -49,6 +52,22 @@ function dumpSdp(test) {
}
var commandsPeerConnection = [
[
'PC_SETUP_SIGNALING_CLIENT',
function (test) {
if (test.steeplechase) {
test.setupSignalingClient();
test.registerSignalingCallback("ice_candidate", function (message) {
var pc = test.pcRemote ? test.pcRemote : test.pcLocal;
pc.storeOrAddIceCandidate(new mozRTCIceCandidate(message.ice_candidate));
});
test.registerSignalingCallback("end_of_trickle_ice", function (message) {
test.signalingMessagesFinished();
});
}
test.next();
}
],
[
'PC_LOCAL_SETUP_ICE_LOGGER',
function (test) {
@ -145,11 +164,12 @@ var commandsPeerConnection = [
test.createOffer(test.pcLocal, function (offer) {
is(test.pcLocal.signalingState, STABLE,
"Local create offer does not change signaling state");
if (!test.pcRemote) {
send_message({"offer": test.originalOffer,
if (test.steeplechase) {
send_message({"type": "offer",
"offer": test.originalOffer,
"offer_constraints": test.pcLocal.constraints,
"offer_options": test.pcLocal.offerOptions});
test._local_offer = test.pcLocal._last_offer;
test._local_offer = test.originalOffer;
test._offer_constraints = test.pcLocal.constraints;
test._offer_options = test.pcLocal.offerOptions;
}
@ -170,13 +190,13 @@ var commandsPeerConnection = [
[
'PC_REMOTE_GET_OFFER',
function (test) {
if (test.pcLocal) {
if (!test.steeplechase) {
test._local_offer = test.originalOffer;
test._offer_constraints = test.pcLocal.constraints;
test._offer_options = test.pcLocal.offerOptions;
test.next();
} else {
wait_for_message().then(function(message) {
test.getSignalingMessage("offer", function (message) {
ok("offer" in message, "Got an offer message");
test._local_offer = new mozRTCSessionDescription(message.offer);
test._offer_constraints = message.offer_constraints;
@ -224,8 +244,9 @@ var commandsPeerConnection = [
test.createAnswer(test.pcRemote, function (answer) {
is(test.pcRemote.signalingState, HAVE_REMOTE_OFFER,
"Remote createAnswer does not change signaling state");
if (!test.pcLocal) {
send_message({"answer": test.originalAnswer,
if (test.steeplechase) {
send_message({"type": "answer",
"answer": test.originalAnswer,
"answer_constraints": test.pcRemote.constraints});
test._remote_answer = test.pcRemote._last_answer;
test._answer_constraints = test.pcRemote.constraints;
@ -261,7 +282,7 @@ var commandsPeerConnection = [
return resultArray;
}
const offerTriples = _sdpCandidatesIntoArray(test.originalOffer.sdp);
const offerTriples = _sdpCandidatesIntoArray(test._local_offer.sdp);
info("Offer ICE host candidates: " + JSON.stringify(offerTriples));
const answerTriples = _sdpCandidatesIntoArray(test.originalAnswer.sdp);
@ -269,7 +290,7 @@ var commandsPeerConnection = [
for (var i=0; i< offerTriples.length; i++) {
if (answerTriples.indexOf(offerTriples[i]) !== -1) {
dump("SDP offer: " + test.originalOffer.sdp.replace(/[\r]/g, '') + "\n");
dump("SDP offer: " + test._local_offer.sdp.replace(/[\r]/g, '') + "\n");
dump("SDP answer: " + test.originalAnswer.sdp.replace(/[\r]/g, '') + "\n");
ok(false, "This IP:Port " + offerTriples[i] + " appears in SDP offer and answer!");
}
@ -293,12 +314,12 @@ var commandsPeerConnection = [
[
'PC_LOCAL_GET_ANSWER',
function (test) {
if (test.pcRemote) {
if (!test.steeplechase) {
test._remote_answer = test.originalAnswer;
test._answer_constraints = test.pcRemote.constraints;
test.next();
} else {
wait_for_message().then(function(message) {
test.getSignalingMessage("answer", function (message) {
ok("answer" in message, "Got an answer message");
test._remote_answer = new mozRTCSessionDescription(message.answer);
test._answer_constraints = message.answer_constraints;
@ -762,8 +783,9 @@ var commandsDataChannel = [
"Local create offer does not change signaling state");
ok(offer.sdp.contains("m=application"),
"m=application is contained in the SDP");
if (!test.pcRemote) {
send_message({"offer": test.originalOffer,
if (test.steeplechase) {
send_message({"type": "offer",
"offer": test.originalOffer,
"offer_constraints": test.pcLocal.constraints,
"offer_options": test.pcLocal.offerOptions});
test._local_offer = test.pcLocal._last_offer;
@ -788,13 +810,13 @@ var commandsDataChannel = [
[
'PC_REMOTE_GET_OFFER',
function (test) {
if (test.pcLocal) {
if (!test.steeplechase) {
test._local_offer = test.originalOffer;
test._offer_constraints = test.pcLocal.constraints;
test._offer_options = test.pcLocal.offerOptions;
test.next();
} else {
wait_for_message().then(function(message) {
test.getSignalingMessage("offer", function (message) {
ok("offer" in message, "Got an offer message");
test._local_offer = new mozRTCSessionDescription(message.offer);
test._offer_constraints = message.offer_constraints;
@ -845,8 +867,9 @@ var commandsDataChannel = [
"Remote createAnswer does not change signaling state");
ok(answer.sdp.contains("m=application"),
"m=application is contained in the SDP");
if (!test.pcLocal) {
send_message({"answer": test.originalAnswer,
if (test.steeplechase) {
send_message({"type":"answer",
"answer": test.originalAnswer,
"answer_constraints": test.pcRemote.constraints});
test._remote_answer = test.pcRemote._last_answer;
test._answer_constraints = test.pcRemote.constraints;
@ -892,12 +915,12 @@ var commandsDataChannel = [
[
'PC_LOCAL_GET_ANSWER',
function (test) {
if (test.pcRemote) {
if (!test.steeplechase) {
test._remote_answer = test.originalAnswer;
test._answer_constraints = test.pcRemote.constraints;
test.next();
} else {
wait_for_message().then(function(message) {
test.getSignalingMessage("answer", function (message) {
ok("answer" in message, "Got an answer message");
test._remote_answer = new mozRTCSessionDescription(message.answer);
test._answer_constraints = message.answer_constraints;

Просмотреть файл

@ -18,7 +18,10 @@
runNetworkTest(function() {
var test = new PeerConnectionTest();
test.setOfferOptions({ offerToReceiveAudio: true });
// TODO: Stop using old constraint-like RTCOptions soon (Bug 1064223).
// Watch out for case-difference when fixing: { offerToReceiveAudio: true }
test.setOfferOptions({ mandatory: { OfferToReceiveAudio: true } });
test.run();
});
</script>

Просмотреть файл

@ -18,7 +18,9 @@
runNetworkTest(function() {
var test = new PeerConnectionTest();
test.setOfferOptions({ offerToReceiveVideo: true });
// TODO: Stop using old constraint-like RTCOptions soon (Bug 1064223).
// Watch out for case-difference when fixing: { offerToReceiveVideo: true }
test.setOfferOptions({ optional: [{ OfferToReceiveAudio: true }] });
test.run();
});
</script>

Просмотреть файл

@ -55,8 +55,19 @@ dictionary RTCDataChannelInit {
dictionary RTCOfferOptions {
long offerToReceiveVideo;
long offerToReceiveAudio;
boolean MozDontOfferDataChannel;
boolean MozBundleOnly;
boolean mozDontOfferDataChannel;
boolean mozBundleOnly;
// TODO: Remove old constraint-like RTCOptions support soon (Bug 1064223).
DeprecatedRTCOfferOptionsSet mandatory;
sequence<DeprecatedRTCOfferOptionsSet> _optional;
};
dictionary DeprecatedRTCOfferOptionsSet {
boolean OfferToReceiveAudio; // Note the uppercase 'O'
boolean OfferToReceiveVideo; // Note the uppercase 'O'
boolean MozDontOfferDataChannel; // Note the uppercase 'M'
boolean MozBundleOnly; // Note the uppercase 'M'
};
interface RTCDataChannel;

Просмотреть файл

@ -343,7 +343,9 @@ ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo(const nsACString& a
ServiceWorkerRegistrationInfo::~ServiceWorkerRegistrationInfo()
{
MOZ_ASSERT(!IsControllingDocuments());
if (IsControllingDocuments()) {
NS_WARNING("ServiceWorkerRegistrationInfo is still controlling documents. This can be a bug or a leak in ServiceWorker API or in any other API that takes the document alive.");
}
}
//////////////////////////

Просмотреть файл

@ -853,7 +853,8 @@ AsyncPanZoomController::AsyncPanZoomController(uint64_t aLayersId,
mTouchBlockBalance(0),
mTreeManager(aTreeManager),
mAPZCId(sAsyncPanZoomControllerCount++),
mSharedLock(nullptr)
mSharedLock(nullptr),
mAsyncTransformAppliedToContent(false)
{
MOZ_COUNT_CTOR(AsyncPanZoomController);
@ -2434,6 +2435,7 @@ bool AsyncPanZoomController::AdvanceAnimations(const TimeStamp& aSampleTime)
// fling is happening, it has to keep compositing so that the animation is
// smooth. If an animation frame is requested, it is the compositor's
// responsibility to schedule a composite.
mAsyncTransformAppliedToContent = false;
bool requestAnimationFrame = false;
Vector<Task*> deferredTasks;

Просмотреть файл

@ -1110,9 +1110,22 @@ public:
mTestAsyncScrollOffset = aPoint;
}
void MarkAsyncTransformAppliedToContent()
{
mAsyncTransformAppliedToContent = true;
}
bool GetAsyncTransformAppliedToContent() const
{
return mAsyncTransformAppliedToContent;
}
private:
// Extra offset to add in SampleContentTransformForFrame for testing
CSSPoint mTestAsyncScrollOffset;
// Flag to track whether or not the APZ transform is not used. This
// flag is recomputed for every composition frame.
bool mAsyncTransformAppliedToContent;
};
class AsyncPanZoomAnimation {

Просмотреть файл

@ -138,7 +138,8 @@ GetBaseTransform2D(Layer* aLayer, Matrix* aTransform)
static void
TranslateShadowLayer2D(Layer* aLayer,
const gfxPoint& aTranslation)
const gfxPoint& aTranslation,
bool aAdjustClipRect)
{
// This layer might also be a scrollable layer and have an async transform.
// To make sure we don't clobber that, we start with the shadow transform.
@ -173,7 +174,7 @@ TranslateShadowLayer2D(Layer* aLayer,
layerComposite->SetShadowTransformSetByAnimation(false);
const nsIntRect* clipRect = aLayer->GetClipRect();
if (clipRect) {
if (aAdjustClipRect && clipRect) {
nsIntRect transformedClipRect(*clipRect);
transformedClipRect.MoveBy(aTranslation.x, aTranslation.y);
layerComposite->SetShadowClipRect(&transformedClipRect);
@ -257,7 +258,7 @@ AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aLayer,
// aTransformedSubtreeRoot. Also, once we do encounter such a child, we don't
// need to recurse any deeper because the fixed layers are relative to their
// nearest scrollable layer.
if (aLayer == aTransformedSubtreeRoot || !isFixedOrSticky) {
if (!isFixedOrSticky) {
// ApplyAsyncContentTransformToTree will call this function again for
// nested scrollable layers, so we don't need to recurse if the layer is
// scrollable.
@ -349,8 +350,15 @@ AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aLayer,
IntervalOverlap(translation.x, stickyInner.x, stickyInner.XMost());
}
// Finally, apply the 2D translation to the layer transform.
TranslateShadowLayer2D(aLayer, ThebesPoint(translation));
// Finally, apply the 2D translation to the layer transform. Note that in
// general we need to apply the same translation to the layer's clip rect, so
// that the effective transform on the clip rect takes it back to where it was
// originally, had there been no async scroll. In the case where the
// fixed/sticky layer is the same as aTransformedSubtreeRoot, then the clip
// rect is not affected by the scroll-induced async scroll transform anyway
// (since the clip is applied post-transform) so we don't need to make the
// adjustment.
TranslateShadowLayer2D(aLayer, ThebesPoint(translation), aLayer != aTransformedSubtreeRoot);
}
static void
@ -504,16 +512,16 @@ SampleAnimations(Layer* aLayer, TimeStamp aPoint)
}
static bool
SampleAPZAnimations(const LayerMetricsWrapper& aLayer, TimeStamp aPoint)
SampleAPZAnimations(const LayerMetricsWrapper& aLayer, TimeStamp aSampleTime)
{
bool activeAnimations = false;
for (LayerMetricsWrapper child = aLayer.GetFirstChild(); child;
child = child.GetNextSibling()) {
activeAnimations |= SampleAPZAnimations(child, aPoint);
activeAnimations |= SampleAPZAnimations(child, aSampleTime);
}
if (AsyncPanZoomController* apzc = aLayer.GetApzc()) {
activeAnimations |= apzc->AdvanceAnimations(aPoint);
activeAnimations |= apzc->AdvanceAnimations(aSampleTime);
}
return activeAnimations;
@ -574,6 +582,10 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer)
scrollOffset,
&overscrollTransform);
if (!aLayer->IsScrollInfoLayer()) {
controller->MarkAsyncTransformAppliedToContent();
}
const FrameMetrics& metrics = aLayer->GetFrameMetrics(i);
CSSToLayerScale paintScale = metrics.LayersPixelsPerCSSPixel();
CSSRect displayPort(metrics.mCriticalDisplayPort.IsEmpty() ?

Просмотреть файл

@ -439,7 +439,8 @@ ContainerRender(ContainerT* aContainer,
// underlying layer.
for (LayerMetricsWrapper i(aContainer); i; i = i.GetFirstChild()) {
if (AsyncPanZoomController* apzc = i.GetApzc()) {
if (!Matrix4x4(apzc->GetCurrentAsyncTransform()).IsIdentity()) {
if (!apzc->GetAsyncTransformAppliedToContent()
&& !Matrix4x4(apzc->GetCurrentAsyncTransform()).IsIdentity()) {
aManager->UnusedApzTransformWarning();
break;
}

Просмотреть файл

@ -390,7 +390,6 @@ RasterImage::RasterImage(imgStatusTracker* aStatusTracker,
ImageResource(aURI), // invoke superclass's constructor
mSize(0,0),
mFrameDecodeFlags(DECODE_FLAGS_DEFAULT),
mAnim(nullptr),
mLockCount(0),
mDecodeCount(0),
mRequestedSampleSize(0),
@ -463,7 +462,6 @@ RasterImage::~RasterImage()
}
}
delete mAnim;
mAnim = nullptr;
// Total statistics
@ -1123,7 +1121,7 @@ RasterImage::EnsureAnimExists()
if (!mAnim) {
// Create the animation context
mAnim = new FrameAnimator(mFrameBlender, mAnimationMode);
mAnim = MakeUnique<FrameAnimator>(mFrameBlender, mAnimationMode);
// We don't support discarding animated images (See bug 414259).
// Lock the image and throw away the key.
@ -1646,7 +1644,6 @@ RasterImage::AddSourceData(const char *aBuffer, uint32_t aCount)
StopAnimation();
mAnimationFinished = false;
if (mAnim) {
delete mAnim;
mAnim = nullptr;
}
// If there's only one frame, this could cause flickering

Просмотреть файл

@ -35,6 +35,7 @@
#include "mozilla/TimeStamp.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/WeakPtr.h"
#include "mozilla/UniquePtr.h"
#ifdef DEBUG
#include "imgIContainerDebug.h"
#endif
@ -644,7 +645,7 @@ private: // data
// IMPORTANT: if you use mAnim in a method, call EnsureImageIsDecoded() first to ensure
// that the frames actually exist (they may have been discarded to save memory, or
// we maybe decoding on draw).
FrameAnimator* mAnim;
UniquePtr<FrameAnimator> mAnim;
// Discard members
uint32_t mLockCount;

Просмотреть файл

@ -1127,18 +1127,21 @@ class AsmJSModule
// the exported functions have been added.
bool addExportedFunction(PropertyName *name,
uint32_t srcStart,
uint32_t srcEnd,
uint32_t funcSrcBegin,
uint32_t funcSrcEnd,
PropertyName *maybeFieldName,
ArgCoercionVector &&argCoercions,
ReturnType returnType)
{
// NB: funcSrcBegin/funcSrcEnd are given relative to the ScriptSource
// (the entire file) and ExportedFunctions store offsets relative to
// the beginning of the module (so that they are caching-invariant).
JS_ASSERT(isFinishedWithFunctionBodies() && !isFinished());
ExportedFunction func(name, srcStart, srcEnd, maybeFieldName,
mozilla::Move(argCoercions), returnType);
if (exports_.length() >= UINT32_MAX)
return false;
return exports_.append(mozilla::Move(func));
JS_ASSERT(srcStart_ < funcSrcBegin);
JS_ASSERT(funcSrcBegin < funcSrcEnd);
ExportedFunction func(name, funcSrcBegin - srcStart_, funcSrcEnd - srcStart_,
maybeFieldName, mozilla::Move(argCoercions), returnType);
return exports_.length() < UINT32_MAX && exports_.append(mozilla::Move(func));
}
unsigned numExportedFunctions() const {
JS_ASSERT(isFinishedWithFunctionBodies());

Просмотреть файл

@ -1015,13 +1015,8 @@ class MOZ_STACK_CLASS ModuleCompiler
void define(ModuleCompiler &m, ParseNode *fn) {
JS_ASSERT(!defined_);
defined_ = true;
// The begin/end char range is relative to the beginning of the module.
// hence the assertions.
JS_ASSERT(fn->pn_pos.begin > m.srcStart());
JS_ASSERT(fn->pn_pos.begin <= fn->pn_pos.end);
srcBegin_ = fn->pn_pos.begin - m.srcStart();
srcEnd_ = fn->pn_pos.end - m.srcStart();
srcBegin_ = fn->pn_pos.begin;
srcEnd_ = fn->pn_pos.end;
}
uint32_t srcBegin() const { JS_ASSERT(defined_); return srcBegin_; }
@ -1462,7 +1457,6 @@ class MOZ_STACK_CLASS ModuleCompiler
Label &syncInterruptLabel() { return syncInterruptLabel_; }
bool hasError() const { return errorString_ != nullptr; }
const AsmJSModule &module() const { return *module_.get(); }
uint32_t srcStart() const { return module_->srcStart(); }
bool usesSignalHandlersForInterrupt() const { return module_->usesSignalHandlersForInterrupt(); }
bool usesSignalHandlersForOOB() const { return module_->usesSignalHandlersForOOB(); }
bool supportsSimd() const { return supportsSimd_; }

Просмотреть файл

@ -799,7 +799,7 @@ FuncConvert(JSContext *cx, unsigned argc, Value *vp)
Elem *val = TypedObjectMemory<Elem *>(args[0]);
RetElem result[Vret::lanes];
for (unsigned i = 0; i < Vret::lanes; i++)
result[i] = RetElem(val[i]);
result[i] = ConvertScalar<RetElem>(val[i]);
return StoreResult<Vret>(cx, args, result);
}

Просмотреть файл

@ -1296,6 +1296,12 @@ InitTypeClasses(JSContext* cx, HandleObject parent)
JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
return false;
// Alias 'ctypes.jschar' as 'ctypes.char16_t' to prevent breaking addons
// that are still using jschar (bug 1064935).
if (!JS_DefineProperty(cx, parent, "jschar", typeObj_char16_t,
JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
return false;
// Create objects representing the special types void_t and voidptr_t.
RootedObject typeObj(cx,
CType::DefineBuiltin(cx, parent, "void_t", CTypeProto, CDataProto, "void",

Просмотреть файл

@ -0,0 +1 @@
evalcx(" s = 3; s; for(let x = 0; x < 1; ++x) { null }", newGlobal())

Просмотреть файл

@ -0,0 +1,8 @@
(function() {
for (let x = 0; x < 1; ++x) {
if (x % 6 == 4) {} else {
return;
}
}
})()

Просмотреть файл

@ -0,0 +1,8 @@
// |jit-test| error: ReferenceError
eval("(function() { " + "\
var o = {};\
o.watch('p', function() { });\
for (var i = 0; i < 10; \u5ede ++)\
o.p = 123;\
" + " })();");

Просмотреть файл

@ -134,6 +134,9 @@ class BaselineFrame
uint8_t *pointer = (uint8_t *)this + Size() + offsetOfCalleeToken();
*(CalleeToken *)pointer = token;
}
bool isConstructing() const {
return CalleeTokenIsConstructing(calleeToken());
}
JSScript *script() const {
if (isEvalFrame())
return evalScript();

Просмотреть файл

@ -778,22 +778,6 @@ ICStubCompiler::emitPostWriteBarrierSlot(MacroAssembler &masm, Register obj, Val
//
// UseCount_Fallback
//
static bool
IsTopFrameConstructing(JSContext *cx)
{
JS_ASSERT(cx->currentlyRunningInJit());
JitActivationIterator activations(cx->runtime());
JitFrameIterator iter(activations);
JS_ASSERT(iter.type() == JitFrame_Exit);
++iter;
JS_ASSERT(iter.type() == JitFrame_BaselineStub);
++iter;
JS_ASSERT(iter.isBaselineJS());
return iter.isConstructing();
}
static bool
EnsureCanEnterIon(JSContext *cx, ICUseCount_Fallback *stub, BaselineFrame *frame,
@ -804,15 +788,14 @@ EnsureCanEnterIon(JSContext *cx, ICUseCount_Fallback *stub, BaselineFrame *frame
bool isLoopEntry = (JSOp(*pc) == JSOP_LOOPENTRY);
bool isConstructing = IsTopFrameConstructing(cx);
MethodStatus stat;
if (isLoopEntry) {
JS_ASSERT(LoopEntryCanIonOsr(pc));
JitSpew(JitSpew_BaselineOSR, " Compile at loop entry!");
stat = CanEnterAtBranch(cx, script, frame, pc, isConstructing);
stat = CanEnterAtBranch(cx, script, frame, pc);
} else if (frame->isFunctionFrame()) {
JitSpew(JitSpew_BaselineOSR, " Compile function from top for later entry!");
stat = CompileFunctionForBaseline(cx, script, frame, isConstructing);
stat = CompileFunctionForBaseline(cx, script, frame);
} else {
return true;
}

Просмотреть файл

@ -2195,8 +2195,7 @@ Compile(JSContext *cx, HandleScript script, BaselineFrame *osrFrame, jsbytecode
// Decide if a transition from interpreter execution to Ion code should occur.
// May compile or recompile the target JSScript.
MethodStatus
jit::CanEnterAtBranch(JSContext *cx, JSScript *script, BaselineFrame *osrFrame,
jsbytecode *pc, bool isConstructing)
jit::CanEnterAtBranch(JSContext *cx, JSScript *script, BaselineFrame *osrFrame, jsbytecode *pc)
{
JS_ASSERT(jit::IsIonEnabled(cx));
JS_ASSERT((JSOp)*pc == JSOP_LOOPENTRY);
@ -2230,7 +2229,8 @@ jit::CanEnterAtBranch(JSContext *cx, JSScript *script, BaselineFrame *osrFrame,
// - Returns Method_Skipped if pc doesn't match
// (This means a background thread compilation with that pc could have started or not.)
RootedScript rscript(cx, script);
MethodStatus status = Compile(cx, rscript, osrFrame, pc, isConstructing, SequentialExecution);
MethodStatus status = Compile(cx, rscript, osrFrame, pc, osrFrame->isConstructing(),
SequentialExecution);
if (status != Method_Compiled) {
if (status == Method_CantCompile)
ForbidCompilation(cx, script);
@ -2309,8 +2309,7 @@ jit::CanEnter(JSContext *cx, RunState &state)
}
MethodStatus
jit::CompileFunctionForBaseline(JSContext *cx, HandleScript script, BaselineFrame *frame,
bool isConstructing)
jit::CompileFunctionForBaseline(JSContext *cx, HandleScript script, BaselineFrame *frame)
{
JS_ASSERT(jit::IsIonEnabled(cx));
JS_ASSERT(frame->fun()->nonLazyScript()->canIonCompile());
@ -2326,7 +2325,7 @@ jit::CompileFunctionForBaseline(JSContext *cx, HandleScript script, BaselineFram
// Attempt compilation. Returns Method_Compiled if already compiled.
MethodStatus status =
Compile(cx, script, frame, nullptr, isConstructing, SequentialExecution);
Compile(cx, script, frame, nullptr, frame->isConstructing(), SequentialExecution);
if (status != Method_Compiled) {
if (status == Method_CantCompile)
ForbidCompilation(cx, script);

Просмотреть файл

@ -84,10 +84,9 @@ void SetIonContext(IonContext *ctx);
bool CanIonCompileScript(JSContext *cx, JSScript *script, bool osr);
MethodStatus CanEnterAtBranch(JSContext *cx, JSScript *script,
BaselineFrame *frame, jsbytecode *pc, bool isConstructing);
BaselineFrame *frame, jsbytecode *pc);
MethodStatus CanEnter(JSContext *cx, RunState &state);
MethodStatus CompileFunctionForBaseline(JSContext *cx, HandleScript script, BaselineFrame *frame,
bool isConstructing);
MethodStatus CompileFunctionForBaseline(JSContext *cx, HandleScript script, BaselineFrame *frame);
MethodStatus CanEnterUsingFastInvoke(JSContext *cx, HandleScript script, uint32_t numActualArgs);
MethodStatus CanEnterInParallel(JSContext *cx, HandleScript script);

Просмотреть файл

@ -2815,6 +2815,10 @@ SetPropertyIC::update(JSContext *cx, size_t cacheIndex, HandleObject obj,
RootedPropertyName name(cx, cache.name());
RootedId id(cx, AtomToId(name));
RootedTypeObject oldType(cx, obj->getType(cx));
if (!oldType)
return false;
// Stop generating new stubs once we hit the stub count limit, see
// GetPropertyCache.
NativeSetPropCacheability canCache = CanAttachNone;
@ -2846,12 +2850,6 @@ SetPropertyIC::update(JSContext *cx, size_t cacheIndex, HandleObject obj,
}
}
// Make sure the object de-lazifies its type. We do this here so that
// the parallel IC can share code that assumes that native objects all
// have a type object.
if (obj->isNative() && !obj->getType(cx))
return false;
RootedShape shape(cx);
RootedObject holder(cx);
bool checkTypeset;
@ -2873,7 +2871,6 @@ SetPropertyIC::update(JSContext *cx, size_t cacheIndex, HandleObject obj,
uint32_t oldSlots = obj->numDynamicSlots();
RootedShape oldShape(cx, obj->lastProperty());
RootedTypeObject oldType(cx, obj->type());
// Set/Add the property on the object, the inlined cache are setup for the next execution.
if (!SetProperty(cx, obj, name, value, cache.strict(), cache.pc()))

Просмотреть файл

@ -2015,7 +2015,7 @@ InlineFrameIterator::isConstructing() const
bool
JitFrameIterator::isConstructing() const
{
return GetCalleeTokenTag(calleeToken()) == CalleeToken_FunctionConstructing;
return CalleeTokenIsConstructing(calleeToken());
}
unsigned

Просмотреть файл

@ -52,6 +52,11 @@ CalleeTokenIsFunction(CalleeToken token)
CalleeTokenTag tag = GetCalleeTokenTag(token);
return tag == CalleeToken_Function || tag == CalleeToken_FunctionConstructing;
}
static inline bool
CalleeTokenIsConstructing(CalleeToken token)
{
return GetCalleeTokenTag(token) == CalleeToken_FunctionConstructing;
}
static inline JSFunction *
CalleeTokenToFunction(CalleeToken token)
{

Просмотреть файл

@ -59,7 +59,16 @@ LoopUnroller::getReplacementDefinition(MDefinition *def)
}
DefinitionMap::Ptr p = unrolledDefinitions.lookup(def);
JS_ASSERT(p);
if (!p) {
// After phi analysis (TypeAnalyzer::replaceRedundantPhi) the resume
// point at the start of a block can contain definitions from within
// the block itself.
JS_ASSERT(def->isConstant());
MConstant *constant = MConstant::New(alloc, def->toConstant()->value());
oldPreheader->insertBefore(*oldPreheader->begin(), constant);
return constant;
}
return p->value();
}
@ -115,7 +124,10 @@ LoopUnroller::go(LoopIterationBound *bound)
JitSpew(JitSpew_Unrolling, "Attempting to unroll loop");
header = bound->header;
JS_ASSERT(header->isLoopHeader());
// UCE might have determined this isn't actually a loop.
if (!header->isLoopHeader())
return;
backedge = header->backedge();
oldPreheader = header->loopPredecessor();

Просмотреть файл

@ -20,6 +20,7 @@
#include "gc/Marking.h"
#include "jit/JitCompartment.h"
#include "js/RootingAPI.h"
#include "proxy/DeadObjectProxy.h"
#include "vm/Debugger.h"
#include "vm/StopIterationObject.h"
#include "vm/WrapperObject.h"

Просмотреть файл

@ -21,6 +21,7 @@
#include "prmjtime.h"
#include "builtin/TestingFunctions.h"
#include "proxy/DeadObjectProxy.h"
#include "vm/WrapperObject.h"
#include "jsobjinlines.h"
@ -597,11 +598,7 @@ JS_GetCustomIteratorCount(JSContext *cx)
JS_FRIEND_API(bool)
JS_IsDeadWrapper(JSObject *obj)
{
if (!obj->is<ProxyObject>()) {
return false;
}
return obj->as<ProxyObject>().handler()->family() == &DeadObjectProxy::family;
return IsDeadProxyObject(obj);
}
void

Просмотреть файл

@ -218,6 +218,7 @@
#include "jit/BaselineJIT.h"
#include "jit/IonCode.h"
#include "js/SliceBudget.h"
#include "proxy/DeadObjectProxy.h"
#include "vm/Debugger.h"
#include "vm/ForkJoin.h"
#include "vm/ProxyObject.h"

Просмотреть файл

@ -709,10 +709,9 @@ TypeScript::InitObject(JSContext *cx, JSScript *script, jsbytecode *pc, JSProtoK
{
JS_ASSERT(!UseNewTypeForInitializer(script, pc, kind));
/* :XXX: Limit script->length so we don't need to check the offset up front? */
uint32_t offset = script->pcToOffset(pc);
if (!script->compileAndGo() || offset >= AllocationSiteKey::OFFSET_LIMIT)
if (offset >= AllocationSiteKey::OFFSET_LIMIT)
return GetTypeNewObject(cx, kind);
AllocationSiteKey key;

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -308,68 +308,6 @@ class JS_PUBLIC_API(DirectProxyHandler) : public BaseProxyHandler
virtual JSObject *weakmapKeyDelegate(JSObject *proxy) const MOZ_OVERRIDE;
};
/*
* Dispatch point for handlers that executes the appropriate C++ or scripted traps.
*
* Important: All proxy traps need either (a) an AutoEnterPolicy in their
* Proxy::foo entry point below or (b) an override in SecurityWrapper. See bug
* 945826 comment 0.
*/
class Proxy
{
public:
/* ES5 Harmony fundamental proxy traps. */
static bool preventExtensions(JSContext *cx, HandleObject proxy);
static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc);
static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandleValue vp);
static bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc);
static bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandleValue vp);
static bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc);
static bool getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props);
static bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
static bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props);
/* ES5 Harmony derived proxy traps. */
static bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
static bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
static bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
MutableHandleValue vp);
static bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
bool strict, MutableHandleValue vp);
static bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props);
static bool iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleValue vp);
/* Spidermonkey extensions. */
static bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible);
static bool call(JSContext *cx, HandleObject proxy, const CallArgs &args);
static bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args);
static bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args);
static bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp);
static bool objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx);
static const char *className(JSContext *cx, HandleObject proxy);
static JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent);
static bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g);
static bool boxedValue_unbox(JSContext *cx, HandleObject proxy, MutableHandleValue vp);
static bool defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp);
static bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop);
static bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp);
static bool watch(JSContext *cx, HandleObject proxy, HandleId id, HandleObject callable);
static bool unwatch(JSContext *cx, HandleObject proxy, HandleId id);
static bool slice(JSContext *cx, HandleObject obj, uint32_t begin, uint32_t end,
HandleObject result);
/* IC entry path for handling __noSuchMethod__ on access. */
static bool callProp(JSContext *cx, HandleObject proxy, HandleObject reveiver, HandleId id,
MutableHandleValue vp);
};
// Use these in places where you don't want to #include vm/ProxyObject.h.
extern JS_FRIEND_DATA(const js::Class* const) CallableProxyClassPtr;
extern JS_FRIEND_DATA(const js::Class* const) UncallableProxyClassPtr;

Просмотреть файл

@ -209,48 +209,6 @@ class JS_FRIEND_API(SecurityWrapper) : public Base
typedef SecurityWrapper<Wrapper> SameCompartmentSecurityWrapper;
typedef SecurityWrapper<CrossCompartmentWrapper> CrossCompartmentSecurityWrapper;
class JS_FRIEND_API(DeadObjectProxy) : public BaseProxyHandler
{
public:
explicit MOZ_CONSTEXPR DeadObjectProxy()
: BaseProxyHandler(&family)
{ }
/* ES5 Harmony fundamental wrapper traps. */
virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool getOwnPropertyNames(JSContext *cx, HandleObject wrapper,
AutoIdVector &props) const MOZ_OVERRIDE;
virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE;
virtual bool enumerate(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const MOZ_OVERRIDE;
/* Spidermonkey extensions. */
virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
CallArgs args) const MOZ_OVERRIDE;
virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v,
bool *bp) const MOZ_OVERRIDE;
virtual bool objectClassIs(HandleObject obj, ESClassValue classValue,
JSContext *cx) const MOZ_OVERRIDE;
virtual const char *className(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) const MOZ_OVERRIDE;
virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) const MOZ_OVERRIDE;
virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint,
MutableHandleValue vp) const MOZ_OVERRIDE;
virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy,
MutableHandleObject protop) const MOZ_OVERRIDE;
static const char family;
static const DeadObjectProxy singleton;
};
extern JSObject *
TransparentObjectWrapper(JSContext *cx, HandleObject existing, HandleObject obj,
HandleObject parent);
@ -283,13 +241,6 @@ UnwrapOneChecked(JSObject *obj, bool stopAtOuter = true);
JS_FRIEND_API(bool)
IsCrossCompartmentWrapper(JSObject *obj);
bool
IsDeadProxyObject(JSObject *obj);
JSObject *
NewDeadProxyObject(JSContext *cx, JSObject *parent,
const ProxyOptions &options = ProxyOptions());
void
NukeCrossCompartmentWrapper(JSContext *cx, JSObject *wrapper);

Просмотреть файл

@ -223,15 +223,22 @@ UNIFIED_SOURCES += [
'jsopcode.cpp',
'jsprf.cpp',
'jspropertytree.cpp',
'jsproxy.cpp',
'jsreflect.cpp',
'jsscript.cpp',
'jsstr.cpp',
'jswatchpoint.cpp',
'jsweakmap.cpp',
'jswrapper.cpp',
'perf/jsperf.cpp',
'prmjtime.cpp',
'proxy/BaseProxyHandler.cpp',
'proxy/CrossCompartmentWrapper.cpp',
'proxy/DeadObjectProxy.cpp',
'proxy/DirectProxyHandler.cpp',
'proxy/Proxy.cpp',
'proxy/ScriptedDirectProxyHandler.cpp',
'proxy/ScriptedIndirectProxyHandler.cpp',
'proxy/SecurityWrapper.cpp',
'proxy/Wrapper.cpp',
'vm/ArgumentsObject.cpp',
'vm/ArrayBufferObject.cpp',
'vm/CallNonGenericMethod.cpp',

Просмотреть файл

@ -0,0 +1,343 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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/. */
#include "jsproxy.h"
#include "vm/ProxyObject.h"
#include "jscntxtinlines.h"
using namespace js;
bool
BaseProxyHandler::enter(JSContext *cx, HandleObject wrapper, HandleId id, Action act,
bool *bp) const
{
*bp = true;
return true;
}
bool
BaseProxyHandler::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const
{
assertEnteredPolicy(cx, proxy, id, GET);
Rooted<PropertyDescriptor> desc(cx);
if (!getPropertyDescriptor(cx, proxy, id, &desc))
return false;
*bp = !!desc.object();
return true;
}
bool
BaseProxyHandler::hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const
{
// Note: Proxy::set needs to invoke hasOwn to determine where the setter
// lives, so we allow SET operations to invoke us.
assertEnteredPolicy(cx, proxy, id, GET | SET);
Rooted<PropertyDescriptor> desc(cx);
if (!getOwnPropertyDescriptor(cx, proxy, id, &desc))
return false;
*bp = !!desc.object();
return true;
}
bool
BaseProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, MutableHandleValue vp) const
{
assertEnteredPolicy(cx, proxy, id, GET);
Rooted<PropertyDescriptor> desc(cx);
if (!getPropertyDescriptor(cx, proxy, id, &desc))
return false;
if (!desc.object()) {
vp.setUndefined();
return true;
}
if (!desc.getter() ||
(!desc.hasGetterObject() && desc.getter() == JS_PropertyStub))
{
vp.set(desc.value());
return true;
}
if (desc.hasGetterObject())
return InvokeGetterOrSetter(cx, receiver, ObjectValue(*desc.getterObject()),
0, nullptr, vp);
if (!desc.isShared())
vp.set(desc.value());
else
vp.setUndefined();
return CallJSPropertyOp(cx, desc.getter(), receiver, id, vp);
}
bool
BaseProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, bool strict, MutableHandleValue vp) const
{
assertEnteredPolicy(cx, proxy, id, SET);
// Find an own or inherited property. The code here is strange for maximum
// backward compatibility with earlier code written before ES6 and before
// SetPropertyIgnoringNamedGetter.
Rooted<PropertyDescriptor> desc(cx);
if (!getOwnPropertyDescriptor(cx, proxy, id, &desc))
return false;
bool descIsOwn = desc.object() != nullptr;
if (!descIsOwn) {
if (!getPropertyDescriptor(cx, proxy, id, &desc))
return false;
}
return SetPropertyIgnoringNamedGetter(cx, this, proxy, receiver, id, &desc, descIsOwn, strict,
vp);
}
bool
js::SetPropertyIgnoringNamedGetter(JSContext *cx, const BaseProxyHandler *handler,
HandleObject proxy, HandleObject receiver,
HandleId id, MutableHandle<PropertyDescriptor> desc,
bool descIsOwn, bool strict, MutableHandleValue vp)
{
/* The control-flow here differs from ::get() because of the fall-through case below. */
if (descIsOwn) {
JS_ASSERT(desc.object());
// Check for read-only properties.
if (desc.isReadonly())
return strict ? Throw(cx, id, JSMSG_READ_ONLY) : true;
if (!desc.setter()) {
// Be wary of the odd explicit undefined setter case possible through
// Object.defineProperty.
if (!desc.hasSetterObject())
desc.setSetter(JS_StrictPropertyStub);
} else if (desc.hasSetterObject() || desc.setter() != JS_StrictPropertyStub) {
if (!CallSetter(cx, receiver, id, desc.setter(), desc.attributes(), strict, vp))
return false;
if (!proxy->is<ProxyObject>() || proxy->as<ProxyObject>().handler() != handler)
return true;
if (desc.isShared())
return true;
}
if (!desc.getter()) {
// Same as above for the null setter case.
if (!desc.hasGetterObject())
desc.setGetter(JS_PropertyStub);
}
desc.value().set(vp.get());
return handler->defineProperty(cx, receiver, id, desc);
}
if (desc.object()) {
// Check for read-only properties.
if (desc.isReadonly())
return strict ? Throw(cx, id, JSMSG_CANT_REDEFINE_PROP) : true;
if (!desc.setter()) {
// Be wary of the odd explicit undefined setter case possible through
// Object.defineProperty.
if (!desc.hasSetterObject())
desc.setSetter(JS_StrictPropertyStub);
} else if (desc.hasSetterObject() || desc.setter() != JS_StrictPropertyStub) {
if (!CallSetter(cx, receiver, id, desc.setter(), desc.attributes(), strict, vp))
return false;
if (!proxy->is<ProxyObject>() || proxy->as<ProxyObject>().handler() != handler)
return true;
if (desc.isShared())
return true;
}
if (!desc.getter()) {
// Same as above for the null setter case.
if (!desc.hasGetterObject())
desc.setGetter(JS_PropertyStub);
}
desc.value().set(vp.get());
return handler->defineProperty(cx, receiver, id, desc);
}
desc.object().set(receiver);
desc.value().set(vp.get());
desc.setAttributes(JSPROP_ENUMERATE);
desc.setGetter(nullptr);
desc.setSetter(nullptr); // Pick up the class getter/setter.
return handler->defineProperty(cx, receiver, id, desc);
}
bool
BaseProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const
{
assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
JS_ASSERT(props.length() == 0);
if (!getOwnPropertyNames(cx, proxy, props))
return false;
/* Select only the enumerable properties through in-place iteration. */
RootedId id(cx);
size_t i = 0;
for (size_t j = 0, len = props.length(); j < len; j++) {
JS_ASSERT(i <= j);
id = props[j];
if (JSID_IS_SYMBOL(id))
continue;
AutoWaivePolicy policy(cx, proxy, id, BaseProxyHandler::GET);
Rooted<PropertyDescriptor> desc(cx);
if (!getOwnPropertyDescriptor(cx, proxy, id, &desc))
return false;
if (desc.object() && desc.isEnumerable())
props[i++].set(id);
}
JS_ASSERT(i <= props.length());
props.resize(i);
return true;
}
bool
BaseProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags,
MutableHandleValue vp) const
{
assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
AutoIdVector props(cx);
if ((flags & JSITER_OWNONLY)
? !keys(cx, proxy, props)
: !enumerate(cx, proxy, props)) {
return false;
}
return EnumeratedIdVectorToIterator(cx, proxy, flags, props, vp);
}
bool
BaseProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args) const
{
MOZ_CRASH("callable proxies should implement call trap");
}
bool
BaseProxyHandler::construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const
{
MOZ_CRASH("callable proxies should implement construct trap");
}
const char *
BaseProxyHandler::className(JSContext *cx, HandleObject proxy) const
{
return proxy->isCallable() ? "Function" : "Object";
}
JSString *
BaseProxyHandler::fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) const
{
if (proxy->isCallable())
return JS_NewStringCopyZ(cx, "function () {\n [native code]\n}");
RootedValue v(cx, ObjectValue(*proxy));
ReportIsNotFunction(cx, v);
return nullptr;
}
bool
BaseProxyHandler::regexp_toShared(JSContext *cx, HandleObject proxy,
RegExpGuard *g) const
{
MOZ_CRASH("This should have been a wrapped regexp");
}
bool
BaseProxyHandler::boxedValue_unbox(JSContext *cx, HandleObject proxy, MutableHandleValue vp) const
{
vp.setUndefined();
return true;
}
bool
BaseProxyHandler::defaultValue(JSContext *cx, HandleObject proxy, JSType hint,
MutableHandleValue vp) const
{
return DefaultValue(cx, proxy, hint, vp);
}
bool
BaseProxyHandler::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
CallArgs args) const
{
ReportIncompatible(cx, args);
return false;
}
bool
BaseProxyHandler::hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v,
bool *bp) const
{
assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
RootedValue val(cx, ObjectValue(*proxy.get()));
js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
JSDVG_SEARCH_STACK, val, js::NullPtr());
return false;
}
bool
BaseProxyHandler::objectClassIs(HandleObject proxy, ESClassValue classValue, JSContext *cx) const
{
return false;
}
void
BaseProxyHandler::finalize(JSFreeOp *fop, JSObject *proxy) const
{
}
void
BaseProxyHandler::objectMoved(JSObject *proxy, const JSObject *old) const
{
}
JSObject *
BaseProxyHandler::weakmapKeyDelegate(JSObject *proxy) const
{
return nullptr;
}
bool
BaseProxyHandler::getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop) const
{
MOZ_CRASH("Must override getPrototypeOf with lazy prototype.");
}
bool
BaseProxyHandler::setPrototypeOf(JSContext *cx, HandleObject, HandleObject, bool *) const
{
// Disallow sets of protos on proxies with lazy protos, but no hook.
// This keeps us away from the footgun of having the first proto set opt
// you out of having dynamic protos altogether.
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_SETPROTOTYPEOF_FAIL,
"incompatible Proxy");
return false;
}
bool
BaseProxyHandler::watch(JSContext *cx, HandleObject proxy, HandleId id, HandleObject callable) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_WATCH,
proxy->getClass()->name);
return false;
}
bool
BaseProxyHandler::unwatch(JSContext *cx, HandleObject proxy, HandleId id) const
{
return true;
}
bool
BaseProxyHandler::slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
HandleObject result) const
{
assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
return js::SliceSlowly(cx, proxy, proxy, begin, end, result);
}

Просмотреть файл

@ -4,180 +4,16 @@
* 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/. */
#include "jsiter.h"
#include "jswrapper.h"
#include "jscntxt.h"
#include "jscompartment.h"
#include "jsexn.h"
#include "jsgc.h"
#include "jsiter.h"
#include "vm/ErrorObject.h"
#include "proxy/DeadObjectProxy.h"
#include "vm/WrapperObject.h"
#include "jscompartmentinlines.h"
#include "jsobjinlines.h"
using namespace js;
using namespace js::gc;
/*
* Wrapper forwards this call directly to the wrapped object for efficiency
* and transparency. In particular, the hint is needed to properly stringify
* Date objects in certain cases - see bug 646129. Note also the
* SecurityWrapper overrides this trap to avoid information leaks. See bug
* 720619.
*/
bool
Wrapper::defaultValue(JSContext *cx, HandleObject proxy, JSType hint, MutableHandleValue vp) const
{
vp.set(ObjectValue(*proxy->as<ProxyObject>().target()));
if (hint == JSTYPE_VOID)
return ToPrimitive(cx, vp);
return ToPrimitive(cx, hint, vp);
}
JSObject *
Wrapper::New(JSContext *cx, JSObject *obj, JSObject *parent, const Wrapper *handler,
const WrapperOptions *options)
{
JS_ASSERT(parent);
RootedValue priv(cx, ObjectValue(*obj));
mozilla::Maybe<WrapperOptions> opts;
if (!options) {
opts.emplace();
opts->selectDefaultClass(obj->isCallable());
options = opts.ptr();
}
return NewProxyObject(cx, handler, priv, options->proto(), parent, *options);
}
JSObject *
Wrapper::Renew(JSContext *cx, JSObject *existing, JSObject *obj, const Wrapper *handler)
{
JS_ASSERT(!obj->isCallable());
existing->as<ProxyObject>().renew(cx, handler, ObjectValue(*obj));
return existing;
}
const Wrapper *
Wrapper::wrapperHandler(JSObject *wrapper)
{
JS_ASSERT(wrapper->is<WrapperObject>());
return static_cast<const Wrapper*>(wrapper->as<ProxyObject>().handler());
}
JSObject *
Wrapper::wrappedObject(JSObject *wrapper)
{
JS_ASSERT(wrapper->is<WrapperObject>());
return wrapper->as<ProxyObject>().target();
}
JS_FRIEND_API(JSObject *)
js::UncheckedUnwrap(JSObject *wrapped, bool stopAtOuter, unsigned *flagsp)
{
unsigned flags = 0;
while (true) {
if (!wrapped->is<WrapperObject>() ||
MOZ_UNLIKELY(stopAtOuter && wrapped->getClass()->ext.innerObject))
{
break;
}
flags |= Wrapper::wrapperHandler(wrapped)->flags();
wrapped = wrapped->as<ProxyObject>().private_().toObjectOrNull();
// This can be called from DirectProxyHandler::weakmapKeyDelegate() on a
// wrapper whose referent has been moved while it is still unmarked.
if (wrapped)
wrapped = MaybeForwarded(wrapped);
}
if (flagsp)
*flagsp = flags;
return wrapped;
}
JS_FRIEND_API(JSObject *)
js::CheckedUnwrap(JSObject *obj, bool stopAtOuter)
{
while (true) {
JSObject *wrapper = obj;
obj = UnwrapOneChecked(obj, stopAtOuter);
if (!obj || obj == wrapper)
return obj;
}
}
JS_FRIEND_API(JSObject *)
js::UnwrapOneChecked(JSObject *obj, bool stopAtOuter)
{
if (!obj->is<WrapperObject>() ||
MOZ_UNLIKELY(!!obj->getClass()->ext.innerObject && stopAtOuter))
{
return obj;
}
const Wrapper *handler = Wrapper::wrapperHandler(obj);
return handler->hasSecurityPolicy() ? nullptr : Wrapper::wrappedObject(obj);
}
bool
js::IsCrossCompartmentWrapper(JSObject *obj)
{
return IsWrapper(obj) &&
!!(Wrapper::wrapperHandler(obj)->flags() & Wrapper::CROSS_COMPARTMENT);
}
const char Wrapper::family = 0;
const Wrapper Wrapper::singleton((unsigned)0);
const Wrapper Wrapper::singletonWithPrototype((unsigned)0, true);
JSObject *Wrapper::defaultProto = TaggedProto::LazyProto;
/* Compartments. */
extern JSObject *
js::TransparentObjectWrapper(JSContext *cx, HandleObject existing, HandleObject obj,
HandleObject parent)
{
// Allow wrapping outer window proxies.
JS_ASSERT(!obj->is<WrapperObject>() || obj->getClass()->ext.innerObject);
return Wrapper::New(cx, obj, parent, &CrossCompartmentWrapper::singleton);
}
ErrorCopier::~ErrorCopier()
{
JSContext *cx = ac->context()->asJSContext();
if (ac->origin() != cx->compartment() && cx->isExceptionPending()) {
RootedValue exc(cx);
if (cx->getPendingException(&exc) && exc.isObject() && exc.toObject().is<ErrorObject>()) {
cx->clearPendingException();
ac.reset();
Rooted<ErrorObject*> errObj(cx, &exc.toObject().as<ErrorObject>());
JSObject *copyobj = js_CopyErrorObject(cx, errObj);
if (copyobj)
cx->setPendingException(ObjectValue(*copyobj));
}
}
}
/* Cross compartment wrappers. */
bool Wrapper::finalizeInBackground(Value priv) const
{
if (!priv.isObject())
return true;
/*
* Make the 'background-finalized-ness' of the wrapper the same as the
* wrapped object, to allow transplanting between them.
*
* If the wrapped object is in the nursery then we know it doesn't have a
* finalizer, and so background finalization is ok.
*/
if (IsInsideNursery(&priv.toObject()))
return true;
return IsBackgroundFinalized(priv.toObject().tenuredGetAllocKind());
}
#define PIERCE(cx, wrapper, pre, op, post) \
JS_BEGIN_MACRO \
@ -596,271 +432,11 @@ CrossCompartmentWrapper::setPrototypeOf(JSContext *cx, HandleObject wrapper,
const CrossCompartmentWrapper CrossCompartmentWrapper::singleton(0u);
/* Security wrappers. */
template <class Base>
bool
SecurityWrapper<Base>::isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) const
js::IsCrossCompartmentWrapper(JSObject *obj)
{
// Just like BaseProxyHandler, SecurityWrappers claim by default to always
// be extensible, so as not to leak information about the state of the
// underlying wrapped thing.
*extensible = true;
return true;
}
template <class Base>
bool
SecurityWrapper<Base>::preventExtensions(JSContext *cx, HandleObject wrapper) const
{
// See above.
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_UNWRAP_DENIED);
return false;
}
template <class Base>
bool
SecurityWrapper<Base>::enter(JSContext *cx, HandleObject wrapper, HandleId id,
Wrapper::Action act, bool *bp) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_UNWRAP_DENIED);
*bp = false;
return false;
}
template <class Base>
bool
SecurityWrapper<Base>::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
CallArgs args) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_UNWRAP_DENIED);
return false;
}
template <class Base>
bool
SecurityWrapper<Base>::setPrototypeOf(JSContext *cx, HandleObject wrapper,
HandleObject proto, bool *bp) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_UNWRAP_DENIED);
return false;
}
// For security wrappers, we run the DefaultValue algorithm on the wrapper
// itself, which means that the existing security policy on operations like
// toString() will take effect and do the right thing here.
template <class Base>
bool
SecurityWrapper<Base>::defaultValue(JSContext *cx, HandleObject wrapper,
JSType hint, MutableHandleValue vp) const
{
return DefaultValue(cx, wrapper, hint, vp);
}
template <class Base>
bool
SecurityWrapper<Base>::objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx) const
{
return false;
}
template <class Base>
bool
SecurityWrapper<Base>::regexp_toShared(JSContext *cx, HandleObject obj, RegExpGuard *g) const
{
return Base::regexp_toShared(cx, obj, g);
}
template <class Base>
bool
SecurityWrapper<Base>::boxedValue_unbox(JSContext *cx, HandleObject obj, MutableHandleValue vp) const
{
vp.setUndefined();
return true;
}
template <class Base>
bool
SecurityWrapper<Base>::defineProperty(JSContext *cx, HandleObject wrapper,
HandleId id, MutableHandle<PropertyDescriptor> desc) const
{
if (desc.getter() || desc.setter()) {
JSString *str = IdToString(cx, id);
AutoStableStringChars chars(cx);
const char16_t *prop = nullptr;
if (str->ensureFlat(cx) && chars.initTwoByte(cx, str))
prop = chars.twoByteChars();
JS_ReportErrorNumberUC(cx, js_GetErrorMessage, nullptr,
JSMSG_ACCESSOR_DEF_DENIED, prop);
return false;
}
return Base::defineProperty(cx, wrapper, id, desc);
}
template <class Base>
bool
SecurityWrapper<Base>::watch(JSContext *cx, HandleObject proxy,
HandleId id, HandleObject callable) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_UNWRAP_DENIED);
return false;
}
template <class Base>
bool
SecurityWrapper<Base>::unwatch(JSContext *cx, HandleObject proxy,
HandleId id) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_UNWRAP_DENIED);
return false;
}
template class js::SecurityWrapper<Wrapper>;
template class js::SecurityWrapper<CrossCompartmentWrapper>;
bool
DeadObjectProxy::isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const
{
// This is kind of meaningless, but dead-object semantics aside,
// [[Extensible]] always being true is consistent with other proxy types.
*extensible = true;
return true;
}
bool
DeadObjectProxy::preventExtensions(JSContext *cx, HandleObject proxy) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<PropertyDescriptor> desc) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<PropertyDescriptor> desc) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<PropertyDescriptor> desc) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::getOwnPropertyNames(JSContext *cx, HandleObject wrapper,
AutoIdVector &props) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::enumerate(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::call(JSContext *cx, HandleObject wrapper, const CallArgs &args) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::construct(JSContext *cx, HandleObject wrapper, const CallArgs &args) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
CallArgs args) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v,
bool *bp) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
const char *
DeadObjectProxy::className(JSContext *cx, HandleObject wrapper) const
{
return "DeadObject";
}
JSString *
DeadObjectProxy::fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) const
{
return nullptr;
}
bool
DeadObjectProxy::regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::defaultValue(JSContext *cx, HandleObject obj, JSType hint,
MutableHandleValue vp) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop) const
{
protop.set(nullptr);
return true;
}
const char DeadObjectProxy::family = 0;
const DeadObjectProxy DeadObjectProxy::singleton;
bool
js::IsDeadProxyObject(JSObject *obj)
{
return obj->is<ProxyObject>() &&
obj->as<ProxyObject>().handler() == &DeadObjectProxy::singleton;
return IsWrapper(obj) &&
!!(Wrapper::wrapperHandler(obj)->flags() & Wrapper::CROSS_COMPARTMENT);
}
void

Просмотреть файл

@ -0,0 +1,159 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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/. */
#include "proxy/DeadObjectProxy.h"
#include "jsapi.h"
#include "jsfun.h" // XXXefaust Bug 1064662
#include "vm/ProxyObject.h"
using namespace js;
using namespace js::gc;
bool
DeadObjectProxy::isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const
{
// This is kind of meaningless, but dead-object semantics aside,
// [[Extensible]] always being true is consistent with other proxy types.
*extensible = true;
return true;
}
bool
DeadObjectProxy::preventExtensions(JSContext *cx, HandleObject proxy) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<PropertyDescriptor> desc) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<PropertyDescriptor> desc) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<PropertyDescriptor> desc) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::getOwnPropertyNames(JSContext *cx, HandleObject wrapper,
AutoIdVector &props) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::enumerate(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::call(JSContext *cx, HandleObject wrapper, const CallArgs &args) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::construct(JSContext *cx, HandleObject wrapper, const CallArgs &args) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
CallArgs args) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v,
bool *bp) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
const char *
DeadObjectProxy::className(JSContext *cx, HandleObject wrapper) const
{
return "DeadObject";
}
JSString *
DeadObjectProxy::fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) const
{
return nullptr;
}
bool
DeadObjectProxy::regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::defaultValue(JSContext *cx, HandleObject obj, JSType hint,
MutableHandleValue vp) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
bool
DeadObjectProxy::getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop) const
{
protop.set(nullptr);
return true;
}
const char DeadObjectProxy::family = 0;
const DeadObjectProxy DeadObjectProxy::singleton;
bool
js::IsDeadProxyObject(JSObject *obj)
{
return obj->is<ProxyObject>() &&
obj->as<ProxyObject>().handler() == &DeadObjectProxy::singleton;
}

Просмотреть файл

@ -0,0 +1,61 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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/. */
#ifndef proxy_DeadObjectProxy_h
#define proxy_DeadObjectProxy_h
#include "jsproxy.h"
namespace js {
class DeadObjectProxy : public BaseProxyHandler
{
public:
explicit MOZ_CONSTEXPR DeadObjectProxy()
: BaseProxyHandler(&family)
{ }
/* ES5 Harmony fundamental wrapper traps. */
virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool getOwnPropertyNames(JSContext *cx, HandleObject wrapper,
AutoIdVector &props) const MOZ_OVERRIDE;
virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE;
virtual bool enumerate(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const MOZ_OVERRIDE;
/* Spidermonkey extensions. */
virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
CallArgs args) const MOZ_OVERRIDE;
virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v,
bool *bp) const MOZ_OVERRIDE;
virtual bool objectClassIs(HandleObject obj, ESClassValue classValue,
JSContext *cx) const MOZ_OVERRIDE;
virtual const char *className(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) const MOZ_OVERRIDE;
virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) const MOZ_OVERRIDE;
virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint,
MutableHandleValue vp) const MOZ_OVERRIDE;
virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy,
MutableHandleObject protop) const MOZ_OVERRIDE;
static const char family;
static const DeadObjectProxy singleton;
};
bool
IsDeadProxyObject(JSObject *obj);
} /* namespace js */
#endif /* proxy_DeadObjectProxy_h */

Просмотреть файл

@ -0,0 +1,250 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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/. */
#include "jsproxy.h"
#include "jswrapper.h" // UncheckedUnwrap
#include "vm/ProxyObject.h"
#include "jsobjinlines.h"
using namespace js;
bool
DirectProxyHandler::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<PropertyDescriptor> desc) const
{
assertEnteredPolicy(cx, proxy, id, GET | SET | GET_PROPERTY_DESCRIPTOR);
JS_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
RootedObject target(cx, proxy->as<ProxyObject>().target());
return JS_GetPropertyDescriptorById(cx, target, id, desc);
}
bool
DirectProxyHandler::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<PropertyDescriptor> desc) const
{
assertEnteredPolicy(cx, proxy, id, GET | SET | GET_PROPERTY_DESCRIPTOR);
RootedObject target(cx, proxy->as<ProxyObject>().target());
return js::GetOwnPropertyDescriptor(cx, target, id, desc);
}
bool
DirectProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<PropertyDescriptor> desc) const
{
assertEnteredPolicy(cx, proxy, id, SET);
RootedObject target(cx, proxy->as<ProxyObject>().target());
RootedValue v(cx, desc.value());
return CheckDefineProperty(cx, target, id, v, desc.attributes(), desc.getter(), desc.setter()) &&
JS_DefinePropertyById(cx, target, id, v, desc.attributes(), desc.getter(), desc.setter());
}
bool
DirectProxyHandler::getOwnPropertyNames(JSContext *cx, HandleObject proxy,
AutoIdVector &props) const
{
assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
RootedObject target(cx, proxy->as<ProxyObject>().target());
return GetPropertyNames(cx, target, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &props);
}
bool
DirectProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const
{
assertEnteredPolicy(cx, proxy, id, SET);
RootedObject target(cx, proxy->as<ProxyObject>().target());
return JSObject::deleteGeneric(cx, target, id, bp);
}
bool
DirectProxyHandler::enumerate(JSContext *cx, HandleObject proxy,
AutoIdVector &props) const
{
assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
JS_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
RootedObject target(cx, proxy->as<ProxyObject>().target());
return GetPropertyNames(cx, target, 0, &props);
}
bool
DirectProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args) const
{
assertEnteredPolicy(cx, proxy, JSID_VOID, CALL);
RootedValue target(cx, proxy->as<ProxyObject>().private_());
return Invoke(cx, args.thisv(), target, args.length(), args.array(), args.rval());
}
bool
DirectProxyHandler::construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const
{
assertEnteredPolicy(cx, proxy, JSID_VOID, CALL);
RootedValue target(cx, proxy->as<ProxyObject>().private_());
return InvokeConstructor(cx, target, args.length(), args.array(), args.rval().address());
}
bool
DirectProxyHandler::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
CallArgs args) const
{
args.setThis(ObjectValue(*args.thisv().toObject().as<ProxyObject>().target()));
if (!test(args.thisv())) {
ReportIncompatible(cx, args);
return false;
}
return CallNativeImpl(cx, impl, args);
}
bool
DirectProxyHandler::hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v,
bool *bp) const
{
assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
bool b;
RootedObject target(cx, proxy->as<ProxyObject>().target());
if (!HasInstance(cx, target, v, &b))
return false;
*bp = !!b;
return true;
}
bool
DirectProxyHandler::getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop) const
{
RootedObject target(cx, proxy->as<ProxyObject>().target());
return JSObject::getProto(cx, target, protop);
}
bool
DirectProxyHandler::setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp) const
{
RootedObject target(cx, proxy->as<ProxyObject>().target());
return JSObject::setProto(cx, target, proto, bp);
}
bool
DirectProxyHandler::objectClassIs(HandleObject proxy, ESClassValue classValue,
JSContext *cx) const
{
RootedObject target(cx, proxy->as<ProxyObject>().target());
return ObjectClassIs(target, classValue, cx);
}
const char *
DirectProxyHandler::className(JSContext *cx, HandleObject proxy) const
{
assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
RootedObject target(cx, proxy->as<ProxyObject>().target());
return JSObject::className(cx, target);
}
JSString *
DirectProxyHandler::fun_toString(JSContext *cx, HandleObject proxy,
unsigned indent) const
{
assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
RootedObject target(cx, proxy->as<ProxyObject>().target());
return fun_toStringHelper(cx, target, indent);
}
bool
DirectProxyHandler::regexp_toShared(JSContext *cx, HandleObject proxy,
RegExpGuard *g) const
{
RootedObject target(cx, proxy->as<ProxyObject>().target());
return RegExpToShared(cx, target, g);
}
bool
DirectProxyHandler::boxedValue_unbox(JSContext *cx, HandleObject proxy, MutableHandleValue vp) const
{
RootedObject target(cx, proxy->as<ProxyObject>().target());
return Unbox(cx, target, vp);
}
JSObject *
DirectProxyHandler::weakmapKeyDelegate(JSObject *proxy) const
{
return UncheckedUnwrap(proxy);
}
bool
DirectProxyHandler::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const
{
assertEnteredPolicy(cx, proxy, id, GET);
JS_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
bool found;
RootedObject target(cx, proxy->as<ProxyObject>().target());
if (!JS_HasPropertyById(cx, target, id, &found))
return false;
*bp = !!found;
return true;
}
bool
DirectProxyHandler::hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const
{
// Note: Proxy::set needs to invoke hasOwn to determine where the setter
// lives, so we allow SET operations to invoke us.
assertEnteredPolicy(cx, proxy, id, GET | SET);
RootedObject target(cx, proxy->as<ProxyObject>().target());
Rooted<PropertyDescriptor> desc(cx);
if (!JS_GetPropertyDescriptorById(cx, target, id, &desc))
return false;
*bp = (desc.object() == target);
return true;
}
bool
DirectProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, MutableHandleValue vp) const
{
assertEnteredPolicy(cx, proxy, id, GET);
RootedObject target(cx, proxy->as<ProxyObject>().target());
return JSObject::getGeneric(cx, target, receiver, id, vp);
}
bool
DirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, bool strict, MutableHandleValue vp) const
{
assertEnteredPolicy(cx, proxy, id, SET);
RootedObject target(cx, proxy->as<ProxyObject>().target());
return JSObject::setGeneric(cx, target, receiver, id, vp, strict);
}
bool
DirectProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const
{
assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
RootedObject target(cx, proxy->as<ProxyObject>().target());
return GetPropertyNames(cx, target, JSITER_OWNONLY, &props);
}
bool
DirectProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags,
MutableHandleValue vp) const
{
assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
JS_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
RootedObject target(cx, proxy->as<ProxyObject>().target());
return GetIterator(cx, target, flags, vp);
}
bool
DirectProxyHandler::isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const
{
RootedObject target(cx, proxy->as<ProxyObject>().target());
return JSObject::isExtensible(cx, target, extensible);
}
bool
DirectProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy) const
{
RootedObject target(cx, proxy->as<ProxyObject>().target());
return JSObject::preventExtensions(cx, target);
}

903
js/src/proxy/Proxy.cpp Normal file
Просмотреть файл

@ -0,0 +1,903 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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/. */
#include <string.h>
#include "jsapi.h"
#include "jscntxt.h"
#include "jsfun.h"
#include "jsgc.h"
#include "jsproxy.h"
#include "jswrapper.h"
#include "gc/Marking.h"
#include "proxy/DeadObjectProxy.h"
#include "proxy/ScriptedDirectProxyHandler.h"
#include "proxy/ScriptedIndirectProxyHandler.h"
#include "vm/WrapperObject.h"
#include "jsatominlines.h"
#include "jsinferinlines.h"
#include "jsobjinlines.h"
#include "vm/ObjectImpl-inl.h"
using namespace js;
using namespace js::gc;
void
js::AutoEnterPolicy::reportErrorIfExceptionIsNotPending(JSContext *cx, jsid id)
{
if (JS_IsExceptionPending(cx))
return;
if (JSID_IS_VOID(id)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
JSMSG_OBJECT_ACCESS_DENIED);
} else {
JSString *str = IdToString(cx, id);
AutoStableStringChars chars(cx);
const char16_t *prop = nullptr;
if (str->ensureFlat(cx) && chars.initTwoByte(cx, str))
prop = chars.twoByteChars();
JS_ReportErrorNumberUC(cx, js_GetErrorMessage, nullptr, JSMSG_PROPERTY_ACCESS_DENIED,
prop);
}
}
#ifdef DEBUG
void
js::AutoEnterPolicy::recordEnter(JSContext *cx, HandleObject proxy, HandleId id, Action act)
{
if (allowed()) {
context = cx;
enteredProxy.emplace(proxy);
enteredId.emplace(id);
enteredAction = act;
prev = cx->runtime()->enteredPolicy;
cx->runtime()->enteredPolicy = this;
}
}
void
js::AutoEnterPolicy::recordLeave()
{
if (enteredProxy) {
JS_ASSERT(context->runtime()->enteredPolicy == this);
context->runtime()->enteredPolicy = prev;
}
}
JS_FRIEND_API(void)
js::assertEnteredPolicy(JSContext *cx, JSObject *proxy, jsid id,
BaseProxyHandler::Action act)
{
MOZ_ASSERT(proxy->is<ProxyObject>());
MOZ_ASSERT(cx->runtime()->enteredPolicy);
MOZ_ASSERT(cx->runtime()->enteredPolicy->enteredProxy->get() == proxy);
MOZ_ASSERT(cx->runtime()->enteredPolicy->enteredId->get() == id);
MOZ_ASSERT(cx->runtime()->enteredPolicy->enteredAction & act);
}
#endif
#define INVOKE_ON_PROTOTYPE(cx, handler, proxy, protoCall) \
JS_BEGIN_MACRO \
RootedObject proto(cx); \
if (!JSObject::getProto(cx, proxy, &proto)) \
return false; \
if (!proto) \
return true; \
assertSameCompartment(cx, proxy, proto); \
return protoCall; \
JS_END_MACRO \
bool
Proxy::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<PropertyDescriptor> desc)
{
JS_CHECK_RECURSION(cx, return false);
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
desc.object().set(nullptr); // default result if we refuse to perform this action
AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET_PROPERTY_DESCRIPTOR, true);
if (!policy.allowed())
return policy.returnValue();
if (!handler->hasPrototype())
return handler->getPropertyDescriptor(cx, proxy, id, desc);
if (!handler->getOwnPropertyDescriptor(cx, proxy, id, desc))
return false;
if (desc.object())
return true;
INVOKE_ON_PROTOTYPE(cx, handler, proxy, JS_GetPropertyDescriptorById(cx, proto, id, desc));
}
bool
Proxy::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, MutableHandleValue vp)
{
JS_CHECK_RECURSION(cx, return false);
Rooted<PropertyDescriptor> desc(cx);
if (!Proxy::getPropertyDescriptor(cx, proxy, id, &desc))
return false;
return NewPropertyDescriptorObject(cx, desc, vp);
}
bool
Proxy::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<PropertyDescriptor> desc)
{
JS_CHECK_RECURSION(cx, return false);
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
desc.object().set(nullptr); // default result if we refuse to perform this action
AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET_PROPERTY_DESCRIPTOR, true);
if (!policy.allowed())
return policy.returnValue();
return handler->getOwnPropertyDescriptor(cx, proxy, id, desc);
}
bool
Proxy::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandleValue vp)
{
JS_CHECK_RECURSION(cx, return false);
Rooted<PropertyDescriptor> desc(cx);
if (!Proxy::getOwnPropertyDescriptor(cx, proxy, id, &desc))
return false;
return NewPropertyDescriptorObject(cx, desc, vp);
}
bool
Proxy::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<PropertyDescriptor> desc)
{
JS_CHECK_RECURSION(cx, return false);
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::SET, true);
if (!policy.allowed())
return policy.returnValue();
return proxy->as<ProxyObject>().handler()->defineProperty(cx, proxy, id, desc);
}
bool
Proxy::getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
JS_CHECK_RECURSION(cx, return false);
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::ENUMERATE, true);
if (!policy.allowed())
return policy.returnValue();
return proxy->as<ProxyObject>().handler()->getOwnPropertyNames(cx, proxy, props);
}
bool
Proxy::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
{
JS_CHECK_RECURSION(cx, return false);
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
*bp = true; // default result if we refuse to perform this action
AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::SET, true);
if (!policy.allowed())
return policy.returnValue();
return proxy->as<ProxyObject>().handler()->delete_(cx, proxy, id, bp);
}
JS_FRIEND_API(bool)
js::AppendUnique(JSContext *cx, AutoIdVector &base, AutoIdVector &others)
{
AutoIdVector uniqueOthers(cx);
if (!uniqueOthers.reserve(others.length()))
return false;
for (size_t i = 0; i < others.length(); ++i) {
bool unique = true;
for (size_t j = 0; j < base.length(); ++j) {
if (others[i].get() == base[j]) {
unique = false;
break;
}
}
if (unique)
uniqueOthers.append(others[i]);
}
return base.appendAll(uniqueOthers);
}
bool
Proxy::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
JS_CHECK_RECURSION(cx, return false);
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::ENUMERATE, true);
if (!policy.allowed())
return policy.returnValue();
if (!handler->hasPrototype())
return proxy->as<ProxyObject>().handler()->enumerate(cx, proxy, props);
if (!handler->keys(cx, proxy, props))
return false;
AutoIdVector protoProps(cx);
INVOKE_ON_PROTOTYPE(cx, handler, proxy,
GetPropertyNames(cx, proto, 0, &protoProps) &&
AppendUnique(cx, props, protoProps));
}
bool
Proxy::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
{
JS_CHECK_RECURSION(cx, return false);
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
*bp = false; // default result if we refuse to perform this action
AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET, true);
if (!policy.allowed())
return policy.returnValue();
if (!handler->hasPrototype())
return handler->has(cx, proxy, id, bp);
if (!handler->hasOwn(cx, proxy, id, bp))
return false;
if (*bp)
return true;
bool Bp;
INVOKE_ON_PROTOTYPE(cx, handler, proxy,
JS_HasPropertyById(cx, proto, id, &Bp) &&
((*bp = Bp) || true));
}
bool
Proxy::hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
{
JS_CHECK_RECURSION(cx, return false);
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
*bp = false; // default result if we refuse to perform this action
AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET, true);
if (!policy.allowed())
return policy.returnValue();
return handler->hasOwn(cx, proxy, id, bp);
}
bool
Proxy::get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
MutableHandleValue vp)
{
JS_CHECK_RECURSION(cx, return false);
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
vp.setUndefined(); // default result if we refuse to perform this action
AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET, true);
if (!policy.allowed())
return policy.returnValue();
bool own;
if (!handler->hasPrototype()) {
own = true;
} else {
if (!handler->hasOwn(cx, proxy, id, &own))
return false;
}
if (own)
return handler->get(cx, proxy, receiver, id, vp);
INVOKE_ON_PROTOTYPE(cx, handler, proxy, JSObject::getGeneric(cx, proto, receiver, id, vp));
}
bool
Proxy::callProp(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
MutableHandleValue vp)
{
// The inline caches need an access point for JSOP_CALLPROP sites that accounts
// for the possibility of __noSuchMethod__
if (!Proxy::get(cx, proxy, receiver, id, vp))
return false;
#if JS_HAS_NO_SUCH_METHOD
if (MOZ_UNLIKELY(vp.isPrimitive())) {
if (!OnUnknownMethod(cx, proxy, IdToValue(id), vp))
return false;
}
#endif
return true;
}
bool
Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, bool strict,
MutableHandleValue vp)
{
JS_CHECK_RECURSION(cx, return false);
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::SET, true);
if (!policy.allowed())
return policy.returnValue();
// If the proxy doesn't require that we consult its prototype for the
// non-own cases, we can sink to the |set| trap.
if (!handler->hasPrototype())
return handler->set(cx, proxy, receiver, id, strict, vp);
// If we have an existing (own or non-own) property with a setter, we want
// to invoke that.
Rooted<PropertyDescriptor> desc(cx);
if (!Proxy::getPropertyDescriptor(cx, proxy, id, &desc))
return false;
if (desc.object() && desc.setter() && desc.setter() != JS_StrictPropertyStub)
return CallSetter(cx, receiver, id, desc.setter(), desc.attributes(), strict, vp);
// Ok. Either there was no pre-existing property, or it was a value prop
// that we're going to shadow. Make a property descriptor and define it.
//
// Note that for pre-existing own value properties, we inherit the existing
// attributes, since we're really just changing the value and not trying to
// reconfigure the property.
Rooted<PropertyDescriptor> newDesc(cx);
if (desc.object() == proxy)
newDesc.setAttributes(desc.attributes());
else
newDesc.setAttributes(JSPROP_ENUMERATE);
newDesc.value().set(vp);
return handler->defineProperty(cx, receiver, id, &newDesc);
}
bool
Proxy::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
JS_CHECK_RECURSION(cx, return false);
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::ENUMERATE, true);
if (!policy.allowed())
return policy.returnValue();
return handler->keys(cx, proxy, props);
}
bool
Proxy::iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleValue vp)
{
JS_CHECK_RECURSION(cx, return false);
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
vp.setUndefined(); // default result if we refuse to perform this action
if (!handler->hasPrototype()) {
AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE,
BaseProxyHandler::ENUMERATE, true);
// If the policy denies access but wants us to return true, we need
// to hand a valid (empty) iterator object to the caller.
if (!policy.allowed()) {
AutoIdVector props(cx);
return policy.returnValue() &&
EnumeratedIdVectorToIterator(cx, proxy, flags, props, vp);
}
return handler->iterate(cx, proxy, flags, vp);
}
AutoIdVector props(cx);
// The other Proxy::foo methods do the prototype-aware work for us here.
if ((flags & JSITER_OWNONLY)
? !Proxy::keys(cx, proxy, props)
: !Proxy::enumerate(cx, proxy, props)) {
return false;
}
return EnumeratedIdVectorToIterator(cx, proxy, flags, props, vp);
}
bool
Proxy::isExtensible(JSContext *cx, HandleObject proxy, bool *extensible)
{
JS_CHECK_RECURSION(cx, return false);
return proxy->as<ProxyObject>().handler()->isExtensible(cx, proxy, extensible);
}
bool
Proxy::preventExtensions(JSContext *cx, HandleObject proxy)
{
JS_CHECK_RECURSION(cx, return false);
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
return handler->preventExtensions(cx, proxy);
}
bool
Proxy::call(JSContext *cx, HandleObject proxy, const CallArgs &args)
{
JS_CHECK_RECURSION(cx, return false);
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
// Because vp[0] is JS_CALLEE on the way in and JS_RVAL on the way out, we
// can only set our default value once we're sure that we're not calling the
// trap.
AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE,
BaseProxyHandler::CALL, true);
if (!policy.allowed()) {
args.rval().setUndefined();
return policy.returnValue();
}
return handler->call(cx, proxy, args);
}
bool
Proxy::construct(JSContext *cx, HandleObject proxy, const CallArgs &args)
{
JS_CHECK_RECURSION(cx, return false);
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
// Because vp[0] is JS_CALLEE on the way in and JS_RVAL on the way out, we
// can only set our default value once we're sure that we're not calling the
// trap.
AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE,
BaseProxyHandler::CALL, true);
if (!policy.allowed()) {
args.rval().setUndefined();
return policy.returnValue();
}
return handler->construct(cx, proxy, args);
}
bool
Proxy::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args)
{
JS_CHECK_RECURSION(cx, return false);
RootedObject proxy(cx, &args.thisv().toObject());
// Note - we don't enter a policy here because our security architecture
// guards against nativeCall by overriding the trap itself in the right
// circumstances.
return proxy->as<ProxyObject>().handler()->nativeCall(cx, test, impl, args);
}
bool
Proxy::hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp)
{
JS_CHECK_RECURSION(cx, return false);
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
*bp = false; // default result if we refuse to perform this action
AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::GET, true);
if (!policy.allowed())
return policy.returnValue();
return proxy->as<ProxyObject>().handler()->hasInstance(cx, proxy, v, bp);
}
bool
Proxy::objectClassIs(HandleObject proxy, ESClassValue classValue, JSContext *cx)
{
JS_CHECK_RECURSION(cx, return false);
return proxy->as<ProxyObject>().handler()->objectClassIs(proxy, classValue, cx);
}
const char *
Proxy::className(JSContext *cx, HandleObject proxy)
{
// Check for unbounded recursion, but don't signal an error; className
// needs to be infallible.
int stackDummy;
if (!JS_CHECK_STACK_SIZE(GetNativeStackLimit(cx), &stackDummy))
return "too much recursion";
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE,
BaseProxyHandler::GET, /* mayThrow = */ false);
// Do the safe thing if the policy rejects.
if (!policy.allowed()) {
return handler->BaseProxyHandler::className(cx, proxy);
}
return handler->className(cx, proxy);
}
JSString *
Proxy::fun_toString(JSContext *cx, HandleObject proxy, unsigned indent)
{
JS_CHECK_RECURSION(cx, return nullptr);
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE,
BaseProxyHandler::GET, /* mayThrow = */ false);
// Do the safe thing if the policy rejects.
if (!policy.allowed())
return handler->BaseProxyHandler::fun_toString(cx, proxy, indent);
return handler->fun_toString(cx, proxy, indent);
}
bool
Proxy::regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g)
{
JS_CHECK_RECURSION(cx, return false);
return proxy->as<ProxyObject>().handler()->regexp_toShared(cx, proxy, g);
}
bool
Proxy::boxedValue_unbox(JSContext *cx, HandleObject proxy, MutableHandleValue vp)
{
JS_CHECK_RECURSION(cx, return false);
return proxy->as<ProxyObject>().handler()->boxedValue_unbox(cx, proxy, vp);
}
bool
Proxy::defaultValue(JSContext *cx, HandleObject proxy, JSType hint, MutableHandleValue vp)
{
JS_CHECK_RECURSION(cx, return false);
return proxy->as<ProxyObject>().handler()->defaultValue(cx, proxy, hint, vp);
}
JSObject * const TaggedProto::LazyProto = reinterpret_cast<JSObject *>(0x1);
bool
Proxy::getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject proto)
{
JS_ASSERT(proxy->getTaggedProto().isLazy());
JS_CHECK_RECURSION(cx, return false);
return proxy->as<ProxyObject>().handler()->getPrototypeOf(cx, proxy, proto);
}
bool
Proxy::setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp)
{
JS_ASSERT(proxy->getTaggedProto().isLazy());
JS_CHECK_RECURSION(cx, return false);
return proxy->as<ProxyObject>().handler()->setPrototypeOf(cx, proxy, proto, bp);
}
/* static */ bool
Proxy::watch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleObject callable)
{
JS_CHECK_RECURSION(cx, return false);
return proxy->as<ProxyObject>().handler()->watch(cx, proxy, id, callable);
}
/* static */ bool
Proxy::unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id)
{
JS_CHECK_RECURSION(cx, return false);
return proxy->as<ProxyObject>().handler()->unwatch(cx, proxy, id);
}
/* static */ bool
Proxy::slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
HandleObject result)
{
JS_CHECK_RECURSION(cx, return false);
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::GET,
/* mayThrow = */ true);
if (!policy.allowed()) {
if (policy.returnValue()) {
JS_ASSERT(!cx->isExceptionPending());
return js::SliceSlowly(cx, proxy, proxy, begin, end, result);
}
return false;
}
return handler->slice(cx, proxy, begin, end, result);
}
JSObject *
js::proxy_innerObject(JSObject *obj)
{
return obj->as<ProxyObject>().private_().toObjectOrNull();
}
bool
js::proxy_LookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
MutableHandleObject objp, MutableHandleShape propp)
{
bool found;
if (!Proxy::has(cx, obj, id, &found))
return false;
if (found) {
MarkNonNativePropertyFound(propp);
objp.set(obj);
} else {
objp.set(nullptr);
propp.set(nullptr);
}
return true;
}
bool
js::proxy_LookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
MutableHandleObject objp, MutableHandleShape propp)
{
RootedId id(cx, NameToId(name));
return proxy_LookupGeneric(cx, obj, id, objp, propp);
}
bool
js::proxy_LookupElement(JSContext *cx, HandleObject obj, uint32_t index,
MutableHandleObject objp, MutableHandleShape propp)
{
RootedId id(cx);
if (!IndexToId(cx, index, &id))
return false;
return proxy_LookupGeneric(cx, obj, id, objp, propp);
}
bool
js::proxy_DefineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue value,
PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
{
Rooted<PropertyDescriptor> desc(cx);
desc.object().set(obj);
desc.value().set(value);
desc.setAttributes(attrs);
desc.setGetter(getter);
desc.setSetter(setter);
return Proxy::defineProperty(cx, obj, id, &desc);
}
bool
js::proxy_DefineProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value,
PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
{
Rooted<jsid> id(cx, NameToId(name));
return proxy_DefineGeneric(cx, obj, id, value, getter, setter, attrs);
}
bool
js::proxy_DefineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue value,
PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
{
RootedId id(cx);
if (!IndexToId(cx, index, &id))
return false;
return proxy_DefineGeneric(cx, obj, id, value, getter, setter, attrs);
}
bool
js::proxy_GetGeneric(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
MutableHandleValue vp)
{
return Proxy::get(cx, obj, receiver, id, vp);
}
bool
js::proxy_GetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandlePropertyName name,
MutableHandleValue vp)
{
Rooted<jsid> id(cx, NameToId(name));
return proxy_GetGeneric(cx, obj, receiver, id, vp);
}
bool
js::proxy_GetElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index,
MutableHandleValue vp)
{
RootedId id(cx);
if (!IndexToId(cx, index, &id))
return false;
return proxy_GetGeneric(cx, obj, receiver, id, vp);
}
bool
js::proxy_SetGeneric(JSContext *cx, HandleObject obj, HandleId id,
MutableHandleValue vp, bool strict)
{
return Proxy::set(cx, obj, obj, id, strict, vp);
}
bool
js::proxy_SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
MutableHandleValue vp, bool strict)
{
Rooted<jsid> id(cx, NameToId(name));
return proxy_SetGeneric(cx, obj, id, vp, strict);
}
bool
js::proxy_SetElement(JSContext *cx, HandleObject obj, uint32_t index,
MutableHandleValue vp, bool strict)
{
RootedId id(cx);
if (!IndexToId(cx, index, &id))
return false;
return proxy_SetGeneric(cx, obj, id, vp, strict);
}
bool
js::proxy_GetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
{
Rooted<PropertyDescriptor> desc(cx);
if (!Proxy::getOwnPropertyDescriptor(cx, obj, id, &desc))
return false;
*attrsp = desc.attributes();
return true;
}
bool
js::proxy_SetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
{
/* Lookup the current property descriptor so we have setter/getter/value. */
Rooted<PropertyDescriptor> desc(cx);
if (!Proxy::getOwnPropertyDescriptor(cx, obj, id, &desc))
return false;
desc.setAttributes(*attrsp);
return Proxy::defineProperty(cx, obj, id, &desc);
}
bool
js::proxy_DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded)
{
bool deleted;
if (!Proxy::delete_(cx, obj, id, &deleted))
return false;
*succeeded = deleted;
return js_SuppressDeletedProperty(cx, obj, id);
}
void
js::proxy_Trace(JSTracer *trc, JSObject *obj)
{
JS_ASSERT(obj->is<ProxyObject>());
ProxyObject::trace(trc, obj);
}
/* static */ void
ProxyObject::trace(JSTracer *trc, JSObject *obj)
{
ProxyObject *proxy = &obj->as<ProxyObject>();
#ifdef DEBUG
if (trc->runtime()->gc.isStrictProxyCheckingEnabled() && proxy->is<WrapperObject>()) {
JSObject *referent = MaybeForwarded(&proxy->private_().toObject());
if (referent->compartment() != proxy->compartment()) {
/*
* Assert that this proxy is tracked in the wrapper map. We maintain
* the invariant that the wrapped object is the key in the wrapper map.
*/
Value key = ObjectValue(*referent);
WrapperMap::Ptr p = proxy->compartment()->lookupWrapper(key);
JS_ASSERT(p);
JS_ASSERT(*p->value().unsafeGet() == ObjectValue(*proxy));
}
}
#endif
// Note: If you add new slots here, make sure to change
// nuke() to cope.
MarkCrossCompartmentSlot(trc, obj, proxy->slotOfPrivate(), "private");
MarkSlot(trc, proxy->slotOfExtra(0), "extra0");
/*
* The GC can use the second reserved slot to link the cross compartment
* wrappers into a linked list, in which case we don't want to trace it.
*/
if (!proxy->is<CrossCompartmentWrapperObject>())
MarkSlot(trc, proxy->slotOfExtra(1), "extra1");
/*
* Allow for people to add extra slots to "proxy" classes, without allowing
* them to set their own trace hook. Trace the extras.
*/
unsigned numSlots = JSCLASS_RESERVED_SLOTS(proxy->getClass());
for (unsigned i = PROXY_MINIMUM_SLOTS; i < numSlots; i++)
MarkSlot(trc, proxy->slotOfClassSpecific(i), "class-specific");
}
JSObject *
js::proxy_WeakmapKeyDelegate(JSObject *obj)
{
JS_ASSERT(obj->is<ProxyObject>());
return obj->as<ProxyObject>().handler()->weakmapKeyDelegate(obj);
}
bool
js::proxy_Convert(JSContext *cx, HandleObject proxy, JSType hint, MutableHandleValue vp)
{
JS_ASSERT(proxy->is<ProxyObject>());
return Proxy::defaultValue(cx, proxy, hint, vp);
}
void
js::proxy_Finalize(FreeOp *fop, JSObject *obj)
{
JS_ASSERT(obj->is<ProxyObject>());
obj->as<ProxyObject>().handler()->finalize(fop, obj);
}
void
js::proxy_ObjectMoved(JSObject *obj, const JSObject *old)
{
JS_ASSERT(obj->is<ProxyObject>());
obj->as<ProxyObject>().handler()->objectMoved(obj, old);
}
bool
js::proxy_HasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp)
{
bool b;
if (!Proxy::hasInstance(cx, proxy, v, &b))
return false;
*bp = !!b;
return true;
}
bool
js::proxy_Call(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedObject proxy(cx, &args.callee());
JS_ASSERT(proxy->is<ProxyObject>());
return Proxy::call(cx, proxy, args);
}
bool
js::proxy_Construct(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedObject proxy(cx, &args.callee());
JS_ASSERT(proxy->is<ProxyObject>());
return Proxy::construct(cx, proxy, args);
}
bool
js::proxy_Watch(JSContext *cx, HandleObject obj, HandleId id, HandleObject callable)
{
return Proxy::watch(cx, obj, id, callable);
}
bool
js::proxy_Unwatch(JSContext *cx, HandleObject obj, HandleId id)
{
return Proxy::unwatch(cx, obj, id);
}
bool
js::proxy_Slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
HandleObject result)
{
return Proxy::slice(cx, proxy, begin, end, result);
}
#define PROXY_CLASS(callOp, constructOp) \
PROXY_CLASS_DEF("Proxy", \
0, /* additional slots */ \
JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy), \
callOp, \
constructOp)
const Class js::ProxyObject::uncallableClass_ = PROXY_CLASS(nullptr, nullptr);
const Class js::ProxyObject::callableClass_ = PROXY_CLASS(proxy_Call, proxy_Construct);
const Class* const js::CallableProxyClassPtr = &ProxyObject::callableClass_;
const Class* const js::UncallableProxyClassPtr = &ProxyObject::uncallableClass_;
JS_FRIEND_API(JSObject *)
js::NewProxyObject(JSContext *cx, const BaseProxyHandler *handler, HandleValue priv, JSObject *proto_,
JSObject *parent_, const ProxyOptions &options)
{
return ProxyObject::New(cx, handler, priv, TaggedProto(proto_), parent_,
options);
}
void
ProxyObject::renew(JSContext *cx, const BaseProxyHandler *handler, Value priv)
{
JS_ASSERT_IF(IsCrossCompartmentWrapper(this), IsDeadProxyObject(this));
JS_ASSERT(getParent() == cx->global());
JS_ASSERT(getClass() == &uncallableClass_);
JS_ASSERT(!getClass()->ext.innerObject);
JS_ASSERT(getTaggedProto().isLazy());
setHandler(handler);
setCrossCompartmentSlot(PRIVATE_SLOT, priv);
setSlot(EXTRA_SLOT + 0, UndefinedValue());
setSlot(EXTRA_SLOT + 1, UndefinedValue());
}
JS_FRIEND_API(JSObject *)
js_InitProxyClass(JSContext *cx, HandleObject obj)
{
static const JSFunctionSpec static_methods[] = {
JS_FN("create", proxy_create, 2, 0),
JS_FN("createFunction", proxy_createFunction, 3, 0),
JS_FN("revocable", proxy_revocable, 2, 0),
JS_FS_END
};
Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
RootedFunction ctor(cx);
ctor = global->createConstructor(cx, proxy, cx->names().Proxy, 2);
if (!ctor)
return nullptr;
if (!JS_DefineFunctions(cx, ctor, static_methods))
return nullptr;
if (!JS_DefineProperty(cx, obj, "Proxy", ctor, 0,
JS_PropertyStub, JS_StrictPropertyStub)) {
return nullptr;
}
global->setConstructor(JSProto_Proxy, ObjectValue(*ctor));
return ctor;
}

82
js/src/proxy/Proxy.h Normal file
Просмотреть файл

@ -0,0 +1,82 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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/. */
#ifndef proxy_Proxy_h
#define proxy_Proxy_h
#include "NamespaceImports.h"
#include "js/Class.h"
namespace js {
class RegExpGuard;
/*
* Dispatch point for handlers that executes the appropriate C++ or scripted traps.
*
* Important: All proxy traps need either (a) an AutoEnterPolicy in their
* Proxy::foo entry point below or (b) an override in SecurityWrapper. See bug
* 945826 comment 0.
*/
class Proxy
{
public:
/* ES5 Harmony fundamental proxy traps. */
static bool preventExtensions(JSContext *cx, HandleObject proxy);
static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc);
static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandleValue vp);
static bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc);
static bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandleValue vp);
static bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc);
static bool getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props);
static bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
static bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props);
/* ES5 Harmony derived proxy traps. */
static bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
static bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
static bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
MutableHandleValue vp);
static bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
bool strict, MutableHandleValue vp);
static bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props);
static bool iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleValue vp);
/* Spidermonkey extensions. */
static bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible);
static bool call(JSContext *cx, HandleObject proxy, const CallArgs &args);
static bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args);
static bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args);
static bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp);
static bool objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx);
static const char *className(JSContext *cx, HandleObject proxy);
static JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent);
static bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g);
static bool boxedValue_unbox(JSContext *cx, HandleObject proxy, MutableHandleValue vp);
static bool defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp);
static bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop);
static bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp);
static bool watch(JSContext *cx, HandleObject proxy, HandleId id, HandleObject callable);
static bool unwatch(JSContext *cx, HandleObject proxy, HandleId id);
static bool slice(JSContext *cx, HandleObject obj, uint32_t begin, uint32_t end,
HandleObject result);
/* IC entry path for handling __noSuchMethod__ on access. */
static bool callProp(JSContext *cx, HandleObject proxy, HandleObject reveiver, HandleId id,
MutableHandleValue vp);
};
} /* namespace js */
#endif /* proxy_Proxy_h */

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,78 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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/. */
#ifndef proxy_ScriptedDirectProxyHandler_h
#define proxy_ScriptedDirectProxyHandler_h
#include "jsproxy.h"
namespace js {
/* Derived class for all scripted direct proxy handlers. */
class ScriptedDirectProxyHandler : public DirectProxyHandler {
public:
MOZ_CONSTEXPR ScriptedDirectProxyHandler()
: DirectProxyHandler(&family)
{ }
/* ES5 Harmony fundamental proxy traps. */
virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool getOwnPropertyNames(JSContext *cx, HandleObject proxy,
AutoIdVector &props) const MOZ_OVERRIDE;
virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE;
/* ES5 Harmony derived proxy traps. */
virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE {
return BaseProxyHandler::hasOwn(cx, proxy, id, bp);
}
virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
MutableHandleValue vp) const MOZ_OVERRIDE;
virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
bool strict, MutableHandleValue vp) const MOZ_OVERRIDE;
// Kick keys out to getOwnPropertyName and then filter. [[GetOwnProperty]] could potentially
// change the enumerability of the target's properties.
virtual bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE {
return BaseProxyHandler::keys(cx, proxy, props);
}
virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags,
MutableHandleValue vp) const MOZ_OVERRIDE;
/* ES6 Harmony traps */
virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
/* Spidermonkey extensions. */
virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
virtual bool isScripted() const MOZ_OVERRIDE { return true; }
static const char family;
static const ScriptedDirectProxyHandler singleton;
// The "proxy extra" slot index in which the handler is stored. Revocable proxies need to set
// this at revocation time.
static const int HANDLER_EXTRA = 0;
// The "function extended" slot index in which the revocation object is stored. Per spec, this
// is to be cleared during the first revocation.
static const int REVOKE_SLOT = 0;
};
bool
proxy(JSContext *cx, unsigned argc, jsval *vp);
bool
proxy_revocable(JSContext *cx, unsigned argc, jsval *vp);
} /* namespace js */
#endif /* proxy_ScriptedDirectProxyHandler_h */

Просмотреть файл

@ -0,0 +1,462 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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/. */
#include "proxy/ScriptedIndirectProxyHandler.h"
#include "jsapi.h"
#include "jscntxt.h"
#include "jsobjinlines.h"
using namespace js;
static bool
GetFundamentalTrap(JSContext *cx, HandleObject handler, HandlePropertyName name,
MutableHandleValue fvalp)
{
JS_CHECK_RECURSION(cx, return false);
return JSObject::getProperty(cx, handler, handler, name, fvalp);
}
static bool
GetDerivedTrap(JSContext *cx, HandleObject handler, HandlePropertyName name,
MutableHandleValue fvalp)
{
JS_ASSERT(name == cx->names().has ||
name == cx->names().hasOwn ||
name == cx->names().get ||
name == cx->names().set ||
name == cx->names().keys ||
name == cx->names().iterate);
return JSObject::getProperty(cx, handler, handler, name, fvalp);
}
static bool
Trap(JSContext *cx, HandleObject handler, HandleValue fval, unsigned argc, Value* argv,
MutableHandleValue rval)
{
return Invoke(cx, ObjectValue(*handler), fval, argc, argv, rval);
}
static bool
Trap1(JSContext *cx, HandleObject handler, HandleValue fval, HandleId id, MutableHandleValue rval)
{
if (!IdToStringOrSymbol(cx, id, rval))
return false;
return Trap(cx, handler, fval, 1, rval.address(), rval);
}
static bool
Trap2(JSContext *cx, HandleObject handler, HandleValue fval, HandleId id, Value v_,
MutableHandleValue rval)
{
RootedValue v(cx, v_);
if (!IdToStringOrSymbol(cx, id, rval))
return false;
JS::AutoValueArray<2> argv(cx);
argv[0].set(rval);
argv[1].set(v);
return Trap(cx, handler, fval, 2, argv.begin(), rval);
}
static bool
IndicatePropertyNotFound(MutableHandle<PropertyDescriptor> desc)
{
desc.object().set(nullptr);
return true;
}
static bool
ValueToBool(HandleValue v, bool *bp)
{
*bp = ToBoolean(v);
return true;
}
static bool
ArrayToIdVector(JSContext *cx, const Value &array, AutoIdVector &props)
{
JS_ASSERT(props.length() == 0);
if (array.isPrimitive())
return true;
RootedObject obj(cx, &array.toObject());
uint32_t length;
if (!GetLengthProperty(cx, obj, &length))
return false;
RootedValue v(cx);
for (uint32_t n = 0; n < length; ++n) {
if (!CheckForInterrupt(cx))
return false;
if (!JSObject::getElement(cx, obj, obj, n, &v))
return false;
RootedId id(cx);
if (!ValueToId<CanGC>(cx, v, &id))
return false;
if (!props.append(id))
return false;
}
return true;
}
namespace {
/*
* Old-style indirect proxies allow callers to specify distinct scripted
* [[Call]] and [[Construct]] traps. We use an intermediate object so that we
* can stash this information in a single reserved slot on the proxy object.
*
* Note - Currently this is slightly unnecesary, because we actually have 2
* extra slots, neither of which are used for ScriptedIndirectProxy. But we're
* eventually moving towards eliminating one of those slots, and so we don't
* want to add a dependency here.
*/
static const Class CallConstructHolder = {
"CallConstructHolder",
JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS
};
} /* anonymous namespace */
// This variable exists solely to provide a unique address for use as an identifier.
const char ScriptedIndirectProxyHandler::family = 0;
bool
ScriptedIndirectProxyHandler::isExtensible(JSContext *cx, HandleObject proxy,
bool *extensible) const
{
// Scripted indirect proxies don't support extensibility changes.
*extensible = true;
return true;
}
bool
ScriptedIndirectProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy) const
{
// See above.
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_CHANGE_EXTENSIBILITY);
return false;
}
static bool
ReturnedValueMustNotBePrimitive(JSContext *cx, HandleObject proxy, JSAtom *atom, const Value &v)
{
if (v.isPrimitive()) {
JSAutoByteString bytes;
if (AtomToPrintableString(cx, atom, &bytes)) {
RootedValue val(cx, ObjectOrNullValue(proxy));
js_ReportValueError2(cx, JSMSG_BAD_TRAP_RETURN_VALUE,
JSDVG_SEARCH_STACK, val, js::NullPtr(), bytes.ptr());
}
return false;
}
return true;
}
static JSObject *
GetIndirectProxyHandlerObject(JSObject *proxy)
{
return proxy->as<ProxyObject>().private_().toObjectOrNull();
}
bool
ScriptedIndirectProxyHandler::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<PropertyDescriptor> desc) const
{
RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
RootedValue fval(cx), value(cx);
return GetFundamentalTrap(cx, handler, cx->names().getPropertyDescriptor, &fval) &&
Trap1(cx, handler, fval, id, &value) &&
((value.get().isUndefined() && IndicatePropertyNotFound(desc)) ||
(ReturnedValueMustNotBePrimitive(cx, proxy, cx->names().getPropertyDescriptor, value) &&
ParsePropertyDescriptorObject(cx, proxy, value, desc)));
}
bool
ScriptedIndirectProxyHandler::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<PropertyDescriptor> desc) const
{
RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
RootedValue fval(cx), value(cx);
return GetFundamentalTrap(cx, handler, cx->names().getOwnPropertyDescriptor, &fval) &&
Trap1(cx, handler, fval, id, &value) &&
((value.get().isUndefined() && IndicatePropertyNotFound(desc)) ||
(ReturnedValueMustNotBePrimitive(cx, proxy, cx->names().getPropertyDescriptor, value) &&
ParsePropertyDescriptorObject(cx, proxy, value, desc)));
}
bool
ScriptedIndirectProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<PropertyDescriptor> desc) const
{
RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
RootedValue fval(cx), value(cx);
return GetFundamentalTrap(cx, handler, cx->names().defineProperty, &fval) &&
NewPropertyDescriptorObject(cx, desc, &value) &&
Trap2(cx, handler, fval, id, value, &value);
}
bool
ScriptedIndirectProxyHandler::getOwnPropertyNames(JSContext *cx, HandleObject proxy,
AutoIdVector &props) const
{
RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
RootedValue fval(cx), value(cx);
return GetFundamentalTrap(cx, handler, cx->names().getOwnPropertyNames, &fval) &&
Trap(cx, handler, fval, 0, nullptr, &value) &&
ArrayToIdVector(cx, value, props);
}
bool
ScriptedIndirectProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const
{
RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
RootedValue fval(cx), value(cx);
return GetFundamentalTrap(cx, handler, cx->names().delete_, &fval) &&
Trap1(cx, handler, fval, id, &value) &&
ValueToBool(value, bp);
}
bool
ScriptedIndirectProxyHandler::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) const
{
RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
RootedValue fval(cx), value(cx);
return GetFundamentalTrap(cx, handler, cx->names().enumerate, &fval) &&
Trap(cx, handler, fval, 0, nullptr, &value) &&
ArrayToIdVector(cx, value, props);
}
bool
ScriptedIndirectProxyHandler::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const
{
RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
RootedValue fval(cx), value(cx);
if (!GetDerivedTrap(cx, handler, cx->names().has, &fval))
return false;
if (!IsCallable(fval))
return BaseProxyHandler::has(cx, proxy, id, bp);
return Trap1(cx, handler, fval, id, &value) &&
ValueToBool(value, bp);
}
bool
ScriptedIndirectProxyHandler::hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const
{
RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
RootedValue fval(cx), value(cx);
if (!GetDerivedTrap(cx, handler, cx->names().hasOwn, &fval))
return false;
if (!IsCallable(fval))
return BaseProxyHandler::hasOwn(cx, proxy, id, bp);
return Trap1(cx, handler, fval, id, &value) &&
ValueToBool(value, bp);
}
bool
ScriptedIndirectProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, MutableHandleValue vp) const
{
RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
RootedValue idv(cx);
if (!IdToStringOrSymbol(cx, id, &idv))
return false;
JS::AutoValueArray<2> argv(cx);
argv[0].setObjectOrNull(receiver);
argv[1].set(idv);
RootedValue fval(cx);
if (!GetDerivedTrap(cx, handler, cx->names().get, &fval))
return false;
if (!IsCallable(fval))
return BaseProxyHandler::get(cx, proxy, receiver, id, vp);
return Trap(cx, handler, fval, 2, argv.begin(), vp);
}
bool
ScriptedIndirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, bool strict, MutableHandleValue vp) const
{
RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
RootedValue idv(cx);
if (!IdToStringOrSymbol(cx, id, &idv))
return false;
JS::AutoValueArray<3> argv(cx);
argv[0].setObjectOrNull(receiver);
argv[1].set(idv);
argv[2].set(vp);
RootedValue fval(cx);
if (!GetDerivedTrap(cx, handler, cx->names().set, &fval))
return false;
if (!IsCallable(fval))
return BaseProxyHandler::set(cx, proxy, receiver, id, strict, vp);
return Trap(cx, handler, fval, 3, argv.begin(), &idv);
}
bool
ScriptedIndirectProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const
{
RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
RootedValue value(cx);
if (!GetDerivedTrap(cx, handler, cx->names().keys, &value))
return false;
if (!IsCallable(value))
return BaseProxyHandler::keys(cx, proxy, props);
return Trap(cx, handler, value, 0, nullptr, &value) &&
ArrayToIdVector(cx, value, props);
}
bool
ScriptedIndirectProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags,
MutableHandleValue vp) const
{
RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
RootedValue value(cx);
if (!GetDerivedTrap(cx, handler, cx->names().iterate, &value))
return false;
if (!IsCallable(value))
return BaseProxyHandler::iterate(cx, proxy, flags, vp);
return Trap(cx, handler, value, 0, nullptr, vp) &&
ReturnedValueMustNotBePrimitive(cx, proxy, cx->names().iterate, vp);
}
bool
ScriptedIndirectProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args) const
{
assertEnteredPolicy(cx, proxy, JSID_VOID, CALL);
RootedObject ccHolder(cx, &proxy->as<ProxyObject>().extra(0).toObject());
JS_ASSERT(ccHolder->getClass() == &CallConstructHolder);
RootedValue call(cx, ccHolder->getReservedSlot(0));
JS_ASSERT(call.isObject() && call.toObject().isCallable());
return Invoke(cx, args.thisv(), call, args.length(), args.array(), args.rval());
}
bool
ScriptedIndirectProxyHandler::construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const
{
assertEnteredPolicy(cx, proxy, JSID_VOID, CALL);
RootedObject ccHolder(cx, &proxy->as<ProxyObject>().extra(0).toObject());
JS_ASSERT(ccHolder->getClass() == &CallConstructHolder);
RootedValue construct(cx, ccHolder->getReservedSlot(1));
JS_ASSERT(construct.isObject() && construct.toObject().isCallable());
return InvokeConstructor(cx, construct, args.length(), args.array(),
args.rval().address());
}
bool
ScriptedIndirectProxyHandler::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
CallArgs args) const
{
return BaseProxyHandler::nativeCall(cx, test, impl, args);
}
JSString *
ScriptedIndirectProxyHandler::fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) const
{
assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
if (!proxy->isCallable()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
JSMSG_INCOMPATIBLE_PROTO,
js_Function_str, js_toString_str,
"object");
return nullptr;
}
RootedObject obj(cx, &proxy->as<ProxyObject>().extra(0).toObject().getReservedSlot(0).toObject());
return fun_toStringHelper(cx, obj, indent);
}
const ScriptedIndirectProxyHandler ScriptedIndirectProxyHandler::singleton;
bool
js::proxy_create(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() < 1) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
"create", "0", "s");
return false;
}
JSObject *handler = NonNullObject(cx, args[0]);
if (!handler)
return false;
JSObject *proto, *parent = nullptr;
if (args.get(1).isObject()) {
proto = &args[1].toObject();
parent = proto->getParent();
} else {
JS_ASSERT(IsFunctionObject(&args.callee()));
proto = nullptr;
}
if (!parent)
parent = args.callee().getParent();
RootedValue priv(cx, ObjectValue(*handler));
JSObject *proxy = NewProxyObject(cx, &ScriptedIndirectProxyHandler::singleton,
priv, proto, parent);
if (!proxy)
return false;
args.rval().setObject(*proxy);
return true;
}
bool
js::proxy_createFunction(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() < 2) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
"createFunction", "1", "");
return false;
}
RootedObject handler(cx, NonNullObject(cx, args[0]));
if (!handler)
return false;
RootedObject proto(cx), parent(cx);
parent = args.callee().getParent();
proto = parent->global().getOrCreateFunctionPrototype(cx);
if (!proto)
return false;
parent = proto->getParent();
RootedObject call(cx, ValueToCallable(cx, args[1], args.length() - 2));
if (!call)
return false;
RootedObject construct(cx, nullptr);
if (args.length() > 2) {
construct = ValueToCallable(cx, args[2], args.length() - 3);
if (!construct)
return false;
} else {
construct = call;
}
// Stash the call and construct traps on a holder object that we can stick
// in a slot on the proxy.
RootedObject ccHolder(cx, JS_NewObjectWithGivenProto(cx, Jsvalify(&CallConstructHolder),
js::NullPtr(), cx->global()));
if (!ccHolder)
return false;
ccHolder->setReservedSlot(0, ObjectValue(*call));
ccHolder->setReservedSlot(1, ObjectValue(*construct));
RootedValue priv(cx, ObjectValue(*handler));
ProxyOptions options;
options.selectDefaultClass(true);
JSObject *proxy =
ProxyObject::New(cx, &ScriptedIndirectProxyHandler::singleton,
priv, TaggedProto(proto), parent, options);
if (!proxy)
return false;
proxy->as<ProxyObject>().setExtra(0, ObjectValue(*ccHolder));
args.rval().setObject(*proxy);
return true;
}

Просмотреть файл

@ -0,0 +1,67 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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/. */
#ifndef proxy_ScriptedIndirectProxyHandler_h
#define proxy_ScriptedIndirectProxyHandler_h
#include "jsproxy.h"
namespace js {
/* Derived class for all scripted indirect proxy handlers. */
class ScriptedIndirectProxyHandler : public BaseProxyHandler
{
public:
MOZ_CONSTEXPR ScriptedIndirectProxyHandler()
: BaseProxyHandler(&family)
{ }
/* ES5 Harmony fundamental proxy traps. */
virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool getOwnPropertyNames(JSContext *cx, HandleObject proxy,
AutoIdVector &props) const MOZ_OVERRIDE;
virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE;
/* ES5 Harmony derived proxy traps. */
virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
MutableHandleValue vp) const MOZ_OVERRIDE;
virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
bool strict, MutableHandleValue vp) const MOZ_OVERRIDE;
virtual bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE;
virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags,
MutableHandleValue vp) const MOZ_OVERRIDE;
/* Spidermonkey extensions. */
virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
CallArgs args) const MOZ_OVERRIDE;
virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) const MOZ_OVERRIDE;
virtual bool isScripted() const MOZ_OVERRIDE { return true; }
static const char family;
static const ScriptedIndirectProxyHandler singleton;
};
bool
proxy_create(JSContext *cx, unsigned argc, Value *vp);
bool
proxy_createFunction(JSContext *cx, unsigned argc, Value *vp);
} /* namespace js */
#endif /* proxy_ScriptedIndirectProxyHandler_h */

Просмотреть файл

@ -0,0 +1,134 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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/. */
#include "jsapi.h"
#include "jswrapper.h"
#include "jsatominlines.h"
using namespace js;
template <class Base>
bool
SecurityWrapper<Base>::isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) const
{
// Just like BaseProxyHandler, SecurityWrappers claim by default to always
// be extensible, so as not to leak information about the state of the
// underlying wrapped thing.
*extensible = true;
return true;
}
template <class Base>
bool
SecurityWrapper<Base>::preventExtensions(JSContext *cx, HandleObject wrapper) const
{
// See above.
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_UNWRAP_DENIED);
return false;
}
template <class Base>
bool
SecurityWrapper<Base>::enter(JSContext *cx, HandleObject wrapper, HandleId id,
Wrapper::Action act, bool *bp) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_UNWRAP_DENIED);
*bp = false;
return false;
}
template <class Base>
bool
SecurityWrapper<Base>::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
CallArgs args) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_UNWRAP_DENIED);
return false;
}
template <class Base>
bool
SecurityWrapper<Base>::setPrototypeOf(JSContext *cx, HandleObject wrapper,
HandleObject proto, bool *bp) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_UNWRAP_DENIED);
return false;
}
// For security wrappers, we run the DefaultValue algorithm on the wrapper
// itself, which means that the existing security policy on operations like
// toString() will take effect and do the right thing here.
template <class Base>
bool
SecurityWrapper<Base>::defaultValue(JSContext *cx, HandleObject wrapper,
JSType hint, MutableHandleValue vp) const
{
return DefaultValue(cx, wrapper, hint, vp);
}
template <class Base>
bool
SecurityWrapper<Base>::objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx) const
{
return false;
}
template <class Base>
bool
SecurityWrapper<Base>::regexp_toShared(JSContext *cx, HandleObject obj, RegExpGuard *g) const
{
return Base::regexp_toShared(cx, obj, g);
}
template <class Base>
bool
SecurityWrapper<Base>::boxedValue_unbox(JSContext *cx, HandleObject obj, MutableHandleValue vp) const
{
vp.setUndefined();
return true;
}
template <class Base>
bool
SecurityWrapper<Base>::defineProperty(JSContext *cx, HandleObject wrapper,
HandleId id, MutableHandle<PropertyDescriptor> desc) const
{
if (desc.getter() || desc.setter()) {
JSString *str = IdToString(cx, id);
AutoStableStringChars chars(cx);
const char16_t *prop = nullptr;
if (str->ensureFlat(cx) && chars.initTwoByte(cx, str))
prop = chars.twoByteChars();
JS_ReportErrorNumberUC(cx, js_GetErrorMessage, nullptr,
JSMSG_ACCESSOR_DEF_DENIED, prop);
return false;
}
return Base::defineProperty(cx, wrapper, id, desc);
}
template <class Base>
bool
SecurityWrapper<Base>::watch(JSContext *cx, HandleObject proxy,
HandleId id, HandleObject callable) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_UNWRAP_DENIED);
return false;
}
template <class Base>
bool
SecurityWrapper<Base>::unwatch(JSContext *cx, HandleObject proxy,
HandleId id) const
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_UNWRAP_DENIED);
return false;
}
template class js::SecurityWrapper<Wrapper>;
template class js::SecurityWrapper<CrossCompartmentWrapper>;

167
js/src/proxy/Wrapper.cpp Normal file
Просмотреть файл

@ -0,0 +1,167 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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/. */
#include "jscntxt.h"
#include "jscompartment.h"
#include "jsexn.h"
#include "jswrapper.h"
#include "vm/ErrorObject.h"
#include "vm/WrapperObject.h"
#include "jsobjinlines.h"
using namespace js;
/*
* Wrapper forwards this call directly to the wrapped object for efficiency
* and transparency. In particular, the hint is needed to properly stringify
* Date objects in certain cases - see bug 646129. Note also the
* SecurityWrapper overrides this trap to avoid information leaks. See bug
* 720619.
*/
bool
Wrapper::defaultValue(JSContext *cx, HandleObject proxy, JSType hint, MutableHandleValue vp) const
{
vp.set(ObjectValue(*proxy->as<ProxyObject>().target()));
if (hint == JSTYPE_VOID)
return ToPrimitive(cx, vp);
return ToPrimitive(cx, hint, vp);
}
JSObject *
Wrapper::New(JSContext *cx, JSObject *obj, JSObject *parent, const Wrapper *handler,
const WrapperOptions *options)
{
JS_ASSERT(parent);
RootedValue priv(cx, ObjectValue(*obj));
mozilla::Maybe<WrapperOptions> opts;
if (!options) {
opts.emplace();
opts->selectDefaultClass(obj->isCallable());
options = opts.ptr();
}
return NewProxyObject(cx, handler, priv, options->proto(), parent, *options);
}
JSObject *
Wrapper::Renew(JSContext *cx, JSObject *existing, JSObject *obj, const Wrapper *handler)
{
JS_ASSERT(!obj->isCallable());
existing->as<ProxyObject>().renew(cx, handler, ObjectValue(*obj));
return existing;
}
const Wrapper *
Wrapper::wrapperHandler(JSObject *wrapper)
{
JS_ASSERT(wrapper->is<WrapperObject>());
return static_cast<const Wrapper*>(wrapper->as<ProxyObject>().handler());
}
JSObject *
Wrapper::wrappedObject(JSObject *wrapper)
{
JS_ASSERT(wrapper->is<WrapperObject>());
return wrapper->as<ProxyObject>().target();
}
JS_FRIEND_API(JSObject *)
js::UncheckedUnwrap(JSObject *wrapped, bool stopAtOuter, unsigned *flagsp)
{
unsigned flags = 0;
while (true) {
if (!wrapped->is<WrapperObject>() ||
MOZ_UNLIKELY(stopAtOuter && wrapped->getClass()->ext.innerObject))
{
break;
}
flags |= Wrapper::wrapperHandler(wrapped)->flags();
wrapped = wrapped->as<ProxyObject>().private_().toObjectOrNull();
// This can be called from DirectProxyHandler::weakmapKeyDelegate() on a
// wrapper whose referent has been moved while it is still unmarked.
if (wrapped)
wrapped = MaybeForwarded(wrapped);
}
if (flagsp)
*flagsp = flags;
return wrapped;
}
JS_FRIEND_API(JSObject *)
js::CheckedUnwrap(JSObject *obj, bool stopAtOuter)
{
while (true) {
JSObject *wrapper = obj;
obj = UnwrapOneChecked(obj, stopAtOuter);
if (!obj || obj == wrapper)
return obj;
}
}
JS_FRIEND_API(JSObject *)
js::UnwrapOneChecked(JSObject *obj, bool stopAtOuter)
{
if (!obj->is<WrapperObject>() ||
MOZ_UNLIKELY(!!obj->getClass()->ext.innerObject && stopAtOuter))
{
return obj;
}
const Wrapper *handler = Wrapper::wrapperHandler(obj);
return handler->hasSecurityPolicy() ? nullptr : Wrapper::wrappedObject(obj);
}
const char Wrapper::family = 0;
const Wrapper Wrapper::singleton((unsigned)0);
const Wrapper Wrapper::singletonWithPrototype((unsigned)0, true);
JSObject *Wrapper::defaultProto = TaggedProto::LazyProto;
/* Compartments. */
extern JSObject *
js::TransparentObjectWrapper(JSContext *cx, HandleObject existing, HandleObject obj,
HandleObject parent)
{
// Allow wrapping outer window proxies.
JS_ASSERT(!obj->is<WrapperObject>() || obj->getClass()->ext.innerObject);
return Wrapper::New(cx, obj, parent, &CrossCompartmentWrapper::singleton);
}
ErrorCopier::~ErrorCopier()
{
JSContext *cx = ac->context()->asJSContext();
if (ac->origin() != cx->compartment() && cx->isExceptionPending()) {
RootedValue exc(cx);
if (cx->getPendingException(&exc) && exc.isObject() && exc.toObject().is<ErrorObject>()) {
cx->clearPendingException();
ac.reset();
Rooted<ErrorObject*> errObj(cx, &exc.toObject().as<ErrorObject>());
JSObject *copyobj = js_CopyErrorObject(cx, errObj);
if (copyobj)
cx->setPendingException(ObjectValue(*copyobj));
}
}
}
bool Wrapper::finalizeInBackground(Value priv) const
{
if (!priv.isObject())
return true;
/*
* Make the 'background-finalized-ness' of the wrapper the same as the
* wrapped object, to allow transplanting between them.
*
* If the wrapped object is in the nursery then we know it doesn't have a
* finalizer, and so background finalization is ok.
*/
if (IsInsideNursery(&priv.toObject()))
return true;
return IsBackgroundFinalized(priv.toObject().tenuredGetAllocKind());
}

Просмотреть файл

@ -8,8 +8,6 @@ var summary = 'int32x4 add';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = int32x4(1, 2, 3, 4);
var b = int32x4(10, 20, 30, 40);
var c = SIMD.int32x4.add(a, b);
@ -18,6 +16,17 @@ function test() {
assertEq(c.z, 33);
assertEq(c.w, 44);
var INT32_MAX = Math.pow(2, 31) - 1;
var INT32_MIN = -Math.pow(2, 31);
var d = int32x4(INT32_MAX, INT32_MIN, INT32_MAX, INT32_MIN);
var e = int32x4(1, -1, 0, 0);
var f = SIMD.int32x4.add(d, e);
assertEq(f.x, INT32_MIN);
assertEq(f.y, INT32_MAX);
assertEq(f.z, INT32_MAX);
assertEq(f.w, INT32_MIN);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

Просмотреть файл

@ -8,8 +8,6 @@ var summary = 'int32x4 and';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = int32x4(1, 2, 3, 4);
var b = int32x4(10, 20, 30, 40);
var c = SIMD.int32x4.and(a, b);
@ -18,6 +16,17 @@ function test() {
assertEq(c.z, 2);
assertEq(c.w, 0);
var INT32_MAX = Math.pow(2, 31) - 1;
var INT32_MIN = -Math.pow(2, 31);
var d = int32x4(INT32_MAX, INT32_MIN, INT32_MAX, INT32_MIN);
var e = int32x4(INT32_MIN, INT32_MAX, INT32_MAX, INT32_MIN);
var f = SIMD.int32x4.and(d, e);
assertEq(f.x, (INT32_MAX & INT32_MIN) | 0);
assertEq(f.y, (INT32_MIN & INT32_MAX) | 0);
assertEq(f.z, (INT32_MAX & INT32_MAX) | 0);
assertEq(f.w, (INT32_MIN & INT32_MIN) | 0);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

Просмотреть файл

@ -8,8 +8,6 @@ var summary = 'int32x4 equal';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = int32x4(1, 20, 30, 40);
var b = int32x4(10, 20, 30, 4);
var c = SIMD.int32x4.equal(a, b);

Просмотреть файл

@ -8,8 +8,6 @@ var summary = 'int32x4 fromFloat32x4';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = float32x4(1.1, 2.2, 3.3, 4.6);
var c = SIMD.int32x4.fromFloat32x4(a);
assertEq(c.x, 1);
@ -17,6 +15,13 @@ function test() {
assertEq(c.z, 3);
assertEq(c.w, 4);
var d = float32x4(NaN, -0, Infinity, -Infinity);
var f = SIMD.int32x4.fromFloat32x4(d);
assertEq(f.x, 0);
assertEq(f.y, 0);
assertEq(f.z, 0);
assertEq(f.w, 0);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

Просмотреть файл

@ -8,14 +8,19 @@ var summary = 'int32x4 fromFloat32x4Bits';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = float32x4(1, 2, 3, 4);
var c = SIMD.int32x4.fromFloat32x4Bits(a);
assertEq(c.x, 1065353216);
assertEq(c.y, 1073741824);
assertEq(c.z, 1077936128);
assertEq(c.w, 1082130432);
assertEq(c.x, 0x3f800000 | 0);
assertEq(c.y, 0x40000000 | 0);
assertEq(c.z, 0x40400000 | 0);
assertEq(c.w, 0x40800000 | 0);
var d = float32x4(NaN, -0, Infinity, -Infinity);
var f = SIMD.int32x4.fromFloat32x4Bits(d);
assertEq(f.x, 0x7fc00000 | 0);
assertEq(f.y, 0x80000000 | 0);
assertEq(f.z, 0x7f800000 | 0);
assertEq(f.w, 0xff800000 | 0);
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -8,8 +8,6 @@ var summary = 'int32x4 greaterThan';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = int32x4(1, 20, 3, 40);
var b = int32x4(10, 2, 30, 4);
var c = SIMD.int32x4.greaterThan(b,a);

Просмотреть файл

@ -8,8 +8,6 @@ var summary = 'int32x4 lessThan';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = int32x4(1, 20, 3, 40);
var b = int32x4(10, 2, 30, 4);
var c = SIMD.int32x4.lessThan(a, b);

Просмотреть файл

@ -8,8 +8,6 @@ var summary = 'int32x4 lsh';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
for (var bits = 0; bits < 32; bits++) {
var a = int32x4(-1, 2, -3, 4);
var c = SIMD.int32x4.shiftLeft(a, bits);
@ -19,6 +17,16 @@ function test() {
assertEq(c.w, 4 << bits);
}
var INT32_MAX = Math.pow(2, 31) - 1;
var INT32_MIN = -Math.pow(2, 31);
var d = int32x4(INT32_MAX, INT32_MIN, INT32_MAX, INT32_MIN);
var f = SIMD.int32x4.shiftLeft(d, 1);
assertEq(f.x, (INT32_MAX << 1) | 0);
assertEq(f.y, (INT32_MIN << 1) | 0);
assertEq(f.z, (INT32_MAX << 1) | 0);
assertEq(f.w, (INT32_MIN << 1) | 0);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

Просмотреть файл

@ -8,8 +8,6 @@ var summary = 'int32x4 mul';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = int32x4(1, 2, 3, 4);
var b = int32x4(10, 20, 30, 40);
var c = SIMD.int32x4.mul(a, b);
@ -18,6 +16,17 @@ function test() {
assertEq(c.z, 90);
assertEq(c.w, 160);
var INT32_MAX = Math.pow(2, 31) - 1;
var INT32_MIN = -Math.pow(2, 31);
var d = int32x4(INT32_MAX, INT32_MIN, INT32_MAX, INT32_MIN);
var e = int32x4(-1, -1, INT32_MIN, INT32_MIN);
var f = SIMD.int32x4.mul(d, e);
assertEq(f.x, (INT32_MAX * -1) | 0);
assertEq(f.y, (INT32_MIN * -1) | 0);
assertEq(f.z, (INT32_MAX * INT32_MIN) | 0);
assertEq(f.w, (INT32_MIN * INT32_MIN) | 0);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

Просмотреть файл

@ -8,8 +8,6 @@ var summary = 'int32x4 neg';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = int32x4(1, 2, 3, 4);
var c = SIMD.int32x4.neg(a);
assertEq(c.x, -1);
@ -17,6 +15,16 @@ function test() {
assertEq(c.z, -3);
assertEq(c.w, -4);
var INT32_MAX = Math.pow(2, 31) - 1;
var INT32_MIN = -Math.pow(2, 31);
var d = int32x4(INT32_MAX, INT32_MIN, -0, 0);
var f = SIMD.int32x4.neg(d);
assertEq(f.x, -INT32_MAX | 0);
assertEq(f.y, -INT32_MIN | 0);
assertEq(f.z, 0);
assertEq(f.w, 0);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

Просмотреть файл

@ -8,8 +8,6 @@ var summary = 'int32x4 not';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = int32x4(1, 2, 3, 4);
var c = SIMD.int32x4.not(a);
assertEq(c.x, -2);
@ -17,6 +15,16 @@ function test() {
assertEq(c.z, -4);
assertEq(c.w, -5);
var INT32_MAX = Math.pow(2, 31) - 1;
var INT32_MIN = -Math.pow(2, 31);
var d = int32x4(INT32_MAX, INT32_MIN, 0, 0);
var f = SIMD.int32x4.not(d);
assertEq(f.x, ~INT32_MAX | 0);
assertEq(f.y, ~INT32_MIN | 0);
assertEq(f.z, ~0 | 0);
assertEq(f.w, ~0 | 0);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

Просмотреть файл

@ -8,8 +8,6 @@ var summary = 'int32x4 or';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = int32x4(1, 2, 3, 4);
var b = int32x4(10, 20, 30, 40);
var c = SIMD.int32x4.or(a, b);
@ -18,6 +16,17 @@ function test() {
assertEq(c.z, 31);
assertEq(c.w, 44);
var INT32_MAX = Math.pow(2, 31) - 1;
var INT32_MIN = -Math.pow(2, 31);
var d = int32x4(INT32_MAX, INT32_MIN, INT32_MAX, INT32_MIN);
var e = int32x4(INT32_MIN, INT32_MAX, INT32_MAX, INT32_MIN);
var f = SIMD.int32x4.or(d, e);
assertEq(f.x, (INT32_MAX | INT32_MIN) | 0);
assertEq(f.y, (INT32_MIN | INT32_MAX) | 0);
assertEq(f.z, (INT32_MAX | INT32_MAX) | 0);
assertEq(f.w, (INT32_MIN | INT32_MIN) | 0);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

Просмотреть файл

@ -8,8 +8,6 @@ var summary = 'int32x4 rsh';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
for (var bits = 0; bits < 32; bits++) {
var a = int32x4(-1, 2, -3, 4);
var c = SIMD.int32x4.shiftRight(a, bits);
@ -19,6 +17,15 @@ function test() {
assertEq(c.w, 4 >> bits);
}
var INT32_MAX = Math.pow(2, 31) - 1;
var INT32_MIN = -Math.pow(2, 31);
var d = int32x4(INT32_MAX, INT32_MIN, INT32_MAX, INT32_MIN);
var f = SIMD.int32x4.shiftRight(d, 1);
assertEq(f.x, INT32_MAX >> 1);
assertEq(f.y, INT32_MIN >> 1);
assertEq(f.z, INT32_MAX >> 1);
assertEq(f.w, INT32_MIN >> 1);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

Просмотреть файл

@ -8,8 +8,6 @@ var summary = 'int32x4 shuffle';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = int32x4(1, 2, 3, 4);
var c = SIMD.int32x4.shuffle(a, 0x1B);
assertEq(c.x, 4);

Просмотреть файл

@ -8,8 +8,6 @@ var summary = 'int32x4 shuffleMix';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = int32x4(1, 2, 3, 4);
var b = int32x4(10, 20, 30, 40);
var c = SIMD.int32x4.shuffleMix(a,b, 0x1B);

Просмотреть файл

@ -8,8 +8,6 @@ var summary = 'int32x4 sub';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = int32x4(1, 2, 3, 4);
var b = int32x4(10, 20, 30, 40);
var c = SIMD.int32x4.sub(b,a);
@ -18,6 +16,17 @@ function test() {
assertEq(c.z, 27);
assertEq(c.w, 36);
var INT32_MAX = Math.pow(2, 31) - 1;
var INT32_MIN = -Math.pow(2, 31);
var d = int32x4(-1, 1, INT32_MAX, INT32_MIN);
var e = int32x4(INT32_MAX, INT32_MIN, INT32_MAX, INT32_MIN);
var f = SIMD.int32x4.sub(e, d);
assertEq(f.x, (INT32_MAX - -1) | 0);
assertEq(f.y, (INT32_MIN - 1) | 0);
assertEq(f.z, 0);
assertEq(f.w, 0);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

Просмотреть файл

@ -8,8 +8,6 @@ var summary = 'int32x4 ursh';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
for (var bits = 0; bits < 32; bits++) {
var a = int32x4(-1, 2, -3, 4);
var c = SIMD.int32x4.shiftRightLogical(a, bits);
@ -19,6 +17,16 @@ function test() {
assertEq(c.w >>> 0, 4 >>> bits);
}
var INT32_MAX = Math.pow(2, 31) - 1;
var INT32_MIN = -Math.pow(2, 31);
var d = int32x4(INT32_MAX, INT32_MIN, INT32_MAX, INT32_MIN);
var f = SIMD.int32x4.shiftRightLogical(d, 0);
assertEq(f.x, (INT32_MAX >>> 0) | 0);
assertEq(f.y, (INT32_MIN >>> 0) | 0);
assertEq(f.z, (INT32_MAX >>> 0) | 0);
assertEq(f.w, (INT32_MIN >>> 0) | 0);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

Просмотреть файл

@ -8,17 +8,17 @@ var summary = 'int32x4 with';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var INT32_MAX = Math.pow(2, 31) - 1;
var a = int32x4(1, 2, 3, 4);
var x = SIMD.int32x4.withX(a, 5);
var y = SIMD.int32x4.withY(a, 5);
var z = SIMD.int32x4.withZ(a, 5);
var w = SIMD.int32x4.withW(a, 5);
var w = SIMD.int32x4.withW(a, INT32_MAX + 1);
assertEq(x.x, 5);
assertEq(y.y, 5);
assertEq(z.z, 5);
assertEq(w.w, 5);
assertEq(w.w, (INT32_MAX + 1) | 0);
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -8,8 +8,6 @@ var summary = 'int32x4 with';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = int32x4(1, 2, 3, 4);
var x = SIMD.int32x4.withFlagX(a, true);
var y = SIMD.int32x4.withFlagY(a, false);

Просмотреть файл

@ -8,8 +8,6 @@ var summary = 'int32x4 xor';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = int32x4(1, 2, 3, 4);
var b = int32x4(10, 20, 30, 40);
var c = SIMD.int32x4.xor(a, b);
@ -18,6 +16,17 @@ function test() {
assertEq(c.z, 29);
assertEq(c.w, 44);
var INT32_MAX = Math.pow(2, 31) - 1;
var INT32_MIN = -Math.pow(2, 31);
var d = int32x4(INT32_MAX, INT32_MIN, INT32_MAX, INT32_MIN);
var e = int32x4(INT32_MIN, INT32_MAX, INT32_MAX, INT32_MIN);
var f = SIMD.int32x4.xor(d, e);
assertEq(f.x, (INT32_MAX ^ INT32_MIN) | 0);
assertEq(f.y, (INT32_MIN ^ INT32_MAX) | 0);
assertEq(f.z, (INT32_MAX ^ INT32_MAX) | 0);
assertEq(f.w, (INT32_MIN ^ INT32_MIN) | 0);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

Просмотреть файл

@ -9,6 +9,7 @@
#include "jsfun.h"
#include "jsobj.h"
#include "proxy/Proxy.h"
#include "vm/ProxyObject.h"
using namespace js;

Просмотреть файл

@ -10,8 +10,8 @@
#include "vm/ObjectImpl.h"
#include "jscntxt.h"
#include "jsproxy.h"
#include "proxy/Proxy.h"
#include "vm/ProxyObject.h"
#include "vm/TypedArrayObject.h"

Просмотреть файл

@ -11,10 +11,10 @@
#include "mozilla/MemoryReporting.h"
#include "jscntxt.h"
#include "jsproxy.h"
#include "gc/Marking.h"
#include "gc/Zone.h"
#include "proxy/Proxy.h"
#include "vm/Shape.h"
/*

Просмотреть файл

@ -744,20 +744,14 @@ Activation::Activation(ThreadSafeContext *cx, Kind kind)
kind_(kind)
{
cx->perThreadData->activation_ = this;
// Link the activation into the list of profiling activations if needed.
if (isProfiling())
registerProfiling();
}
Activation::~Activation()
{
JS_ASSERT_IF(isProfiling(), this != cx_->perThreadData->profilingActivation_);
JS_ASSERT(cx_->perThreadData->activation_ == this);
JS_ASSERT(hideScriptedCallerCount_ == 0);
cx_->perThreadData->activation_ = prev_;
if (isProfiling())
unregisterProfiling();
}
bool

Просмотреть файл

@ -1554,11 +1554,11 @@ AsmJSActivation::AsmJSActivation(JSContext *cx, AsmJSModule &module)
fp_(nullptr),
exitReason_(AsmJSExit::None)
{
(void) entrySP_; // squelch GCC warning
// NB: this is a hack and can be removed once Ion switches over to
// JS::ProfilingFrameIterator.
if (cx->runtime()->spsProfiler.enabled()) {
// Use a profiler string that matches jsMatch regex in
// browser/devtools/profiler/cleopatra/js/parserWorker.js.
// (For now use a single static string to avoid further slowing down
// calls into asm.js.)
profiler_ = &cx->runtime()->spsProfiler;
profiler_->enterAsmJS("asm.js code :0", this);
}
@ -1568,14 +1568,21 @@ AsmJSActivation::AsmJSActivation(JSContext *cx, AsmJSModule &module)
prevAsmJS_ = cx->mainThread().asmJSActivationStack_;
{
JSRuntime::AutoLockForInterrupt lock(cx->runtime());
cx->mainThread().asmJSActivationStack_ = this;
}
(void) entrySP_; // squelch GCC warning
// Now that the AsmJSActivation is fully initialized, make it visible to
// asynchronous profiling.
registerProfiling();
}
AsmJSActivation::~AsmJSActivation()
{
// Hide this activation from the profiler before is is destroyed.
unregisterProfiling();
if (profiler_)
profiler_->exitAsmJS();

Просмотреть файл

@ -19,7 +19,6 @@
#include "mozilla/Attributes.h"
#include "mozilla/Preferences.h"
#include "nsJSEnvironment.h"
#include "mozilla/StartupTimeline.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/XPTInterfaceInfoManager.h"
#include "mozilla/dom/DOMException.h"
@ -3557,7 +3556,8 @@ nsXPCComponents_Utils::SetAddonInterposition(const nsACString &addonIdStr,
NS_IMETHODIMP
nsXPCComponents_Utils::Now(double *aRetval)
{
TimeStamp start = StartupTimeline::Get(StartupTimeline::PROCESS_CREATION);
bool isInconsistent = false;
TimeStamp start = TimeStamp::ProcessCreation(isInconsistent);
*aRetval = (TimeStamp::Now() - start).ToMilliseconds();
return NS_OK;
}

Просмотреть файл

@ -120,10 +120,6 @@ ForceCOWBehavior(JSObject *obj)
"instances modulo this hack");
return true;
}
// Proxies get OpaqueXrayTraits, but we still need COWs to them for now to
// let the SpecialPowers wrapper work.
if (key == JSProto_Proxy)
return true;
return false;
}

Просмотреть файл

@ -1936,6 +1936,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
AutoSaveRestoreBlendMode autoRestoreBlendMode(*aBuilder);
aBuilder->SetContainsBlendModes(BlendModeSet());
nsRect dirtyRectOutsideTransform = dirtyRect;
if (isTransformed) {
const nsRect overflow = GetVisualOverflowRectRelativeToSelf();
if (aBuilder->IsForPainting() &&
@ -1960,6 +1961,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
}
bool usingSVGEffects = nsSVGIntegrationUtils::UsingEffectsForFrame(this);
nsRect dirtyRectOutsideSVGEffects = dirtyRect;
if (usingSVGEffects) {
dirtyRect =
nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(this, dirtyRect);
@ -2082,6 +2084,8 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
* output even if the element being filtered wouldn't otherwise do so.
*/
if (usingSVGEffects) {
// Revert to the post-filter dirty rect.
buildingDisplayList.SetDirtyRect(dirtyRectOutsideSVGEffects);
/* List now emptied, so add the new list to the top. */
resultList.AppendNewToTop(
new (aBuilder) nsDisplaySVGEffects(aBuilder, this, &resultList));
@ -2116,7 +2120,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
clipState.Restore();
// Revert to the dirtyrect coming in from the parent, without our transform
// taken into account.
buildingDisplayList.SetDirtyRect(aDirtyRect);
buildingDisplayList.SetDirtyRect(dirtyRectOutsideTransform);
// Revert to the outer reference frame and offset because all display
// items we create from now on are outside the transform.
const nsIFrame* outerReferenceFrame =

Просмотреть файл

@ -0,0 +1,8 @@
<!DOCTYPE HTML>
<html>
<meta name="viewport" content="width=device-width">
<body style="height: 5000px; overflow:hidden">
<div style="display: block; margin-top: 100px; position:fixed; overflow:scroll; top: 0px; width: 50px; height: 100px"><div style="height:200px; background-color: red"></div></div>
<div style="display: block; margin-top: 20px; position:relative; left: 50px; width: 50px; height: 100px; background-color: red"></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,15 @@
<!DOCTYPE HTML>
<html reftest-async-scroll
reftest-displayport-x="0" reftest-displayport-y="0"
reftest-displayport-w="800" reftest-displayport-h="2000"
reftest-async-scroll-x="0" reftest-async-scroll-y="80">
<meta name="viewport" content="width=device-width">
<body style="height: 5000px; overflow:hidden">
<!-- In this test the fixed-position element is a child of the scrollable layer, but
gets a clip rect because it is itself a container for scrolling sublayers. This
tests that such a layer is transformed correctly while an async scroll transform
is in effect. -->
<div style="display: block; margin-top: 100px; position:fixed; overflow:scroll; top: 0px; width: 50px; height: 100px"><div style="height:200px; background-color: red"></div></div>
<div style="display: block; margin-top: 100px; position:relative; left: 50px; width: 50px; height: 100px; background-color: red"></div>
</body>
</html>

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше