mirror of
https://github.com/roytam1/palemoon26.git
synced 2026-05-26 05:44:31 +00:00
cherry-picked upstream changes:
bug886205, bug870103, bug886611, bug886241, bug878142, bug857334, bug886128, bug885596, bug887068, bug868302, bug886575, bug809969, bug860782, bug886285, bug848592, bug877748, bug886647, bug879079, bug886827, bug884648, bug866638, bug885463, bug826124, bug844805, bug886551, bug884407, bug884369, bug887002, bug886632, 572efc8fea86, bug886230, bug886689, bug884124
This commit is contained in:
@@ -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 },
|
||||
|
||||
@@ -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() &&
|
||||
|
||||
@@ -830,6 +830,10 @@ already_AddRefed<nsFrameSelection>
|
||||
XULTextFieldAccessible::FrameSelection()
|
||||
{
|
||||
nsCOMPtr<nsIContent> inputContent(GetInputField());
|
||||
NS_ASSERTION(inputContent, "No input content");
|
||||
if (!inputContent)
|
||||
return nullptr;
|
||||
|
||||
nsIFrame* frame = inputContent->GetPrimaryFrame();
|
||||
return frame ? frame->GetFrameSelection() : nullptr;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
</pre>
|
||||
|
||||
<!-- aria -->
|
||||
<div id="atomic" aria-atomic="true"></div>
|
||||
<div id="atomic" aria-atomic="true">live region</div>
|
||||
<div id="atomic_false" aria-atomic="false">live region</div>
|
||||
<div id="autocomplete" role="textbox" aria-autocomplete="true"></div>
|
||||
<div id="checkbox" role="checkbox"></div>
|
||||
<div id="checkedCheckbox" role="checkbox" aria-checked="true"></div>
|
||||
|
||||
@@ -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 @@
|
||||
<input type="button" id="button" aria-controls="lr1 lr2"
|
||||
onclick="getNode('lr1').textContent += '1'; getNode('lr2').textContent += 'a';"/>
|
||||
|
||||
<div id="atomic" aria-atomic="true">live region</div>
|
||||
|
||||
<span id="flowto" aria-flowto="flowfrom">flow to</span>
|
||||
<span id="flowfrom">flow from</span>
|
||||
|
||||
|
||||
@@ -464,7 +464,7 @@ var PlacesCommandHook = {
|
||||
"", "chrome,toolbar=yes,dialog=no,resizable", aLeftPaneRoot);
|
||||
}
|
||||
else {
|
||||
organizer.PlacesOrganizer.selectLeftPaneQuery(aLeftPaneRoot);
|
||||
organizer.PlacesOrganizer.selectLeftPaneContainerByHierarchy(aLeftPaneRoot);
|
||||
organizer.focus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
SpeechRecognitionError::Constructor(const GlobalObject& aGlobal,
|
||||
const nsAString& aType,
|
||||
const SpeechRecognitionErrorInit& aParam,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.Get());
|
||||
nsRefPtr<SpeechRecognitionError> 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
|
||||
@@ -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<SpeechRecognitionError> Constructor(const GlobalObject& aGlobal,
|
||||
const nsAString& aType,
|
||||
const SpeechRecognitionErrorInit& aParam,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> 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__
|
||||
@@ -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',
|
||||
]
|
||||
|
||||
@@ -521,11 +521,10 @@ SpeechRecognition::AbortError(SpeechEvent* aEvent)
|
||||
void
|
||||
SpeechRecognition::NotifyError(SpeechEvent* aEvent)
|
||||
{
|
||||
nsCOMPtr<nsIDOMEvent> 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<nsIObserverService> 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<DOMMediaStream*>(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<nsIDOMEvent> domEvent;
|
||||
NS_NewDOMSpeechRecognitionError(getter_AddRefs(domEvent), nullptr, nullptr, nullptr);
|
||||
nsRefPtr<SpeechRecognitionError> srError =
|
||||
new SpeechRecognitionError(nullptr, nullptr, nullptr);
|
||||
|
||||
nsCOMPtr<nsIDOMSpeechRecognitionError> srError = do_QueryInterface(domEvent);
|
||||
ErrorResult err;
|
||||
srError->InitSpeechRecognitionError(NS_LITERAL_STRING("error"), true, false,
|
||||
aErrorCode, aMessage);
|
||||
aErrorCode, aMessage, err);
|
||||
|
||||
nsRefPtr<SpeechEvent> 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,
|
||||
|
||||
@@ -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<already_AddRefed<SharedBuffer> >& aResult);
|
||||
AudioSegment* CreateAudioSegment(nsTArray<already_AddRefed<SharedBuffer> >& aChunks);
|
||||
@@ -284,7 +284,7 @@ public:
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE;
|
||||
AudioSegment* mAudioSegment;
|
||||
nsRefPtr<SpeechRecognitionResultList> mRecognitionResultList; // TODO: make this a session being passed which also has index and stuff
|
||||
nsCOMPtr<nsIDOMSpeechRecognitionError> mError;
|
||||
nsRefPtr<SpeechRecognitionError> mError;
|
||||
|
||||
friend class SpeechRecognition;
|
||||
private:
|
||||
|
||||
@@ -8,7 +8,6 @@ MODULE = 'content'
|
||||
XPIDL_MODULE = 'dom_webspeechrecognition'
|
||||
|
||||
XPIDL_SOURCES = [
|
||||
'nsIDOMSpeechRecognitionError.idl',
|
||||
'nsIDOMSpeechRecognitionEvent.idl',
|
||||
'nsISpeechRecognitionService.idl'
|
||||
]
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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")) {
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=886230
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 886230</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<style type="text/css">
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=886230">Mozilla Bug 886230</a>
|
||||
<p id="display">
|
||||
<svg>
|
||||
<mask id="m"><text id="t">x</text></mask>
|
||||
<rect width="600" height="400" mask="url(#m)"/>
|
||||
</svg>
|
||||
</p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
function runTest() {
|
||||
var svgText = document.getElementById("t");
|
||||
|
||||
// Recreate the frames for the <text> with the pref set.
|
||||
svgText.style.display = "none";
|
||||
svgText.getComputedTextLength();
|
||||
svgText.style.display = "inline";
|
||||
svgText.getComputedTextLength();
|
||||
|
||||
// Dirty the frames.
|
||||
document.getElementById("display").style.width = "700px";
|
||||
svgText.removeChild(svgText.firstChild);
|
||||
|
||||
// Paint without flushing layout. If the test fails, we'll trigger
|
||||
// an assertion.
|
||||
SpecialPowers.snapshotWindowWithOptions(window, undefined, undefined, { DRAWWINDOW_DO_NOT_FLUSH: true });
|
||||
|
||||
ok(true);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
window.addEventListener("load", function() {
|
||||
SpecialPowers.pushPrefEnv({'set': [['svg.text.css-frames.enabled', true]]}, runTest);
|
||||
}, false);
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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",
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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 = "";
|
||||
};
|
||||
|
||||
@@ -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<uint32_t>(true) ||
|
||||
aValue == static_cast<uint32_t>(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<uint32_t>(true) ||
|
||||
aValue == static_cast<uint32_t>(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<uint32_t>(true) ||
|
||||
aValue == static_cast<uint32_t>(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<uint32_t>(true) ||
|
||||
aValue == static_cast<uint32_t>(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<uint32_t>(true) ||
|
||||
aValue == static_cast<uint32_t>(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<uint32_t>(true) ||
|
||||
aValue == static_cast<uint32_t>(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<uint32_t>(true) ||
|
||||
aValue == static_cast<uint32_t>(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<uint32_t>(true) ||
|
||||
aValue == static_cast<uint32_t>(false)),
|
||||
NS_ERROR_INVALID_ARG);
|
||||
SetItemType(aValue ? static_cast<int32_t>(typeChromeWrapper)
|
||||
: static_cast<int32_t>(typeContentWrapper));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
+4
-1
@@ -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',
|
||||
]
|
||||
|
||||
+10
-7
@@ -535,7 +535,7 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
|
||||
#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<T>
|
||||
|
||||
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<T>
|
||||
}
|
||||
|
||||
~Rooted() {
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
#ifdef JSGC_TRACK_EXACT_ROOTS
|
||||
JS_ASSERT(*stack == reinterpret_cast<Rooted<void*>*>(this));
|
||||
*stack = prev;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
#ifdef JSGC_TRACK_EXACT_ROOTS
|
||||
Rooted<T> *previous() { return prev; }
|
||||
#endif
|
||||
|
||||
@@ -640,7 +640,10 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
|
||||
|
||||
private:
|
||||
void commonInit(Rooted<void*> **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<T>::kind();
|
||||
this->stack = &thingGCRooters[kind];
|
||||
this->prev = *stack;
|
||||
@@ -650,11 +653,11 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
#ifdef JSGC_TRACK_EXACT_ROOTS
|
||||
Rooted<void*> **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;
|
||||
|
||||
@@ -480,7 +480,7 @@ js::PrincipalsForCompiledCode(const CallReceiver &call, JSContext *cx)
|
||||
{
|
||||
JSObject &callee = call.callee();
|
||||
JS_ASSERT(IsAnyBuiltinEval(&callee.as<JSFunction>()) ||
|
||||
IsBuiltinFunctionConstructor(&callee.as<JSFunction>()));
|
||||
callee.as<JSFunction>().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
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
|
||||
#include "jscntxtinlines.h"
|
||||
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
#include "vm/Shape-inl.h"
|
||||
#endif
|
||||
|
||||
using namespace js;
|
||||
|
||||
using mozilla::ArrayLength;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "jit/AsmJS.h"
|
||||
#include "vm/ForkJoin.h"
|
||||
#include "vm/Interpreter.h"
|
||||
|
||||
#include "vm/ObjectImpl-inl.h"
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -698,6 +698,52 @@ FoldConstants<FullParseHandler>(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<NoGC>(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:;
|
||||
}
|
||||
|
||||
|
||||
@@ -317,57 +317,7 @@ class FullParseHandler
|
||||
return new_<PropertyAccess>(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<NoGC>(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_<PropertyByValue>(lhs, index, lhs->pn_pos.begin, end);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ struct JSContext;
|
||||
namespace js {
|
||||
namespace frontend {
|
||||
|
||||
struct ParseNode;
|
||||
class ParseNode;
|
||||
|
||||
bool
|
||||
NameFunctions(JSContext *cx, ParseNode *pn);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -4435,6 +4435,11 @@ Parser<ParseHandler>::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<ParseHandler>::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<ParseHandler>::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();
|
||||
|
||||
@@ -36,7 +36,6 @@ typedef HashSet<JSAtom *> FuncStmtSet;
|
||||
class SharedContext;
|
||||
|
||||
typedef Vector<Definition *, 16> DeclVector;
|
||||
typedef Vector<JSFunction *, 4> 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 <typename ParseHandler>
|
||||
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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
+8
-2
@@ -384,8 +384,14 @@ class EncapsulatedValue : public ValueOperations<EncapsulatedValue>
|
||||
}
|
||||
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);
|
||||
|
||||
+10
-1
@@ -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<ArrayObject>())
|
||||
return false;
|
||||
|
||||
uint32_t initlen = obj->getDenseInitializedLength();
|
||||
|
||||
@@ -192,6 +192,9 @@ IsValueAboutToBeFinalized(Value *v);
|
||||
|
||||
/*** Slot Marking ***/
|
||||
|
||||
bool
|
||||
IsSlotMarked(HeapSlot *s);
|
||||
|
||||
void
|
||||
MarkSlot(JSTracer *trc, HeapSlot *s, const char *name);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
+24
-4
@@ -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<ArrayObject>()) {
|
||||
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<ArrayObject>())
|
||||
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<ArrayObject>() && nslots <= GetGCKindSlots(dstKind)) {
|
||||
dst->setFixedElements();
|
||||
dstHeader = dst->getElementsHeader();
|
||||
js_memcpy(dstHeader, srcHeader, nslots * sizeof(HeapSlot));
|
||||
|
||||
@@ -449,6 +449,12 @@ AutoGCRooter::trace(JSTracer *trc)
|
||||
return;
|
||||
}
|
||||
|
||||
case FUNVECTOR: {
|
||||
AutoFunctionVector::VectorImpl &vector = static_cast<AutoFunctionVector *>(this)->vector;
|
||||
MarkObjectRootRange(trc, vector.length(), vector.begin(), "js::AutoFunctionVector.vector");
|
||||
return;
|
||||
}
|
||||
|
||||
case STRINGVECTOR: {
|
||||
AutoStringVector::VectorImpl &vector = static_cast<AutoStringVector *>(this)->vector;
|
||||
MarkStringRootRange(trc, vector.length(), vector.begin(), "js::AutoStringVector.vector");
|
||||
|
||||
@@ -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<JSObject *>(tenured));
|
||||
return;
|
||||
}
|
||||
#ifdef JS_ION
|
||||
JS_ASSERT(kind == JSTRACE_IONCODE);
|
||||
static_cast<jit::IonCode *>(tenured)->trace(trc);
|
||||
#else
|
||||
MOZ_NOT_REACHED("Only objects can be in the wholeCellBuffer if IonMonkey is disabled.");
|
||||
#endif
|
||||
}
|
||||
|
||||
/*** MonoTypeBuffer ***/
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
@@ -0,0 +1,8 @@
|
||||
if (this.hasOwnProperty('Intl')) {
|
||||
gc();
|
||||
gcslice(0);
|
||||
var thisValues = [ "x" ];
|
||||
thisValues.forEach(function (value) {
|
||||
var format = Intl.DateTimeFormat.call(value);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
gc();
|
||||
gcslice(0);
|
||||
function isClone(a, b) {
|
||||
var rmemory = new WeakMap();
|
||||
rmemory.set(a,b);
|
||||
}
|
||||
isClone([]);
|
||||
@@ -0,0 +1 @@
|
||||
if (Math["key"]) {}
|
||||
@@ -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");
|
||||
@@ -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)
|
||||
|
||||
+1
-1
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<ArrayObject>() && 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<DoCreateRestParameterFn>(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
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace js {
|
||||
namespace jit {
|
||||
|
||||
class StackValue;
|
||||
struct ICEntry;
|
||||
class ICEntry;
|
||||
class ICStub;
|
||||
|
||||
class PCMappingSlotInfo
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
+7
-7
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+49
-55
@@ -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<JSFunction>();
|
||||
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<JSFunction>(), 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<MInstruction *> 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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<ArrayObject>());
|
||||
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<ArrayObject>() && !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<ArrayObject>())
|
||||
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);
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ typedef Vector<IonBuilder*, 0, SystemAllocPolicy> 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_;
|
||||
|
||||
@@ -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<ArrayObject>()) {
|
||||
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<ArrayObject>().length()),
|
||||
Address(obj, elementsOffset + ObjectElements::offsetOfLength()));
|
||||
store32(Imm32(templateObject->shouldConvertDoubleElements()
|
||||
? ObjectElements::CONVERT_DOUBLE_ELEMENTS
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -175,7 +175,7 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
|
||||
|
||||
// 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);
|
||||
|
||||
@@ -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<ArrayObject>());
|
||||
JS_ASSERT(!res->getDenseInitializedLength());
|
||||
JS_ASSERT(res->type() == templateObj->type());
|
||||
// See note in visitRest in ParallelArrayAnalysis.
|
||||
JS_ASSERT(res->type()->unknownProperties());
|
||||
|
||||
if (length) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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 */
|
||||
+25
-35
@@ -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<ArrayObject>());
|
||||
|
||||
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<ArrayObject>());
|
||||
|
||||
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<ArrayObject>());
|
||||
|
||||
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<ArrayObject*> arr1(cx, &obj1->as<ArrayObject>());
|
||||
Rooted<ArrayObject*> arr2(cx, &obj2->as<ArrayObject>());
|
||||
Rooted<ArrayObject*> arrRes(cx, objRes ? &objRes->as<ArrayObject>() : 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<ArrayObject*> arrRes(cx, &objRes->as<ArrayObject>());
|
||||
|
||||
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
|
||||
|
||||
+1
-1
@@ -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")
|
||||
|
||||
+16
-14
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+16
-1
@@ -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<JSObject *>
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
class AutoFunctionVector : public AutoVectorRooter<JSFunction *>
|
||||
{
|
||||
public:
|
||||
explicit AutoFunctionVector(JSContext *cx
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: AutoVectorRooter<JSFunction *>(cx, FUNVECTOR)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
class AutoScriptVector : public AutoVectorRooter<JSScript *>
|
||||
{
|
||||
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;
|
||||
|
||||
|
||||
+185
-168
@@ -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<ArrayObject>()) {
|
||||
*lengthp = obj->as<ArrayObject>().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<ArrayObject>() && 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<ArrayObject>() && !obj->isIndexed()) {
|
||||
Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
|
||||
/* 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<ArrayObject>() && !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<ArrayObject>()) {
|
||||
vp.setNumber(obj->as<ArrayObject>().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<ArrayObject>()) {
|
||||
return JSObject::defineProperty(cx, obj, cx->names().length, vp,
|
||||
NULL, NULL, JSPROP_ENUMERATE);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(obj->arrayLengthIsWritable(),
|
||||
Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
|
||||
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<ArrayObject*> 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<uint32_t> 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<ArrayObject>()) {
|
||||
*definesPast = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t length = obj->getArrayLength();
|
||||
Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
|
||||
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<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
|
||||
|
||||
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<ArrayObject>();
|
||||
}
|
||||
|
||||
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<ArrayObject>() && !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<ArrayObject>())
|
||||
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<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
|
||||
|
||||
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<ArrayObject>())
|
||||
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<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
|
||||
|
||||
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<ArrayObject>()) {
|
||||
Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
|
||||
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<ArrayObject>());
|
||||
JS_ASSERT(obj->as<ArrayObject>().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<ArrayObject>() &&
|
||||
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<ArrayObject>())
|
||||
break;
|
||||
if (ObjectMayHaveExtraIndexedProperties(obj))
|
||||
break;
|
||||
if (!obj->arrayLengthIsWritable())
|
||||
if (!obj->as<ArrayObject>().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<ArrayObject>() && !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<ArrayObject>())
|
||||
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<ArrayObject*> 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<ArrayObject>()) {
|
||||
Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
|
||||
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<ArrayObject*> arr1, Handle<ArrayObject*> arr2,
|
||||
Handle<ArrayObject*> 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<ArrayObject*> arr(cx);
|
||||
if (obj->is<ArrayObject>() && !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<ArrayObject*> narr(cx);
|
||||
|
||||
if (obj->isArray() && end <= obj->getDenseInitializedLength() &&
|
||||
if (obj->is<ArrayObject>() && 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<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
|
||||
|
||||
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<bool allocateCapacity>
|
||||
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<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
|
||||
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<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
|
||||
|
||||
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<false>(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<true>(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<false>(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<true>(cx, length, proto);
|
||||
if (!obj)
|
||||
ArrayObject* arr = NewArray<true>(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<true>(cx, length, proto);
|
||||
if (!obj)
|
||||
ArrayObject* arr = NewArray<true>(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<ArrayObject>()) {
|
||||
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<ArrayObject>().length());
|
||||
fprintf(stderr, ", capacity %u", obj->getDenseCapacity());
|
||||
fputs(")\n", stderr);
|
||||
js_free(bytes);
|
||||
}
|
||||
|
||||
+9
-6
@@ -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<ArrayObject*> arr1, Handle<ArrayObject*> arr2,
|
||||
Handle<ArrayObject*> result);
|
||||
|
||||
extern void
|
||||
ArrayShiftMoveElements(JSObject *obj);
|
||||
|
||||
+4
-2
@@ -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;
|
||||
|
||||
+7
-2
@@ -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); }
|
||||
};
|
||||
|
||||
+3
-3
@@ -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<ArrayObject>() ? SCTAG_ARRAY_OBJECT : SCTAG_OBJECT_OBJECT, 0);
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -682,14 +682,14 @@ JSStructuredCloneWriter::startWrite(const Value &v)
|
||||
RegExpObject &reobj = obj->as<RegExpObject>();
|
||||
return out.writePair(SCTAG_REGEXP_OBJECT, reobj.getFlags()) &&
|
||||
writeString(SCTAG_STRING, reobj.getSource());
|
||||
} else if (obj->isDate()) {
|
||||
} else if (obj->is<DateObject>()) {
|
||||
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<ArrayBufferObject>() && obj->as<ArrayBufferObject>().hasData()) {
|
||||
return writeArrayBuffer(obj);
|
||||
} else if (obj->isObject() || obj->isArray()) {
|
||||
} else if (obj->isObject() || obj->is<ArrayObject>()) {
|
||||
return traverseObject(obj);
|
||||
} else if (obj->is<BooleanObject>()) {
|
||||
return out.writePair(SCTAG_BOOLEAN_OBJECT, obj->as<BooleanObject>().unbox());
|
||||
|
||||
+1
-1
@@ -1205,7 +1205,7 @@ JSContext::JSContext(JSRuntime *rt)
|
||||
JS_ASSERT(static_cast<ContextFriendFields*>(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)
|
||||
|
||||
+235
-341
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
||||
|
||||
+23
-29
@@ -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<ErrorObject>());
|
||||
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<ErrorObject>(), 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<ErrorObject>().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<ErrorObject>().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<ErrorObject>().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<ErrorObject>())
|
||||
return NULL;
|
||||
|
||||
JSExnPrivate *priv = GetExnPrivate(obj);
|
||||
JSExnPrivate *priv = obj->as<ErrorObject>().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<GlobalObject*> 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<ErrorObject>() || 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<ErrorObject>().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<ErrorObject>(), copy);
|
||||
copy.forget();
|
||||
autoFreeErrorReport.forget();
|
||||
return copyobj;
|
||||
|
||||
@@ -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;
|
||||
|
||||
+5
-2
@@ -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 *
|
||||
|
||||
+75
-8
@@ -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>()) {
|
||||
JSFunction *fun = &callee->as<JSFunction>();
|
||||
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<const js::FunctionExtended *>(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);
|
||||
|
||||
@@ -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<JSFunction>() == rhs.toObject().is<JSFunction>());
|
||||
}
|
||||
|
||||
/* 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>()) {
|
||||
JSFunction *fun = &callee->as<JSFunction>();
|
||||
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 */
|
||||
|
||||
+6
-7
@@ -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);
|
||||
|
||||
+4
-4
@@ -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<ArrayObject>());
|
||||
|
||||
unsigned len = obj->getDenseInitializedLength();
|
||||
if (len == 0)
|
||||
@@ -3210,7 +3210,7 @@ TypeCompartment::fixArrayType(JSContext *cx, JSObject *obj)
|
||||
Rooted<Type> origType(cx, type);
|
||||
/* Make a new type to use for future arrays with the same elements. */
|
||||
RootedObject objProto(cx, obj->getProto());
|
||||
Rooted<TypeObject*> objType(cx, newTypeObject(cx, &ArrayClass, objProto));
|
||||
Rooted<TypeObject*> 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<ArrayObject>() && obj->as<ArrayObject>().length() > INT32_MAX)
|
||||
type->flags |= OBJECT_FLAG_LENGTH_OVERFLOW;
|
||||
|
||||
obj->type_ = type;
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -175,7 +175,7 @@ StatsCellCallback(JSRuntime *rt, void *data, void *thing, JSGCTraceKind traceKin
|
||||
CompartmentStats *cStats = GetCompartmentStats(obj->compartment());
|
||||
if (obj->is<JSFunction>())
|
||||
cStats->gcHeapObjectsFunction += thingSize;
|
||||
else if (obj->isArray())
|
||||
else if (obj->is<ArrayObject>())
|
||||
cStats->gcHeapObjectsDenseArray += thingSize;
|
||||
else if (obj->isCrossCompartmentWrapper())
|
||||
cStats->gcHeapObjectsCrossCompartmentWrapper += thingSize;
|
||||
|
||||
+10
-8
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+6
-9
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+41
-30
@@ -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<ArrayObject*> 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<ArrayObject>()) {
|
||||
Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
|
||||
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<ArrayObject>())
|
||||
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<RegExpObject>() && !b->is<RegExpObject>());
|
||||
|
||||
/* Arrays can use their fixed storage for elements. */
|
||||
JS_ASSERT(!a->isArray() && !b->isArray());
|
||||
JS_ASSERT(!a->is<ArrayObject>() && !b->is<ArrayObject>());
|
||||
|
||||
/*
|
||||
* 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<ArrayObject>() && !as<ArrayObject>().lengthIsWritable()) {
|
||||
JS_ASSERT(newcap <= as<ArrayObject>().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<ArrayObject>()) {
|
||||
Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
|
||||
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<ArrayObject>()) {
|
||||
Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
|
||||
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<ArrayObject>() && id == NameToId(cx->names().length)) {
|
||||
Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
|
||||
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<ArgumentsObject>()) {
|
||||
sizes->argumentsData = as<ArgumentsObject>().sizeOfMisc(mallocSizeOf);
|
||||
} else if (isRegExpStatics()) {
|
||||
} else if (is<RegExpStaticsObject>()) {
|
||||
sizes->regExpStatics = js::SizeOfRegExpStaticsData(this, mallocSizeOf);
|
||||
} else if (is<PropertyIteratorObject>()) {
|
||||
sizes->propertyIteratorData = as<PropertyIteratorObject>().sizeOfMisc(mallocSizeOf);
|
||||
|
||||
+246
-123
@@ -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<js::CanGC>(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);
|
||||
|
||||
+8
-376
@@ -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<js::GlobalObject>());
|
||||
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<js::ArrayObject>() && !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<js::ArrayObject>(), as<js::ArrayObject>().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<js::CanGC>(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<ArrayObject>();
|
||||
case ESClass_Number: return obj->is<NumberObject>();
|
||||
case ESClass_String: return obj->is<StringObject>();
|
||||
case ESClass_Boolean: return obj->is<BooleanObject>();
|
||||
case ESClass_RegExp: return obj->is<RegExpObject>();
|
||||
case ESClass_ArrayBuffer: return obj->is<ArrayBufferObject>();
|
||||
case ESClass_Date: return obj->isDate();
|
||||
case ESClass_Date: return obj->is<DateObject>();
|
||||
}
|
||||
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 */
|
||||
|
||||
+1
-1
@@ -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<ArrayObject>() && !replacer->isIndexed())
|
||||
len = Min(len, replacer->getDenseInitializedLength());
|
||||
|
||||
// Cap the initial size to a moderately small value. This avoids
|
||||
|
||||
+2
-2
@@ -148,10 +148,10 @@ struct Token;
|
||||
struct TokenPos;
|
||||
class TokenStream;
|
||||
class ParseMapPool;
|
||||
struct ParseNode;
|
||||
class ParseNode;
|
||||
|
||||
template <typename ParseHandler>
|
||||
struct Parser;
|
||||
class Parser;
|
||||
|
||||
} /* namespace frontend */
|
||||
|
||||
|
||||
+6
-2
@@ -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<ContextFriendFields *>(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.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user