diff --git a/accessible/src/base/ARIAMap.cpp b/accessible/src/base/ARIAMap.cpp index d8cfd812f..af64f4a90 100644 --- a/accessible/src/base/ARIAMap.cpp +++ b/accessible/src/base/ARIAMap.cpp @@ -685,7 +685,7 @@ struct AttrCharacteristics static const AttrCharacteristics gWAIUnivAttrMap[] = { {&nsGkAtoms::aria_activedescendant, ATTR_BYPASSOBJ }, - {&nsGkAtoms::aria_atomic, ATTR_VALTOKEN | ATTR_GLOBAL }, + {&nsGkAtoms::aria_atomic, ATTR_BYPASSOBJ_IF_FALSE | ATTR_VALTOKEN | ATTR_GLOBAL }, {&nsGkAtoms::aria_busy, ATTR_VALTOKEN | ATTR_GLOBAL }, {&nsGkAtoms::aria_checked, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, /* exposes checkable obj attr */ {&nsGkAtoms::aria_controls, ATTR_BYPASSOBJ | ATTR_GLOBAL }, diff --git a/accessible/src/base/nsAccUtils.cpp b/accessible/src/base/nsAccUtils.cpp index d4825ac4b..0cd188cfd 100644 --- a/accessible/src/base/nsAccUtils.cpp +++ b/accessible/src/base/nsAccUtils.cpp @@ -130,7 +130,7 @@ nsAccUtils::SetLiveContainerAttributes(nsIPersistentProperties *aAttributes, nsIContent *aStartContent, nsIContent *aTopContent) { - nsAutoString atomic, live, relevant, busy; + nsAutoString live, relevant, busy; nsIContent *ancestor = aStartContent; while (ancestor) { @@ -159,10 +159,11 @@ nsAccUtils::SetLiveContainerAttributes(nsIPersistentProperties *aAttributes, } // container-atomic attribute - if (atomic.IsEmpty() && - HasDefinedARIAToken(ancestor, nsGkAtoms::aria_atomic) && - ancestor->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_atomic, atomic)) - SetAccAttr(aAttributes, nsGkAtoms::containerAtomic, atomic); + if (ancestor->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_atomic, + nsGkAtoms::_true, eCaseMatters)) { + SetAccAttr(aAttributes, nsGkAtoms::containerAtomic, + NS_LITERAL_STRING("true")); + } // container-busy attribute if (busy.IsEmpty() && diff --git a/accessible/src/xul/XULFormControlAccessible.cpp b/accessible/src/xul/XULFormControlAccessible.cpp index 7964499c8..9a660b172 100644 --- a/accessible/src/xul/XULFormControlAccessible.cpp +++ b/accessible/src/xul/XULFormControlAccessible.cpp @@ -830,6 +830,10 @@ already_AddRefed XULTextFieldAccessible::FrameSelection() { nsCOMPtr inputContent(GetInputField()); + NS_ASSERTION(inputContent, "No input content"); + if (!inputContent) + return nullptr; + nsIFrame* frame = inputContent->GetPrimaryFrame(); return frame ? frame->GetFrameSelection() : nullptr; } diff --git a/accessible/tests/mochitest/attributes/test_obj.html b/accessible/tests/mochitest/attributes/test_obj.html index 45b2c92be..fa4311352 100644 --- a/accessible/tests/mochitest/attributes/test_obj.html +++ b/accessible/tests/mochitest/attributes/test_obj.html @@ -22,7 +22,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=558036 function doTest() { // aria - testAttrs("atomic", {"atomic" : "true"}, true); + testAttrs("atomic", {"atomic" : "true", "container-atomic" : "true"}, true); + testAttrs(getNode("atomic").firstChild, {"container-atomic" : "true"}, true); + testAbsentAttrs("atomic_false", {"atomic" : "false", "container-atomic" : "false"}); + testAbsentAttrs(getNode("atomic_false").firstChild, {"container-atomic" : "false"}); + testAttrs("autocomplete", {"autocomplete" : "true"}, true); testAttrs("checkbox", {"checkable" : "true"}, true); testAttrs("checkedCheckbox", {"checkable" : "true"}, true); @@ -174,7 +178,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=558036 -
+
live region
+
live region
diff --git a/accessible/tests/mochitest/relations/test_general.html b/accessible/tests/mochitest/relations/test_general.html index df7f3a95b..ca048ffc9 100644 --- a/accessible/tests/mochitest/relations/test_general.html +++ b/accessible/tests/mochitest/relations/test_general.html @@ -117,6 +117,9 @@ testRelation("listitem1", RELATION_NODE_PARENT_OF, [ "listitem1.1", "listitem1.2" ]); + // aria-atomic + testRelation(getNode("atomic").firstChild, RELATION_MEMBER_OF, "atomic"); + // aria-controls getAccessible("tab"); todo(false, @@ -317,6 +320,8 @@ +
live region
+ flow to flow from diff --git a/browser/base/content/browser-places.js b/browser/base/content/browser-places.js index d475000e9..e15884b5d 100644 --- a/browser/base/content/browser-places.js +++ b/browser/base/content/browser-places.js @@ -464,7 +464,7 @@ var PlacesCommandHook = { "", "chrome,toolbar=yes,dialog=no,resizable", aLeftPaneRoot); } else { - organizer.PlacesOrganizer.selectLeftPaneQuery(aLeftPaneRoot); + organizer.PlacesOrganizer.selectLeftPaneContainerByHierarchy(aLeftPaneRoot); organizer.focus(); } } diff --git a/browser/components/migration/src/SafariProfileMigrator.js b/browser/components/migration/src/SafariProfileMigrator.js index 2f0753b26..397c15d5a 100644 --- a/browser/components/migration/src/SafariProfileMigrator.js +++ b/browser/components/migration/src/SafariProfileMigrator.js @@ -212,10 +212,17 @@ History.prototype = { for (let entry of entries) { if (entry.has("lastVisitedDate")) { let visitDate = this._parseCocoaDate(entry.get("lastVisitedDate")); - places.push({ uri: NetUtil.newURI(entry.get("")), - title: entry.get("title"), - visits: [{ transitionType: transType, - visitDate: visitDate }] }); + try { + places.push({ uri: NetUtil.newURI(entry.get("")), + title: entry.get("title"), + visits: [{ transitionType: transType, + visitDate: visitDate }] }); + } + catch(ex) { + // Safari's History file may contain malformed URIs which + // will be ignored. + Cu.reportError(ex) + } } } if (places.length > 0) { diff --git a/browser/components/places/content/places.js b/browser/components/places/content/places.js index da30d5bf9..8c9eb8e8a 100644 --- a/browser/components/places/content/places.js +++ b/browser/components/places/content/places.js @@ -37,6 +37,50 @@ var PlacesOrganizer = { PlacesUtils.asContainer(this._places.selectedNode).containerOpen = true; }, + /** + * Opens a given hierarchy in the left pane, stopping at the last reachable + * container. + * + * @param aHierarchy A single container or an array of containers, sorted from + * the outmost to the innermost in the hierarchy. Each + * container may be either an item id, a Places URI string, + * or a named query. + * @see PlacesUIUtils.leftPaneQueries for supported named queries. + */ + selectLeftPaneContainerByHierarchy: + function PO_selectLeftPaneContainerByHierarchy(aHierarchy) { + if (!aHierarchy) + throw new Error("Invalid containers hierarchy"); + let hierarchy = [].concat(aHierarchy); + let selectWasSuppressed = this._places.view.selection.selectEventsSuppressed; + if (!selectWasSuppressed) + this._places.view.selection.selectEventsSuppressed = true; + try { + for (let container of hierarchy) { + switch (typeof container) { + case "number": + this._places.selectItems([container]); + break; + case "string": + if (container.substr(0, 6) == "place:") + this._places.selectPlaceURI(container); + else if (container in PlacesUIUtils.leftPaneQueries) + this.selectLeftPaneQuery(container); + else + throw new Error("Invalid container found: " + container); + break; + default: + throw new Error("Invalid container type found: " + container); + break; + } + PlacesUtils.asContainer(this._places.selectedNode).containerOpen = true; + } + } finally { + if (!selectWasSuppressed) + this._places.view.selection.selectEventsSuppressed = false; + } + }, + init: function PO_init() { ContentArea.init(); @@ -47,12 +91,13 @@ var PlacesOrganizer = { if (window.arguments && window.arguments[0]) leftPaneSelection = window.arguments[0]; - this.selectLeftPaneQuery(leftPaneSelection); - if (leftPaneSelection == "History") { + this.selectLeftPaneContainerByHierarchy(leftPaneSelection); + if (leftPaneSelection === "History") { let historyNode = this._places.selectedNode; if (historyNode.childCount > 0) this._places.selectNode(historyNode.getChild(0)); } + // clear the back-stack this._backHistory.splice(0, this._backHistory.length); document.getElementById("OrganizerCommand:Back").setAttribute("disabled", true); diff --git a/content/canvas/src/CanvasRenderingContext2D.cpp b/content/canvas/src/CanvasRenderingContext2D.cpp index 5368153a3..b2250d14c 100644 --- a/content/canvas/src/CanvasRenderingContext2D.cpp +++ b/content/canvas/src/CanvasRenderingContext2D.cpp @@ -3334,6 +3334,9 @@ CanvasRenderingContext2D::DrawWindow(nsIDOMWindow* window, double x, if (flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_ASYNC_DECODE_IMAGES) { renderDocFlags |= nsIPresShell::RENDER_ASYNC_DECODE_IMAGES; } + if (flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_DO_NOT_FLUSH) { + renderDocFlags |= nsIPresShell::RENDER_DRAWWINDOW_NOT_FLUSHING; + } // gfxContext-over-Azure may modify the DrawTarget's transform, so // save and restore it diff --git a/content/events/src/SpeechRecognitionError.cpp b/content/events/src/SpeechRecognitionError.cpp new file mode 100644 index 000000000..5c42ccf31 --- /dev/null +++ b/content/events/src/SpeechRecognitionError.cpp @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "nsDOMClassInfoID.h" +#include "SpeechRecognitionError.h" + +namespace mozilla { +namespace dom { + +SpeechRecognitionError::SpeechRecognitionError(mozilla::dom::EventTarget* aOwner, nsPresContext* aPresContext, nsEvent* aEvent) +: nsDOMEvent(aOwner, aPresContext, aEvent), + mError() +{} + +SpeechRecognitionError::~SpeechRecognitionError() {} + +already_AddRefed +SpeechRecognitionError::Constructor(const GlobalObject& aGlobal, + const nsAString& aType, + const SpeechRecognitionErrorInit& aParam, + ErrorResult& aRv) +{ + nsCOMPtr t = do_QueryInterface(aGlobal.Get()); + nsRefPtr e = new SpeechRecognitionError(t, nullptr, nullptr); + bool trusted = e->Init(t); + e->InitSpeechRecognitionError(aType, aParam.mBubbles, aParam.mCancelable, aParam.mError, aParam.mMessage, aRv); + e->SetTrusted(trusted); + return e.forget(); +} + +void +SpeechRecognitionError::InitSpeechRecognitionError(const nsAString& aType, + bool aCanBubble, + bool aCancelable, + SpeechRecognitionErrorCode aError, + const nsAString& aMessage, + ErrorResult& aRv) +{ + aRv = nsDOMEvent::InitEvent(aType, aCanBubble, aCancelable); + NS_ENSURE_SUCCESS_VOID(aRv.ErrorCode()); + + mError = aError; + mMessage = aMessage; + return; +} + +} // namespace dom +} // namespace mozilla diff --git a/content/events/src/SpeechRecognitionError.h b/content/events/src/SpeechRecognitionError.h new file mode 100644 index 000000000..9a5a8ed29 --- /dev/null +++ b/content/events/src/SpeechRecognitionError.h @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 SpeechRecognitionError_h__ +#define SpeechRecognitionError_h__ + +#include "nsDOMEvent.h" +#include "mozilla/dom/SpeechRecognitionErrorBinding.h" + +namespace mozilla { +namespace dom { + +class SpeechRecognitionError : public nsDOMEvent +{ +public: + SpeechRecognitionError(mozilla::dom::EventTarget* aOwner, + nsPresContext* aPresContext, + nsEvent* aEvent); + virtual ~SpeechRecognitionError(); + + static already_AddRefed Constructor(const GlobalObject& aGlobal, + const nsAString& aType, + const SpeechRecognitionErrorInit& aParam, + ErrorResult& aRv); + + virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aScope) MOZ_OVERRIDE + { + return mozilla::dom::SpeechRecognitionErrorBinding::Wrap(aCx, aScope, this); + } + + void + GetMessage(nsAString& aString) + { + aString = mMessage; + } + + SpeechRecognitionErrorCode + Error() + { + return mError; + } + + void + InitSpeechRecognitionError(const nsAString& aType, + bool aCanBubble, + bool aCancelable, + SpeechRecognitionErrorCode aError, + const nsAString& aMessage, + ErrorResult& aRv); + +protected: + SpeechRecognitionErrorCode mError; + nsString mMessage; +}; + +} +} + +#endif // SpeechRecognitionError_h__ diff --git a/content/events/src/moz.build b/content/events/src/moz.build index e25bfc666..6b071c321 100644 --- a/content/events/src/moz.build +++ b/content/events/src/moz.build @@ -16,6 +16,7 @@ EXPORTS += [ ] EXPORTS.mozilla.dom += [ + 'SpeechRecognitionError.h', 'Touch.h', ] @@ -59,4 +60,5 @@ CPP_SOURCES += [ 'nsIMEStateManager.cpp', 'nsPaintRequest.cpp', 'nsPrivateTextRange.cpp', + 'SpeechRecognitionError.cpp', ] diff --git a/content/media/webspeech/recognition/SpeechRecognition.cpp b/content/media/webspeech/recognition/SpeechRecognition.cpp index f3f723d84..b4a8468d1 100644 --- a/content/media/webspeech/recognition/SpeechRecognition.cpp +++ b/content/media/webspeech/recognition/SpeechRecognition.cpp @@ -521,11 +521,10 @@ SpeechRecognition::AbortError(SpeechEvent* aEvent) void SpeechRecognition::NotifyError(SpeechEvent* aEvent) { - nsCOMPtr domEvent = do_QueryInterface(aEvent->mError); - domEvent->SetTrusted(true); + aEvent->mError->SetTrusted(true); bool defaultActionEnabled; - this->DispatchEvent(domEvent, &defaultActionEnabled); + this->DispatchEvent(aEvent->mError, &defaultActionEnabled); return; } @@ -576,7 +575,7 @@ SpeechRecognition::Observe(nsISupports* aSubject, const char* aTopic, StateBetween(STATE_IDLE, STATE_WAITING_FOR_SPEECH)) { DispatchError(SpeechRecognition::EVENT_AUDIO_ERROR, - nsIDOMSpeechRecognitionError::NO_SPEECH, + SpeechRecognitionErrorCode::No_speech, NS_LITERAL_STRING("No speech detected (timeout)")); } else if (!strcmp(aTopic, SPEECH_RECOGNITION_TEST_END_TOPIC)) { nsCOMPtr obs = services::GetObserverService(); @@ -602,7 +601,7 @@ SpeechRecognition::ProcessTestEventRequest(nsISupports* aSubject, const nsAStrin Abort(); } else if (aEventName.EqualsLiteral("EVENT_AUDIO_ERROR")) { DispatchError(SpeechRecognition::EVENT_AUDIO_ERROR, - nsIDOMSpeechRecognitionError::AUDIO_CAPTURE, // TODO different codes? + SpeechRecognitionErrorCode::Audio_capture, // TODO different codes? NS_LITERAL_STRING("AUDIO_ERROR test event")); } else if (aEventName.EqualsLiteral("EVENT_AUDIO_DATA")) { StartRecording(static_cast(aSubject)); @@ -748,19 +747,21 @@ SpeechRecognition::Abort() } void -SpeechRecognition::DispatchError(EventType aErrorType, int aErrorCode, +SpeechRecognition::DispatchError(EventType aErrorType, + SpeechRecognitionErrorCode aErrorCode, const nsAString& aMessage) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aErrorType == EVENT_RECOGNITIONSERVICE_ERROR || aErrorType == EVENT_AUDIO_ERROR, "Invalid error type!"); - nsCOMPtr domEvent; - NS_NewDOMSpeechRecognitionError(getter_AddRefs(domEvent), nullptr, nullptr, nullptr); + nsRefPtr srError = + new SpeechRecognitionError(nullptr, nullptr, nullptr); - nsCOMPtr srError = do_QueryInterface(domEvent); + ErrorResult err; srError->InitSpeechRecognitionError(NS_LITERAL_STRING("error"), true, false, - aErrorCode, aMessage); + aErrorCode, aMessage, err); + nsRefPtr event = new SpeechEvent(this, aErrorType); event->mError = srError; NS_DispatchToMainThread(event); @@ -1002,12 +1003,12 @@ NS_IMPL_ISUPPORTS1(SpeechRecognition::GetUserMediaErrorCallback, nsIDOMGetUserMe NS_IMETHODIMP SpeechRecognition::GetUserMediaErrorCallback::OnError(const nsAString& aError) { - int errorCode; + SpeechRecognitionErrorCode errorCode; if (aError.Equals(NS_LITERAL_STRING("PERMISSION_DENIED"))) { - errorCode = nsIDOMSpeechRecognitionError::NOT_ALLOWED; + errorCode = SpeechRecognitionErrorCode::Not_allowed; } else { - errorCode = nsIDOMSpeechRecognitionError::AUDIO_CAPTURE; + errorCode = SpeechRecognitionErrorCode::Audio_capture; } mRecognition->DispatchError(SpeechRecognition::EVENT_AUDIO_ERROR, errorCode, diff --git a/content/media/webspeech/recognition/SpeechRecognition.h b/content/media/webspeech/recognition/SpeechRecognition.h index 5d46c7886..13e6cd4d2 100644 --- a/content/media/webspeech/recognition/SpeechRecognition.h +++ b/content/media/webspeech/recognition/SpeechRecognition.h @@ -28,7 +28,7 @@ #include "nsISpeechRecognitionService.h" #include "endpointer.h" -#include "nsIDOMSpeechRecognitionError.h" +#include "mozilla/dom/SpeechRecognitionError.h" struct JSContext; class nsIDOMWindow; @@ -127,7 +127,7 @@ public: EVENT_COUNT }; - void DispatchError(EventType aErrorType, int aErrorCode, const nsAString& aMessage); + void DispatchError(EventType aErrorType, SpeechRecognitionErrorCode aErrorCode, const nsAString& aMessage); uint32_t FillSamplesBuffer(const int16_t* aSamples, uint32_t aSampleCount); uint32_t SplitSamplesBuffer(const int16_t* aSamplesBuffer, uint32_t aSampleCount, nsTArray >& aResult); AudioSegment* CreateAudioSegment(nsTArray >& aChunks); @@ -284,7 +284,7 @@ public: NS_IMETHOD Run() MOZ_OVERRIDE; AudioSegment* mAudioSegment; nsRefPtr mRecognitionResultList; // TODO: make this a session being passed which also has index and stuff - nsCOMPtr mError; + nsRefPtr mError; friend class SpeechRecognition; private: diff --git a/content/media/webspeech/recognition/moz.build b/content/media/webspeech/recognition/moz.build index fac3ce876..87815e871 100644 --- a/content/media/webspeech/recognition/moz.build +++ b/content/media/webspeech/recognition/moz.build @@ -8,7 +8,6 @@ MODULE = 'content' XPIDL_MODULE = 'dom_webspeechrecognition' XPIDL_SOURCES = [ - 'nsIDOMSpeechRecognitionError.idl', 'nsIDOMSpeechRecognitionEvent.idl', 'nsISpeechRecognitionService.idl' ] diff --git a/content/media/webspeech/recognition/nsIDOMSpeechRecognitionError.idl b/content/media/webspeech/recognition/nsIDOMSpeechRecognitionError.idl deleted file mode 100644 index 0ee760896..000000000 --- a/content/media/webspeech/recognition/nsIDOMSpeechRecognitionError.idl +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. - * - * The origin of this IDL file is - * http://dvcs.w3.org/hg/speech-api/raw-file/tip/speechapi.html - * - * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C - * liability, trademark and document use rules apply. - */ - -#include "nsIDOMEvent.idl" - -[scriptable, builtinclass, uuid(5ddc5a46-e7db-4c5c-8ed4-80cf5d88fca3)] -interface nsIDOMSpeechRecognitionError : nsIDOMEvent { - const unsigned long NO_SPEECH = 0; - const unsigned long ABORTED = 1; - const unsigned long AUDIO_CAPTURE = 2; - const unsigned long NETWORK = 3; - const unsigned long NOT_ALLOWED = 4; - const unsigned long SERVICE_NOT_ALLOWED = 5; - const unsigned long BAD_GRAMMAR = 6; - const unsigned long LANGUAGE_NOT_SUPPORTED = 7; - - [noscript] void initSpeechRecognitionError(in DOMString eventTypeArg, - in boolean canBubbleArg, - in boolean cancelableArg, - in unsigned long error, - in DOMString message); - - readonly attribute unsigned long error; - readonly attribute DOMString message; -}; - -dictionary SpeechRecognitionErrorInit : EventInit { - unsigned long error; - DOMString message; -}; diff --git a/content/media/webspeech/recognition/test/FakeSpeechRecognitionService.cpp b/content/media/webspeech/recognition/test/FakeSpeechRecognitionService.cpp index 901992efb..f51423509 100644 --- a/content/media/webspeech/recognition/test/FakeSpeechRecognitionService.cpp +++ b/content/media/webspeech/recognition/test/FakeSpeechRecognitionService.cpp @@ -74,7 +74,7 @@ FakeSpeechRecognitionService::Observe(nsISupports* aSubject, const char* aTopic, if (eventName.EqualsLiteral("EVENT_RECOGNITIONSERVICE_ERROR")) { mRecognition->DispatchError(SpeechRecognition::EVENT_RECOGNITIONSERVICE_ERROR, - nsIDOMSpeechRecognitionError::NETWORK, // TODO different codes? + SpeechRecognitionErrorCode::Network, // TODO different codes? NS_LITERAL_STRING("RECOGNITIONSERVICE_ERROR test event")); } else if (eventName.EqualsLiteral("EVENT_RECOGNITIONSERVICE_FINAL_RESULT")) { diff --git a/content/media/webspeech/recognition/test/head.js b/content/media/webspeech/recognition/test/head.js index cdcaf07d1..615a73678 100644 --- a/content/media/webspeech/recognition/test/head.js +++ b/content/media/webspeech/recognition/test/head.js @@ -5,14 +5,14 @@ const SPEECH_RECOGNITION_TEST_REQUEST_EVENT_TOPIC = "SpeechRecognitionTest:Reque const SPEECH_RECOGNITION_TEST_END_TOPIC = "SpeechRecognitionTest:End"; var errorCodes = { - NO_SPEECH : 0, - ABORTED : 1, - AUDIO_CAPTURE : 2, - NETWORK : 3, - NOT_ALLOWED : 4, - SERVICE_NOT_ALLOWED : 5, - BAD_GRAMMAR : 6, - LANGUAGE_NOT_SUPPORTED : 7 + NO_SPEECH : "no-speech", + ABORTED : "aborted", + AUDIO_CAPTURE : "audio-capture", + NETWORK : "network", + NOT_ALLOWED : "not-allowed", + SERVICE_NOT_ALLOWED : "service-not-allowed", + BAD_GRAMMAR : "bad-grammar", + LANGUAGE_NOT_SUPPORTED : "language-not-supported" }; netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); diff --git a/content/svg/content/test/Makefile.in b/content/svg/content/test/Makefile.in index 205a094d6..786c3057c 100644 --- a/content/svg/content/test/Makefile.in +++ b/content/svg/content/test/Makefile.in @@ -80,6 +80,7 @@ MOCHITEST_FILES = \ switch-helper.svg \ test_text.html \ test_text_2.html \ + test_text_dirty.html \ test_text_scaled.html \ test_text_selection.html \ test_text_update.html \ diff --git a/content/svg/content/test/test_text_dirty.html b/content/svg/content/test/test_text_dirty.html new file mode 100644 index 000000000..cfa4ab9d7 --- /dev/null +++ b/content/svg/content/test/test_text_dirty.html @@ -0,0 +1,55 @@ + + + + + Test for Bug 886230 + + + + + + +Mozilla Bug 886230 +

+ + x + + +

+ +
+
+
+ + diff --git a/dom/apps/src/Webapps.jsm b/dom/apps/src/Webapps.jsm index c2ccdfbc8..0d8c92c69 100644 --- a/dom/apps/src/Webapps.jsm +++ b/dom/apps/src/Webapps.jsm @@ -258,6 +258,8 @@ this.DOMApplicationRegistry = { // Install the permissions for this app, as if we were updating // to cleanup the old ones if needed. + // TODO It's not clear what this should do when there are multiple profiles. +#ifdef MOZ_B2G this._readManifests([{ id: aId }], (function(aResult) { let data = aResult[0]; PermissionsInstaller.installPermissions({ @@ -268,6 +270,7 @@ this.DOMApplicationRegistry = { debug("Error installing permissions for " + aId); }); }).bind(this)); +#endif }, updateOfflineCacheForApp: function updateOfflineCacheForApp(aId) { @@ -1237,11 +1240,13 @@ this.DOMApplicationRegistry = { this._saveApps((function() { // Update the handlers and permissions for this app. this.updateAppHandlers(aOldManifest, aData, app); +#ifdef MOZ_B2G PermissionsInstaller.installPermissions( { manifest: aData, origin: app.origin, manifestURL: app.manifestURL }, true); +#endif this.broadcastMessage("Webapps:PackageEvent", { type: "applied", manifestURL: app.manifestURL, @@ -1462,13 +1467,14 @@ this.DOMApplicationRegistry = { this._writeFile(manFile, JSON.stringify(aNewManifest), function() { }); manifest = new ManifestHelper(aNewManifest, app.origin); +#ifdef MOZ_B2G // Update the permissions for this app. PermissionsInstaller.installPermissions({ manifest: app.manifest, origin: app.origin, manifestURL: aData.manifestURL }, true); - +#endif app.name = manifest.name; app.csp = manifest.csp || ""; app.updateTime = Date.now(); @@ -2012,12 +2018,14 @@ this.DOMApplicationRegistry = { // For package apps, the permissions are not in the mini-manifest, so // don't update the permissions yet. if (!aData.isPackage) { +#ifdef MOZ_B2G PermissionsInstaller.installPermissions({ origin: appObject.origin, manifestURL: appObject.manifestURL, manifest: jsonManifest }, isReinstall, (function() { this.uninstall(aData, aData.mm); }).bind(this)); +#endif } ["installState", "downloadAvailable", @@ -2075,12 +2083,13 @@ this.DOMApplicationRegistry = { app.downloadAvailable = false; this._saveApps((function() { this.updateAppHandlers(null, aManifest, appObject); - +#ifdef MOZ_B2G // Update the permissions for this app. PermissionsInstaller.installPermissions({ manifest: aManifest, origin: appObject.origin, manifestURL: appObject.manifestURL }, true); +#endif debug("About to fire Webapps:PackageEvent 'installed'"); this.broadcastMessage("Webapps:PackageEvent", { type: "installed", diff --git a/dom/push/src/PushService.jsm b/dom/push/src/PushService.jsm index 0149a311a..fc9a4c3e0 100644 --- a/dom/push/src/PushService.jsm +++ b/dom/push/src/PushService.jsm @@ -364,7 +364,7 @@ this.PushService = { // just for it if (this._ws) { debug("Had a connection, so telling the server"); - this._request("unregister", {channelID: records[i].channelID}); + this._sendRequest("unregister", {channelID: records[i].channelID}); } } }.bind(this), function() { diff --git a/dom/tests/browser/Makefile.in b/dom/tests/browser/Makefile.in index f65f9de96..b20e699d3 100644 --- a/dom/tests/browser/Makefile.in +++ b/dom/tests/browser/Makefile.in @@ -28,7 +28,7 @@ MOCHITEST_BROWSER_FILES := \ page_privatestorageevent.html $(NULL) -ifeq (,$(filter-out Linux WINNT,$(OS_ARCH))) +ifdef MOZ_B2G MOCHITEST_BROWSER_FILES += \ browser_webapps_permissions.js \ test-webapp.webapp \ diff --git a/dom/webidl/SpeechRecognitionError.webidl b/dom/webidl/SpeechRecognitionError.webidl index 91725a591..f5dc5fcb3 100644 --- a/dom/webidl/SpeechRecognitionError.webidl +++ b/dom/webidl/SpeechRecognitionError.webidl @@ -4,24 +4,26 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ -[Constructor(DOMString type, optional SpeechRecognitionErrorInit eventInitDict), HeaderFile="GeneratedEventClasses.h"] +enum SpeechRecognitionErrorCode { + "no-speech", + "aborted", + "audio-capture", + "network", + "not-allowed", + "service-not-allowed", + "bad-grammar", + "language-not-supported" +}; + +[Constructor(DOMString type, optional SpeechRecognitionErrorInit eventInitDict)] interface SpeechRecognitionError : Event { - const unsigned long NO_SPEECH = 0; - const unsigned long ABORTED = 1; - const unsigned long AUDIO_CAPTURE = 2; - const unsigned long NETWORK = 3; - const unsigned long NOT_ALLOWED = 4; - const unsigned long SERVICE_NOT_ALLOWED = 5; - const unsigned long BAD_GRAMMAR = 6; - const unsigned long LANGUAGE_NOT_SUPPORTED = 7; - - readonly attribute unsigned long error; + readonly attribute SpeechRecognitionErrorCode error; readonly attribute DOMString? message; }; dictionary SpeechRecognitionErrorInit : EventInit { - unsigned long error = 0; + SpeechRecognitionErrorCode error = "no-speech"; DOMString message = ""; }; diff --git a/embedding/browser/webBrowser/nsWebBrowser.cpp b/embedding/browser/webBrowser/nsWebBrowser.cpp index acacc1869..81624d147 100644 --- a/embedding/browser/webBrowser/nsWebBrowser.cpp +++ b/embedding/browser/webBrowser/nsWebBrowser.cpp @@ -701,49 +701,63 @@ NS_IMETHODIMP nsWebBrowser::SetProperty(uint32_t aId, uint32_t aValue) case nsIWebBrowserSetup::SETUP_ALLOW_PLUGINS: { NS_ENSURE_STATE(mDocShell); - NS_ENSURE_TRUE((aValue == true || aValue == false), NS_ERROR_INVALID_ARG); + NS_ENSURE_TRUE((aValue == static_cast(true) || + aValue == static_cast(false)), + NS_ERROR_INVALID_ARG); mDocShell->SetAllowPlugins(!!aValue); } break; case nsIWebBrowserSetup::SETUP_ALLOW_JAVASCRIPT: { NS_ENSURE_STATE(mDocShell); - NS_ENSURE_TRUE((aValue == true || aValue == false), NS_ERROR_INVALID_ARG); + NS_ENSURE_TRUE((aValue == static_cast(true) || + aValue == static_cast(false)), + NS_ERROR_INVALID_ARG); mDocShell->SetAllowJavascript(!!aValue); } break; case nsIWebBrowserSetup::SETUP_ALLOW_META_REDIRECTS: { NS_ENSURE_STATE(mDocShell); - NS_ENSURE_TRUE((aValue == true || aValue == false), NS_ERROR_INVALID_ARG); + NS_ENSURE_TRUE((aValue == static_cast(true) || + aValue == static_cast(false)), + NS_ERROR_INVALID_ARG); mDocShell->SetAllowMetaRedirects(!!aValue); } break; case nsIWebBrowserSetup::SETUP_ALLOW_SUBFRAMES: { NS_ENSURE_STATE(mDocShell); - NS_ENSURE_TRUE((aValue == true || aValue == false), NS_ERROR_INVALID_ARG); + NS_ENSURE_TRUE((aValue == static_cast(true) || + aValue == static_cast(false)), + NS_ERROR_INVALID_ARG); mDocShell->SetAllowSubframes(!!aValue); } break; case nsIWebBrowserSetup::SETUP_ALLOW_IMAGES: { NS_ENSURE_STATE(mDocShell); - NS_ENSURE_TRUE((aValue == true || aValue == false), NS_ERROR_INVALID_ARG); + NS_ENSURE_TRUE((aValue == static_cast(true) || + aValue == static_cast(false)), + NS_ERROR_INVALID_ARG); mDocShell->SetAllowImages(!!aValue); } break; case nsIWebBrowserSetup::SETUP_ALLOW_DNS_PREFETCH: { NS_ENSURE_STATE(mDocShell); - NS_ENSURE_TRUE((aValue == true || aValue == false), NS_ERROR_INVALID_ARG); + NS_ENSURE_TRUE((aValue == static_cast(true) || + aValue == static_cast(false)), + NS_ERROR_INVALID_ARG); mDocShell->SetAllowDNSPrefetch(!!aValue); } break; case nsIWebBrowserSetup::SETUP_USE_GLOBAL_HISTORY: { NS_ENSURE_STATE(mDocShell); - NS_ENSURE_TRUE((aValue == true || aValue == false), NS_ERROR_INVALID_ARG); + NS_ENSURE_TRUE((aValue == static_cast(true) || + aValue == static_cast(false)), + NS_ERROR_INVALID_ARG); rv = EnableGlobalHistory(!!aValue); mShouldEnableHistory = aValue; } @@ -755,7 +769,9 @@ NS_IMETHODIMP nsWebBrowser::SetProperty(uint32_t aId, uint32_t aValue) break; case nsIWebBrowserSetup::SETUP_IS_CHROME_WRAPPER: { - NS_ENSURE_TRUE((aValue == true || aValue == false), NS_ERROR_INVALID_ARG); + NS_ENSURE_TRUE((aValue == static_cast(true) || + aValue == static_cast(false)), + NS_ERROR_INVALID_ARG); SetItemType(aValue ? static_cast(typeChromeWrapper) : static_cast(typeContentWrapper)); } diff --git a/gfx/ycbcr/Makefile.in b/gfx/ycbcr/Makefile.in index 4c5eeda02..bd1487c62 100644 --- a/gfx/ycbcr/Makefile.in +++ b/gfx/ycbcr/Makefile.in @@ -10,13 +10,6 @@ EXPORT_LIBRARY = 1 DEFINES += -D_IMPL_NS_GFX -ifeq (arm,$(findstring arm,$(OS_TEST))) -ifdef HAVE_ARM_NEON -ASFILES = yuv_row_arm.$(ASM_SUFFIX) \ - $(NULL) -endif -endif - include $(topsrcdir)/config/rules.mk # These files use MMX and SSE2 intrinsics, so they need special compile flags diff --git a/gfx/ycbcr/moz.build b/gfx/ycbcr/moz.build index a9e91685a..a71ce6c06 100644 --- a/gfx/ycbcr/moz.build +++ b/gfx/ycbcr/moz.build @@ -61,7 +61,10 @@ else: 'yuv_row_other.cpp', ] -if CONFIG['OS_TEST'].startswith('arm') and CONFIG['HAVE_ARM_NEON']: +if CONFIG['CPU_ARCH'] == 'arm' and CONFIG['HAVE_ARM_NEON']: + ASFILES += [ + 'yuv_row_arm.s', + ] CPP_SOURCES += [ 'yuv_convert_arm.cpp', ] diff --git a/js/public/RootingAPI.h b/js/public/RootingAPI.h index dc100ecf7..169c7cc36 100644 --- a/js/public/RootingAPI.h +++ b/js/public/RootingAPI.h @@ -535,7 +535,7 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase #ifdef JS_THREADSAFE MOZ_ASSERT(js::IsInRequest(cxArg)); #endif -#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING) +#ifdef JSGC_TRACK_EXACT_ROOTS js::ContextFriendFields *cx = js::ContextFriendFields::get(cxArg); commonInit(cx->thingGCRooters); #endif @@ -543,7 +543,7 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase void init(js::PerThreadDataFriendFields *pt) { MOZ_ASSERT(pt); -#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING) +#ifdef JSGC_TRACK_EXACT_ROOTS commonInit(pt->thingGCRooters); #endif } @@ -598,13 +598,13 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase } ~Rooted() { -#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING) +#ifdef JSGC_TRACK_EXACT_ROOTS JS_ASSERT(*stack == reinterpret_cast*>(this)); *stack = prev; #endif } -#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING) +#ifdef JSGC_TRACK_EXACT_ROOTS Rooted *previous() { return prev; } #endif @@ -640,7 +640,10 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase private: void commonInit(Rooted **thingGCRooters) { -#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING) +#if defined(DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE) + scanned = false; +#endif +#ifdef JSGC_TRACK_EXACT_ROOTS js::ThingRootKind kind = js::GCMethods::kind(); this->stack = &thingGCRooters[kind]; this->prev = *stack; @@ -650,11 +653,11 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase #endif } -#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING) +#ifdef JSGC_TRACK_EXACT_ROOTS Rooted **stack, *prev; #endif -#if defined(DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE) +#ifdef JSGC_ROOT_ANALYSIS /* Has the rooting analysis ever scanned this Rooted's stack location? */ friend void JS::CheckStackRoots(JSContext*); bool scanned; diff --git a/js/src/builtin/Eval.cpp b/js/src/builtin/Eval.cpp index 69514254c..e443897a0 100644 --- a/js/src/builtin/Eval.cpp +++ b/js/src/builtin/Eval.cpp @@ -480,7 +480,7 @@ js::PrincipalsForCompiledCode(const CallReceiver &call, JSContext *cx) { JSObject &callee = call.callee(); JS_ASSERT(IsAnyBuiltinEval(&callee.as()) || - IsBuiltinFunctionConstructor(&callee.as())); + callee.as().isBuiltinFunctionConstructor()); // To compute the principals of the compiled eval/Function code, we simply // use the callee's principals. To see why the caller's principals are diff --git a/js/src/builtin/Profilers.cpp b/js/src/builtin/Profilers.cpp index 5c0616573..2c2cfc9e3 100644 --- a/js/src/builtin/Profilers.cpp +++ b/js/src/builtin/Profilers.cpp @@ -21,6 +21,10 @@ #include "jscntxtinlines.h" +#ifdef JSGC_GENERATIONAL +#include "vm/Shape-inl.h" +#endif + using namespace js; using mozilla::ArrayLength; diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 0a784cae9..d544101ac 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -16,6 +16,7 @@ #include "jit/AsmJS.h" #include "vm/ForkJoin.h" +#include "vm/Interpreter.h" #include "vm/ObjectImpl-inl.h" diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index bf8d24015..c6d799bf0 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -1862,21 +1862,11 @@ EmitElemOpBase(JSContext *cx, BytecodeEmitter *bce, JSOp op) } static bool -EmitPropLHS(JSContext *cx, ParseNode *pn, JSOp *op, BytecodeEmitter *bce, bool callContext) +EmitPropLHS(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce) { + JS_ASSERT(pn->isKind(PNK_DOT)); ParseNode *pn2 = pn->maybeExpr(); - if (callContext) { - JS_ASSERT(pn->isKind(PNK_DOT)); - JS_ASSERT(*op == JSOP_GETPROP); - *op = JSOP_CALLPROP; - } else if (*op == JSOP_GETPROP && pn->isKind(PNK_DOT)) { - if (pn2->isKind(PNK_NAME)) { - if (!BindNameToSlot(cx, bce, pn2)) - return false; - } - } - /* * If the object operand is also a dotted property reference, reverse the * list linked via pn_expr temporarily so we can iterate over it from the @@ -1904,7 +1894,7 @@ EmitPropLHS(JSContext *cx, ParseNode *pn, JSOp *op, BytecodeEmitter *bce, bool c do { /* Walk back up the list, emitting annotated name ops. */ - if (!EmitAtomOp(cx, pndot, pndot->getOp(), bce)) + if (!EmitAtomOp(cx, pndot, JSOP_GETPROP, bce)) return false; /* Reverse the pn_expr link again. */ @@ -1912,20 +1902,19 @@ EmitPropLHS(JSContext *cx, ParseNode *pn, JSOp *op, BytecodeEmitter *bce, bool c pndot->pn_expr = pndown; pndown = pndot; } while ((pndot = pnup) != NULL); - } else { - if (!EmitTree(cx, bce, pn2)) - return false; + return true; } - return true; + + // The non-optimized case. + return EmitTree(cx, bce, pn2); } static bool -EmitPropOp(JSContext *cx, ParseNode *pn, JSOp requested, BytecodeEmitter *bce, bool callContext) +EmitPropOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce) { JS_ASSERT(pn->isArity(PN_NAME)); - JSOp op = requested; - if (!EmitPropLHS(cx, pn, &op, bce, callContext)) + if (!EmitPropLHS(cx, pn, op, bce)) return false; if (op == JSOP_CALLPROP && Emit1(cx, bce, JSOP_DUP) < 0) @@ -1952,9 +1941,8 @@ EmitPropIncDec(JSContext *cx, ParseNode *pn, BytecodeEmitter *bce) JSOp binop = GetIncDecInfo(pn->getKind(), &post); JSOp get = JSOP_GETPROP; - if (!EmitPropLHS(cx, pn->pn_kid, &get, bce, false)) // OBJ + if (!EmitPropLHS(cx, pn->pn_kid, get, bce)) // OBJ return false; - JS_ASSERT(get == JSOP_GETPROP); if (Emit1(cx, bce, JSOP_DUP) < 0) // OBJ OBJ return false; if (!EmitAtomOp(cx, pn->pn_kid, JSOP_GETPROP, bce)) // OBJ V @@ -3413,7 +3401,7 @@ EmitAssignment(JSContext *cx, BytecodeEmitter *bce, ParseNode *lhs, JSOp op, Par return false; } - /* If += etc., emit the binary operator with a decompiler note. */ + /* If += etc., emit the binary operator with a source note. */ if (op != JSOP_NOP) { /* * Take care to avoid SRC_ASSIGNOP if the left-hand side is a const @@ -3447,7 +3435,7 @@ EmitAssignment(JSContext *cx, BytecodeEmitter *bce, ParseNode *lhs, JSOp op, Par } break; case PNK_DOT: - if (!EmitIndexOp(cx, lhs->getOp(), atomIndex, bce)) + if (!EmitIndexOp(cx, JSOP_SETPROP, atomIndex, bce)) return false; break; case PNK_CALL: @@ -4934,7 +4922,7 @@ EmitDelete(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) break; } case PNK_DOT: - if (!EmitPropOp(cx, pn2, JSOP_DELPROP, bce, false)) + if (!EmitPropOp(cx, pn2, JSOP_DELPROP, bce)) return false; break; case PNK_ELEM: @@ -5042,11 +5030,10 @@ EmitCallOrNew(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) return false; break; case PNK_DOT: - if (!EmitPropOp(cx, pn2, pn2->getOp(), bce, callop)) + if (!EmitPropOp(cx, pn2, callop ? JSOP_CALLPROP : JSOP_GETPROP, bce)) return false; break; case PNK_ELEM: - JS_ASSERT(pn2->isOp(JSOP_GETELEM)); if (!EmitElemOp(cx, pn2, callop ? JSOP_CALLELEM : JSOP_GETELEM, bce)) return false; break; @@ -5932,22 +5919,11 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) break; case PNK_DOT: - /* - * Pop a stack operand, convert it to object, get a property named by - * this bytecode's immediate-indexed atom operand, and push its value - * (not a reference to it). - */ - ok = EmitPropOp(cx, pn, pn->getOp(), bce, false); + ok = EmitPropOp(cx, pn, JSOP_GETPROP, bce); break; case PNK_ELEM: - /* - * Pop two operands, convert the left one to object and the right one - * to property name (atom or tagged int), get the named property, and - * push its value. Set the "obj" register to the result of ToObject - * on the left operand. - */ - ok = EmitElemOp(cx, pn, pn->getOp(), bce); + ok = EmitElemOp(cx, pn, JSOP_GETELEM, bce); break; case PNK_NEW: diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp index 650a739cf..252732809 100644 --- a/js/src/frontend/FoldConstants.cpp +++ b/js/src/frontend/FoldConstants.cpp @@ -698,6 +698,52 @@ FoldConstants(JSContext *cx, ParseNode **pnp, } break; + case PNK_ELEM: { + // An indexed expression, pn1[pn2]. A few cases can be improved. + PropertyName *name = NULL; + if (pn2->isKind(PNK_STRING)) { + JSAtom *atom = pn2->pn_atom; + uint32_t index; + + if (atom->isIndex(&index)) { + // Optimization 1: We have something like pn1["100"]. This is + // equivalent to pn1[100] which is faster. + pn2->setKind(PNK_NUMBER); + pn2->setOp(JSOP_DOUBLE); + pn2->pn_dval = index; + } else { + name = atom->asPropertyName(); + } + } else if (pn2->isKind(PNK_NUMBER)) { + double number = pn2->pn_dval; + if (number != ToUint32(number)) { + // Optimization 2: We have something like pn1[3.14]. The number + // is not an array index. This is equivalent to pn1["3.14"] + // which enables optimization 3 below. + JSAtom *atom = ToAtom(cx, DoubleValue(number)); + if (!atom) + return false; + name = atom->asPropertyName(); + } + } + + if (name) { + // Optimization 3: We have pn1["foo"] where foo is not an index. + // Convert to a property access (like pn1.foo) which we optimize + // better downstream. + ParseNode *expr = parser->handler.newPropertyAccess(pn->pn_left, name, pn->pn_pos.end); + if (!expr) + return false; + ReplaceNode(pnp, expr); + + pn->pn_left = NULL; + pn->pn_right = NULL; + parser->handler.freeTree(pn); + pn = expr; + } + break; + } + default:; } diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index 43295c55a..59c8addd7 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -317,57 +317,7 @@ class FullParseHandler return new_(pn, name, pn->pn_pos.begin, end); } - private: - /* - * Examine the RHS of a MemberExpression obj[pn], to optimize expressions - * like obj["name"] or obj["0"]. - * - * If pn is a number or string constant that's not an index, store the - * corresponding PropertyName in *namep. Otherwise store NULL in *namep. - * - * Also, if pn is a string constant whose value is the ToString of an - * index, morph it to a number. - * - * Return false on OOM. - */ - bool foldConstantIndex(ParseNode *pn, PropertyName **namep) { - if (pn->isKind(PNK_STRING)) { - JSAtom *atom = pn->pn_atom; - uint32_t index; - - if (atom->isIndex(&index)) { - pn->setKind(PNK_NUMBER); - pn->setOp(JSOP_DOUBLE); - pn->pn_dval = index; - } else { - *namep = atom->asPropertyName(); - return true; - } - } else if (pn->isKind(PNK_NUMBER)) { - double number = pn->pn_dval; - if (number != ToUint32(number)) { - JSContext *cx = tokenStream.getContext(); - JSAtom *atom = ToAtom(cx, DoubleValue(number)); - if (!atom) - return false; - *namep = atom->asPropertyName(); - return true; - } - } - - *namep = NULL; - return true; - } - - public: ParseNode *newPropertyByValue(ParseNode *lhs, ParseNode *index, uint32_t end) { - if (foldConstants) { - PropertyName *name; - if (!foldConstantIndex(index, &name)) - return null(); - if (name) - return newPropertyAccess(lhs, name, end); - } return new_(lhs, index, lhs->pn_pos.begin, end); } diff --git a/js/src/frontend/NameFunctions.h b/js/src/frontend/NameFunctions.h index 1100c5172..bfefd4cf2 100644 --- a/js/src/frontend/NameFunctions.h +++ b/js/src/frontend/NameFunctions.h @@ -12,7 +12,7 @@ struct JSContext; namespace js { namespace frontend { -struct ParseNode; +class ParseNode; bool NameFunctions(JSContext *cx, ParseNode *pn); diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index 8ff5cb34f..daee03446 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -416,9 +416,8 @@ class ConditionalExpression; class PropertyAccess; class ModuleBox; -struct ParseNode +class ParseNode { - private: uint32_t pn_type : 16, /* PNK_* type */ pn_op : 8, /* see JSOp enum and jsopcode.tbl */ pn_arity : 5, /* see ParseNodeArity enum */ @@ -1166,7 +1165,7 @@ class PropertyAccess : public ParseNode { public: PropertyAccess(ParseNode *lhs, PropertyName *name, uint32_t begin, uint32_t end) - : ParseNode(PNK_DOT, JSOP_GETPROP, PN_NAME, TokenPos(begin, end)) + : ParseNode(PNK_DOT, JSOP_NOP, PN_NAME, TokenPos(begin, end)) { JS_ASSERT(lhs != NULL); JS_ASSERT(name != NULL); @@ -1193,7 +1192,7 @@ class PropertyByValue : public ParseNode { public: PropertyByValue(ParseNode *lhs, ParseNode *propExpr, uint32_t begin, uint32_t end) - : ParseNode(PNK_ELEM, JSOP_GETELEM, PN_BINARY, TokenPos(begin, end)) + : ParseNode(PNK_ELEM, JSOP_NOP, PN_BINARY, TokenPos(begin, end)) { pn_u.binary.left = lhs; pn_u.binary.right = propExpr; diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index bec96b70e..f6236f0a2 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4435,6 +4435,11 @@ Parser::returnStatementOrYieldExpression() (isYield && (next == TOK_YIELD || next == TOK_RB || next == TOK_RP || next == TOK_COLON || next == TOK_COMMA))) { + if (isYield) { + if (!reportWithOffset(ParseWarning, false, pos().begin, JSMSG_YIELD_WITHOUT_OPERAND)) + return null(); + } + exprNode = null(); if (!isYield) pc->funHasReturnVoid = true; @@ -5337,9 +5342,7 @@ Parser::unaryExpr() return null(); // Per spec, deleting any unary expression is valid -- it simply returns - // true -- except for a few cases that are illegal in strict mode. - if (foldConstants && !FoldConstants(context, &expr, this)) - return null(); + // true -- except for one case that is illegal in strict mode. if (handler.isName(expr)) { if (!report(ParseStrictError, pc->sc->strict, expr, JSMSG_DEPRECATED_DELETE_OPERAND)) return null(); @@ -6236,13 +6239,6 @@ Parser::memberExpr(TokenKind tt, bool allowCallSyntax) MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX); - /* - * Do folding so we don't have roundtrip changes for cases like: - * function (obj) { return obj["a" + "b"] } - */ - if (foldConstants && !FoldConstants(context, &propExpr, this)) - return null(); - nextMember = handler.newPropertyByValue(lhs, propExpr, pos().end); if (!nextMember) return null(); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index f0a7fb8b7..92458814e 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -36,7 +36,6 @@ typedef HashSet FuncStmtSet; class SharedContext; typedef Vector DeclVector; -typedef Vector FunctionVector; struct GenericParseContext { @@ -201,7 +200,7 @@ struct ParseContext : public GenericParseContext the same name. */ // All inner functions in this context. Only filled in when parsing syntax. - FunctionVector innerFunctions; + AutoFunctionVector innerFunctions; // Set when parsing a declaration-like destructuring pattern. This flag // causes PrimaryExpr to create PN_NAME parse nodes for variable references @@ -258,8 +257,9 @@ enum VarContext { HoistVars, DontHoistVars }; enum FunctionType { Getter, Setter, Normal }; template -struct Parser : private AutoGCRooter, public StrictModeGetter +class Parser : private AutoGCRooter, public StrictModeGetter { + public: JSContext *const context; /* FIXME Bug 551291: use AutoGCRooter::context? */ TokenStream tokenStream; LifoAlloc::Mark tempPoolMark; diff --git a/js/src/gc/Barrier-inl.h b/js/src/gc/Barrier-inl.h index 7be0c1dfa..93116e645 100644 --- a/js/src/gc/Barrier-inl.h +++ b/js/src/gc/Barrier-inl.h @@ -56,20 +56,6 @@ EncapsulatedValue::~EncapsulatedValue() pre(); } -inline void -EncapsulatedValue::init(const Value &v) -{ - JS_ASSERT(!IsPoisonedValue(v)); - value = v; -} - -inline void -EncapsulatedValue::init(JSRuntime *rt, const Value &v) -{ - JS_ASSERT(!IsPoisonedValue(v)); - value = v; -} - inline EncapsulatedValue & EncapsulatedValue::operator=(const Value &v) { diff --git a/js/src/gc/Barrier.h b/js/src/gc/Barrier.h index 05d0d925c..bbf49aad0 100644 --- a/js/src/gc/Barrier.h +++ b/js/src/gc/Barrier.h @@ -384,8 +384,14 @@ class EncapsulatedValue : public ValueOperations } inline ~EncapsulatedValue(); - inline void init(const Value &v); - inline void init(JSRuntime *rt, const Value &v); + void init(const Value &v) { + JS_ASSERT(!IsPoisonedValue(v)); + value = v; + } + void init(JSRuntime *rt, const Value &v) { + JS_ASSERT(!IsPoisonedValue(v)); + value = v; + } inline EncapsulatedValue &operator=(const Value &v); inline EncapsulatedValue &operator=(const EncapsulatedValue &v); diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 47a7fca0c..d1f589536 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -8,10 +8,13 @@ #include "mozilla/DebugOnly.h" +#include "jstypedarray.h" + #include "jit/IonCode.h" #include "vm/Shape.h" #include "jscompartmentinlines.h" +#include "jsinferinlines.h" #include "gc/Nursery-inl.h" #include "vm/Shape-inl.h" @@ -599,6 +602,12 @@ gc::IsValueAboutToBeFinalized(Value *v) /*** Slot Marking ***/ +bool +gc::IsSlotMarked(HeapSlot *s) +{ + return IsMarked(s); +} + void gc::MarkSlot(JSTracer *trc, HeapSlot *s, const char *name) { @@ -1245,7 +1254,7 @@ GCMarker::restoreValueArray(JSObject *obj, void **vpp, void **endp) HeapSlot::Kind kind = (HeapSlot::Kind) stack.pop(); if (kind == HeapSlot::Element) { - if (obj->getClass() != &ArrayClass) + if (!obj->is()) return false; uint32_t initlen = obj->getDenseInitializedLength(); diff --git a/js/src/gc/Marking.h b/js/src/gc/Marking.h index 0180f480c..68bc95b30 100644 --- a/js/src/gc/Marking.h +++ b/js/src/gc/Marking.h @@ -192,6 +192,9 @@ IsValueAboutToBeFinalized(Value *v); /*** Slot Marking ***/ +bool +IsSlotMarked(HeapSlot *s); + void MarkSlot(JSTracer *trc, HeapSlot *s, const char *name); diff --git a/js/src/gc/Nursery-inl.h b/js/src/gc/Nursery-inl.h index bb1c8dca3..474422a0c 100644 --- a/js/src/gc/Nursery-inl.h +++ b/js/src/gc/Nursery-inl.h @@ -22,7 +22,7 @@ namespace gc { */ class RelocationOverlay { - friend struct MinorCollectionTracer; + friend class MinorCollectionTracer; /* The low bit is set so this should never equal a normal pointer. */ const static uintptr_t Relocated = uintptr_t(0xbad0bad1); diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp index fc0da8030..300cb9204 100644 --- a/js/src/gc/Nursery.cpp +++ b/js/src/gc/Nursery.cpp @@ -48,7 +48,7 @@ js::Nursery::init() // were marked as uncommitted, but it's a little complicated to avoid // clobbering pre-existing unrelated mappings. while (IsPoisonedPtr(heap) || IsPoisonedPtr((void*)(uintptr_t(heap) + NurserySize))) - heap = MapAlignedPages(NurserySize, Alignment); + heap = MapAlignedPages(runtime(), NurserySize, Alignment); #endif if (!heap) return false; @@ -58,7 +58,9 @@ js::Nursery::init() rt->gcNurseryEnd_ = chunk(LastNurseryChunk).end(); numActiveChunks_ = 1; setCurrentChunk(0); +#ifdef DEBUG JS_POISON(heap, FreshNursery, NurserySize); +#endif for (int i = 0; i < NumNurseryChunks; ++i) chunk(i).runtime = rt; @@ -108,7 +110,9 @@ js::Nursery::allocate(size_t size) void *thing = (void *)position(); position_ = position() + size; +#ifdef DEBUG JS_POISON(thing, AllocatedThing, size); +#endif return thing; } @@ -216,6 +220,7 @@ class MinorCollectionTracer : public JSTracer RelocationOverlay **tail; /* Save and restore all of the runtime state we use during MinorGC. */ + bool savedRuntimeNeedBarrier; AutoDisableProxyCheck disableStrictProxyChecking; /* Insert the given relocation entry into the list of things to visit. */ @@ -232,11 +237,26 @@ class MinorCollectionTracer : public JSTracer tenuredSize(0), head(NULL), tail(&head), + savedRuntimeNeedBarrier(rt->needsBarrier()), disableStrictProxyChecking(rt) { JS_TracerInit(this, rt, Nursery::MinorGCCallback); eagerlyTraceWeakMaps = TraceWeakMapKeysValues; rt->gcNumber++; + + /* + * We disable the runtime needsBarrier() check so that pre-barriers do + * not fire on objects that have been relocated. The pre-barrier's + * call to obj->zone() will try to look through shape_, which is now + * the relocation magic and will crash. However, zone->needsBarrier() + * must still be set correctly so that allocations we make in minor + * GCs between incremental slices will allocate their objects marked. + */ + rt->setNeedsBarrier(false); + } + + ~MinorCollectionTracer() { + runtime->setNeedsBarrier(savedRuntimeNeedBarrier); } }; @@ -246,7 +266,7 @@ class MinorCollectionTracer : public JSTracer static AllocKind GetObjectAllocKindForCopy(JSRuntime *rt, JSObject *obj) { - if (obj->isArray()) { + if (obj->is()) { JS_ASSERT(obj->numFixedSlots() == 0); /* Use minimal size object if we are just going to copy the pointer. */ @@ -305,7 +325,7 @@ js::Nursery::moveObjectToTenured(JSObject *dst, JSObject *src, AllocKind dstKind * We deal with this by copying elements manually, possibly re-inlining * them if there is adequate room inline in dst. */ - if (src->isArray()) + if (src->is()) srcSize = sizeof(ObjectImpl); js_memcpy(dst, src, srcSize); @@ -374,7 +394,7 @@ js::Nursery::moveElementsToTenured(JSObject *dst, JSObject *src, AllocKind dstKi size_t nslots = ObjectElements::VALUES_PER_HEADER + srcHeader->capacity; /* Unlike other objects, Arrays can have fixed elements. */ - if (src->isArray() && nslots <= GetGCKindSlots(dstKind)) { + if (src->is() && nslots <= GetGCKindSlots(dstKind)) { dst->setFixedElements(); dstHeader = dst->getElementsHeader(); js_memcpy(dstHeader, srcHeader, nslots * sizeof(HeapSlot)); diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index 88574f393..65d059528 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -449,6 +449,12 @@ AutoGCRooter::trace(JSTracer *trc) return; } + case FUNVECTOR: { + AutoFunctionVector::VectorImpl &vector = static_cast(this)->vector; + MarkObjectRootRange(trc, vector.length(), vector.begin(), "js::AutoFunctionVector.vector"); + return; + } + case STRINGVECTOR: { AutoStringVector::VectorImpl &vector = static_cast(this)->vector; MarkStringRootRange(trc, vector.length(), vector.begin(), "js::AutoStringVector.vector"); diff --git a/js/src/gc/StoreBuffer.cpp b/js/src/gc/StoreBuffer.cpp index 067b4ebd8..7f78cb987 100644 --- a/js/src/gc/StoreBuffer.cpp +++ b/js/src/gc/StoreBuffer.cpp @@ -6,11 +6,13 @@ #ifdef JSGC_GENERATIONAL -#include "jsgc.h" +#include "gc/StoreBuffer.h" + +#include "mozilla/Assertions.h" + +#include "vm/ForkJoin.h" #include "gc/Barrier-inl.h" -#include "gc/StoreBuffer.h" -#include "vm/ForkJoin.h" #include "vm/ObjectImpl-inl.h" using namespace js; @@ -64,8 +66,12 @@ StoreBuffer::WholeCellEdges::mark(JSTracer *trc) MarkChildren(trc, static_cast(tenured)); return; } +#ifdef JS_ION JS_ASSERT(kind == JSTRACE_IONCODE); static_cast(tenured)->trace(trc); +#else + MOZ_NOT_REACHED("Only objects can be in the wholeCellBuffer if IonMonkey is disabled."); +#endif } /*** MonoTypeBuffer ***/ diff --git a/js/src/gc/StoreBuffer.h b/js/src/gc/StoreBuffer.h index ba561eb9c..4ef7defad 100644 --- a/js/src/gc/StoreBuffer.h +++ b/js/src/gc/StoreBuffer.h @@ -13,10 +13,12 @@ # error "Generational GC requires exact rooting." #endif -#include "jsgc.h" #include "jsalloc.h" +#include "jsgc.h" #include "jsobj.h" +#include "gc/Nursery.h" + namespace js { namespace gc { diff --git a/js/src/jit-test/lib/asserts.js b/js/src/jit-test/lib/asserts.js index 44a174caf..358d4c6bf 100644 --- a/js/src/jit-test/lib/asserts.js +++ b/js/src/jit-test/lib/asserts.js @@ -21,6 +21,67 @@ if (typeof assertThrowsInstanceOf === 'undefined') { }; } +if (typeof assertWarning === 'undefined') { + var assertWarning = function assertWarning(f, errorClass, msg) { + var hadWerror = options().split(",").indexOf("werror") !== -1; + + // Ensure the "werror" option is disabled. + if (hadWerror) + options("werror"); + + try { + f(); + } catch (exc) { + if (hadWerror) + options("werror"); + + // print() rather than throw a different exception value, in case + // the caller wants exc.stack. + if (msg) + print("assertWarning: " + msg); + print("assertWarning: Unexpected exception calling " + f + + " with warnings-as-errors disabled"); + throw exc; + } + + // Enable the "werror" option. + options("werror"); + + try { + assertThrowsInstanceOf(f, errorClass, msg); + } catch (exc) { + if (msg) + print("assertWarning: " + msg); + throw exc; + } finally { + if (!hadWerror) + options("werror"); + } + }; +} + +if (typeof assertNoWarning === 'undefined') { + var assertNoWarning = function assertWarning(f, msg) { + // Ensure the "werror" option is enabled. + var hadWerror = options().split(",").indexOf("werror") !== -1; + if (!hadWerror) + options("werror"); + + try { + f(); + } catch (exc) { + if (msg) + print("assertNoWarning: " + msg); + print("assertNoWarning: Unexpected exception calling " + f + + "with warnings-as-errors enabled"); + throw exc; + } finally { + if (!hadWerror) + options("werror"); + } + }; +} + if (typeof assertThrowsValue === 'undefined') { var assertThrowsValue = function assertThrowsValue(f, val, msg) { var fullmsg; diff --git a/js/src/jit-test/tests/asm.js/testLiterals.js b/js/src/jit-test/tests/asm.js/testLiterals.js index 45f325f07..01ddf3b42 100644 --- a/js/src/jit-test/tests/asm.js/testLiterals.js +++ b/js/src/jit-test/tests/asm.js/testLiterals.js @@ -3,6 +3,8 @@ load(libdir + 'asm.js'); assertAsmTypeFail(USE_ASM + 'function f(d) { d=+d; var e=0; e=d; return +e } return f'); assertAsmTypeFail(USE_ASM + 'function f(d) { d=+d; var e=1e1; e=d; return +e } return f'); assertAsmTypeFail(USE_ASM + 'function f(d) { d=+d; var e=+0; e=d; return +e } return f'); +assertEq(asmLink(asmCompile(USE_ASM + 'function f() { var e=-0; return +e } return f'))(-0), -0); +assertEq(asmLink(asmCompile(USE_ASM + 'function f() { var e=-0.0; return +e } return f'))(-0), -0); assertEq(asmLink(asmCompile(USE_ASM + 'function f(d) { d=+d; var e=0.0; e=d; return +e } return f'))(0.1), 0.1); assertEq(asmLink(asmCompile(USE_ASM + 'function f(d) { d=+d; var e=-0.0; e=d; return +e } return f'))(0.1), 0.1); assertEq(asmLink(asmCompile(USE_ASM + 'function f(d) { d=+d; var e=10.0; e=d; return +e } return f'))(0.1), 0.1); diff --git a/js/src/jit-test/tests/basic/bug-826124.js b/js/src/jit-test/tests/basic/bug-826124.js new file mode 100644 index 000000000..6efda93aa --- /dev/null +++ b/js/src/jit-test/tests/basic/bug-826124.js @@ -0,0 +1,14 @@ +var x = {}; +function f() { y.prop; } +x.toStr = function () { f(); }; +try { + f(); +} catch (e) { } +try { + x.toStr(); +} catch (e) { } +try { + function f() { which = 2; } + x.toStr(); +} catch (e) { which = 1; } +assertEq(which, 2); diff --git a/js/src/jit-test/tests/gc/bug-886551-1.js b/js/src/jit-test/tests/gc/bug-886551-1.js new file mode 100644 index 000000000..59df90fe2 --- /dev/null +++ b/js/src/jit-test/tests/gc/bug-886551-1.js @@ -0,0 +1,8 @@ +if (this.hasOwnProperty('Intl')) { + gc(); + gcslice(0); + var thisValues = [ "x" ]; + thisValues.forEach(function (value) { + var format = Intl.DateTimeFormat.call(value); + }); +} diff --git a/js/src/jit-test/tests/gc/bug-886551-2.js b/js/src/jit-test/tests/gc/bug-886551-2.js new file mode 100644 index 000000000..750d8f0d3 --- /dev/null +++ b/js/src/jit-test/tests/gc/bug-886551-2.js @@ -0,0 +1,7 @@ +gc(); +gcslice(0); +function isClone(a, b) { + var rmemory = new WeakMap(); + rmemory.set(a,b); +} +isClone([]); diff --git a/js/src/jit-test/tests/parser/bug-844805.js b/js/src/jit-test/tests/parser/bug-844805.js new file mode 100644 index 000000000..b6bad2105 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-844805.js @@ -0,0 +1 @@ +if (Math["key"]) {} diff --git a/js/src/jit-test/tests/parser/yield-without-operand.js b/js/src/jit-test/tests/parser/yield-without-operand.js new file mode 100644 index 000000000..7c52c57c2 --- /dev/null +++ b/js/src/jit-test/tests/parser/yield-without-operand.js @@ -0,0 +1,22 @@ +// yield without an operand causes a warning. See bug 885463. + +load(libdir + "asserts.js"); + +assertWarning(() => Function("yield"), SyntaxError, + "yield followed by EOF should cause a warning"); +assertWarning(() => Function("yield;"), SyntaxError, + "yield followed by semicolon should cause a warning"); +assertWarning(() => Function("yield\n print('ok');"), SyntaxError, + "yield followed by newline should cause a warning"); + +assertWarning(() => eval("(function () { yield; })"), SyntaxError, + "yield followed by semicolon in eval code should cause a warning"); +assertWarning(() => eval("(function () { yield })"), SyntaxError, + "yield followed by } in eval code should cause a warning"); + +assertNoWarning(() => Function("yield 0;"), + "yield with an operand should be fine"); +assertNoWarning(() => Function("yield 0"), + "yield with an operand should be fine, even without a semicolon"); + +print("\npassed - all those warnings are normal and there's no real way to suppress them"); diff --git a/js/src/jit/AsmJS.cpp b/js/src/jit/AsmJS.cpp index d05289ecf..9b46c5a84 100644 --- a/js/src/jit/AsmJS.cpp +++ b/js/src/jit/AsmJS.cpp @@ -697,12 +697,10 @@ ExtractNumericLiteral(ParseNode *pn) d = NumberNodeValue(numberNode); } - if (NumberNodeHasFrac(numberNode)) + if (NumberNodeHasFrac(numberNode) || IsNegativeZero(d)) return NumLit(NumLit::Double, DoubleValue(d)); int64_t i64 = int64_t(d); - if (d != double(i64)) - return NumLit(NumLit::OutOfRangeInt, UndefinedValue()); if (i64 >= 0) { if (i64 <= INT32_MAX) diff --git a/js/src/jit/AsmJS.h b/js/src/jit/AsmJS.h index 2e4ac3063..0db969445 100644 --- a/js/src/jit/AsmJS.h +++ b/js/src/jit/AsmJS.h @@ -17,7 +17,7 @@ namespace js { class ScriptSource; class SPSProfiler; class AsmJSModule; -namespace frontend { struct TokenStream; struct ParseNode; } +namespace frontend { class TokenStream; class ParseNode; } namespace jit { class MIRGenerator; class LIRGraph; } // Called after parsing a function 'fn' which contains the "use asm" directive. diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index 173cc7168..940a2fc75 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -2744,11 +2744,6 @@ BaselineCompiler::emit_JSOP_REST() { frame.syncStack(0); - RootedTypeObject type(cx, types::TypeScript::InitObject(cx, script, pc, JSProto_Array)); - if (!type) - return false; - masm.movePtr(ImmGCPtr(type), R0.scratchReg()); - ICRest_Fallback::Compiler stubCompiler(cx); if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false; diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 17ff5df94..7ec37396c 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -2352,7 +2352,7 @@ DoToNumberFallback(JSContext *cx, ICToNumber_Fallback *stub, HandleValue arg, Mu { FallbackICSpew(cx, stub, "ToNumber"); ret.set(arg); - return ToNumber(cx, ret.address()); + return ToNumber(cx, ret); } typedef bool (*DoToNumberFallbackFn)(JSContext *, ICToNumber_Fallback *, HandleValue, MutableHandleValue); @@ -5176,7 +5176,7 @@ TryAttachLengthStub(JSContext *cx, HandleScript script, ICGetProp_Fallback *stub RootedObject obj(cx, &val.toObject()); - if (obj->isArray() && res.isInt32()) { + if (obj->is() && res.isInt32()) { IonSpew(IonSpew_BaselineIC, " Generating GetProp(Array.length) stub"); ICGetProp_ArrayLength::Compiler compiler(cx); ICStub *newStub = compiler.getStub(compiler.getStubSpace(script)); @@ -5531,7 +5531,7 @@ ICGetProp_ArrayLength::Compiler::generateStubCode(MacroAssembler &masm) // Unbox R0 and guard it's an array. Register obj = masm.extractObject(R0, ExtractTemp0); - masm.branchTestObjClass(Assembler::NotEqual, obj, scratch, &ArrayClass, &failure); + masm.branchTestObjClass(Assembler::NotEqual, obj, scratch, &ArrayObject::class_, &failure); // Load obj->elements->length. masm.loadPtr(Address(obj, JSObject::offsetOfElements()), scratch); @@ -8158,7 +8158,7 @@ ICTypeOf_Typed::Compiler::generateStubCode(MacroAssembler &masm) static bool DoCreateRestParameter(JSContext *cx, BaselineFrame *frame, ICRest_Fallback *stub, - HandleTypeObject type, MutableHandleValue res) + MutableHandleValue res) { FallbackICSpew(cx, stub, "Rest"); @@ -8170,19 +8170,12 @@ DoCreateRestParameter(JSContext *cx, BaselineFrame *frame, ICRest_Fallback *stub JSObject *obj = NewDenseCopiedArray(cx, numRest, rest, NULL); if (!obj) return false; - obj->setType(type); - - // Ensure that values in the rest array are represented in the type of the - // array. - for (unsigned i = 0; i < numRest; i++) - types::AddTypePropertyId(cx, obj, JSID_VOID, rest[i]); - res.setObject(*obj); return true; } typedef bool(*DoCreateRestParameterFn)(JSContext *cx, BaselineFrame *, ICRest_Fallback *, - HandleTypeObject, MutableHandleValue); + MutableHandleValue); static const VMFunction DoCreateRestParameterInfo = FunctionInfo(DoCreateRestParameter); @@ -8191,7 +8184,6 @@ ICRest_Fallback::Compiler::generateStubCode(MacroAssembler &masm) { EmitRestoreTailCallReg(masm); - masm.push(R0.scratchReg()); // type masm.push(BaselineStubReg); // stub masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg()); // frame pointer diff --git a/js/src/jit/BaselineJIT.h b/js/src/jit/BaselineJIT.h index a6b7a7bdd..4a3d79a2e 100644 --- a/js/src/jit/BaselineJIT.h +++ b/js/src/jit/BaselineJIT.h @@ -24,7 +24,7 @@ namespace js { namespace jit { class StackValue; -struct ICEntry; +class ICEntry; class ICStub; class PCMappingSlotInfo diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 923c92c6e..09a818d44 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -22,7 +22,7 @@ #include "builtin/Eval.h" #include "gc/Nursery.h" #include "vm/ForkJoin.h" -#include "ParallelArrayAnalysis.h" +#include "ParallelSafetyAnalysis.h" #include "jsscriptinlines.h" diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index 11f7aa910..fc329da0c 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -21,7 +21,7 @@ #include "EdgeCaseAnalysis.h" #include "RangeAnalysis.h" #include "LinearScan.h" -#include "ParallelArrayAnalysis.h" +#include "ParallelSafetyAnalysis.h" #include "jscompartment.h" #include "vm/ThreadPool.h" #include "vm/ForkJoin.h" @@ -1008,6 +1008,12 @@ OptimizeMIR(MIRGenerator *mir) if (mir->shouldCancel("Apply types")) return false; + if (graph.entryBlock()->info().executionMode() == ParallelExecution) { + ParallelSafetyAnalysis analysis(mir, graph); + if (!analysis.analyze()) + return false; + } + // Alias analysis is required for LICM and GVN so that we don't move // loads across stores. if (js_IonOptions.licm || js_IonOptions.gvn) { @@ -1146,12 +1152,6 @@ OptimizeMIR(MIRGenerator *mir) IonSpewPass("Bounds Check Elimination"); AssertGraphCoherency(graph); - if (graph.entryBlock()->info().executionMode() == ParallelExecution) { - ParallelArrayAnalysis analysis(mir, graph); - if (!analysis.analyze()) - return false; - } - return true; } diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index a7c4a5fbf..5a9efe3f8 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -4153,10 +4153,7 @@ IonBuilder::inlineCalls(CallInfo &callInfo, AutoObjectVector &targets, return false; // Create a function MConstant to use in the entry ResumePoint. - // Note that guarding is on the original function pointer even - // if there is a clone, since cloning occurs at the callsite. - JSFunction *original = &originals[i]->as(); - MConstant *funcDef = MConstant::New(ObjectValue(*original)); + MConstant *funcDef = MConstant::New(ObjectValue(*target)); funcDef->setFoldedUnchecked(); dispatchBlock->add(funcDef); @@ -4203,7 +4200,10 @@ IonBuilder::inlineCalls(CallInfo &callInfo, AutoObjectVector &targets, setCurrent(dispatchBlock); // Connect the inline path to the returnBlock. - dispatch->addCase(original, inlineBlock); + // + // Note that guarding is on the original function pointer even + // if there is a clone, since cloning occurs at the callsite. + dispatch->addCase(&originals[i]->as(), inlineBlock); MDefinition *retVal = inlineReturnBlock->peek(-1); retPhi->addInput(retVal); @@ -6899,7 +6899,7 @@ IonBuilder::jsop_length_fastPath() types::StackTypeSet *objTypes = obj->resultTypeSet(); if (objTypes && - objTypes->getKnownClass() == &ArrayClass && + objTypes->getKnownClass() == &ArrayObject::class_ && !objTypes->hasObjectFlags(cx, types::OBJECT_FLAG_LENGTH_OVERFLOW)) { current->pop(); @@ -6959,33 +6959,55 @@ IonBuilder::jsop_arguments_length() bool IonBuilder::jsop_arguments_getelem() { - if (inliningDepth_ != 0) - return abort("NYI inlined get argument element"); + JS_ASSERT(!info().argsObjAliasesFormals()); + // Get the argument id MDefinition *idx = current->pop(); // Type Inference has guaranteed this is an optimized arguments object. MDefinition *args = current->pop(); args->setFoldedUnchecked(); - // To ensure that we are not looking above the number of actual arguments. - MArgumentsLength *length = MArgumentsLength::New(); - current->add(length); - // Ensure idx is an integer. - MInstruction *index = MToInt32::New(idx); - current->add(index); + // When we are not inlining, we can just get the arguments from the stack. + if (inliningDepth_ == 0) { + // To ensure that we are not looking above the number of actual arguments. + MArgumentsLength *length = MArgumentsLength::New(); + current->add(length); - // Bailouts if we read more than the number of actual arguments. - index = addBoundsCheck(index, length); + // Ensure idx is an integer. + MInstruction *index = MToInt32::New(idx); + current->add(index); - // Load the argument from the actual arguments. - MGetArgument *load = MGetArgument::New(index); - current->add(load); - current->push(load); + // Bailouts if we read more than the number of actual arguments. + index = addBoundsCheck(index, length); - types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc); - return pushTypeBarrier(load, types, true); + // Load the argument from the actual arguments. + MGetArgument *load = MGetArgument::New(index); + current->add(load); + current->push(load); + + types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc); + return pushTypeBarrier(load, types, true); + } + + // When the id is constant, we can just return the corresponding inlined argument + if (idx->isConstant() && idx->toConstant()->value().isInt32()) { + JS_ASSERT(inliningDepth_ > 0); + + int32_t id = idx->toConstant()->value().toInt32(); + idx->setFoldedUnchecked(); + + if (id < (int32_t)inlineCallInfo_->argc() && id >= 0) + current->push(inlineCallInfo_->getArg(id)); + else + pushConstant(UndefinedValue()); + + return true; + } + + // inlined not constant not supported, yet. + return abort("NYI inlined not constant get argument element"); } bool @@ -6999,8 +7021,8 @@ IonBuilder::jsop_rest() { // We don't know anything about the callee. if (inliningDepth_ == 0) { - // Get an empty template array. - JSObject *templateObject = getNewArrayTemplateObject(0); + // Get an empty template array that doesn't have a pc-tracked type. + JSObject *templateObject = NewDenseUnallocatedArray(cx, 0, NULL, TenuredObject); if (!templateObject) return false; @@ -7019,7 +7041,7 @@ IonBuilder::jsop_rest() unsigned numActuals = inlineCallInfo_->argv().length(); unsigned numFormals = info().nargs() - 1; unsigned numRest = numActuals > numFormals ? numActuals - numFormals : 0; - JSObject *templateObject = getNewArrayTemplateObject(numRest); + JSObject *templateObject = NewDenseUnallocatedArray(cx, numRest, NULL, TenuredObject); MNewArray *array = new MNewArray(numRest, templateObject, MNewArray::NewArray_Allocating); current->add(array); @@ -7032,15 +7054,6 @@ IonBuilder::jsop_rest() MElements *elements = MElements::New(array); current->add(elements); - types::TypeObject *arrayType = templateObject->type(); - types::HeapTypeSet *elemTypes = NULL; - Vector setElemCalls(cx); - if (!arrayType->unknownProperties()) { - elemTypes = arrayType->getProperty(cx, JSID_VOID, false); - if (!elemTypes) - return false; - } - // Unroll the argument copy loop. We don't need to do any bounds or hole // checking here. MConstant *index; @@ -7048,35 +7061,16 @@ IonBuilder::jsop_rest() index = MConstant::New(Int32Value(i - numFormals)); current->add(index); - MInstruction *store; MDefinition *arg = inlineCallInfo_->argv()[i]; - if (elemTypes && !TypeSetIncludes(elemTypes, arg->type(), arg->resultTypeSet())) { - elemTypes->addFreeze(cx); - store = MCallSetElement::New(array, index, arg); - if (!setElemCalls.append(store)) - return false; - } else { - store = MStoreElement::New(elements, index, arg, /* needsHoleCheck = */ false); - } - + MStoreElement *store = MStoreElement::New(elements, index, arg, + /* needsHoleCheck = */ false); current->add(store); } MSetInitializedLength *initLength = MSetInitializedLength::New(elements, index); current->add(initLength); - current->push(array); - // The reason this loop of resumeAfters is here and not above is because - // resume points check the stack depth at its callsite in IonBuilder - // matches the expected stack depth at the point where we would bail back - // to in the interpreter. So we can't call resumeAfter until after we have - // pushed the array onto the stack. - for (unsigned i = 0; i < setElemCalls.length(); i++) { - if (!resumeAfter(setElemCalls[i])) - return false; - } - return true; } diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index e96a5f3a4..ee225017a 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -720,7 +720,7 @@ class CallInfo return args_; } - MDefinition *getArg(uint32_t i) { + MDefinition *getArg(uint32_t i) const { JS_ASSERT(i < argc()); return args_[i]; } diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index 933d42da1..8b35a1964 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -1176,7 +1176,7 @@ GetPropertyIC::attachCallGetter(JSContext *cx, IonScript *ion, JSObject *obj, bool GetPropertyIC::attachArrayLength(JSContext *cx, IonScript *ion, JSObject *obj) { - JS_ASSERT(obj->isArray()); + JS_ASSERT(obj->is()); JS_ASSERT(!idempotent()); Label failures; @@ -1440,7 +1440,7 @@ TryAttachNativeGetPropStub(JSContext *cx, IonScript *ion, if (readSlot) return cache.attachReadSlot(cx, ion, obj, holder, shape); - else if (obj->isArray() && !cache.hasArrayLengthStub() && cx->names().length == name) + else if (obj->is() && !cache.hasArrayLengthStub() && cx->names().length == name) return cache.attachArrayLength(cx, ion, obj); return cache.attachCallGetter(cx, ion, obj, holder, shape, safepointIndex, returnAddr); } @@ -2613,7 +2613,7 @@ GetElementIC::reset() static bool IsElementSetInlineable(HandleObject obj, HandleValue index) { - if (!obj->isArray()) + if (!obj->is()) return false; if (obj->watched()) @@ -3057,11 +3057,10 @@ CallsiteCloneIC::attach(JSContext *cx, IonScript *ion, HandleFunction original, RepatchStubAppender attacher(*this); // Guard against object identity on the original. - attacher.branchNextStub(masm, Assembler::NotEqual, calleeReg(), - ImmWord(uintptr_t(original.get()))); + attacher.branchNextStub(masm, Assembler::NotEqual, calleeReg(), ImmGCPtr(original)); // Load the clone. - masm.movePtr(ImmWord(uintptr_t(clone.get())), outputReg()); + masm.movePtr(ImmGCPtr(clone), outputReg()); attacher.jumpRejoin(masm); diff --git a/js/src/jit/IonCompartment.h b/js/src/jit/IonCompartment.h index 9b392b0f3..83c5edb7a 100644 --- a/js/src/jit/IonCompartment.h +++ b/js/src/jit/IonCompartment.h @@ -66,7 +66,7 @@ typedef Vector OffThreadCompilationVector; // Optimized stubs are allocated per-compartment and are always purged when // JIT-code is discarded. Fallback stubs are allocated per BaselineScript and // are only destroyed when the BaselineScript is destroyed. -struct ICStubSpace +class ICStubSpace { protected: LifoAlloc allocator_; diff --git a/js/src/jit/IonMacroAssembler.cpp b/js/src/jit/IonMacroAssembler.cpp index 5517f3b96..4c467ad67 100644 --- a/js/src/jit/IonMacroAssembler.cpp +++ b/js/src/jit/IonMacroAssembler.cpp @@ -580,7 +580,7 @@ MacroAssembler::initGCThing(const Register &obj, JSObject *templateObject) storePtr(ImmGCPtr(templateObject->type()), Address(obj, JSObject::offsetOfType())); storePtr(ImmWord((void *)NULL), Address(obj, JSObject::offsetOfSlots())); - if (templateObject->isArray()) { + if (templateObject->is()) { JS_ASSERT(!templateObject->getDenseInitializedLength()); int elementsOffset = JSObject::offsetOfFixedElements(); @@ -594,7 +594,7 @@ MacroAssembler::initGCThing(const Register &obj, JSObject *templateObject) Address(obj, elementsOffset + ObjectElements::offsetOfCapacity())); store32(Imm32(templateObject->getDenseInitializedLength()), Address(obj, elementsOffset + ObjectElements::offsetOfInitializedLength())); - store32(Imm32(templateObject->getArrayLength()), + store32(Imm32(templateObject->as().length()), Address(obj, elementsOffset + ObjectElements::offsetOfLength())); store32(Imm32(templateObject->shouldConvertDoubleElements() ? ObjectElements::CONVERT_DOUBLE_ELEMENTS diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 1e100ee0b..24e546a34 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -310,7 +310,7 @@ IonBuilder::inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode) types::OBJECT_FLAG_ITERATED; types::StackTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet(); - if (!thisTypes || thisTypes->getKnownClass() != &ArrayClass) + if (!thisTypes || thisTypes->getKnownClass() != &ArrayObject::class_) return InliningStatus_NotInlined; if (thisTypes->hasObjectFlags(cx, unhandledFlags)) return InliningStatus_NotInlined; @@ -361,7 +361,7 @@ IonBuilder::inlineArrayPush(CallInfo &callInfo) return InliningStatus_NotInlined; types::StackTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet(); - if (!thisTypes || thisTypes->getKnownClass() != &ArrayClass) + if (!thisTypes || thisTypes->getKnownClass() != &ArrayObject::class_) return InliningStatus_NotInlined; if (thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_SPARSE_INDEXES | types::OBJECT_FLAG_LENGTH_OVERFLOW)) @@ -419,7 +419,7 @@ IonBuilder::inlineArrayConcat(CallInfo &callInfo) if (!thisTypes || !argTypes) return InliningStatus_NotInlined; - if (thisTypes->getKnownClass() != &ArrayClass) + if (thisTypes->getKnownClass() != &ArrayObject::class_) return InliningStatus_NotInlined; if (thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_SPARSE_INDEXES | types::OBJECT_FLAG_LENGTH_OVERFLOW)) @@ -427,7 +427,7 @@ IonBuilder::inlineArrayConcat(CallInfo &callInfo) return InliningStatus_NotInlined; } - if (argTypes->getKnownClass() != &ArrayClass) + if (argTypes->getKnownClass() != &ArrayObject::class_) return InliningStatus_NotInlined; if (argTypes->hasObjectFlags(cx, types::OBJECT_FLAG_SPARSE_INDEXES | types::OBJECT_FLAG_LENGTH_OVERFLOW)) diff --git a/js/src/jit/MIRGraph.h b/js/src/jit/MIRGraph.h index f696d2823..768ec5e2b 100644 --- a/js/src/jit/MIRGraph.h +++ b/js/src/jit/MIRGraph.h @@ -175,7 +175,7 @@ class MBasicBlock : public TempObject, public InlineListNode // Replaces an edge for a given block with a new block. This is // used for critical edge splitting and also for inserting - // bailouts during ParallelArrayAnalysis. + // bailouts during ParallelSafetyAnalysis. // // Note: If successorWithPhis is set, you must not be replacing it. void replacePredecessor(MBasicBlock *old, MBasicBlock *split); diff --git a/js/src/jit/ParallelFunctions.cpp b/js/src/jit/ParallelFunctions.cpp index ba1513bbf..4d5406b46 100644 --- a/js/src/jit/ParallelFunctions.cpp +++ b/js/src/jit/ParallelFunctions.cpp @@ -466,10 +466,9 @@ jit::InitRestParameter(ForkJoinSlice *slice, uint32_t length, Value *rest, // before this point. We can do the allocation here like in the sequential // path, but duplicating the initGCThing logic is too tedious. JS_ASSERT(res); - JS_ASSERT(res->isArray()); + JS_ASSERT(res->is()); JS_ASSERT(!res->getDenseInitializedLength()); JS_ASSERT(res->type() == templateObj->type()); - // See note in visitRest in ParallelArrayAnalysis. JS_ASSERT(res->type()->unknownProperties()); if (length) { diff --git a/js/src/jit/ParallelArrayAnalysis.cpp b/js/src/jit/ParallelSafetyAnalysis.cpp similarity index 89% rename from js/src/jit/ParallelArrayAnalysis.cpp rename to js/src/jit/ParallelSafetyAnalysis.cpp index 09ae6bcde..2f550a945 100644 --- a/js/src/jit/ParallelArrayAnalysis.cpp +++ b/js/src/jit/ParallelSafetyAnalysis.cpp @@ -9,15 +9,15 @@ #include "Ion.h" #include "MIR.h" #include "MIRGraph.h" -#include "ParallelArrayAnalysis.h" +#include "ParallelSafetyAnalysis.h" #include "IonSpewer.h" #include "UnreachableCodeElimination.h" #include "IonAnalysis.h" #include "vm/Stack.h" -namespace js { -namespace jit { +using namespace js; +using namespace jit; using parallel::Spew; using parallel::SpewMIR; @@ -63,9 +63,8 @@ using parallel::SpewCompile; return insertWriteGuard(prop, prop->obj()); \ } -class ParallelArrayVisitor : public MInstructionVisitor +class ParallelSafetyVisitor : public MInstructionVisitor { - JSContext *cx_; MIRGraph &graph_; bool unsafe_; MDefinition *parSlice_; @@ -91,9 +90,8 @@ class ParallelArrayVisitor : public MInstructionVisitor } public: - ParallelArrayVisitor(JSContext *cx, MIRGraph &graph) - : cx_(cx), - graph_(graph), + ParallelSafetyVisitor(MIRGraph &graph) + : graph_(graph), unsafe_(false), parSlice_(NULL) { } @@ -116,7 +114,7 @@ class ParallelArrayVisitor : public MInstructionVisitor SAFE_OP(Callee) SAFE_OP(TableSwitch) SAFE_OP(Goto) - CUSTOM_OP(Test) + SAFE_OP(Test) SAFE_OP(Compare) SAFE_OP(Phi) SAFE_OP(Beta) @@ -300,7 +298,7 @@ class ParallelArrayVisitor : public MInstructionVisitor }; bool -ParallelArrayAnalysis::analyze() +ParallelSafetyAnalysis::analyze() { // Walk the basic blocks in a DFS. When we encounter a block with an // unsafe instruction, then we know that this block will bailout when @@ -309,12 +307,11 @@ ParallelArrayAnalysis::analyze() // We don't need a worklist, though, because the graph is sorted // in RPO. Therefore, we just use the marked flags to tell us // when we visited some predecessor of the current block. - JSContext *cx = GetIonContext()->cx; - ParallelArrayVisitor visitor(cx, graph_); + ParallelSafetyVisitor visitor(graph_); graph_.entryBlock()->mark(); // Note: in par. exec., we never enter from OSR. uint32_t marked = 0; for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) { - if (mir_->shouldCancel("ParallelArrayAnalysis")) + if (mir_->shouldCancel("ParallelSafetyAnalysis")) return false; if (block->isMarked()) { @@ -326,7 +323,7 @@ ParallelArrayAnalysis::analyze() for (MInstructionIterator ins(block->begin()); ins != block->end() && !visitor.unsafe();) { - if (mir_->shouldCancel("ParallelArrayAnalysis")) + if (mir_->shouldCancel("ParallelSafetyAnalysis")) return false; // We may be removing or replacing the current @@ -370,12 +367,12 @@ ParallelArrayAnalysis::analyze() } Spew(SpewCompile, "Safe"); - IonSpewPass("ParallelArrayAnalysis"); + IonSpewPass("ParallelSafetyAnalysis"); UnreachableCodeElimination uce(mir_, graph_); if (!uce.removeUnmarkedBlocks(marked)) return false; - IonSpewPass("UCEAfterParallelArrayAnalysis"); + IonSpewPass("UCEAfterParallelSafetyAnalysis"); AssertExtendedGraphCoherency(graph_); if (!removeResumePointOperands()) @@ -383,16 +380,11 @@ ParallelArrayAnalysis::analyze() IonSpewPass("RemoveResumePointOperands"); AssertExtendedGraphCoherency(graph_); - if (!EliminateDeadCode(mir_, graph_)) - return false; - IonSpewPass("DCEAfterParallelArrayAnalysis"); - AssertExtendedGraphCoherency(graph_); - return true; } bool -ParallelArrayAnalysis::removeResumePointOperands() +ParallelSafetyAnalysis::removeResumePointOperands() { // In parallel exec mode, nothing is effectful, therefore we do // not need to reconstruct interpreter state and can simply @@ -432,21 +424,15 @@ ParallelArrayAnalysis::removeResumePointOperands() } void -ParallelArrayAnalysis::replaceOperandsOnResumePoint(MResumePoint *resumePoint, - MDefinition *withDef) +ParallelSafetyAnalysis::replaceOperandsOnResumePoint(MResumePoint *resumePoint, + MDefinition *withDef) { for (size_t i = 0; i < resumePoint->numOperands(); i++) resumePoint->replaceOperand(i, withDef); } bool -ParallelArrayVisitor::visitTest(MTest *) -{ - return true; -} - -bool -ParallelArrayVisitor::convertToBailout(MBasicBlock *block, MInstruction *ins) +ParallelSafetyVisitor::convertToBailout(MBasicBlock *block, MInstruction *ins) { JS_ASSERT(unsafe()); // `block` must have contained unsafe items JS_ASSERT(block->isMarked()); // `block` must have been reachable to get here @@ -506,7 +492,7 @@ ParallelArrayVisitor::convertToBailout(MBasicBlock *block, MInstruction *ins) // These allocations will take place using per-helper-thread arenas. bool -ParallelArrayVisitor::visitNewParallelArray(MNewParallelArray *ins) +ParallelSafetyVisitor::visitNewParallelArray(MNewParallelArray *ins) { MParNew *parNew = new MParNew(parSlice(), ins->templateObject()); replace(ins, parNew); @@ -514,7 +500,7 @@ ParallelArrayVisitor::visitNewParallelArray(MNewParallelArray *ins) } bool -ParallelArrayVisitor::visitNewCallObject(MNewCallObject *ins) +ParallelSafetyVisitor::visitNewCallObject(MNewCallObject *ins) { // fast path: replace with ParNewCallObject op MParNewCallObject *parNewCallObjectInstruction = @@ -524,7 +510,7 @@ ParallelArrayVisitor::visitNewCallObject(MNewCallObject *ins) } bool -ParallelArrayVisitor::visitLambda(MLambda *ins) +ParallelSafetyVisitor::visitLambda(MLambda *ins) { if (ins->fun()->hasSingletonType() || types::UseNewTypeForClone(ins->fun())) @@ -540,7 +526,7 @@ ParallelArrayVisitor::visitLambda(MLambda *ins) } bool -ParallelArrayVisitor::visitNewObject(MNewObject *newInstruction) +ParallelSafetyVisitor::visitNewObject(MNewObject *newInstruction) { if (newInstruction->shouldUseVM()) { SpewMIR(newInstruction, "should use VM"); @@ -552,7 +538,7 @@ ParallelArrayVisitor::visitNewObject(MNewObject *newInstruction) } bool -ParallelArrayVisitor::visitNewArray(MNewArray *newInstruction) +ParallelSafetyVisitor::visitNewArray(MNewArray *newInstruction) { if (newInstruction->shouldUseVM()) { SpewMIR(newInstruction, "should use VM"); @@ -564,24 +550,14 @@ ParallelArrayVisitor::visitNewArray(MNewArray *newInstruction) } bool -ParallelArrayVisitor::visitRest(MRest *ins) +ParallelSafetyVisitor::visitRest(MRest *ins) { - // Construct a new template object that has a generic type object and not - // a pc-tracked one. This is because we cannot ensure that the arguments - // array's element types to contain the argument types in a threadsafe - // manner, so we might as well just not track its element types so that we - // can stay parallel. - JSObject *templateObj = NewDenseUnallocatedArray(cx_, 0, NULL, TenuredObject); - if (!templateObj) - return false; - - return replace(ins, MParRest::New(parSlice(), ins->numActuals(), - ins->numFormals(), templateObj)); + return replace(ins, MParRest::New(parSlice(), ins)); } bool -ParallelArrayVisitor::replaceWithParNew(MInstruction *newInstruction, - JSObject *templateObject) +ParallelSafetyVisitor::replaceWithParNew(MInstruction *newInstruction, + JSObject *templateObject) { MParNew *parNewInstruction = new MParNew(parSlice(), templateObject); replace(newInstruction, parNewInstruction); @@ -589,8 +565,8 @@ ParallelArrayVisitor::replaceWithParNew(MInstruction *newInstruction, } bool -ParallelArrayVisitor::replace(MInstruction *oldInstruction, - MInstruction *replacementInstruction) +ParallelSafetyVisitor::replace(MInstruction *oldInstruction, + MInstruction *replacementInstruction) { MBasicBlock *block = oldInstruction->block(); block->insertBefore(oldInstruction, replacementInstruction); @@ -610,8 +586,8 @@ ParallelArrayVisitor::replace(MInstruction *oldInstruction, // per-thread-arena or not. bool -ParallelArrayVisitor::insertWriteGuard(MInstruction *writeInstruction, - MDefinition *valueBeingWritten) +ParallelSafetyVisitor::insertWriteGuard(MInstruction *writeInstruction, + MDefinition *valueBeingWritten) { // Many of the write operations do not take the JS object // but rather something derived from it, such as the elements. @@ -689,7 +665,7 @@ ParallelArrayVisitor::insertWriteGuard(MInstruction *writeInstruction, // Ion compiled. If a function has no IonScript, we bail out. bool -ParallelArrayVisitor::visitCall(MCall *ins) +ParallelSafetyVisitor::visitCall(MCall *ins) { // DOM? Scary. if (ins->isDOMFunction()) { @@ -697,7 +673,7 @@ ParallelArrayVisitor::visitCall(MCall *ins) return markUnsafe(); } - RootedFunction target(cx_, ins->getSingleTarget()); + JSFunction *target = ins->getSingleTarget(); if (target) { // Native? Scary. if (target->isNative()) { @@ -724,14 +700,14 @@ ParallelArrayVisitor::visitCall(MCall *ins) // Similar considerations apply to checking for interrupts. bool -ParallelArrayVisitor::visitCheckOverRecursed(MCheckOverRecursed *ins) +ParallelSafetyVisitor::visitCheckOverRecursed(MCheckOverRecursed *ins) { MParCheckOverRecursed *replacement = new MParCheckOverRecursed(parSlice()); return replace(ins, replacement); } bool -ParallelArrayVisitor::visitInterruptCheck(MInterruptCheck *ins) +ParallelSafetyVisitor::visitInterruptCheck(MInterruptCheck *ins) { MParCheckInterrupt *replacement = new MParCheckInterrupt(parSlice()); return replace(ins, replacement); @@ -747,8 +723,8 @@ ParallelArrayVisitor::visitInterruptCheck(MInterruptCheck *ins) // if the operands are not both integers/floats. bool -ParallelArrayVisitor::visitSpecializedInstruction(MInstruction *ins, MIRType spec, - uint32_t flags) +ParallelSafetyVisitor::visitSpecializedInstruction(MInstruction *ins, MIRType spec, + uint32_t flags) { uint32_t flag = 1 << spec; if (flags & flag) @@ -762,7 +738,7 @@ ParallelArrayVisitor::visitSpecializedInstruction(MInstruction *ins, MIRType spe // Throw bool -ParallelArrayVisitor::visitThrow(MThrow *thr) +ParallelSafetyVisitor::visitThrow(MThrow *thr) { MBasicBlock *block = thr->block(); JS_ASSERT(block->lastIns() == thr); @@ -790,7 +766,7 @@ static bool AddCallTarget(HandleScript script, CallTargetVector &targets); bool -AddPossibleCallees(MIRGraph &graph, CallTargetVector &targets) +jit::AddPossibleCallees(MIRGraph &graph, CallTargetVector &targets) { JSContext *cx = GetIonContext()->cx; @@ -889,6 +865,3 @@ AddCallTarget(HandleScript script, CallTargetVector &targets) return true; } - -} -} diff --git a/js/src/jit/ParallelArrayAnalysis.h b/js/src/jit/ParallelSafetyAnalysis.h similarity index 85% rename from js/src/jit/ParallelArrayAnalysis.h rename to js/src/jit/ParallelSafetyAnalysis.h index 60b6e0a1b..fbdacc507 100644 --- a/js/src/jit/ParallelArrayAnalysis.h +++ b/js/src/jit/ParallelSafetyAnalysis.h @@ -4,8 +4,8 @@ * 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 jit_ParallelArrayAnalysis_h -#define jit_ParallelArrayAnalysis_h +#ifndef ion_ParallelSafetyAnalysis_h +#define ion_ParallelSafetyAnalysis_h #include "MIR.h" #include "CompileInfo.h" @@ -22,7 +22,7 @@ class AutoDestroyAllocator; // Determines whether a function is compatible for parallel execution. // Removes basic blocks containing unsafe MIR operations from the // graph and replaces them with MParBailout blocks. -class ParallelArrayAnalysis +class ParallelSafetyAnalysis { MIRGenerator *mir_; MIRGraph &graph_; @@ -31,8 +31,8 @@ class ParallelArrayAnalysis void replaceOperandsOnResumePoint(MResumePoint *resumePoint, MDefinition *withDef); public: - ParallelArrayAnalysis(MIRGenerator *mir, - MIRGraph &graph) + ParallelSafetyAnalysis(MIRGenerator *mir, + MIRGraph &graph) : mir_(mir), graph_(graph) {} @@ -52,4 +52,4 @@ bool AddPossibleCallees(MIRGraph &graph, CallTargetVector &targets); } // namespace jit } // namespace js -#endif /* jit_ParallelArrayAnalysis_h */ +#endif /* ion_ParallelSafetyAnalysis_h */ diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 212bc46d1..b422941be 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -10,6 +10,7 @@ #include "jit/BaselineIC.h" #include "jit/IonFrames.h" +#include "vm/ArrayObject.h" #include "vm/Debugger.h" #include "vm/Interpreter.h" #include "vm/StringObject-inl.h" @@ -309,7 +310,7 @@ NewInitObjectWithClassPrototype(JSContext *cx, HandleObject templateObject) bool ArrayPopDense(JSContext *cx, HandleObject obj, MutableHandleValue rval) { - JS_ASSERT(obj->isArray()); + JS_ASSERT(obj->is()); AutoDetectInvalidation adi(cx, rval.address()); @@ -329,7 +330,7 @@ ArrayPopDense(JSContext *cx, HandleObject obj, MutableHandleValue rval) bool ArrayPushDense(JSContext *cx, HandleObject obj, HandleValue v, uint32_t *length) { - JS_ASSERT(obj->isArray()); + JS_ASSERT(obj->is()); Value argv[] = { UndefinedValue(), ObjectValue(*obj), v }; AutoValueArray ava(cx, argv, 3); @@ -343,7 +344,7 @@ ArrayPushDense(JSContext *cx, HandleObject obj, HandleValue v, uint32_t *length) bool ArrayShiftDense(JSContext *cx, HandleObject obj, MutableHandleValue rval) { - JS_ASSERT(obj->isArray()); + JS_ASSERT(obj->is()); AutoDetectInvalidation adi(cx, rval.address()); @@ -361,20 +362,20 @@ ArrayShiftDense(JSContext *cx, HandleObject obj, MutableHandleValue rval) } JSObject * -ArrayConcatDense(JSContext *cx, HandleObject obj1, HandleObject obj2, HandleObject res) +ArrayConcatDense(JSContext *cx, HandleObject obj1, HandleObject obj2, HandleObject objRes) { - JS_ASSERT(obj1->isArray()); - JS_ASSERT(obj2->isArray()); - JS_ASSERT_IF(res, res->isArray()); + Rooted arr1(cx, &obj1->as()); + Rooted arr2(cx, &obj2->as()); + Rooted arrRes(cx, objRes ? &objRes->as() : NULL); - if (res) { + if (arrRes) { // Fast path if we managed to allocate an object inline. - if (!js::array_concat_dense(cx, obj1, obj2, res)) + if (!js::array_concat_dense(cx, arr1, arr2, arrRes)) return NULL; - return res; + return arrRes; } - Value argv[] = { UndefinedValue(), ObjectValue(*obj1), ObjectValue(*obj2) }; + Value argv[] = { UndefinedValue(), ObjectValue(*arr1), ObjectValue(*arr2) }; AutoValueArray ava(cx, argv, 3); if (!js::array_concat(cx, 1, argv)) return NULL; @@ -700,39 +701,28 @@ NewArgumentsObject(JSContext *cx, BaselineFrame *frame, MutableHandleValue res) JSObject * InitRestParameter(JSContext *cx, uint32_t length, Value *rest, HandleObject templateObj, - HandleObject res) + HandleObject objRes) { - if (res) { - JS_ASSERT(res->isArray()); - JS_ASSERT(!res->getDenseInitializedLength()); - JS_ASSERT(res->type() == templateObj->type()); + if (objRes) { + Rooted arrRes(cx, &objRes->as()); + + JS_ASSERT(!arrRes->getDenseInitializedLength()); + JS_ASSERT(arrRes->type() == templateObj->type()); + JS_ASSERT(arrRes->type()->unknownProperties()); // Fast path: we managed to allocate the array inline; initialize the // slots. if (length > 0) { - if (!res->ensureElements(cx, length)) + if (!arrRes->ensureElements(cx, length)) return NULL; - res->setDenseInitializedLength(length); - res->initDenseElements(0, rest, length); - res->setArrayLengthInt32(length); - - // Ensure that values in the rest array are represented in the - // type of the array. - for (unsigned i = 0; i < length; i++) - types::AddTypePropertyId(cx, res, JSID_VOID, rest[i]); + arrRes->setDenseInitializedLength(length); + arrRes->initDenseElements(0, rest, length); + arrRes->setLengthInt32(length); } - return res; + return arrRes; } - JSObject *obj = NewDenseCopiedArray(cx, length, rest, NULL); - if (!obj) - return NULL; - obj->setType(templateObj->type()); - - for (unsigned i = 0; i < length; i++) - types::AddTypePropertyId(cx, obj, JSID_VOID, rest[i]); - - return obj; + return NewDenseCopiedArray(cx, length, rest, NULL); } bool diff --git a/js/src/js.msg b/js/src/js.msg index 6e8c26345..91c3c007f 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -322,7 +322,7 @@ MSG_DEF(JSMSG_INVALID_FOR_IN_INIT, 268, 0, JSEXN_SYNTAXERR, "for-in loop let MSG_DEF(JSMSG_CLEARED_SCOPE, 269, 0, JSEXN_TYPEERR, "attempt to run compile-and-go script on a cleared scope") MSG_DEF(JSMSG_MALFORMED_ESCAPE, 270, 1, JSEXN_SYNTAXERR, "malformed {0} character escape sequence") MSG_DEF(JSMSG_BAD_GENEXP_BODY, 271, 1, JSEXN_SYNTAXERR, "illegal use of {0} in generator expression") -MSG_DEF(JSMSG_UNUSED272, 272, 0, JSEXN_NONE, "") +MSG_DEF(JSMSG_YIELD_WITHOUT_OPERAND, 272, 0, JSEXN_SYNTAXERR, "yield without a value is deprecated, and illegal in ES6 (use 'yield undefined' instead)") MSG_DEF(JSMSG_UNNAMED_FUNCTION_STMT, 273, 0, JSEXN_SYNTAXERR, "function statement requires a name") MSG_DEF(JSMSG_CCW_REQUIRED, 274, 1, JSEXN_TYPEERR, "{0}: argument must be an object from a different compartment") MSG_DEF(JSMSG_DEBUG_BAD_RESUMPTION, 275, 0, JSEXN_TYPEERR, "debugger resumption value must be undefined, {throw: val}, {return: val}, or null") diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 1f1dbf403..9502ba639 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -64,7 +64,9 @@ #include "jit/AsmJS.h" #include "jit/PcScriptCache.h" #include "js/CharacterEncoding.h" +#include "vm/DateObject.h" #include "vm/Debugger.h" +#include "vm/ErrorObject.h" #include "vm/Interpreter.h" #include "vm/NumericConversions.h" #include "vm/Shape.h" @@ -621,7 +623,7 @@ JS_IsBuiltinEvalFunction(JSFunction *fun) JS_PUBLIC_API(JSBool) JS_IsBuiltinFunctionConstructor(JSFunction *fun) { - return IsBuiltinFunctionConstructor(fun); + return fun->isBuiltinFunctionConstructor(); } /************************************************************************/ @@ -1717,13 +1719,13 @@ StdNameToPropertyName(JSContext *cx, const JSStdName *stdn) static const JSStdName standard_class_atoms[] = { {js_InitFunctionClass, EAGER_CLASS_ATOM(Function), &JSFunction::class_}, {js_InitObjectClass, EAGER_ATOM_AND_CLASP(Object)}, - {js_InitArrayClass, EAGER_ATOM_AND_CLASP(Array)}, + {js_InitArrayClass, EAGER_ATOM_AND_OCLASP(Array)}, {js_InitBooleanClass, EAGER_ATOM_AND_OCLASP(Boolean)}, - {js_InitDateClass, EAGER_ATOM_AND_CLASP(Date)}, + {js_InitDateClass, EAGER_ATOM_AND_OCLASP(Date)}, {js_InitMathClass, EAGER_ATOM_AND_CLASP(Math)}, {js_InitNumberClass, EAGER_ATOM_AND_OCLASP(Number)}, {js_InitStringClass, EAGER_ATOM_AND_OCLASP(String)}, - {js_InitExceptionClasses, EAGER_ATOM_AND_CLASP(Error)}, + {js_InitExceptionClasses, EAGER_ATOM_AND_OCLASP(Error)}, {js_InitRegExpClass, EAGER_ATOM_AND_OCLASP(RegExp)}, #if JS_HAS_GENERATORS {js_InitIteratorClasses, EAGER_ATOM_AND_OCLASP(StopIteration)}, @@ -1771,14 +1773,14 @@ static const JSStdName standard_class_names[] = { #endif /* Exception constructors. */ - {js_InitExceptionClasses, EAGER_CLASS_ATOM(Error), CLASP(Error)}, - {js_InitExceptionClasses, EAGER_CLASS_ATOM(InternalError), CLASP(Error)}, - {js_InitExceptionClasses, EAGER_CLASS_ATOM(EvalError), CLASP(Error)}, - {js_InitExceptionClasses, EAGER_CLASS_ATOM(RangeError), CLASP(Error)}, - {js_InitExceptionClasses, EAGER_CLASS_ATOM(ReferenceError), CLASP(Error)}, - {js_InitExceptionClasses, EAGER_CLASS_ATOM(SyntaxError), CLASP(Error)}, - {js_InitExceptionClasses, EAGER_CLASS_ATOM(TypeError), CLASP(Error)}, - {js_InitExceptionClasses, EAGER_CLASS_ATOM(URIError), CLASP(Error)}, + {js_InitExceptionClasses, EAGER_CLASS_ATOM(Error), OCLASP(Error)}, + {js_InitExceptionClasses, EAGER_CLASS_ATOM(InternalError), OCLASP(Error)}, + {js_InitExceptionClasses, EAGER_CLASS_ATOM(EvalError), OCLASP(Error)}, + {js_InitExceptionClasses, EAGER_CLASS_ATOM(RangeError), OCLASP(Error)}, + {js_InitExceptionClasses, EAGER_CLASS_ATOM(ReferenceError), OCLASP(Error)}, + {js_InitExceptionClasses, EAGER_CLASS_ATOM(SyntaxError), OCLASP(Error)}, + {js_InitExceptionClasses, EAGER_CLASS_ATOM(TypeError), OCLASP(Error)}, + {js_InitExceptionClasses, EAGER_CLASS_ATOM(URIError), OCLASP(Error)}, {js_InitIteratorClasses, EAGER_CLASS_ATOM(Iterator), &PropertyIteratorObject::class_}, @@ -2954,7 +2956,7 @@ JS_IdArrayGet(JSContext *cx, JSIdArray *ida, int index) JS_PUBLIC_API(void) JS_DestroyIdArray(JSContext *cx, JSIdArray *ida) { - DestroyIdArray(cx->runtime()->defaultFreeOp(), ida); + cx->runtime()->defaultFreeOp()->free_(ida); } JS_PUBLIC_API(JSBool) @@ -4431,7 +4433,7 @@ prop_iter_finalize(FreeOp *fop, JSObject *obj) if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() >= 0) { /* Non-native case: destroy the ida enumerated when obj was created. */ JSIdArray *ida = (JSIdArray *) pdata; - DestroyIdArray(fop, ida); + fop->free_(ida); } } diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 72e61d347..70b2daa87 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -132,7 +132,8 @@ class JS_PUBLIC_API(AutoGCRooter) { OBJU32HASHMAP=-24, /* js::AutoObjectUnsigned32HashMap */ OBJHASHSET = -25, /* js::AutoObjectHashSet */ JSONPARSER = -26, /* js::JSONParser */ - CUSTOM = -27 /* js::CustomAutoRooter */ + CUSTOM = -27, /* js::CustomAutoRooter */ + FUNVECTOR = -28 /* js::AutoFunctionVector */ }; private: @@ -574,6 +575,19 @@ class AutoObjectVector : public AutoVectorRooter MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; +class AutoFunctionVector : public AutoVectorRooter +{ + public: + explicit AutoFunctionVector(JSContext *cx + MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoVectorRooter(cx, FUNVECTOR) + { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } + + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + class AutoScriptVector : public AutoVectorRooter { public: @@ -5217,6 +5231,7 @@ using JS::Latin1CharsZ; using JS::AutoIdVector; using JS::AutoValueVector; using JS::AutoObjectVector; +using JS::AutoFunctionVector; using JS::AutoScriptVector; using JS::AutoIdArray; diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 43634fef5..4ff165d10 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -33,6 +33,7 @@ #include "jscntxtinlines.h" #include "jsstrinlines.h" +#include "vm/ArrayObject-inl.h" #include "vm/ArgumentsObject-inl.h" #include "vm/Interpreter-inl.h" #include "vm/ObjectImpl-inl.h" @@ -50,8 +51,8 @@ using mozilla::PointerRangeSize; JSBool js::GetLengthProperty(JSContext *cx, HandleObject obj, uint32_t *lengthp) { - if (obj->isArray()) { - *lengthp = obj->getArrayLength(); + if (obj->is()) { + *lengthp = obj->as().length(); return true; } @@ -235,7 +236,7 @@ GetElementsSlow(JSContext *cx, HandleObject aobj, uint32_t length, Value *vp) bool js::GetElements(JSContext *cx, HandleObject aobj, uint32_t length, Value *vp) { - if (aobj->isArray() && length <= aobj->getDenseInitializedLength() && + if (aobj->is() && length <= aobj->getDenseInitializedLength() && !ObjectMayHaveExtraIndexedProperties(aobj)) { /* No other indexed properties so hole = undefined */ @@ -266,24 +267,25 @@ SetArrayElement(JSContext *cx, HandleObject obj, double index, HandleValue v) { JS_ASSERT(index >= 0); - if (obj->isArray() && !obj->isIndexed()) { + if (obj->is() && !obj->isIndexed()) { + Rooted arr(cx, &obj->as()); /* Predicted/prefetched code should favor the remains-dense case. */ JSObject::EnsureDenseResult result = JSObject::ED_SPARSE; do { if (index > uint32_t(-1)) break; uint32_t idx = uint32_t(index); - if (idx >= obj->getArrayLength() && !obj->arrayLengthIsWritable()) { + if (idx >= arr->length() && !arr->lengthIsWritable()) { JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL, JSMSG_CANT_REDEFINE_ARRAY_LENGTH); return false; } - result = obj->ensureDenseElements(cx, idx, 1); + result = arr->ensureDenseElements(cx, idx, 1); if (result != JSObject::ED_OK) break; - if (idx >= obj->getArrayLength()) - obj->setArrayLengthInt32(idx + 1); - JSObject::setDenseElementWithType(cx, obj, idx, v); + if (idx >= arr->length()) + arr->setLengthInt32(idx + 1); + JSObject::setDenseElementWithType(cx, arr, idx, v); return true; } while (false); @@ -318,7 +320,7 @@ DeleteArrayElement(JSContext *cx, HandleObject obj, double index, JSBool *succee JS_ASSERT(index >= 0); JS_ASSERT(floor(index) == index); - if (obj->isArray() && !obj->isIndexed()) { + if (obj->is() && !obj->isIndexed()) { if (index <= UINT32_MAX) { uint32_t idx = uint32_t(index); if (idx < obj->getDenseInitializedLength()) { @@ -375,8 +377,8 @@ array_length_getter(JSContext *cx, HandleObject obj_, HandleId id, MutableHandle { RootedObject obj(cx, obj_); do { - if (obj->isArray()) { - vp.setNumber(obj->getArrayLength()); + if (obj->is()) { + vp.setNumber(obj->as().length()); return true; } if (!JSObject::getProto(cx, obj, &obj)) @@ -388,14 +390,15 @@ array_length_getter(JSContext *cx, HandleObject obj_, HandleId id, MutableHandle static JSBool array_length_setter(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, MutableHandleValue vp) { - if (!obj->isArray()) { + if (!obj->is()) { return JSObject::defineProperty(cx, obj, cx->names().length, vp, NULL, NULL, JSPROP_ENUMERATE); } - MOZ_ASSERT(obj->arrayLengthIsWritable(), + Rooted arr(cx, &obj->as()); + MOZ_ASSERT(arr->lengthIsWritable(), "setter shouldn't be called if property is non-writable"); - return ArraySetLength(cx, obj, id, JSPROP_PERMANENT, vp, strict); + return ArraySetLength(cx, arr, id, JSPROP_PERMANENT, vp, strict); } struct ReverseIndexComparator @@ -425,10 +428,9 @@ js::CanonicalizeArrayLengthValue(JSContext *cx, HandleValue v, uint32_t *newLen) /* ES6 20130308 draft 8.4.2.4 ArraySetLength */ bool -js::ArraySetLength(JSContext *cx, HandleObject obj, HandleId id, unsigned attrs, +js::ArraySetLength(JSContext *cx, Handle arr, HandleId id, unsigned attrs, HandleValue value, bool setterIsStrict) { - MOZ_ASSERT(obj->isArray()); MOZ_ASSERT(id == NameToId(cx->names().length)); MOZ_ASSERT(attrs & JSPROP_PERMANENT); MOZ_ASSERT(!(attrs & JSPROP_ENUMERATE)); @@ -441,16 +443,16 @@ js::ArraySetLength(JSContext *cx, HandleObject obj, HandleId id, unsigned attrs, return false; /* Steps 6-7. */ - bool lengthIsWritable = obj->arrayLengthIsWritable(); + bool lengthIsWritable = arr->lengthIsWritable(); #ifdef DEBUG { - RootedShape lengthShape(cx, obj->nativeLookup(cx, id)); + RootedShape lengthShape(cx, arr->nativeLookup(cx, id)); MOZ_ASSERT(lengthShape); MOZ_ASSERT(lengthShape->writable() == lengthIsWritable); } #endif - uint32_t oldLen = obj->getArrayLength(); + uint32_t oldLen = arr->length(); /* Steps 8-9 for arrays with non-writable length. */ if (!lengthIsWritable) { @@ -484,14 +486,14 @@ js::ArraySetLength(JSContext *cx, HandleObject obj, HandleId id, unsigned attrs, // that element must prevent any deletions below it. Bug 586842 should // fix this inefficiency by moving indexed storage to be entirely // separate from non-indexed storage. - if (!obj->isIndexed()) { - uint32_t oldCapacity = obj->getDenseCapacity(); - uint32_t oldInitializedLength = obj->getDenseInitializedLength(); + if (!arr->isIndexed()) { + uint32_t oldCapacity = arr->getDenseCapacity(); + uint32_t oldInitializedLength = arr->getDenseInitializedLength(); MOZ_ASSERT(oldCapacity >= oldInitializedLength); if (oldInitializedLength > newLen) - obj->setDenseInitializedLength(newLen); + arr->setDenseInitializedLength(newLen); if (oldCapacity > newLen) - obj->shrinkElements(cx, newLen); + arr->shrinkElements(cx, newLen); // We've done the work of deleting any dense elements needing // deletion, and there are no sparse elements. Thus we can skip @@ -530,7 +532,7 @@ js::ArraySetLength(JSContext *cx, HandleObject obj, HandleId id, unsigned attrs, /* Steps 15b-d. */ JSBool deleteSucceeded; - if (!JSObject::deleteElement(cx, obj, oldLen, &deleteSucceeded)) + if (!JSObject::deleteElement(cx, arr, oldLen, &deleteSucceeded)) return false; if (!deleteSucceeded) { newLen = oldLen + 1; @@ -554,7 +556,7 @@ js::ArraySetLength(JSContext *cx, HandleObject obj, HandleId id, unsigned attrs, Vector indexes(cx); { AutoIdVector props(cx); - if (!GetPropertyNames(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, &props)) + if (!GetPropertyNames(cx, arr, JSITER_OWNONLY | JSITER_HIDDEN, &props)) return false; for (size_t i = 0; i < props.length(); i++) { @@ -590,7 +592,7 @@ js::ArraySetLength(JSContext *cx, HandleObject obj, HandleId id, unsigned attrs, /* Steps 15b-d. */ JSBool deleteSucceeded; - if (!JSObject::deleteElement(cx, obj, index, &deleteSucceeded)) + if (!JSObject::deleteElement(cx, arr, index, &deleteSucceeded)) return false; if (!deleteSucceeded) { newLen = index + 1; @@ -607,8 +609,8 @@ js::ArraySetLength(JSContext *cx, HandleObject obj, HandleId id, unsigned attrs, // API call on the floor here. Given that getter/setter will go away in // the long run, with accessors replacing them both internally and at the // API level, just run with this. - RootedShape lengthShape(cx, obj->nativeLookup(cx, id)); - if (!JSObject::changeProperty(cx, obj, lengthShape, attrs, + RootedShape lengthShape(cx, arr->nativeLookup(cx, id)); + if (!JSObject::changeProperty(cx, arr, lengthShape, attrs, JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_SHARED, array_length_getter, array_length_setter)) { @@ -616,8 +618,8 @@ js::ArraySetLength(JSContext *cx, HandleObject obj, HandleId id, unsigned attrs, } RootedValue v(cx, NumberValue(newLen)); - AddTypePropertyId(cx, obj, id, v); - JSObject::setArrayLength(cx, obj, newLen); + AddTypePropertyId(cx, arr, id, v); + ArrayObject::setLength(cx, arr, newLen); // All operations past here until the |!succeeded| code must be infallible, // so that all element fields remain properly synchronized. @@ -625,7 +627,7 @@ js::ArraySetLength(JSContext *cx, HandleObject obj, HandleId id, unsigned attrs, // Trim the initialized length, if needed, to preserve the <= length // invariant. (Capacity was already reduced during element deletion, if // necessary.) - ObjectElements *header = obj->getElementsHeader(); + ObjectElements *header = arr->getElementsHeader(); header->initializedLength = Min(header->initializedLength, newLen); if (attrs & JSPROP_READONLY) { @@ -637,9 +639,9 @@ js::ArraySetLength(JSContext *cx, HandleObject obj, HandleId id, unsigned attrs, // But in JIT code every check counts -- so we piggyback the check on // the already-required range check for |index < capacity| by making // capacity of arrays with non-writable length never exceed the length. - if (obj->getDenseCapacity() > newLen) { - obj->shrinkElements(cx, newLen); - obj->getElementsHeader()->capacity = newLen; + if (arr->getDenseCapacity() > newLen) { + arr->shrinkElements(cx, newLen); + arr->getElementsHeader()->capacity = newLen; } } @@ -647,7 +649,7 @@ js::ArraySetLength(JSContext *cx, HandleObject obj, HandleId id, unsigned attrs, RootedId elementId(cx); if (!IndexToId(cx, newLen - 1, &elementId)) return false; - return obj->reportNotConfigurable(cx, elementId); + return arr->reportNotConfigurable(cx, elementId); } return true; @@ -657,18 +659,19 @@ bool js::WouldDefinePastNonwritableLength(JSContext *cx, HandleObject obj, uint32_t index, bool strict, bool *definesPast) { - if (!obj->isArray()) { + if (!obj->is()) { *definesPast = false; return true; } - uint32_t length = obj->getArrayLength(); + Rooted arr(cx, &obj->as()); + uint32_t length = arr->length(); if (index < length) { *definesPast = false; return true; } - if (obj->arrayLengthIsWritable()) { + if (arr->lengthIsWritable()) { *definesPast = false; return true; } @@ -688,15 +691,17 @@ static JSBool array_addProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp) { - uint32_t index, length; + Rooted arr(cx, &obj->as()); + uint32_t index; if (!js_IdIsIndex(id, &index)) return true; - length = obj->getArrayLength(); + + uint32_t length = arr->length(); if (index >= length) { - MOZ_ASSERT(obj->arrayLengthIsWritable(), + MOZ_ASSERT(arr->lengthIsWritable(), "how'd this element get added if length is non-writable?"); - JSObject::setArrayLength(cx, obj, index + 1); + ArrayObject::setLength(cx, arr, index + 1); } return true; } @@ -737,7 +742,7 @@ js::ObjectMayHaveExtraIndexedProperties(JSObject *obj) return false; } -Class js::ArrayClass = { +Class ArrayObject::class_ = { "Array", JSCLASS_HAS_CACHED_PROTO(JSProto_Array), array_addProperty, @@ -783,7 +788,7 @@ AddLengthProperty(JSContext *cx, HandleObject obj) JS_ALWAYS_INLINE bool IsArray(const Value &v) { - return v.isObject() && v.toObject().isArray(); + return v.isObject() && v.toObject().is(); } JS_ALWAYS_INLINE bool @@ -896,7 +901,7 @@ ArrayJoinKernel(JSContext *cx, SeparatorOp sepOp, HandleObject obj, uint32_t len { uint32_t i = 0; - if (!Locale && obj->isArray() && !ObjectMayHaveExtraIndexedProperties(obj)) { + if (!Locale && obj->is() && !ObjectMayHaveExtraIndexedProperties(obj)) { // This loop handles all elements up to initializedLength. If // length > initLength we rely on the second loop to add the // other elements. @@ -1145,7 +1150,7 @@ InitArrayElements(JSContext *cx, HandleObject obj, uint32_t start, uint32_t coun * length. */ do { - if (!obj->isArray()) + if (!obj->is()) break; if (ObjectMayHaveExtraIndexedProperties(obj)) break; @@ -1153,10 +1158,12 @@ InitArrayElements(JSContext *cx, HandleObject obj, uint32_t start, uint32_t coun if (obj->shouldConvertDoubleElements()) break; - if (!obj->arrayLengthIsWritable() && start + count > obj->getArrayLength()) + Rooted arr(cx, &obj->as()); + + if (!arr->lengthIsWritable() && start + count > arr->length()) break; - JSObject::EnsureDenseResult result = obj->ensureDenseElements(cx, start, count); + JSObject::EnsureDenseResult result = arr->ensureDenseElements(cx, start, count); if (result != JSObject::ED_OK) { if (result == JSObject::ED_FAILED) return false; @@ -1165,12 +1172,12 @@ InitArrayElements(JSContext *cx, HandleObject obj, uint32_t start, uint32_t coun } uint32_t newlen = start + count; - if (newlen > obj->getArrayLength()) - obj->setArrayLengthInt32(newlen); + if (newlen > arr->length()) + arr->setLengthInt32(newlen); JS_ASSERT(count < UINT32_MAX / sizeof(Value)); - obj->copyDenseElements(start, vector, count); - JS_ASSERT_IF(count != 0, !obj->getDenseElement(newlen - 1).isMagic(JS_ELEMENTS_HOLE)); + arr->copyDenseElements(start, vector, count); + JS_ASSERT_IF(count != 0, !arr->getDenseElement(newlen - 1).isMagic(JS_ELEMENTS_HOLE)); return true; } while (false); @@ -1217,7 +1224,7 @@ array_reverse(JSContext *cx, unsigned argc, Value *vp) return false; do { - if (!obj->isArray()) + if (!obj->is()) break; if (ObjectMayHaveExtraIndexedProperties(obj)) break; @@ -1635,7 +1642,7 @@ MergeSortByKey(K keys, size_t len, K scratch, C comparator, AutoValueVector *vec * necessary each inner iteration moves some number of unsorted elements * (including |i|) directly to sorted position. Thus on completion |*vec| * is sorted, and out-of-position elements have moved once. Complexity is - * Θ(len) + O(len) == O(2*len), with each element visited at most twice. + * ?(len) + O(len) == O(2*len), with each element visited at most twice. */ for (size_t i = 0; i < len; i++) { size_t j = keys[i].elementIndex; @@ -1912,18 +1919,20 @@ js::array_sort(JSContext *cx, unsigned argc, Value *vp) JS_ALWAYS_INLINE JSBool NewbornArrayPushImpl(JSContext *cx, HandleObject obj, const Value &v) { + Rooted arr(cx, &obj->as()); + JS_ASSERT(!v.isMagic()); - JS_ASSERT(obj->arrayLengthIsWritable()); + JS_ASSERT(arr->lengthIsWritable()); - uint32_t length = obj->getArrayLength(); - JS_ASSERT(length <= obj->getDenseCapacity()); + uint32_t length = arr->length(); + JS_ASSERT(length <= arr->getDenseCapacity()); - if (!obj->ensureElements(cx, length + 1)) + if (!arr->ensureElements(cx, length + 1)) return false; - obj->setDenseInitializedLength(length + 1); - obj->setArrayLengthInt32(length + 1); - JSObject::initDenseElementWithType(cx, obj, length, v); + arr->setDenseInitializedLength(length + 1); + arr->setLengthInt32(length + 1); + JSObject::initDenseElementWithType(cx, arr, length, v); return true; } @@ -1945,25 +1954,25 @@ js::array_push(JSContext *cx, unsigned argc, Value *vp) return false; /* Fast path for the fully-dense case. */ - if (obj->isArray() && - obj->arrayLengthIsWritable() && - !ObjectMayHaveExtraIndexedProperties(obj)) - { - uint32_t length = obj->getArrayLength(); - uint32_t argCount = args.length(); - JSObject::EnsureDenseResult result = obj->ensureDenseElements(cx, length, argCount); - if (result == JSObject::ED_FAILED) - return false; + if (obj->is()) { + Rooted arr(cx, &obj->as()); + if (arr->lengthIsWritable() && !ObjectMayHaveExtraIndexedProperties(arr)) { + uint32_t length = arr->length(); + uint32_t argCount = args.length(); + JSObject::EnsureDenseResult result = arr->ensureDenseElements(cx, length, argCount); + if (result == JSObject::ED_FAILED) + return false; - if (result == JSObject::ED_OK) { - obj->setArrayLengthInt32(length + argCount); - for (uint32_t i = 0, index = length; i < argCount; index++, i++) - JSObject::setDenseElementWithType(cx, obj, index, args[i]); - args.rval().setNumber(obj->getArrayLength()); - return true; + if (result == JSObject::ED_OK) { + arr->setLengthInt32(length + argCount); + for (uint32_t i = 0, index = length; i < argCount; index++, i++) + JSObject::setDenseElementWithType(cx, arr, index, args[i]); + args.rval().setNumber(arr->length()); + return true; + } + + MOZ_ASSERT(result == JSObject::ED_SPARSE); } - - MOZ_ASSERT(result == JSObject::ED_SPARSE); } /* Steps 2-3. */ @@ -2028,8 +2037,8 @@ js::array_pop(JSContext *cx, unsigned argc, Value *vp) void js::ArrayShiftMoveElements(JSObject *obj) { - JS_ASSERT(obj->isArray()); - JS_ASSERT(obj->arrayLengthIsWritable()); + JS_ASSERT(obj->is()); + JS_ASSERT(obj->as().lengthIsWritable()); /* * At this point the length and initialized length have already been @@ -2070,7 +2079,7 @@ js::array_shift(JSContext *cx, unsigned argc, Value *vp) uint32_t newlen = len - 1; /* Fast paths. */ - if (obj->isArray() && + if (obj->is() && obj->getDenseInitializedLength() > 0 && newlen < obj->getDenseCapacity() && !ObjectMayHaveExtraIndexedProperties(obj)) @@ -2135,11 +2144,11 @@ array_unshift(JSContext *cx, unsigned argc, Value *vp) if (length > 0) { bool optimized = false; do { - if (!obj->isArray()) + if (!obj->is()) break; if (ObjectMayHaveExtraIndexedProperties(obj)) break; - if (!obj->arrayLengthIsWritable()) + if (!obj->as().lengthIsWritable()) break; JSObject::EnsureDenseResult result = obj->ensureDenseElements(cx, length, args.length()); if (result != JSObject::ED_OK) { @@ -2191,18 +2200,17 @@ array_unshift(JSContext *cx, unsigned argc, Value *vp) } static inline void -TryReuseArrayType(JSObject *obj, JSObject *nobj) +TryReuseArrayType(JSObject *obj, ArrayObject *narr) { /* - * Try to change the type of a newly created array nobj to the same type + * Try to change the type of a newly created array narr to the same type * as obj. This can only be performed if the original object is an array * and has the same prototype. */ - JS_ASSERT(nobj->isArray()); - JS_ASSERT(nobj->getProto()->hasNewType(&ArrayClass, nobj->type())); + JS_ASSERT(narr->getProto()->hasNewType(&ArrayObject::class_, narr->type())); - if (obj->isArray() && !obj->hasSingletonType() && obj->getProto() == nobj->getProto()) - nobj->setType(obj->type()); + if (obj->is() && !obj->hasSingletonType() && obj->getProto() == narr->getProto()) + narr->setType(obj->type()); } /* @@ -2220,7 +2228,7 @@ CanOptimizeForDenseStorage(HandleObject arr, uint32_t startingIndex, uint32_t co return false; /* There's no optimizing possible if it's not an array. */ - if (!arr->isArray()) + if (!arr->is()) return false; /* @@ -2295,7 +2303,7 @@ array_splice(JSContext *cx, unsigned argc, Value *vp) JS_ASSERT(len - actualStart >= actualDeleteCount); /* Steps 2, 8-9. */ - RootedObject arr(cx); + Rooted arr(cx); if (CanOptimizeForDenseStorage(obj, actualStart, actualDeleteCount, cx)) { arr = NewDenseCopiedArray(cx, actualDeleteCount, obj, actualStart); if (!arr) @@ -2404,11 +2412,14 @@ array_splice(JSContext *cx, unsigned argc, Value *vp) * path may validly *not* throw -- if all the elements being moved are * holes.) */ - if (obj->isArray() && obj->arrayLengthIsWritable()) { - JSObject::EnsureDenseResult res = - obj->ensureDenseElements(cx, len, itemCount - actualDeleteCount); - if (res == JSObject::ED_FAILED) - return false; + if (obj->is()) { + Rooted arr(cx, &obj->as()); + if (arr->lengthIsWritable()) { + JSObject::EnsureDenseResult res = + arr->ensureDenseElements(cx, arr->length(), itemCount - actualDeleteCount); + if (res == JSObject::ED_FAILED) + return false; + } } if (CanOptimizeForDenseStorage(obj, len, itemCount - actualDeleteCount, cx)) { @@ -2463,15 +2474,14 @@ array_splice(JSContext *cx, unsigned argc, Value *vp) #ifdef JS_ION bool -js::array_concat_dense(JSContext *cx, HandleObject obj1, HandleObject obj2, HandleObject result) +js::array_concat_dense(JSContext *cx, Handle arr1, Handle arr2, + Handle result) { - JS_ASSERT(result->isArray() && obj1->isArray() && obj2->isArray()); + uint32_t initlen1 = arr1->getDenseInitializedLength(); + JS_ASSERT(initlen1 == arr1->length()); - uint32_t initlen1 = obj1->getDenseInitializedLength(); - JS_ASSERT(initlen1 == obj1->getArrayLength()); - - uint32_t initlen2 = obj2->getDenseInitializedLength(); - JS_ASSERT(initlen2 == obj2->getArrayLength()); + uint32_t initlen2 = arr2->getDenseInitializedLength(); + JS_ASSERT(initlen2 == arr2->length()); /* No overflow here due to nelements limit. */ uint32_t len = initlen1 + initlen2; @@ -2482,9 +2492,9 @@ js::array_concat_dense(JSContext *cx, HandleObject obj1, HandleObject obj2, Hand JS_ASSERT(!result->getDenseInitializedLength()); result->setDenseInitializedLength(len); - result->initDenseElements(0, obj1->getDenseElements(), initlen1); - result->initDenseElements(initlen1, obj2->getDenseElements(), initlen2); - result->setArrayLengthInt32(len); + result->initDenseElements(0, arr1->getDenseElements(), initlen1); + result->initDenseElements(initlen1, arr2->getDenseElements(), initlen2); + result->setLengthInt32(len); return true; } #endif /* JS_ION */ @@ -2514,8 +2524,8 @@ js::array_concat(JSContext *cx, unsigned argc, Value *vp) * Step 5. This may also inline the first iteration of Step 6 if it is * possible to perform a fast, dense copy. */ - RootedObject arr(cx); - if (obj->isArray() && !obj->isIndexed()) { + Rooted arr(cx); + if (obj->is() && !obj->isIndexed()) { uint32_t initlen = obj->getDenseInitializedLength(); arr = NewDenseCopiedArray(cx, initlen, obj, 0); if (!arr) @@ -2622,23 +2632,23 @@ array_slice(JSContext *cx, unsigned argc, Value *vp) if (begin > end) begin = end; - RootedObject nobj(cx); + Rooted narr(cx); - if (obj->isArray() && end <= obj->getDenseInitializedLength() && + if (obj->is() && end <= obj->getDenseInitializedLength() && !ObjectMayHaveExtraIndexedProperties(obj)) { - nobj = NewDenseCopiedArray(cx, end - begin, obj, begin); - if (!nobj) + narr = NewDenseCopiedArray(cx, end - begin, obj, begin); + if (!narr) return false; - TryReuseArrayType(obj, nobj); - args.rval().setObject(*nobj); + TryReuseArrayType(obj, narr); + args.rval().setObject(*narr); return true; } - nobj = NewDenseAllocatedArray(cx, end - begin); - if (!nobj) + narr = NewDenseAllocatedArray(cx, end - begin); + if (!narr) return false; - TryReuseArrayType(obj, nobj); + TryReuseArrayType(obj, narr); RootedValue value(cx); for (slot = begin; slot < end; slot++) { @@ -2646,11 +2656,11 @@ array_slice(JSContext *cx, unsigned argc, Value *vp) !GetElement(cx, obj, slot, &hole, &value)) { return false; } - if (!hole && !SetArrayElement(cx, nobj, slot - begin, value)) + if (!hole && !SetArrayElement(cx, narr, slot - begin, value)) return false; } - args.rval().setObject(*nobj); + args.rval().setObject(*narr); return true; } @@ -2916,13 +2926,15 @@ js_Array(JSContext *cx, unsigned argc, Value *vp) if (!obj) return false; - obj->setType(type); + Rooted arr(cx, &obj->as()); + + arr->setType(type); /* If the length calculation overflowed, make sure that is marked for the new type. */ - if (obj->getArrayLength() > INT32_MAX) - JSObject::setArrayLength(cx, obj, obj->getArrayLength()); + if (arr->length() > INT32_MAX) + ArrayObject::setLength(cx, arr, arr->length()); - args.rval().setObject(*obj); + args.rval().setObject(*arr); return true; } @@ -2937,7 +2949,7 @@ js_InitArrayClass(JSContext *cx, HandleObject obj) if (!proto) return NULL; - RootedTypeObject type(cx, proto->getNewType(cx, &ArrayClass)); + RootedTypeObject type(cx, proto->getNewType(cx, &ArrayObject::class_)); if (!type) return NULL; @@ -2945,7 +2957,7 @@ js_InitArrayClass(JSContext *cx, HandleObject obj) if (!NewObjectMetadata(cx, &metadata)) return NULL; - RootedShape shape(cx, EmptyShape::getInitialShape(cx, &ArrayClass, TaggedProto(proto), + RootedShape shape(cx, EmptyShape::getInitialShape(cx, &ArrayObject::class_, TaggedProto(proto), proto->getParent(), metadata, gc::FINALIZE_OBJECT0)); @@ -2964,7 +2976,7 @@ js_InitArrayClass(JSContext *cx, HandleObject obj) * arrays in JSON and script literals and allows setDenseArrayElement to * be used without updating the indexed type set for such default arrays. */ - if (!JSObject::setNewTypeUnknown(cx, &ArrayClass, arrayProto)) + if (!JSObject::setNewTypeUnknown(cx, &ArrayObject::class_, arrayProto)) return NULL; if (!LinkConstructorAndPrototype(cx, ctor, arrayProto)) @@ -3004,11 +3016,11 @@ EnsureNewArrayElements(JSContext *cx, JSObject *obj, uint32_t length) } template -static JS_ALWAYS_INLINE JSObject * +static JS_ALWAYS_INLINE ArrayObject * NewArray(JSContext *cx, uint32_t length, JSObject *protoArg, NewObjectKind newKind = GenericObject) { gc::AllocKind allocKind = GuessArrayGCKind(length); - JS_ASSERT(CanBeFinalizedInBackground(allocKind, &ArrayClass)); + JS_ASSERT(CanBeFinalizedInBackground(allocKind, &ArrayObject::class_)); allocKind = GetBackgroundAllocKind(allocKind); NewObjectCache &cache = cx->runtime()->newObjectCache; @@ -3016,16 +3028,18 @@ NewArray(JSContext *cx, uint32_t length, JSObject *protoArg, NewObjectKind newKi NewObjectCache::EntryIndex entry = -1; if (newKind == GenericObject && !cx->compartment()->objectMetadataCallback && - cache.lookupGlobal(&ArrayClass, cx->global(), allocKind, &entry)) + cache.lookupGlobal(&ArrayObject::class_, cx->global(), allocKind, &entry)) { - RootedObject obj(cx, cache.newObjectFromHit(cx, entry, GetInitialHeap(newKind, &ArrayClass))); + RootedObject obj(cx, cache.newObjectFromHit(cx, entry, + GetInitialHeap(newKind, &ArrayObject::class_))); if (obj) { /* Fixup the elements pointer and length, which may be incorrect. */ - obj->setFixedElements(); - JSObject::setArrayLength(cx, obj, length); - if (allocateCapacity && !EnsureNewArrayElements(cx, obj, length)) + Rooted arr(cx, &obj->as()); + arr->setFixedElements(); + ArrayObject::setLength(cx, arr, length); + if (allocateCapacity && !EnsureNewArrayElements(cx, arr, length)) return NULL; - return obj; + return arr; } } @@ -3033,10 +3047,10 @@ NewArray(JSContext *cx, uint32_t length, JSObject *protoArg, NewObjectKind newKi if (protoArg) JS::PoisonPtr(&protoArg); - if (!proto && !FindProto(cx, &ArrayClass, &proto)) + if (!proto && !FindProto(cx, &ArrayObject::class_, &proto)) return NULL; - RootedTypeObject type(cx, proto->getNewType(cx, &ArrayClass)); + RootedTypeObject type(cx, proto->getNewType(cx, &ArrayObject::class_)); if (!type) return NULL; @@ -3048,95 +3062,98 @@ NewArray(JSContext *cx, uint32_t length, JSObject *protoArg, NewObjectKind newKi * Get a shape with zero fixed slots, regardless of the size class. * See JSObject::createArray. */ - RootedShape shape(cx, EmptyShape::getInitialShape(cx, &ArrayClass, TaggedProto(proto), + RootedShape shape(cx, EmptyShape::getInitialShape(cx, &ArrayObject::class_, TaggedProto(proto), cx->global(), metadata, gc::FINALIZE_OBJECT0)); if (!shape) return NULL; - RootedObject obj(cx, JSObject::createArray(cx, allocKind, GetInitialHeap(newKind, &ArrayClass), + RootedObject obj(cx, JSObject::createArray(cx, allocKind, + GetInitialHeap(newKind, &ArrayObject::class_), shape, type, length)); if (!obj) return NULL; + Rooted arr(cx, &obj->as()); + if (shape->isEmptyShape()) { - if (!AddLengthProperty(cx, obj)) + if (!AddLengthProperty(cx, arr)) return NULL; - shape = obj->lastProperty(); + shape = arr->lastProperty(); EmptyShape::insertInitialShape(cx, shape, proto); } - if (newKind == SingletonObject && !JSObject::setSingletonType(cx, obj)) + if (newKind == SingletonObject && !JSObject::setSingletonType(cx, arr)) return NULL; if (entry != -1) - cache.fillGlobal(entry, &ArrayClass, cx->global(), allocKind, obj); + cache.fillGlobal(entry, &ArrayObject::class_, cx->global(), allocKind, arr); - if (allocateCapacity && !EnsureNewArrayElements(cx, obj, length)) + if (allocateCapacity && !EnsureNewArrayElements(cx, arr, length)) return NULL; - Probes::createObject(cx, obj); - return obj; + Probes::createObject(cx, arr); + return arr; } -JSObject * JS_FASTCALL +ArrayObject * JS_FASTCALL js::NewDenseEmptyArray(JSContext *cx, JSObject *proto /* = NULL */, NewObjectKind newKind /* = GenericObject */) { return NewArray(cx, 0, proto, newKind); } -JSObject * JS_FASTCALL +ArrayObject * JS_FASTCALL js::NewDenseAllocatedArray(JSContext *cx, uint32_t length, JSObject *proto /* = NULL */, NewObjectKind newKind /* = GenericObject */) { return NewArray(cx, length, proto, newKind); } -JSObject * JS_FASTCALL +ArrayObject * JS_FASTCALL js::NewDenseUnallocatedArray(JSContext *cx, uint32_t length, JSObject *proto /* = NULL */, NewObjectKind newKind /* = GenericObject */) { return NewArray(cx, length, proto, newKind); } -JSObject * +ArrayObject * js::NewDenseCopiedArray(JSContext *cx, uint32_t length, HandleObject src, uint32_t elementOffset, JSObject *proto /* = NULL */) { JS_ASSERT(!src->isIndexed()); - JSObject* obj = NewArray(cx, length, proto); - if (!obj) + ArrayObject* arr = NewArray(cx, length, proto); + if (!arr) return NULL; - JS_ASSERT(obj->getDenseCapacity() >= length); + JS_ASSERT(arr->getDenseCapacity() >= length); const Value* vp = src->getDenseElements() + elementOffset; - obj->setDenseInitializedLength(vp ? length : 0); + arr->setDenseInitializedLength(vp ? length : 0); if (vp) - obj->initDenseElements(0, vp, length); + arr->initDenseElements(0, vp, length); - return obj; + return arr; } // values must point at already-rooted Value objects -JSObject * +ArrayObject * js::NewDenseCopiedArray(JSContext *cx, uint32_t length, const Value *values, JSObject *proto /* = NULL */, NewObjectKind newKind /* = GenericObject */) { - JSObject* obj = NewArray(cx, length, proto); - if (!obj) + ArrayObject* arr = NewArray(cx, length, proto); + if (!arr) return NULL; - JS_ASSERT(obj->getDenseCapacity() >= length); + JS_ASSERT(arr->getDenseCapacity() >= length); - obj->setDenseInitializedLength(values ? length : 0); + arr->setDenseInitializedLength(values ? length : 0); if (values) - obj->initDenseElements(0, values, length); + arr->initDenseElements(0, values, length); - return obj; + return arr; } #ifdef DEBUG @@ -3144,7 +3161,7 @@ JSBool js_ArrayInfo(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - JSObject *array; + JSObject *obj; for (unsigned i = 0; i < args.length(); i++) { RootedValue arg(cx, args[i]); @@ -3153,13 +3170,13 @@ js_ArrayInfo(JSContext *cx, unsigned argc, Value *vp) if (!bytes) return false; if (arg.isPrimitive() || - !(array = arg.toObjectOrNull())->isArray()) { + !(obj = arg.toObjectOrNull())->is()) { fprintf(stderr, "%s: not array\n", bytes); js_free(bytes); continue; } - fprintf(stderr, "%s: (len %u", bytes, array->getArrayLength()); - fprintf(stderr, ", capacity %u", array->getDenseCapacity()); + fprintf(stderr, "%s: (len %u", bytes, obj->as().length()); + fprintf(stderr, ", capacity %u", obj->getDenseCapacity()); fputs(")\n", stderr); js_free(bytes); } diff --git a/js/src/jsarray.h b/js/src/jsarray.h index 535702784..44e35ce26 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -41,13 +41,15 @@ js_InitContextBusyArrayTable(JSContext *cx); namespace js { +class ArrayObject; + /* Create a dense array with no capacity allocated, length set to 0. */ -extern JSObject * JS_FASTCALL +extern ArrayObject * JS_FASTCALL NewDenseEmptyArray(JSContext *cx, JSObject *proto = NULL, NewObjectKind newKind = GenericObject); /* Create a dense array with length and capacity == 'length', initialized length set to 0. */ -extern JSObject * JS_FASTCALL +extern ArrayObject * JS_FASTCALL NewDenseAllocatedArray(JSContext *cx, uint32_t length, JSObject *proto = NULL, NewObjectKind newKind = GenericObject); @@ -55,16 +57,16 @@ NewDenseAllocatedArray(JSContext *cx, uint32_t length, JSObject *proto = NULL, * Create a dense array with a set length, but without allocating space for the * contents. This is useful, e.g., when accepting length from the user. */ -extern JSObject * JS_FASTCALL +extern ArrayObject * JS_FASTCALL NewDenseUnallocatedArray(JSContext *cx, uint32_t length, JSObject *proto = NULL, NewObjectKind newKind = GenericObject); /* Create a dense array with a copy of the dense array elements in src. */ -extern JSObject * +extern ArrayObject * NewDenseCopiedArray(JSContext *cx, uint32_t length, HandleObject src, uint32_t elementOffset, JSObject *proto = NULL); /* Create a dense array from the given array values, which must be rooted */ -extern JSObject * +extern ArrayObject * NewDenseCopiedArray(JSContext *cx, uint32_t length, const Value *values, JSObject *proto = NULL, NewObjectKind newKind = GenericObject); @@ -117,7 +119,8 @@ extern JSBool array_concat(JSContext *cx, unsigned argc, js::Value *vp); extern bool -array_concat_dense(JSContext *cx, HandleObject obj1, HandleObject obj2, HandleObject result); +array_concat_dense(JSContext *cx, Handle arr1, Handle arr2, + Handle result); extern void ArrayShiftMoveElements(JSObject *obj); diff --git a/js/src/jsatom.cpp b/js/src/jsatom.cpp index 9298c8e11..a27512cb2 100644 --- a/js/src/jsatom.cpp +++ b/js/src/jsatom.cpp @@ -7,7 +7,7 @@ /* * JS atom table. */ -#include "jsatom.h" +#include "jsatominlines.h" #include "mozilla/RangedPtr.h" #include "mozilla/Util.h" @@ -22,9 +22,11 @@ #include "gc/Marking.h" #include "vm/Xdr.h" -#include "jsatominlines.h" #include "jscompartmentinlines.h" +#ifdef JSGC_GENERATIONAL +#include "vm/Shape-inl.h" +#endif #include "vm/String-inl.h" using namespace js; diff --git a/js/src/jsclass.h b/js/src/jsclass.h index 12a64197b..3265b485f 100644 --- a/js/src/jsclass.h +++ b/js/src/jsclass.h @@ -21,6 +21,10 @@ class PropertyName; class SpecialId; class PropertyId; +// This is equal to JSFunction::class_. Use it in places where you don't want +// to #include jsfun.h. +extern JS_FRIEND_DATA(js::Class*) FunctionClassPtr; + static JS_ALWAYS_INLINE jsid SPECIALID_TO_JSID(const SpecialId &sid); @@ -312,8 +316,9 @@ struct Class return flags & JSCLASS_EMULATES_UNDEFINED; } - /* Defined in jsfuninlines.h */ - inline bool isCallable() const; + bool isCallable() const { + return this == js::FunctionClassPtr || call; + } static size_t offsetOfFlags() { return offsetof(Class, flags); } }; diff --git a/js/src/jsclone.cpp b/js/src/jsclone.cpp index 8df21bf9e..493e51e6c 100644 --- a/js/src/jsclone.cpp +++ b/js/src/jsclone.cpp @@ -641,7 +641,7 @@ JSStructuredCloneWriter::traverseObject(HandleObject obj) checkStack(); /* Write the header for obj. */ - return out.writePair(obj->isArray() ? SCTAG_ARRAY_OBJECT : SCTAG_OBJECT_OBJECT, 0); + return out.writePair(obj->is() ? SCTAG_ARRAY_OBJECT : SCTAG_OBJECT_OBJECT, 0); } bool @@ -682,14 +682,14 @@ JSStructuredCloneWriter::startWrite(const Value &v) RegExpObject &reobj = obj->as(); return out.writePair(SCTAG_REGEXP_OBJECT, reobj.getFlags()) && writeString(SCTAG_STRING, reobj.getSource()); - } else if (obj->isDate()) { + } else if (obj->is()) { double d = js_DateGetMsecSinceEpoch(obj); return out.writePair(SCTAG_DATE_OBJECT, 0) && out.writeDouble(d); } else if (obj->isTypedArray()) { return writeTypedArray(obj); } else if (obj->is() && obj->as().hasData()) { return writeArrayBuffer(obj); - } else if (obj->isObject() || obj->isArray()) { + } else if (obj->isObject() || obj->is()) { return traverseObject(obj); } else if (obj->is()) { return out.writePair(SCTAG_BOOLEAN_OBJECT, obj->as().unbox()); diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index c4c8354a9..33354e903 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -1205,7 +1205,7 @@ JSContext::JSContext(JSRuntime *rt) JS_ASSERT(static_cast(this) == ContextFriendFields::get(this)); -#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING) +#ifdef JSGC_TRACK_EXACT_ROOTS PodArrayZero(thingGCRooters); #endif #if defined(DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE) diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp index 793abc64b..29aa5aef2 100644 --- a/js/src/jsdate.cpp +++ b/js/src/jsdate.cpp @@ -516,7 +516,7 @@ static JSBool date_convert(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp) { JS_ASSERT(hint == JSTYPE_NUMBER || hint == JSTYPE_STRING || hint == JSTYPE_VOID); - JS_ASSERT(obj->isDate()); + JS_ASSERT(obj->is()); return DefaultValue(cx, obj, (hint == JSTYPE_VOID) ? JSTYPE_STRING : hint, vp); } @@ -525,9 +525,9 @@ date_convert(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp * Other Support routines and definitions */ -Class js::DateClass = { +Class DateObject::class_ = { js_Date_str, - JSCLASS_HAS_RESERVED_SLOTS(JSObject::DATE_CLASS_RESERVED_SLOTS) | + JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_Date), JS_PropertyStub, /* addProperty */ JS_DeletePropertyStub, /* delProperty */ @@ -1238,59 +1238,41 @@ date_now(JSContext *cx, unsigned argc, Value *vp) return JS_TRUE; } -/* - * Set UTC time to a given time and invalidate cached local time. - */ -static void -SetUTCTime(JSObject *obj, double t, Value *vp = NULL) +void +DateObject::setUTCTime(double t, Value *vp) { - JS_ASSERT(obj->isDate()); + for (size_t ind = COMPONENTS_START_SLOT; ind < RESERVED_SLOTS; ind++) + setReservedSlot(ind, UndefinedValue()); - for (size_t ind = JSObject::JSSLOT_DATE_COMPONENTS_START; - ind < JSObject::DATE_CLASS_RESERVED_SLOTS; - ind++) { - obj->setSlot(ind, UndefinedValue()); - } - - obj->setDateUTCTime(DoubleValue(t)); + setFixedSlot(UTC_TIME_SLOT, DoubleValue(t)); if (vp) vp->setDouble(t); } -/* - * Cache the local time, year, month, and so forth of the object. - * If UTC time is not finite (e.g., NaN), the local time - * slots will be set to the UTC time without conversion. - */ -static void -FillLocalTimeSlots(DateTimeInfo *dtInfo, JSObject *obj) +void +DateObject::fillLocalTimeSlots(DateTimeInfo *dtInfo) { - JS_ASSERT(obj->isDate()); - /* Check if the cache is already populated. */ - if (!obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_TIME).isUndefined() && - obj->getSlot(JSObject::JSSLOT_DATE_TZA).toDouble() == dtInfo->localTZA()) + if (!getReservedSlot(LOCAL_TIME_SLOT).isUndefined() && + getReservedSlot(TZA_SLOT).toDouble() == dtInfo->localTZA()) { return; } /* Remember timezone used to generate the local cache. */ - obj->setSlot(JSObject::JSSLOT_DATE_TZA, DoubleValue(dtInfo->localTZA())); + setReservedSlot(TZA_SLOT, DoubleValue(dtInfo->localTZA())); - double utcTime = obj->getDateUTCTime().toNumber(); + double utcTime = UTCTime().toNumber(); if (!IsFinite(utcTime)) { - for (size_t ind = JSObject::JSSLOT_DATE_COMPONENTS_START; - ind < JSObject::DATE_CLASS_RESERVED_SLOTS; - ind++) { - obj->setSlot(ind, DoubleValue(utcTime)); - } + for (size_t ind = COMPONENTS_START_SLOT; ind < RESERVED_SLOTS; ind++) + setReservedSlot(ind, DoubleValue(utcTime)); return; } double localTime = LocalTime(utcTime, dtInfo); - obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_TIME, DoubleValue(localTime)); + setReservedSlot(LOCAL_TIME_SLOT, DoubleValue(localTime)); int year = (int) floor(localTime /(msPerDay * 365.2425)) + 1970; double yearStartTime = TimeFromYear(year); @@ -1311,7 +1293,7 @@ FillLocalTimeSlots(DateTimeInfo *dtInfo, JSObject *obj) } } - obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR, Int32Value(year)); + setReservedSlot(LOCAL_YEAR_SLOT, Int32Value(year)); uint64_t yearTime = uint64_t(localTime - yearStartTime); int yearSeconds = uint32_t(yearTime / 1000); @@ -1381,44 +1363,42 @@ FillLocalTimeSlots(DateTimeInfo *dtInfo, JSObject *obj) month = 11; } while (0); - obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_MONTH, Int32Value(month)); - obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_DATE, Int32Value(day - step)); + setReservedSlot(LOCAL_MONTH_SLOT, Int32Value(month)); + setReservedSlot(LOCAL_DATE_SLOT, Int32Value(day - step)); int weekday = WeekDay(localTime); - obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_DAY, Int32Value(weekday)); + setReservedSlot(LOCAL_DAY_SLOT, Int32Value(weekday)); int seconds = yearSeconds % 60; - obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_SECONDS, Int32Value(seconds)); + setReservedSlot(LOCAL_SECONDS_SLOT, Int32Value(seconds)); int minutes = (yearSeconds / 60) % 60; - obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_MINUTES, Int32Value(minutes)); + setReservedSlot(LOCAL_MINUTES_SLOT, Int32Value(minutes)); int hours = (yearSeconds / (60 * 60)) % 24; - obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS, Int32Value(hours)); + setReservedSlot(LOCAL_HOURS_SLOT, Int32Value(hours)); } inline double -GetCachedLocalTime(DateTimeInfo *dtInfo, JSObject *obj) +DateObject::cachedLocalTime(DateTimeInfo *dtInfo) { - JS_ASSERT(obj); - FillLocalTimeSlots(dtInfo, obj); - return obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_TIME).toDouble(); + fillLocalTimeSlots(dtInfo); + return getReservedSlot(LOCAL_TIME_SLOT).toDouble(); } JS_ALWAYS_INLINE bool IsDate(const Value &v) { - return v.isObject() && v.toObject().hasClass(&DateClass); + return v.isObject() && v.toObject().is(); } /* * See ECMA 15.9.5.4 thru 15.9.5.23 */ -JS_ALWAYS_INLINE bool -date_getTime_impl(JSContext *cx, CallArgs args) +/* static */ JS_ALWAYS_INLINE bool +DateObject::getTime_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - args.rval().set(args.thisv().toObject().getDateUTCTime()); + args.rval().set(args.thisv().toObject().as().UTCTime()); return true; } @@ -1426,18 +1406,16 @@ static JSBool date_getTime(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); + return CallNonGenericMethod(cx, args); } -JS_ALWAYS_INLINE bool -date_getYear_impl(JSContext *cx, CallArgs args) +/* static */ JS_ALWAYS_INLINE bool +DateObject::getYear_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); + DateObject *dateObj = &args.thisv().toObject().as(); + dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo); - JSObject *thisObj = &args.thisv().toObject(); - FillLocalTimeSlots(&cx->runtime()->dateTimeInfo, thisObj); - - Value yearVal = thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR); + Value yearVal = dateObj->getReservedSlot(LOCAL_YEAR_SLOT); if (yearVal.isInt32()) { /* Follow ECMA-262 to the letter, contrary to IE JScript. */ int year = yearVal.toInt32() - 1900; @@ -1453,18 +1431,16 @@ static JSBool date_getYear(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); + return CallNonGenericMethod(cx, args); } -JS_ALWAYS_INLINE bool -date_getFullYear_impl(JSContext *cx, CallArgs args) +/* static */ JS_ALWAYS_INLINE bool +DateObject::getFullYear_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); + DateObject *dateObj = &args.thisv().toObject().as(); + dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo); - JSObject *thisObj = &args.thisv().toObject(); - FillLocalTimeSlots(&cx->runtime()->dateTimeInfo, thisObj); - - args.rval().set(thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR)); + args.rval().set(dateObj->getReservedSlot(LOCAL_YEAR_SLOT)); return true; } @@ -1472,15 +1448,13 @@ static JSBool date_getFullYear(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); + return CallNonGenericMethod(cx, args); } -JS_ALWAYS_INLINE bool -date_getUTCFullYear_impl(JSContext *cx, CallArgs args) +/* static */ JS_ALWAYS_INLINE bool +DateObject::getUTCFullYear_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - double result = args.thisv().toObject().getDateUTCTime().toNumber(); + double result = args.thisv().toObject().as().UTCTime().toNumber(); if (IsFinite(result)) result = YearFromTime(result); @@ -1492,18 +1466,16 @@ static JSBool date_getUTCFullYear(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); + return CallNonGenericMethod(cx, args); } -JS_ALWAYS_INLINE bool -date_getMonth_impl(JSContext *cx, CallArgs args) +/* static */ JS_ALWAYS_INLINE bool +DateObject::getMonth_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); + DateObject *dateObj = &args.thisv().toObject().as(); + dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo); - JSObject *thisObj = &args.thisv().toObject(); - FillLocalTimeSlots(&cx->runtime()->dateTimeInfo, thisObj); - - args.rval().set(thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MONTH)); + args.rval().set(dateObj->getReservedSlot(LOCAL_MONTH_SLOT)); return true; } @@ -1511,15 +1483,13 @@ static JSBool date_getMonth(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); + return CallNonGenericMethod(cx, args); } -JS_ALWAYS_INLINE bool -date_getUTCMonth_impl(JSContext *cx, CallArgs args) +/* static */ JS_ALWAYS_INLINE bool +DateObject::getUTCMonth_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - double d = args.thisv().toObject().getDateUTCTime().toNumber(); + double d = args.thisv().toObject().as().UTCTime().toNumber(); args.rval().setNumber(MonthFromTime(d)); return true; } @@ -1528,18 +1498,16 @@ static JSBool date_getUTCMonth(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); + return CallNonGenericMethod(cx, args); } -JS_ALWAYS_INLINE bool -date_getDate_impl(JSContext *cx, CallArgs args) +/* static */ JS_ALWAYS_INLINE bool +DateObject::getDate_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); + DateObject *dateObj = &args.thisv().toObject().as(); + dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo); - JSObject *thisObj = &args.thisv().toObject(); - FillLocalTimeSlots(&cx->runtime()->dateTimeInfo, thisObj); - - args.rval().set(thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DATE)); + args.rval().set(dateObj->getReservedSlot(LOCAL_DATE_SLOT)); return true; } @@ -1547,15 +1515,13 @@ static JSBool date_getDate(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); + return CallNonGenericMethod(cx, args); } -JS_ALWAYS_INLINE bool -date_getUTCDate_impl(JSContext *cx, CallArgs args) +/* static */ JS_ALWAYS_INLINE bool +DateObject::getUTCDate_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - double result = args.thisv().toObject().getDateUTCTime().toNumber(); + double result = args.thisv().toObject().as().UTCTime().toNumber(); if (IsFinite(result)) result = DateFromTime(result); @@ -1567,18 +1533,16 @@ static JSBool date_getUTCDate(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); + return CallNonGenericMethod(cx, args); } -JS_ALWAYS_INLINE bool -date_getDay_impl(JSContext *cx, CallArgs args) +/* static */ JS_ALWAYS_INLINE bool +DateObject::getDay_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); + DateObject *dateObj = &args.thisv().toObject().as(); + dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo); - JSObject *thisObj = &args.thisv().toObject(); - FillLocalTimeSlots(&cx->runtime()->dateTimeInfo, thisObj); - - args.rval().set(thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DAY)); + args.rval().set(dateObj->getReservedSlot(LOCAL_DAY_SLOT)); return true; } @@ -1586,15 +1550,13 @@ static JSBool date_getDay(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); + return CallNonGenericMethod(cx, args); } -JS_ALWAYS_INLINE bool -date_getUTCDay_impl(JSContext *cx, CallArgs args) +/* static */ JS_ALWAYS_INLINE bool +DateObject::getUTCDay_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - double result = args.thisv().toObject().getDateUTCTime().toNumber(); + double result = args.thisv().toObject().as().UTCTime().toNumber(); if (IsFinite(result)) result = WeekDay(result); @@ -1606,18 +1568,16 @@ static JSBool date_getUTCDay(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); + return CallNonGenericMethod(cx, args); } -JS_ALWAYS_INLINE bool -date_getHours_impl(JSContext *cx, CallArgs args) +/* static */ JS_ALWAYS_INLINE bool +DateObject::getHours_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); + DateObject *dateObj = &args.thisv().toObject().as(); + dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo); - JSObject *thisObj = &args.thisv().toObject(); - FillLocalTimeSlots(&cx->runtime()->dateTimeInfo, thisObj); - - args.rval().set(thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS)); + args.rval().set(dateObj->getReservedSlot(LOCAL_HOURS_SLOT)); return true; } @@ -1625,15 +1585,13 @@ static JSBool date_getHours(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); + return CallNonGenericMethod(cx, args); } -JS_ALWAYS_INLINE bool -date_getUTCHours_impl(JSContext *cx, CallArgs args) +/* static */ JS_ALWAYS_INLINE bool +DateObject::getUTCHours_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - double result = args.thisv().toObject().getDateUTCTime().toNumber(); + double result = args.thisv().toObject().as().UTCTime().toNumber(); if (IsFinite(result)) result = HourFromTime(result); @@ -1645,18 +1603,16 @@ static JSBool date_getUTCHours(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); + return CallNonGenericMethod(cx, args); } -JS_ALWAYS_INLINE bool -date_getMinutes_impl(JSContext *cx, CallArgs args) +/* static */ JS_ALWAYS_INLINE bool +DateObject::getMinutes_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); + DateObject *dateObj = &args.thisv().toObject().as(); + dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo); - JSObject *thisObj = &args.thisv().toObject(); - FillLocalTimeSlots(&cx->runtime()->dateTimeInfo, thisObj); - - args.rval().set(thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MINUTES)); + args.rval().set(dateObj->getReservedSlot(LOCAL_MINUTES_SLOT)); return true; } @@ -1664,15 +1620,13 @@ static JSBool date_getMinutes(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); + return CallNonGenericMethod(cx, args); } -JS_ALWAYS_INLINE bool -date_getUTCMinutes_impl(JSContext *cx, CallArgs args) +/* static */ JS_ALWAYS_INLINE bool +DateObject::getUTCMinutes_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - double result = args.thisv().toObject().getDateUTCTime().toNumber(); + double result = args.thisv().toObject().as().UTCTime().toNumber(); if (IsFinite(result)) result = MinFromTime(result); @@ -1684,20 +1638,18 @@ static JSBool date_getUTCMinutes(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); + return CallNonGenericMethod(cx, args); } /* Date.getSeconds is mapped to getUTCSeconds */ -JS_ALWAYS_INLINE bool -date_getUTCSeconds_impl(JSContext *cx, CallArgs args) +/* static */ JS_ALWAYS_INLINE bool +DateObject::getUTCSeconds_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); + DateObject *dateObj = &args.thisv().toObject().as(); + dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo); - JSObject *thisObj = &args.thisv().toObject(); - FillLocalTimeSlots(&cx->runtime()->dateTimeInfo, thisObj); - - args.rval().set(thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_SECONDS)); + args.rval().set(dateObj->getReservedSlot(LOCAL_SECONDS_SLOT)); return true; } @@ -1705,17 +1657,15 @@ static JSBool date_getUTCSeconds(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); + return CallNonGenericMethod(cx, args); } /* Date.getMilliseconds is mapped to getUTCMilliseconds */ -JS_ALWAYS_INLINE bool -date_getUTCMilliseconds_impl(JSContext *cx, CallArgs args) +/* static */ JS_ALWAYS_INLINE bool +DateObject::getUTCMilliseconds_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - double result = args.thisv().toObject().getDateUTCTime().toNumber(); + double result = args.thisv().toObject().as().UTCTime().toNumber(); if (IsFinite(result)) result = msFromTime(result); @@ -1727,17 +1677,15 @@ static JSBool date_getUTCMilliseconds(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); + return CallNonGenericMethod(cx, args); } -JS_ALWAYS_INLINE bool -date_getTimezoneOffset_impl(JSContext *cx, CallArgs args) +/* static */ JS_ALWAYS_INLINE bool +DateObject::getTimezoneOffset_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - JSObject *thisObj = &args.thisv().toObject(); - double utctime = thisObj->getDateUTCTime().toNumber(); - double localtime = GetCachedLocalTime(&cx->runtime()->dateTimeInfo, thisObj); + DateObject *dateObj = &args.thisv().toObject().as(); + double utctime = dateObj->UTCTime().toNumber(); + double localtime = dateObj->cachedLocalTime(&cx->runtime()->dateTimeInfo); /* * Return the time zone offset in minutes for the current locale that is @@ -1753,17 +1701,15 @@ static JSBool date_getTimezoneOffset(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); + return CallNonGenericMethod(cx, args); } JS_ALWAYS_INLINE bool date_setTime_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - RootedObject thisObj(cx, &args.thisv().toObject()); + Rooted dateObj(cx, &args.thisv().toObject().as()); if (args.length() == 0) { - SetUTCTime(thisObj, js_NaN, args.rval().address()); + dateObj->setUTCTime(js_NaN, args.rval().address()); return true; } @@ -1771,7 +1717,7 @@ date_setTime_impl(JSContext *cx, CallArgs args) if (!ToNumber(cx, args[0], &result)) return false; - SetUTCTime(thisObj, TimeClip(result), args.rval().address()); + dateObj->setUTCTime(TimeClip(result), args.rval().address()); return true; } @@ -1816,12 +1762,10 @@ GetMinsOrDefault(JSContext *cx, const CallArgs &args, unsigned i, double t, doub JS_ALWAYS_INLINE bool date_setMilliseconds_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - RootedObject thisObj(cx, &args.thisv().toObject()); + Rooted dateObj(cx, &args.thisv().toObject().as()); /* Step 1. */ - double t = LocalTime(thisObj->getDateUTCTime().toNumber(), &cx->runtime()->dateTimeInfo); + double t = LocalTime(dateObj->UTCTime().toNumber(), &cx->runtime()->dateTimeInfo); /* Step 2. */ double milli; @@ -1833,7 +1777,7 @@ date_setMilliseconds_impl(JSContext *cx, CallArgs args) double u = TimeClip(UTC(MakeDate(Day(t), time), &cx->runtime()->dateTimeInfo)); /* Steps 4-5. */ - SetUTCTime(thisObj, u, args.rval().address()); + dateObj->setUTCTime(u, args.rval().address()); return true; } @@ -1848,12 +1792,10 @@ date_setMilliseconds(JSContext *cx, unsigned argc, Value *vp) JS_ALWAYS_INLINE bool date_setUTCMilliseconds_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - RootedObject thisObj(cx, &args.thisv().toObject()); + Rooted dateObj(cx, &args.thisv().toObject().as()); /* Step 1. */ - double t = thisObj->getDateUTCTime().toNumber(); + double t = dateObj->UTCTime().toNumber(); /* Step 2. */ double milli; @@ -1865,7 +1807,7 @@ date_setUTCMilliseconds_impl(JSContext *cx, CallArgs args) double v = TimeClip(MakeDate(Day(t), time)); /* Steps 4-5. */ - SetUTCTime(thisObj, v, args.rval().address()); + dateObj->setUTCTime(v, args.rval().address()); return true; } @@ -1880,12 +1822,10 @@ date_setUTCMilliseconds(JSContext *cx, unsigned argc, Value *vp) JS_ALWAYS_INLINE bool date_setSeconds_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - RootedObject thisObj(cx, &args.thisv().toObject()); + Rooted dateObj(cx, &args.thisv().toObject().as()); /* Step 1. */ - double t = LocalTime(thisObj->getDateUTCTime().toNumber(), &cx->runtime()->dateTimeInfo); + double t = LocalTime(dateObj->UTCTime().toNumber(), &cx->runtime()->dateTimeInfo); /* Step 2. */ double s; @@ -1904,7 +1844,7 @@ date_setSeconds_impl(JSContext *cx, CallArgs args) double u = TimeClip(UTC(date, &cx->runtime()->dateTimeInfo)); /* Steps 6-7. */ - SetUTCTime(thisObj, u, args.rval().address()); + dateObj->setUTCTime(u, args.rval().address()); return true; } @@ -1919,12 +1859,10 @@ date_setSeconds(JSContext *cx, unsigned argc, Value *vp) JS_ALWAYS_INLINE bool date_setUTCSeconds_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - RootedObject thisObj(cx, &args.thisv().toObject()); + Rooted dateObj(cx, &args.thisv().toObject().as()); /* Step 1. */ - double t = thisObj->getDateUTCTime().toNumber(); + double t = dateObj->UTCTime().toNumber(); /* Step 2. */ double s; @@ -1943,7 +1881,7 @@ date_setUTCSeconds_impl(JSContext *cx, CallArgs args) double v = TimeClip(date); /* Steps 6-7. */ - SetUTCTime(thisObj, v, args.rval().address()); + dateObj->setUTCTime(v, args.rval().address()); return true; } @@ -1958,12 +1896,10 @@ date_setUTCSeconds(JSContext *cx, unsigned argc, Value *vp) JS_ALWAYS_INLINE bool date_setMinutes_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - RootedObject thisObj(cx, &args.thisv().toObject()); + Rooted dateObj(cx, &args.thisv().toObject().as()); /* Step 1. */ - double t = LocalTime(thisObj->getDateUTCTime().toNumber(), &cx->runtime()->dateTimeInfo); + double t = LocalTime(dateObj->UTCTime().toNumber(), &cx->runtime()->dateTimeInfo); /* Step 2. */ double m; @@ -1987,7 +1923,7 @@ date_setMinutes_impl(JSContext *cx, CallArgs args) double u = TimeClip(UTC(date, &cx->runtime()->dateTimeInfo)); /* Steps 7-8. */ - SetUTCTime(thisObj, u, args.rval().address()); + dateObj->setUTCTime(u, args.rval().address()); return true; } @@ -2002,12 +1938,10 @@ date_setMinutes(JSContext *cx, unsigned argc, Value *vp) JS_ALWAYS_INLINE bool date_setUTCMinutes_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - RootedObject thisObj(cx, &args.thisv().toObject()); + Rooted dateObj(cx, &args.thisv().toObject().as()); /* Step 1. */ - double t = thisObj->getDateUTCTime().toNumber(); + double t = dateObj->UTCTime().toNumber(); /* Step 2. */ double m; @@ -2031,7 +1965,7 @@ date_setUTCMinutes_impl(JSContext *cx, CallArgs args) double v = TimeClip(date); /* Steps 7-8. */ - SetUTCTime(thisObj, v, args.rval().address()); + dateObj->setUTCTime(v, args.rval().address()); return true; } @@ -2046,12 +1980,10 @@ date_setUTCMinutes(JSContext *cx, unsigned argc, Value *vp) JS_ALWAYS_INLINE bool date_setHours_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - RootedObject thisObj(cx, &args.thisv().toObject()); + Rooted dateObj(cx, &args.thisv().toObject().as()); /* Step 1. */ - double t = LocalTime(thisObj->getDateUTCTime().toNumber(), &cx->runtime()->dateTimeInfo); + double t = LocalTime(dateObj->UTCTime().toNumber(), &cx->runtime()->dateTimeInfo); /* Step 2. */ double h; @@ -2080,7 +2012,7 @@ date_setHours_impl(JSContext *cx, CallArgs args) double u = TimeClip(UTC(date, &cx->runtime()->dateTimeInfo)); /* Steps 7-8. */ - SetUTCTime(thisObj, u, args.rval().address()); + dateObj->setUTCTime(u, args.rval().address()); return true; } @@ -2095,12 +2027,10 @@ date_setHours(JSContext *cx, unsigned argc, Value *vp) JS_ALWAYS_INLINE bool date_setUTCHours_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - RootedObject thisObj(cx, &args.thisv().toObject()); + Rooted dateObj(cx, &args.thisv().toObject().as()); /* Step 1. */ - double t = thisObj->getDateUTCTime().toNumber(); + double t = dateObj->UTCTime().toNumber(); /* Step 2. */ double h; @@ -2129,7 +2059,7 @@ date_setUTCHours_impl(JSContext *cx, CallArgs args) double v = TimeClip(newDate); /* Steps 8-9. */ - SetUTCTime(thisObj, v, args.rval().address()); + dateObj->setUTCTime(v, args.rval().address()); return true; } @@ -2144,26 +2074,24 @@ date_setUTCHours(JSContext *cx, unsigned argc, Value *vp) JS_ALWAYS_INLINE bool date_setDate_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - RootedObject thisObj(cx, &args.thisv().toObject()); + Rooted dateObj(cx, &args.thisv().toObject().as()); /* Step 1. */ - double t = LocalTime(thisObj->getDateUTCTime().toNumber(), &cx->runtime()->dateTimeInfo); + double t = LocalTime(dateObj->UTCTime().toNumber(), &cx->runtime()->dateTimeInfo); /* Step 2. */ - double dt; - if (!ToNumber(cx, args.length() > 0 ? args[0] : UndefinedValue(), &dt)) + double date; + if (!ToNumber(cx, args.length() > 0 ? args[0] : UndefinedValue(), &date)) return false; /* Step 3. */ - double newDate = MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), dt), TimeWithinDay(t)); + double newDate = MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)); /* Step 4. */ double u = TimeClip(UTC(newDate, &cx->runtime()->dateTimeInfo)); /* Steps 5-6. */ - SetUTCTime(thisObj, u, args.rval().address()); + dateObj->setUTCTime(u, args.rval().address()); return true; } @@ -2178,26 +2106,24 @@ date_setDate(JSContext *cx, unsigned argc, Value *vp) JS_ALWAYS_INLINE bool date_setUTCDate_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - RootedObject thisObj(cx, &args.thisv().toObject()); + Rooted dateObj(cx, &args.thisv().toObject().as()); /* Step 1. */ - double t = thisObj->getDateUTCTime().toNumber(); + double t = dateObj->UTCTime().toNumber(); /* Step 2. */ - double dt; - if (!ToNumber(cx, args.length() > 0 ? args[0] : UndefinedValue(), &dt)) + double date; + if (!ToNumber(cx, args.length() > 0 ? args[0] : UndefinedValue(), &date)) return false; /* Step 3. */ - double newDate = MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), dt), TimeWithinDay(t)); + double newDate = MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)); /* Step 4. */ double v = TimeClip(newDate); /* Steps 5-6. */ - SetUTCTime(thisObj, v, args.rval().address()); + dateObj->setUTCTime(v, args.rval().address()); return true; } @@ -2232,12 +2158,10 @@ GetMonthOrDefault(JSContext *cx, const CallArgs &args, unsigned i, double t, dou JS_ALWAYS_INLINE bool date_setMonth_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - RootedObject thisObj(cx, &args.thisv().toObject()); + Rooted dateObj(cx, &args.thisv().toObject().as()); /* Step 1. */ - double t = LocalTime(thisObj->getDateUTCTime().toNumber(), &cx->runtime()->dateTimeInfo); + double t = LocalTime(dateObj->UTCTime().toNumber(), &cx->runtime()->dateTimeInfo); /* Step 2. */ double m; @@ -2245,18 +2169,18 @@ date_setMonth_impl(JSContext *cx, CallArgs args) return false; /* Step 3. */ - double dt; - if (!GetDateOrDefault(cx, args, 1, t, &dt)) + double date; + if (!GetDateOrDefault(cx, args, 1, t, &date)) return false; /* Step 4. */ - double newDate = MakeDate(MakeDay(YearFromTime(t), m, dt), TimeWithinDay(t)); + double newDate = MakeDate(MakeDay(YearFromTime(t), m, date), TimeWithinDay(t)); /* Step 5. */ double u = TimeClip(UTC(newDate, &cx->runtime()->dateTimeInfo)); /* Steps 6-7. */ - SetUTCTime(thisObj, u, args.rval().address()); + dateObj->setUTCTime(u, args.rval().address()); return true; } @@ -2271,12 +2195,10 @@ date_setMonth(JSContext *cx, unsigned argc, Value *vp) JS_ALWAYS_INLINE bool date_setUTCMonth_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - RootedObject thisObj(cx, &args.thisv().toObject()); + Rooted dateObj(cx, &args.thisv().toObject().as()); /* Step 1. */ - double t = thisObj->getDateUTCTime().toNumber(); + double t = dateObj->UTCTime().toNumber(); /* Step 2. */ double m; @@ -2284,18 +2206,18 @@ date_setUTCMonth_impl(JSContext *cx, CallArgs args) return false; /* Step 3. */ - double dt; - if (!GetDateOrDefault(cx, args, 1, t, &dt)) + double date; + if (!GetDateOrDefault(cx, args, 1, t, &date)) return false; /* Step 4. */ - double newDate = MakeDate(MakeDay(YearFromTime(t), m, dt), TimeWithinDay(t)); + double newDate = MakeDate(MakeDay(YearFromTime(t), m, date), TimeWithinDay(t)); /* Step 5. */ double v = TimeClip(newDate); /* Steps 6-7. */ - SetUTCTime(thisObj, v, args.rval().address()); + dateObj->setUTCTime(v, args.rval().address()); return true; } @@ -2307,18 +2229,18 @@ date_setUTCMonth(JSContext *cx, unsigned argc, Value *vp) } static double -ThisLocalTimeOrZero(HandleObject date, DateTimeInfo *dtInfo) +ThisLocalTimeOrZero(Handle dateObj, DateTimeInfo *dtInfo) { - double t = date->getDateUTCTime().toNumber(); + double t = dateObj->UTCTime().toNumber(); if (IsNaN(t)) return +0; return LocalTime(t, dtInfo); } static double -ThisUTCTimeOrZero(HandleObject date) +ThisUTCTimeOrZero(Handle dateObj) { - double t = date->getDateUTCTime().toNumber(); + double t = dateObj->as().UTCTime().toNumber(); return IsNaN(t) ? +0 : t; } @@ -2326,12 +2248,10 @@ ThisUTCTimeOrZero(HandleObject date) JS_ALWAYS_INLINE bool date_setFullYear_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - RootedObject thisObj(cx, &args.thisv().toObject()); + Rooted dateObj(cx, &args.thisv().toObject().as()); /* Step 1. */ - double t = ThisLocalTimeOrZero(thisObj, &cx->runtime()->dateTimeInfo); + double t = ThisLocalTimeOrZero(dateObj, &cx->runtime()->dateTimeInfo); /* Step 2. */ double y; @@ -2344,18 +2264,18 @@ date_setFullYear_impl(JSContext *cx, CallArgs args) return false; /* Step 4. */ - double dt; - if (!GetDateOrDefault(cx, args, 2, t, &dt)) + double date; + if (!GetDateOrDefault(cx, args, 2, t, &date)) return false; /* Step 5. */ - double newDate = MakeDate(MakeDay(y, m, dt), TimeWithinDay(t)); + double newDate = MakeDate(MakeDay(y, m, date), TimeWithinDay(t)); /* Step 6. */ double u = TimeClip(UTC(newDate, &cx->runtime()->dateTimeInfo)); /* Steps 7-8. */ - SetUTCTime(thisObj, u, args.rval().address()); + dateObj->setUTCTime(u, args.rval().address()); return true; } @@ -2370,12 +2290,10 @@ date_setFullYear(JSContext *cx, unsigned argc, Value *vp) JS_ALWAYS_INLINE bool date_setUTCFullYear_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - RootedObject thisObj(cx, &args.thisv().toObject()); + Rooted dateObj(cx, &args.thisv().toObject().as()); /* Step 1. */ - double t = ThisUTCTimeOrZero(thisObj); + double t = ThisUTCTimeOrZero(dateObj); /* Step 2. */ double y; @@ -2388,18 +2306,18 @@ date_setUTCFullYear_impl(JSContext *cx, CallArgs args) return false; /* Step 4. */ - double dt; - if (!GetDateOrDefault(cx, args, 2, t, &dt)) + double date; + if (!GetDateOrDefault(cx, args, 2, t, &date)) return false; /* Step 5. */ - double newDate = MakeDate(MakeDay(y, m, dt), TimeWithinDay(t)); + double newDate = MakeDate(MakeDay(y, m, date), TimeWithinDay(t)); /* Step 6. */ double v = TimeClip(newDate); /* Steps 7-8. */ - SetUTCTime(thisObj, v, args.rval().address()); + dateObj->setUTCTime(v, args.rval().address()); return true; } @@ -2414,12 +2332,10 @@ date_setUTCFullYear(JSContext *cx, unsigned argc, Value *vp) JS_ALWAYS_INLINE bool date_setYear_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - RootedObject thisObj(cx, &args.thisv().toObject()); + Rooted dateObj(cx, &args.thisv().toObject().as()); /* Step 1. */ - double t = ThisLocalTimeOrZero(thisObj, &cx->runtime()->dateTimeInfo); + double t = ThisLocalTimeOrZero(dateObj, &cx->runtime()->dateTimeInfo); /* Step 2. */ double y; @@ -2428,7 +2344,7 @@ date_setYear_impl(JSContext *cx, CallArgs args) /* Step 3. */ if (IsNaN(y)) { - SetUTCTime(thisObj, js_NaN, args.rval().address()); + dateObj->setUTCTime(js_NaN, args.rval().address()); return true; } @@ -2444,7 +2360,7 @@ date_setYear_impl(JSContext *cx, CallArgs args) double u = UTC(MakeDate(day, TimeWithinDay(t)), &cx->runtime()->dateTimeInfo); /* Steps 7-8. */ - SetUTCTime(thisObj, TimeClip(u), args.rval().address()); + dateObj->setUTCTime(TimeClip(u), args.rval().address()); return true; } @@ -2501,9 +2417,7 @@ print_iso_string(char* buf, size_t size, double utctime) JS_ALWAYS_INLINE bool date_toGMTString_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - double utctime = args.thisv().toObject().getDateUTCTime().toNumber(); + double utctime = args.thisv().toObject().as().UTCTime().toNumber(); char buf[100]; if (!IsFinite(utctime)) @@ -2529,9 +2443,7 @@ date_toGMTString(JSContext *cx, unsigned argc, Value *vp) JS_ALWAYS_INLINE bool date_toISOString_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - double utctime = args.thisv().toObject().getDateUTCTime().toNumber(); + double utctime = args.thisv().toObject().as().UTCTime().toNumber(); if (!IsFinite(utctime)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INVALID_DATE); return false; @@ -2747,7 +2659,7 @@ date_format(JSContext *cx, double date, formatspec format, MutableHandleValue rv static bool ToLocaleFormatHelper(JSContext *cx, HandleObject obj, const char *format, MutableHandleValue rval) { - double utctime = obj->getDateUTCTime().toNumber(); + double utctime = obj->as().UTCTime().toNumber(); char buf[100]; if (!IsFinite(utctime)) { @@ -2792,13 +2704,13 @@ ToLocaleFormatHelper(JSContext *cx, HandleObject obj, const char *format, Mutabl #if !ENABLE_INTL_API static bool -ToLocaleStringHelper(JSContext *cx, HandleObject thisObj, MutableHandleValue rval) +ToLocaleStringHelper(JSContext *cx, Handle dateObj, MutableHandleValue rval) { /* * Use '%#c' for windows, because '%c' is backward-compatible and non-y2k * with msvc; '%#c' requests that a full year be used in the result string. */ - return ToLocaleFormatHelper(cx, thisObj, + return ToLocaleFormatHelper(cx, dateObj, #if defined(_WIN32) && !defined(__MWERKS__) "%#c" #else @@ -2811,10 +2723,8 @@ ToLocaleStringHelper(JSContext *cx, HandleObject thisObj, MutableHandleValue rva JS_ALWAYS_INLINE bool date_toLocaleString_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - RootedObject thisObj(cx, &args.thisv().toObject()); - return ToLocaleStringHelper(cx, thisObj, args.rval()); + Rooted dateObj(cx, &args.thisv().toObject().as()); + return ToLocaleStringHelper(cx, dateObj, args.rval()); } static JSBool @@ -2828,8 +2738,6 @@ date_toLocaleString(JSContext *cx, unsigned argc, Value *vp) JS_ALWAYS_INLINE bool date_toLocaleDateString_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - /* * Use '%#x' for windows, because '%x' is backward-compatible and non-y2k * with msvc; '%#x' requests that a full year be used in the result string. @@ -2842,8 +2750,8 @@ date_toLocaleDateString_impl(JSContext *cx, CallArgs args) #endif ; - RootedObject thisObj(cx, &args.thisv().toObject()); - return ToLocaleFormatHelper(cx, thisObj, format, args.rval()); + Rooted dateObj(cx, &args.thisv().toObject().as()); + return ToLocaleFormatHelper(cx, dateObj, format, args.rval()); } static JSBool @@ -2857,10 +2765,8 @@ date_toLocaleDateString(JSContext *cx, unsigned argc, Value *vp) JS_ALWAYS_INLINE bool date_toLocaleTimeString_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - RootedObject thisObj(cx, &args.thisv().toObject()); - return ToLocaleFormatHelper(cx, thisObj, "%X", args.rval()); + Rooted dateObj(cx, &args.thisv().toObject().as()); + return ToLocaleFormatHelper(cx, dateObj, "%X", args.rval()); } static JSBool @@ -2874,16 +2780,14 @@ date_toLocaleTimeString(JSContext *cx, unsigned argc, Value *vp) JS_ALWAYS_INLINE bool date_toLocaleFormat_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - RootedObject thisObj(cx, &args.thisv().toObject()); + Rooted dateObj(cx, &args.thisv().toObject().as()); if (args.length() == 0) { /* * Use '%#c' for windows, because '%c' is backward-compatible and non-y2k * with msvc; '%#c' requests that a full year be used in the result string. */ - return ToLocaleFormatHelper(cx, thisObj, + return ToLocaleFormatHelper(cx, dateObj, #if defined(_WIN32) && !defined(__MWERKS__) "%#c" #else @@ -2900,7 +2804,7 @@ date_toLocaleFormat_impl(JSContext *cx, CallArgs args) if (!fmtbytes) return false; - return ToLocaleFormatHelper(cx, thisObj, fmtbytes.ptr(), args.rval()); + return ToLocaleFormatHelper(cx, dateObj, fmtbytes.ptr(), args.rval()); } static JSBool @@ -2914,9 +2818,7 @@ date_toLocaleFormat(JSContext *cx, unsigned argc, Value *vp) JS_ALWAYS_INLINE bool date_toTimeString_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - return date_format(cx, args.thisv().toObject().getDateUTCTime().toNumber(), + return date_format(cx, args.thisv().toObject().as().UTCTime().toNumber(), FORMATSPEC_TIME, args.rval()); } @@ -2931,9 +2833,7 @@ date_toTimeString(JSContext *cx, unsigned argc, Value *vp) JS_ALWAYS_INLINE bool date_toDateString_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - return date_format(cx, args.thisv().toObject().getDateUTCTime().toNumber(), + return date_format(cx, args.thisv().toObject().as().UTCTime().toNumber(), FORMATSPEC_DATE, args.rval()); } @@ -2948,11 +2848,9 @@ date_toDateString(JSContext *cx, unsigned argc, Value *vp) JS_ALWAYS_INLINE bool date_toSource_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - StringBuffer sb(cx); if (!sb.append("(new Date(") || - !NumberValueToStringBuffer(cx, args.thisv().toObject().getDateUTCTime(), sb) || + !NumberValueToStringBuffer(cx, args.thisv().toObject().as().UTCTime(), sb) || !sb.append("))")) { return false; @@ -2976,8 +2874,7 @@ date_toSource(JSContext *cx, unsigned argc, Value *vp) JS_ALWAYS_INLINE bool date_toString_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - return date_format(cx, args.thisv().toObject().getDateUTCTime().toNumber(), + return date_format(cx, args.thisv().toObject().as().UTCTime().toNumber(), FORMATSPEC_FULL, args.rval()); } @@ -2991,11 +2888,8 @@ date_toString(JSContext *cx, unsigned argc, Value *vp) JS_ALWAYS_INLINE bool date_valueOf_impl(JSContext *cx, CallArgs args) { - JS_ASSERT(IsDate(args.thisv())); - - JSObject *thisObj = &args.thisv().toObject(); - - args.rval().set(thisObj->getDateUTCTime()); + Rooted dateObj(cx, &args.thisv().toObject().as()); + args.rval().set(dateObj->UTCTime()); return true; } @@ -3140,10 +3034,10 @@ js_InitDateClass(JSContext *cx, HandleObject obj) Rooted global(cx, &obj->as()); - RootedObject dateProto(cx, global->createBlankPrototype(cx, &DateClass)); + RootedObject dateProto(cx, global->createBlankPrototype(cx, &DateObject::class_)); if (!dateProto) return NULL; - SetUTCTime(dateProto, js_NaN); + dateProto->as().setUTCTime(js_NaN); RootedFunction ctor(cx); ctor = global->createConstructor(cx, js_Date, cx->names().Date, MAXARGS); @@ -3182,10 +3076,10 @@ js_InitDateClass(JSContext *cx, HandleObject obj) JS_FRIEND_API(JSObject *) js_NewDateObjectMsec(JSContext *cx, double msec_time) { - JSObject *obj = NewBuiltinClassInstance(cx, &DateClass); + JSObject *obj = NewBuiltinClassInstance(cx, &DateObject::class_); if (!obj) return NULL; - SetUTCTime(obj, msec_time); + obj->as().setUTCTime(msec_time); return obj; } @@ -3201,7 +3095,7 @@ js_NewDateObject(JSContext *cx, int year, int mon, int mday, JS_FRIEND_API(JSBool) js_DateIsValid(JSObject *obj) { - return obj->isDate() && !IsNaN(obj->getDateUTCTime().toNumber()); + return obj->is() && !IsNaN(obj->as().UTCTime().toNumber()); } JS_FRIEND_API(int) @@ -3209,7 +3103,7 @@ js_DateGetYear(JSContext *cx, JSObject *obj) { /* Preserve legacy API behavior of returning 0 for invalid dates. */ JS_ASSERT(obj); - double localtime = GetCachedLocalTime(&cx->runtime()->dateTimeInfo, obj); + double localtime = obj->as().cachedLocalTime(&cx->runtime()->dateTimeInfo); if (IsNaN(localtime)) return 0; @@ -3220,7 +3114,7 @@ JS_FRIEND_API(int) js_DateGetMonth(JSContext *cx, JSObject *obj) { JS_ASSERT(obj); - double localtime = GetCachedLocalTime(&cx->runtime()->dateTimeInfo, obj); + double localtime = obj->as().cachedLocalTime(&cx->runtime()->dateTimeInfo); if (IsNaN(localtime)) return 0; @@ -3231,7 +3125,7 @@ JS_FRIEND_API(int) js_DateGetDate(JSContext *cx, JSObject *obj) { JS_ASSERT(obj); - double localtime = GetCachedLocalTime(&cx->runtime()->dateTimeInfo, obj); + double localtime = obj->as().cachedLocalTime(&cx->runtime()->dateTimeInfo); if (IsNaN(localtime)) return 0; @@ -3242,7 +3136,7 @@ JS_FRIEND_API(int) js_DateGetHours(JSContext *cx, JSObject *obj) { JS_ASSERT(obj); - double localtime = GetCachedLocalTime(&cx->runtime()->dateTimeInfo, obj); + double localtime = obj->as().cachedLocalTime(&cx->runtime()->dateTimeInfo); if (IsNaN(localtime)) return 0; @@ -3253,7 +3147,7 @@ JS_FRIEND_API(int) js_DateGetMinutes(JSContext *cx, JSObject *obj) { JS_ASSERT(obj); - double localtime = GetCachedLocalTime(&cx->runtime()->dateTimeInfo, obj); + double localtime = obj->as().cachedLocalTime(&cx->runtime()->dateTimeInfo); if (IsNaN(localtime)) return 0; @@ -3263,10 +3157,10 @@ js_DateGetMinutes(JSContext *cx, JSObject *obj) JS_FRIEND_API(int) js_DateGetSeconds(JSObject *obj) { - if (!obj->isDate()) + if (!obj->is()) return 0; - double utctime = obj->getDateUTCTime().toNumber(); + double utctime = obj->as().UTCTime().toNumber(); if (IsNaN(utctime)) return 0; return (int) SecFromTime(utctime); @@ -3275,28 +3169,28 @@ js_DateGetSeconds(JSObject *obj) JS_FRIEND_API(double) js_DateGetMsecSinceEpoch(JSObject *obj) { - return obj->isDate() ? obj->getDateUTCTime().toNumber() : 0; + return obj->is() ? obj->as().UTCTime().toNumber() : 0; } static const NativeImpl sReadOnlyDateMethods[] = { - date_getTime_impl, - date_getYear_impl, - date_getFullYear_impl, - date_getUTCFullYear_impl, - date_getMonth_impl, - date_getUTCMonth_impl, - date_getDate_impl, - date_getUTCDate_impl, - date_getDay_impl, - date_getUTCDay_impl, - date_getHours_impl, - date_getUTCHours_impl, - date_getMinutes_impl, - date_getUTCMinutes_impl, - date_getUTCSeconds_impl, - date_getUTCMilliseconds_impl, - date_getTimezoneOffset_impl, + DateObject::getTime_impl, + DateObject::getYear_impl, + DateObject::getFullYear_impl, + DateObject::getUTCFullYear_impl, + DateObject::getMonth_impl, + DateObject::getUTCMonth_impl, + DateObject::getDate_impl, + DateObject::getUTCDate_impl, + DateObject::getDay_impl, + DateObject::getUTCDay_impl, + DateObject::getHours_impl, + DateObject::getUTCHours_impl, + DateObject::getMinutes_impl, + DateObject::getUTCMinutes_impl, + DateObject::getUTCSeconds_impl, + DateObject::getUTCMilliseconds_impl, + DateObject::getTimezoneOffset_impl, date_toGMTString_impl, date_toISOString_impl, date_toLocaleFormat_impl, diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index 7021e1676..685737c73 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -1325,6 +1325,9 @@ JSAbstractFramePtr::evaluateUCInStackFrame(JSContext *cx, const char *filename, unsigned lineno, MutableHandleValue rval) { + /* Protect inlined chars from root analysis poisoning. */ + SkipRoot skipChars(cx, &chars); + if (!CheckDebugMode(cx)) return false; diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index fae979872..eb9252bf8 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -24,6 +24,7 @@ #include "jsscript.h" #include "gc/Marking.h" +#include "vm/ErrorObject.h" #include "vm/GlobalObject.h" #include "vm/StringBuffer.h" @@ -37,7 +38,7 @@ using mozilla::ArrayLength; using mozilla::PodArrayZero; using mozilla::PodZero; -/* Forward declarations for ErrorClass's initializer. */ +/* Forward declarations for ErrorObject::class_'s initializer. */ static JSBool Exception(JSContext *cx, unsigned argc, Value *vp); @@ -51,7 +52,7 @@ static JSBool exn_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags, MutableHandleObject objp); -Class js::ErrorClass = { +Class ErrorObject::class_ = { js_Error_str, JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_CACHED_PROTO(JSProto_Error), @@ -240,14 +241,14 @@ struct SuppressErrorsGuard }; static void -SetExnPrivate(JSObject *exnObject, JSExnPrivate *priv); +SetExnPrivate(ErrorObject &exnObject, JSExnPrivate *priv); static bool InitExnPrivate(JSContext *cx, HandleObject exnObject, HandleString message, HandleString filename, unsigned lineno, unsigned column, JSErrorReport *report, int exnType) { - JS_ASSERT(exnObject->isError()); + JS_ASSERT(exnObject->is()); JS_ASSERT(!exnObject->getPrivate()); JSCheckAccessOp checkAccess = cx->runtime()->securityCallbacks->checkObjectAccess; @@ -329,21 +330,14 @@ InitExnPrivate(JSContext *cx, HandleObject exnObject, HandleString message, priv->stackElems[i].ulineno = frames[i].ulineno; } - SetExnPrivate(exnObject, priv); + SetExnPrivate(exnObject->as(), priv); return true; } -static inline JSExnPrivate * -GetExnPrivate(JSObject *obj) -{ - JS_ASSERT(obj->isError()); - return (JSExnPrivate *) obj->getPrivate(); -} - static void exn_trace(JSTracer *trc, JSObject *obj) { - if (JSExnPrivate *priv = GetExnPrivate(obj)) { + if (JSExnPrivate *priv = obj->as().getExnPrivate()) { if (priv->message) MarkString(trc, &priv->message, "exception message"); if (priv->filename) @@ -359,21 +353,20 @@ exn_trace(JSTracer *trc, JSObject *obj) /* NB: An error object's private must be set through this function. */ static void -SetExnPrivate(JSObject *exnObject, JSExnPrivate *priv) +SetExnPrivate(ErrorObject &exnObject, JSExnPrivate *priv) { - JS_ASSERT(!exnObject->getPrivate()); - JS_ASSERT(exnObject->isError()); + JS_ASSERT(!exnObject.getExnPrivate()); if (JSErrorReport *report = priv->errorReport) { if (JSPrincipals *prin = report->originPrincipals) JS_HoldPrincipals(prin); } - exnObject->setPrivate(priv); + exnObject.setPrivate(priv); } static void exn_finalize(FreeOp *fop, JSObject *obj) { - if (JSExnPrivate *priv = GetExnPrivate(obj)) { + if (JSExnPrivate *priv = obj->as().getExnPrivate()) { if (JSErrorReport *report = priv->errorReport) { /* HOLD called by SetExnPrivate. */ if (JSPrincipals *prin = report->originPrincipals) @@ -396,7 +389,7 @@ exn_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags, unsigned attrs; objp.set(NULL); - priv = GetExnPrivate(obj); + priv = obj->as().getExnPrivate(); if (priv && JSID_IS_ATOM(id)) { RootedString str(cx, JSID_TO_STRING(id)); @@ -475,10 +468,10 @@ js_ErrorFromException(jsval exn) // JSErrorReport's principal or also tries to do toString on our object and // will fail if they can't unwrap it. JSObject *obj = UncheckedUnwrap(JSVAL_TO_OBJECT(exn)); - if (!obj->isError()) + if (!obj->is()) return NULL; - JSExnPrivate *priv = GetExnPrivate(obj); + JSExnPrivate *priv = obj->as().getExnPrivate(); if (!priv) return NULL; @@ -550,7 +543,8 @@ Exception(JSContext *cx, unsigned argc, Value *vp) return false; } - RootedObject obj(cx, NewObjectWithGivenProto(cx, &ErrorClass, &protov.toObject(), NULL)); + RootedObject obj(cx, NewObjectWithGivenProto(cx, &ErrorObject::class_, &protov.toObject(), + NULL)); if (!obj) return false; @@ -783,7 +777,8 @@ InitErrorClass(JSContext *cx, Handle global, int type, HandleObje { JSProtoKey key = GetExceptionProtoKey(type); RootedAtom name(cx, ClassName(key, cx)); - RootedObject errorProto(cx, global->createBlankPrototypeInheriting(cx, &ErrorClass, *proto)); + RootedObject errorProto(cx, global->createBlankPrototypeInheriting(cx, &ErrorObject::class_, + *proto)); if (!errorProto) return NULL; @@ -956,7 +951,7 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp, return false; tv[0] = OBJECT_TO_JSVAL(errProto); - RootedObject errObject(cx, NewObjectWithGivenProto(cx, &ErrorClass, errProto, NULL)); + RootedObject errObject(cx, NewObjectWithGivenProto(cx, &ErrorObject::class_, errProto, NULL)); if (!errObject) return false; tv[1] = OBJECT_TO_JSVAL(errObject); @@ -1047,8 +1042,7 @@ js_ReportUncaughtException(JSContext *cx) const char *filename_str = js_fileName_str; JSAutoByteString filename; if (!reportp && exnObject && - (exnObject->isError() || - IsDuckTypedErrorObject(cx, exnObject, &filename_str))) + (exnObject->is() || IsDuckTypedErrorObject(cx, exnObject, &filename_str))) { RootedString name(cx); if (JS_GetProperty(cx, exnObject, js_name_str, &roots[2]) && @@ -1139,7 +1133,7 @@ extern JSObject * js_CopyErrorObject(JSContext *cx, HandleObject errobj, HandleObject scope) { assertSameCompartment(cx, scope); - JSExnPrivate *priv = GetExnPrivate(errobj); + JSExnPrivate *priv = errobj->as().getExnPrivate(); size_t size = offsetof(JSExnPrivate, stackElems) + priv->stackDepth * sizeof(JSStackTraceElem); @@ -1174,10 +1168,10 @@ js_CopyErrorObject(JSContext *cx, HandleObject errobj, HandleObject scope) RootedObject proto(cx, scope->global().getOrCreateCustomErrorPrototype(cx, copy->exnType)); if (!proto) return NULL; - RootedObject copyobj(cx, NewObjectWithGivenProto(cx, &ErrorClass, proto, NULL)); + RootedObject copyobj(cx, NewObjectWithGivenProto(cx, &ErrorObject::class_, proto, NULL)); if (!copyobj) return NULL; - SetExnPrivate(copyobj, copy); + SetExnPrivate(copyobj->as(), copy); copy.forget(); autoFreeErrorReport.forget(); return copyobj; diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 788be2d66..19929e53c 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -395,10 +395,6 @@ struct Atom { } /* namespace shadow */ -// This is equal to JSFunction::class_. Use it in places where you don't want -// to #include jsfun.h. -extern JS_FRIEND_DATA(js::Class*) FunctionClassPtr; - extern JS_FRIEND_DATA(js::Class) FunctionProxyClass; extern JS_FRIEND_DATA(js::Class) OuterWindowProxyClass; extern JS_FRIEND_DATA(js::Class) ObjectProxyClass; diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index f281358c2..d0e676b67 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -1520,6 +1520,9 @@ js::Function(JSContext *cx, unsigned argc, Value *vp) const jschar *chars = linear->chars(); size_t length = linear->length(); + /* Protect inlined chars from root analysis poisoning. */ + SkipRoot skip(cx, &chars); + /* * NB: (new Function) is not lexically closed by its caller, it's just an * anonymous function in the top-level scope that its constructor inhabits. @@ -1542,9 +1545,9 @@ js::Function(JSContext *cx, unsigned argc, Value *vp) } bool -js::IsBuiltinFunctionConstructor(JSFunction *fun) +JSFunction::isBuiltinFunctionConstructor() { - return fun->maybeNative() == Function; + return maybeNative() == Function; } JSFunction * diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 83b31211a..181804fb1 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -11,6 +11,7 @@ */ #include "jsprvtd.h" #include "jsobj.h" +#include "jsscript.h" #include "gc/Barrier.h" @@ -82,7 +83,17 @@ class JSFunction : public JSObject public: /* Call objects must be created for each invocation of a heavyweight function. */ - inline bool isHeavyweight() const; + bool isHeavyweight() const { + JS_ASSERT(!isInterpretedLazy()); + + if (isNative()) + return false; + + // Note: this should be kept in sync with FunctionBox::isHeavyweight(). + return nonLazyScript()->bindings.hasAnyAliasedBindings() || + nonLazyScript()->funHasExtensibleScope || + nonLazyScript()->funNeedsDeclEnvObject; + } /* A function can be classified as either native (C++) or interpreted (JS): */ bool isInterpreted() const { return flags & (INTERPRETED | INTERPRETED_LAZY); } @@ -128,12 +139,16 @@ class JSFunction : public JSObject return isInterpreted() && !isFunctionPrototype() && (!isSelfHostedBuiltin() || isSelfHostedConstructor()); } - bool isNamedLambda() const { + bool isNamedLambda() const { return isLambda() && atom_ && !hasGuessedAtom(); } + bool isBuiltinFunctionConstructor(); + /* Returns the strictness of this function, which must be interpreted. */ - inline bool strict() const; + bool strict() const { + return nonLazyScript()->strict; + } // Can be called multiple times by the parser. void setArgCount(uint16_t nargs) { @@ -190,7 +205,10 @@ class JSFunction : public JSObject * For an interpreted function, accessors for the initial scope object of * activations (stack frames) of the function. */ - inline JSObject *environment() const; + JSObject *environment() const { + JS_ASSERT(isInterpreted()); + return u.i.env_; + } inline void setEnvironment(JSObject *obj); inline void initEnvironment(JSObject *obj); @@ -258,7 +276,12 @@ class JSFunction : public JSObject inline void setScript(JSScript *script_); inline void initScript(JSScript *script_); - inline void initLazyScript(js::LazyScript *script); + void initLazyScript(js::LazyScript *lazy) { + JS_ASSERT(isInterpreted()); + flags &= ~INTERPRETED; + flags |= INTERPRETED_LAZY; + u.i.s.lazy_ = lazy; + } JSNative native() const { JS_ASSERT(isNative()); @@ -269,9 +292,21 @@ class JSFunction : public JSObject return isInterpreted() ? NULL : native(); } - inline void initNative(js::Native native, const JSJitInfo *jitinfo); - inline const JSJitInfo *jitInfo() const; - inline void setJitInfo(const JSJitInfo *data); + void initNative(js::Native native, const JSJitInfo *jitinfo) { + JS_ASSERT(native); + u.n.native = native; + u.n.jitinfo = jitinfo; + } + + const JSJitInfo *jitInfo() const { + JS_ASSERT(isNative()); + return u.n.jitinfo; + } + + void setJitInfo(const JSJitInfo *data) { + JS_ASSERT(isNative()); + u.n.jitinfo = data; + } static unsigned offsetOfNativeOrScript() { JS_STATIC_ASSERT(offsetof(U, n.native) == offsetof(U, i.s.script_)); @@ -347,6 +382,31 @@ JSAPIToJSFunctionFlags(unsigned flags) namespace js { +/* Valueified JS_IsConstructing. */ +static JS_ALWAYS_INLINE bool +IsConstructing(const Value *vp) +{ +#ifdef DEBUG + JSObject *callee = &JS_CALLEE(cx, vp).toObject(); + if (callee->is()) { + JSFunction *fun = &callee->as(); + JS_ASSERT(fun->isNativeConstructor()); + } else { + JS_ASSERT(callee->getClass()->construct != NULL); + } +#endif + return vp[1].isMagic(); +} + +inline bool +IsConstructing(CallReceiver call) +{ + return IsConstructing(call.base()); +} + +extern JSBool +Function(JSContext *cx, unsigned argc, Value *vp); + extern JSFunction * NewFunction(JSContext *cx, HandleObject funobj, JSNative native, unsigned nargs, JSFunction::Flags flags, HandleObject parent, HandleAtom atom, @@ -400,6 +460,13 @@ JSFunction::toExtended() const return static_cast(this); } +inline const js::Value & +JSFunction::getExtendedSlot(size_t which) const +{ + JS_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots)); + return toExtended()->extendedSlots[which]; +} + namespace js { JSString *FunctionToString(JSContext *cx, HandleFunction fun, bool bodyOnly, bool lambdaParen); diff --git a/js/src/jsfuninlines.h b/js/src/jsfuninlines.h index c334ffdcc..eee4fdcc1 100644 --- a/js/src/jsfuninlines.h +++ b/js/src/jsfuninlines.h @@ -16,12 +16,6 @@ #include "vm/ScopeObject-inl.h" #include "vm/String-inl.h" -inline bool -JSFunction::strict() const -{ - return nonLazyScript()->strict; -} - inline void JSFunction::initAtom(JSAtom *atom) { @@ -38,13 +32,6 @@ JSFunction::setGuessedAtom(JSAtom *atom) flags |= HAS_GUESSED_ATOM; } -inline JSObject * -JSFunction::environment() const -{ - JS_ASSERT(isInterpreted()); - return u.i.env_; -} - inline void JSFunction::setEnvironment(JSObject *obj) { @@ -59,28 +46,6 @@ JSFunction::initEnvironment(JSObject *obj) ((js::HeapPtrObject *)&u.i.env_)->init(obj); } -inline void -JSFunction::initNative(js::Native native, const JSJitInfo *data) -{ - JS_ASSERT(native); - u.n.native = native; - u.n.jitinfo = data; -} - -inline const JSJitInfo * -JSFunction::jitInfo() const -{ - JS_ASSERT(isNative()); - return u.n.jitinfo; -} - -inline void -JSFunction::setJitInfo(const JSJitInfo *data) -{ - JS_ASSERT(isNative()); - u.n.jitinfo = data; -} - inline void JSFunction::initializeExtended() { @@ -105,45 +70,8 @@ JSFunction::setExtendedSlot(size_t which, const js::Value &val) toExtended()->extendedSlots[which] = val; } -inline const js::Value & -JSFunction::getExtendedSlot(size_t which) const -{ - JS_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots)); - return toExtended()->extendedSlots[which]; -} - namespace js { -extern JS_ALWAYS_INLINE bool -SameTraceType(const Value &lhs, const Value &rhs) -{ - return SameType(lhs, rhs) && - (lhs.isPrimitive() || - lhs.toObject().is() == rhs.toObject().is()); -} - -/* Valueified JS_IsConstructing. */ -static JS_ALWAYS_INLINE bool -IsConstructing(const Value *vp) -{ -#ifdef DEBUG - JSObject *callee = &JS_CALLEE(cx, vp).toObject(); - if (callee->is()) { - JSFunction *fun = &callee->as(); - JS_ASSERT(fun->isNativeConstructor()); - } else { - JS_ASSERT(callee->getClass()->construct != NULL); - } -#endif - return vp[1].isMagic(); -} - -inline bool -IsConstructing(CallReceiver call) -{ - return IsConstructing(call.base()); -} - inline const char * GetFunctionNameBytes(JSContext *cx, JSFunction *fun, JSAutoByteString *bytes) { @@ -153,12 +81,6 @@ GetFunctionNameBytes(JSContext *cx, JSFunction *fun, JSAutoByteString *bytes) return js_anonymous_str; } -extern JSBool -Function(JSContext *cx, unsigned argc, Value *vp); - -extern bool -IsBuiltinFunctionConstructor(JSFunction *fun); - static inline JSObject * SkipScopeParent(JSObject *parent) { @@ -224,20 +146,6 @@ CloneFunctionObjectIfNotSingleton(JSContext *cx, HandleFunction fun, HandleObjec } /* namespace js */ -inline bool -JSFunction::isHeavyweight() const -{ - JS_ASSERT(!isInterpretedLazy()); - - if (isNative()) - return false; - - // Note: this should be kept in sync with FunctionBox::isHeavyweight(). - return nonLazyScript()->bindings.hasAnyAliasedBindings() || - nonLazyScript()->funHasExtensibleScope || - nonLazyScript()->funNeedsDeclEnvObject; -} - inline JSScript * JSFunction::existingScript() { @@ -272,17 +180,6 @@ JSFunction::initScript(JSScript *script_) mutableScript().init(script_); } -inline void -JSFunction::initLazyScript(js::LazyScript *lazy) -{ - JS_ASSERT(isInterpreted()); - - flags &= ~INTERPRETED; - flags |= INTERPRETED_LAZY; - - u.i.s.lazy_ = lazy; -} - inline JSObject * JSFunction::getBoundFunctionTarget() const { @@ -292,10 +189,4 @@ JSFunction::getBoundFunctionTarget() const return getParent(); } -inline bool -js::Class::isCallable() const -{ - return this == &JSFunction::class_ || call; -} - #endif /* jsfuninlines_h */ diff --git a/js/src/jsgc.h b/js/src/jsgc.h index d1bbe4faa..105c728a5 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -25,11 +25,11 @@ #include "js/HashTable.h" #include "js/Vector.h" -struct JSAtom; +class JSAtom; struct JSCompartment; -struct JSFunction; -struct JSFlatString; -struct JSLinearString; +class JSFunction; +class JSFlatString; +class JSLinearString; namespace js { @@ -258,9 +258,8 @@ struct ArenaList { void insert(ArenaHeader *arena); }; -struct ArenaLists +class ArenaLists { - private: /* * For each arena kind its free list is represented as the first span with * free things. Initially all the spans are initialized as empty. After we @@ -684,7 +683,7 @@ class GCHelperThread { bool backgroundAllocation; - friend struct js::gc::ArenaLists; + friend class js::gc::ArenaLists; void replenishAndFreeLater(void *ptr); diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index 9bd3dbe1d..5246aab34 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -2087,7 +2087,7 @@ StackTypeSet::convertDoubleElements(JSContext *cx) // double in their element types (as the conversion may render the type // information incorrect), nor for non-array objects (as their elements // may point to emptyObjectElements, which cannot be converted). - if (!types->hasType(Type::DoubleType()) || type->clasp != &ArrayClass) { + if (!types->hasType(Type::DoubleType()) || type->clasp != &ArrayObject::class_) { dontConvert = true; alwaysConvert = false; continue; @@ -3181,7 +3181,7 @@ TypeCompartment::fixArrayType(JSContext *cx, JSObject *obj) * If the array is heterogenous, keep the existing type object, which has * unknown properties. */ - JS_ASSERT(obj->isArray()); + JS_ASSERT(obj->is()); unsigned len = obj->getDenseInitializedLength(); if (len == 0) @@ -3210,7 +3210,7 @@ TypeCompartment::fixArrayType(JSContext *cx, JSObject *obj) Rooted origType(cx, type); /* Make a new type to use for future arrays with the same elements. */ RootedObject objProto(cx, obj->getProto()); - Rooted objType(cx, newTypeObject(cx, &ArrayClass, objProto)); + Rooted objType(cx, newTypeObject(cx, &ArrayObject::class_, objProto)); if (!objType) { cx->compartment()->types.setPendingNukeTypes(cx); return; @@ -6010,7 +6010,7 @@ JSObject::makeLazyType(JSContext *cx, HandleObject obj) if (obj->isIndexed()) type->flags |= OBJECT_FLAG_SPARSE_INDEXES; - if (obj->isArray() && obj->getArrayLength() > INT32_MAX) + if (obj->is() && obj->as().length() > INT32_MAX) type->flags |= OBJECT_FLAG_LENGTH_OVERFLOW; obj->type_ = type; diff --git a/js/src/jsinferinlines.h b/js/src/jsinferinlines.h index d4c57a1ca..9a4b43219 100644 --- a/js/src/jsinferinlines.h +++ b/js/src/jsinferinlines.h @@ -19,6 +19,7 @@ #include "builtin/ParallelArray.h" #include "jit/IonFrames.h" #include "js/RootingAPI.h" +#include "vm/ArrayObject.h" #include "vm/BooleanObject.h" #include "vm/GlobalObject.h" #include "vm/NumberObject.h" @@ -465,7 +466,7 @@ GetClassForProtoKey(JSProtoKey key) case JSProto_Object: return &ObjectClass; case JSProto_Array: - return &ArrayClass; + return &ArrayObject::class_; case JSProto_Number: return &NumberObject::class_; diff --git a/js/src/jsmemorymetrics.cpp b/js/src/jsmemorymetrics.cpp index 5851e0c1d..3a5f2f189 100644 --- a/js/src/jsmemorymetrics.cpp +++ b/js/src/jsmemorymetrics.cpp @@ -175,7 +175,7 @@ StatsCellCallback(JSRuntime *rt, void *data, void *thing, JSGCTraceKind traceKin CompartmentStats *cStats = GetCompartmentStats(obj->compartment()); if (obj->is()) cStats->gcHeapObjectsFunction += thingSize; - else if (obj->isArray()) + else if (obj->is()) cStats->gcHeapObjectsDenseArray += thingSize; else if (obj->isCrossCompartmentWrapper()) cStats->gcHeapObjectsCrossCompartmentWrapper += thingSize; diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index fa2899b93..e7f4410c5 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -418,24 +418,26 @@ Class NumberObject::class_ = { static JSBool Number(JSContext *cx, unsigned argc, Value *vp) { - /* Sample JS_CALLEE before clobbering. */ - bool isConstructing = IsConstructing(vp); + CallArgs args = CallArgsFromVp(argc, vp); - if (argc > 0) { - if (!ToNumber(cx, &vp[2])) + /* Sample JS_CALLEE before clobbering. */ + bool isConstructing = IsConstructing(args); + + if (args.length() > 0) { + if (!ToNumber(cx, args.handleAt(0))) return false; - vp[0] = vp[2]; + args.rval().set(args[0]); } else { - vp[0].setInt32(0); + args.rval().setInt32(0); } if (!isConstructing) return true; - JSObject *obj = NumberObject::create(cx, vp[0].toNumber()); + JSObject *obj = NumberObject::create(cx, args.rval().toNumber()); if (!obj) return false; - vp->setObject(*obj); + args.rval().setObject(*obj); return true; } diff --git a/js/src/jsnum.h b/js/src/jsnum.h index 77a3f000b..24d4c495b 100644 --- a/js/src/jsnum.h +++ b/js/src/jsnum.h @@ -148,23 +148,20 @@ GetPrefixInteger(JSContext *cx, const jschar *start, const jschar *end, int base /* ES5 9.3 ToNumber, overwriting *vp with the appropriate number value. */ JS_ALWAYS_INLINE bool -ToNumber(JSContext *cx, Value *vp) +ToNumber(JSContext *cx, JS::MutableHandleValue vp) { #ifdef DEBUG - { - SkipRoot skip(cx, vp); - MaybeCheckStackRoots(cx); - } + MaybeCheckStackRoots(cx); #endif - if (vp->isNumber()) + if (vp.isNumber()) return true; double d; - extern bool ToNumberSlow(JSContext *cx, js::Value v, double *dp); - if (!ToNumberSlow(cx, *vp, &d)) + extern bool ToNumberSlow(JSContext *cx, Value v, double *dp); + if (!ToNumberSlow(cx, vp, &d)) return false; - vp->setNumber(d); + vp.setNumber(d); return true; } diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 4bd3cb4c9..90b160683 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -37,6 +37,7 @@ #include "jit/BaselineJIT.h" #include "js/MemoryMetrics.h" #include "vm/Interpreter.h" +#include "vm/RegExpStaticsObject.h" #include "vm/Shape.h" #include "jsatominlines.h" @@ -45,6 +46,7 @@ #include "jscompartmentinlines.h" #include "jstypedarrayinlines.h" #include "builtin/Iterator-inl.h" +#include "vm/ArrayObject-inl.h" #include "vm/BooleanObject-inl.h" #include "vm/NumberObject-inl.h" #include "vm/RegExpStatics-inl.h" @@ -968,11 +970,9 @@ DefinePropertyOnObject(JSContext *cx, HandleObject obj, HandleId id, const PropD /* ES6 20130308 draft 8.4.2.1 [[DefineOwnProperty]] */ static JSBool -DefinePropertyOnArray(JSContext *cx, HandleObject obj, HandleId id, const PropDesc &desc, +DefinePropertyOnArray(JSContext *cx, Handle arr, HandleId id, const PropDesc &desc, bool throwError, bool *rval) { - JS_ASSERT(obj->isArray()); - /* Step 2. */ if (id == NameToId(cx->names().length)) { // Canonicalize value, if necessary, before proceeding any further. It @@ -989,7 +989,7 @@ DefinePropertyOnArray(JSContext *cx, HandleObject obj, HandleId id, const PropDe return false; v.setNumber(newLen); } else { - v.setNumber(obj->getArrayLength()); + v.setNumber(arr->length()); } if (desc.hasConfigurable() && desc.configurable()) @@ -1000,8 +1000,8 @@ DefinePropertyOnArray(JSContext *cx, HandleObject obj, HandleId id, const PropDe if (desc.isAccessorDescriptor()) return Reject(cx, id, JSMSG_CANT_REDEFINE_PROP, throwError, rval); - unsigned attrs = obj->nativeLookup(cx, id)->attributes(); - if (!obj->arrayLengthIsWritable()) { + unsigned attrs = arr->nativeLookup(cx, id)->attributes(); + if (!arr->lengthIsWritable()) { if (desc.hasWritable() && desc.writable()) return Reject(cx, id, JSMSG_CANT_REDEFINE_PROP, throwError, rval); } else { @@ -1009,33 +1009,35 @@ DefinePropertyOnArray(JSContext *cx, HandleObject obj, HandleId id, const PropDe attrs = attrs | JSPROP_READONLY; } - return ArraySetLength(cx, obj, id, attrs, v, throwError); + return ArraySetLength(cx, arr, id, attrs, v, throwError); } /* Step 3. */ uint32_t index; if (js_IdIsIndex(id, &index)) { /* Step 3b. */ - uint32_t oldLen = obj->getArrayLength(); + uint32_t oldLen = arr->length(); /* Steps 3a, 3e. */ - if (index >= oldLen && !obj->arrayLengthIsWritable()) - return Reject(cx, obj, JSMSG_CANT_APPEND_TO_ARRAY, throwError, rval); + if (index >= oldLen && !arr->lengthIsWritable()) + return Reject(cx, arr, JSMSG_CANT_APPEND_TO_ARRAY, throwError, rval); /* Steps 3f-j. */ - return DefinePropertyOnObject(cx, obj, id, desc, throwError, rval); + return DefinePropertyOnObject(cx, arr, id, desc, throwError, rval); } /* Step 4. */ - return DefinePropertyOnObject(cx, obj, id, desc, throwError, rval); + return DefinePropertyOnObject(cx, arr, id, desc, throwError, rval); } bool js::DefineProperty(JSContext *cx, HandleObject obj, HandleId id, const PropDesc &desc, bool throwError, bool *rval) { - if (obj->isArray()) - return DefinePropertyOnArray(cx, obj, id, desc, throwError, rval); + if (obj->is()) { + Rooted arr(cx, &obj->as()); + return DefinePropertyOnArray(cx, arr, id, desc, throwError, rval); + } if (obj->getOps()->lookupGeneric) { /* @@ -1228,7 +1230,7 @@ JSObject::sealOrFreeze(JSContext *cx, HandleObject obj, ImmutabilityType it) // arrays with non-writable length. We don't need to do anything special // for that, because capacity was zeroed out by preventExtensions. (See // the assertion before the if-else above.) - if (it == FREEZE && obj->isArray()) + if (it == FREEZE && obj->is()) obj->getElementsHeader()->setNonwritableArrayLength(); return true; @@ -1291,7 +1293,7 @@ JSObject::className(JSContext *cx, HandleObject obj) static inline gc::AllocKind NewObjectGCKind(js::Class *clasp) { - if (clasp == &ArrayClass) + if (clasp == &ArrayObject::class_) return gc::FINALIZE_OBJECT8; if (clasp == &JSFunction::class_) return gc::FINALIZE_OBJECT2; @@ -1302,7 +1304,7 @@ static inline JSObject * NewObject(JSContext *cx, Class *clasp, types::TypeObject *type_, JSObject *parent, gc::AllocKind kind, NewObjectKind newKind) { - JS_ASSERT(clasp != &ArrayClass); + JS_ASSERT(clasp != &ArrayObject::class_); JS_ASSERT_IF(clasp == &JSFunction::class_, kind == JSFunction::FinalizeKind || kind == JSFunction::ExtendedFinalizeKind); JS_ASSERT_IF(parent, &parent->global() == cx->compartment()->maybeGlobal()); @@ -2073,7 +2075,7 @@ JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved & JS_ASSERT(!a->is() && !b->is()); /* Arrays can use their fixed storage for elements. */ - JS_ASSERT(!a->isArray() && !b->isArray()); + JS_ASSERT(!a->is() && !b->is()); /* * Callers should not try to swap ArrayBuffer objects, @@ -2891,8 +2893,6 @@ bool JSObject::growElements(ThreadSafeContext *tcx, uint32_t newcap) { JS_ASSERT(isExtensible()); - JS_ASSERT_IF(isArray() && !arrayLengthIsWritable(), - newcap <= getArrayLength()); /* * When an object with CAPACITY_DOUBLING_MAX or fewer elements needs to @@ -2912,7 +2912,8 @@ JSObject::growElements(ThreadSafeContext *tcx, uint32_t newcap) : oldcap + (oldcap >> 3); uint32_t actualCapacity; - if (isArray() && !arrayLengthIsWritable()) { + if (is() && !as().lengthIsWritable()) { + JS_ASSERT(newcap <= as().length()); // Preserve the |capacity <= length| invariant for arrays with // non-writable length. See also js::ArraySetLength which initially // enforces this requirement. @@ -3387,10 +3388,11 @@ CallAddPropertyHookDense(JSContext *cx, Class *clasp, HandleObject obj, uint32_t HandleValue nominal) { /* Inline addProperty for array objects. */ - if (obj->isArray()) { - uint32_t length = obj->getArrayLength(); + if (obj->is()) { + Rooted arr(cx, &obj->as()); + uint32_t length = arr->length(); if (index >= length) - JSObject::setArrayLength(cx, obj, index + 1); + ArrayObject::setLength(cx, arr, index + 1); return true; } @@ -3438,14 +3440,15 @@ DefinePropertyOrElement(JSContext *cx, HandleObject obj, HandleId id, } } - if (obj->isArray()) { + if (obj->is()) { + Rooted arr(cx, &obj->as()); if (id == NameToId(cx->names().length)) - return ArraySetLength(cx, obj, id, attrs, value, setterIsStrict); + return ArraySetLength(cx, arr, id, attrs, value, setterIsStrict); uint32_t index; if (js_IdIsIndex(id, &index)) { bool definesPast; - if (!WouldDefinePastNonwritableLength(cx, obj, index, setterIsStrict, &definesPast)) + if (!WouldDefinePastNonwritableLength(cx, arr, index, setterIsStrict, &definesPast)) return false; if (definesPast) return true; @@ -4535,8 +4538,10 @@ baseops::SetPropertyHelper(JSContext *cx, HandleObject obj, HandleObject receive return true; } - if (obj->isArray() && id == NameToId(cx->names().length)) - return ArraySetLength(cx, obj, id, attrs, vp, strict); + if (obj->is() && id == NameToId(cx->names().length)) { + Rooted arr(cx, &obj->as()); + return ArraySetLength(cx, arr, id, attrs, vp, strict); + } if (!shape) { if (!obj->isExtensible()) { @@ -5239,6 +5244,12 @@ DumpProperty(JSObject *obj, Shape &shape) fprintf(stderr, "\n"); } +bool +JSObject::isProxySlow() const +{ + return isProxy(); +} + void JSObject::dump() { @@ -5449,7 +5460,7 @@ JSObject::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::ObjectsExt // Note that sizes->private_ is measured elsewhere. if (is()) { sizes->argumentsData = as().sizeOfMisc(mallocSizeOf); - } else if (isRegExpStatics()) { + } else if (is()) { sizes->regExpStatics = js::SizeOfRegExpStaticsData(this, mallocSizeOf); } else if (is()) { sizes->propertyIteratorData = as().sizeOfMisc(mallocSizeOf); diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 3eacd2dc8..846f36de3 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -188,15 +188,11 @@ DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, JSBool *succeeded); } /* namespace js::baseops */ -extern Class ArrayClass; -extern Class DateClass; -extern Class ErrorClass; extern Class IntlClass; extern Class JSONClass; extern Class MathClass; extern Class ObjectClass; extern Class ProxyClass; -extern Class RegExpStaticsClass; class ArrayBufferObject; class GlobalObject; @@ -333,13 +329,15 @@ class JSObject : public js::ObjectImpl /* Accessors for properties. */ /* Whether a slot is at a fixed offset from this object. */ - inline bool isFixedSlot(size_t slot); + bool isFixedSlot(size_t slot) { + return slot < numFixedSlots(); + } /* Index into the dynamic slots array to use for a dynamic slot. */ - inline size_t dynamicSlotIndex(size_t slot); - - /* Get a raw pointer to the object's properties. */ - inline const js::HeapSlot *getRawSlots(); + size_t dynamicSlotIndex(size_t slot) { + JS_ASSERT(slot >= numFixedSlots()); + return slot - numFixedSlots(); + } /* * Grow or shrink slots immediately before changing the slot span. @@ -409,7 +407,11 @@ class JSObject : public js::ObjectImpl * If obj is a proxy and the proto is lazy, this code may allocate or * GC in order to compute the proto. Currently, it will not run JS code. */ - inline JSObject *getProto() const; + bool isProxySlow() const; + JSObject *getProto() const { + JS_ASSERT(!isProxySlow()); + return js::ObjectImpl::getProto(); + } static inline bool getProto(JSContext *cx, js::HandleObject obj, js::MutableHandleObject protop); @@ -529,9 +531,18 @@ class JSObject : public js::ObjectImpl inline bool ensureElements(JSContext *cx, uint32_t cap); bool growElements(js::ThreadSafeContext *tcx, uint32_t newcap); void shrinkElements(JSContext *cx, uint32_t cap); - inline void setDynamicElements(js::ObjectElements *header); + void setDynamicElements(js::ObjectElements *header) { + JS_ASSERT(!hasDynamicElements()); + elements = header->elements(); + JS_ASSERT(hasDynamicElements()); + } + + uint32_t getDenseCapacity() { + JS_ASSERT(isNativeSlow()); + JS_ASSERT(getElementsHeader()->capacity >= getElementsHeader()->initializedLength); + return getElementsHeader()->capacity; + } - inline uint32_t getDenseCapacity(); inline void setDenseInitializedLength(uint32_t length); inline void ensureDenseInitializedLength(JSContext *cx, uint32_t index, uint32_t extra); inline void setDenseElement(uint32_t index, const js::Value &val); @@ -548,7 +559,12 @@ class JSObject : public js::ObjectImpl inline void initDenseElements(uint32_t dstStart, const js::Value *src, uint32_t count); inline void moveDenseElements(uint32_t dstStart, uint32_t srcStart, uint32_t count); inline void moveDenseElementsUnbarriered(uint32_t dstStart, uint32_t srcStart, uint32_t count); - inline bool shouldConvertDoubleElements(); + + bool shouldConvertDoubleElements() { + JS_ASSERT(isNativeSlow()); + return getElementsHeader()->shouldConvertDoubleElements(); + } + inline void setShouldConvertDoubleElements(); /* Packed information for this object's elements. */ @@ -596,41 +612,6 @@ class JSObject : public js::ObjectImpl */ static EnsureDenseResult maybeDensifySparseElements(JSContext *cx, js::HandleObject obj); - /* Array specific accessors. */ - inline bool arrayLengthIsWritable() const; - inline uint32_t getArrayLength() const; - static inline void setArrayLength(JSContext *cx, js::HandleObject obj, uint32_t length); - inline void setArrayLengthInt32(uint32_t length); - - public: - /* - * Date-specific getters and setters. - */ - - static const uint32_t JSSLOT_DATE_UTC_TIME = 0; - static const uint32_t JSSLOT_DATE_TZA = 1; - - /* - * Cached slots holding local properties of the date. - * These are undefined until the first actual lookup occurs - * and are reset to undefined whenever the date's time is modified. - */ - static const uint32_t JSSLOT_DATE_COMPONENTS_START = 2; - - static const uint32_t JSSLOT_DATE_LOCAL_TIME = JSSLOT_DATE_COMPONENTS_START + 0; - static const uint32_t JSSLOT_DATE_LOCAL_YEAR = JSSLOT_DATE_COMPONENTS_START + 1; - static const uint32_t JSSLOT_DATE_LOCAL_MONTH = JSSLOT_DATE_COMPONENTS_START + 2; - static const uint32_t JSSLOT_DATE_LOCAL_DATE = JSSLOT_DATE_COMPONENTS_START + 3; - static const uint32_t JSSLOT_DATE_LOCAL_DAY = JSSLOT_DATE_COMPONENTS_START + 4; - static const uint32_t JSSLOT_DATE_LOCAL_HOURS = JSSLOT_DATE_COMPONENTS_START + 5; - static const uint32_t JSSLOT_DATE_LOCAL_MINUTES = JSSLOT_DATE_COMPONENTS_START + 6; - static const uint32_t JSSLOT_DATE_LOCAL_SECONDS = JSSLOT_DATE_COMPONENTS_START + 7; - - static const uint32_t DATE_CLASS_RESERVED_SLOTS = JSSLOT_DATE_LOCAL_SECONDS + 1; - - inline const js::Value &getDateUTCTime() const; - inline void setDateUTCTime(const js::Value &pthis); - public: /* * Iterator-specific getters and setters. @@ -641,7 +622,9 @@ class JSObject : public js::ObjectImpl /* * Back to generic stuff. */ - inline bool isCallable(); + bool isCallable() { + return getClass()->isCallable(); + } inline void finish(js::FreeOp *fop); JS_ALWAYS_INLINE void finalize(js::FreeOp *fop); @@ -751,91 +734,196 @@ class JSObject : public js::ObjectImpl /* Clear the scope, making it empty. */ static void clear(JSContext *cx, js::HandleObject obj); - static inline JSBool lookupGeneric(JSContext *cx, js::HandleObject obj, - js::HandleId id, - js::MutableHandleObject objp, js::MutableHandleShape propp); - static inline JSBool lookupProperty(JSContext *cx, js::HandleObject obj, - js::PropertyName *name, - js::MutableHandleObject objp, js::MutableHandleShape propp); - static inline JSBool lookupElement(JSContext *cx, js::HandleObject obj, - uint32_t index, - js::MutableHandleObject objp, js::MutableHandleShape propp); - static inline JSBool lookupSpecial(JSContext *cx, js::HandleObject obj, - js::SpecialId sid, - js::MutableHandleObject objp, js::MutableHandleShape propp); + static JSBool lookupGeneric(JSContext *cx, js::HandleObject obj, js::HandleId id, + js::MutableHandleObject objp, js::MutableHandleShape propp) + { + /* NB: The logic of lookupGeneric is implicitly reflected in IonBuilder.cpp's + * |CanEffectlesslyCallLookupGenericOnObject| logic. + * If this changes, please remember to update the logic there as well. + */ + js::LookupGenericOp op = obj->getOps()->lookupGeneric; + if (op) + return op(cx, obj, id, objp, propp); + return js::baseops::LookupProperty(cx, obj, id, objp, propp); + } - static inline JSBool defineGeneric(JSContext *cx, js::HandleObject obj, + static JSBool lookupProperty(JSContext *cx, js::HandleObject obj, js::PropertyName *name, + js::MutableHandleObject objp, js::MutableHandleShape propp) + { + JS::RootedId id(cx, js::NameToId(name)); + return lookupGeneric(cx, obj, id, objp, propp); + } + + static JSBool lookupElement(JSContext *cx, js::HandleObject obj, uint32_t index, + js::MutableHandleObject objp, js::MutableHandleShape propp) + { + js::LookupElementOp op = obj->getOps()->lookupElement; + return (op ? op : js::baseops::LookupElement)(cx, obj, index, objp, propp); + } + + static JSBool lookupSpecial(JSContext *cx, js::HandleObject obj, js::SpecialId sid, + js::MutableHandleObject objp, js::MutableHandleShape propp) + { + JS::RootedId id(cx, SPECIALID_TO_JSID(sid)); + return lookupGeneric(cx, obj, id, objp, propp); + } + + static JSBool defineGeneric(JSContext *cx, js::HandleObject obj, js::HandleId id, js::HandleValue value, JSPropertyOp getter = JS_PropertyStub, JSStrictPropertyOp setter = JS_StrictPropertyStub, - unsigned attrs = JSPROP_ENUMERATE); - static inline JSBool defineProperty(JSContext *cx, js::HandleObject obj, - js::PropertyName *name, js::HandleValue value, - JSPropertyOp getter = JS_PropertyStub, - JSStrictPropertyOp setter = JS_StrictPropertyStub, - unsigned attrs = JSPROP_ENUMERATE); + unsigned attrs = JSPROP_ENUMERATE) + { + JS_ASSERT(!(attrs & JSPROP_NATIVE_ACCESSORS)); + js::DefineGenericOp op = obj->getOps()->defineGeneric; + return (op ? op : js::baseops::DefineGeneric)(cx, obj, id, value, getter, setter, attrs); + } - static inline JSBool defineElement(JSContext *cx, js::HandleObject obj, - uint32_t index, js::HandleValue value, - JSPropertyOp getter = JS_PropertyStub, - JSStrictPropertyOp setter = JS_StrictPropertyStub, - unsigned attrs = JSPROP_ENUMERATE); - static inline JSBool defineSpecial(JSContext *cx, js::HandleObject obj, - js::SpecialId sid, js::HandleValue value, - JSPropertyOp getter = JS_PropertyStub, - JSStrictPropertyOp setter = JS_StrictPropertyStub, - unsigned attrs = JSPROP_ENUMERATE); + static JSBool defineProperty(JSContext *cx, js::HandleObject obj, + js::PropertyName *name, js::HandleValue value, + JSPropertyOp getter = JS_PropertyStub, + JSStrictPropertyOp setter = JS_StrictPropertyStub, + unsigned attrs = JSPROP_ENUMERATE) + { + JS::RootedId id(cx, js::NameToId(name)); + return defineGeneric(cx, obj, id, value, getter, setter, attrs); + } - static inline JSBool getGeneric(JSContext *cx, js::HandleObject obj, - js::HandleObject receiver, - js::HandleId id, js::MutableHandleValue vp); - static inline JSBool getGenericNoGC(JSContext *cx, JSObject *obj, JSObject *receiver, - jsid id, js::Value *vp); - static inline JSBool getProperty(JSContext *cx, js::HandleObject obj, - js::HandleObject receiver, - js::PropertyName *name, js::MutableHandleValue vp); - static inline JSBool getPropertyNoGC(JSContext *cx, JSObject *obj, JSObject *receiver, - js::PropertyName *name, js::Value *vp); - static inline JSBool getElement(JSContext *cx, js::HandleObject obj, - js::HandleObject receiver, + static JSBool defineElement(JSContext *cx, js::HandleObject obj, + uint32_t index, js::HandleValue value, + JSPropertyOp getter = JS_PropertyStub, + JSStrictPropertyOp setter = JS_StrictPropertyStub, + unsigned attrs = JSPROP_ENUMERATE) + { + js::DefineElementOp op = obj->getOps()->defineElement; + return (op ? op : js::baseops::DefineElement)(cx, obj, index, value, getter, setter, attrs); + } + + static JSBool defineSpecial(JSContext *cx, js::HandleObject obj, + js::SpecialId sid, js::HandleValue value, + JSPropertyOp getter = JS_PropertyStub, + JSStrictPropertyOp setter = JS_StrictPropertyStub, + unsigned attrs = JSPROP_ENUMERATE) + { + JS::RootedId id(cx, SPECIALID_TO_JSID(sid)); + return defineGeneric(cx, obj, id, value, getter, setter, attrs); + } + + static JSBool getGeneric(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, + js::HandleId id, js::MutableHandleValue vp) + { + js::GenericIdOp op = obj->getOps()->getGeneric; + if (op) { + if (!op(cx, obj, receiver, id, vp)) + return false; + } else { + if (!js::baseops::GetProperty(cx, obj, receiver, id, vp)) + return false; + } + return true; + } + + static JSBool getGenericNoGC(JSContext *cx, JSObject *obj, JSObject *receiver, + jsid id, js::Value *vp) + { + js::GenericIdOp op = obj->getOps()->getGeneric; + if (op) + return false; + return js::baseops::GetPropertyNoGC(cx, obj, receiver, id, vp); + } + + static JSBool getProperty(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, + js::PropertyName *name, js::MutableHandleValue vp) + { + JS::RootedId id(cx, js::NameToId(name)); + return getGeneric(cx, obj, receiver, id, vp); + } + + static JSBool getPropertyNoGC(JSContext *cx, JSObject *obj, JSObject *receiver, + js::PropertyName *name, js::Value *vp) + { + return getGenericNoGC(cx, obj, receiver, js::NameToId(name), vp); + } + + static inline JSBool getElement(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, uint32_t index, js::MutableHandleValue vp); static inline JSBool getElementNoGC(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t index, js::Value *vp); + /* If element is not present (e.g. array hole) *present is set to false and the contents of *vp are unusable garbage. */ static inline JSBool getElementIfPresent(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, uint32_t index, js::MutableHandleValue vp, bool *present); - static inline JSBool getSpecial(JSContext *cx, js::HandleObject obj, - js::HandleObject receiver, js::SpecialId sid, - js::MutableHandleValue vp); - static inline JSBool setGeneric(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, - js::HandleId id, - js::MutableHandleValue vp, JSBool strict); - static inline JSBool setProperty(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, - js::PropertyName *name, - js::MutableHandleValue vp, JSBool strict); - static inline JSBool setElement(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, - uint32_t index, - js::MutableHandleValue vp, JSBool strict); - static inline JSBool setSpecial(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, - js::SpecialId sid, - js::MutableHandleValue vp, JSBool strict); + static JSBool getSpecial(JSContext *cx, js::HandleObject obj, + js::HandleObject receiver, js::SpecialId sid, + js::MutableHandleValue vp) + { + JS::RootedId id(cx, SPECIALID_TO_JSID(sid)); + return getGeneric(cx, obj, receiver, id, vp); + } + + static JSBool setGeneric(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, + js::HandleId id, js::MutableHandleValue vp, JSBool strict) + { + if (obj->getOps()->setGeneric) + return nonNativeSetProperty(cx, obj, id, vp, strict); + return js::baseops::SetPropertyHelper(cx, obj, receiver, id, 0, vp, strict); + } + + static JSBool setProperty(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, + js::PropertyName *name, + js::MutableHandleValue vp, JSBool strict) + { + JS::RootedId id(cx, js::NameToId(name)); + return setGeneric(cx, obj, receiver, id, vp, strict); + } + + static JSBool setElement(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, + uint32_t index, js::MutableHandleValue vp, JSBool strict) + { + if (obj->getOps()->setElement) + return nonNativeSetElement(cx, obj, index, vp, strict); + return js::baseops::SetElementHelper(cx, obj, receiver, index, 0, vp, strict); + } + + static JSBool setSpecial(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, + js::SpecialId sid, js::MutableHandleValue vp, JSBool strict) + { + JS::RootedId id(cx, SPECIALID_TO_JSID(sid)); + return setGeneric(cx, obj, receiver, id, vp, strict); + } + static JSBool nonNativeSetProperty(JSContext *cx, js::HandleObject obj, js::HandleId id, js::MutableHandleValue vp, JSBool strict); static JSBool nonNativeSetElement(JSContext *cx, js::HandleObject obj, uint32_t index, js::MutableHandleValue vp, JSBool strict); - static inline JSBool getGenericAttributes(JSContext *cx, js::HandleObject obj, - js::HandleId id, unsigned *attrsp); - static inline JSBool getPropertyAttributes(JSContext *cx, js::HandleObject obj, - js::PropertyName *name, unsigned *attrsp); + static JSBool getGenericAttributes(JSContext *cx, js::HandleObject obj, + js::HandleId id, unsigned *attrsp) + { + js::GenericAttributesOp op = obj->getOps()->getGenericAttributes; + return (op ? op : js::baseops::GetAttributes)(cx, obj, id, attrsp); + } + + static JSBool getPropertyAttributes(JSContext *cx, js::HandleObject obj, + js::PropertyName *name, unsigned *attrsp) + { + JS::RootedId id(cx, js::NameToId(name)); + return getGenericAttributes(cx, obj, id, attrsp); + } + static inline JSBool getElementAttributes(JSContext *cx, js::HandleObject obj, uint32_t index, unsigned *attrsp); - static inline JSBool getSpecialAttributes(JSContext *cx, js::HandleObject obj, - js::SpecialId sid, unsigned *attrsp); + + static JSBool getSpecialAttributes(JSContext *cx, js::HandleObject obj, + js::SpecialId sid, unsigned *attrsp) + { + JS::RootedId id(cx, SPECIALID_TO_JSID(sid)); + return getGenericAttributes(cx, obj, id, attrsp); + } static inline JSBool setGenericAttributes(JSContext *cx, js::HandleObject obj, js::HandleId id, unsigned *attrsp); @@ -856,11 +944,31 @@ class JSObject : public js::ObjectImpl static bool deleteByValue(JSContext *cx, js::HandleObject obj, const js::Value &property, JSBool *succeeded); - static inline bool enumerate(JSContext *cx, JS::HandleObject obj, JSIterateOp iterop, - JS::MutableHandleValue statep, JS::MutableHandleId idp); - static inline bool defaultValue(JSContext *cx, js::HandleObject obj, - JSType hint, js::MutableHandleValue vp); - static inline JSObject *thisObject(JSContext *cx, js::HandleObject obj); + static bool enumerate(JSContext *cx, JS::HandleObject obj, JSIterateOp iterop, + JS::MutableHandleValue statep, JS::MutableHandleId idp) + { + JSNewEnumerateOp op = obj->getOps()->enumerate; + return (op ? op : JS_EnumerateState)(cx, obj, iterop, statep, idp); + } + + static bool defaultValue(JSContext *cx, js::HandleObject obj, JSType hint, + js::MutableHandleValue vp) + { + JSConvertOp op = obj->getClass()->convert; + bool ok; + if (op == JS_ConvertStub) + ok = js::DefaultValue(cx, obj, hint, vp); + else + ok = op(cx, obj, hint, vp); + JS_ASSERT_IF(ok, vp.isPrimitive()); + return ok; + } + + static JSObject *thisObject(JSContext *cx, js::HandleObject obj) + { + JSObjectOp op = obj->getOps()->thisObject; + return op ? op(cx, obj) : obj; + } static bool thisObject(JSContext *cx, const js::Value &v, js::Value *vp); @@ -912,12 +1020,8 @@ class JSObject : public js::ObjectImpl } /* Direct subtypes of JSObject: */ - inline bool isArray() const { return hasClass(&js::ArrayClass); } - inline bool isDate() const { return hasClass(&js::DateClass); } - inline bool isError() const { return hasClass(&js::ErrorClass); } inline bool isObject() const { return hasClass(&js::ObjectClass); } using js::ObjectImpl::isProxy; - inline bool isRegExpStatics() const { return hasClass(&js::RegExpStaticsClass); } inline bool isTypedArray() const; /* Subtypes of Proxy. */ @@ -969,6 +1073,28 @@ struct JSObject_Slots8 : JSObject { js::Value fslots[8]; }; struct JSObject_Slots12 : JSObject { js::Value fslots[12]; }; struct JSObject_Slots16 : JSObject { js::Value fslots[16]; }; +static inline bool +js_IsCallable(const js::Value &v) +{ + return v.isObject() && v.toObject().isCallable(); +} + +inline JSObject * +GetInnerObject(JSContext *cx, js::HandleObject obj) +{ + if (JSObjectOp op = obj->getClass()->ext.innerObject) + return op(cx, obj); + return obj; +} + +inline JSObject * +GetOuterObject(JSContext *cx, js::HandleObject obj) +{ + if (JSObjectOp op = obj->getClass()->ext.outerObject) + return op(cx, obj); + return obj; +} + class JSValueArray { public: jsval *array; @@ -1361,9 +1487,6 @@ NonNullObject(JSContext *cx, const Value &v); extern const char * InformalValueTypeName(const Value &v); -inline void -DestroyIdArray(FreeOp *fop, JSIdArray *ida); - extern bool GetFirstArgumentAsObject(JSContext *cx, const CallArgs &args, const char *method, MutableHandleObject objp); diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 86c4f1430..efc63aa83 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -11,6 +11,8 @@ #include "jswrapper.h" +#include "vm/ArrayObject.h" +#include "vm/DateObject.h" #include "vm/NumberObject.h" #include "vm/Probes.h" #include "vm/StringObject.h" @@ -20,68 +22,6 @@ #include "vm/ObjectImpl-inl.h" -/* static */ inline bool -JSObject::enumerate(JSContext *cx, JS::HandleObject obj, JSIterateOp iterop, - JS::MutableHandleValue statep, JS::MutableHandleId idp) -{ - JSNewEnumerateOp op = obj->getOps()->enumerate; - return (op ? op : JS_EnumerateState)(cx, obj, iterop, statep, idp); -} - -/* static */ inline bool -JSObject::defaultValue(JSContext *cx, js::HandleObject obj, JSType hint, js::MutableHandleValue vp) -{ - JSConvertOp op = obj->getClass()->convert; - bool ok; - if (op == JS_ConvertStub) - ok = js::DefaultValue(cx, obj, hint, vp); - else - ok = op(cx, obj, hint, vp); - JS_ASSERT_IF(ok, vp.isPrimitive()); - return ok; -} - -/* static */ inline JSObject * -JSObject::thisObject(JSContext *cx, js::HandleObject obj) -{ - JSObjectOp op = obj->getOps()->thisObject; - return op ? op(cx, obj) : obj; -} - -/* static */ inline JSBool -JSObject::setGeneric(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, - js::HandleId id, js::MutableHandleValue vp, JSBool strict) -{ - if (obj->getOps()->setGeneric) - return nonNativeSetProperty(cx, obj, id, vp, strict); - return js::baseops::SetPropertyHelper(cx, obj, receiver, id, 0, vp, strict); -} - -/* static */ inline JSBool -JSObject::setProperty(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, - js::PropertyName *name, js::MutableHandleValue vp, JSBool strict) -{ - JS::RootedId id(cx, js::NameToId(name)); - return setGeneric(cx, obj, receiver, id, vp, strict); -} - -/* static */ inline JSBool -JSObject::setElement(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, - uint32_t index, js::MutableHandleValue vp, JSBool strict) -{ - if (obj->getOps()->setElement) - return nonNativeSetElement(cx, obj, index, vp, strict); - return js::baseops::SetElementHelper(cx, obj, receiver, index, 0, vp, strict); -} - -/* static */ inline JSBool -JSObject::setSpecial(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, - js::SpecialId sid, js::MutableHandleValue vp, JSBool strict) -{ - JS::RootedId id(cx, SPECIALID_TO_JSID(sid)); - return setGeneric(cx, obj, receiver, id, vp, strict); -} - /* static */ inline JSBool JSObject::setGenericAttributes(JSContext *cx, js::HandleObject obj, js::HandleId id, unsigned *attrsp) @@ -122,46 +62,6 @@ JSObject::changePropertyAttributes(JSContext *cx, js::HandleObject obj, return !!changeProperty(cx, obj, shape, attrs, 0, shape->getter(), shape->setter()); } -/* static */ inline JSBool -JSObject::getGeneric(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, - js::HandleId id, js::MutableHandleValue vp) -{ - js::GenericIdOp op = obj->getOps()->getGeneric; - if (op) { - if (!op(cx, obj, receiver, id, vp)) - return false; - } else { - if (!js::baseops::GetProperty(cx, obj, receiver, id, vp)) - return false; - } - return true; -} - -/* static */ inline JSBool -JSObject::getGenericNoGC(JSContext *cx, JSObject *obj, JSObject *receiver, - jsid id, js::Value *vp) -{ - js::GenericIdOp op = obj->getOps()->getGeneric; - if (op) - return false; - return js::baseops::GetPropertyNoGC(cx, obj, receiver, id, vp); -} - -/* static */ inline JSBool -JSObject::getProperty(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, - js::PropertyName *name, js::MutableHandleValue vp) -{ - JS::RootedId id(cx, js::NameToId(name)); - return getGeneric(cx, obj, receiver, id, vp); -} - -/* static */ inline JSBool -JSObject::getPropertyNoGC(JSContext *cx, JSObject *obj, JSObject *receiver, - js::PropertyName *name, js::Value *vp) -{ - return getGenericNoGC(cx, obj, receiver, js::NameToId(name), vp); -} - /* static */ inline bool JSObject::deleteProperty(JSContext *cx, js::HandleObject obj, js::HandlePropertyName name, JSBool *succeeded) @@ -227,19 +127,6 @@ JSObject::getMetadata() const return lastProperty()->getObjectMetadata(); } -inline bool -JSObject::isFixedSlot(size_t slot) -{ - return slot < numFixedSlots(); -} - -inline size_t -JSObject::dynamicSlotIndex(size_t slot) -{ - JS_ASSERT(slot >= numFixedSlots()); - return slot - numFixedSlots(); -} - inline void JSObject::setLastPropertyInfallible(js::Shape *shape) { @@ -278,13 +165,6 @@ JSObject::canRemoveLastProperty() && previous->getObjectFlags() == lastProperty()->getObjectFlags(); } -inline const js::HeapSlot * -JSObject::getRawSlots() -{ - JS_ASSERT(is()); - return slots; -} - inline void JSObject::setReservedSlot(uint32_t index, const js::Value &v) { @@ -314,48 +194,6 @@ JSObject::prepareElementRangeForOverwrite(size_t start, size_t end) elements[i].js::HeapSlot::~HeapSlot(); } -inline uint32_t -JSObject::getArrayLength() const -{ - JS_ASSERT(isArray()); - return getElementsHeader()->length; -} - -inline bool -JSObject::arrayLengthIsWritable() const -{ - JS_ASSERT(isArray()); - return !getElementsHeader()->hasNonwritableArrayLength(); -} - -/* static */ inline void -JSObject::setArrayLength(JSContext *cx, js::HandleObject obj, uint32_t length) -{ - JS_ASSERT(obj->isArray()); - JS_ASSERT(obj->arrayLengthIsWritable()); - - if (length > INT32_MAX) { - /* Track objects with overflowing lengths in type information. */ - js::types::MarkTypeObjectFlags(cx, obj, - js::types::OBJECT_FLAG_LENGTH_OVERFLOW); - jsid lengthId = js::NameToId(cx->names().length); - js::types::AddTypePropertyId(cx, obj, lengthId, - js::types::Type::DoubleType()); - } - - obj->getElementsHeader()->length = length; -} - -inline void -JSObject::setArrayLengthInt32(uint32_t length) -{ - /* Variant of setArrayLength for use on arrays where the length cannot overflow int32_t. */ - JS_ASSERT(isArray()); - JS_ASSERT(arrayLengthIsWritable()); - JS_ASSERT(length <= INT32_MAX); - getElementsHeader()->length = length; -} - inline void JSObject::setDenseInitializedLength(uint32_t length) { @@ -365,25 +203,10 @@ JSObject::setDenseInitializedLength(uint32_t length) getElementsHeader()->initializedLength = length; } -inline uint32_t -JSObject::getDenseCapacity() -{ - JS_ASSERT(isNative()); - JS_ASSERT(getElementsHeader()->capacity >= getElementsHeader()->initializedLength); - return getElementsHeader()->capacity; -} - -inline bool -JSObject::shouldConvertDoubleElements() -{ - JS_ASSERT(isNative()); - return getElementsHeader()->shouldConvertDoubleElements(); -} - inline void JSObject::setShouldConvertDoubleElements() { - JS_ASSERT(isArray() && !hasEmptyElements()); + JS_ASSERT(is() && !hasEmptyElements()); getElementsHeader()->setShouldConvertDoubleElements(); } @@ -395,14 +218,6 @@ JSObject::ensureElements(JSContext *cx, uint32_t capacity) return true; } -inline void -JSObject::setDynamicElements(js::ObjectElements *header) -{ - JS_ASSERT(!hasDynamicElements()); - elements = header->elements(); - JS_ASSERT(hasDynamicElements()); -} - inline void JSObject::setDenseElement(uint32_t index, const js::Value &val) { @@ -603,7 +418,7 @@ inline JSObject::EnsureDenseResult JSObject::parExtendDenseElements(js::ThreadSafeContext *tcx, js::Value *v, uint32_t extra) { JS_ASSERT(isNative()); - JS_ASSERT_IF(isArray(), arrayLengthIsWritable()); + JS_ASSERT_IF(is(), as().lengthIsWritable()); js::ObjectElements *header = getElementsHeader(); uint32_t initializedLength = header->initializedLength; @@ -676,34 +491,6 @@ JSObject::ensureDenseElements(JSContext *cx, uint32_t index, uint32_t extra) return ED_OK; } -namespace js { - -/* - * Any name atom for a function which will be added as a DeclEnv object to the - * scope chain above call objects for fun. - */ -static inline JSAtom * -CallObjectLambdaName(JSFunction &fun) -{ - return fun.isNamedLambda() ? fun.atom() : NULL; -} - -} /* namespace js */ - -inline const js::Value & -JSObject::getDateUTCTime() const -{ - JS_ASSERT(isDate()); - return getFixedSlot(JSSLOT_DATE_UTC_TIME); -} - -inline void -JSObject::setDateUTCTime(const js::Value &time) -{ - JS_ASSERT(isDate()); - setFixedSlot(JSSLOT_DATE_UTC_TIME, time); -} - /* static */ inline bool JSObject::setSingletonType(JSContext *cx, js::HandleObject obj) { @@ -758,13 +545,6 @@ JSObject::setType(js::types::TypeObject *newType) type_ = newType; } -inline JSObject * -JSObject::getProto() const -{ - JS_ASSERT(!isProxy()); - return js::ObjectImpl::getProto(); -} - /* static */ inline bool JSObject::getProto(JSContext *cx, js::HandleObject obj, js::MutableHandleObject protop) { @@ -853,7 +633,7 @@ JSObject::create(JSContext *cx, js::gc::AllocKind kind, js::gc::InitialHeap heap */ JS_ASSERT(shape && type); JS_ASSERT(type->clasp == shape->getObjectClass()); - JS_ASSERT(type->clasp != &js::ArrayClass); + JS_ASSERT(type->clasp != &js::ArrayObject::class_); JS_ASSERT(js::gc::GetGCKindSlots(kind, type->clasp) == shape->numFixedSlots()); JS_ASSERT_IF(type->clasp->flags & JSCLASS_BACKGROUND_FINALIZE, IsBackgroundFinalized(kind)); JS_ASSERT_IF(type->clasp->finalize, heap == js::gc::TenuredHeap); @@ -903,7 +683,7 @@ JSObject::createArray(JSContext *cx, js::gc::AllocKind kind, js::gc::InitialHeap { JS_ASSERT(shape && type); JS_ASSERT(type->clasp == shape->getObjectClass()); - JS_ASSERT(type->clasp == &js::ArrayClass); + JS_ASSERT(type->clasp == &js::ArrayObject::class_); JS_ASSERT_IF(type->clasp->finalize, heap == js::gc::TenuredHeap); /* @@ -965,12 +745,6 @@ JSObject::hasProperty(JSContext *cx, js::HandleObject obj, return true; } -inline bool -JSObject::isCallable() -{ - return getClass()->isCallable(); -} - inline void JSObject::nativeSetSlot(uint32_t slot, const js::Value &value) { @@ -1005,88 +779,6 @@ JSObject::hasShapeTable() const return lastProperty()->hasTable(); } -/* static */ inline JSBool -JSObject::lookupGeneric(JSContext *cx, js::HandleObject obj, js::HandleId id, - js::MutableHandleObject objp, js::MutableHandleShape propp) -{ - /* NB: The logic of lookupGeneric is implicitly reflected in IonBuilder.cpp's - * |CanEffectlesslyCallLookupGenericOnObject| logic. - * If this changes, please remember to update the logic there as well. - */ - js::LookupGenericOp op = obj->getOps()->lookupGeneric; - if (op) - return op(cx, obj, id, objp, propp); - return js::baseops::LookupProperty(cx, obj, id, objp, propp); -} - -/* static */ inline JSBool -JSObject::lookupProperty(JSContext *cx, js::HandleObject obj, js::PropertyName *name, - js::MutableHandleObject objp, js::MutableHandleShape propp) -{ - JS::RootedId id(cx, js::NameToId(name)); - return lookupGeneric(cx, obj, id, objp, propp); -} - -/* static */ inline JSBool -JSObject::defineGeneric(JSContext *cx, js::HandleObject obj, - js::HandleId id, js::HandleValue value, - JSPropertyOp getter /* = JS_PropertyStub */, - JSStrictPropertyOp setter /* = JS_StrictPropertyStub */, - unsigned attrs /* = JSPROP_ENUMERATE */) -{ - JS_ASSERT(!(attrs & JSPROP_NATIVE_ACCESSORS)); - js::DefineGenericOp op = obj->getOps()->defineGeneric; - return (op ? op : js::baseops::DefineGeneric)(cx, obj, id, value, getter, setter, attrs); -} - -/* static */ inline JSBool -JSObject::defineProperty(JSContext *cx, js::HandleObject obj, - js::PropertyName *name, js::HandleValue value, - JSPropertyOp getter /* = JS_PropertyStub */, - JSStrictPropertyOp setter /* = JS_StrictPropertyStub */, - unsigned attrs /* = JSPROP_ENUMERATE */) -{ - JS::RootedId id(cx, js::NameToId(name)); - return defineGeneric(cx, obj, id, value, getter, setter, attrs); -} - -/* static */ inline JSBool -JSObject::defineElement(JSContext *cx, js::HandleObject obj, - uint32_t index, js::HandleValue value, - JSPropertyOp getter /* = JS_PropertyStub */, - JSStrictPropertyOp setter /* = JS_StrictPropertyStub */, - unsigned attrs /* = JSPROP_ENUMERATE */) -{ - js::DefineElementOp op = obj->getOps()->defineElement; - return (op ? op : js::baseops::DefineElement)(cx, obj, index, value, getter, setter, attrs); -} - -/* static */ inline JSBool -JSObject::defineSpecial(JSContext *cx, js::HandleObject obj, js::SpecialId sid, js::HandleValue value, - JSPropertyOp getter /* = JS_PropertyStub */, - JSStrictPropertyOp setter /* = JS_StrictPropertyStub */, - unsigned attrs /* = JSPROP_ENUMERATE */) -{ - JS::RootedId id(cx, SPECIALID_TO_JSID(sid)); - return defineGeneric(cx, obj, id, value, getter, setter, attrs); -} - -/* static */ inline JSBool -JSObject::lookupElement(JSContext *cx, js::HandleObject obj, uint32_t index, - js::MutableHandleObject objp, js::MutableHandleShape propp) -{ - js::LookupElementOp op = obj->getOps()->lookupElement; - return (op ? op : js::baseops::LookupElement)(cx, obj, index, objp, propp); -} - -/* static */ inline JSBool -JSObject::lookupSpecial(JSContext *cx, js::HandleObject obj, js::SpecialId sid, - js::MutableHandleObject objp, js::MutableHandleShape propp) -{ - JS::RootedId id(cx, SPECIALID_TO_JSID(sid)); - return lookupGeneric(cx, obj, id, objp, propp); -} - /* static */ inline JSBool JSObject::getElement(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, uint32_t index, js::MutableHandleValue vp) @@ -1147,30 +839,6 @@ JSObject::getElementIfPresent(JSContext *cx, js::HandleObject obj, js::HandleObj return getGeneric(cx, obj, receiver, id, vp); } -/* static */ inline JSBool -JSObject::getSpecial(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, - js::SpecialId sid, js::MutableHandleValue vp) -{ - JS::RootedId id(cx, SPECIALID_TO_JSID(sid)); - return getGeneric(cx, obj, receiver, id, vp); -} - -/* static */ inline JSBool -JSObject::getGenericAttributes(JSContext *cx, js::HandleObject obj, - js::HandleId id, unsigned *attrsp) -{ - js::GenericAttributesOp op = obj->getOps()->getGenericAttributes; - return (op ? op : js::baseops::GetAttributes)(cx, obj, id, attrsp); -} - -/* static */ inline JSBool -JSObject::getPropertyAttributes(JSContext *cx, js::HandleObject obj, - js::PropertyName *name, unsigned *attrsp) -{ - JS::RootedId id(cx, js::NameToId(name)); - return getGenericAttributes(cx, obj, id, attrsp); -} - /* static */ inline JSBool JSObject::getElementAttributes(JSContext *cx, js::HandleObject obj, uint32_t index, unsigned *attrsp) @@ -1181,14 +849,6 @@ JSObject::getElementAttributes(JSContext *cx, js::HandleObject obj, return getGenericAttributes(cx, obj, id, attrsp); } -/* static */ inline JSBool -JSObject::getSpecialAttributes(JSContext *cx, js::HandleObject obj, - js::SpecialId sid, unsigned *attrsp) -{ - JS::RootedId id(cx, SPECIALID_TO_JSID(sid)); - return getGenericAttributes(cx, obj, id, attrsp); -} - inline bool JSObject::isCrossCompartmentWrapper() const { @@ -1212,12 +872,6 @@ JSObject::global() const return *compartment()->maybeGlobal(); } -static inline bool -js_IsCallable(const js::Value &v) -{ - return v.isObject() && v.toObject().isCallable(); -} - namespace js { PropDesc::PropDesc(const Value &getter, const Value &setter, @@ -1236,22 +890,6 @@ PropDesc::PropDesc(const Value &getter, const Value &setter, MOZ_ASSERT(setter.isUndefined() || js_IsCallable(setter)); } -inline JSObject * -GetInnerObject(JSContext *cx, HandleObject obj) -{ - if (JSObjectOp op = obj->getClass()->ext.innerObject) - return op(cx, obj); - return obj; -} - -inline JSObject * -GetOuterObject(JSContext *cx, HandleObject obj) -{ - if (JSObjectOp op = obj->getClass()->ext.outerObject) - return op(cx, obj); - return obj; -} - static JS_ALWAYS_INLINE bool IsFunctionObject(const js::Value &v) { @@ -1624,13 +1262,13 @@ ObjectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx) return Proxy::objectClassIs(obj, classValue, cx); switch (classValue) { - case ESClass_Array: return obj->isArray(); + case ESClass_Array: return obj->is(); case ESClass_Number: return obj->is(); case ESClass_String: return obj->is(); case ESClass_Boolean: return obj->is(); case ESClass_RegExp: return obj->is(); case ESClass_ArrayBuffer: return obj->is(); - case ESClass_Date: return obj->isDate(); + case ESClass_Date: return obj->is(); } JS_NOT_REACHED("bad classValue"); return false; @@ -1709,10 +1347,4 @@ js_PurgeScopeChain(JSContext *cx, JS::HandleObject obj, JS::HandleId id) return true; } -inline void -js::DestroyIdArray(FreeOp *fop, JSIdArray *ida) -{ - fop->free_(ida); -} - #endif /* jsobjinlines_h */ diff --git a/js/src/json.cpp b/js/src/json.cpp index c459b5615..ffb0dd4a8 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -563,7 +563,7 @@ js_Stringify(JSContext *cx, MutableHandleValue vp, JSObject *replacer_, Value sp /* Step 4b(ii). */ uint32_t len; JS_ALWAYS_TRUE(GetLengthProperty(cx, replacer, &len)); - if (replacer->isArray() && !replacer->isIndexed()) + if (replacer->is() && !replacer->isIndexed()) len = Min(len, replacer->getDenseInitializedLength()); // Cap the initial size to a moderately small value. This avoids diff --git a/js/src/jsprvtd.h b/js/src/jsprvtd.h index abf84067a..4e7dfffbd 100644 --- a/js/src/jsprvtd.h +++ b/js/src/jsprvtd.h @@ -148,10 +148,10 @@ struct Token; struct TokenPos; class TokenStream; class ParseMapPool; -struct ParseNode; +class ParseNode; template -struct Parser; +class Parser; } /* namespace frontend */ diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h index 2a59753ca..9790d67a0 100644 --- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -14,6 +14,10 @@ #include "jsprototypes.h" #include "jstypes.h" +#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING) || defined(DEBUG) +# define JSGC_TRACK_EXACT_ROOTS +#endif + namespace JS { /* @@ -296,7 +300,7 @@ struct ContextFriendFields return reinterpret_cast(cx); } -#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING) +#ifdef JSGC_TRACK_EXACT_ROOTS /* * Stack allocated GC roots for stack GC heap pointers, which may be * overwritten if moved during a GC. @@ -344,7 +348,7 @@ struct PerThreadDataFriendFields PerThreadDataFriendFields(); -#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING) +#ifdef JSGC_TRACK_EXACT_ROOTS /* * Stack allocated GC roots for stack GC heap pointers, which may be * overwritten if moved during a GC. diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 2f8862911..f871366ee 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -279,10 +279,9 @@ typedef HashMap, SystemAllocPolicy> DebugScriptMap; -struct ScriptSource +class ScriptSource { friend class SourceCompressorThread; - private: union { // Before setSourceCopy or setSource are successfully called, this union // has a NULL pointer. When the script source is ready, @@ -1325,7 +1324,7 @@ class SourceCompressorThread struct SourceCompressionToken { - friend struct ScriptSource; + friend class ScriptSource; friend class SourceCompressorThread; private: JSContext *cx; diff --git a/js/src/jsscriptinlines.h b/js/src/jsscriptinlines.h index b74f1ac3e..ffc22f0a1 100644 --- a/js/src/jsscriptinlines.h +++ b/js/src/jsscriptinlines.h @@ -20,6 +20,7 @@ #include "vm/Shape.h" #include "jscompartmentinlines.h" +#include "jsinferinlines.h" #include "vm/Shape-inl.h" diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index 2e7fb5bfe..95c6baa70 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -539,10 +539,6 @@ ArrayBufferObject::addView(JSObject *view) } *views = view; - - // The view list is not stored in the private slot, but it needs the same - // post barrier implementation - privateWriteBarrierPost((void**)views); } JSObject * @@ -1366,6 +1362,26 @@ js::ClampDoubleToUint8(const double x) return y; } +/* + * This method is used to trace TypedArray and DataView objects. We need a + * custom tracer because some of an ArrayBufferView's reserved slots are weak + * references, and some need to be updated specially during moving GCs. + */ +static void +TraceArrayBufferView(JSTracer *trc, JSObject *obj) +{ + HeapSlot &bufSlot = obj->getReservedSlotRef(BufferView::BUFFER_SLOT); + MarkSlot(trc, &bufSlot, "typedarray.buffer"); + + /* Update obj's data slot if the array buffer moved. */ + ArrayBufferObject &buf = bufSlot.toObject().as(); + int32_t offset = obj->getReservedSlot(BufferView::BYTEOFFSET_SLOT).toInt32(); + obj->initPrivate(buf.dataPointer() + offset); + + /* Update NEXT_VEIW_SLOT, if the view moved. */ + IsSlotMarked(&obj->getReservedSlotRef(BufferView::NEXT_VIEW_SLOT)); +} + template static inline const int TypeIDOfType(); template<> inline const int TypeIDOfType() { return TypedArray::TYPE_INT8; } template<> inline const int TypeIDOfType() { return TypedArray::TYPE_UINT8; } @@ -1416,12 +1432,6 @@ class TypedArrayTemplate return v.isObject() && v.toObject().hasClass(fastClass()); } - static void - obj_trace(JSTracer *trc, JSObject *obj) - { - MarkSlot(trc, &obj->getFixedSlotRef(BUFFER_SLOT), "typedarray.buffer"); - } - static JSBool obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandlePropertyName name, MutableHandleValue vp) @@ -2381,8 +2391,8 @@ class TypedArrayTemplate uint64_t gcNumber = runtime->gcNumber; #endif - if (ar->isArray() && !ar->isIndexed() && ar->getDenseInitializedLength() >= len) { - JS_ASSERT(ar->getArrayLength() == len); + if (ar->is() && !ar->isIndexed() && ar->getDenseInitializedLength() >= len) { + JS_ASSERT(ar->as().length() == len); src = ar->getDenseElements(); uint32_t i = 0; @@ -3550,7 +3560,7 @@ IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float64, double, double) NULL, /* call */ \ NULL, /* construct */ \ NULL, /* hasInstance */ \ - _typedArray::obj_trace, /* trace */ \ + TraceArrayBufferView, /* trace */ \ { \ NULL, /* outerObject */ \ NULL, /* innerObject */ \ @@ -3751,6 +3761,7 @@ Class DataViewObject::class_ = { "DataView", JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | + /* Bug 886622: Consider making this Class NON_NATIVE. */ JSCLASS_HAS_RESERVED_SLOTS(DataViewObject::RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_DataView), JS_PropertyStub, /* addProperty */ @@ -3760,12 +3771,12 @@ Class DataViewObject::class_ = { JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, - NULL, /* finalize */ - NULL, /* checkAccess */ - NULL, /* call */ - NULL, /* construct */ - NULL, /* hasInstance */ - NULL, /* trace */ + NULL, /* finalize */ + NULL, /* checkAccess */ + NULL, /* call */ + NULL, /* construct */ + NULL, /* hasInstance */ + TraceArrayBufferView, /* trace */ JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }; diff --git a/js/src/jstypedarrayinlines.h b/js/src/jstypedarrayinlines.h index 6c8bf758d..c473d5d4a 100644 --- a/js/src/jstypedarrayinlines.h +++ b/js/src/jstypedarrayinlines.h @@ -175,13 +175,8 @@ class ArrayBufferViewByteOffsetRef : public gc::BufferableRef explicit ArrayBufferViewByteOffsetRef(JSObject *obj) : obj(obj) {} void mark(JSTracer *trc) { - /* Update obj's private to point to the moved buffer's array data. */ MarkObjectUnbarriered(trc, &obj, "TypedArray"); - HeapSlot &bufSlot = obj->getReservedSlotRef(BufferView::BUFFER_SLOT); - gc::MarkSlot(trc, &bufSlot, "TypedArray::BUFFER_SLOT"); - ArrayBufferObject &buf = bufSlot.toObject().as(); - int32_t offset = obj->getReservedSlot(BufferView::BYTEOFFSET_SLOT).toInt32(); - obj->initPrivate(buf.dataPointer() + offset); + obj->getClass()->trace(trc, obj); } }; #endif diff --git a/js/src/jswrapper.cpp b/js/src/jswrapper.cpp index 354e9c148..dfae6e829 100644 --- a/js/src/jswrapper.cpp +++ b/js/src/jswrapper.cpp @@ -13,6 +13,8 @@ #include "jsgc.h" #include "jsiter.h" +#include "vm/ErrorObject.h" + #include "jsobjinlines.h" #include "builtin/Iterator-inl.h" @@ -138,7 +140,9 @@ ErrorCopier::~ErrorCopier() JSContext *cx = ac.ref().context(); if (ac.ref().origin() != cx->compartment() && cx->isExceptionPending()) { RootedValue exc(cx, cx->getPendingException()); - if (exc.isObject() && exc.toObject().isError() && exc.toObject().getPrivate()) { + if (exc.isObject() && exc.toObject().is() && + exc.toObject().as().getExnPrivate()) + { cx->clearPendingException(); ac.destroy(); Rooted errObj(cx, &exc.toObject()); diff --git a/js/src/moz.build b/js/src/moz.build index 46ae502bf..fe4770a8c 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -229,7 +229,7 @@ if CONFIG['ENABLE_ION']: 'MIR.cpp', 'MIRGraph.cpp', 'MoveResolver.cpp', - 'ParallelArrayAnalysis.cpp', + 'ParallelSafetyAnalysis.cpp', 'ParallelFunctions.cpp', 'RangeAnalysis.cpp', 'RegisterAllocator.cpp', diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 5c2425b16..1b87e28cb 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -1520,7 +1520,7 @@ static JSTrapStatus TrapHandler(JSContext *cx, JSScript *, jsbytecode *pc, jsval *rvalArg, jsval closure) { - JSString *str = JSVAL_TO_STRING(closure); + RootedString str(cx, JSVAL_TO_STRING(closure)); RootedValue rval(cx, *rvalArg); ScriptFrameIter iter(cx); diff --git a/js/src/vm/ArrayObject-inl.h b/js/src/vm/ArrayObject-inl.h new file mode 100644 index 000000000..f91cbe220 --- /dev/null +++ b/js/src/vm/ArrayObject-inl.h @@ -0,0 +1,35 @@ +/* -*- 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 vm_ArrayObject_inl_h +#define vm_ArrayObject_inl_h + +#include "vm/ArrayObject.h" +#include "vm/String.h" + +#include "jsinferinlines.h" + +namespace js { + +/* static */ inline void +ArrayObject::setLength(JSContext *cx, Handle arr, uint32_t length) +{ + JS_ASSERT(arr->lengthIsWritable()); + + if (length > INT32_MAX) { + /* Track objects with overflowing lengths in type information. */ + js::types::MarkTypeObjectFlags(cx, arr, js::types::OBJECT_FLAG_LENGTH_OVERFLOW); + jsid lengthId = js::NameToId(cx->names().length); + js::types::AddTypePropertyId(cx, arr, lengthId, js::types::Type::DoubleType()); + } + + arr->getElementsHeader()->length = length; +} + +} // namespace js + +#endif // vm_ArrayObject_inl_h + diff --git a/js/src/vm/ArrayObject.h b/js/src/vm/ArrayObject.h new file mode 100644 index 000000000..c401bf768 --- /dev/null +++ b/js/src/vm/ArrayObject.h @@ -0,0 +1,40 @@ +/* -*- 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 vm_ArrayObject_h +#define vm_ArrayObject_h + +#include "jsobj.h" + +namespace js { + +class ArrayObject : public JSObject +{ + public: + static Class class_; + + bool lengthIsWritable() const { + return !getElementsHeader()->hasNonwritableArrayLength(); + } + + uint32_t length() const { + return getElementsHeader()->length; + } + + static inline void setLength(JSContext *cx, Handle arr, uint32_t length); + + // Variant of setLength for use on arrays where the length cannot overflow int32_t. + void setLengthInt32(uint32_t length) { + JS_ASSERT(lengthIsWritable()); + JS_ASSERT(length <= INT32_MAX); + getElementsHeader()->length = length; + } +}; + +} // namespace js + +#endif // vm_ArrayObject_h + diff --git a/js/src/vm/DateObject.h b/js/src/vm/DateObject.h new file mode 100644 index 000000000..08b13a7d3 --- /dev/null +++ b/js/src/vm/DateObject.h @@ -0,0 +1,79 @@ +/* -*- 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 vm_DateObject_h_ +#define vm_DateObject_h_ + +#include "jsobj.h" + +#include "js/Value.h" + +namespace js { + +class DateTimeInfo; + +class DateObject : public JSObject +{ + static const uint32_t UTC_TIME_SLOT = 0; + static const uint32_t TZA_SLOT = 1; + + /* + * Cached slots holding local properties of the date. + * These are undefined until the first actual lookup occurs + * and are reset to undefined whenever the date's time is modified. + */ + static const uint32_t COMPONENTS_START_SLOT = 2; + + static const uint32_t LOCAL_TIME_SLOT = COMPONENTS_START_SLOT + 0; + static const uint32_t LOCAL_YEAR_SLOT = COMPONENTS_START_SLOT + 1; + static const uint32_t LOCAL_MONTH_SLOT = COMPONENTS_START_SLOT + 2; + static const uint32_t LOCAL_DATE_SLOT = COMPONENTS_START_SLOT + 3; + static const uint32_t LOCAL_DAY_SLOT = COMPONENTS_START_SLOT + 4; + static const uint32_t LOCAL_HOURS_SLOT = COMPONENTS_START_SLOT + 5; + static const uint32_t LOCAL_MINUTES_SLOT = COMPONENTS_START_SLOT + 6; + static const uint32_t LOCAL_SECONDS_SLOT = COMPONENTS_START_SLOT + 7; + + static const uint32_t RESERVED_SLOTS = LOCAL_SECONDS_SLOT + 1; + + public: + static Class class_; + + inline const js::Value &UTCTime() const { + return getFixedSlot(UTC_TIME_SLOT); + } + + // Set UTC time to a given time and invalidate cached local time. + void setUTCTime(double t, Value *vp = NULL); + + inline double cachedLocalTime(DateTimeInfo *dtInfo); + + // Cache the local time, year, month, and so forth of the object. + // If UTC time is not finite (e.g., NaN), the local time + // slots will be set to the UTC time without conversion. + void fillLocalTimeSlots(DateTimeInfo *dtInfo); + + static JS_ALWAYS_INLINE bool getTime_impl(JSContext *cx, CallArgs args); + static JS_ALWAYS_INLINE bool getYear_impl(JSContext *cx, CallArgs args); + static JS_ALWAYS_INLINE bool getFullYear_impl(JSContext *cx, CallArgs args); + static JS_ALWAYS_INLINE bool getUTCFullYear_impl(JSContext *cx, CallArgs args); + static JS_ALWAYS_INLINE bool getMonth_impl(JSContext *cx, CallArgs args); + static JS_ALWAYS_INLINE bool getUTCMonth_impl(JSContext *cx, CallArgs args); + static JS_ALWAYS_INLINE bool getDate_impl(JSContext *cx, CallArgs args); + static JS_ALWAYS_INLINE bool getUTCDate_impl(JSContext *cx, CallArgs args); + static JS_ALWAYS_INLINE bool getDay_impl(JSContext *cx, CallArgs args); + static JS_ALWAYS_INLINE bool getUTCDay_impl(JSContext *cx, CallArgs args); + static JS_ALWAYS_INLINE bool getHours_impl(JSContext *cx, CallArgs args); + static JS_ALWAYS_INLINE bool getUTCHours_impl(JSContext *cx, CallArgs args); + static JS_ALWAYS_INLINE bool getMinutes_impl(JSContext *cx, CallArgs args); + static JS_ALWAYS_INLINE bool getUTCMinutes_impl(JSContext *cx, CallArgs args); + static JS_ALWAYS_INLINE bool getUTCSeconds_impl(JSContext *cx, CallArgs args); + static JS_ALWAYS_INLINE bool getUTCMilliseconds_impl(JSContext *cx, CallArgs args); + static JS_ALWAYS_INLINE bool getTimezoneOffset_impl(JSContext *cx, CallArgs args); +}; + +} // namespace js + +#endif // vm_DateObject_h_ diff --git a/js/src/vm/ErrorObject.h b/js/src/vm/ErrorObject.h new file mode 100644 index 000000000..92625cbca --- /dev/null +++ b/js/src/vm/ErrorObject.h @@ -0,0 +1,26 @@ +/* -*- 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 vm_ErrorObject_h_ +#define vm_ErrorObject_h_ + +#include "jsobj.h" + +class JSExnPrivate; + +namespace js { + +class ErrorObject : public JSObject +{ + public: + static Class class_; + + JSExnPrivate *getExnPrivate() { return static_cast(getPrivate()); } +}; + +} // namespace js + +#endif // vm_ErrorObject_h_ diff --git a/js/src/vm/ForkJoin.h b/js/src/vm/ForkJoin.h index b961548db..14254dbc2 100644 --- a/js/src/vm/ForkJoin.h +++ b/js/src/vm/ForkJoin.h @@ -200,7 +200,7 @@ namespace js { -struct ForkJoinSlice; +class ForkJoinSlice; bool ForkJoin(JSContext *cx, CallArgs &args); @@ -290,7 +290,7 @@ struct ParallelBailoutRecord { struct ForkJoinShared; -struct ForkJoinSlice : ThreadSafeContext +class ForkJoinSlice : public ThreadSafeContext { public: // Which slice should you process? Ranges from 0 to |numSlices|. diff --git a/js/src/vm/Interpreter-inl.h b/js/src/vm/Interpreter-inl.h index 66fc67a41..e82ab0860 100644 --- a/js/src/vm/Interpreter-inl.h +++ b/js/src/vm/Interpreter-inl.h @@ -200,9 +200,8 @@ GetLengthProperty(const Value &lval, MutableHandleValue vp) } if (lval.isObject()) { JSObject *obj = &lval.toObject(); - if (obj->isArray()) { - uint32_t length = obj->getArrayLength(); - vp.setNumber(length); + if (obj->is()) { + vp.setNumber(obj->as().length()); return true; } @@ -576,7 +575,7 @@ GetObjectElementOperation(JSContext *cx, JSOp op, JSObject *objArg, bool wasObje if (script->hasAnalysis()) { script->analysis()->getCode(pc).getStringElement = true; - if (!objArg->isArray() && !objArg->isNative() && !objArg->isTypedArray()) + if (!objArg->is() && !objArg->isNative() && !objArg->isTypedArray()) script->analysis()->getCode(pc).nonNativeGetElement = true; } } @@ -750,7 +749,7 @@ InitArrayElemOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, uint32_t JSOp op = JSOp(*pc); JS_ASSERT(op == JSOP_INITELEM_ARRAY || op == JSOP_INITELEM_INC); - JS_ASSERT(obj->isArray()); + JS_ASSERT(obj->is()); /* * If val is a hole, do not call JSObject::defineElement. In this case, diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 917fd75ae..8706475eb 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -2031,7 +2031,7 @@ BEGIN_CASE(JSOP_NEG) END_CASE(JSOP_NEG) BEGIN_CASE(JSOP_POS) - if (!ToNumber(cx, ®s.sp[-1])) + if (!ToNumber(cx, MutableHandleValue::fromMarkedLocation(®s.sp[-1]))) goto error; if (!regs.sp[-1].isInt32()) TypeScript::MonitorOverflow(cx, script, regs.pc); @@ -2750,7 +2750,7 @@ BEGIN_CASE(JSOP_NEWINIT) RootedObject &obj = rootObject0; NewObjectKind newKind; if (i == JSProto_Array) { - newKind = UseNewTypeForInitializer(cx, script, regs.pc, &ArrayClass); + newKind = UseNewTypeForInitializer(cx, script, regs.pc, &ArrayObject::class_); obj = NewDenseEmptyArray(cx, NULL, newKind); } else { gc::AllocKind allocKind = GuessObjectGCKind(0); @@ -2769,7 +2769,7 @@ BEGIN_CASE(JSOP_NEWARRAY) { unsigned count = GET_UINT24(regs.pc); RootedObject &obj = rootObject0; - NewObjectKind newKind = UseNewTypeForInitializer(cx, script, regs.pc, &ArrayClass); + NewObjectKind newKind = UseNewTypeForInitializer(cx, script, regs.pc, &ArrayObject::class_); obj = NewDenseAllocatedArray(cx, count, NULL, newKind); if (!obj || !SetInitializerObjectType(cx, script, regs.pc, obj, newKind)) goto error; @@ -2855,7 +2855,7 @@ BEGIN_CASE(JSOP_INITELEM_ARRAY) RootedObject &obj = rootObject0; obj = ®s.sp[-2].toObject(); - JS_ASSERT(obj->isArray()); + JS_ASSERT(obj->is()); uint32_t index = GET_UINT24(regs.pc); if (!InitArrayElemOperation(cx, regs.pc, obj, index, val)) diff --git a/js/src/vm/Interpreter.h b/js/src/vm/Interpreter.h index c9fc15042..1378dcc7f 100644 --- a/js/src/vm/Interpreter.h +++ b/js/src/vm/Interpreter.h @@ -396,37 +396,6 @@ class TryNoteIter /************************************************************************/ -/* - * To really poison a set of values, using 'magic' or 'undefined' isn't good - * enough since often these will just be ignored by buggy code (see bug 629974) - * in debug builds and crash in release builds. Instead, we use a safe-for-crash - * pointer. - */ -static JS_ALWAYS_INLINE void -Debug_SetValueRangeToCrashOnTouch(Value *beg, Value *end) -{ -#ifdef DEBUG - for (Value *v = beg; v != end; ++v) - v->setObject(*reinterpret_cast(0x42)); -#endif -} - -static JS_ALWAYS_INLINE void -Debug_SetValueRangeToCrashOnTouch(Value *vec, size_t len) -{ -#ifdef DEBUG - Debug_SetValueRangeToCrashOnTouch(vec, vec + len); -#endif -} - -static JS_ALWAYS_INLINE void -Debug_SetValueRangeToCrashOnTouch(HeapValue *vec, size_t len) -{ -#ifdef DEBUG - Debug_SetValueRangeToCrashOnTouch((Value *) vec, len); -#endif -} - bool Throw(JSContext *cx, HandleValue v); diff --git a/js/src/vm/ObjectImpl-inl.h b/js/src/vm/ObjectImpl-inl.h index c5a4b4a86..bca18c168 100644 --- a/js/src/vm/ObjectImpl-inl.h +++ b/js/src/vm/ObjectImpl-inl.h @@ -16,97 +16,22 @@ #include "gc/Heap.h" #include "gc/Marking.h" #include "js/TemplateLib.h" -#include "vm/Interpreter.h" #include "vm/ObjectImpl.h" #include "gc/Barrier-inl.h" -namespace js { - -static MOZ_ALWAYS_INLINE void -Debug_SetSlotRangeToCrashOnTouch(HeapSlot *vec, uint32_t len) -{ -#ifdef DEBUG - Debug_SetValueRangeToCrashOnTouch((Value *) vec, len); -#endif -} - -static MOZ_ALWAYS_INLINE void -Debug_SetSlotRangeToCrashOnTouch(HeapSlot *begin, HeapSlot *end) -{ -#ifdef DEBUG - Debug_SetValueRangeToCrashOnTouch((Value *) begin, end - begin); -#endif -} - -} // namespace js - inline JSCompartment * js::ObjectImpl::compartment() const { return lastProperty()->base()->compartment(); } -inline js::TaggedProto -js::ObjectImpl::getTaggedProto() const -{ - return TaggedProto(getProto()); -} - -inline js::Shape * -js::ObjectImpl::nativeLookup(JSContext *cx, PropertyId pid) -{ - return nativeLookup(cx, pid.asId()); -} - -inline js::Shape * -js::ObjectImpl::nativeLookup(JSContext *cx, PropertyName *name) -{ - return nativeLookup(cx, NameToId(name)); -} - -inline bool -js::ObjectImpl::nativeContains(JSContext *cx, jsid id) -{ - return nativeLookup(cx, id) != NULL; -} - -inline bool -js::ObjectImpl::nativeContains(JSContext *cx, PropertyName *name) -{ - return nativeLookup(cx, name) != NULL; -} - inline bool js::ObjectImpl::nativeContains(JSContext *cx, Shape *shape) { return nativeLookup(cx, shape->propid()) == shape; } -inline js::Shape * -js::ObjectImpl::nativeLookupPure(PropertyId pid) -{ - return nativeLookupPure(pid.asId()); -} - -inline js::Shape * -js::ObjectImpl::nativeLookupPure(PropertyName *name) -{ - return nativeLookupPure(NameToId(name)); -} - -inline bool -js::ObjectImpl::nativeContainsPure(jsid id) -{ - return nativeLookupPure(id) != NULL; -} - -inline bool -js::ObjectImpl::nativeContainsPure(PropertyName *name) -{ - return nativeContainsPure(NameToId(name)); -} - inline bool js::ObjectImpl::nativeContainsPure(Shape *shape) { @@ -123,88 +48,6 @@ js::ObjectImpl::isExtensible() const return !lastProperty()->hasObjectFlag(BaseShape::NOT_EXTENSIBLE); } -inline uint32_t -js::ObjectImpl::getDenseInitializedLength() -{ - MOZ_ASSERT(isNative()); - return getElementsHeader()->initializedLength; -} - -inline uint32_t -js::ObjectImpl::getDenseCapacity() -{ - MOZ_ASSERT(isNative()); - return getElementsHeader()->capacity; -} - -inline js::HeapSlotArray -js::ObjectImpl::getDenseElements() -{ - MOZ_ASSERT(isNative()); - return HeapSlotArray(elements); -} - -inline const js::Value & -js::ObjectImpl::getDenseElement(uint32_t idx) -{ - MOZ_ASSERT(isNative() && idx < getDenseInitializedLength()); - return elements[idx]; -} - -inline bool -js::ObjectImpl::containsDenseElement(uint32_t idx) -{ - MOZ_ASSERT(isNative()); - return idx < getDenseInitializedLength() && !elements[idx].isMagic(JS_ELEMENTS_HOLE); -} - -inline void -js::ObjectImpl::getSlotRangeUnchecked(uint32_t start, uint32_t length, - HeapSlot **fixedStart, HeapSlot **fixedEnd, - HeapSlot **slotsStart, HeapSlot **slotsEnd) -{ - MOZ_ASSERT(start + length >= start); - - uint32_t fixed = numFixedSlots(); - if (start < fixed) { - if (start + length < fixed) { - *fixedStart = &fixedSlots()[start]; - *fixedEnd = &fixedSlots()[start + length]; - *slotsStart = *slotsEnd = NULL; - } else { - uint32_t localCopy = fixed - start; - *fixedStart = &fixedSlots()[start]; - *fixedEnd = &fixedSlots()[start + localCopy]; - *slotsStart = &slots[0]; - *slotsEnd = &slots[length - localCopy]; - } - } else { - *fixedStart = *fixedEnd = NULL; - *slotsStart = &slots[start - fixed]; - *slotsEnd = &slots[start - fixed + length]; - } -} - -inline void -js::ObjectImpl::getSlotRange(uint32_t start, uint32_t length, - HeapSlot **fixedStart, HeapSlot **fixedEnd, - HeapSlot **slotsStart, HeapSlot **slotsEnd) -{ - MOZ_ASSERT(slotInRange(start + length, SENTINEL_ALLOWED)); - getSlotRangeUnchecked(start, length, fixedStart, fixedEnd, slotsStart, slotsEnd); -} - -inline void -js::ObjectImpl::invalidateSlotRange(uint32_t start, uint32_t length) -{ -#ifdef DEBUG - HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd; - getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd); - Debug_SetSlotRangeToCrashOnTouch(fixedStart, fixedEnd); - Debug_SetSlotRangeToCrashOnTouch(slotsStart, slotsEnd); -#endif /* DEBUG */ -} - inline bool js::ObjectImpl::isNative() const { @@ -217,22 +60,6 @@ js::ObjectImpl::isProxy() const return js::IsProxy(const_cast(this->asObjectPtr())); } -inline js::HeapSlot & -js::ObjectImpl::nativeGetSlotRef(uint32_t slot) -{ - MOZ_ASSERT(isNative()); - MOZ_ASSERT(slot < slotSpan()); - return getSlotRef(slot); -} - -inline const js::Value & -js::ObjectImpl::nativeGetSlot(uint32_t slot) const -{ - MOZ_ASSERT(isNative()); - MOZ_ASSERT(slot < slotSpan()); - return getSlot(slot); -} - #ifdef DEBUG inline bool IsObjectValueInCompartment(js::Value v, JSCompartment *comp) @@ -309,18 +136,6 @@ js::ObjectImpl::numDynamicSlots() const return dynamicSlotsCount(numFixedSlots(), slotSpan()); } -inline JSClass * -js::ObjectImpl::getJSClass() const -{ - return Jsvalify(getClass()); -} - -inline const js::ObjectOps * -js::ObjectImpl::getOps() const -{ - return &getClass()->ops; -} - inline bool js::ObjectImpl::isDelegate() const { @@ -333,26 +148,6 @@ js::ObjectImpl::inDictionaryMode() const return lastProperty()->inDictionary(); } -/* static */ inline uint32_t -js::ObjectImpl::dynamicSlotsCount(uint32_t nfixed, uint32_t span) -{ - if (span <= nfixed) - return 0; - span -= nfixed; - if (span <= SLOT_CAPACITY_MIN) - return SLOT_CAPACITY_MIN; - - uint32_t slots = RoundUpPow2(span); - MOZ_ASSERT(slots >= span); - return slots; -} - -inline size_t -js::ObjectImpl::tenuredSizeOfThis() const -{ - return js::gc::Arena::thingSize(tenuredGetAllocKind()); -} - JS_ALWAYS_INLINE JS::Zone * js::ObjectImpl::zone() const { @@ -442,17 +237,4 @@ js::ObjectImpl::setPrivateGCThing(js::gc::Cell *cell) privateWriteBarrierPost(pprivate); } -inline void -js::ObjectImpl::setPrivateUnbarriered(void *data) -{ - void **pprivate = &privateRef(numFixedSlots()); - *pprivate = data; -} - -inline void -js::ObjectImpl::initPrivate(void *data) -{ - privateRef(numFixedSlots()) = data; -} - #endif /* vm_ObjectImpl_inl_h */ diff --git a/js/src/vm/ObjectImpl.cpp b/js/src/vm/ObjectImpl.cpp index b1ce27530..e515ebc41 100644 --- a/js/src/vm/ObjectImpl.cpp +++ b/js/src/vm/ObjectImpl.cpp @@ -4,6 +4,8 @@ * 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 "vm/ObjectImpl-inl.h" + #include "js/Value.h" #include "vm/Debugger.h" #include "vm/ObjectImpl.h" @@ -12,10 +14,21 @@ #include "gc/Barrier-inl.h" #include "gc/Marking.h" -#include "vm/ObjectImpl-inl.h" using namespace js; +bool +js::ObjectImpl::isNativeSlow() const +{ + return isNative(); +} + +uint32_t +js::ObjectImpl::slotSpanSlow() const +{ + return slotSpan(); +} + PropDesc::PropDesc() : pd_(UndefinedValue()), value_(UndefinedValue()), diff --git a/js/src/vm/ObjectImpl.h b/js/src/vm/ObjectImpl.h index 8eba5da6a..f3bb3f77b 100644 --- a/js/src/vm/ObjectImpl.h +++ b/js/src/vm/ObjectImpl.h @@ -27,6 +27,53 @@ class ObjectImpl; class Nursery; class Shape; +/* + * To really poison a set of values, using 'magic' or 'undefined' isn't good + * enough since often these will just be ignored by buggy code (see bug 629974) + * in debug builds and crash in release builds. Instead, we use a safe-for-crash + * pointer. + */ +static JS_ALWAYS_INLINE void +Debug_SetValueRangeToCrashOnTouch(Value *beg, Value *end) +{ +#ifdef DEBUG + for (Value *v = beg; v != end; ++v) + v->setObject(*reinterpret_cast(0x42)); +#endif +} + +static JS_ALWAYS_INLINE void +Debug_SetValueRangeToCrashOnTouch(Value *vec, size_t len) +{ +#ifdef DEBUG + Debug_SetValueRangeToCrashOnTouch(vec, vec + len); +#endif +} + +static JS_ALWAYS_INLINE void +Debug_SetValueRangeToCrashOnTouch(HeapValue *vec, size_t len) +{ +#ifdef DEBUG + Debug_SetValueRangeToCrashOnTouch((Value *) vec, len); +#endif +} + +static MOZ_ALWAYS_INLINE void +Debug_SetSlotRangeToCrashOnTouch(HeapSlot *vec, uint32_t len) +{ +#ifdef DEBUG + Debug_SetValueRangeToCrashOnTouch((Value *) vec, len); +#endif +} + +static MOZ_ALWAYS_INLINE void +Debug_SetSlotRangeToCrashOnTouch(HeapSlot *begin, HeapSlot *end) +{ +#ifdef DEBUG + Debug_SetValueRangeToCrashOnTouch((Value *) begin, end - begin); +#endif +} + static inline PropertyOp CastAsPropertyOp(JSObject *object) { @@ -890,6 +937,7 @@ ElementsHeader::asArrayBufferElements() return *static_cast(this); } +class ArrayObject; class ArrayBufferObject; /* @@ -901,8 +949,8 @@ class ArrayBufferObject; * to be thrown. */ extern bool -ArraySetLength(JSContext *cx, HandleObject obj, HandleId id, unsigned attrs, HandleValue value, - bool setterIsStrict); +ArraySetLength(JSContext *cx, Handle obj, HandleId id, unsigned attrs, + HandleValue value, bool setterIsStrict); /* * Elements header used for all native objects. The elements component of such @@ -927,7 +975,7 @@ ArraySetLength(JSContext *cx, HandleObject obj, HandleId id, unsigned attrs, Han * * We track these pieces of metadata for dense elements: * - The length property as a uint32_t, accessible for array objects with - * getArrayLength(), setArrayLength(). This is unused for non-arrays. + * ArrayObject::{length,setLength}(). This is unused for non-arrays. * - The number of element slots (capacity), gettable with * getDenseElementsCapacity(). * - The array's initialized length, accessible with @@ -989,12 +1037,13 @@ class ObjectElements private: friend class ::JSObject; friend class ObjectImpl; + friend class ArrayObject; friend class ArrayBufferObject; friend class Nursery; friend bool - ArraySetLength(JSContext *cx, HandleObject obj, HandleId id, unsigned attrs, HandleValue value, - bool setterIsStrict); + ArraySetLength(JSContext *cx, Handle obj, HandleId id, unsigned attrs, + HandleValue value, bool setterIsStrict); /* See Flags enum above. */ uint32_t flags; @@ -1161,8 +1210,8 @@ class ObjectImpl : public gc::Cell HeapSlot *elements; /* Slots for object elements. */ friend bool - ArraySetLength(JSContext *cx, HandleObject obj, HandleId id, unsigned attrs, HandleValue value, - bool setterIsStrict); + ArraySetLength(JSContext *cx, Handle obj, HandleId id, unsigned attrs, + HandleValue value, bool setterIsStrict); private: static void staticAsserts() { @@ -1204,11 +1253,27 @@ class ObjectImpl : public gc::Cell static bool preventExtensions(JSContext *cx, Handle obj); - inline HeapSlotArray getDenseElements(); - inline const Value & getDenseElement(uint32_t idx); - inline bool containsDenseElement(uint32_t idx); - inline uint32_t getDenseInitializedLength(); - inline uint32_t getDenseCapacity(); + HeapSlotArray getDenseElements() { + JS_ASSERT(isNativeSlow()); + return HeapSlotArray(elements); + } + const Value &getDenseElement(uint32_t idx) { + JS_ASSERT(isNativeSlow()); + MOZ_ASSERT(idx < getDenseInitializedLength()); + return elements[idx]; + } + bool containsDenseElement(uint32_t idx) { + JS_ASSERT(isNativeSlow()); + return idx < getDenseInitializedLength() && !elements[idx].isMagic(JS_ELEMENTS_HOLE); + } + uint32_t getDenseInitializedLength() { + JS_ASSERT(isNativeSlow()); + return getElementsHeader()->initializedLength; + } + uint32_t getDenseCapacity() { + JS_ASSERT(isNativeSlow()); + return getElementsHeader()->capacity; + } bool makeElementsSparse(JSContext *cx) { NEW_OBJECT_REPRESENTATION_ONLY(); @@ -1245,19 +1310,54 @@ class ObjectImpl : public gc::Cell * Get internal pointers to the range of values starting at start and * running for length. */ - inline void getSlotRangeUnchecked(uint32_t start, uint32_t length, - HeapSlot **fixedStart, HeapSlot **fixedEnd, - HeapSlot **slotsStart, HeapSlot **slotsEnd); - inline void getSlotRange(uint32_t start, uint32_t length, - HeapSlot **fixedStart, HeapSlot **fixedEnd, - HeapSlot **slotsStart, HeapSlot **slotsEnd); + void getSlotRangeUnchecked(uint32_t start, uint32_t length, + HeapSlot **fixedStart, HeapSlot **fixedEnd, + HeapSlot **slotsStart, HeapSlot **slotsEnd) + { + MOZ_ASSERT(start + length >= start); + + uint32_t fixed = numFixedSlots(); + if (start < fixed) { + if (start + length < fixed) { + *fixedStart = &fixedSlots()[start]; + *fixedEnd = &fixedSlots()[start + length]; + *slotsStart = *slotsEnd = NULL; + } else { + uint32_t localCopy = fixed - start; + *fixedStart = &fixedSlots()[start]; + *fixedEnd = &fixedSlots()[start + localCopy]; + *slotsStart = &slots[0]; + *slotsEnd = &slots[length - localCopy]; + } + } else { + *fixedStart = *fixedEnd = NULL; + *slotsStart = &slots[start - fixed]; + *slotsEnd = &slots[start - fixed + length]; + } + } + + void getSlotRange(uint32_t start, uint32_t length, + HeapSlot **fixedStart, HeapSlot **fixedEnd, + HeapSlot **slotsStart, HeapSlot **slotsEnd) + { + MOZ_ASSERT(slotInRange(start + length, SENTINEL_ALLOWED)); + getSlotRangeUnchecked(start, length, fixedStart, fixedEnd, slotsStart, slotsEnd); + } protected: friend struct GCMarker; friend class Shape; friend class NewObjectCache; - inline void invalidateSlotRange(uint32_t start, uint32_t count); + void invalidateSlotRange(uint32_t start, uint32_t length) { +#ifdef DEBUG + HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd; + getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd); + Debug_SetSlotRangeToCrashOnTouch(fixedStart, fixedEnd); + Debug_SetSlotRangeToCrashOnTouch(slotsStart, slotsEnd); +#endif /* DEBUG */ + } + void initializeSlotRange(uint32_t start, uint32_t count); /* @@ -1317,7 +1417,9 @@ class ObjectImpl : public gc::Cell */ public: - inline js::TaggedProto getTaggedProto() const; + js::TaggedProto getTaggedProto() const { + return TaggedProto(getProto()); + } Shape * lastProperty() const { MOZ_ASSERT(shape_); @@ -1330,7 +1432,9 @@ class ObjectImpl : public gc::Cell inline JSCompartment *compartment() const; + // isNativeSlow() is equivalent to isNative(), but isn't inlined. inline bool isNative() const; + bool isNativeSlow() const; types::TypeObject *type() const { MOZ_ASSERT(!hasLazyType()); @@ -1353,17 +1457,27 @@ class ObjectImpl : public gc::Cell */ bool hasLazyType() const { return type_->lazy(); } + // slotSpanSlow() is the same as slotSpan(), but isn't inlined. inline uint32_t slotSpan() const; + uint32_t slotSpanSlow() const; /* Compute dynamicSlotsCount() for this object. */ inline uint32_t numDynamicSlots() const; Shape *nativeLookup(JSContext *cx, jsid id); - inline Shape *nativeLookup(JSContext *cx, PropertyId pid); - inline Shape *nativeLookup(JSContext *cx, PropertyName *name); + Shape *nativeLookup(JSContext *cx, PropertyId pid) { + return nativeLookup(cx, pid.asId()); + } + Shape *nativeLookup(JSContext *cx, PropertyName *name) { + return nativeLookup(cx, NameToId(name)); + } - inline bool nativeContains(JSContext *cx, jsid id); - inline bool nativeContains(JSContext *cx, PropertyName* name); + bool nativeContains(JSContext *cx, jsid id) { + return nativeLookup(cx, id) != NULL; + } + bool nativeContains(JSContext *cx, PropertyName* name) { + return nativeLookup(cx, name) != NULL; + } inline bool nativeContains(JSContext *cx, Shape* shape); /* @@ -1371,18 +1485,30 @@ class ObjectImpl : public gc::Cell * operation would have been effectful. */ Shape *nativeLookupPure(jsid id); - inline Shape *nativeLookupPure(PropertyId pid); - inline Shape *nativeLookupPure(PropertyName *name); + Shape *nativeLookupPure(PropertyId pid) { + return nativeLookupPure(pid.asId()); + } + Shape *nativeLookupPure(PropertyName *name) { + return nativeLookupPure(NameToId(name)); + } - inline bool nativeContainsPure(jsid id); - inline bool nativeContainsPure(PropertyName* name); - inline bool nativeContainsPure(Shape* shape); + bool nativeContainsPure(jsid id) { + return nativeLookupPure(id) != NULL; + } + bool nativeContainsPure(PropertyName* name) { + return nativeContainsPure(NameToId(name)); + } + bool nativeContainsPure(Shape* shape); - inline JSClass *getJSClass() const; - inline bool hasClass(const Class *c) const { + JSClass *getJSClass() const { + return Jsvalify(getClass()); + } + bool hasClass(const Class *c) const { return getClass() == c; } - inline const ObjectOps *getOps() const; + const ObjectOps *getOps() const { + return &getClass()->ops; + } /* * An object is a delegate if it is on another object's prototype or scope @@ -1432,8 +1558,14 @@ class ObjectImpl : public gc::Cell return *getSlotAddress(slot); } - inline HeapSlot &nativeGetSlotRef(uint32_t slot); - inline const Value &nativeGetSlot(uint32_t slot) const; + HeapSlot &nativeGetSlotRef(uint32_t slot) { + JS_ASSERT(isNativeSlow() && slot < slotSpanSlow()); + return getSlotRef(slot); + } + const Value &nativeGetSlot(uint32_t slot) const { + JS_ASSERT(isNativeSlow() && slot < slotSpanSlow()); + return getSlot(slot); + } inline void setSlot(uint32_t slot, const Value &value); inline void setCrossCompartmentSlot(uint32_t slot, const Value &value); @@ -1462,10 +1594,22 @@ class ObjectImpl : public gc::Cell * capacity is not stored explicitly, and the allocated size of the slot * array is kept in sync with this count. */ - static inline uint32_t dynamicSlotsCount(uint32_t nfixed, uint32_t span); + static uint32_t dynamicSlotsCount(uint32_t nfixed, uint32_t span) { + if (span <= nfixed) + return 0; + span -= nfixed; + if (span <= SLOT_CAPACITY_MIN) + return SLOT_CAPACITY_MIN; + + uint32_t slots = RoundUpPow2(span); + MOZ_ASSERT(slots >= span); + return slots; + } /* Memory usage functions. */ - inline size_t tenuredSizeOfThis() const; + size_t tenuredSizeOfThis() const { + return js::gc::Arena::thingSize(tenuredGetAllocKind()); + } /* Elements accessors. */ @@ -1538,8 +1682,13 @@ class ObjectImpl : public gc::Cell } inline void setPrivate(void *data); inline void setPrivateGCThing(gc::Cell *cell); - inline void setPrivateUnbarriered(void *data); - inline void initPrivate(void *data); + void setPrivateUnbarriered(void *data) { + void **pprivate = &privateRef(numFixedSlots()); + *pprivate = data; + } + void initPrivate(void *data) { + privateRef(numFixedSlots()) = data; + } /* Access private data for an object with a known number of fixed slots. */ inline void *getPrivate(uint32_t nfixed) const { diff --git a/js/src/vm/RegExpStatics.cpp b/js/src/vm/RegExpStatics.cpp index dfaedab66..0916ec945 100644 --- a/js/src/vm/RegExpStatics.cpp +++ b/js/src/vm/RegExpStatics.cpp @@ -6,6 +6,8 @@ #include "vm/RegExpStatics.h" +#include "vm/RegExpStaticsObject.h" + #include "jsobjinlines.h" #include "vm/RegExpObject-inl.h" @@ -36,7 +38,7 @@ resc_trace(JSTracer *trc, JSObject *obj) res->mark(trc); } -Class js::RegExpStaticsClass = { +Class RegExpStaticsObject::class_ = { "RegExpStatics", JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS, JS_PropertyStub, /* addProperty */ @@ -57,7 +59,7 @@ Class js::RegExpStaticsClass = { JSObject * RegExpStatics::create(JSContext *cx, GlobalObject *parent) { - JSObject *obj = NewObjectWithGivenProto(cx, &RegExpStaticsClass, NULL, parent); + JSObject *obj = NewObjectWithGivenProto(cx, &RegExpStaticsObject::class_, NULL, parent); if (!obj) return NULL; RegExpStatics *res = cx->new_(); diff --git a/js/src/vm/RegExpStaticsObject.h b/js/src/vm/RegExpStaticsObject.h new file mode 100644 index 000000000..47a792a3e --- /dev/null +++ b/js/src/vm/RegExpStaticsObject.h @@ -0,0 +1,22 @@ +/* -*- 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 vm_RegExpStaticsObject_h +#define vm_RegExpStaticsObject_h + +#include "jsobj.h" + +namespace js { + +class RegExpStaticsObject : public JSObject +{ + public: + static Class class_; +}; + +} // namespace js + +#endif /* vm_RegExpStaticsObject_h */ diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 5d385222e..742b0b79e 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -911,6 +911,14 @@ js::CloneStaticBlockObject(JSContext *cx, HandleObject enclosingScope, Handleas(); RootedAtom source(cx, reobj.getSource()); clone = RegExpObject::createNoStatics(cx, source, reobj.getFlags(), NULL); - } else if (srcObj->isDate()) { - clone = JS_NewDateObjectMsec(cx, srcObj->getDateUTCTime().toNumber()); + } else if (srcObj->is()) { + clone = JS_NewDateObjectMsec(cx, srcObj->as().UTCTime().toNumber()); } else if (srcObj->is()) { clone = BooleanObject::create(cx, srcObj->as().unbox()); } else if (srcObj->is()) { @@ -811,7 +811,7 @@ CloneObject(JSContext *cx, HandleObject srcObj, CloneMemory &clonedObjects) if (!str) return NULL; clone = StringObject::create(cx, str); - } else if (srcObj->isArray()) { + } else if (srcObj->is()) { clone = NewDenseEmptyArray(cx, NULL, TenuredObject); } else { JS_ASSERT(srcObj->isNative()); diff --git a/js/src/vm/Shape-inl.h b/js/src/vm/Shape-inl.h index f9122420f..833d7069d 100644 --- a/js/src/vm/Shape-inl.h +++ b/js/src/vm/Shape-inl.h @@ -26,8 +26,6 @@ #include "jscntxtinlines.h" #include "jsgcinlines.h" -#include "vm/ScopeObject-inl.h" - namespace js { static inline void diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index da08e893b..6c3ef474d 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -590,10 +590,11 @@ JSObject::putProperty(JSContext *cx, HandleObject obj, HandleId id, JS_ASSERT(!JSID_IS_VOID(id)); #ifdef DEBUG - if (obj->isArray()) { + if (obj->is()) { + ArrayObject *arr = &obj->as(); uint32_t index; if (js_IdIsIndex(id, &index)) - JS_ASSERT(index < obj->getArrayLength() || obj->arrayLengthIsWritable()); + JS_ASSERT(index < arr->length() || arr->lengthIsWritable()); } #endif diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 2130d9669..906109752 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -192,20 +192,7 @@ StackFrame::createRestParameter(JSContext *cx) unsigned nformal = fun()->nargs - 1, nactual = numActualArgs(); unsigned nrest = (nactual > nformal) ? nactual - nformal : 0; Value *restvp = argv() + nformal; - RootedObject obj(cx, NewDenseCopiedArray(cx, nrest, restvp, NULL)); - if (!obj) - return NULL; - - RootedTypeObject type(cx, types::GetTypeCallerInitObject(cx, JSProto_Array)); - if (!type) - return NULL; - obj->setType(type); - - /* Ensure that values in the rest array are represented in the type of the array. */ - for (unsigned i = 0; i < nrest; i++) - types::AddTypePropertyId(cx, obj, JSID_VOID, restvp[i]); - - return obj; + return NewDenseCopiedArray(cx, nrest, restvp, NULL); } static inline void diff --git a/js/src/vm/String.cpp b/js/src/vm/String.cpp index 43fafb64a..9d0ff34ad 100644 --- a/js/src/vm/String.cpp +++ b/js/src/vm/String.cpp @@ -4,7 +4,7 @@ * 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 "vm/String.h" +#include "vm/String-inl.h" #include "mozilla/MemoryReporting.h" #include "mozilla/PodOperations.h" @@ -14,7 +14,9 @@ #include "jscompartmentinlines.h" -#include "String-inl.h" +#ifdef JSGC_GENERATIONAL +#include "vm/Shape-inl.h" +#endif using namespace js; diff --git a/js/xpconnect/src/event_impl_gen.conf.in b/js/xpconnect/src/event_impl_gen.conf.in index 748d6f744..8a3db4092 100644 --- a/js/xpconnect/src/event_impl_gen.conf.in +++ b/js/xpconnect/src/event_impl_gen.conf.in @@ -57,7 +57,6 @@ simple_events = [ #endif #ifdef MOZ_WEBSPEECH 'SpeechRecognitionEvent', - 'SpeechRecognitionError', #endif ] diff --git a/layout/base/nsIPresShell.h b/layout/base/nsIPresShell.h index c14dcafa8..e6057b48b 100644 --- a/layout/base/nsIPresShell.h +++ b/layout/base/nsIPresShell.h @@ -173,7 +173,8 @@ protected: typedef mozilla::layers::LayerManager LayerManager; enum eRenderFlag { - STATE_IGNORING_VIEWPORT_SCROLLING = 0x1 + STATE_IGNORING_VIEWPORT_SCROLLING = 0x1, + STATE_DRAWWINDOW_NOT_FLUSHING = 0x2 }; typedef uint8_t RenderFlags; // for storing the above flags @@ -970,7 +971,8 @@ public: RENDER_CARET = 0x04, RENDER_USE_WIDGET_LAYERS = 0x08, RENDER_ASYNC_DECODE_IMAGES = 0x10, - RENDER_DOCUMENT_RELATIVE = 0x20 + RENDER_DOCUMENT_RELATIVE = 0x20, + RENDER_DRAWWINDOW_NOT_FLUSHING = 0x40 }; virtual NS_HIDDEN_(nsresult) RenderDocument(const nsRect& aRect, uint32_t aFlags, nscolor aBackgroundColor, @@ -1207,6 +1209,13 @@ public: float GetXResolution() { return mXResolution; } float GetYResolution() { return mYResolution; } + /** + * Returns whether we are in a DrawWindow() call that used the + * DRAWWINDOW_DO_NOT_FLUSH flag. + */ + bool InDrawWindowNotFlushing() const + { return mRenderFlags & STATE_DRAWWINDOW_NOT_FLUSHING; } + /** * Set the isFirstPaint flag. */ diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index cd730f252..40bdfb422 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -4277,6 +4277,9 @@ PresShell::RenderDocument(const nsRect& aRect, uint32_t aFlags, wouldFlushRetainedLayers = !IgnoringViewportScrolling(); mRenderFlags = ChangeFlag(mRenderFlags, true, STATE_IGNORING_VIEWPORT_SCROLLING); } + if (aFlags & RENDER_DRAWWINDOW_NOT_FLUSHING) { + mRenderFlags = ChangeFlag(mRenderFlags, true, STATE_DRAWWINDOW_NOT_FLUSHING); + } if (aFlags & RENDER_DOCUMENT_RELATIVE) { // XXX be smarter about this ... drawWindow might want a rect // that's "pretty close" to what our retained layer tree covers. diff --git a/layout/style/AnimationCommon.cpp b/layout/style/AnimationCommon.cpp index 93ee787c4..3aaa29742 100644 --- a/layout/style/AnimationCommon.cpp +++ b/layout/style/AnimationCommon.cpp @@ -59,28 +59,6 @@ CommonAnimationManager::Disconnect() mPresContext = nullptr; } -void -CommonAnimationManager::AddElementData(CommonElementAnimationData* aData) -{ - if (PR_CLIST_IS_EMPTY(&mElementData)) { - // We need to observe the refresh driver. - nsRefreshDriver *rd = mPresContext->RefreshDriver(); - rd->AddRefreshObserver(this, Flush_Style); - } - - PR_INSERT_BEFORE(aData, &mElementData); -} - -void -CommonAnimationManager::ElementDataRemoved() -{ - // If we have no transitions or animations left, remove ourselves from - // the refresh driver. - if (PR_CLIST_IS_EMPTY(&mElementData)) { - mPresContext->RefreshDriver()->RemoveRefreshObserver(this, Flush_Style); - } -} - void CommonAnimationManager::RemoveAllElementData() { diff --git a/layout/style/AnimationCommon.h b/layout/style/AnimationCommon.h index a247ddd09..09f18a2f2 100644 --- a/layout/style/AnimationCommon.h +++ b/layout/style/AnimationCommon.h @@ -65,8 +65,8 @@ public: protected: friend struct CommonElementAnimationData; // for ElementDataRemoved - void AddElementData(CommonElementAnimationData* aData); - void ElementDataRemoved(); + virtual void AddElementData(CommonElementAnimationData* aData) = 0; + virtual void ElementDataRemoved() = 0; void RemoveAllElementData(); PRCList mElementData; diff --git a/layout/style/nsAnimationManager.cpp b/layout/style/nsAnimationManager.cpp index 413c5ee15..71c46b536 100644 --- a/layout/style/nsAnimationManager.cpp +++ b/layout/style/nsAnimationManager.cpp @@ -474,6 +474,7 @@ nsAnimationManager::EnsureStyleRuleFor(ElementAnimations* aET) aET->EnsureStyleRuleFor(mPresContext->RefreshDriver()->MostRecentRefresh(), mPendingEvents, false); + CheckNeedsRefresh(); } /* virtual */ void @@ -636,6 +637,7 @@ nsAnimationManager::CheckAnimationRule(nsStyleContext* aStyleContext, ea->mNeedsRefreshes = true; ea->EnsureStyleRuleFor(refreshTime, mPendingEvents, false); + CheckNeedsRefresh(); // We don't actually dispatch the mPendingEvents now. We'll either // dispatch them the next time we get a refresh driver notification // or the next time somebody calls @@ -1005,6 +1007,39 @@ nsAnimationManager::WillRefresh(mozilla::TimeStamp aTime) FlushAnimations(Can_Throttle); } +void +nsAnimationManager::AddElementData(CommonElementAnimationData* aData) +{ + if (!mObservingRefreshDriver) { + NS_ASSERTION(static_cast(aData)->mNeedsRefreshes, + "Added data which doesn't need refreshing?"); + // We need to observe the refresh driver. + mPresContext->RefreshDriver()->AddRefreshObserver(this, Flush_Style); + mObservingRefreshDriver = true; + } + + PR_INSERT_BEFORE(aData, &mElementData); +} + +void +nsAnimationManager::CheckNeedsRefresh() +{ + for (PRCList *l = PR_LIST_HEAD(&mElementData); l != &mElementData; + l = PR_NEXT_LINK(l)) { + if (static_cast(l)->mNeedsRefreshes) { + if (!mObservingRefreshDriver) { + mPresContext->RefreshDriver()->AddRefreshObserver(this, Flush_Style); + mObservingRefreshDriver = true; + } + return; + } + } + if (mObservingRefreshDriver) { + mObservingRefreshDriver = false; + mPresContext->RefreshDriver()->RemoveRefreshObserver(this, Flush_Style); + } +} + void nsAnimationManager::FlushAnimations(FlushFlags aFlags) { @@ -1023,6 +1058,7 @@ nsAnimationManager::FlushAnimations(FlushFlags aFlags) nsRefPtr oldStyleRule = ea->mStyleRule; ea->EnsureStyleRuleFor(now, mPendingEvents, canThrottleTick); + CheckNeedsRefresh(); if (oldStyleRule != ea->mStyleRule) { ea->PostRestyleForAnimation(mPresContext); } else { diff --git a/layout/style/nsAnimationManager.h b/layout/style/nsAnimationManager.h index c89822ac7..49b96125f 100644 --- a/layout/style/nsAnimationManager.h +++ b/layout/style/nsAnimationManager.h @@ -145,6 +145,8 @@ struct ElementAnimations MOZ_FINAL // run (because it is not currently active and has no fill behavior), but // only does so if aAnimation is non-null; with a null aAnimation it is an // error to give aCurrentTime < aStartTime, and fill-forwards is assumed. + // After calling GetPositionInIteration with non-null aAnimation and aEa, be + // sure to call CheckNeedsRefresh on the animation manager afterwards. static double GetPositionInIteration(TimeDuration aElapsedDuration, TimeDuration aIterationDuration, double aIterationCount, @@ -187,11 +189,13 @@ struct ElementAnimations MOZ_FINAL InfallibleTArray mAnimations; }; -class nsAnimationManager : public mozilla::css::CommonAnimationManager +class nsAnimationManager MOZ_FINAL + : public mozilla::css::CommonAnimationManager { public: nsAnimationManager(nsPresContext *aPresContext) : mozilla::css::CommonAnimationManager(aPresContext) + , mObservingRefreshDriver(false) { } @@ -274,6 +278,18 @@ public: nsCSSPseudoElements::Type aPseudoType, bool aCreateIfNeeded); +protected: + virtual void ElementDataRemoved() MOZ_OVERRIDE + { + CheckNeedsRefresh(); + } + virtual void AddElementData(mozilla::css::CommonElementAnimationData* aData) MOZ_OVERRIDE; + + /** + * Check to see if we should stop or start observing the refresh driver + */ + void CheckNeedsRefresh(); + private: void BuildAnimations(nsStyleContext* aStyleContext, InfallibleTArray& aAnimations); @@ -289,6 +305,8 @@ private: void DoDispatchEvents(); EventArray mPendingEvents; + + bool mObservingRefreshDriver; }; #endif /* !defined(nsAnimationManager_h_) */ diff --git a/layout/style/nsTransitionManager.cpp b/layout/style/nsTransitionManager.cpp index 46bd41317..e0ea0c928 100644 --- a/layout/style/nsTransitionManager.cpp +++ b/layout/style/nsTransitionManager.cpp @@ -436,6 +436,28 @@ nsTransitionManager::UpdateAllThrottledStyles() FlushOverflowChangedTracker(); } +void +nsTransitionManager::ElementDataRemoved() +{ + // If we have no transitions or animations left, remove ourselves from + // the refresh driver. + if (PR_CLIST_IS_EMPTY(&mElementData)) { + mPresContext->RefreshDriver()->RemoveRefreshObserver(this, Flush_Style); + } +} + +void +nsTransitionManager::AddElementData(CommonElementAnimationData* aData) +{ + if (PR_CLIST_IS_EMPTY(&mElementData)) { + // We need to observe the refresh driver. + nsRefreshDriver *rd = mPresContext->RefreshDriver(); + rd->AddRefreshObserver(this, Flush_Style); + } + + PR_INSERT_BEFORE(aData, &mElementData); +} + already_AddRefed nsTransitionManager::StyleContextChanged(dom::Element *aElement, nsStyleContext *aOldStyleContext, @@ -1120,9 +1142,6 @@ nsTransitionManager::FlushTransitions(FlushFlags aFlags) } } - // We might have removed transitions above. - ElementDataRemoved(); - if (didThrottle) { mPresContext->Document()->SetNeedStyleFlush(); } diff --git a/layout/style/nsTransitionManager.h b/layout/style/nsTransitionManager.h index 02f748b29..352c94353 100644 --- a/layout/style/nsTransitionManager.h +++ b/layout/style/nsTransitionManager.h @@ -100,7 +100,8 @@ struct ElementTransitions MOZ_FINAL -class nsTransitionManager : public mozilla::css::CommonAnimationManager +class nsTransitionManager MOZ_FINAL + : public mozilla::css::CommonAnimationManager { public: nsTransitionManager(nsPresContext *aPresContext) @@ -202,6 +203,10 @@ public: // other than primary frames. void UpdateAllThrottledStyles(); +protected: + virtual void ElementDataRemoved() MOZ_OVERRIDE; + virtual void AddElementData(mozilla::css::CommonElementAnimationData* aData) MOZ_OVERRIDE; + private: void ConsiderStartingTransition(nsCSSProperty aProperty, const nsTransition& aTransition, diff --git a/layout/svg/nsSVGGlyphFrame.cpp b/layout/svg/nsSVGGlyphFrame.cpp index e20f636f9..1734d57ee 100644 --- a/layout/svg/nsSVGGlyphFrame.cpp +++ b/layout/svg/nsSVGGlyphFrame.cpp @@ -972,7 +972,7 @@ nsSVGGlyphFrame::SetupCairoStroke(gfxContext *aContext, } const nsStyleSVG *style = StyleSVG(); - nsSVGUtils::SetupCairoStrokeHitGeometry(this, aContext, aOuterObjectPaint); + nsSVGUtils::SetupCairoStrokeGeometry(this, aContext, aOuterObjectPaint); float opacity = nsSVGUtils::GetOpacity(style->mStrokeOpacitySource, style->mStrokeOpacity, aOuterObjectPaint); diff --git a/layout/svg/nsSVGPathGeometryFrame.cpp b/layout/svg/nsSVGPathGeometryFrame.cpp index e81466d39..50d48aea9 100644 --- a/layout/svg/nsSVGPathGeometryFrame.cpp +++ b/layout/svg/nsSVGPathGeometryFrame.cpp @@ -259,7 +259,7 @@ nsSVGPathGeometryFrame::GetFrameForPoint(const nsPoint &aPoint) if (hitTestFlags & SVG_HIT_TEST_FILL) isHit = tmpCtx->PointInFill(userSpacePoint); if (!isHit && (hitTestFlags & SVG_HIT_TEST_STROKE)) { - nsSVGUtils::SetupCairoStrokeHitGeometry(this, tmpCtx); + nsSVGUtils::SetupCairoStrokeGeometry(this, tmpCtx); // tmpCtx's matrix may have transformed by SetupCairoStrokeGeometry // if there is a non-scaling stroke. We need to transform userSpacePoint // so that everything is using the same coordinate system. @@ -447,7 +447,7 @@ nsSVGPathGeometryFrame::GetBBoxContribution(const gfxMatrix &aToBBoxUserspace, // though, because if pathExtents is empty, its position will not have // been set. Happily we can use tmpCtx->GetUserStrokeExtent() to find // the center point of the extents even though it gets the extents wrong. - nsSVGUtils::SetupCairoStrokeGeometry(this, tmpCtx); + nsSVGUtils::SetupCairoStrokeBBoxGeometry(this, tmpCtx); pathExtents.MoveTo(tmpCtx->GetUserStrokeExtent().Center()); pathExtents.SizeTo(0, 0); } diff --git a/layout/svg/nsSVGTextFrame2.cpp b/layout/svg/nsSVGTextFrame2.cpp index 465b524fc..39c7213ac 100644 --- a/layout/svg/nsSVGTextFrame2.cpp +++ b/layout/svg/nsSVGTextFrame2.cpp @@ -3356,12 +3356,22 @@ nsSVGTextFrame2::PaintSVG(nsRenderingContext* aContext, if (!kid) return NS_OK; + nsPresContext* presContext = PresContext(); + gfxContext *gfx = aContext->ThebesContext(); gfxMatrix initialMatrix = gfx->CurrentMatrix(); AutoCanvasTMForMarker autoCanvasTMFor(this, FOR_PAINTING); if (mState & NS_STATE_SVG_NONDISPLAY_CHILD) { + // If we are in a canvas DrawWindow call that used the + // DRAWWINDOW_DO_NOT_FLUSH flag, then we may still have out + // of date frames. Just don't paint anything if they are + // dirty. + if (presContext->PresShell()->InDrawWindowNotFlushing() && + NS_SUBTREE_DIRTY(this)) { + return NS_OK; + } // Text frames inside , , etc. will never have had // ReflowSVG called on them, so call UpdateGlyphPositioning to do this now. UpdateGlyphPositioning(); @@ -3381,8 +3391,6 @@ nsSVGTextFrame2::PaintSVG(nsRenderingContext* aContext, gfxMatrix matrixForPaintServers(canvasTM); matrixForPaintServers.Multiply(initialMatrix); - nsPresContext* presContext = PresContext(); - // Check if we need to draw anything. if (aDirtyRect) { NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() || @@ -5307,7 +5315,7 @@ nsSVGTextFrame2::SetupCairoStroke(gfxContext* aContext, gfxContextMatrixAutoSaveRestore matrixRestore(aContext); aContext->IdentityMatrix(); - nsSVGUtils::SetupCairoStrokeHitGeometry(aFrame, aContext, aOuterObjectPaint); + nsSVGUtils::SetupCairoStrokeGeometry(aFrame, aContext, aOuterObjectPaint); float opacity = nsSVGUtils::GetOpacity(style->mStrokeOpacitySource, style->mStrokeOpacity, aOuterObjectPaint); diff --git a/layout/svg/nsSVGUtils.cpp b/layout/svg/nsSVGUtils.cpp index 644887596..2f3335bd5 100644 --- a/layout/svg/nsSVGUtils.cpp +++ b/layout/svg/nsSVGUtils.cpp @@ -1640,8 +1640,9 @@ nsSVGUtils::GetStrokeWidth(nsIFrame* aFrame, gfxTextObjectPaint *aObjectPaint) } void -nsSVGUtils::SetupCairoStrokeGeometry(nsIFrame* aFrame, gfxContext *aContext, - gfxTextObjectPaint *aObjectPaint) +nsSVGUtils::SetupCairoStrokeBBoxGeometry(nsIFrame* aFrame, + gfxContext *aContext, + gfxTextObjectPaint *aObjectPaint) { float width = GetStrokeWidth(aFrame, aObjectPaint); if (width <= 0) @@ -1745,10 +1746,10 @@ GetStrokeDashData(nsIFrame* aFrame, } void -nsSVGUtils::SetupCairoStrokeHitGeometry(nsIFrame* aFrame, gfxContext* aContext, - gfxTextObjectPaint *aObjectPaint) +nsSVGUtils::SetupCairoStrokeGeometry(nsIFrame* aFrame, gfxContext* aContext, + gfxTextObjectPaint *aObjectPaint) { - SetupCairoStrokeGeometry(aFrame, aContext, aObjectPaint); + SetupCairoStrokeBBoxGeometry(aFrame, aContext, aObjectPaint); AutoFallibleTArray dashes; gfxFloat dashOffset; @@ -1823,7 +1824,7 @@ nsSVGUtils::SetupCairoStroke(nsIFrame* aFrame, gfxContext* aContext, if (!HasStroke(aFrame, aObjectPaint)) { return false; } - SetupCairoStrokeHitGeometry(aFrame, aContext, aObjectPaint); + SetupCairoStrokeGeometry(aFrame, aContext, aObjectPaint); return SetupCairoStrokePaint(aFrame, aContext, aObjectPaint); } diff --git a/layout/svg/nsSVGUtils.h b/layout/svg/nsSVGUtils.h index 00b2d6e96..bb0b99643 100644 --- a/layout/svg/nsSVGUtils.h +++ b/layout/svg/nsSVGUtils.h @@ -641,17 +641,19 @@ public: gfxTextObjectPaint *aObjectPaint = nullptr); /* - * Set up a cairo context for measuring a stroked path + * Set up a cairo context for measuring the bounding box of a stroked path. + */ + static void SetupCairoStrokeBBoxGeometry(nsIFrame* aFrame, + gfxContext *aContext, + gfxTextObjectPaint *aObjectPaint = nullptr); + + /* + * Set up a cairo context for a stroked path (including any dashing that + * applies). */ static void SetupCairoStrokeGeometry(nsIFrame* aFrame, gfxContext *aContext, gfxTextObjectPaint *aObjectPaint = nullptr); - /* - * Set up a cairo context for hit testing a stroked path - */ - static void SetupCairoStrokeHitGeometry(nsIFrame* aFrame, gfxContext *aContext, - gfxTextObjectPaint *aObjectPaint = nullptr); - /* * Set up a cairo context for stroking, including setting up any stroke-related * properties such as dashing and setting the current paint on the gfxContext. diff --git a/mfbt/CheckedInt.h b/mfbt/CheckedInt.h index e0c0ebe74..a6f68b56a 100644 --- a/mfbt/CheckedInt.h +++ b/mfbt/CheckedInt.h @@ -604,7 +604,7 @@ class CheckedInt "This type is not supported by CheckedInt"); } - friend class detail::NegateImpl; + friend struct detail::NegateImpl; public: /** diff --git a/mobile/android/chrome/content/WebAppRT.js b/mobile/android/chrome/content/WebAppRT.js index 26db33892..59ac0715e 100644 --- a/mobile/android/chrome/content/WebAppRT.js +++ b/mobile/android/chrome/content/WebAppRT.js @@ -8,6 +8,7 @@ let Cu = Components.utils; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/FileUtils.jsm"); Cu.import("resource://gre/modules/NetUtil.jsm"); +Cu.import("resource://gre/modules/PermissionsInstaller.jsm"); function pref(name, value) { return { @@ -42,21 +43,23 @@ let WebAppRT = { // prevent offering to use helper apps for things that this app handles // i.e. don't show the "Open in market?" popup when we're showing the market app let uri = Services.io.newURI(aUrl, null, null); - Services.perms.add(uri, "native-intent", Ci.nsIPermissionManager.DENY_ACTION); - Services.perms.add(uri, "offline-app", Ci.nsIPermissionManager.ALLOW_ACTION); - Services.perms.add(uri, "indexedDB", Ci.nsIPermissionManager.ALLOW_ACTION); - Services.perms.add(uri, "indexedDB-unlimited", Ci.nsIPermissionManager.ALLOW_ACTION); // update the blocklist url to use a different app id let blocklist = Services.prefs.getCharPref("extensions.blocklist.url"); blocklist = blocklist.replace(/%APP_ID%/g, "webapprt-mobile@mozilla.org"); Services.prefs.setCharPref("extensions.blocklist.url", blocklist); + + this.getManifestFor(aUrl, function (aManifest, aApp) { + if (aManifest) { + PermissionsInstaller.installPermissions(aApp, true); + } + }); } this.findManifestUrlFor(aUrl, aCallback); }, - findManifestUrlFor: function(aUrl, aCallback) { + getManifestFor: function (aUrl, aCallback) { let request = navigator.mozApps.mgmt.getAll(); request.onsuccess = function() { let apps = request.result; @@ -64,35 +67,38 @@ let WebAppRT = { let app = apps[i]; let manifest = new ManifestHelper(app.manifest, app.origin); - // First see if this url matches any manifests we have registered - // If so, get the launchUrl from the manifest and we'll launch with that - //let app = DOMApplicationRegistry.getAppByManifestURL(aUrl); - if (app.manifestURL == aUrl) { - BrowserApp.manifest = app.manifest; - BrowserApp.manifestUrl = aUrl; - aCallback(manifest.fullLaunchPath()); - return; - } - - // Otherwise, see if the apps launch path is this url - if (manifest.fullLaunchPath() == aUrl) { - BrowserApp.manifest = app.manifest; - BrowserApp.manifestUrl = app.manifestURL; - aCallback(aUrl); + // if this is a path to the manifest, or the launch path, then we have a hit. + if (app.manifestURL == aUrl || manifest.fullLaunchPath() == aUrl) { + aCallback(manifest, app); return; } } - // Finally, just attempt to open the webapp as a normal web page - aCallback(aUrl); + // Otherwise, once we loop through all of them, we have a miss. + aCallback(undefined); }; request.onerror = function() { - // Attempt to open the webapp as a normal web page - aCallback(aUrl); + // Treat an error like a miss. We can't find the manifest. + aCallback(undefined); }; }, + findManifestUrlFor: function(aUrl, aCallback) { + this.getManifestFor(aUrl, function(aManifest, aApp) { + if (!aManifest) { + // we can't find the manifest, so open it like a web page + aCallback(aUrl); + return; + } + + BrowserApp.manifest = aManifest; + BrowserApp.manifestUrl = aApp.manifestURL; + + aCallback(aManifest.fullLaunchPath()); + }); + }, + getDefaultPrefs: function() { // read default prefs from the disk try { @@ -134,7 +140,7 @@ let WebAppRT = { handleEvent: function(event) { let target = event.target; - + // walk up the tree to find the nearest link tag while (target && !(target instanceof HTMLAnchorElement)) { target = target.parentNode; @@ -143,15 +149,15 @@ let WebAppRT = { if (!target || target.getAttribute("target") != "_blank") { return; } - + let uri = Services.io.newURI(target.href, target.ownerDocument.characterSet, null); - + // Direct the URL to the browser. Cc["@mozilla.org/uriloader/external-protocol-service;1"]. getService(Ci.nsIExternalProtocolService). getProtocolHandlerInfo(uri.scheme). launchWithURI(uri); - + // Prevent the runtime from loading the URL. We do this after directing it // to the browser to give the runtime a shot at handling the URL if we fail // to direct it to the browser for some reason. diff --git a/netwerk/protocol/http/SpdySession3.cpp b/netwerk/protocol/http/SpdySession3.cpp index d2ef75436..394bc6e20 100644 --- a/netwerk/protocol/http/SpdySession3.cpp +++ b/netwerk/protocol/http/SpdySession3.cpp @@ -623,7 +623,7 @@ SpdySession3::UncompressAndDiscard(uint32_t offset, if (zlib_rv == Z_NEED_DICT) { if (triedDictionary) { LOG3(("SpdySession3::UncompressAndDiscard %p Dictionary Error\n", this)); - return NS_ERROR_FAILURE; + return NS_ERROR_ILLEGAL_VALUE; } triedDictionary = true; @@ -631,7 +631,10 @@ SpdySession3::UncompressAndDiscard(uint32_t offset, sizeof(SpdyStream3::kDictionary)); } - if (zlib_rv == Z_DATA_ERROR || zlib_rv == Z_MEM_ERROR) + if (zlib_rv == Z_DATA_ERROR) + return NS_ERROR_ILLEGAL_VALUE; + + if (zlib_rv == Z_MEM_ERROR) return NS_ERROR_FAILURE; } while (mDownstreamZlib.avail_in); @@ -1146,11 +1149,11 @@ SpdySession3::HandleSynReply(SpdySession3 *self) if (streamID >= self->mNextStreamID) self->GenerateRstStream(RST_INVALID_STREAM, streamID); - if (NS_FAILED(self->UncompressAndDiscard(12, - self->mInputFrameDataSize - 4))) { + rv = self->UncompressAndDiscard(12, self->mInputFrameDataSize - 4); + if (NS_FAILED(rv)) { LOG(("SpdySession3::HandleSynReply uncompress failed\n")); // this is fatal to the session - return NS_ERROR_FAILURE; + return rv; } self->ResetDownstreamState(); @@ -1168,7 +1171,7 @@ SpdySession3::HandleSynReply(SpdySession3 *self) if (NS_FAILED(rv)) { LOG(("SpdySession3::HandleSynReply uncompress failed\n")); - return NS_ERROR_FAILURE; + return rv; } if (self->mInputFrameDataStream->GetFullyOpen()) { @@ -1519,11 +1522,11 @@ SpdySession3::HandleHeaders(SpdySession3 *self) if (streamID >= self->mNextStreamID) self->GenerateRstStream(RST_INVALID_STREAM, streamID); - if (NS_FAILED(self->UncompressAndDiscard(12, - self->mInputFrameDataSize - 4))) { + rv = self->UncompressAndDiscard(12, self->mInputFrameDataSize - 4); + if (NS_FAILED(rv)) { LOG(("SpdySession3::HandleHeaders uncompress failed\n")); // this is fatal to the session - return NS_ERROR_FAILURE; + return rv; } self->ResetDownstreamState(); return NS_OK; @@ -1539,7 +1542,7 @@ SpdySession3::HandleHeaders(SpdySession3 *self) self->mInputFrameDataSize - 4); if (NS_FAILED(rv)) { LOG(("SpdySession3::HandleHeaders uncompress failed\n")); - return NS_ERROR_FAILURE; + return rv; } self->mInputFrameDataLast = self->mInputFrameBuffer[4] & kFlag_Data_FIN; @@ -2212,8 +2215,15 @@ SpdySession3::Close(nsresult aReason) mStreamIDHash.Clear(); mStreamTransactionHash.Clear(); - if (NS_SUCCEEDED(aReason)) - GenerateGoAway(OK); + uint32_t goAwayReason; + if (NS_SUCCEEDED(aReason)) { + goAwayReason = OK; + } else if (aReason == NS_ERROR_ILLEGAL_VALUE) { + goAwayReason = PROTOCOL_ERROR; + } else { + goAwayReason = INTERNAL_ERROR; + } + GenerateGoAway(goAwayReason); mConnection = nullptr; mSegmentReader = nullptr; mSegmentWriter = nullptr; diff --git a/netwerk/protocol/http/SpdyStream3.cpp b/netwerk/protocol/http/SpdyStream3.cpp index f92a0f01f..34f63b5df 100644 --- a/netwerk/protocol/http/SpdyStream3.cpp +++ b/netwerk/protocol/http/SpdyStream3.cpp @@ -1014,14 +1014,17 @@ SpdyStream3::Uncompress(z_stream *context, if (zlib_rv == Z_NEED_DICT) { if (triedDictionary) { LOG3(("SpdySession3::Uncompress %p Dictionary Error\n", this)); - return NS_ERROR_FAILURE; + return NS_ERROR_ILLEGAL_VALUE; } triedDictionary = true; inflateSetDictionary(context, kDictionary, sizeof(kDictionary)); } - if (zlib_rv == Z_DATA_ERROR || zlib_rv == Z_MEM_ERROR) + if (zlib_rv == Z_DATA_ERROR) + return NS_ERROR_ILLEGAL_VALUE; + + if (zlib_rv == Z_MEM_ERROR) return NS_ERROR_FAILURE; // zlib's inflate() decreases context->avail_out by the amount it places diff --git a/testing/specialpowers/content/specialpowersAPI.js b/testing/specialpowers/content/specialpowersAPI.js index 30bf79cf9..293555d18 100644 --- a/testing/specialpowers/content/specialpowersAPI.js +++ b/testing/specialpowers/content/specialpowersAPI.js @@ -1112,33 +1112,42 @@ SpecialPowersAPI.prototype = { return this.wrap(Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest)); }, - snapshotWindow: function (win, withCaret, rect, bgcolor) { + snapshotWindowWithOptions: function (win, rect, bgcolor, options) { var el = this.window.get().document.createElementNS("http://www.w3.org/1999/xhtml", "canvas"); - if (arguments.length < 3) { + if (rect === undefined) { rect = { top: win.scrollY, left: win.scrollX, width: win.innerWidth, height: win.innerHeight }; } - if (arguments.length < 4) { + if (bgcolor === undefined) { bgcolor = "rgb(255,255,255)"; } + if (options === undefined) { + options = { }; + } el.width = rect.width; el.height = rect.height; var ctx = el.getContext("2d"); var flags = 0; + for (var option in options) { + flags |= options[option] && ctx[option]; + } + ctx.drawWindow(win, rect.left, rect.top, rect.width, rect.height, bgcolor, - withCaret ? ctx.DRAWWINDOW_DRAW_CARET : 0); + flags); return el; }, + snapshotWindow: function (win, withCaret, rect, bgcolor) { + return this.snapshotWindowWithOptions(win, rect, bgcolor, + { DRAWWINDOW_DRAW_CARET: withCaret }); + }, + snapshotRect: function (win, rect, bgcolor) { - // Splice in our "do not want caret" bit - args = Array.slice(arguments); - args.splice(1, 0, false); - return this.snapshotWindow.apply(this, args); + return this.snapshotWindowWithOptions(win, rect, bgcolor); }, gc: function() { diff --git a/toolkit/components/places/moz.build b/toolkit/components/places/moz.build index 3b427c341..f1d9a7891 100644 --- a/toolkit/components/places/moz.build +++ b/toolkit/components/places/moz.build @@ -22,7 +22,7 @@ if CONFIG['MOZ_PLACES']: 'nsIBrowserHistory.idl', 'nsIFaviconService.idl', 'nsINavBookmarksService.idl', - 'nsITaggingService.idl ', + 'nsITaggingService.idl', 'nsPIPlacesDatabase.idl', 'nsPIPlacesHistoryListenersNotifier.idl', ] diff --git a/toolkit/components/thumbnails/content/backgroundPageThumbsContent.js b/toolkit/components/thumbnails/content/backgroundPageThumbsContent.js index d10699160..9597e82cb 100644 --- a/toolkit/components/thumbnails/content/backgroundPageThumbsContent.js +++ b/toolkit/components/thumbnails/content/backgroundPageThumbsContent.js @@ -18,6 +18,9 @@ const backgroundPageThumbsContent = { getInterface(Ci.nsIDOMWindowUtils); dwu.preventFurtherDialogs(); + docShell.allowMedia = false; + docShell.allowPlugins = false; + // Stop about:blank from loading. If it finishes loading after a capture // request is received, it could trigger the capture's load listener. this._webNav.stop(Ci.nsIWebNavigation.STOP_NETWORK); diff --git a/toolkit/mozapps/update/test/TestAUSReadStrings.cpp b/toolkit/mozapps/update/test/TestAUSReadStrings.cpp index 3c12865d0..311e6f970 100644 --- a/toolkit/mozapps/update/test/TestAUSReadStrings.cpp +++ b/toolkit/mozapps/update/test/TestAUSReadStrings.cpp @@ -74,16 +74,6 @@ void fail(const char* msg, ...) ++gFailCount; } -/** - * Prints the given string prepending "TEST-PASS | " for the benefit of - * the test harness and with "\n" at the end, to be used at the end of a - * successful test function. - */ -void passed(const char* test) -{ - printf("TEST-PASS | %s\n", test); -} - int NS_main(int argc, NS_tchar **argv) { printf("Running TestAUSReadStrings tests\n"); diff --git a/xpcom/base/nsMemoryInfoDumper.cpp b/xpcom/base/nsMemoryInfoDumper.cpp index c2dd773ee..dae89ae93 100644 --- a/xpcom/base/nsMemoryInfoDumper.cpp +++ b/xpcom/base/nsMemoryInfoDumper.cpp @@ -184,7 +184,7 @@ public: * function is also called when you're at eof (read() returns 0 in this case). */ virtual void OnFileCanReadWithoutBlocking(int aFd) = 0; - virtual void OnFileCanWriteWithoutBlocking(int Afd) {}; + virtual void OnFileCanWriteWithoutBlocking(int aFd) {}; NS_DECL_ISUPPORTS