mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-08 00:38:39 +09:00
Compare commits
No commits in common. "main" and "13.2-release" have entirely different histories.
main
...
13.2-relea
493 changed files with 611 additions and 211980 deletions
|
|
@ -65,9 +65,9 @@ pref("@GUAO_PREF@.mewe.com", "Mozilla/5.0 (%OS_SLICE% rv:102.0) Gecko/20100101 F
|
||||||
|
|
||||||
// UA-sniffing domains that are "app/vendor-specific" and do not like Dactyloidae
|
// UA-sniffing domains that are "app/vendor-specific" and do not like Dactyloidae
|
||||||
pref("@GUAO_PREF@.web.whatsapp.com","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36");
|
pref("@GUAO_PREF@.web.whatsapp.com","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36");
|
||||||
pref("@GUAO_PREF@.youtube.com","Mozilla/5.0 (%OS_SLICE%; Win64; x64; rv:147.0) Gecko/20100101 Firefox/147.0");
|
pref("@GUAO_PREF@.youtube.com","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36");
|
||||||
pref("@GUAO_PREF@.studio.youtube.com","Mozilla/5.0 (%OS_SLICE%; Win64; x64; rv:147.0) Gecko/20100101 Firefox/147.0");
|
pref("@GUAO_PREF@.studio.youtube.com","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36");
|
||||||
pref("@GUAO_PREF@.gaming.youtube.com","Mozilla/5.0 (%OS_SLICE%; Win64; x64; rv:147.0) Gecko/20100101 Firefox/147.0");
|
pref("@GUAO_PREF@.gaming.youtube.com","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36");
|
||||||
|
|
||||||
// The following domains do not like the Goanna slice
|
// The following domains do not like the Goanna slice
|
||||||
pref("@GUAO_PREF@.bab.la","Mozilla/5.0 (%OS_SLICE% rv:@GK_VERSION@) @GK_SLICE@ @FX_SLICE@");
|
pref("@GUAO_PREF@.bab.la","Mozilla/5.0 (%OS_SLICE% rv:@GK_VERSION@) @GK_SLICE@ @FX_SLICE@");
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
52.13.2.1
|
52.13.2
|
||||||
|
|
@ -1 +1 @@
|
||||||
13.2.1
|
13.2
|
||||||
|
|
@ -138,207 +138,6 @@ StructuredCloneCallbacksError(JSContext* aCx,
|
||||||
NS_WARNING("Failed to clone data.");
|
NS_WARNING("Failed to clone data.");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SameThreadStreamTransferData
|
|
||||||
{
|
|
||||||
SameThreadStreamTransferData(JSContext* aCx, JS::HandleObject aRecord)
|
|
||||||
: mRecord(aCx, aRecord)
|
|
||||||
{}
|
|
||||||
|
|
||||||
~SameThreadStreamTransferData()
|
|
||||||
{
|
|
||||||
mRecord.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
JS::PersistentRootedObject mRecord;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool
|
|
||||||
CallStreamTransferHelper(JSContext* aCx,
|
|
||||||
const char* aHelperName,
|
|
||||||
JS::HandleValue aArgument,
|
|
||||||
JS::MutableHandleValue aResult)
|
|
||||||
{
|
|
||||||
JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
|
|
||||||
if (!global) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve the stream extras lazily before looking up the internal helper.
|
|
||||||
JS::Rooted<JS::Value> ignored(aCx);
|
|
||||||
if (!JS_GetProperty(aCx, global, "WritableStream", &ignored)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS::Rooted<JS::Value> helper(aCx);
|
|
||||||
if (!JS_GetProperty(aCx, global, aHelperName, &helper)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!helper.isObject() || !JS::IsCallable(&helper.toObject())) {
|
|
||||||
aResult.setUndefined();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS::Rooted<JS::Value> argument(aCx, aArgument);
|
|
||||||
if (!JS_WrapValue(aCx, &argument)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return JS::Call(aCx, JS::UndefinedHandleValue, helper,
|
|
||||||
JS::HandleValueArray(argument), aResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TryWriteSameThreadStreamTransfer(JSContext* aCx,
|
|
||||||
JS::Handle<JSObject*> aObj,
|
|
||||||
const char* aHelperName,
|
|
||||||
uint32_t aTransferTag,
|
|
||||||
uint32_t* aTag,
|
|
||||||
JS::TransferableOwnership* aOwnership,
|
|
||||||
void** aContent,
|
|
||||||
uint64_t* aExtraData,
|
|
||||||
bool* aHandled)
|
|
||||||
{
|
|
||||||
*aHandled = false;
|
|
||||||
|
|
||||||
JS::Rooted<JS::Value> argument(aCx, JS::ObjectValue(*aObj));
|
|
||||||
JS::Rooted<JS::Value> transferRecord(aCx);
|
|
||||||
if (!CallStreamTransferHelper(aCx, aHelperName, argument, &transferRecord)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transferRecord.isUndefined()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!transferRecord.isObject()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS::Rooted<JSObject*> record(aCx, &transferRecord.toObject());
|
|
||||||
SameThreadStreamTransferData* data =
|
|
||||||
new SameThreadStreamTransferData(aCx, record);
|
|
||||||
|
|
||||||
*aTag = aTransferTag;
|
|
||||||
*aOwnership = JS::SCTAG_TMO_CUSTOM;
|
|
||||||
*aContent = data;
|
|
||||||
*aExtraData = 0;
|
|
||||||
*aHandled = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TryWriteReadableStreamPortTransfer(JSContext* aCx,
|
|
||||||
JS::Handle<JSObject*> aObj,
|
|
||||||
nsTArray<MessagePortIdentifier>& aPortIdentifiers,
|
|
||||||
uint32_t* aTag,
|
|
||||||
JS::TransferableOwnership* aOwnership,
|
|
||||||
void** aContent,
|
|
||||||
uint64_t* aExtraData,
|
|
||||||
bool* aHandled)
|
|
||||||
{
|
|
||||||
*aHandled = false;
|
|
||||||
|
|
||||||
JS::Rooted<JS::Value> argument(aCx, JS::ObjectValue(*aObj));
|
|
||||||
JS::Rooted<JS::Value> transferPortValue(aCx);
|
|
||||||
if (!CallStreamTransferHelper(aCx, "__uxpTransferReadableStreamPort",
|
|
||||||
argument, &transferPortValue)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transferPortValue.isUndefined()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!transferPortValue.isObject()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS::Rooted<JSObject*> transferPortObj(aCx, &transferPortValue.toObject());
|
|
||||||
MessagePort* port = nullptr;
|
|
||||||
nsresult rv = UNWRAP_OBJECT(MessagePort, &transferPortObj, port);
|
|
||||||
if (NS_FAILED(rv) || !port) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
*aExtraData = aPortIdentifiers.Length();
|
|
||||||
MessagePortIdentifier* identifier = aPortIdentifiers.AppendElement();
|
|
||||||
port->CloneAndDisentangle(*identifier);
|
|
||||||
|
|
||||||
*aTag = SCTAG_DOM_TRANSFERRED_READABLESTREAM;
|
|
||||||
*aOwnership = JS::SCTAG_TMO_CUSTOM;
|
|
||||||
*aContent = nullptr;
|
|
||||||
*aHandled = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ReadSameThreadStreamTransfer(JSContext* aCx,
|
|
||||||
void* aContent,
|
|
||||||
const char* aHelperName,
|
|
||||||
JS::MutableHandleObject aReturnObject)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(aContent);
|
|
||||||
SameThreadStreamTransferData* data =
|
|
||||||
static_cast<SameThreadStreamTransferData*>(aContent);
|
|
||||||
|
|
||||||
JS::Rooted<JS::Value> record(aCx, JS::ObjectValue(*data->mRecord));
|
|
||||||
JS::Rooted<JS::Value> result(aCx);
|
|
||||||
if (!CallStreamTransferHelper(aCx, aHelperName, record, &result)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result.isObject()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
aReturnObject.set(&result.toObject());
|
|
||||||
delete data;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ReadReadableStreamPortTransfer(JSContext* aCx,
|
|
||||||
nsISupports* aParent,
|
|
||||||
nsTArray<MessagePortIdentifier>& aPortIdentifiers,
|
|
||||||
uint64_t aExtraData,
|
|
||||||
JS::MutableHandleObject aReturnObject)
|
|
||||||
{
|
|
||||||
if (aExtraData >= aPortIdentifiers.Length()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aParent);
|
|
||||||
|
|
||||||
ErrorResult rv;
|
|
||||||
RefPtr<MessagePort> port =
|
|
||||||
MessagePort::Create(global, aPortIdentifiers[aExtraData], rv);
|
|
||||||
if (NS_WARN_IF(rv.Failed())) {
|
|
||||||
rv.SuppressException();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS::Rooted<JS::Value> portValue(aCx);
|
|
||||||
if (!GetOrCreateDOMReflector(aCx, port, &portValue)) {
|
|
||||||
JS_ClearPendingException(aCx);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS::Rooted<JS::Value> result(aCx);
|
|
||||||
if (!CallStreamTransferHelper(aCx,
|
|
||||||
"__uxpReceiveReadableStreamTransferFromPort",
|
|
||||||
portValue, &result)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result.isObject()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
aReturnObject.set(&result.toObject());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
const JSStructuredCloneCallbacks StructuredCloneHolder::sCallbacks = {
|
const JSStructuredCloneCallbacks StructuredCloneHolder::sCallbacks = {
|
||||||
|
|
@ -1576,35 +1375,6 @@ StructuredCloneHolder::CustomReadTransferHandler(JSContext* aCx,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread) {
|
|
||||||
if (aTag == SCTAG_DOM_TRANSFERRED_WRITABLESTREAM) {
|
|
||||||
return ReadSameThreadStreamTransfer(aCx, aContent,
|
|
||||||
"__uxpReceiveWritableStreamTransfer",
|
|
||||||
aReturnObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aTag == SCTAG_DOM_TRANSFERRED_READABLESTREAM) {
|
|
||||||
return ReadSameThreadStreamTransfer(aCx, aContent,
|
|
||||||
"__uxpReceiveReadableStreamTransfer",
|
|
||||||
aReturnObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aTag == SCTAG_DOM_TRANSFERRED_TRANSFORMSTREAM) {
|
|
||||||
return ReadSameThreadStreamTransfer(aCx, aContent,
|
|
||||||
"__uxpReceiveTransformStreamTransfer",
|
|
||||||
aReturnObject);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread ||
|
|
||||||
mStructuredCloneScope == StructuredCloneScope::DifferentProcess) &&
|
|
||||||
aTag == SCTAG_DOM_TRANSFERRED_READABLESTREAM) {
|
|
||||||
MOZ_ASSERT(!aContent);
|
|
||||||
return ReadReadableStreamPortTransfer(aCx, mParent, mPortIdentifiers,
|
|
||||||
aExtraData,
|
|
||||||
aReturnObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1673,55 +1443,6 @@ StructuredCloneHolder::CustomWriteTransferHandler(JSContext* aCx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread) {
|
|
||||||
bool handled = false;
|
|
||||||
if (!TryWriteSameThreadStreamTransfer(aCx, obj,
|
|
||||||
"__uxpTransferWritableStream",
|
|
||||||
SCTAG_DOM_TRANSFERRED_WRITABLESTREAM,
|
|
||||||
aTag, aOwnership, aContent,
|
|
||||||
aExtraData, &handled)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (handled) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!TryWriteSameThreadStreamTransfer(aCx, obj,
|
|
||||||
"__uxpTransferReadableStream",
|
|
||||||
SCTAG_DOM_TRANSFERRED_READABLESTREAM,
|
|
||||||
aTag, aOwnership, aContent,
|
|
||||||
aExtraData, &handled)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (handled) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!TryWriteSameThreadStreamTransfer(aCx, obj,
|
|
||||||
"__uxpTransferTransformStream",
|
|
||||||
SCTAG_DOM_TRANSFERRED_TRANSFORMSTREAM,
|
|
||||||
aTag, aOwnership, aContent,
|
|
||||||
aExtraData, &handled)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (handled) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread ||
|
|
||||||
mStructuredCloneScope == StructuredCloneScope::DifferentProcess) {
|
|
||||||
bool handled = false;
|
|
||||||
if (!TryWriteReadableStreamPortTransfer(aCx, obj, mPortIdentifiers,
|
|
||||||
aTag, aOwnership, aContent,
|
|
||||||
aExtraData, &handled)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (handled) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1759,26 +1480,6 @@ StructuredCloneHolder::CustomFreeTransferHandler(uint32_t aTag,
|
||||||
delete data;
|
delete data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((aTag == SCTAG_DOM_TRANSFERRED_WRITABLESTREAM ||
|
|
||||||
aTag == SCTAG_DOM_TRANSFERRED_READABLESTREAM ||
|
|
||||||
aTag == SCTAG_DOM_TRANSFERRED_TRANSFORMSTREAM) &&
|
|
||||||
mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread) {
|
|
||||||
MOZ_ASSERT(aContent);
|
|
||||||
SameThreadStreamTransferData* data =
|
|
||||||
static_cast<SameThreadStreamTransferData*>(aContent);
|
|
||||||
delete data;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aTag == SCTAG_DOM_TRANSFERRED_READABLESTREAM &&
|
|
||||||
(mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread ||
|
|
||||||
mStructuredCloneScope == StructuredCloneScope::DifferentProcess)) {
|
|
||||||
MOZ_ASSERT(!aContent);
|
|
||||||
MOZ_ASSERT(aExtraData < mPortIdentifiers.Length());
|
|
||||||
MessagePort::ForceClose(mPortIdentifiers[aExtraData]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
||||||
|
|
@ -68,11 +68,6 @@ enum StructuredCloneTags {
|
||||||
// This tag is used by both main thread and workers.
|
// This tag is used by both main thread and workers.
|
||||||
SCTAG_DOM_URLSEARCHPARAMS,
|
SCTAG_DOM_URLSEARCHPARAMS,
|
||||||
|
|
||||||
// Same-thread transferable stream records. These are not supported by IDB.
|
|
||||||
SCTAG_DOM_TRANSFERRED_READABLESTREAM,
|
|
||||||
SCTAG_DOM_TRANSFERRED_WRITABLESTREAM,
|
|
||||||
SCTAG_DOM_TRANSFERRED_TRANSFORMSTREAM,
|
|
||||||
|
|
||||||
// When adding a new tag for IDB, please don't add it to the end of the list!
|
// When adding a new tag for IDB, please don't add it to the end of the list!
|
||||||
// Tags that are supported by IDB must not ever change. See the static assert
|
// Tags that are supported by IDB must not ever change. See the static assert
|
||||||
// in IDBObjectStore.cpp, method CommonStructuredCloneReadCallback.
|
// in IDBObjectStore.cpp, method CommonStructuredCloneReadCallback.
|
||||||
|
|
|
||||||
|
|
@ -127,29 +127,7 @@ void
|
||||||
nsDOMTokenList::AddInternal(const nsAttrValue* aAttr,
|
nsDOMTokenList::AddInternal(const nsAttrValue* aAttr,
|
||||||
const nsTArray<nsString>& aTokens)
|
const nsTArray<nsString>& aTokens)
|
||||||
{
|
{
|
||||||
if (!mElement || aTokens.IsEmpty()) {
|
if (!mElement) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hot path: single-token classList.add() when the class is already present.
|
|
||||||
// Skip attribute rebuild and SetAttr entirely (avoids mutation observers /
|
|
||||||
// style invalidation). Frameworks hit this constantly.
|
|
||||||
if (aTokens.Length() == 1) {
|
|
||||||
const nsString& token = aTokens[0];
|
|
||||||
if (aAttr && aAttr->Contains(token)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoString resultStr;
|
|
||||||
if (aAttr) {
|
|
||||||
aAttr->ToString(resultStr);
|
|
||||||
if (!resultStr.IsEmpty() &&
|
|
||||||
!nsContentUtils::IsHTMLWhitespace(resultStr.Last())) {
|
|
||||||
resultStr.Append(' ');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resultStr.Append(token);
|
|
||||||
mElement->SetAttr(kNameSpaceID_None, mAttrAtom, resultStr, true);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -183,11 +161,6 @@ nsDOMTokenList::AddInternal(const nsAttrValue* aAttr,
|
||||||
addedClasses.AppendElement(aToken);
|
addedClasses.AppendElement(aToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
// No new tokens: leave the attribute untouched (do not create class="").
|
|
||||||
if (!oneWasAdded) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mElement->SetAttr(kNameSpaceID_None, mAttrAtom, resultStr, true);
|
mElement->SetAttr(kNameSpaceID_None, mAttrAtom, resultStr, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -217,37 +190,20 @@ nsDOMTokenList::RemoveInternal(const nsAttrValue* aAttr,
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aAttr, "Need an attribute");
|
MOZ_ASSERT(aAttr, "Need an attribute");
|
||||||
|
|
||||||
if (aTokens.IsEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hot path: single-token classList.remove() when the class is absent.
|
|
||||||
if (aTokens.Length() == 1 && !aAttr->Contains(aTokens[0])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoString input;
|
nsAutoString input;
|
||||||
aAttr->ToString(input);
|
aAttr->ToString(input);
|
||||||
|
|
||||||
WhitespaceTokenizer tokenizer(input);
|
WhitespaceTokenizer tokenizer(input);
|
||||||
nsAutoString output;
|
nsAutoString output;
|
||||||
bool removed = false;
|
|
||||||
|
|
||||||
while (tokenizer.hasMoreTokens()) {
|
while (tokenizer.hasMoreTokens()) {
|
||||||
auto& currentToken = tokenizer.nextToken();
|
auto& currentToken = tokenizer.nextToken();
|
||||||
if (aTokens.Contains(currentToken)) {
|
if (!aTokens.Contains(currentToken)) {
|
||||||
removed = true;
|
if (!output.IsEmpty()) {
|
||||||
continue;
|
output.Append(char16_t(' '));
|
||||||
|
}
|
||||||
|
output.Append(currentToken);
|
||||||
}
|
}
|
||||||
if (!output.IsEmpty()) {
|
|
||||||
output.Append(char16_t(' '));
|
|
||||||
}
|
|
||||||
output.Append(currentToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Token set unchanged: skip SetAttr to avoid style/mutation work.
|
|
||||||
if (!removed) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mElement->SetAttr(kNameSpaceID_None, mAttrAtom, output, true);
|
mElement->SetAttr(kNameSpaceID_None, mAttrAtom, output, true);
|
||||||
|
|
@ -346,16 +302,6 @@ nsDOMTokenList::ReplaceInternal(const nsAttrValue* aAttr,
|
||||||
const nsAString& aToken,
|
const nsAString& aToken,
|
||||||
const nsAString& aNewToken)
|
const nsAString& aNewToken)
|
||||||
{
|
{
|
||||||
// Replacing a token with itself cannot change the token set.
|
|
||||||
if (aToken.Equals(aNewToken)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Old token absent: no update (and avoid rewriting whitespace).
|
|
||||||
if (!aAttr->Contains(aToken)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoString attribute;
|
nsAutoString attribute;
|
||||||
aAttr->ToString(attribute);
|
aAttr->ToString(attribute);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1929,9 +1929,6 @@ public:
|
||||||
{
|
{
|
||||||
ProcessGlobal* global = ProcessGlobal::Get();
|
ProcessGlobal* global = ProcessGlobal::Get();
|
||||||
MOZ_ASSERT(!aRunInGlobalScope);
|
MOZ_ASSERT(!aRunInGlobalScope);
|
||||||
if (NS_WARN_IF(!global)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
global->LoadScript(aURL);
|
global->LoadScript(aURL);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2334,7 +2334,8 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aRequest->IsModuleRequest()) {
|
if (aRequest->IsModuleRequest()) {
|
||||||
AutoCurrentScriptUpdater scriptUpdater(this, aRequest->Element());
|
// For modules, currentScript is set to null.
|
||||||
|
AutoCurrentScriptUpdater scriptUpdater(this, nullptr);
|
||||||
|
|
||||||
ModuleLoadRequest* request = aRequest->AsModuleRequest();
|
ModuleLoadRequest* request = aRequest->AsModuleRequest();
|
||||||
MOZ_ASSERT(request->mModuleScript);
|
MOZ_ASSERT(request->mModuleScript);
|
||||||
|
|
|
||||||
|
|
@ -301,7 +301,6 @@ LoadContextOptions(const char* aPrefName, void* /* aClosure */)
|
||||||
.setAsyncStack(GetWorkerPref<bool>(NS_LITERAL_CSTRING("asyncstack")))
|
.setAsyncStack(GetWorkerPref<bool>(NS_LITERAL_CSTRING("asyncstack")))
|
||||||
.setWerror(GetWorkerPref<bool>(NS_LITERAL_CSTRING("werror")))
|
.setWerror(GetWorkerPref<bool>(NS_LITERAL_CSTRING("werror")))
|
||||||
.setStreams(GetWorkerPref<bool>(NS_LITERAL_CSTRING("streams")))
|
.setStreams(GetWorkerPref<bool>(NS_LITERAL_CSTRING("streams")))
|
||||||
.setWeakRefs(GetWorkerPref<bool>(NS_LITERAL_CSTRING("weakrefs")))
|
|
||||||
.setExtraWarnings(GetWorkerPref<bool>(NS_LITERAL_CSTRING("strict")))
|
.setExtraWarnings(GetWorkerPref<bool>(NS_LITERAL_CSTRING("strict")))
|
||||||
.setArrayProtoValues(GetWorkerPref<bool>(
|
.setArrayProtoValues(GetWorkerPref<bool>(
|
||||||
NS_LITERAL_CSTRING("array_prototype_values")));
|
NS_LITERAL_CSTRING("array_prototype_values")));
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ WORKER_SIMPLE_PREF("dom.serviceWorkers.openWindow.enabled", OpenWindowEnabled, O
|
||||||
WORKER_SIMPLE_PREF("dom.storageManager.enabled", StorageManagerEnabled, STORAGEMANAGER_ENABLED)
|
WORKER_SIMPLE_PREF("dom.storageManager.enabled", StorageManagerEnabled, STORAGEMANAGER_ENABLED)
|
||||||
WORKER_SIMPLE_PREF("dom.push.enabled", PushEnabled, PUSH_ENABLED)
|
WORKER_SIMPLE_PREF("dom.push.enabled", PushEnabled, PUSH_ENABLED)
|
||||||
WORKER_SIMPLE_PREF("dom.streams.enabled", StreamsEnabled, STREAMS_ENABLED)
|
WORKER_SIMPLE_PREF("dom.streams.enabled", StreamsEnabled, STREAMS_ENABLED)
|
||||||
WORKER_SIMPLE_PREF("javascript.options.weakrefs", WeakRefsEnabled, WEAKREFS_ENABLED)
|
|
||||||
WORKER_SIMPLE_PREF("dom.requestcontext.enabled", RequestContextEnabled, REQUESTCONTEXT_ENABLED)
|
WORKER_SIMPLE_PREF("dom.requestcontext.enabled", RequestContextEnabled, REQUESTCONTEXT_ENABLED)
|
||||||
WORKER_SIMPLE_PREF("gfx.offscreencanvas.enabled", OffscreenCanvasEnabled, OFFSCREENCANVAS_ENABLED)
|
WORKER_SIMPLE_PREF("gfx.offscreencanvas.enabled", OffscreenCanvasEnabled, OFFSCREENCANVAS_ENABLED)
|
||||||
WORKER_SIMPLE_PREF("dom.webkitBlink.dirPicker.enabled", WebkitBlinkDirectoryPickerEnabled, DOM_WEBKITBLINK_DIRPICKER_WEBKITBLINK)
|
WORKER_SIMPLE_PREF("dom.webkitBlink.dirPicker.enabled", WebkitBlinkDirectoryPickerEnabled, DOM_WEBKITBLINK_DIRPICKER_WEBKITBLINK)
|
||||||
|
|
|
||||||
|
|
@ -952,38 +952,12 @@ using namespace std;
|
||||||
void
|
void
|
||||||
imgCacheQueue::Remove(imgCacheEntry* entry)
|
imgCacheQueue::Remove(imgCacheEntry* entry)
|
||||||
{
|
{
|
||||||
uint64_t index = mQueue.IndexOf(entry);
|
queueContainer::iterator it = find(mQueue.begin(), mQueue.end(), entry);
|
||||||
if (index == queueContainer::NoIndex) {
|
if (it != mQueue.end()) {
|
||||||
return;
|
mSize -= (*it)->GetDataSize();
|
||||||
|
mQueue.erase(it);
|
||||||
|
MarkDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
mSize -= mQueue[index]->GetDataSize();
|
|
||||||
|
|
||||||
// If the queue is clean and this is the first entry,
|
|
||||||
// then we can efficiently remove the entry without
|
|
||||||
// dirtying the sort order.
|
|
||||||
if (!IsDirty() && index == 0) {
|
|
||||||
std::pop_heap(mQueue.begin(), mQueue.end(),
|
|
||||||
imgLoader::CompareCacheEntries);
|
|
||||||
mQueue.RemoveElementAt(mQueue.Length() - 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove from the middle of the list. This potentially
|
|
||||||
// breaks the binary heap sort order.
|
|
||||||
mQueue.RemoveElementAt(index);
|
|
||||||
|
|
||||||
// If we only have one entry or the queue is empty, though,
|
|
||||||
// then the sort order is still effectively good.
|
|
||||||
// Simply refresh the list to clear the dirty flag.
|
|
||||||
if (mQueue.Length() <= 1) {
|
|
||||||
Refresh();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise we must mark the queue dirty and potentially
|
|
||||||
// trigger an expensive sort later.
|
|
||||||
MarkDirty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -992,26 +966,23 @@ imgCacheQueue::Push(imgCacheEntry* entry)
|
||||||
mSize += entry->GetDataSize();
|
mSize += entry->GetDataSize();
|
||||||
|
|
||||||
RefPtr<imgCacheEntry> refptr(entry);
|
RefPtr<imgCacheEntry> refptr(entry);
|
||||||
mQueue.AppendElement(Move(refptr));
|
mQueue.push_back(refptr);
|
||||||
// If we're not dirty already, then we can efficiently add this to the binary heap immediately.
|
MarkDirty();
|
||||||
if (!IsDirty()) {
|
|
||||||
std::push_heap(mQueue.begin(), mQueue.end(), imgLoader::CompareCacheEntries);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<imgCacheEntry>
|
already_AddRefed<imgCacheEntry>
|
||||||
imgCacheQueue::Pop()
|
imgCacheQueue::Pop()
|
||||||
{
|
{
|
||||||
if (mQueue.IsEmpty()) {
|
if (mQueue.empty()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (IsDirty()) {
|
if (IsDirty()) {
|
||||||
Refresh();
|
Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RefPtr<imgCacheEntry> entry = mQueue[0];
|
||||||
std::pop_heap(mQueue.begin(), mQueue.end(), imgLoader::CompareCacheEntries);
|
std::pop_heap(mQueue.begin(), mQueue.end(), imgLoader::CompareCacheEntries);
|
||||||
RefPtr<imgCacheEntry> entry = Move(mQueue.LastElement());
|
mQueue.pop_back();
|
||||||
mQueue.RemoveElementAt(mQueue.Length() - 1);
|
|
||||||
|
|
||||||
mSize -= entry->GetDataSize();
|
mSize -= entry->GetDataSize();
|
||||||
return entry.forget();
|
return entry.forget();
|
||||||
|
|
@ -1020,7 +991,6 @@ imgCacheQueue::Pop()
|
||||||
void
|
void
|
||||||
imgCacheQueue::Refresh()
|
imgCacheQueue::Refresh()
|
||||||
{
|
{
|
||||||
// Re-heap the list. This is an O(3 * n) operation and best avoided if possible.
|
|
||||||
std::make_heap(mQueue.begin(), mQueue.end(), imgLoader::CompareCacheEntries);
|
std::make_heap(mQueue.begin(), mQueue.end(), imgLoader::CompareCacheEntries);
|
||||||
mDirty = false;
|
mDirty = false;
|
||||||
}
|
}
|
||||||
|
|
@ -1040,13 +1010,7 @@ imgCacheQueue::IsDirty()
|
||||||
uint32_t
|
uint32_t
|
||||||
imgCacheQueue::GetNumElements() const
|
imgCacheQueue::GetNumElements() const
|
||||||
{
|
{
|
||||||
return mQueue.Length();
|
return mQueue.size();
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
imgCacheQueue::Contains(imgCacheEntry* aEntry) const
|
|
||||||
{
|
|
||||||
return mQueue.Contains(aEntry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
imgCacheQueue::iterator
|
imgCacheQueue::iterator
|
||||||
|
|
@ -1638,11 +1602,7 @@ void
|
||||||
imgLoader::CacheEntriesChanged(bool aForChrome, int32_t aSizeDiff /* = 0 */)
|
imgLoader::CacheEntriesChanged(bool aForChrome, int32_t aSizeDiff /* = 0 */)
|
||||||
{
|
{
|
||||||
imgCacheQueue& queue = GetCacheQueue(aForChrome);
|
imgCacheQueue& queue = GetCacheQueue(aForChrome);
|
||||||
// We only need to dirty the queue if there is any sorting taking place.
|
queue.MarkDirty();
|
||||||
// Empty or single-entry lists can't become dirty.
|
|
||||||
if (queue.GetNumElements() > 1) {
|
|
||||||
queue.MarkDirty();
|
|
||||||
}
|
|
||||||
queue.UpdateSize(aSizeDiff);
|
queue.UpdateSize(aSizeDiff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1671,9 +1631,7 @@ imgLoader::CheckCacheLimits(imgCacheTable& cache, imgCacheQueue& queue)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry) {
|
if (entry) {
|
||||||
// We just popped this entry from the queue, so pass AlreadyRemoved
|
RemoveFromCache(entry);
|
||||||
// to avoid searching the queue again in RemoveFromCache.
|
|
||||||
RemoveFromCache(entry, QueueState::AlreadyRemoved);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1972,7 +1930,7 @@ imgLoader::RemoveFromCache(const ImageCacheKey& aKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
imgLoader::RemoveFromCache(imgCacheEntry* entry, QueueState aQueueState)
|
imgLoader::RemoveFromCache(imgCacheEntry* entry)
|
||||||
{
|
{
|
||||||
LOG_STATIC_FUNC(gImgLog, "imgLoader::RemoveFromCache entry");
|
LOG_STATIC_FUNC(gImgLog, "imgLoader::RemoveFromCache entry");
|
||||||
|
|
||||||
|
|
@ -1988,24 +1946,13 @@ imgLoader::RemoveFromCache(imgCacheEntry* entry, QueueState aQueueState)
|
||||||
|
|
||||||
cache.Remove(key);
|
cache.Remove(key);
|
||||||
|
|
||||||
if (queue.IsDirty()) {
|
|
||||||
queue.Refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry->HasNoProxies()) {
|
if (entry->HasNoProxies()) {
|
||||||
LOG_STATIC_FUNC(gImgLog,
|
LOG_STATIC_FUNC(gImgLog,
|
||||||
"imgLoader::RemoveFromCache removing from tracker");
|
"imgLoader::RemoveFromCache removing from tracker");
|
||||||
if (mCacheTracker) {
|
if (mCacheTracker) {
|
||||||
mCacheTracker->RemoveObject(entry);
|
mCacheTracker->RemoveObject(entry);
|
||||||
}
|
}
|
||||||
// Only search the queue to remove the entry if its possible it might
|
queue.Remove(entry);
|
||||||
// be in the queue. If we know its not in the queue this would be
|
|
||||||
// wasted work.
|
|
||||||
MOZ_ASSERT_IF(aQueueState == QueueState::AlreadyRemoved,
|
|
||||||
!queue.Contains(entry));
|
|
||||||
if (aQueueState == QueueState::MaybeExists) {
|
|
||||||
queue.Remove(entry);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
entry->SetEvicted(true);
|
entry->SetEvicted(true);
|
||||||
|
|
@ -2050,13 +1997,13 @@ imgLoader::EvictEntries(imgCacheQueue& aQueueToClear)
|
||||||
// We have to make a temporary, since RemoveFromCache removes the element
|
// We have to make a temporary, since RemoveFromCache removes the element
|
||||||
// from the queue, invalidating iterators.
|
// from the queue, invalidating iterators.
|
||||||
nsTArray<RefPtr<imgCacheEntry> > entries(aQueueToClear.GetNumElements());
|
nsTArray<RefPtr<imgCacheEntry> > entries(aQueueToClear.GetNumElements());
|
||||||
for (auto i = aQueueToClear.begin(); i != aQueueToClear.end(); ++i) {
|
for (imgCacheQueue::const_iterator i = aQueueToClear.begin();
|
||||||
|
i != aQueueToClear.end(); ++i) {
|
||||||
entries.AppendElement(*i);
|
entries.AppendElement(*i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate in reverse order to minimize array copying.
|
for (uint32_t i = 0; i < entries.Length(); ++i) {
|
||||||
for (auto& entry : entries) {
|
if (!RemoveFromCache(entries[i])) {
|
||||||
if (!RemoveFromCache(entry)) {
|
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -178,8 +178,7 @@ public:
|
||||||
uint32_t GetSize() const;
|
uint32_t GetSize() const;
|
||||||
void UpdateSize(int32_t diff);
|
void UpdateSize(int32_t diff);
|
||||||
uint32_t GetNumElements() const;
|
uint32_t GetNumElements() const;
|
||||||
bool Contains(imgCacheEntry* aEntry) const;
|
typedef std::vector<RefPtr<imgCacheEntry> > queueContainer;
|
||||||
typedef nsTArray<RefPtr<imgCacheEntry> > queueContainer;
|
|
||||||
typedef queueContainer::iterator iterator;
|
typedef queueContainer::iterator iterator;
|
||||||
typedef queueContainer::const_iterator const_iterator;
|
typedef queueContainer::const_iterator const_iterator;
|
||||||
|
|
||||||
|
|
@ -317,16 +316,7 @@ public:
|
||||||
nsresult InitCache();
|
nsresult InitCache();
|
||||||
|
|
||||||
bool RemoveFromCache(const ImageCacheKey& aKey);
|
bool RemoveFromCache(const ImageCacheKey& aKey);
|
||||||
|
bool RemoveFromCache(imgCacheEntry* entry);
|
||||||
// Enumeration describing if a given entry is in the cache queue or not.
|
|
||||||
// There are some cases we know the entry is definitely not in the queue.
|
|
||||||
enum class QueueState {
|
|
||||||
MaybeExists,
|
|
||||||
AlreadyRemoved
|
|
||||||
};
|
|
||||||
|
|
||||||
bool RemoveFromCache(imgCacheEntry* entry,
|
|
||||||
QueueState aQueueState = QueueState::MaybeExists);
|
|
||||||
|
|
||||||
bool PutIntoCache(const ImageCacheKey& aKey, imgCacheEntry* aEntry);
|
bool PutIntoCache(const ImageCacheKey& aKey, imgCacheEntry* aEntry);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -253,67 +253,6 @@ function ArraySort(comparefn) {
|
||||||
return MergeSort(O, len, comparefn);
|
return MergeSort(O, len, comparefn);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ES2023 22.1.3.30 Array.prototype.toSorted ( comparefn )
|
|
||||||
function ArrayToSorted(comparefn) {
|
|
||||||
if (comparefn !== undefined) {
|
|
||||||
if (!IsCallable(comparefn)) {
|
|
||||||
ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, comparefn));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 1: Let O be ? ToObject(this). Let len be ? ToLength(O.length).
|
|
||||||
var O = ToObject(this);
|
|
||||||
var len = ToLength(O.length);
|
|
||||||
|
|
||||||
// Step 2: Snapshot values in ascending index order into a List.
|
|
||||||
var items = new List();
|
|
||||||
var itemsLen = len;
|
|
||||||
for (var k = 0; k < len; k++) {
|
|
||||||
items[k] = O[k];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 3: Create SortCompare per spec.
|
|
||||||
var wrappedCompareFn = comparefn;
|
|
||||||
var sortCompare;
|
|
||||||
if (wrappedCompareFn === undefined) {
|
|
||||||
sortCompare = function(x, y) {
|
|
||||||
if (x === undefined)
|
|
||||||
return y === undefined ? 0 : 1;
|
|
||||||
if (y === undefined)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
var xString = ToString(x);
|
|
||||||
var yString = ToString(y);
|
|
||||||
if (xString < yString)
|
|
||||||
return -1;
|
|
||||||
if (xString > yString)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
sortCompare = function(x, y) {
|
|
||||||
if (x === undefined)
|
|
||||||
return y === undefined ? 0 : 1;
|
|
||||||
if (y === undefined)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
var v = ToNumber(wrappedCompareFn(x, y));
|
|
||||||
return v !== v ? 0 : v;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 4: Sort the snapshot List using SortCompare.
|
|
||||||
if (itemsLen > 1)
|
|
||||||
MergeSort(items, itemsLen, sortCompare);
|
|
||||||
|
|
||||||
// Step 5: Create result array and write sorted values.
|
|
||||||
var A = ArraySpeciesCreate(O, len);
|
|
||||||
for (var j = 0; j < itemsLen; j++)
|
|
||||||
_DefineDataProperty(A, j, items[j]);
|
|
||||||
|
|
||||||
return A;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ES5 15.4.4.18. */
|
/* ES5 15.4.4.18. */
|
||||||
function ArrayForEach(callbackfn/*, thisArg*/) {
|
function ArrayForEach(callbackfn/*, thisArg*/) {
|
||||||
/* Step 1. */
|
/* Step 1. */
|
||||||
|
|
|
||||||
|
|
@ -47,12 +47,10 @@
|
||||||
#include "builtin/AtomicsObject.h"
|
#include "builtin/AtomicsObject.h"
|
||||||
|
|
||||||
#include "mozilla/Atomics.h"
|
#include "mozilla/Atomics.h"
|
||||||
#include "mozilla/Casting.h"
|
|
||||||
#include "mozilla/FloatingPoint.h"
|
#include "mozilla/FloatingPoint.h"
|
||||||
#include "mozilla/Maybe.h"
|
#include "mozilla/Maybe.h"
|
||||||
#include "mozilla/Unused.h"
|
#include "mozilla/Unused.h"
|
||||||
|
|
||||||
#include "builtin/Promise.h"
|
|
||||||
#include "jsapi.h"
|
#include "jsapi.h"
|
||||||
#include "jsfriendapi.h"
|
#include "jsfriendapi.h"
|
||||||
#include "jsnum.h"
|
#include "jsnum.h"
|
||||||
|
|
@ -60,9 +58,7 @@
|
||||||
#include "jit/AtomicOperations.h"
|
#include "jit/AtomicOperations.h"
|
||||||
#include "jit/InlinableNatives.h"
|
#include "jit/InlinableNatives.h"
|
||||||
#include "js/Class.h"
|
#include "js/Class.h"
|
||||||
#include "vm/BigIntType.h"
|
|
||||||
#include "vm/GlobalObject.h"
|
#include "vm/GlobalObject.h"
|
||||||
#include "vm/HelperThreads.h"
|
|
||||||
#include "vm/Time.h"
|
#include "vm/Time.h"
|
||||||
#include "vm/TypedArrayObject.h"
|
#include "vm/TypedArrayObject.h"
|
||||||
#include "wasm/WasmInstance.h"
|
#include "wasm/WasmInstance.h"
|
||||||
|
|
@ -125,68 +121,6 @@ GetTypedArrayIndex(JSContext* cx, HandleValue v, Handle<TypedArrayObject*> view,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
|
||||||
IsWaitableTypedArray(Scalar::Type viewType)
|
|
||||||
{
|
|
||||||
return viewType == Scalar::Int32 || viewType == Scalar::BigInt64;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t
|
|
||||||
GetWaiterByteOffset(Handle<TypedArrayObject*> view, uint32_t offset)
|
|
||||||
{
|
|
||||||
return view->byteOffset() + offset * TypedArrayElemSize(view->type());
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t
|
|
||||||
BigIntToRawBits(Scalar::Type viewType, BigInt* value)
|
|
||||||
{
|
|
||||||
if (viewType == Scalar::BigInt64)
|
|
||||||
return uint64_t(BigInt::toInt64(value));
|
|
||||||
MOZ_ASSERT(viewType == Scalar::BigUint64);
|
|
||||||
return BigInt::toUint64(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
BigIntToRawBits(JSContext* cx, Scalar::Type viewType, HandleValue value, uint64_t* bits)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(Scalar::isBigIntType(viewType));
|
|
||||||
|
|
||||||
RootedBigInt bigint(cx, ToBigInt(cx, value));
|
|
||||||
if (!bigint)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
*bits = BigIntToRawBits(viewType, bigint);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
SetBigIntResult(JSContext* cx, Scalar::Type viewType, uint64_t bits, MutableHandleValue result)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(Scalar::isBigIntType(viewType));
|
|
||||||
|
|
||||||
BigInt* bigint = viewType == Scalar::BigInt64
|
|
||||||
? BigInt::createFromInt64(cx, mozilla::BitwiseCast<int64_t>(bits))
|
|
||||||
: BigInt::createFromUint64(cx, bits);
|
|
||||||
if (!bigint)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
result.setBigInt(bigint);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
WaitValueMatches(Handle<TypedArrayObject*> view, uint32_t offset, uint64_t expected)
|
|
||||||
{
|
|
||||||
SharedMem<void*> viewData = view->viewDataShared();
|
|
||||||
if (view->type() == Scalar::BigInt64) {
|
|
||||||
return jit::AtomicOperations::loadSafeWhenRacy(viewData.cast<uint64_t*>() + offset) ==
|
|
||||||
expected;
|
|
||||||
}
|
|
||||||
|
|
||||||
return uint32_t(jit::AtomicOperations::loadSafeWhenRacy(viewData.cast<int32_t*>() + offset)) ==
|
|
||||||
uint32_t(expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t
|
static int32_t
|
||||||
CompareExchange(Scalar::Type viewType, int32_t oldCandidate, int32_t newCandidate,
|
CompareExchange(Scalar::Type viewType, int32_t oldCandidate, int32_t newCandidate,
|
||||||
SharedMem<void*> viewData, uint32_t offset, bool* badArrayType = nullptr)
|
SharedMem<void*> viewData, uint32_t offset, bool* badArrayType = nullptr)
|
||||||
|
|
@ -257,20 +191,6 @@ js::atomics_compareExchange(JSContext* cx, unsigned argc, Value* vp)
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
if (!GetTypedArrayIndex(cx, idxv, view, &offset))
|
if (!GetTypedArrayIndex(cx, idxv, view, &offset))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (Scalar::isBigIntType(view->type())) {
|
|
||||||
uint64_t oldCandidate;
|
|
||||||
if (!BigIntToRawBits(cx, view->type(), oldv, &oldCandidate))
|
|
||||||
return false;
|
|
||||||
uint64_t newCandidate;
|
|
||||||
if (!BigIntToRawBits(cx, view->type(), newv, &newCandidate))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint64_t result = jit::AtomicOperations::compareExchangeSeqCst(
|
|
||||||
view->viewDataShared().cast<uint64_t*>() + offset, oldCandidate, newCandidate);
|
|
||||||
return SetBigIntResult(cx, view->type(), result, r);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t oldCandidate;
|
int32_t oldCandidate;
|
||||||
if (!ToInt32(cx, oldv, &oldCandidate))
|
if (!ToInt32(cx, oldv, &oldCandidate))
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -339,22 +259,6 @@ js::atomics_load(JSContext* cx, unsigned argc, Value* vp)
|
||||||
r.setNumber(v);
|
r.setNumber(v);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case Scalar::BigInt64: {
|
|
||||||
int64_t v = jit::AtomicOperations::loadSeqCst(viewData.cast<int64_t*>() + offset);
|
|
||||||
BigInt* bigint = BigInt::createFromInt64(cx, v);
|
|
||||||
if (!bigint)
|
|
||||||
return false;
|
|
||||||
r.setBigInt(bigint);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case Scalar::BigUint64: {
|
|
||||||
uint64_t v = jit::AtomicOperations::loadSeqCst(viewData.cast<uint64_t*>() + offset);
|
|
||||||
BigInt* bigint = BigInt::createFromUint64(cx, v);
|
|
||||||
if (!bigint)
|
|
||||||
return false;
|
|
||||||
r.setBigInt(bigint);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return ReportBadArrayType(cx);
|
return ReportBadArrayType(cx);
|
||||||
}
|
}
|
||||||
|
|
@ -433,25 +337,6 @@ ExchangeOrStore(JSContext* cx, unsigned argc, Value* vp)
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
if (!GetTypedArrayIndex(cx, idxv, view, &offset))
|
if (!GetTypedArrayIndex(cx, idxv, view, &offset))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (Scalar::isBigIntType(view->type())) {
|
|
||||||
RootedBigInt bigint(cx, ToBigInt(cx, valv));
|
|
||||||
if (!bigint)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint64_t value = BigIntToRawBits(view->type(), bigint);
|
|
||||||
if (op == DoStore) {
|
|
||||||
jit::AtomicOperations::storeSeqCst(view->viewDataShared().cast<uint64_t*>() + offset,
|
|
||||||
value);
|
|
||||||
r.setBigInt(bigint);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t result = jit::AtomicOperations::exchangeSeqCst(
|
|
||||||
view->viewDataShared().cast<uint64_t*>() + offset, value);
|
|
||||||
return SetBigIntResult(cx, view->type(), result, r);
|
|
||||||
}
|
|
||||||
|
|
||||||
double integerValue;
|
double integerValue;
|
||||||
if (!ToInteger(cx, valv, &integerValue))
|
if (!ToInteger(cx, valv, &integerValue))
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -495,24 +380,6 @@ AtomicsBinop(JSContext* cx, HandleValue objv, HandleValue idxv, HandleValue valv
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
if (!GetTypedArrayIndex(cx, idxv, view, &offset))
|
if (!GetTypedArrayIndex(cx, idxv, view, &offset))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (Scalar::isBigIntType(view->type())) {
|
|
||||||
uint64_t value;
|
|
||||||
if (!BigIntToRawBits(cx, view->type(), valv, &value))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
SharedMem<uint64_t*> addr = view->viewDataShared().cast<uint64_t*>() + offset;
|
|
||||||
uint64_t old = jit::AtomicOperations::loadSeqCst(addr);
|
|
||||||
for (;;) {
|
|
||||||
uint64_t replacement = T::operate64(old, value);
|
|
||||||
uint64_t observed = jit::AtomicOperations::compareExchangeSeqCst(addr, old,
|
|
||||||
replacement);
|
|
||||||
if (observed == old)
|
|
||||||
return SetBigIntResult(cx, view->type(), old, r);
|
|
||||||
old = observed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t numberValue;
|
int32_t numberValue;
|
||||||
if (!ToInt32(cx, valv, &numberValue))
|
if (!ToInt32(cx, valv, &numberValue))
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -567,7 +434,6 @@ class PerformAdd
|
||||||
public:
|
public:
|
||||||
INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchAddSeqCst)
|
INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchAddSeqCst)
|
||||||
static int32_t perform(int32_t x, int32_t y) { return x + y; }
|
static int32_t perform(int32_t x, int32_t y) { return x + y; }
|
||||||
static uint64_t operate64(uint64_t x, uint64_t y) { return x + y; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
@ -582,7 +448,6 @@ class PerformSub
|
||||||
public:
|
public:
|
||||||
INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchSubSeqCst)
|
INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchSubSeqCst)
|
||||||
static int32_t perform(int32_t x, int32_t y) { return x - y; }
|
static int32_t perform(int32_t x, int32_t y) { return x - y; }
|
||||||
static uint64_t operate64(uint64_t x, uint64_t y) { return x - y; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
@ -597,7 +462,6 @@ class PerformAnd
|
||||||
public:
|
public:
|
||||||
INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchAndSeqCst)
|
INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchAndSeqCst)
|
||||||
static int32_t perform(int32_t x, int32_t y) { return x & y; }
|
static int32_t perform(int32_t x, int32_t y) { return x & y; }
|
||||||
static uint64_t operate64(uint64_t x, uint64_t y) { return x & y; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
@ -612,7 +476,6 @@ class PerformOr
|
||||||
public:
|
public:
|
||||||
INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchOrSeqCst)
|
INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchOrSeqCst)
|
||||||
static int32_t perform(int32_t x, int32_t y) { return x | y; }
|
static int32_t perform(int32_t x, int32_t y) { return x | y; }
|
||||||
static uint64_t operate64(uint64_t x, uint64_t y) { return x | y; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
@ -627,7 +490,6 @@ class PerformXor
|
||||||
public:
|
public:
|
||||||
INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchXorSeqCst)
|
INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchXorSeqCst)
|
||||||
static int32_t perform(int32_t x, int32_t y) { return x ^ y; }
|
static int32_t perform(int32_t x, int32_t y) { return x ^ y; }
|
||||||
static uint64_t operate64(uint64_t x, uint64_t y) { return x ^ y; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
@ -831,13 +693,11 @@ js::atomics_cmpxchg_asm_callout(wasm::Instance* instance, int32_t vt, int32_t of
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
class AtomicsWaitAsyncTask;
|
|
||||||
|
|
||||||
// Represents one waiting worker.
|
// Represents one waiting worker.
|
||||||
//
|
//
|
||||||
// The type is declared opaque in SharedArrayObject.h. Instances of
|
// The type is declared opaque in SharedArrayObject.h. Instances of
|
||||||
// js::FutexWaiter are linked onto a list across a call to FutexRuntime::wait()
|
// js::FutexWaiter are stack-allocated and linked onto a list across a
|
||||||
// or an async wait task.
|
// call to FutexRuntime::wait().
|
||||||
//
|
//
|
||||||
// The 'waiters' field of the SharedArrayRawBuffer points to the highest
|
// The 'waiters' field of the SharedArrayRawBuffer points to the highest
|
||||||
// priority waiter in the list, and lower priority nodes are linked through
|
// priority waiter in the list, and lower priority nodes are linked through
|
||||||
|
|
@ -851,34 +711,14 @@ class FutexWaiter
|
||||||
public:
|
public:
|
||||||
FutexWaiter(uint32_t offset, JSRuntime* rt)
|
FutexWaiter(uint32_t offset, JSRuntime* rt)
|
||||||
: offset(offset),
|
: offset(offset),
|
||||||
kind(Sync),
|
|
||||||
rt(rt),
|
rt(rt),
|
||||||
asyncTask(nullptr),
|
|
||||||
lower_pri(nullptr),
|
lower_pri(nullptr),
|
||||||
back(nullptr)
|
back(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
FutexWaiter(uint32_t offset, AtomicsWaitAsyncTask* asyncTask)
|
uint32_t offset; // int32 element index within the SharedArrayBuffer
|
||||||
: offset(offset),
|
|
||||||
kind(Async),
|
|
||||||
rt(nullptr),
|
|
||||||
asyncTask(asyncTask),
|
|
||||||
lower_pri(nullptr),
|
|
||||||
back(nullptr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isWaiting() const;
|
|
||||||
void notify();
|
|
||||||
|
|
||||||
uint32_t offset; // byte offset within the SharedArrayBuffer
|
|
||||||
enum WaiterKind {
|
|
||||||
Sync,
|
|
||||||
Async
|
|
||||||
} kind;
|
|
||||||
JSRuntime* rt; // The runtime of the waiter
|
JSRuntime* rt; // The runtime of the waiter
|
||||||
AtomicsWaitAsyncTask* asyncTask; // The async waiter task, if any
|
|
||||||
FutexWaiter* lower_pri; // Lower priority nodes in circular doubly-linked list of waiters
|
FutexWaiter* lower_pri; // Lower priority nodes in circular doubly-linked list of waiters
|
||||||
FutexWaiter* back; // Other direction
|
FutexWaiter* back; // Other direction
|
||||||
};
|
};
|
||||||
|
|
@ -902,195 +742,8 @@ class AutoLockFutexAPI
|
||||||
js::UniqueLock<js::Mutex>& unique() { return *unique_; }
|
js::UniqueLock<js::Mutex>& unique() { return *unique_; }
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
|
||||||
AddWaiter(SharedArrayRawBuffer* sarb, FutexWaiter* waiter)
|
|
||||||
{
|
|
||||||
if (FutexWaiter* waiters = sarb->waiters()) {
|
|
||||||
waiter->lower_pri = waiters;
|
|
||||||
waiter->back = waiters->back;
|
|
||||||
waiters->back->lower_pri = waiter;
|
|
||||||
waiters->back = waiter;
|
|
||||||
} else {
|
|
||||||
waiter->lower_pri = waiter->back = waiter;
|
|
||||||
sarb->setWaiters(waiter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
RemoveWaiter(SharedArrayRawBuffer* sarb, FutexWaiter* waiter)
|
|
||||||
{
|
|
||||||
if (waiter->lower_pri == waiter) {
|
|
||||||
sarb->setWaiters(nullptr);
|
|
||||||
} else {
|
|
||||||
waiter->lower_pri->back = waiter->back;
|
|
||||||
waiter->back->lower_pri = waiter->lower_pri;
|
|
||||||
if (sarb->waiters() == waiter)
|
|
||||||
sarb->setWaiters(waiter->lower_pri);
|
|
||||||
}
|
|
||||||
waiter->lower_pri = nullptr;
|
|
||||||
waiter->back = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
class AtomicsWaitAsyncTask : public PromiseTask
|
|
||||||
{
|
|
||||||
enum class State {
|
|
||||||
Waiting,
|
|
||||||
Notified,
|
|
||||||
TimedOut
|
|
||||||
};
|
|
||||||
|
|
||||||
SharedArrayRawBuffer* sarb_;
|
|
||||||
FutexWaiter waiter_;
|
|
||||||
mozilla::Maybe<mozilla::TimeDuration> timeout_;
|
|
||||||
ConditionVariable cond_;
|
|
||||||
State state_;
|
|
||||||
bool isInWaiterList_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AtomicsWaitAsyncTask(JSContext* cx, Handle<PromiseObject*> promise,
|
|
||||||
SharedArrayRawBuffer* sarb, uint32_t offset,
|
|
||||||
mozilla::Maybe<mozilla::TimeDuration>& timeout)
|
|
||||||
: PromiseTask(cx, promise),
|
|
||||||
sarb_(sarb),
|
|
||||||
waiter_(offset, this),
|
|
||||||
timeout_(timeout),
|
|
||||||
state_(State::Waiting),
|
|
||||||
isInWaiterList_(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~AtomicsWaitAsyncTask() {
|
|
||||||
if (isInWaiterList_) {
|
|
||||||
AutoLockFutexAPI lock;
|
|
||||||
if (isInWaiterList_)
|
|
||||||
removeFromWaiterList();
|
|
||||||
}
|
|
||||||
sarb_->dropReference();
|
|
||||||
}
|
|
||||||
|
|
||||||
FutexWaiter* waiter() {
|
|
||||||
return &waiter_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setInWaiterList() {
|
|
||||||
isInWaiterList_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isWaiting() const {
|
|
||||||
return state_ == State::Waiting;
|
|
||||||
}
|
|
||||||
|
|
||||||
void notify() {
|
|
||||||
MOZ_ASSERT(isWaiting());
|
|
||||||
state_ = State::Notified;
|
|
||||||
cond_.notify_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
void execute() override {
|
|
||||||
AutoLockFutexAPI lock;
|
|
||||||
|
|
||||||
const bool isTimed = timeout_.isSome();
|
|
||||||
auto finalEnd = timeout_.map([](mozilla::TimeDuration& timeout) {
|
|
||||||
return mozilla::TimeStamp::Now() + timeout;
|
|
||||||
});
|
|
||||||
auto maxSlice = mozilla::TimeDuration::FromSeconds(4000.0);
|
|
||||||
|
|
||||||
while (state_ == State::Waiting) {
|
|
||||||
if (isTimed) {
|
|
||||||
auto sliceEnd = finalEnd.map([&](mozilla::TimeStamp& finalEnd) {
|
|
||||||
auto sliceEnd = mozilla::TimeStamp::Now() + maxSlice;
|
|
||||||
if (finalEnd < sliceEnd)
|
|
||||||
sliceEnd = finalEnd;
|
|
||||||
return sliceEnd;
|
|
||||||
});
|
|
||||||
|
|
||||||
mozilla::Unused << cond_.wait_until(lock.unique(), *sliceEnd);
|
|
||||||
if (state_ == State::Waiting && mozilla::TimeStamp::Now() >= *finalEnd) {
|
|
||||||
state_ = State::TimedOut;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cond_.wait(lock.unique());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isInWaiterList_)
|
|
||||||
removeFromWaiterList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void removeFromWaiterList() {
|
|
||||||
MOZ_ASSERT(isInWaiterList_);
|
|
||||||
RemoveWaiter(sarb_, &waiter_);
|
|
||||||
isInWaiterList_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool finishPromise(JSContext* cx, Handle<PromiseObject*> promise) override {
|
|
||||||
RootedValue result(cx);
|
|
||||||
if (state_ == State::TimedOut)
|
|
||||||
result.setString(cx->names().futexTimedOut);
|
|
||||||
else
|
|
||||||
result.setString(cx->names().futexOK);
|
|
||||||
return PromiseObject::resolve(cx, promise, result);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
bool
|
|
||||||
FutexWaiter::isWaiting() const
|
|
||||||
{
|
|
||||||
if (kind == Sync)
|
|
||||||
return rt->fx.isWaiting();
|
|
||||||
return asyncTask->isWaiting();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
FutexWaiter::notify()
|
|
||||||
{
|
|
||||||
if (kind == Sync) {
|
|
||||||
rt->fx.notify(FutexRuntime::NotifyExplicit);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
asyncTask->notify();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace js
|
} // namespace js
|
||||||
|
|
||||||
static bool
|
|
||||||
GetWaitTimeout(JSContext* cx, HandleValue timeoutv,
|
|
||||||
mozilla::Maybe<mozilla::TimeDuration>* timeout)
|
|
||||||
{
|
|
||||||
timeout->reset();
|
|
||||||
if (!timeoutv.isUndefined()) {
|
|
||||||
double timeout_ms;
|
|
||||||
if (!ToNumber(cx, timeoutv, &timeout_ms))
|
|
||||||
return false;
|
|
||||||
if (!mozilla::IsNaN(timeout_ms)) {
|
|
||||||
if (timeout_ms < 0)
|
|
||||||
*timeout = mozilla::Some(mozilla::TimeDuration::FromSeconds(0.0));
|
|
||||||
else if (!mozilla::IsInfinite(timeout_ms))
|
|
||||||
*timeout = mozilla::Some(mozilla::TimeDuration::FromMilliseconds(timeout_ms));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
CreateWaitAsyncResult(JSContext* cx, bool isAsync, HandleValue value, MutableHandleValue rval)
|
|
||||||
{
|
|
||||||
RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx));
|
|
||||||
if (!obj)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
RootedValue asyncValue(cx, BooleanValue(isAsync));
|
|
||||||
if (!NativeDefineDataProperty(cx, obj, cx->names().async, asyncValue, JSPROP_ENUMERATE))
|
|
||||||
return false;
|
|
||||||
if (!NativeDefineDataProperty(cx, obj, cx->names().value, value, JSPROP_ENUMERATE))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
rval.setObject(*obj);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
js::atomics_wait(JSContext* cx, unsigned argc, Value* vp)
|
js::atomics_wait(JSContext* cx, unsigned argc, Value* vp)
|
||||||
{
|
{
|
||||||
|
|
@ -1106,24 +759,26 @@ js::atomics_wait(JSContext* cx, unsigned argc, Value* vp)
|
||||||
Rooted<TypedArrayObject*> view(cx, nullptr);
|
Rooted<TypedArrayObject*> view(cx, nullptr);
|
||||||
if (!GetSharedTypedArray(cx, objv, &view))
|
if (!GetSharedTypedArray(cx, objv, &view))
|
||||||
return false;
|
return false;
|
||||||
if (!IsWaitableTypedArray(view->type()))
|
if (view->type() != Scalar::Int32)
|
||||||
return ReportBadArrayType(cx);
|
return ReportBadArrayType(cx);
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
if (!GetTypedArrayIndex(cx, idxv, view, &offset))
|
if (!GetTypedArrayIndex(cx, idxv, view, &offset))
|
||||||
return false;
|
return false;
|
||||||
uint64_t value = 0;
|
int32_t value;
|
||||||
if (view->type() == Scalar::BigInt64) {
|
if (!ToInt32(cx, valv, &value))
|
||||||
if (!BigIntToRawBits(cx, view->type(), valv, &value))
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
int32_t int32Value;
|
|
||||||
if (!ToInt32(cx, valv, &int32Value))
|
|
||||||
return false;
|
|
||||||
value = uint32_t(int32Value);
|
|
||||||
}
|
|
||||||
mozilla::Maybe<mozilla::TimeDuration> timeout;
|
|
||||||
if (!GetWaitTimeout(cx, timeoutv, &timeout))
|
|
||||||
return false;
|
return false;
|
||||||
|
mozilla::Maybe<mozilla::TimeDuration> timeout;
|
||||||
|
if (!timeoutv.isUndefined()) {
|
||||||
|
double timeout_ms;
|
||||||
|
if (!ToNumber(cx, timeoutv, &timeout_ms))
|
||||||
|
return false;
|
||||||
|
if (!mozilla::IsNaN(timeout_ms)) {
|
||||||
|
if (timeout_ms < 0)
|
||||||
|
timeout = mozilla::Some(mozilla::TimeDuration::FromSeconds(0.0));
|
||||||
|
else if (!mozilla::IsInfinite(timeout_ms))
|
||||||
|
timeout = mozilla::Some(mozilla::TimeDuration::FromMilliseconds(timeout_ms));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!rt->fx.canWait())
|
if (!rt->fx.canWait())
|
||||||
return ReportCannotWait(cx);
|
return ReportCannotWait(cx);
|
||||||
|
|
@ -1132,7 +787,8 @@ js::atomics_wait(JSContext* cx, unsigned argc, Value* vp)
|
||||||
// and it provides the necessary memory fence.
|
// and it provides the necessary memory fence.
|
||||||
AutoLockFutexAPI lock;
|
AutoLockFutexAPI lock;
|
||||||
|
|
||||||
if (!WaitValueMatches(view, offset, value)) {
|
SharedMem<int32_t*> addr = view->viewDataShared().cast<int32_t*>() + offset;
|
||||||
|
if (jit::AtomicOperations::loadSafeWhenRacy(addr) != value) {
|
||||||
r.setString(cx->names().futexNotEqual);
|
r.setString(cx->names().futexNotEqual);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -1140,8 +796,16 @@ js::atomics_wait(JSContext* cx, unsigned argc, Value* vp)
|
||||||
Rooted<SharedArrayBufferObject*> sab(cx, view->bufferShared());
|
Rooted<SharedArrayBufferObject*> sab(cx, view->bufferShared());
|
||||||
SharedArrayRawBuffer* sarb = sab->rawBufferObject();
|
SharedArrayRawBuffer* sarb = sab->rawBufferObject();
|
||||||
|
|
||||||
FutexWaiter w(GetWaiterByteOffset(view, offset), rt);
|
FutexWaiter w(offset, rt);
|
||||||
AddWaiter(sarb, &w);
|
if (FutexWaiter* waiters = sarb->waiters()) {
|
||||||
|
w.lower_pri = waiters;
|
||||||
|
w.back = waiters->back;
|
||||||
|
waiters->back->lower_pri = &w;
|
||||||
|
waiters->back = &w;
|
||||||
|
} else {
|
||||||
|
w.lower_pri = w.back = &w;
|
||||||
|
sarb->setWaiters(&w);
|
||||||
|
}
|
||||||
|
|
||||||
FutexRuntime::WaitResult result = FutexRuntime::FutexOK;
|
FutexRuntime::WaitResult result = FutexRuntime::FutexOK;
|
||||||
bool retval = rt->fx.wait(cx, lock.unique(), timeout, &result);
|
bool retval = rt->fx.wait(cx, lock.unique(), timeout, &result);
|
||||||
|
|
@ -1156,96 +820,15 @@ js::atomics_wait(JSContext* cx, unsigned argc, Value* vp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoveWaiter(sarb, &w);
|
if (w.lower_pri == &w) {
|
||||||
return retval;
|
sarb->setWaiters(nullptr);
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
js::atomics_waitAsync(JSContext* cx, unsigned argc, Value* vp)
|
|
||||||
{
|
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
|
||||||
HandleValue objv = args.get(0);
|
|
||||||
HandleValue idxv = args.get(1);
|
|
||||||
HandleValue valv = args.get(2);
|
|
||||||
HandleValue timeoutv = args.get(3);
|
|
||||||
MutableHandleValue r = args.rval();
|
|
||||||
|
|
||||||
Rooted<TypedArrayObject*> view(cx, nullptr);
|
|
||||||
if (!GetSharedTypedArray(cx, objv, &view))
|
|
||||||
return false;
|
|
||||||
if (!IsWaitableTypedArray(view->type()))
|
|
||||||
return ReportBadArrayType(cx);
|
|
||||||
uint32_t offset;
|
|
||||||
if (!GetTypedArrayIndex(cx, idxv, view, &offset))
|
|
||||||
return false;
|
|
||||||
uint64_t value = 0;
|
|
||||||
if (view->type() == Scalar::BigInt64) {
|
|
||||||
if (!BigIntToRawBits(cx, view->type(), valv, &value))
|
|
||||||
return false;
|
|
||||||
} else {
|
} else {
|
||||||
int32_t int32Value;
|
w.lower_pri->back = w.back;
|
||||||
if (!ToInt32(cx, valv, &int32Value))
|
w.back->lower_pri = w.lower_pri;
|
||||||
return false;
|
if (sarb->waiters() == &w)
|
||||||
value = uint32_t(int32Value);
|
sarb->setWaiters(w.lower_pri);
|
||||||
}
|
}
|
||||||
mozilla::Maybe<mozilla::TimeDuration> timeout;
|
return retval;
|
||||||
if (!GetWaitTimeout(cx, timeoutv, &timeout))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Rooted<PromiseObject*> promise(cx, PromiseObject::createSkippingExecutor(cx));
|
|
||||||
if (!promise)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
RootedValue promiseValue(cx, ObjectValue(*promise));
|
|
||||||
RootedValue result(cx);
|
|
||||||
if (!CreateWaitAsyncResult(cx, true, promiseValue, &result))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Rooted<SharedArrayBufferObject*> sab(cx, view->bufferShared());
|
|
||||||
SharedArrayRawBuffer* sarb = sab->rawBufferObject();
|
|
||||||
if (!sarb->addReference()) {
|
|
||||||
JS_ReportErrorASCII(cx, "Reference count overflow on SharedArrayBuffer");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto task = cx->make_unique<AtomicsWaitAsyncTask>(cx, promise, sarb, offset, timeout);
|
|
||||||
if (!task) {
|
|
||||||
sarb->dropReference();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isAsync = false;
|
|
||||||
RootedValue immediateResult(cx);
|
|
||||||
{
|
|
||||||
AutoLockFutexAPI lock;
|
|
||||||
|
|
||||||
if (!WaitValueMatches(view, offset, value)) {
|
|
||||||
immediateResult.setString(cx->names().futexNotEqual);
|
|
||||||
} else if (timeout.isSome() && timeout->ToMilliseconds() == 0.0) {
|
|
||||||
immediateResult.setString(cx->names().futexTimedOut);
|
|
||||||
} else {
|
|
||||||
if (!cx->startAsyncTaskCallback || !cx->finishAsyncTaskCallback ||
|
|
||||||
!CanUseExtraThreads())
|
|
||||||
{
|
|
||||||
JS_ReportErrorASCII(cx, "Atomics.waitAsync not supported in this runtime.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
task->waiter()->offset = GetWaiterByteOffset(view, offset);
|
|
||||||
AddWaiter(sarb, task->waiter());
|
|
||||||
task->setInWaiterList();
|
|
||||||
isAsync = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isAsync)
|
|
||||||
return CreateWaitAsyncResult(cx, false, immediateResult, r);
|
|
||||||
|
|
||||||
if (!StartPromiseTask(cx, Move(task)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
r.set(result);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
@ -1260,12 +843,11 @@ js::atomics_notify(JSContext* cx, unsigned argc, Value* vp)
|
||||||
Rooted<TypedArrayObject*> view(cx, nullptr);
|
Rooted<TypedArrayObject*> view(cx, nullptr);
|
||||||
if (!GetSharedTypedArray(cx, objv, &view))
|
if (!GetSharedTypedArray(cx, objv, &view))
|
||||||
return false;
|
return false;
|
||||||
if (!IsWaitableTypedArray(view->type()))
|
if (view->type() != Scalar::Int32)
|
||||||
return ReportBadArrayType(cx);
|
return ReportBadArrayType(cx);
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
if (!GetTypedArrayIndex(cx, idxv, view, &offset))
|
if (!GetTypedArrayIndex(cx, idxv, view, &offset))
|
||||||
return false;
|
return false;
|
||||||
offset = GetWaiterByteOffset(view, offset);
|
|
||||||
double count;
|
double count;
|
||||||
if (countv.isUndefined()) {
|
if (countv.isUndefined()) {
|
||||||
count = mozilla::PositiveInfinity<double>();
|
count = mozilla::PositiveInfinity<double>();
|
||||||
|
|
@ -1288,9 +870,9 @@ js::atomics_notify(JSContext* cx, unsigned argc, Value* vp)
|
||||||
do {
|
do {
|
||||||
FutexWaiter* c = iter;
|
FutexWaiter* c = iter;
|
||||||
iter = iter->lower_pri;
|
iter = iter->lower_pri;
|
||||||
if (c->offset != offset || !c->isWaiting())
|
if (c->offset != offset || !c->rt->fx.isWaiting())
|
||||||
continue;
|
continue;
|
||||||
c->notify();
|
c->rt->fx.notify(FutexRuntime::NotifyExplicit);
|
||||||
++woken;
|
++woken;
|
||||||
--count;
|
--count;
|
||||||
} while (count > 0 && iter != waiters);
|
} while (count > 0 && iter != waiters);
|
||||||
|
|
@ -1524,7 +1106,6 @@ const JSFunctionSpec AtomicsMethods[] = {
|
||||||
JS_INLINABLE_FN("xor", atomics_xor, 3,0, AtomicsXor),
|
JS_INLINABLE_FN("xor", atomics_xor, 3,0, AtomicsXor),
|
||||||
JS_INLINABLE_FN("isLockFree", atomics_isLockFree, 1,0, AtomicsIsLockFree),
|
JS_INLINABLE_FN("isLockFree", atomics_isLockFree, 1,0, AtomicsIsLockFree),
|
||||||
JS_FN("wait", atomics_wait, 4,0),
|
JS_FN("wait", atomics_wait, 4,0),
|
||||||
JS_FN("waitAsync", atomics_waitAsync, 4,0),
|
|
||||||
JS_FN("notify", atomics_notify, 3,0),
|
JS_FN("notify", atomics_notify, 3,0),
|
||||||
JS_FN("wake", atomics_notify, 3,0), //Legacy name
|
JS_FN("wake", atomics_notify, 3,0), //Legacy name
|
||||||
JS_FS_END
|
JS_FS_END
|
||||||
|
|
|
||||||
|
|
@ -24,19 +24,18 @@ class AtomicsObject : public JSObject
|
||||||
static MOZ_MUST_USE bool toString(JSContext* cx, unsigned int argc, Value* vp);
|
static MOZ_MUST_USE bool toString(JSContext* cx, unsigned int argc, Value* vp);
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] bool atomics_compareExchange(JSContext* cx, unsigned argc, Value* vp);
|
MOZ_MUST_USE bool atomics_compareExchange(JSContext* cx, unsigned argc, Value* vp);
|
||||||
[[nodiscard]] bool atomics_exchange(JSContext* cx, unsigned argc, Value* vp);
|
MOZ_MUST_USE bool atomics_exchange(JSContext* cx, unsigned argc, Value* vp);
|
||||||
[[nodiscard]] bool atomics_load(JSContext* cx, unsigned argc, Value* vp);
|
MOZ_MUST_USE bool atomics_load(JSContext* cx, unsigned argc, Value* vp);
|
||||||
[[nodiscard]] bool atomics_store(JSContext* cx, unsigned argc, Value* vp);
|
MOZ_MUST_USE bool atomics_store(JSContext* cx, unsigned argc, Value* vp);
|
||||||
[[nodiscard]] bool atomics_add(JSContext* cx, unsigned argc, Value* vp);
|
MOZ_MUST_USE bool atomics_add(JSContext* cx, unsigned argc, Value* vp);
|
||||||
[[nodiscard]] bool atomics_sub(JSContext* cx, unsigned argc, Value* vp);
|
MOZ_MUST_USE bool atomics_sub(JSContext* cx, unsigned argc, Value* vp);
|
||||||
[[nodiscard]] bool atomics_and(JSContext* cx, unsigned argc, Value* vp);
|
MOZ_MUST_USE bool atomics_and(JSContext* cx, unsigned argc, Value* vp);
|
||||||
[[nodiscard]] bool atomics_or(JSContext* cx, unsigned argc, Value* vp);
|
MOZ_MUST_USE bool atomics_or(JSContext* cx, unsigned argc, Value* vp);
|
||||||
[[nodiscard]] bool atomics_xor(JSContext* cx, unsigned argc, Value* vp);
|
MOZ_MUST_USE bool atomics_xor(JSContext* cx, unsigned argc, Value* vp);
|
||||||
[[nodiscard]] bool atomics_isLockFree(JSContext* cx, unsigned argc, Value* vp);
|
MOZ_MUST_USE bool atomics_isLockFree(JSContext* cx, unsigned argc, Value* vp);
|
||||||
[[nodiscard]] bool atomics_wait(JSContext* cx, unsigned argc, Value* vp);
|
MOZ_MUST_USE bool atomics_wait(JSContext* cx, unsigned argc, Value* vp);
|
||||||
[[nodiscard]] bool atomics_waitAsync(JSContext* cx, unsigned argc, Value* vp);
|
MOZ_MUST_USE bool atomics_notify(JSContext* cx, unsigned argc, Value* vp);
|
||||||
[[nodiscard]] bool atomics_notify(JSContext* cx, unsigned argc, Value* vp);
|
|
||||||
|
|
||||||
/* asm.js callouts */
|
/* asm.js callouts */
|
||||||
namespace wasm { class Instance; }
|
namespace wasm { class Instance; }
|
||||||
|
|
|
||||||
|
|
@ -55,49 +55,6 @@ function MapForEach(callbackfn, thisArg = undefined) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ES2024
|
|
||||||
// Map.groupBy ( items, callbackfn )
|
|
||||||
function MapGroupBy(items, callbackfn) {
|
|
||||||
// Step 1.
|
|
||||||
RequireObjectCoercible(items);
|
|
||||||
|
|
||||||
// Step 2.
|
|
||||||
if (!IsCallable(callbackfn))
|
|
||||||
ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(1, callbackfn));
|
|
||||||
|
|
||||||
// Step 3.
|
|
||||||
var groups = std_Map_create();
|
|
||||||
|
|
||||||
// Step 4.
|
|
||||||
var k = 0;
|
|
||||||
|
|
||||||
// Steps 5-8.
|
|
||||||
for (var value of allowContentIter(items)) {
|
|
||||||
// Step 6.a.
|
|
||||||
if (k >= MAX_NUMERIC_INDEX)
|
|
||||||
ThrowTypeError(JSMSG_TOO_LONG_ARRAY);
|
|
||||||
|
|
||||||
// Step 6.b.
|
|
||||||
var key = callContentFunction(callbackfn, undefined, value, k);
|
|
||||||
|
|
||||||
// Steps 6.c-d.
|
|
||||||
var elements;
|
|
||||||
if (callFunction(std_Map_has, groups, key)) {
|
|
||||||
elements = callFunction(std_Map_get, groups, key);
|
|
||||||
callFunction(std_Array_push, elements, value);
|
|
||||||
} else {
|
|
||||||
elements = [value];
|
|
||||||
callFunction(std_Map_set, groups, key, elements);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 6.e.
|
|
||||||
k++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 9.
|
|
||||||
return groups;
|
|
||||||
}
|
|
||||||
|
|
||||||
var iteratorTemp = { mapIterationResultPair : null };
|
var iteratorTemp = { mapIterationResultPair : null };
|
||||||
|
|
||||||
function MapIteratorNext() {
|
function MapIteratorNext() {
|
||||||
|
|
|
||||||
|
|
@ -332,15 +332,9 @@ const JSPropertySpec MapObject::staticProperties[] = {
|
||||||
JS_PS_END
|
JS_PS_END
|
||||||
};
|
};
|
||||||
|
|
||||||
const JSFunctionSpec MapObject::staticMethods[] = {
|
|
||||||
JS_SELF_HOSTED_FN("groupBy", "MapGroupBy", 2, 0),
|
|
||||||
JS_FS_END
|
|
||||||
};
|
|
||||||
|
|
||||||
static JSObject*
|
static JSObject*
|
||||||
InitClass(JSContext* cx, Handle<GlobalObject*> global, const Class* clasp, JSProtoKey key, Native construct,
|
InitClass(JSContext* cx, Handle<GlobalObject*> global, const Class* clasp, JSProtoKey key, Native construct,
|
||||||
const JSPropertySpec* properties, const JSFunctionSpec* methods,
|
const JSPropertySpec* properties, const JSFunctionSpec* methods,
|
||||||
const JSFunctionSpec* staticMethods,
|
|
||||||
const JSPropertySpec* staticProperties)
|
const JSPropertySpec* staticProperties)
|
||||||
{
|
{
|
||||||
RootedPlainObject proto(cx, NewBuiltinClassInstance<PlainObject>(cx));
|
RootedPlainObject proto(cx, NewBuiltinClassInstance<PlainObject>(cx));
|
||||||
|
|
@ -349,13 +343,8 @@ InitClass(JSContext* cx, Handle<GlobalObject*> global, const Class* clasp, JSPro
|
||||||
|
|
||||||
Rooted<JSFunction*> ctor(cx, global->createConstructor(cx, construct, ClassName(key, cx), 0));
|
Rooted<JSFunction*> ctor(cx, global->createConstructor(cx, construct, ClassName(key, cx), 0));
|
||||||
if (!ctor ||
|
if (!ctor ||
|
||||||
!JS_DefineProperties(cx, ctor, staticProperties))
|
!JS_DefineProperties(cx, ctor, staticProperties) ||
|
||||||
{
|
!LinkConstructorAndPrototype(cx, ctor, proto) ||
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
if (staticMethods && !JS_DefineFunctions(cx, ctor, staticMethods))
|
|
||||||
return nullptr;
|
|
||||||
if (!LinkConstructorAndPrototype(cx, ctor, proto) ||
|
|
||||||
!DefinePropertiesAndFunctions(cx, proto, properties, methods) ||
|
!DefinePropertiesAndFunctions(cx, proto, properties, methods) ||
|
||||||
!GlobalObject::initBuiltinConstructor(cx, global, key, ctor, proto))
|
!GlobalObject::initBuiltinConstructor(cx, global, key, ctor, proto))
|
||||||
{
|
{
|
||||||
|
|
@ -370,7 +359,7 @@ MapObject::initClass(JSContext* cx, JSObject* obj)
|
||||||
Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
|
Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
|
||||||
RootedObject proto(cx,
|
RootedObject proto(cx,
|
||||||
InitClass(cx, global, &class_, JSProto_Map, construct, properties, methods,
|
InitClass(cx, global, &class_, JSProto_Map, construct, properties, methods,
|
||||||
staticMethods, staticProperties));
|
staticProperties));
|
||||||
if (proto) {
|
if (proto) {
|
||||||
// Define the "entries" method.
|
// Define the "entries" method.
|
||||||
JSFunction* fun = JS_DefineFunction(cx, proto, "entries", entries, 0, 0);
|
JSFunction* fun = JS_DefineFunction(cx, proto, "entries", entries, 0, 0);
|
||||||
|
|
@ -1095,7 +1084,7 @@ SetObject::initClass(JSContext* cx, JSObject* obj)
|
||||||
Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
|
Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
|
||||||
RootedObject proto(cx,
|
RootedObject proto(cx,
|
||||||
InitClass(cx, global, &class_, JSProto_Set, construct, properties, methods,
|
InitClass(cx, global, &class_, JSProto_Set, construct, properties, methods,
|
||||||
nullptr, staticProperties));
|
staticProperties));
|
||||||
if (proto) {
|
if (proto) {
|
||||||
// Define the "values" method.
|
// Define the "values" method.
|
||||||
JSFunction* fun = JS_DefineFunction(cx, proto, "values", values, 0, 0);
|
JSFunction* fun = JS_DefineFunction(cx, proto, "values", values, 0, 0);
|
||||||
|
|
|
||||||
|
|
@ -109,10 +109,8 @@ class MapObject : public NativeObject {
|
||||||
|
|
||||||
static MOZ_MUST_USE bool getKeysAndValuesInterleaved(JSContext* cx, HandleObject obj,
|
static MOZ_MUST_USE bool getKeysAndValuesInterleaved(JSContext* cx, HandleObject obj,
|
||||||
JS::MutableHandle<GCVector<JS::Value>> entries);
|
JS::MutableHandle<GCVector<JS::Value>> entries);
|
||||||
[[nodiscard]] static bool entries(JSContext* cx, unsigned argc, Value* vp);
|
static MOZ_MUST_USE bool entries(JSContext* cx, unsigned argc, Value* vp);
|
||||||
[[nodiscard]] static bool get(JSContext* cx, unsigned argc, Value* vp);
|
static MOZ_MUST_USE bool has(JSContext* cx, unsigned argc, Value* vp);
|
||||||
[[nodiscard]] static bool has(JSContext* cx, unsigned argc, Value* vp);
|
|
||||||
[[nodiscard]] static bool set(JSContext* cx, unsigned argc, Value* vp);
|
|
||||||
static MapObject* create(JSContext* cx, HandleObject proto = nullptr);
|
static MapObject* create(JSContext* cx, HandleObject proto = nullptr);
|
||||||
|
|
||||||
// Publicly exposed Map calls for JSAPI access (webidl maplike/setlike
|
// Publicly exposed Map calls for JSAPI access (webidl maplike/setlike
|
||||||
|
|
@ -139,7 +137,6 @@ class MapObject : public NativeObject {
|
||||||
|
|
||||||
static const JSPropertySpec properties[];
|
static const JSPropertySpec properties[];
|
||||||
static const JSFunctionSpec methods[];
|
static const JSFunctionSpec methods[];
|
||||||
static const JSFunctionSpec staticMethods[];
|
|
||||||
static const JSPropertySpec staticProperties[];
|
static const JSPropertySpec staticProperties[];
|
||||||
ValueMap* getData() { return static_cast<ValueMap*>(getPrivate()); }
|
ValueMap* getData() { return static_cast<ValueMap*>(getPrivate()); }
|
||||||
static ValueMap& extract(HandleObject o);
|
static ValueMap& extract(HandleObject o);
|
||||||
|
|
@ -153,20 +150,22 @@ class MapObject : public NativeObject {
|
||||||
|
|
||||||
static MOZ_MUST_USE bool iterator_impl(JSContext* cx, const CallArgs& args, IteratorKind kind);
|
static MOZ_MUST_USE bool iterator_impl(JSContext* cx, const CallArgs& args, IteratorKind kind);
|
||||||
|
|
||||||
[[nodiscard]] static bool size_impl(JSContext* cx, const CallArgs& args);
|
static MOZ_MUST_USE bool size_impl(JSContext* cx, const CallArgs& args);
|
||||||
[[nodiscard]] static bool size(JSContext* cx, unsigned argc, Value* vp);
|
static MOZ_MUST_USE bool size(JSContext* cx, unsigned argc, Value* vp);
|
||||||
[[nodiscard]] static bool get_impl(JSContext* cx, const CallArgs& args);
|
static MOZ_MUST_USE bool get_impl(JSContext* cx, const CallArgs& args);
|
||||||
[[nodiscard]] static bool has_impl(JSContext* cx, const CallArgs& args);
|
static MOZ_MUST_USE bool get(JSContext* cx, unsigned argc, Value* vp);
|
||||||
[[nodiscard]] static bool set_impl(JSContext* cx, const CallArgs& args);
|
static MOZ_MUST_USE bool has_impl(JSContext* cx, const CallArgs& args);
|
||||||
[[nodiscard]] static bool delete_impl(JSContext* cx, const CallArgs& args);
|
static MOZ_MUST_USE bool set_impl(JSContext* cx, const CallArgs& args);
|
||||||
[[nodiscard]] static bool delete_(JSContext* cx, unsigned argc, Value* vp);
|
static MOZ_MUST_USE bool set(JSContext* cx, unsigned argc, Value* vp);
|
||||||
[[nodiscard]] static bool keys_impl(JSContext* cx, const CallArgs& args);
|
static MOZ_MUST_USE bool delete_impl(JSContext* cx, const CallArgs& args);
|
||||||
[[nodiscard]] static bool keys(JSContext* cx, unsigned argc, Value* vp);
|
static MOZ_MUST_USE bool delete_(JSContext* cx, unsigned argc, Value* vp);
|
||||||
[[nodiscard]] static bool values_impl(JSContext* cx, const CallArgs& args);
|
static MOZ_MUST_USE bool keys_impl(JSContext* cx, const CallArgs& args);
|
||||||
[[nodiscard]] static bool values(JSContext* cx, unsigned argc, Value* vp);
|
static MOZ_MUST_USE bool keys(JSContext* cx, unsigned argc, Value* vp);
|
||||||
[[nodiscard]] static bool entries_impl(JSContext* cx, const CallArgs& args);
|
static MOZ_MUST_USE bool values_impl(JSContext* cx, const CallArgs& args);
|
||||||
[[nodiscard]] static bool clear_impl(JSContext* cx, const CallArgs& args);
|
static MOZ_MUST_USE bool values(JSContext* cx, unsigned argc, Value* vp);
|
||||||
[[nodiscard]] static bool clear(JSContext* cx, unsigned argc, Value* vp);
|
static MOZ_MUST_USE bool entries_impl(JSContext* cx, const CallArgs& args);
|
||||||
|
static MOZ_MUST_USE bool clear_impl(JSContext* cx, const CallArgs& args);
|
||||||
|
static MOZ_MUST_USE bool clear(JSContext* cx, unsigned argc, Value* vp);
|
||||||
};
|
};
|
||||||
|
|
||||||
class MapIteratorObject : public NativeObject
|
class MapIteratorObject : public NativeObject
|
||||||
|
|
|
||||||
|
|
@ -240,16 +240,12 @@ function ObjectGroupBy(items, callbackfn) {
|
||||||
// Steps 5-8.
|
// Steps 5-8.
|
||||||
for (var value of allowContentIter(items)) {
|
for (var value of allowContentIter(items)) {
|
||||||
// Step 6.a.
|
// Step 6.a.
|
||||||
if (k >= MAX_NUMERIC_INDEX)
|
|
||||||
ThrowTypeError(JSMSG_TOO_LONG_ARRAY);
|
|
||||||
|
|
||||||
// Step 6.b.
|
|
||||||
var key = callContentFunction(callbackfn, undefined, value, k);
|
var key = callContentFunction(callbackfn, undefined, value, k);
|
||||||
|
|
||||||
// Step 6.c.
|
// Step 6.b.
|
||||||
key = ToPropertyKey(key);
|
key = ToPropertyKey(key);
|
||||||
|
|
||||||
// Steps 6.d-e.
|
// Steps 6.c-d.
|
||||||
var elements = groups[key];
|
var elements = groups[key];
|
||||||
if (elements === undefined) {
|
if (elements === undefined) {
|
||||||
_DefineDataProperty(groups, key, [value]);
|
_DefineDataProperty(groups, key, [value]);
|
||||||
|
|
@ -257,7 +253,7 @@ function ObjectGroupBy(items, callbackfn) {
|
||||||
callFunction(std_Array_push, elements, value);
|
callFunction(std_Array_push, elements, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 6.f.
|
// Step 6.e.
|
||||||
k++;
|
k++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3673,48 +3673,6 @@ Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ES2024
|
|
||||||
// Promise.withResolvers ( )
|
|
||||||
static bool
|
|
||||||
Promise_static_withResolvers(JSContext* cx, unsigned argc, Value* vp)
|
|
||||||
{
|
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
|
||||||
|
|
||||||
// Step 1.
|
|
||||||
if (!args.thisv().isObject()) {
|
|
||||||
ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, -1, args.thisv(), nullptr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
RootedObject C(cx, &args.thisv().toObject());
|
|
||||||
|
|
||||||
// Step 2.
|
|
||||||
Rooted<PromiseCapability> capability(cx);
|
|
||||||
if (!NewPromiseCapability(cx, C, &capability, false))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Step 3.
|
|
||||||
RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx));
|
|
||||||
if (!obj)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Steps 4-7.
|
|
||||||
RootedValue promise(cx, ObjectValue(*capability.promise()));
|
|
||||||
if (!::JS_DefineProperty(cx, obj, "promise", promise, JSPROP_ENUMERATE))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
RootedValue resolve(cx, ObjectValue(*capability.resolve()));
|
|
||||||
if (!::JS_DefineProperty(cx, obj, "resolve", resolve, JSPROP_ENUMERATE))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
RootedValue reject(cx, ObjectValue(*capability.reject()));
|
|
||||||
if (!::JS_DefineProperty(cx, obj, "reject", reject, JSPROP_ENUMERATE))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Step 8.
|
|
||||||
args.rval().setObject(*obj);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unforgeable version of ES2016, 25.4.4.5, Promise.resolve.
|
* Unforgeable version of ES2016, 25.4.4.5, Promise.resolve.
|
||||||
*/
|
*/
|
||||||
|
|
@ -5222,7 +5180,6 @@ static const JSFunctionSpec promise_static_methods[] = {
|
||||||
JS_FN("race", Promise_static_race, 1, 0),
|
JS_FN("race", Promise_static_race, 1, 0),
|
||||||
JS_FN("reject", Promise_reject, 1, 0),
|
JS_FN("reject", Promise_reject, 1, 0),
|
||||||
JS_FN("resolve", Promise_static_resolve, 1, 0),
|
JS_FN("resolve", Promise_static_resolve, 1, 0),
|
||||||
JS_FN("withResolvers", Promise_static_withResolvers, 0, 0),
|
|
||||||
JS_FS_END
|
JS_FS_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -165,8 +165,6 @@ class CountQueuingStrategy : public NativeObject
|
||||||
static const Class protoClass_;
|
static const Class protoClass_;
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] bool InitStreamExtras(JSContext* cx, HandleObject global);
|
|
||||||
|
|
||||||
} // namespace js
|
} // namespace js
|
||||||
|
|
||||||
#endif /* builtin_Stream_h */
|
#endif /* builtin_Stream_h */
|
||||||
|
|
|
||||||
|
|
@ -654,82 +654,6 @@ function String_repeat(count) {
|
||||||
return T;
|
return T;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ES2024
|
|
||||||
// String.prototype.isWellFormed ( )
|
|
||||||
function String_isWellFormed() {
|
|
||||||
// Steps 1-2.
|
|
||||||
RequireObjectCoercible(this);
|
|
||||||
var S = ToString(this);
|
|
||||||
|
|
||||||
// Step 3.
|
|
||||||
var length = S.length;
|
|
||||||
for (var k = 0; k < length; k++) {
|
|
||||||
var c = callFunction(std_String_charCodeAt, S, k);
|
|
||||||
if (c >= 0xD800 && c <= 0xDBFF) {
|
|
||||||
if (k + 1 >= length)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var d = callFunction(std_String_charCodeAt, S, k + 1);
|
|
||||||
if (d < 0xDC00 || d > 0xDFFF)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
k++;
|
|
||||||
} else if (c >= 0xDC00 && c <= 0xDFFF) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 4.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ES2024
|
|
||||||
// String.prototype.toWellFormed ( )
|
|
||||||
function String_toWellFormed() {
|
|
||||||
// Steps 1-2.
|
|
||||||
RequireObjectCoercible(this);
|
|
||||||
var S = ToString(this);
|
|
||||||
|
|
||||||
// Step 3.
|
|
||||||
var length = S.length;
|
|
||||||
var result = "";
|
|
||||||
var copied = 0;
|
|
||||||
|
|
||||||
for (var k = 0; k < length; k++) {
|
|
||||||
var c = callFunction(std_String_charCodeAt, S, k);
|
|
||||||
var isUnpairedSurrogate = false;
|
|
||||||
|
|
||||||
if (c >= 0xD800 && c <= 0xDBFF) {
|
|
||||||
if (k + 1 < length) {
|
|
||||||
var d = callFunction(std_String_charCodeAt, S, k + 1);
|
|
||||||
if (d >= 0xDC00 && d <= 0xDFFF) {
|
|
||||||
k++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
isUnpairedSurrogate = true;
|
|
||||||
} else if (c >= 0xDC00 && c <= 0xDFFF) {
|
|
||||||
isUnpairedSurrogate = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isUnpairedSurrogate) {
|
|
||||||
if (copied < k)
|
|
||||||
result += callFunction(String_substring, S, copied, k);
|
|
||||||
result += "\uFFFD";
|
|
||||||
copied = k + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copied === 0)
|
|
||||||
return S;
|
|
||||||
|
|
||||||
if (copied < length)
|
|
||||||
result += callFunction(String_substring, S, copied, length);
|
|
||||||
|
|
||||||
// Step 4.
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ES6 draft specification, section 21.1.3.27, version 2013-09-27.
|
// ES6 draft specification, section 21.1.3.27, version 2013-09-27.
|
||||||
function String_iterator() {
|
function String_iterator() {
|
||||||
RequireObjectCoercible(this);
|
RequireObjectCoercible(this);
|
||||||
|
|
|
||||||
|
|
@ -37,25 +37,10 @@ function TypedArrayLengthMethod() {
|
||||||
return TypedArrayLength(this);
|
return TypedArrayLength(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
function TypedArrayContentTypeIsBigIntMethod() {
|
|
||||||
return IsBigInt64TypedArray(this) || IsBigUint64TypedArray(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ThrowIfTypedArrayOutOfBounds(tarray) {
|
|
||||||
if (TypedArrayIsOutOfBounds(tarray))
|
|
||||||
ThrowTypeError(JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ThrowIfPossiblyWrappedTypedArrayOutOfBounds(tarray) {
|
|
||||||
if (PossiblyWrappedTypedArrayIsOutOfBounds(tarray))
|
|
||||||
ThrowTypeError(JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
function GetAttachedArrayBuffer(tarray) {
|
function GetAttachedArrayBuffer(tarray) {
|
||||||
var buffer = ViewedArrayBufferIfReified(tarray);
|
var buffer = ViewedArrayBufferIfReified(tarray);
|
||||||
if (IsDetachedBuffer(buffer))
|
if (IsDetachedBuffer(buffer))
|
||||||
ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
|
ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
|
||||||
ThrowIfTypedArrayOutOfBounds(tarray);
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -75,13 +60,6 @@ function IsTypedArrayEnsuringArrayBuffer(arg) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsObject(arg) && IsPossiblyWrappedTypedArray(arg)) {
|
|
||||||
if (PossiblyWrappedTypedArrayHasDetachedBuffer(arg))
|
|
||||||
ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
|
|
||||||
ThrowIfPossiblyWrappedTypedArrayOutOfBounds(arg);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
callFunction(CallTypedArrayMethodIfWrapped, arg, "GetAttachedArrayBufferMethod");
|
callFunction(CallTypedArrayMethodIfWrapped, arg, "GetAttachedArrayBufferMethod");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -101,7 +79,6 @@ function ValidateTypedArray(obj, error) {
|
||||||
if (IsPossiblyWrappedTypedArray(obj)) {
|
if (IsPossiblyWrappedTypedArray(obj)) {
|
||||||
if (PossiblyWrappedTypedArrayHasDetachedBuffer(obj))
|
if (PossiblyWrappedTypedArrayHasDetachedBuffer(obj))
|
||||||
ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
|
ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
|
||||||
ThrowIfPossiblyWrappedTypedArrayOutOfBounds(obj);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1047,18 +1024,12 @@ function TypedArraySet(overloaded, offset = 0) {
|
||||||
// Steps 9-10.
|
// Steps 9-10.
|
||||||
var targetBuffer = GetAttachedArrayBuffer(target);
|
var targetBuffer = GetAttachedArrayBuffer(target);
|
||||||
|
|
||||||
ThrowIfTypedArrayOutOfBounds(target);
|
|
||||||
|
|
||||||
// Step 11.
|
// Step 11.
|
||||||
var targetLength = TypedArrayLength(target);
|
var targetLength = TypedArrayLength(target);
|
||||||
|
|
||||||
// Steps 12 et seq.
|
// Steps 12 et seq.
|
||||||
if (IsPossiblyWrappedTypedArray(overloaded)) {
|
if (IsPossiblyWrappedTypedArray(overloaded))
|
||||||
if (PossiblyWrappedTypedArrayHasDetachedBuffer(overloaded))
|
|
||||||
ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
|
|
||||||
ThrowIfPossiblyWrappedTypedArrayOutOfBounds(overloaded);
|
|
||||||
return SetFromTypedArray(target, overloaded, targetOffset, targetLength);
|
return SetFromTypedArray(target, overloaded, targetOffset, targetLength);
|
||||||
}
|
|
||||||
|
|
||||||
return SetFromNonTypedArray(target, overloaded, targetOffset, targetLength, targetBuffer);
|
return SetFromNonTypedArray(target, overloaded, targetOffset, targetLength, targetBuffer);
|
||||||
}
|
}
|
||||||
|
|
@ -1395,8 +1366,6 @@ function TypedArraySubarray(begin, end) {
|
||||||
"TypedArraySubarray");
|
"TypedArraySubarray");
|
||||||
}
|
}
|
||||||
|
|
||||||
GetAttachedArrayBuffer(obj);
|
|
||||||
|
|
||||||
// Steps 4-6.
|
// Steps 4-6.
|
||||||
var buffer = TypedArrayBuffer(obj);
|
var buffer = TypedArrayBuffer(obj);
|
||||||
var srcLength = TypedArrayLength(obj);
|
var srcLength = TypedArrayLength(obj);
|
||||||
|
|
@ -1877,10 +1846,7 @@ function ArrayBufferSlice(start, end) {
|
||||||
ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
|
ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
|
||||||
|
|
||||||
// Steps 19-21.
|
// Steps 19-21.
|
||||||
var currentLen = ArrayBufferByteLength(O);
|
ArrayBufferCopyData(new_, 0, O, first | 0, newLen | 0, isWrapped);
|
||||||
var copyLen = first >= currentLen ? 0 : std_Math_min(newLen, currentLen - first);
|
|
||||||
if (copyLen > 0)
|
|
||||||
ArrayBufferCopyData(new_, 0, O, first | 0, copyLen | 0, isWrapped);
|
|
||||||
|
|
||||||
// Step 22.
|
// Step 22.
|
||||||
return new_;
|
return new_;
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@
|
||||||
#include "jsapi.h"
|
#include "jsapi.h"
|
||||||
#include "jscntxt.h"
|
#include "jscntxt.h"
|
||||||
|
|
||||||
#include "builtin/WeakRefObject.h"
|
|
||||||
#include "vm/SelfHosting.h"
|
#include "vm/SelfHosting.h"
|
||||||
|
|
||||||
#include "vm/Interpreter-inl.h"
|
#include "vm/Interpreter-inl.h"
|
||||||
|
|
@ -22,80 +21,21 @@ IsWeakMap(HandleValue v)
|
||||||
return v.isObject() && v.toObject().is<WeakMapObject>();
|
return v.isObject() && v.toObject().is<WeakMapObject>();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WeakMapObject::Data
|
|
||||||
{
|
|
||||||
ObjectValueMap objectMap;
|
|
||||||
SymbolValueMap symbolMap;
|
|
||||||
|
|
||||||
Data(JSContext* cx, JSObject* owner)
|
|
||||||
: objectMap(cx, owner),
|
|
||||||
symbolMap(cx, owner)
|
|
||||||
{}
|
|
||||||
|
|
||||||
bool init() {
|
|
||||||
return objectMap.init() && symbolMap.init();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ObjectValueMap*
|
|
||||||
WeakMapObject::getMap()
|
|
||||||
{
|
|
||||||
Data* data = getData();
|
|
||||||
return data ? &data->objectMap : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
SymbolValueMap*
|
|
||||||
WeakMapObject::getSymbolMap()
|
|
||||||
{
|
|
||||||
Data* data = getData();
|
|
||||||
return data ? &data->symbolMap : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
EnsureWeakMapData(JSContext* cx, Handle<WeakMapObject*> mapObj)
|
|
||||||
{
|
|
||||||
if (mapObj->getData())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
auto data = cx->make_unique<WeakMapObject::Data>(cx, mapObj.get());
|
|
||||||
if (!data)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!data->init()) {
|
|
||||||
JS_ReportOutOfMemory(cx);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mapObj->setPrivate(data.release());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ALWAYS_INLINE bool
|
MOZ_ALWAYS_INLINE bool
|
||||||
WeakMap_has_impl(JSContext* cx, const CallArgs& args)
|
WeakMap_has_impl(JSContext* cx, const CallArgs& args)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(IsWeakMap(args.thisv()));
|
MOZ_ASSERT(IsWeakMap(args.thisv()));
|
||||||
|
|
||||||
if (!CanBeHeldWeakly(args.get(0))) {
|
if (!args.get(0).isObject()) {
|
||||||
args.rval().setBoolean(false);
|
args.rval().setBoolean(false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
WeakMapObject& weakMap = args.thisv().toObject().as<WeakMapObject>();
|
if (ObjectValueMap* map = args.thisv().toObject().as<WeakMapObject>().getMap()) {
|
||||||
if (args.get(0).isObject()) {
|
JSObject* key = &args[0].toObject();
|
||||||
if (ObjectValueMap* map = weakMap.getMap()) {
|
if (map->has(key)) {
|
||||||
JSObject* key = &args[0].toObject();
|
args.rval().setBoolean(true);
|
||||||
if (map->has(key)) {
|
return true;
|
||||||
args.rval().setBoolean(true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (SymbolValueMap* map = weakMap.getSymbolMap()) {
|
|
||||||
JS::Symbol* key = args[0].toSymbol();
|
|
||||||
if (map->has(key)) {
|
|
||||||
args.rval().setBoolean(true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -115,27 +55,16 @@ WeakMap_get_impl(JSContext* cx, const CallArgs& args)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(IsWeakMap(args.thisv()));
|
MOZ_ASSERT(IsWeakMap(args.thisv()));
|
||||||
|
|
||||||
if (!CanBeHeldWeakly(args.get(0))) {
|
if (!args.get(0).isObject()) {
|
||||||
args.rval().setUndefined();
|
args.rval().setUndefined();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
WeakMapObject& weakMap = args.thisv().toObject().as<WeakMapObject>();
|
if (ObjectValueMap* map = args.thisv().toObject().as<WeakMapObject>().getMap()) {
|
||||||
if (args.get(0).isObject()) {
|
JSObject* key = &args[0].toObject();
|
||||||
if (ObjectValueMap* map = weakMap.getMap()) {
|
if (ObjectValueMap::Ptr ptr = map->lookup(key)) {
|
||||||
JSObject* key = &args[0].toObject();
|
args.rval().set(ptr->value());
|
||||||
if (ObjectValueMap::Ptr ptr = map->lookup(key)) {
|
return true;
|
||||||
args.rval().set(ptr->value());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (SymbolValueMap* map = weakMap.getSymbolMap()) {
|
|
||||||
JS::Symbol* key = args[0].toSymbol();
|
|
||||||
if (SymbolValueMap::Ptr ptr = map->lookup(key)) {
|
|
||||||
args.rval().set(ptr->value());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,29 +84,17 @@ WeakMap_delete_impl(JSContext* cx, const CallArgs& args)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(IsWeakMap(args.thisv()));
|
MOZ_ASSERT(IsWeakMap(args.thisv()));
|
||||||
|
|
||||||
if (!CanBeHeldWeakly(args.get(0))) {
|
if (!args.get(0).isObject()) {
|
||||||
args.rval().setBoolean(false);
|
args.rval().setBoolean(false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
WeakMapObject& weakMap = args.thisv().toObject().as<WeakMapObject>();
|
if (ObjectValueMap* map = args.thisv().toObject().as<WeakMapObject>().getMap()) {
|
||||||
if (args.get(0).isObject()) {
|
JSObject* key = &args[0].toObject();
|
||||||
if (ObjectValueMap* map = weakMap.getMap()) {
|
if (ObjectValueMap::Ptr ptr = map->lookup(key)) {
|
||||||
JSObject* key = &args[0].toObject();
|
map->remove(ptr);
|
||||||
if (ObjectValueMap::Ptr ptr = map->lookup(key)) {
|
args.rval().setBoolean(true);
|
||||||
map->remove(ptr);
|
return true;
|
||||||
args.rval().setBoolean(true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (SymbolValueMap* map = weakMap.getSymbolMap()) {
|
|
||||||
JS::Symbol* key = args[0].toSymbol();
|
|
||||||
if (SymbolValueMap::Ptr ptr = map->lookup(key)) {
|
|
||||||
map->remove(ptr);
|
|
||||||
args.rval().setBoolean(true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -209,13 +126,22 @@ TryPreserveReflector(JSContext* cx, HandleObject obj)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static MOZ_ALWAYS_INLINE bool
|
||||||
SetWeakMapObjectEntryInternal(JSContext* cx, Handle<WeakMapObject*> mapObj,
|
SetWeakMapEntryInternal(JSContext* cx, Handle<WeakMapObject*> mapObj,
|
||||||
HandleObject key, HandleValue value)
|
HandleObject key, HandleValue value)
|
||||||
{
|
{
|
||||||
if (!EnsureWeakMapData(cx, mapObj))
|
|
||||||
return false;
|
|
||||||
ObjectValueMap* map = mapObj->getMap();
|
ObjectValueMap* map = mapObj->getMap();
|
||||||
|
if (!map) {
|
||||||
|
auto newMap = cx->make_unique<ObjectValueMap>(cx, mapObj.get());
|
||||||
|
if (!newMap)
|
||||||
|
return false;
|
||||||
|
if (!newMap->init()) {
|
||||||
|
JS_ReportOutOfMemory(cx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
map = newMap.release();
|
||||||
|
mapObj->setPrivate(map);
|
||||||
|
}
|
||||||
|
|
||||||
// Preserve wrapped native keys to prevent wrapper optimization.
|
// Preserve wrapped native keys to prevent wrapper optimization.
|
||||||
if (!TryPreserveReflector(cx, key))
|
if (!TryPreserveReflector(cx, key))
|
||||||
|
|
@ -236,28 +162,13 @@ SetWeakMapObjectEntryInternal(JSContext* cx, Handle<WeakMapObject*> mapObj,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
MOZ_ALWAYS_INLINE bool
|
||||||
SetWeakMapSymbolEntryInternal(JSContext* cx, Handle<WeakMapObject*> mapObj,
|
WeakMap_set_impl(JSContext* cx, const CallArgs& args)
|
||||||
Handle<JS::Symbol*> key, HandleValue value)
|
|
||||||
{
|
{
|
||||||
if (!EnsureWeakMapData(cx, mapObj))
|
MOZ_ASSERT(IsWeakMap(args.thisv()));
|
||||||
return false;
|
|
||||||
SymbolValueMap* map = mapObj->getSymbolMap();
|
|
||||||
|
|
||||||
MOZ_ASSERT_IF(value.isObject(), value.toObject().compartment() == mapObj->compartment());
|
if (!args.get(0).isObject()) {
|
||||||
if (!map->put(key, value)) {
|
UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, args.get(0), nullptr);
|
||||||
JS_ReportOutOfMemory(cx);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static MOZ_ALWAYS_INLINE bool
|
|
||||||
SetWeakMapEntryInternal(JSContext* cx, Handle<WeakMapObject*> mapObj,
|
|
||||||
HandleValue key, HandleValue value)
|
|
||||||
{
|
|
||||||
if (!CanBeHeldWeakly(key)) {
|
|
||||||
UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, key, nullptr);
|
|
||||||
if (!bytes)
|
if (!bytes)
|
||||||
return false;
|
return false;
|
||||||
JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
|
JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
|
||||||
|
|
@ -265,24 +176,11 @@ SetWeakMapEntryInternal(JSContext* cx, Handle<WeakMapObject*> mapObj,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key.isObject()) {
|
RootedObject key(cx, &args[0].toObject());
|
||||||
RootedObject objectKey(cx, &key.toObject());
|
|
||||||
return SetWeakMapObjectEntryInternal(cx, mapObj, objectKey, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
Rooted<JS::Symbol*> symbolKey(cx, key.toSymbol());
|
|
||||||
return SetWeakMapSymbolEntryInternal(cx, mapObj, symbolKey, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ALWAYS_INLINE bool
|
|
||||||
WeakMap_set_impl(JSContext* cx, const CallArgs& args)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(IsWeakMap(args.thisv()));
|
|
||||||
|
|
||||||
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
||||||
Rooted<WeakMapObject*> map(cx, &thisObj->as<WeakMapObject>());
|
Rooted<WeakMapObject*> map(cx, &thisObj->as<WeakMapObject>());
|
||||||
|
|
||||||
if (!SetWeakMapEntryInternal(cx, map, args.get(0), args.get(1)))
|
if (!SetWeakMapEntryInternal(cx, map, key, args.get(1)))
|
||||||
return false;
|
return false;
|
||||||
args.rval().set(args.thisv());
|
args.rval().set(args.thisv());
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -295,13 +193,6 @@ js::WeakMap_set(JSContext* cx, unsigned argc, Value* vp)
|
||||||
return CallNonGenericMethod<IsWeakMap, WeakMap_set_impl>(cx, args);
|
return CallNonGenericMethod<IsWeakMap, WeakMap_set_impl>(cx, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
js::SetWeakMapEntryValue(JSContext* cx, HandleObject mapObj, HandleValue key, HandleValue val)
|
|
||||||
{
|
|
||||||
Rooted<WeakMapObject*> rootedMap(cx, &mapObj->as<WeakMapObject>());
|
|
||||||
return SetWeakMapEntryInternal(cx, rootedMap, key, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_FRIEND_API(bool)
|
JS_FRIEND_API(bool)
|
||||||
JS_NondeterministicGetWeakMapKeys(JSContext* cx, HandleObject objArg, MutableHandleObject ret)
|
JS_NondeterministicGetWeakMapKeys(JSContext* cx, HandleObject objArg, MutableHandleObject ret)
|
||||||
{
|
{
|
||||||
|
|
@ -314,11 +205,11 @@ JS_NondeterministicGetWeakMapKeys(JSContext* cx, HandleObject objArg, MutableHan
|
||||||
RootedObject arr(cx, NewDenseEmptyArray(cx));
|
RootedObject arr(cx, NewDenseEmptyArray(cx));
|
||||||
if (!arr)
|
if (!arr)
|
||||||
return false;
|
return false;
|
||||||
WeakMapObject::Data* data = obj->as<WeakMapObject>().getData();
|
ObjectValueMap* map = obj->as<WeakMapObject>().getMap();
|
||||||
if (data) {
|
if (map) {
|
||||||
// Prevent GC from mutating the weakmap while iterating.
|
// Prevent GC from mutating the weakmap while iterating.
|
||||||
AutoSuppressGC suppress(cx);
|
AutoSuppressGC suppress(cx);
|
||||||
for (ObjectValueMap::Base::Range r = data->objectMap.all(); !r.empty(); r.popFront()) {
|
for (ObjectValueMap::Base::Range r = map->all(); !r.empty(); r.popFront()) {
|
||||||
JS::ExposeObjectToActiveJS(r.front().key());
|
JS::ExposeObjectToActiveJS(r.front().key());
|
||||||
RootedObject key(cx, r.front().key());
|
RootedObject key(cx, r.front().key());
|
||||||
if (!cx->compartment()->wrap(cx, &key))
|
if (!cx->compartment()->wrap(cx, &key))
|
||||||
|
|
@ -326,14 +217,6 @@ JS_NondeterministicGetWeakMapKeys(JSContext* cx, HandleObject objArg, MutableHan
|
||||||
if (!NewbornArrayPush(cx, arr, ObjectValue(*key)))
|
if (!NewbornArrayPush(cx, arr, ObjectValue(*key)))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (SymbolValueMap::Base::Range r = data->symbolMap.all(); !r.empty(); r.popFront()) {
|
|
||||||
gc::ExposeGCThingToActiveJS(JS::GCCellPtr(r.front().key().get()));
|
|
||||||
RootedValue key(cx, SymbolValue(r.front().key()));
|
|
||||||
if (!cx->compartment()->wrap(cx, &key))
|
|
||||||
return false;
|
|
||||||
if (!NewbornArrayPush(cx, arr, key))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ret.set(arr);
|
ret.set(arr);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -342,23 +225,21 @@ JS_NondeterministicGetWeakMapKeys(JSContext* cx, HandleObject objArg, MutableHan
|
||||||
static void
|
static void
|
||||||
WeakMap_mark(JSTracer* trc, JSObject* obj)
|
WeakMap_mark(JSTracer* trc, JSObject* obj)
|
||||||
{
|
{
|
||||||
if (WeakMapObject::Data* data = obj->as<WeakMapObject>().getData()) {
|
if (ObjectValueMap* map = obj->as<WeakMapObject>().getMap())
|
||||||
data->objectMap.trace(trc);
|
map->trace(trc);
|
||||||
data->symbolMap.trace(trc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
WeakMap_finalize(FreeOp* fop, JSObject* obj)
|
WeakMap_finalize(FreeOp* fop, JSObject* obj)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(fop->maybeOffMainThread());
|
MOZ_ASSERT(fop->maybeOffMainThread());
|
||||||
if (WeakMapObject::Data* data = obj->as<WeakMapObject>().getData()) {
|
if (ObjectValueMap* map = obj->as<WeakMapObject>().getMap()) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
data->~Data();
|
map->~ObjectValueMap();
|
||||||
memset(static_cast<void*>(data), 0xdc, sizeof(*data));
|
memset(static_cast<void*>(map), 0xdc, sizeof(*map));
|
||||||
fop->free_(data);
|
fop->free_(map);
|
||||||
#else
|
#else
|
||||||
fop->delete_(data);
|
fop->delete_(map);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -401,8 +282,7 @@ JS::SetWeakMapEntry(JSContext* cx, HandleObject mapObj, HandleObject key,
|
||||||
CHECK_REQUEST(cx);
|
CHECK_REQUEST(cx);
|
||||||
assertSameCompartment(cx, key, val);
|
assertSameCompartment(cx, key, val);
|
||||||
Rooted<WeakMapObject*> rootedMap(cx, &mapObj->as<WeakMapObject>());
|
Rooted<WeakMapObject*> rootedMap(cx, &mapObj->as<WeakMapObject>());
|
||||||
RootedValue keyValue(cx, ObjectValue(*key));
|
return SetWeakMapEntryInternal(cx, rootedMap, key, val);
|
||||||
return SetWeakMapEntryInternal(cx, rootedMap, keyValue, val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
|
@ -506,3 +386,4 @@ js::InitBareWeakMapCtor(JSContext* cx, HandleObject obj)
|
||||||
{
|
{
|
||||||
return InitWeakMapClass(cx, obj, false);
|
return InitWeakMapClass(cx, obj, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,7 @@ class WeakMapObject : public NativeObject
|
||||||
public:
|
public:
|
||||||
static const Class class_;
|
static const Class class_;
|
||||||
|
|
||||||
struct Data;
|
ObjectValueMap* getMap() { return static_cast<ObjectValueMap*>(getPrivate()); }
|
||||||
|
|
||||||
Data* getData() { return static_cast<Data*>(getPrivate()); }
|
|
||||||
ObjectValueMap* getMap();
|
|
||||||
SymbolValueMap* getSymbolMap();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace js
|
} // namespace js
|
||||||
|
|
|
||||||
|
|
@ -1,208 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
||||||
* 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 "builtin/WeakRefObject.h"
|
|
||||||
|
|
||||||
#include "jsapi.h"
|
|
||||||
#include "jscntxt.h"
|
|
||||||
|
|
||||||
#include "gc/Nursery.h"
|
|
||||||
#include "gc/Tracer.h"
|
|
||||||
#include "vm/GlobalObject.h"
|
|
||||||
|
|
||||||
#include "jsobjinlines.h"
|
|
||||||
|
|
||||||
#include "vm/Interpreter-inl.h"
|
|
||||||
#include "vm/NativeObject-inl.h"
|
|
||||||
|
|
||||||
using namespace js;
|
|
||||||
|
|
||||||
static WeakRefObject::Referent*
|
|
||||||
GetReferent(JSObject* obj)
|
|
||||||
{
|
|
||||||
return obj->as<WeakRefObject>().getData();
|
|
||||||
}
|
|
||||||
|
|
||||||
static MOZ_ALWAYS_INLINE bool
|
|
||||||
IsWeakRef(HandleValue v)
|
|
||||||
{
|
|
||||||
return v.isObject() && v.toObject().is<WeakRefObject>();
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
WeakRef_deref_impl(JSContext* cx, const CallArgs& args)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(IsWeakRef(args.thisv()));
|
|
||||||
|
|
||||||
WeakRefObject::Referent* data = GetReferent(&args.thisv().toObject());
|
|
||||||
JSObject* target = data ? data->target.get() : nullptr;
|
|
||||||
if (target)
|
|
||||||
args.rval().setObject(*target);
|
|
||||||
else
|
|
||||||
args.rval().setUndefined();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const JSPropertySpec WeakRefObject::properties[] = {
|
|
||||||
JS_PS_END
|
|
||||||
};
|
|
||||||
|
|
||||||
const JSFunctionSpec WeakRefObject::methods[] = {
|
|
||||||
JS_FN("deref", WeakRefObject::deref, 0, 0),
|
|
||||||
JS_FS_END
|
|
||||||
};
|
|
||||||
|
|
||||||
static JSObject*
|
|
||||||
InitWeakRefClass(JSContext* cx, HandleObject obj, bool defineMembers)
|
|
||||||
{
|
|
||||||
Handle<GlobalObject*> global = obj.as<GlobalObject>();
|
|
||||||
RootedPlainObject proto(cx, NewBuiltinClassInstance<PlainObject>(cx));
|
|
||||||
if (!proto)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
RootedFunction ctor(cx, GlobalObject::createConstructor(cx, WeakRefObject::construct,
|
|
||||||
ClassName(JSProto_WeakRef, cx), 1));
|
|
||||||
if (!ctor)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
if (!LinkConstructorAndPrototype(cx, ctor, proto))
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
if (defineMembers) {
|
|
||||||
if (!DefinePropertiesAndFunctions(cx, proto, WeakRefObject::properties, WeakRefObject::methods))
|
|
||||||
return nullptr;
|
|
||||||
if (!DefineToStringTag(cx, proto, cx->names().WeakRef))
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_WeakRef, ctor, proto))
|
|
||||||
return nullptr;
|
|
||||||
return proto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */ WeakRefObject*
|
|
||||||
WeakRefObject::create(JSContext* cx, HandleObject target, HandleObject proto /* = nullptr */)
|
|
||||||
{
|
|
||||||
Rooted<WeakRefObject*> obj(cx, NewObjectWithClassProto<WeakRefObject>(cx, proto));
|
|
||||||
if (!obj)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
Referent* data = cx->new_<Referent>(target, cx->options().weakRefs());
|
|
||||||
if (!data)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
obj->setPrivate(data);
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */ bool
|
|
||||||
WeakRefObject::construct(JSContext* cx, unsigned argc, Value* vp)
|
|
||||||
{
|
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
|
||||||
|
|
||||||
if (!ThrowIfNotConstructing(cx, args, "WeakRef"))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!args.get(0).isObject()) {
|
|
||||||
UniqueChars bytes =
|
|
||||||
DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, args.get(0), nullptr);
|
|
||||||
if (!bytes)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
|
|
||||||
bytes.get());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
RootedObject target(cx, &args[0].toObject());
|
|
||||||
|
|
||||||
RootedObject proto(cx);
|
|
||||||
RootedObject newTarget(cx, &args.newTarget().toObject());
|
|
||||||
if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Rooted<WeakRefObject*> obj(cx, WeakRefObject::create(cx, target, proto));
|
|
||||||
if (!obj)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
args.rval().setObject(*obj);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */ bool
|
|
||||||
WeakRefObject::deref(JSContext* cx, unsigned argc, Value* vp)
|
|
||||||
{
|
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
|
||||||
return CallNonGenericMethod<IsWeakRef, WeakRef_deref_impl>(cx, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */ void
|
|
||||||
WeakRefObject::trace(JSTracer* trc, JSObject* obj)
|
|
||||||
{
|
|
||||||
if (Referent* data = GetReferent(obj)) {
|
|
||||||
JSObject* target = data->target.unbarrieredGet();
|
|
||||||
if (!target)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// When pref-disabled, keep referent alive via strong trace so deref()
|
|
||||||
// stays usable as a stub without touching GC internals.
|
|
||||||
if (!data->enabled) {
|
|
||||||
TraceManuallyBarrieredEdge(trc, data->target.unsafeGet(), "WeakRef stub referent");
|
|
||||||
} else if (IsInsideNursery(target)) {
|
|
||||||
// Weak edges must be tenured; trace strongly while referent is in the nursery.
|
|
||||||
TraceManuallyBarrieredEdge(trc, data->target.unsafeGet(), "WeakRef nursery referent");
|
|
||||||
} else {
|
|
||||||
TraceWeakEdge(trc, &data->target, "WeakRef referent");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */ void
|
|
||||||
WeakRefObject::finalize(FreeOp* fop, JSObject* obj)
|
|
||||||
{
|
|
||||||
if (Referent* data = GetReferent(obj))
|
|
||||||
fop->delete_(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const ClassOps WeakRefObjectClassOps = {
|
|
||||||
nullptr, /* addProperty */
|
|
||||||
nullptr, /* delProperty */
|
|
||||||
nullptr, /* getProperty */
|
|
||||||
nullptr, /* setProperty */
|
|
||||||
nullptr, /* enumerate */
|
|
||||||
nullptr, /* resolve */
|
|
||||||
nullptr, /* mayResolve */
|
|
||||||
WeakRefObject::finalize,
|
|
||||||
nullptr, /* call */
|
|
||||||
nullptr, /* hasInstance */
|
|
||||||
nullptr, /* construct */
|
|
||||||
WeakRefObject::trace
|
|
||||||
};
|
|
||||||
|
|
||||||
const Class WeakRefObject::class_ = {
|
|
||||||
"WeakRef",
|
|
||||||
JSCLASS_HAS_PRIVATE |
|
|
||||||
JSCLASS_HAS_CACHED_PROTO(JSProto_WeakRef) |
|
|
||||||
JSCLASS_BACKGROUND_FINALIZE,
|
|
||||||
&WeakRefObjectClassOps
|
|
||||||
};
|
|
||||||
|
|
||||||
/* static */ JSObject*
|
|
||||||
WeakRefObject::initClass(JSContext* cx, HandleObject obj)
|
|
||||||
{
|
|
||||||
return ::InitWeakRefClass(cx, obj, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObject*
|
|
||||||
js::InitWeakRefClass(JSContext* cx, HandleObject obj)
|
|
||||||
{
|
|
||||||
return WeakRefObject::initClass(cx, obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObject*
|
|
||||||
js::InitBareWeakRefCtor(JSContext* cx, HandleObject obj)
|
|
||||||
{
|
|
||||||
return ::InitWeakRefClass(cx, obj, false);
|
|
||||||
}
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
||||||
* 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 builtin_WeakRefObject_h
|
|
||||||
#define builtin_WeakRefObject_h
|
|
||||||
|
|
||||||
#include "gc/Barrier.h"
|
|
||||||
#include "vm/NativeObject.h"
|
|
||||||
|
|
||||||
namespace js {
|
|
||||||
|
|
||||||
class WeakRefObject : public NativeObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
struct Referent {
|
|
||||||
explicit Referent(JSObject* obj, bool enabled)
|
|
||||||
: target(obj), enabled(enabled) {}
|
|
||||||
WeakRef<JSObject*> target;
|
|
||||||
bool enabled;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const Class class_;
|
|
||||||
|
|
||||||
static JSObject* initClass(JSContext* cx, HandleObject obj);
|
|
||||||
static WeakRefObject* create(JSContext* cx, HandleObject target, HandleObject proto = nullptr);
|
|
||||||
|
|
||||||
static void trace(JSTracer* trc, JSObject* obj);
|
|
||||||
static void finalize(FreeOp* fop, JSObject* obj);
|
|
||||||
[[nodiscard]] static bool construct(JSContext* cx, unsigned argc, Value* vp);
|
|
||||||
static bool deref(JSContext* cx, unsigned argc, Value* vp);
|
|
||||||
|
|
||||||
Referent* getData() const {
|
|
||||||
return static_cast<Referent*>(getPrivate());
|
|
||||||
}
|
|
||||||
|
|
||||||
WeakRef<JSObject*>& target() {
|
|
||||||
MOZ_ASSERT(getData());
|
|
||||||
return getData()->target;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const JSPropertySpec properties[];
|
|
||||||
static const JSFunctionSpec methods[];
|
|
||||||
|
|
||||||
private:
|
|
||||||
};
|
|
||||||
|
|
||||||
extern JSObject*
|
|
||||||
InitWeakRefClass(JSContext* cx, HandleObject obj);
|
|
||||||
|
|
||||||
extern JSObject*
|
|
||||||
InitBareWeakRefCtor(JSContext* cx, HandleObject obj);
|
|
||||||
|
|
||||||
static inline bool
|
|
||||||
CanBeHeldWeakly(const Value& value)
|
|
||||||
{
|
|
||||||
return value.isObject() || value.isSymbol();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace js
|
|
||||||
|
|
||||||
#endif /* builtin_WeakRefObject_h */
|
|
||||||
|
|
@ -32,7 +32,7 @@ function WeakSet_add(value) {
|
||||||
ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "WeakSet", "add", typeof S);
|
ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "WeakSet", "add", typeof S);
|
||||||
|
|
||||||
// Step 5.
|
// Step 5.
|
||||||
if (!CanBeHeldWeakly(value))
|
if (!IsObject(value))
|
||||||
ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, DecompileArg(0, value));
|
ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, DecompileArg(0, value));
|
||||||
|
|
||||||
// Steps 7-8.
|
// Steps 7-8.
|
||||||
|
|
@ -55,7 +55,7 @@ function WeakSet_delete(value) {
|
||||||
ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "WeakSet", "delete", typeof S);
|
ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "WeakSet", "delete", typeof S);
|
||||||
|
|
||||||
// Step 5.
|
// Step 5.
|
||||||
if (!CanBeHeldWeakly(value))
|
if (!IsObject(value))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Steps 7-8.
|
// Steps 7-8.
|
||||||
|
|
@ -75,7 +75,7 @@ function WeakSet_has(value) {
|
||||||
ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "WeakSet", "has", typeof S);
|
ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "WeakSet", "has", typeof S);
|
||||||
|
|
||||||
// Step 6.
|
// Step 6.
|
||||||
if (!CanBeHeldWeakly(value))
|
if (!IsObject(value))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Steps 7-8.
|
// Steps 7-8.
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@
|
||||||
#include "builtin/MapObject.h"
|
#include "builtin/MapObject.h"
|
||||||
#include "builtin/SelfHostingDefines.h"
|
#include "builtin/SelfHostingDefines.h"
|
||||||
#include "builtin/WeakMapObject.h"
|
#include "builtin/WeakMapObject.h"
|
||||||
#include "builtin/WeakRefObject.h"
|
|
||||||
#include "vm/GlobalObject.h"
|
#include "vm/GlobalObject.h"
|
||||||
#include "vm/SelfHosting.h"
|
#include "vm/SelfHosting.h"
|
||||||
|
|
||||||
|
|
@ -109,6 +108,7 @@ WeakSetObject::construct(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
|
||||||
if (optimized) {
|
if (optimized) {
|
||||||
RootedValue keyVal(cx);
|
RootedValue keyVal(cx);
|
||||||
|
RootedObject keyObject(cx);
|
||||||
RootedValue placeholder(cx, BooleanValue(true));
|
RootedValue placeholder(cx, BooleanValue(true));
|
||||||
RootedObject map(cx, &obj->getReservedSlot(WEAKSET_MAP_SLOT).toObject());
|
RootedObject map(cx, &obj->getReservedSlot(WEAKSET_MAP_SLOT).toObject());
|
||||||
RootedArrayObject array(cx, &iterable.toObject().as<ArrayObject>());
|
RootedArrayObject array(cx, &iterable.toObject().as<ArrayObject>());
|
||||||
|
|
@ -116,7 +116,7 @@ WeakSetObject::construct(JSContext* cx, unsigned argc, Value* vp)
|
||||||
keyVal.set(array->getDenseElement(index));
|
keyVal.set(array->getDenseElement(index));
|
||||||
MOZ_ASSERT(!keyVal.isMagic(JS_ELEMENTS_HOLE));
|
MOZ_ASSERT(!keyVal.isMagic(JS_ELEMENTS_HOLE));
|
||||||
|
|
||||||
if (!CanBeHeldWeakly(keyVal)) {
|
if (keyVal.isPrimitive()) {
|
||||||
UniqueChars bytes =
|
UniqueChars bytes =
|
||||||
DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, keyVal, nullptr);
|
DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, keyVal, nullptr);
|
||||||
if (!bytes)
|
if (!bytes)
|
||||||
|
|
@ -126,7 +126,8 @@ WeakSetObject::construct(JSContext* cx, unsigned argc, Value* vp)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SetWeakMapEntryValue(cx, map, keyVal, placeholder))
|
keyObject = &keyVal.toObject();
|
||||||
|
if (!SetWeakMapEntry(cx, map, keyObject, placeholder))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1470,12 +1470,6 @@ TryAttachGetElemStub(JSContext* cx, JSScript* script, jsbytecode* pc, ICGetElem_
|
||||||
res.isNumber() &&
|
res.isNumber() &&
|
||||||
!TypedArrayGetElemStubExists(stub, obj))
|
!TypedArrayGetElemStubExists(stub, obj))
|
||||||
{
|
{
|
||||||
if (obj->is<TypedArrayObject>() &&
|
|
||||||
obj->as<TypedArrayObject>().hasResizableOrGrowableBuffer())
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cx->runtime()->jitSupportsFloatingPoint &&
|
if (!cx->runtime()->jitSupportsFloatingPoint &&
|
||||||
(TypedThingRequiresFloatingPoint(obj) || rhs.isDouble()))
|
(TypedThingRequiresFloatingPoint(obj) || rhs.isDouble()))
|
||||||
{
|
{
|
||||||
|
|
@ -2166,8 +2160,6 @@ ICGetElem_TypedArray::Compiler::generateStubCode(MacroAssembler& masm)
|
||||||
Register obj = masm.extractObject(R0, ExtractTemp0);
|
Register obj = masm.extractObject(R0, ExtractTemp0);
|
||||||
masm.loadPtr(Address(ICStubReg, ICGetElem_TypedArray::offsetOfShape()), scratchReg);
|
masm.loadPtr(Address(ICStubReg, ICGetElem_TypedArray::offsetOfShape()), scratchReg);
|
||||||
masm.branchTestObjShape(Assembler::NotEqual, obj, scratchReg, &failure);
|
masm.branchTestObjShape(Assembler::NotEqual, obj, scratchReg, &failure);
|
||||||
if (layout_ == Layout_TypedArray)
|
|
||||||
GuardResizableOrGrowableTypedArray(masm, obj, scratchReg, &failure);
|
|
||||||
|
|
||||||
// Ensure the index is an integer.
|
// Ensure the index is an integer.
|
||||||
if (cx->runtime()->jitSupportsFloatingPoint) {
|
if (cx->runtime()->jitSupportsFloatingPoint) {
|
||||||
|
|
@ -2639,9 +2631,6 @@ DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub_
|
||||||
bool expectOutOfBounds;
|
bool expectOutOfBounds;
|
||||||
double idx = index.toNumber();
|
double idx = index.toNumber();
|
||||||
if (obj->is<TypedArrayObject>()) {
|
if (obj->is<TypedArrayObject>()) {
|
||||||
if (obj->as<TypedArrayObject>().hasResizableOrGrowableBuffer())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
expectOutOfBounds = (idx < 0 || idx >= double(obj->as<TypedArrayObject>().length()));
|
expectOutOfBounds = (idx < 0 || idx >= double(obj->as<TypedArrayObject>().length()));
|
||||||
} else {
|
} else {
|
||||||
// Typed objects throw on out of bounds accesses. Don't attach
|
// Typed objects throw on out of bounds accesses. Don't attach
|
||||||
|
|
@ -3232,8 +3221,6 @@ ICSetElem_TypedArray::Compiler::generateStubCode(MacroAssembler& masm)
|
||||||
Register obj = masm.extractObject(R0, ExtractTemp0);
|
Register obj = masm.extractObject(R0, ExtractTemp0);
|
||||||
masm.loadPtr(Address(ICStubReg, ICSetElem_TypedArray::offsetOfShape()), scratchReg);
|
masm.loadPtr(Address(ICStubReg, ICSetElem_TypedArray::offsetOfShape()), scratchReg);
|
||||||
masm.branchTestObjShape(Assembler::NotEqual, obj, scratchReg, &failure);
|
masm.branchTestObjShape(Assembler::NotEqual, obj, scratchReg, &failure);
|
||||||
if (layout_ == Layout_TypedArray)
|
|
||||||
GuardResizableOrGrowableTypedArray(masm, obj, scratchReg, &failure);
|
|
||||||
|
|
||||||
// Ensure the index is an integer.
|
// Ensure the index is an integer.
|
||||||
if (cx->runtime()->jitSupportsFloatingPoint) {
|
if (cx->runtime()->jitSupportsFloatingPoint) {
|
||||||
|
|
|
||||||
|
|
@ -8889,17 +8889,9 @@ CodeGenerator::branchIfNotEmptyObjectElements(Register obj, Label* target)
|
||||||
Address(obj, NativeObject::offsetOfElements()),
|
Address(obj, NativeObject::offsetOfElements()),
|
||||||
ImmPtr(js::emptyObjectElements),
|
ImmPtr(js::emptyObjectElements),
|
||||||
&emptyObj);
|
&emptyObj);
|
||||||
masm.branchPtr(Assembler::Equal,
|
|
||||||
Address(obj, NativeObject::offsetOfElements()),
|
|
||||||
ImmPtr(js::emptyObjectElementsShared),
|
|
||||||
&emptyObj);
|
|
||||||
masm.branchPtr(Assembler::Equal,
|
|
||||||
Address(obj, NativeObject::offsetOfElements()),
|
|
||||||
ImmPtr(js::emptyObjectElementsResizableOrGrowable),
|
|
||||||
&emptyObj);
|
|
||||||
masm.branchPtr(Assembler::NotEqual,
|
masm.branchPtr(Assembler::NotEqual,
|
||||||
Address(obj, NativeObject::offsetOfElements()),
|
Address(obj, NativeObject::offsetOfElements()),
|
||||||
ImmPtr(js::emptyObjectElementsSharedResizableOrGrowable),
|
ImmPtr(js::emptyObjectElementsShared),
|
||||||
target);
|
target);
|
||||||
masm.bind(&emptyObj);
|
masm.bind(&emptyObj);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -537,7 +537,8 @@ class CodeGenerator final : public CodeGeneratorSpecific
|
||||||
Label* ifDoesntEmulateUndefined,
|
Label* ifDoesntEmulateUndefined,
|
||||||
Register scratch, OutOfLineTestObject* ool);
|
Register scratch, OutOfLineTestObject* ool);
|
||||||
|
|
||||||
// Branch to target unless obj has one of the empty elements pointers.
|
// Branch to target unless obj has an emptyObjectElements or emptyObjectElementsShared
|
||||||
|
// elements pointer.
|
||||||
void branchIfNotEmptyObjectElements(Register obj, Label* target);
|
void branchIfNotEmptyObjectElements(Register obj, Label* target);
|
||||||
|
|
||||||
void emitStoreElementTyped(const LAllocation* value, MIRType valueType, MIRType elementType,
|
void emitStoreElementTyped(const LAllocation* value, MIRType valueType, MIRType elementType,
|
||||||
|
|
|
||||||
|
|
@ -1245,7 +1245,6 @@ GenerateTypedArrayLength(JSContext* cx, MacroAssembler& masm, IonCache::StubAtta
|
||||||
masm.branchPtr(Assembler::AboveOrEqual, tmpReg,
|
masm.branchPtr(Assembler::AboveOrEqual, tmpReg,
|
||||||
ImmPtr(&TypedArrayObject::classes[Scalar::MaxTypedArrayViewType]),
|
ImmPtr(&TypedArrayObject::classes[Scalar::MaxTypedArrayViewType]),
|
||||||
failures);
|
failures);
|
||||||
GuardResizableOrGrowableTypedArray(masm, object, tmpReg, failures);
|
|
||||||
|
|
||||||
// Load length.
|
// Load length.
|
||||||
masm.loadTypedOrValue(Address(object, TypedArrayObject::lengthOffset()), output);
|
masm.loadTypedOrValue(Address(object, TypedArrayObject::lengthOffset()), output);
|
||||||
|
|
@ -1645,9 +1644,6 @@ GetPropertyIC::tryAttachTypedArrayLength(JSContext* cx, HandleScript outerScript
|
||||||
if (!JSID_IS_ATOM(id, cx->names().length))
|
if (!JSID_IS_ATOM(id, cx->names().length))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (obj->as<TypedArrayObject>().hasResizableOrGrowableBuffer())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (hasTypedArrayLengthStub(obj))
|
if (hasTypedArrayLengthStub(obj))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|
@ -4042,12 +4038,6 @@ GetPropertyIC::canAttachTypedOrUnboxedArrayElement(JSObject* obj, const Value& i
|
||||||
if (!obj->is<TypedArrayObject>() && !obj->is<UnboxedArrayObject>())
|
if (!obj->is<TypedArrayObject>() && !obj->is<UnboxedArrayObject>())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (obj->is<TypedArrayObject>() &&
|
|
||||||
obj->as<TypedArrayObject>().hasResizableOrGrowableBuffer())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(idval.isInt32() || idval.isString());
|
MOZ_ASSERT(idval.isInt32() || idval.isString());
|
||||||
|
|
||||||
// Don't emit a stub if the access is out of bounds. We make to make
|
// Don't emit a stub if the access is out of bounds. We make to make
|
||||||
|
|
@ -4102,9 +4092,6 @@ GenerateGetTypedOrUnboxedArrayElement(JSContext* cx, MacroAssembler& masm,
|
||||||
// Decide to what type index the stub should be optimized
|
// Decide to what type index the stub should be optimized
|
||||||
Register tmpReg = output.scratchReg().gpr();
|
Register tmpReg = output.scratchReg().gpr();
|
||||||
MOZ_ASSERT(tmpReg != InvalidReg);
|
MOZ_ASSERT(tmpReg != InvalidReg);
|
||||||
if (array->is<TypedArrayObject>())
|
|
||||||
GuardResizableOrGrowableTypedArray(masm, object, tmpReg, &failures);
|
|
||||||
|
|
||||||
Register indexReg = tmpReg;
|
Register indexReg = tmpReg;
|
||||||
if (idval.isString()) {
|
if (idval.isString()) {
|
||||||
MOZ_ASSERT(GetIndexFromString(idval.toString()) != UINT32_MAX);
|
MOZ_ASSERT(GetIndexFromString(idval.toString()) != UINT32_MAX);
|
||||||
|
|
@ -4588,7 +4575,6 @@ GenerateSetTypedArrayElement(JSContext* cx, MacroAssembler& masm, IonCache::Stub
|
||||||
if (!shape)
|
if (!shape)
|
||||||
return false;
|
return false;
|
||||||
masm.branchTestObjShape(Assembler::NotEqual, object, shape, &failures);
|
masm.branchTestObjShape(Assembler::NotEqual, object, shape, &failures);
|
||||||
GuardResizableOrGrowableTypedArray(masm, object, temp, &failures);
|
|
||||||
|
|
||||||
// Ensure the index is an int32.
|
// Ensure the index is an int32.
|
||||||
Register indexReg;
|
Register indexReg;
|
||||||
|
|
@ -4675,9 +4661,6 @@ SetPropertyIC::tryAttachTypedArrayElement(JSContext* cx, HandleScript outerScrip
|
||||||
if (!IsTypedArrayElementSetInlineable(obj, idval, val))
|
if (!IsTypedArrayElementSetInlineable(obj, idval, val))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (obj->as<TypedArrayObject>().hasResizableOrGrowableBuffer())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
*emitted = true;
|
*emitted = true;
|
||||||
|
|
||||||
MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
|
MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
|
||||||
|
|
|
||||||
|
|
@ -365,9 +365,13 @@ IonBuilder::inlineNativeGetter(CallInfo& callInfo, JSFunction* target)
|
||||||
|
|
||||||
// Try to optimize typed array lengths.
|
// Try to optimize typed array lengths.
|
||||||
if (TypedArrayObject::isOriginalLengthGetter(native)) {
|
if (TypedArrayObject::isOriginalLengthGetter(native)) {
|
||||||
// RAB/GSAB views can have dynamic length or temporarily become
|
Scalar::Type type = thisTypes->getTypedArrayType(constraints());
|
||||||
// out-of-bounds. Let the property IC/VM path handle the getter.
|
if (type == Scalar::MaxTypedArrayViewType)
|
||||||
return InliningStatus_NotInlined;
|
return InliningStatus_NotInlined;
|
||||||
|
|
||||||
|
MInstruction* length = addTypedArrayLength(thisArg);
|
||||||
|
current->push(length);
|
||||||
|
return InliningStatus_Inlined;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to optimize RegExp getters.
|
// Try to optimize RegExp getters.
|
||||||
|
|
@ -2476,10 +2480,21 @@ IsTypedArrayObject(CompilerConstraintList* constraints, MDefinition* def)
|
||||||
IonBuilder::InliningStatus
|
IonBuilder::InliningStatus
|
||||||
IonBuilder::inlinePossiblyWrappedTypedArrayLength(CallInfo& callInfo)
|
IonBuilder::inlinePossiblyWrappedTypedArrayLength(CallInfo& callInfo)
|
||||||
{
|
{
|
||||||
(void) callInfo;
|
MOZ_ASSERT(!callInfo.constructing());
|
||||||
|
MOZ_ASSERT(callInfo.argc() == 1);
|
||||||
|
if (callInfo.getArg(0)->type() != MIRType::Object)
|
||||||
|
return InliningStatus_NotInlined;
|
||||||
|
if (getInlineReturnType() != MIRType::Int32)
|
||||||
|
return InliningStatus_NotInlined;
|
||||||
|
|
||||||
// RAB/GSAB views require dynamic length semantics.
|
if (!IsTypedArrayObject(constraints(), callInfo.getArg(0)))
|
||||||
return InliningStatus_NotInlined;
|
return InliningStatus_NotInlined;
|
||||||
|
|
||||||
|
MInstruction* length = addTypedArrayLength(callInfo.getArg(0));
|
||||||
|
current->push(length);
|
||||||
|
|
||||||
|
callInfo.setImplicitlyUsedUnchecked();
|
||||||
|
return InliningStatus_Inlined;
|
||||||
}
|
}
|
||||||
|
|
||||||
IonBuilder::InliningStatus
|
IonBuilder::InliningStatus
|
||||||
|
|
@ -3236,14 +3251,45 @@ bool
|
||||||
IonBuilder::atomicsMeetsPreconditions(CallInfo& callInfo, Scalar::Type* arrayType,
|
IonBuilder::atomicsMeetsPreconditions(CallInfo& callInfo, Scalar::Type* arrayType,
|
||||||
bool* requiresTagCheck, AtomicCheckResult checkResult)
|
bool* requiresTagCheck, AtomicCheckResult checkResult)
|
||||||
{
|
{
|
||||||
(void) callInfo;
|
if (!JitSupportsAtomics())
|
||||||
(void) arrayType;
|
return false;
|
||||||
(void) requiresTagCheck;
|
|
||||||
(void) checkResult;
|
|
||||||
|
|
||||||
// Atomics bounds checks through addTypedArrayLengthAndData assume stable
|
if (callInfo.getArg(0)->type() != MIRType::Object)
|
||||||
// SharedArrayBuffer lengths. Avoid this path now that growable SAB exists.
|
return false;
|
||||||
return false;
|
|
||||||
|
if (callInfo.getArg(1)->type() != MIRType::Int32)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Ensure that the first argument is a TypedArray that maps shared
|
||||||
|
// memory.
|
||||||
|
//
|
||||||
|
// Then check both that the element type is something we can
|
||||||
|
// optimize and that the return type is suitable for that element
|
||||||
|
// type.
|
||||||
|
|
||||||
|
TemporaryTypeSet* arg0Types = callInfo.getArg(0)->resultTypeSet();
|
||||||
|
if (!arg0Types)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
TemporaryTypeSet::TypedArraySharedness sharedness;
|
||||||
|
*arrayType = arg0Types->getTypedArrayType(constraints(), &sharedness);
|
||||||
|
*requiresTagCheck = sharedness != TemporaryTypeSet::KnownShared;
|
||||||
|
switch (*arrayType) {
|
||||||
|
case Scalar::Int8:
|
||||||
|
case Scalar::Uint8:
|
||||||
|
case Scalar::Int16:
|
||||||
|
case Scalar::Uint16:
|
||||||
|
case Scalar::Int32:
|
||||||
|
return checkResult == DontCheckAtomicResult || getInlineReturnType() == MIRType::Int32;
|
||||||
|
case Scalar::Uint32:
|
||||||
|
// Bug 1077305: it would be attractive to allow inlining even
|
||||||
|
// if the inline return type is Int32, which it will frequently
|
||||||
|
// be.
|
||||||
|
return checkResult == DontCheckAtomicResult || getInlineReturnType() == MIRType::Double;
|
||||||
|
default:
|
||||||
|
// Excludes floating types and Uint8Clamped.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -5505,15 +5505,25 @@ jit::ElementAccessIsTypedArray(CompilerConstraintList* constraints,
|
||||||
MDefinition* obj, MDefinition* id,
|
MDefinition* obj, MDefinition* id,
|
||||||
Scalar::Type* arrayType)
|
Scalar::Type* arrayType)
|
||||||
{
|
{
|
||||||
(void) constraints;
|
if (obj->mightBeType(MIRType::String))
|
||||||
(void) obj;
|
return false;
|
||||||
(void) id;
|
|
||||||
(void) arrayType;
|
|
||||||
|
|
||||||
// Resizable ArrayBuffer and growable SharedArrayBuffer views need dynamic
|
if (id->type() != MIRType::Int32 && id->type() != MIRType::Double)
|
||||||
// length/out-of-bounds handling. This older MIR path assumes stable
|
return false;
|
||||||
// typed-array length/data slots, so keep element accesses on IC/VM paths.
|
|
||||||
return false;
|
TemporaryTypeSet* types = obj->resultTypeSet();
|
||||||
|
if (!types)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*arrayType = types->getTypedArrayType(constraints);
|
||||||
|
|
||||||
|
// FIXME: https://bugzil.la/1536699
|
||||||
|
if (*arrayType == Scalar::MaxTypedArrayViewType ||
|
||||||
|
Scalar::isBigIntType(*arrayType)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
||||||
|
|
@ -3631,17 +3631,6 @@ CheckForTypedObjectWithDetachedStorage(JSContext* cx, MacroAssembler& masm, Labe
|
||||||
masm.branch32(Assembler::NotEqual, AbsoluteAddress(address), Imm32(0), failure);
|
masm.branch32(Assembler::NotEqual, AbsoluteAddress(address), Imm32(0), failure);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
GuardResizableOrGrowableTypedArray(MacroAssembler& masm, Register obj, Register scratch,
|
|
||||||
Label* failure)
|
|
||||||
{
|
|
||||||
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
|
|
||||||
masm.branchTest32(Assembler::NonZero,
|
|
||||||
Address(scratch, ObjectElements::offsetOfFlags()),
|
|
||||||
Imm32(ObjectElements::RESIZABLE_OR_GROWABLE_BUFFER),
|
|
||||||
failure);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
LoadTypedThingData(MacroAssembler& masm, TypedThingLayout layout, Register obj, Register result)
|
LoadTypedThingData(MacroAssembler& masm, TypedThingLayout layout, Register obj, Register result)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2307,11 +2307,7 @@ CheckDOMProxyExpandoDoesNotShadow(JSContext* cx, MacroAssembler& masm, Register
|
||||||
void
|
void
|
||||||
CheckForTypedObjectWithDetachedStorage(JSContext* cx, MacroAssembler& masm, Label* failure);
|
CheckForTypedObjectWithDetachedStorage(JSContext* cx, MacroAssembler& masm, Label* failure);
|
||||||
|
|
||||||
void
|
MOZ_MUST_USE bool
|
||||||
GuardResizableOrGrowableTypedArray(MacroAssembler& masm, Register obj, Register scratch,
|
|
||||||
Label* failure);
|
|
||||||
|
|
||||||
[[nodiscard]] bool
|
|
||||||
DoCallNativeGetter(JSContext* cx, HandleFunction callee, HandleObject obj,
|
DoCallNativeGetter(JSContext* cx, HandleFunction callee, HandleObject obj,
|
||||||
MutableHandleValue result);
|
MutableHandleValue result);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -548,8 +548,6 @@ MSG_DEF(JSMSG_TOO_LONG_ARRAY, 0, JSEXN_TYPEERR, "Too long array")
|
||||||
|
|
||||||
// Typed array
|
// Typed array
|
||||||
MSG_DEF(JSMSG_BAD_INDEX, 0, JSEXN_RANGEERR, "invalid or out-of-range index")
|
MSG_DEF(JSMSG_BAD_INDEX, 0, JSEXN_RANGEERR, "invalid or out-of-range index")
|
||||||
MSG_DEF(JSMSG_ARRAYBUFFER_NOT_RESIZABLE, 0, JSEXN_TYPEERR, "ArrayBuffer is not resizable")
|
|
||||||
MSG_DEF(JSMSG_ARRAYBUFFER_CANNOT_DETACH, 0, JSEXN_TYPEERR, "ArrayBuffer cannot be detached")
|
|
||||||
MSG_DEF(JSMSG_NON_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected ArrayBuffer, but species constructor returned non-ArrayBuffer")
|
MSG_DEF(JSMSG_NON_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected ArrayBuffer, but species constructor returned non-ArrayBuffer")
|
||||||
MSG_DEF(JSMSG_SAME_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected different ArrayBuffer, but species constructor returned same ArrayBuffer")
|
MSG_DEF(JSMSG_SAME_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected different ArrayBuffer, but species constructor returned same ArrayBuffer")
|
||||||
MSG_DEF(JSMSG_SHORT_ARRAY_BUFFER_RETURNED, 2, JSEXN_TYPEERR, "expected ArrayBuffer with at least {0} bytes, but species constructor returns ArrayBuffer with {1} bytes")
|
MSG_DEF(JSMSG_SHORT_ARRAY_BUFFER_RETURNED, 2, JSEXN_TYPEERR, "expected ArrayBuffer with at least {0} bytes, but species constructor returns ArrayBuffer with {1} bytes")
|
||||||
|
|
@ -557,15 +555,12 @@ MSG_DEF(JSMSG_TYPED_ARRAY_BAD_ARGS, 0, JSEXN_TYPEERR, "invalid arguments")
|
||||||
MSG_DEF(JSMSG_TYPED_ARRAY_NEGATIVE_ARG,1, JSEXN_RANGEERR, "argument {0} must be >= 0")
|
MSG_DEF(JSMSG_TYPED_ARRAY_NEGATIVE_ARG,1, JSEXN_RANGEERR, "argument {0} must be >= 0")
|
||||||
MSG_DEF(JSMSG_TYPED_ARRAY_DETACHED, 0, JSEXN_TYPEERR, "attempting to access detached ArrayBuffer")
|
MSG_DEF(JSMSG_TYPED_ARRAY_DETACHED, 0, JSEXN_TYPEERR, "attempting to access detached ArrayBuffer")
|
||||||
MSG_DEF(JSMSG_TYPED_ARRAY_CONSTRUCT_BOUNDS, 0, JSEXN_RANGEERR, "attempting to construct out-of-bounds TypedArray on ArrayBuffer")
|
MSG_DEF(JSMSG_TYPED_ARRAY_CONSTRUCT_BOUNDS, 0, JSEXN_RANGEERR, "attempting to construct out-of-bounds TypedArray on ArrayBuffer")
|
||||||
MSG_DEF(JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS, 0, JSEXN_TYPEERR, "attempting to access out-of-bounds TypedArray")
|
|
||||||
MSG_DEF(JSMSG_DATA_VIEW_OUT_OF_BOUNDS, 0, JSEXN_TYPEERR, "attempting to access out-of-bounds DataView")
|
|
||||||
MSG_DEF(JSMSG_TYPED_ARRAY_CALL_OR_CONSTRUCT, 1, JSEXN_TYPEERR, "cannot directly {0} builtin %TypedArray%")
|
MSG_DEF(JSMSG_TYPED_ARRAY_CALL_OR_CONSTRUCT, 1, JSEXN_TYPEERR, "cannot directly {0} builtin %TypedArray%")
|
||||||
MSG_DEF(JSMSG_NON_TYPED_ARRAY_RETURNED, 0, JSEXN_TYPEERR, "constructor didn't return TypedArray object")
|
MSG_DEF(JSMSG_NON_TYPED_ARRAY_RETURNED, 0, JSEXN_TYPEERR, "constructor didn't return TypedArray object")
|
||||||
MSG_DEF(JSMSG_SHORT_TYPED_ARRAY_RETURNED, 2, JSEXN_TYPEERR, "expected TypedArray of at least length {0}, but constructor returned TypedArray of length {1}")
|
MSG_DEF(JSMSG_SHORT_TYPED_ARRAY_RETURNED, 2, JSEXN_TYPEERR, "expected TypedArray of at least length {0}, but constructor returned TypedArray of length {1}")
|
||||||
|
|
||||||
// Shared array buffer
|
// Shared array buffer
|
||||||
MSG_DEF(JSMSG_SHARED_ARRAY_BAD_LENGTH, 0, JSEXN_RANGEERR, "length argument out of range")
|
MSG_DEF(JSMSG_SHARED_ARRAY_BAD_LENGTH, 0, JSEXN_RANGEERR, "length argument out of range")
|
||||||
MSG_DEF(JSMSG_SHARED_ARRAY_NOT_GROWABLE, 0, JSEXN_TYPEERR, "SharedArrayBuffer is not growable")
|
|
||||||
MSG_DEF(JSMSG_NON_SHARED_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected SharedArrayBuffer, but species constructor returned non-SharedArrayBuffer")
|
MSG_DEF(JSMSG_NON_SHARED_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected SharedArrayBuffer, but species constructor returned non-SharedArrayBuffer")
|
||||||
MSG_DEF(JSMSG_SAME_SHARED_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected different SharedArrayBuffer, but species constructor returned same SharedArrayBuffer")
|
MSG_DEF(JSMSG_SAME_SHARED_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected different SharedArrayBuffer, but species constructor returned same SharedArrayBuffer")
|
||||||
MSG_DEF(JSMSG_SHORT_SHARED_ARRAY_BUFFER_RETURNED, 2, JSEXN_TYPEERR, "expected SharedArrayBuffer with at least {0} bytes, but species constructor returns SharedArrayBuffer with {1} bytes")
|
MSG_DEF(JSMSG_SHORT_SHARED_ARRAY_BUFFER_RETURNED, 2, JSEXN_TYPEERR, "expected SharedArrayBuffer with at least {0} bytes, but species constructor returns SharedArrayBuffer with {1} bytes")
|
||||||
|
|
|
||||||
|
|
@ -951,20 +951,6 @@ LookupStdName(const JSAtomState& names, JSAtom* name, const JSStdName* table)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
|
||||||
IsStreamExtraName(JSFlatString* name)
|
|
||||||
{
|
|
||||||
return JS_FlatStringEqualsAscii(name, "WritableStream") ||
|
|
||||||
JS_FlatStringEqualsAscii(name, "WritableStreamDefaultWriter") ||
|
|
||||||
JS_FlatStringEqualsAscii(name, "WritableStreamDefaultController") ||
|
|
||||||
JS_FlatStringEqualsAscii(name, "TransformStream") ||
|
|
||||||
JS_FlatStringEqualsAscii(name, "TransformStreamDefaultController") ||
|
|
||||||
JS_FlatStringEqualsAscii(name, "TextEncoderStream") ||
|
|
||||||
JS_FlatStringEqualsAscii(name, "TextDecoderStream") ||
|
|
||||||
JS_FlatStringEqualsAscii(name, "CompressionStream") ||
|
|
||||||
JS_FlatStringEqualsAscii(name, "DecompressionStream");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Table of standard classes, indexed by JSProtoKey. For entries where the
|
* Table of standard classes, indexed by JSProtoKey. For entries where the
|
||||||
* JSProtoKey does not correspond to a class with a meaningful constructor, we
|
* JSProtoKey does not correspond to a class with a meaningful constructor, we
|
||||||
|
|
@ -1055,27 +1041,11 @@ JS_ResolveStandardClass(JSContext* cx, HandleObject obj, HandleId id, bool* reso
|
||||||
if (!GlobalObject::ensureConstructor(cx, global, key))
|
if (!GlobalObject::ensureConstructor(cx, global, key))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (key == JSProto_ReadableStream) {
|
|
||||||
RootedObject globalObj(cx, global);
|
|
||||||
if (!InitStreamExtras(cx, globalObj))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
*resolved = true;
|
*resolved = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cx->options().streams() && IsStreamExtraName(idAtom)) {
|
|
||||||
RootedObject globalObj(cx, global);
|
|
||||||
if (!InitStreamExtras(cx, globalObj))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!HasOwnProperty(cx, globalObj, id, resolved))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// There is no such property to resolve. An ordinary resolve hook would
|
// There is no such property to resolve. An ordinary resolve hook would
|
||||||
// just return true at this point. But the global object is special in one
|
// just return true at this point. But the global object is special in one
|
||||||
// more way: its prototype chain is lazily initialized. That is,
|
// more way: its prototype chain is lazily initialized. That is,
|
||||||
|
|
@ -1105,7 +1075,6 @@ JS_MayResolveStandardClass(const JSAtomState& names, jsid id, JSObject* maybeObj
|
||||||
|
|
||||||
return atom == names.undefined ||
|
return atom == names.undefined ||
|
||||||
atom == names.globalThis ||
|
atom == names.globalThis ||
|
||||||
IsStreamExtraName(atom) ||
|
|
||||||
LookupStdName(names, atom, standard_class_names) ||
|
LookupStdName(names, atom, standard_class_names) ||
|
||||||
LookupStdName(names, atom, builtin_property_names);
|
LookupStdName(names, atom, builtin_property_names);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -998,9 +998,7 @@ class JS_PUBLIC_API(ContextOptions) {
|
||||||
werror_(false),
|
werror_(false),
|
||||||
strictMode_(false),
|
strictMode_(false),
|
||||||
extraWarnings_(false),
|
extraWarnings_(false),
|
||||||
arrayProtoValues_(true),
|
arrayProtoValues_(true)
|
||||||
streams_(true),
|
|
||||||
weakRefs_(false)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1140,16 +1138,6 @@ class JS_PUBLIC_API(ContextOptions) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool weakRefs() const { return weakRefs_; }
|
|
||||||
ContextOptions& setWeakRefs(bool flag) {
|
|
||||||
weakRefs_ = flag;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
ContextOptions& toggleWeakRefs() {
|
|
||||||
weakRefs_ = !weakRefs_;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool baseline_ : 1;
|
bool baseline_ : 1;
|
||||||
bool ion_ : 1;
|
bool ion_ : 1;
|
||||||
|
|
@ -1167,7 +1155,6 @@ class JS_PUBLIC_API(ContextOptions) {
|
||||||
bool extraWarnings_ : 1;
|
bool extraWarnings_ : 1;
|
||||||
bool arrayProtoValues_ : 1;
|
bool arrayProtoValues_ : 1;
|
||||||
bool streams_ : 1;
|
bool streams_ : 1;
|
||||||
bool weakRefs_ : 1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
JS_PUBLIC_API(ContextOptions&)
|
JS_PUBLIC_API(ContextOptions&)
|
||||||
|
|
|
||||||
|
|
@ -1221,12 +1221,7 @@ js::array_join(JSContext* cx, unsigned argc, Value* vp)
|
||||||
sepstr = cx->names().comma;
|
sepstr = cx->names().comma;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 6: empty arrays always join to the empty string.
|
// Step 6 is implicit in the loops below.
|
||||||
// (Separator ToString above still runs for side effects / OOM.)
|
|
||||||
if (length == 0) {
|
|
||||||
args.rval().setString(cx->names().empty);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// An optimized version of a special case of steps 7-11: when length==1 and
|
// An optimized version of a special case of steps 7-11: when length==1 and
|
||||||
// the 0th element is a string, ToString() of that element is a no-op and
|
// the 0th element is a string, ToString() of that element is a no-op and
|
||||||
|
|
@ -1386,8 +1381,8 @@ template <JSValueType Type>
|
||||||
DenseElementResult
|
DenseElementResult
|
||||||
ArrayReverseDenseKernel(JSContext* cx, HandleObject obj, uint32_t length)
|
ArrayReverseDenseKernel(JSContext* cx, HandleObject obj, uint32_t length)
|
||||||
{
|
{
|
||||||
/* Empty, singleton, or uninitialized arrays are already reversed. */
|
/* An empty array or an array with no elements is already reversed. */
|
||||||
if (length <= 1 || GetBoxedOrUnboxedInitializedLength<Type>(obj) == 0)
|
if (length == 0 || GetBoxedOrUnboxedInitializedLength<Type>(obj) == 0)
|
||||||
return DenseElementResult::Success;
|
return DenseElementResult::Success;
|
||||||
|
|
||||||
if (Type == JSVAL_TYPE_MAGIC) {
|
if (Type == JSVAL_TYPE_MAGIC) {
|
||||||
|
|
@ -1456,12 +1451,6 @@ js::array_reverse(JSContext* cx, unsigned argc, Value* vp)
|
||||||
if (!GetLengthProperty(cx, obj, &len))
|
if (!GetLengthProperty(cx, obj, &len))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// length 0/1: reverse is a no-op; return this immediately.
|
|
||||||
if (len <= 1) {
|
|
||||||
args.rval().setObject(*obj);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ObjectMayHaveExtraIndexedProperties(obj)) {
|
if (!ObjectMayHaveExtraIndexedProperties(obj)) {
|
||||||
ArrayReverseDenseKernelFunctor functor(cx, obj, len);
|
ArrayReverseDenseKernelFunctor functor(cx, obj, len);
|
||||||
DenseElementResult result = CallBoxedOrUnboxedSpecialization(functor, obj);
|
DenseElementResult result = CallBoxedOrUnboxedSpecialization(functor, obj);
|
||||||
|
|
@ -3227,7 +3216,6 @@ static const JSFunctionSpec array_methods[] = {
|
||||||
/* ES2023 proposals */
|
/* ES2023 proposals */
|
||||||
JS_SELF_HOSTED_FN("findLast", "ArrayFindLast", 1,0),
|
JS_SELF_HOSTED_FN("findLast", "ArrayFindLast", 1,0),
|
||||||
JS_SELF_HOSTED_FN("findLastIndex", "ArrayFindLastIndex", 1,0),
|
JS_SELF_HOSTED_FN("findLastIndex", "ArrayFindLastIndex", 1,0),
|
||||||
JS_SELF_HOSTED_FN("toSorted", "ArrayToSorted", 1,0),
|
|
||||||
|
|
||||||
JS_FS_END
|
JS_FS_END
|
||||||
};
|
};
|
||||||
|
|
@ -3402,8 +3390,7 @@ array_proto_finish(JSContext* cx, JS::HandleObject ctor, JS::HandleObject proto)
|
||||||
!DefineProperty(cx, unscopables, cx->names().flatMap, value) ||
|
!DefineProperty(cx, unscopables, cx->names().flatMap, value) ||
|
||||||
!DefineProperty(cx, unscopables, cx->names().includes, value) ||
|
!DefineProperty(cx, unscopables, cx->names().includes, value) ||
|
||||||
!DefineProperty(cx, unscopables, cx->names().keys, value) ||
|
!DefineProperty(cx, unscopables, cx->names().keys, value) ||
|
||||||
!DefineProperty(cx, unscopables, cx->names().values, value) ||
|
!DefineProperty(cx, unscopables, cx->names().values, value))
|
||||||
!DefineProperty(cx, unscopables, cx->names().toSorted, value))
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1748,9 +1748,6 @@ JS_IsFloat64Array(JSObject* obj);
|
||||||
extern JS_FRIEND_API(bool)
|
extern JS_FRIEND_API(bool)
|
||||||
JS_GetTypedArraySharedness(JSObject* obj);
|
JS_GetTypedArraySharedness(JSObject* obj);
|
||||||
|
|
||||||
extern JS_FRIEND_API(uint32_t)
|
|
||||||
JS_GetTypedArrayLength(JSObject* obj);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test for specific typed array types (ArrayBufferView subtypes) and return
|
* Test for specific typed array types (ArrayBufferView subtypes) and return
|
||||||
* the unwrapped object if so, else nullptr. Never throws.
|
* the unwrapped object if so, else nullptr. Never throws.
|
||||||
|
|
@ -1817,7 +1814,8 @@ inline void \
|
||||||
Get ## Type ## ArrayLengthAndData(JSObject* obj, uint32_t* length, bool* isSharedMemory, type** data) \
|
Get ## Type ## ArrayLengthAndData(JSObject* obj, uint32_t* length, bool* isSharedMemory, type** data) \
|
||||||
{ \
|
{ \
|
||||||
MOZ_ASSERT(GetObjectClass(obj) == detail::Type ## ArrayClassPtr); \
|
MOZ_ASSERT(GetObjectClass(obj) == detail::Type ## ArrayClassPtr); \
|
||||||
*length = JS_GetTypedArrayLength(obj); \
|
const JS::Value& lenSlot = GetReservedSlot(obj, detail::TypedArrayLengthSlot); \
|
||||||
|
*length = mozilla::AssertedCast<uint32_t>(lenSlot.toInt32()); \
|
||||||
*isSharedMemory = JS_GetTypedArraySharedness(obj); \
|
*isSharedMemory = JS_GetTypedArraySharedness(obj); \
|
||||||
*data = static_cast<type*>(GetObjectPrivate(obj)); \
|
*data = static_cast<type*>(GetObjectPrivate(obj)); \
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,6 @@ IF_SAB(real,imaginary)(Atomics, InitAtomicsClass, OCLASP(Atomics)) \
|
||||||
imaginary(WritableStreamDefaultController,dummy, dummy) \
|
imaginary(WritableStreamDefaultController,dummy, dummy) \
|
||||||
real(ByteLengthQueuingStrategy, InitViaClassSpec, &js::ByteLengthQueuingStrategy::class_) \
|
real(ByteLengthQueuingStrategy, InitViaClassSpec, &js::ByteLengthQueuingStrategy::class_) \
|
||||||
real(CountQueuingStrategy, InitViaClassSpec, &js::CountQueuingStrategy::class_) \
|
real(CountQueuingStrategy, InitViaClassSpec, &js::CountQueuingStrategy::class_) \
|
||||||
real(WeakRef, InitWeakRefClass, OCLASP(WeakRef)) \
|
|
||||||
|
|
||||||
#define JS_FOR_EACH_PROTOTYPE(macro) JS_FOR_PROTOTYPES(macro,macro)
|
#define JS_FOR_EACH_PROTOTYPE(macro) JS_FOR_PROTOTYPES(macro,macro)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2329,12 +2329,6 @@ js::str_startsWith(JSContext* cx, unsigned argc, Value* vp)
|
||||||
// Step 13
|
// Step 13
|
||||||
uint32_t searchLen = searchStr->length();
|
uint32_t searchLen = searchStr->length();
|
||||||
|
|
||||||
// Empty search string always matches (and is extremely common).
|
|
||||||
if (searchLen == 0) {
|
|
||||||
args.rval().setBoolean(true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 14
|
// Step 14
|
||||||
if (searchLen + start < searchLen || searchLen + start > textLen) {
|
if (searchLen + start < searchLen || searchLen + start > textLen) {
|
||||||
args.rval().setBoolean(false);
|
args.rval().setBoolean(false);
|
||||||
|
|
@ -2401,12 +2395,6 @@ js::str_endsWith(JSContext* cx, unsigned argc, Value* vp)
|
||||||
// Step 13
|
// Step 13
|
||||||
uint32_t searchLen = searchStr->length();
|
uint32_t searchLen = searchStr->length();
|
||||||
|
|
||||||
// Empty search string always matches.
|
|
||||||
if (searchLen == 0) {
|
|
||||||
args.rval().setBoolean(true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 15 (reordered)
|
// Step 15 (reordered)
|
||||||
if (searchLen > end) {
|
if (searchLen > end) {
|
||||||
args.rval().setBoolean(false);
|
args.rval().setBoolean(false);
|
||||||
|
|
@ -3344,8 +3332,6 @@ static const JSFunctionSpec string_methods[] = {
|
||||||
JS_SELF_HOSTED_FN("toLocaleUpperCase", "String_toLocaleUpperCase", 0,0),
|
JS_SELF_HOSTED_FN("toLocaleUpperCase", "String_toLocaleUpperCase", 0,0),
|
||||||
JS_SELF_HOSTED_FN("localeCompare", "String_localeCompare", 1,0),
|
JS_SELF_HOSTED_FN("localeCompare", "String_localeCompare", 1,0),
|
||||||
JS_SELF_HOSTED_FN("repeat", "String_repeat", 1,0),
|
JS_SELF_HOSTED_FN("repeat", "String_repeat", 1,0),
|
||||||
JS_SELF_HOSTED_FN("isWellFormed", "String_isWellFormed", 0,0),
|
|
||||||
JS_SELF_HOSTED_FN("toWellFormed", "String_toWellFormed", 0,0),
|
|
||||||
JS_FN("normalize", str_normalize, 0,0),
|
JS_FN("normalize", str_normalize, 0,0),
|
||||||
|
|
||||||
/* Perl-ish methods (search is actually Python-esque). */
|
/* Perl-ish methods (search is actually Python-esque). */
|
||||||
|
|
|
||||||
|
|
@ -16,25 +16,11 @@
|
||||||
#include "gc/Marking.h"
|
#include "gc/Marking.h"
|
||||||
#include "gc/StoreBuffer.h"
|
#include "gc/StoreBuffer.h"
|
||||||
#include "js/HashTable.h"
|
#include "js/HashTable.h"
|
||||||
#include "vm/Symbol.h"
|
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
class WeakMapBase;
|
class WeakMapBase;
|
||||||
|
|
||||||
template <>
|
|
||||||
struct MovableCellHasher<JS::Symbol*>
|
|
||||||
{
|
|
||||||
using Key = JS::Symbol*;
|
|
||||||
using Lookup = JS::Symbol*;
|
|
||||||
|
|
||||||
static bool hasHash(const Lookup& l) { return true; }
|
|
||||||
static bool ensureHash(const Lookup& l) { return true; }
|
|
||||||
static HashNumber hash(const Lookup& l) { return l->hash(); }
|
|
||||||
static bool match(const Key& k, const Lookup& l) { return k == l; }
|
|
||||||
static void rekey(Key& k, const Key& newKey) { k = newKey; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// A subclass template of js::HashMap whose keys and values may be garbage-collected. When
|
// A subclass template of js::HashMap whose keys and values may be garbage-collected. When
|
||||||
// a key is collected, the table entry disappears, dropping its reference to the value.
|
// a key is collected, the table entry disappears, dropping its reference to the value.
|
||||||
//
|
//
|
||||||
|
|
@ -310,16 +296,9 @@ class WeakMap : public HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy>,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject* getDelegate(JS::Symbol* sym) const {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void exposeGCThingToActiveJS(const JS::Value& v) const { JS::ExposeValueToActiveJS(v); }
|
void exposeGCThingToActiveJS(const JS::Value& v) const { JS::ExposeValueToActiveJS(v); }
|
||||||
void exposeGCThingToActiveJS(JSObject* obj) const { JS::ExposeObjectToActiveJS(obj); }
|
void exposeGCThingToActiveJS(JSObject* obj) const { JS::ExposeObjectToActiveJS(obj); }
|
||||||
void exposeGCThingToActiveJS(JS::Symbol* sym) const {
|
|
||||||
gc::ExposeGCThingToActiveJS(JS::GCCellPtr(sym));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool keyNeedsMark(JSObject* key) const {
|
bool keyNeedsMark(JSObject* key) const {
|
||||||
JSObject* delegate = getDelegate(key);
|
JSObject* delegate = getDelegate(key);
|
||||||
|
|
@ -334,10 +313,6 @@ class WeakMap : public HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy>,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool keyNeedsMark(JS::Symbol* sym) const {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool findZoneEdges() override {
|
bool findZoneEdges() override {
|
||||||
// This is overridden by ObjectValueMap.
|
// This is overridden by ObjectValueMap.
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -403,9 +378,6 @@ WeakMap_set(JSContext* cx, unsigned argc, Value* vp);
|
||||||
extern bool
|
extern bool
|
||||||
WeakMap_delete(JSContext* cx, unsigned argc, Value* vp);
|
WeakMap_delete(JSContext* cx, unsigned argc, Value* vp);
|
||||||
|
|
||||||
extern bool
|
|
||||||
SetWeakMapEntryValue(JSContext* cx, HandleObject mapObj, HandleValue key, HandleValue val);
|
|
||||||
|
|
||||||
extern JSObject*
|
extern JSObject*
|
||||||
InitWeakMapClass(JSContext* cx, HandleObject obj);
|
InitWeakMapClass(JSContext* cx, HandleObject obj);
|
||||||
|
|
||||||
|
|
@ -422,16 +394,6 @@ class ObjectValueMap : public WeakMap<HeapPtr<JSObject*>, HeapPtr<Value>,
|
||||||
virtual bool findZoneEdges();
|
virtual bool findZoneEdges();
|
||||||
};
|
};
|
||||||
|
|
||||||
class SymbolValueMap : public WeakMap<HeapPtr<JS::Symbol*>, HeapPtr<Value>,
|
|
||||||
MovableCellHasher<HeapPtr<JS::Symbol*>>>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SymbolValueMap(JSContext* cx, JSObject* obj)
|
|
||||||
: WeakMap<HeapPtr<JS::Symbol*>, HeapPtr<Value>,
|
|
||||||
MovableCellHasher<HeapPtr<JS::Symbol*>>>(cx, obj)
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Generic weak map for mapping objects to other objects.
|
// Generic weak map for mapping objects to other objects.
|
||||||
class ObjectWeakMap
|
class ObjectWeakMap
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,6 @@ main_deunified_sources = [
|
||||||
'builtin/TestingFunctions.cpp',
|
'builtin/TestingFunctions.cpp',
|
||||||
'builtin/TypedObject.cpp',
|
'builtin/TypedObject.cpp',
|
||||||
'builtin/WeakMapObject.cpp',
|
'builtin/WeakMapObject.cpp',
|
||||||
'builtin/WeakRefObject.cpp',
|
|
||||||
'builtin/WeakSetObject.cpp',
|
'builtin/WeakSetObject.cpp',
|
||||||
'devtools/sharkctl.cpp',
|
'devtools/sharkctl.cpp',
|
||||||
'ds/LifoAlloc.cpp',
|
'ds/LifoAlloc.cpp',
|
||||||
|
|
|
||||||
|
|
@ -3330,15 +3330,6 @@ static const JSClass sandbox_class = {
|
||||||
&sandbox_classOps
|
&sandbox_classOps
|
||||||
};
|
};
|
||||||
|
|
||||||
enum GlobalAppSlot {
|
|
||||||
GlobalAppSlotModuleMetadataHook,
|
|
||||||
GlobalAppSlotModuleDynamicImportHook,
|
|
||||||
GlobalAppSlotCount
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert(GlobalAppSlotCount <= JSCLASS_GLOBAL_APPLICATION_SLOTS,
|
|
||||||
"global application slots overflow");
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
SetStandardCompartmentOptions(JS::CompartmentOptions& options)
|
SetStandardCompartmentOptions(JS::CompartmentOptions& options)
|
||||||
{
|
{
|
||||||
|
|
@ -4167,7 +4158,7 @@ ParseModule(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
|
||||||
const char16_t* chars = stableChars.twoByteRange().begin().get();
|
const char16_t* chars = stableChars.twoByteRange().begin().get();
|
||||||
JS::SourceBufferHolder srcBuf(chars, scriptContents->length(),
|
JS::SourceBufferHolder srcBuf(chars, scriptContents->length(),
|
||||||
JS::SourceBufferHolder::NoOwnership);
|
SourceBufferHolder::NoOwnership);
|
||||||
|
|
||||||
RootedObject module(cx, frontend::CompileModule(cx, options, srcBuf));
|
RootedObject module(cx, frontend::CompileModule(cx, options, srcBuf));
|
||||||
if (!module)
|
if (!module)
|
||||||
|
|
@ -4378,7 +4369,7 @@ AbortDynamicModuleImport(JSContext* cx, unsigned argc, Value* vp)
|
||||||
RootedString specifier(cx, args[1].toString());
|
RootedString specifier(cx, args[1].toString());
|
||||||
Rooted<PromiseObject*> promise(cx, &args[2].toObject().as<PromiseObject>());
|
Rooted<PromiseObject*> promise(cx, &args[2].toObject().as<PromiseObject>());
|
||||||
|
|
||||||
cx->setPendingException(args[3], nullptr);
|
cx->setPendingException(args[3]);
|
||||||
return js::FinishDynamicModuleImport(cx, args[0], specifier, promise);
|
return js::FinishDynamicModuleImport(cx, args[0], specifier, promise);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -8431,7 +8422,7 @@ main(int argc, char** argv, char** envp)
|
||||||
|
|
||||||
JS::SetModuleResolveHook(cx->runtime(), ShellModuleResolveHook);
|
JS::SetModuleResolveHook(cx->runtime(), ShellModuleResolveHook);
|
||||||
JS::SetModuleDynamicImportHook(cx, ShellModuleDynamicImportHook);
|
JS::SetModuleDynamicImportHook(cx, ShellModuleDynamicImportHook);
|
||||||
JS::SetModuleMetadataHook(cx, CallModuleMetadataHook);
|
JS::SetModuleMetadataHook(cx, ShellModuleMetadataHook);
|
||||||
|
|
||||||
result = Shell(cx, &op, envp);
|
result = Shell(cx, &op, envp);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
<!doctype html>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>Array.prototype.toSorted test</title>
|
|
||||||
<style>
|
|
||||||
body { font: 14px/1.4 sans-serif; padding: 16px; }
|
|
||||||
.pass { color: #0a0; }
|
|
||||||
.fail { color: #c00; }
|
|
||||||
pre { white-space: pre-wrap; }
|
|
||||||
</style>
|
|
||||||
<pre id="log"></pre>
|
|
||||||
<script>
|
|
||||||
(function() {
|
|
||||||
const log = document.getElementById("log");
|
|
||||||
function write(msg, cls) {
|
|
||||||
const line = document.createElement("div");
|
|
||||||
if (cls) line.className = cls;
|
|
||||||
line.textContent = msg;
|
|
||||||
log.appendChild(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
window.assertEq = function(actual, expected, msg) {
|
|
||||||
if (actual !== expected) {
|
|
||||||
throw new Error((msg ? msg + ": " : "") +
|
|
||||||
"expected " + expected + ", got " + actual);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
window.assertThrowsInstanceOf = function(fn, ctor, msg) {
|
|
||||||
let threw = false;
|
|
||||||
try {
|
|
||||||
fn();
|
|
||||||
} catch (e) {
|
|
||||||
if (e instanceof ctor) {
|
|
||||||
threw = true;
|
|
||||||
} else {
|
|
||||||
throw new Error((msg ? msg + ": " : "") +
|
|
||||||
"threw " + e + ", expected " + ctor.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!threw) {
|
|
||||||
throw new Error((msg ? msg + ": " : "") + "did not throw");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
window.reportCompare = function() {};
|
|
||||||
|
|
||||||
let hadError = false;
|
|
||||||
window.addEventListener("error", function(e) {
|
|
||||||
hadError = true;
|
|
||||||
write("FAIL: " + e.message, "fail");
|
|
||||||
});
|
|
||||||
window.addEventListener("load", function() {
|
|
||||||
write("PASS: toSorted.js loaded", "pass");
|
|
||||||
if (!hadError)
|
|
||||||
write("PASS: all toSorted tests passed", "pass");
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
<script src="toSorted.js"></script>
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
/* Any copyright is dedicated to the Public Domain.
|
|
||||||
* http://creativecommons.org/licenses/publicdomain/ */
|
|
||||||
|
|
||||||
assertEq(typeof Array.prototype.toSorted, "function");
|
|
||||||
|
|
||||||
// Non-mutating behavior.
|
|
||||||
let original = [3, 1, 2];
|
|
||||||
let sorted = original.toSorted();
|
|
||||||
assertEq(original !== sorted, true);
|
|
||||||
assertEq(original.join(","), "3,1,2");
|
|
||||||
assertEq(sorted.join(","), "1,2,3");
|
|
||||||
|
|
||||||
// Compare function.
|
|
||||||
let nums = [10, 1, 5];
|
|
||||||
let desc = nums.toSorted((a, b) => b - a);
|
|
||||||
assertEq(desc.join(","), "10,5,1");
|
|
||||||
|
|
||||||
// Stable sort.
|
|
||||||
let stableInput = [
|
|
||||||
{v: 1, id: "a"},
|
|
||||||
{v: 1, id: "b"},
|
|
||||||
{v: 1, id: "c"}
|
|
||||||
];
|
|
||||||
let stableSorted = stableInput.toSorted((x, y) => x.v - y.v);
|
|
||||||
assertEq(stableSorted.map(o => o.id).join(""), "abc");
|
|
||||||
|
|
||||||
// Holes are treated as undefined (properties are created).
|
|
||||||
let sparse = [3, , 1];
|
|
||||||
let sparseSorted = sparse.toSorted();
|
|
||||||
assertEq(sparseSorted.length, 3);
|
|
||||||
assertEq(sparseSorted[0], 1);
|
|
||||||
assertEq(sparseSorted[1], 3);
|
|
||||||
assertEq(2 in sparseSorted, true);
|
|
||||||
assertEq(sparseSorted[2], undefined);
|
|
||||||
|
|
||||||
// Array-like input.
|
|
||||||
let arrayLike = {0: 2, 1: 1, length: 2};
|
|
||||||
let arrayLikeSorted = Array.prototype.toSorted.call(arrayLike);
|
|
||||||
assertEq(Array.isArray(arrayLikeSorted), true);
|
|
||||||
assertEq(arrayLikeSorted.join(","), "1,2");
|
|
||||||
|
|
||||||
// Getter access order (ascending indices).
|
|
||||||
let accessLog = [];
|
|
||||||
let getterArr = {
|
|
||||||
length: 3,
|
|
||||||
get 0() { accessLog.push(0); return 3; },
|
|
||||||
get 1() { accessLog.push(1); return 1; },
|
|
||||||
get 2() { accessLog.push(2); return 2; }
|
|
||||||
};
|
|
||||||
Array.prototype.toSorted.call(getterArr);
|
|
||||||
assertEq(accessLog.join(","), "0,1,2");
|
|
||||||
|
|
||||||
// Comparator errors propagate.
|
|
||||||
assertThrowsInstanceOf(() => [1, 2].toSorted(1), TypeError);
|
|
||||||
|
|
||||||
if (typeof reportCompare === "function")
|
|
||||||
reportCompare(0, 0);
|
|
||||||
|
|
@ -1,98 +0,0 @@
|
||||||
// |reftest| skip-if(!ArrayBuffer.prototype.transfer)
|
|
||||||
|
|
||||||
var fixed = new ArrayBuffer(4);
|
|
||||||
assertEq(fixed.byteLength, 4);
|
|
||||||
assertEq(fixed.maxByteLength, 4);
|
|
||||||
assertEq(fixed.resizable, false);
|
|
||||||
assertEq(fixed.detached, false);
|
|
||||||
new Uint8Array(fixed).set([1, 2, 3, 4]);
|
|
||||||
fixed.extra = 17;
|
|
||||||
assertEq(Array.from(new Uint8Array(fixed)).join(","), "1,2,3,4");
|
|
||||||
assertThrowsInstanceOf(() => fixed.resize(2), TypeError);
|
|
||||||
assertEq(ArrayBuffer.prototype.transfer.length, 0);
|
|
||||||
assertEq(ArrayBuffer.prototype.transferToFixedLength.length, 0);
|
|
||||||
var resizeArgumentConverted = false;
|
|
||||||
assertThrowsInstanceOf(() => fixed.resize({ valueOf() { resizeArgumentConverted = true; return 1; } }),
|
|
||||||
TypeError);
|
|
||||||
assertEq(resizeArgumentConverted, false);
|
|
||||||
|
|
||||||
var resizable = new ArrayBuffer(4, { maxByteLength: 8 });
|
|
||||||
assertEq(resizable.byteLength, 4);
|
|
||||||
assertEq(resizable.maxByteLength, 8);
|
|
||||||
assertEq(resizable.resizable, true);
|
|
||||||
|
|
||||||
var bytes = new Uint8Array(resizable);
|
|
||||||
bytes[0] = 11;
|
|
||||||
bytes[3] = 44;
|
|
||||||
resizable.resize(6);
|
|
||||||
assertEq(resizable.byteLength, 6);
|
|
||||||
assertEq(new Uint8Array(resizable)[0], 11);
|
|
||||||
assertEq(new Uint8Array(resizable)[3], 44);
|
|
||||||
assertEq(new Uint8Array(resizable)[4], 0);
|
|
||||||
assertThrowsInstanceOf(() => resizable.resize(9), RangeError);
|
|
||||||
|
|
||||||
var source = new ArrayBuffer(4);
|
|
||||||
var sourceBytes = new Uint8Array(source);
|
|
||||||
sourceBytes[0] = 1;
|
|
||||||
sourceBytes[1] = 2;
|
|
||||||
var sourceView = new Uint8Array(source);
|
|
||||||
var moved = source.transfer(6);
|
|
||||||
assertEq(source.detached, true);
|
|
||||||
assertEq(source.byteLength, 0);
|
|
||||||
assertEq(source.maxByteLength, 0);
|
|
||||||
assertEq(sourceView.length, 0);
|
|
||||||
assertEq(moved.byteLength, 6);
|
|
||||||
assertEq(moved.resizable, false);
|
|
||||||
assertEq(moved.maxByteLength, 6);
|
|
||||||
assertEq(new Uint8Array(moved)[0], 1);
|
|
||||||
assertEq(new Uint8Array(moved)[1], 2);
|
|
||||||
assertEq(new Uint8Array(moved)[4], 0);
|
|
||||||
|
|
||||||
var resizableSource = new ArrayBuffer(4, { maxByteLength: 8 });
|
|
||||||
new Uint8Array(resizableSource)[0] = 7;
|
|
||||||
var resizableMoved = resizableSource.transfer();
|
|
||||||
assertEq(resizableSource.detached, true);
|
|
||||||
assertEq(resizableSource.resizable, true);
|
|
||||||
assertEq(resizableMoved.byteLength, 4);
|
|
||||||
assertEq(resizableMoved.maxByteLength, 8);
|
|
||||||
assertEq(resizableMoved.resizable, true);
|
|
||||||
assertEq(new Uint8Array(resizableMoved)[0], 7);
|
|
||||||
|
|
||||||
var fixedMoved = resizableMoved.transferToFixedLength(10);
|
|
||||||
assertEq(resizableMoved.detached, true);
|
|
||||||
assertEq(fixedMoved.byteLength, 10);
|
|
||||||
assertEq(fixedMoved.maxByteLength, 10);
|
|
||||||
assertEq(fixedMoved.resizable, false);
|
|
||||||
assertEq(new Uint8Array(fixedMoved)[0], 7);
|
|
||||||
|
|
||||||
var sliceSource = new ArrayBuffer(8, { maxByteLength: 8 });
|
|
||||||
var sliceSourceBytes = new Uint8Array(sliceSource);
|
|
||||||
for (var i = 0; i < sliceSourceBytes.length; i++)
|
|
||||||
sliceSourceBytes[i] = i + 1;
|
|
||||||
|
|
||||||
sliceSource.constructor = {
|
|
||||||
[Symbol.species]: function(byteLength) {
|
|
||||||
sliceSource.resize(4);
|
|
||||||
return new ArrayBuffer(byteLength);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var sliced = sliceSource.slice(2, 8);
|
|
||||||
var slicedBytes = new Uint8Array(sliced);
|
|
||||||
assertEq(sliced.byteLength, 6);
|
|
||||||
assertEq(slicedBytes[0], 3);
|
|
||||||
assertEq(slicedBytes[1], 4);
|
|
||||||
assertEq(slicedBytes[2], 0);
|
|
||||||
assertEq(slicedBytes[5], 0);
|
|
||||||
|
|
||||||
sliceSource.resize(8);
|
|
||||||
for (var i = 0; i < sliceSourceBytes.length; i++)
|
|
||||||
sliceSourceBytes[i] = i + 1;
|
|
||||||
var zeroCopied = sliceSource.slice(6, 8);
|
|
||||||
assertEq(zeroCopied.byteLength, 2);
|
|
||||||
assertEq(new Uint8Array(zeroCopied)[0], 0);
|
|
||||||
|
|
||||||
assertThrowsInstanceOf(() => new ArrayBuffer(4, { maxByteLength: 3 }), RangeError);
|
|
||||||
|
|
||||||
if (typeof reportCompare === "function")
|
|
||||||
reportCompare(0, 0);
|
|
||||||
|
|
@ -1,218 +0,0 @@
|
||||||
// |reftest| skip-if(!this.SharedArrayBuffer)
|
|
||||||
|
|
||||||
var rab = new ArrayBuffer(4, { maxByteLength: 16 });
|
|
||||||
var tracking = new Uint8Array(rab);
|
|
||||||
var fixed = new Uint8Array(rab, 1, 2);
|
|
||||||
var bytes = new Uint8Array(rab);
|
|
||||||
|
|
||||||
bytes[1] = 11;
|
|
||||||
bytes[2] = 22;
|
|
||||||
|
|
||||||
assertEq(tracking.length, 4);
|
|
||||||
assertEq(tracking.byteLength, 4);
|
|
||||||
assertEq(tracking.byteOffset, 0);
|
|
||||||
assertEq(fixed.length, 2);
|
|
||||||
assertEq(fixed.byteLength, 2);
|
|
||||||
assertEq(fixed.byteOffset, 1);
|
|
||||||
|
|
||||||
rab.resize(2);
|
|
||||||
assertEq(tracking.length, 2);
|
|
||||||
assertEq(tracking.byteLength, 2);
|
|
||||||
assertEq(fixed.length, 0);
|
|
||||||
assertEq(fixed.byteLength, 0);
|
|
||||||
assertEq(fixed.byteOffset, 0);
|
|
||||||
assertEq(fixed[0], undefined);
|
|
||||||
|
|
||||||
rab.resize(8);
|
|
||||||
assertEq(tracking.length, 8);
|
|
||||||
assertEq(tracking.byteLength, 8);
|
|
||||||
assertEq(fixed.length, 2);
|
|
||||||
assertEq(fixed.byteLength, 2);
|
|
||||||
assertEq(fixed.byteOffset, 1);
|
|
||||||
assertEq(fixed[0], 11);
|
|
||||||
assertEq(fixed[1], 0);
|
|
||||||
tracking[6] = 66;
|
|
||||||
assertEq(new Uint8Array(rab)[6], 66);
|
|
||||||
|
|
||||||
var dv = new DataView(rab, 4);
|
|
||||||
assertEq(dv.byteOffset, 4);
|
|
||||||
assertEq(dv.byteLength, 4);
|
|
||||||
dv.setUint8(0, 44);
|
|
||||||
assertEq(tracking[4], 44);
|
|
||||||
|
|
||||||
rab.resize(3);
|
|
||||||
assertThrowsInstanceOf(() => dv.byteOffset, TypeError);
|
|
||||||
assertThrowsInstanceOf(() => dv.byteLength, TypeError);
|
|
||||||
assertThrowsInstanceOf(() => dv.getUint8(0), TypeError);
|
|
||||||
|
|
||||||
rab.resize(6);
|
|
||||||
assertEq(dv.byteOffset, 4);
|
|
||||||
assertEq(dv.byteLength, 2);
|
|
||||||
assertEq(dv.getUint8(0), 0);
|
|
||||||
|
|
||||||
var fixedDv = new DataView(rab, 4, 2);
|
|
||||||
rab.resize(5);
|
|
||||||
assertThrowsInstanceOf(() => fixedDv.byteOffset, TypeError);
|
|
||||||
assertThrowsInstanceOf(() => fixedDv.byteLength, TypeError);
|
|
||||||
assertThrowsInstanceOf(() => fixedDv.getUint8(0), TypeError);
|
|
||||||
rab.resize(6);
|
|
||||||
assertEq(fixedDv.byteOffset, 4);
|
|
||||||
assertEq(fixedDv.byteLength, 2);
|
|
||||||
|
|
||||||
var methodRab = new ArrayBuffer(4, { maxByteLength: 8 });
|
|
||||||
var methodFixed = new Uint8Array(methodRab, 2, 2);
|
|
||||||
methodRab.resize(2);
|
|
||||||
[
|
|
||||||
() => methodFixed.at(0),
|
|
||||||
() => methodFixed.copyWithin(0, 0),
|
|
||||||
() => methodFixed.entries(),
|
|
||||||
() => methodFixed.every(x => true),
|
|
||||||
() => methodFixed.fill(1),
|
|
||||||
() => methodFixed.filter(x => true),
|
|
||||||
() => methodFixed.find(x => true),
|
|
||||||
() => methodFixed.findIndex(x => true),
|
|
||||||
() => methodFixed.findLast(x => true),
|
|
||||||
() => methodFixed.findLastIndex(x => true),
|
|
||||||
() => methodFixed.forEach(x => x),
|
|
||||||
() => methodFixed.includes(0),
|
|
||||||
() => methodFixed.indexOf(0),
|
|
||||||
() => methodFixed.join(","),
|
|
||||||
() => methodFixed.keys(),
|
|
||||||
() => methodFixed.lastIndexOf(0),
|
|
||||||
() => methodFixed.map(x => x),
|
|
||||||
() => methodFixed.reduce((a, b) => a + b, 0),
|
|
||||||
() => methodFixed.reduceRight((a, b) => a + b, 0),
|
|
||||||
() => methodFixed.reverse(),
|
|
||||||
() => methodFixed.set([1], 0),
|
|
||||||
() => methodFixed.slice(),
|
|
||||||
() => methodFixed.some(x => true),
|
|
||||||
() => methodFixed.sort(),
|
|
||||||
() => methodFixed.subarray(),
|
|
||||||
() => methodFixed.toLocaleString(),
|
|
||||||
() => methodFixed.toReversed(),
|
|
||||||
() => methodFixed.toSorted(),
|
|
||||||
() => methodFixed.toString(),
|
|
||||||
() => methodFixed.values(),
|
|
||||||
() => methodFixed.with(0, 1),
|
|
||||||
() => methodFixed[Symbol.iterator](),
|
|
||||||
].forEach(fn => assertThrowsInstanceOf(fn, TypeError));
|
|
||||||
|
|
||||||
methodRab.resize(4);
|
|
||||||
assertEq(methodFixed.length, 2);
|
|
||||||
|
|
||||||
var sourceRab = new ArrayBuffer(4, { maxByteLength: 8 });
|
|
||||||
var oobSource = new Uint8Array(sourceRab, 2, 2);
|
|
||||||
sourceRab.resize(2);
|
|
||||||
assertThrowsInstanceOf(() => new Uint8Array(oobSource), TypeError);
|
|
||||||
assertThrowsInstanceOf(() => new Uint16Array(oobSource), TypeError);
|
|
||||||
assertThrowsInstanceOf(() => new Uint8Array(4).set(oobSource), TypeError);
|
|
||||||
sourceRab.resize(4);
|
|
||||||
assertEq(new Uint8Array(oobSource).length, 2);
|
|
||||||
|
|
||||||
var ctorRab = new ArrayBuffer(8, { maxByteLength: 8 });
|
|
||||||
var ShrinkingNewTarget = new Proxy(function() {}, {
|
|
||||||
get(target, prop, receiver) {
|
|
||||||
if (prop === "prototype") {
|
|
||||||
ctorRab.resize(2);
|
|
||||||
return DataView.prototype;
|
|
||||||
}
|
|
||||||
return Reflect.get(target, prop, receiver);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
assertThrowsInstanceOf(() => Reflect.construct(DataView, [ctorRab, 4], ShrinkingNewTarget),
|
|
||||||
RangeError);
|
|
||||||
|
|
||||||
var fixedCtorRab = new ArrayBuffer(8, { maxByteLength: 8 });
|
|
||||||
var FixedShrinkingNewTarget = new Proxy(function() {}, {
|
|
||||||
get(target, prop, receiver) {
|
|
||||||
if (prop === "prototype") {
|
|
||||||
fixedCtorRab.resize(5);
|
|
||||||
return DataView.prototype;
|
|
||||||
}
|
|
||||||
return Reflect.get(target, prop, receiver);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
assertThrowsInstanceOf(() => Reflect.construct(DataView, [fixedCtorRab, 4, 2],
|
|
||||||
FixedShrinkingNewTarget),
|
|
||||||
RangeError);
|
|
||||||
|
|
||||||
var gsab = new SharedArrayBuffer(4, { maxByteLength: 16 });
|
|
||||||
var sharedTracking = new Uint8Array(gsab);
|
|
||||||
assertEq(sharedTracking.length, 4);
|
|
||||||
gsab.grow(8);
|
|
||||||
assertEq(sharedTracking.length, 8);
|
|
||||||
sharedTracking[6] = 33;
|
|
||||||
assertEq(new Uint8Array(gsab)[6], 33);
|
|
||||||
|
|
||||||
var sharedDv = new DataView(gsab);
|
|
||||||
assertEq(sharedDv.buffer, gsab);
|
|
||||||
assertEq(sharedDv.byteOffset, 0);
|
|
||||||
assertEq(sharedDv.byteLength, 8);
|
|
||||||
sharedDv.setUint8(7, 99);
|
|
||||||
assertEq(sharedTracking[7], 99);
|
|
||||||
gsab.grow(12);
|
|
||||||
assertEq(sharedDv.byteLength, 12);
|
|
||||||
assertEq(sharedDv.getUint8(7), 99);
|
|
||||||
|
|
||||||
var fixedSharedDv = new DataView(gsab, 4, 2);
|
|
||||||
assertEq(fixedSharedDv.byteOffset, 4);
|
|
||||||
assertEq(fixedSharedDv.byteLength, 2);
|
|
||||||
gsab.grow(16);
|
|
||||||
assertEq(fixedSharedDv.byteOffset, 4);
|
|
||||||
assertEq(fixedSharedDv.byteLength, 2);
|
|
||||||
|
|
||||||
function readLength(view) {
|
|
||||||
return view.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
function readElement(view, index) {
|
|
||||||
return view[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeElement(view, index, value) {
|
|
||||||
view[index] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
var normal = new Uint8Array(4);
|
|
||||||
normal[0] = 7;
|
|
||||||
for (var i = 0; i < 2000; i++) {
|
|
||||||
assertEq(readLength(normal), 4);
|
|
||||||
assertEq(readElement(normal, 0), 7);
|
|
||||||
writeElement(normal, 1, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
var icRab = new ArrayBuffer(4, { maxByteLength: 8 });
|
|
||||||
var icTracking = new Uint8Array(icRab);
|
|
||||||
icTracking[0] = 9;
|
|
||||||
assertEq(readLength(icTracking), 4);
|
|
||||||
assertEq(readElement(icTracking, 0), 9);
|
|
||||||
icRab.resize(0);
|
|
||||||
assertEq(readLength(icTracking), 0);
|
|
||||||
assertEq(readElement(icTracking, 0), undefined);
|
|
||||||
writeElement(icTracking, 0, 1);
|
|
||||||
icRab.resize(4);
|
|
||||||
assertEq(readLength(icTracking), 4);
|
|
||||||
assertEq(readElement(icTracking, 0), 0);
|
|
||||||
writeElement(icTracking, 0, 12);
|
|
||||||
assertEq(readElement(icTracking, 0), 12);
|
|
||||||
|
|
||||||
var icFixed = new Uint8Array(icRab, 1, 2);
|
|
||||||
assertEq(readLength(icFixed), 2);
|
|
||||||
icRab.resize(2);
|
|
||||||
assertEq(readLength(icFixed), 0);
|
|
||||||
assertEq(readElement(icFixed, 0), undefined);
|
|
||||||
writeElement(icFixed, 0, 55);
|
|
||||||
icRab.resize(4);
|
|
||||||
assertEq(readLength(icFixed), 2);
|
|
||||||
assertEq(readElement(icFixed, 0), 0);
|
|
||||||
|
|
||||||
var icGsab = new SharedArrayBuffer(4, { maxByteLength: 8 });
|
|
||||||
var icSharedTracking = new Uint8Array(icGsab);
|
|
||||||
assertEq(readLength(icSharedTracking), 4);
|
|
||||||
icGsab.grow(8);
|
|
||||||
assertEq(readLength(icSharedTracking), 8);
|
|
||||||
writeElement(icSharedTracking, 5, 77);
|
|
||||||
assertEq(readElement(icSharedTracking, 5), 77);
|
|
||||||
|
|
||||||
if (typeof reportCompare === "function")
|
|
||||||
reportCompare(true, true);
|
|
||||||
|
|
@ -1,77 +0,0 @@
|
||||||
// |reftest| skip-if(!this.SharedArrayBuffer || !this.Atomics || !this.drainJobQueue)
|
|
||||||
|
|
||||||
if (typeof SharedArrayBuffer === "function" && typeof Atomics === "object" &&
|
|
||||||
typeof drainJobQueue === "function") {
|
|
||||||
const sab = new SharedArrayBuffer(4);
|
|
||||||
const i32 = new Int32Array(sab);
|
|
||||||
|
|
||||||
let result = Atomics.waitAsync(i32, 0, 1, 10);
|
|
||||||
assertEq(result.async, false);
|
|
||||||
assertEq(result.value, "not-equal");
|
|
||||||
|
|
||||||
result = Atomics.waitAsync(i32, 0, 0, 0);
|
|
||||||
assertEq(result.async, false);
|
|
||||||
assertEq(result.value, "timed-out");
|
|
||||||
|
|
||||||
result = Atomics.waitAsync(i32, 0, 0);
|
|
||||||
assertEq(result.async, true);
|
|
||||||
let notified;
|
|
||||||
result.value.then(value => {
|
|
||||||
notified = value;
|
|
||||||
});
|
|
||||||
assertEq(Atomics.notify(i32, 0, 1), 1);
|
|
||||||
drainJobQueue();
|
|
||||||
assertEq(notified, "ok");
|
|
||||||
|
|
||||||
result = Atomics.waitAsync(i32, 0, 0, 1);
|
|
||||||
assertEq(result.async, true);
|
|
||||||
let timedOut;
|
|
||||||
result.value.then(value => {
|
|
||||||
timedOut = value;
|
|
||||||
});
|
|
||||||
drainJobQueue();
|
|
||||||
assertEq(timedOut, "timed-out");
|
|
||||||
|
|
||||||
if (typeof BigInt64Array === "function") {
|
|
||||||
const bigSab = new SharedArrayBuffer(16);
|
|
||||||
const i64 = new BigInt64Array(bigSab);
|
|
||||||
const u64 = new BigUint64Array(bigSab);
|
|
||||||
|
|
||||||
assertEq(Atomics.store(i64, 0, -1n), -1n);
|
|
||||||
assertEq(Atomics.load(i64, 0), -1n);
|
|
||||||
assertEq(Atomics.load(u64, 0), 18446744073709551615n);
|
|
||||||
assertEq(Atomics.exchange(i64, 0, 7n), -1n);
|
|
||||||
assertEq(Atomics.compareExchange(i64, 0, 7n, 10n), 7n);
|
|
||||||
assertEq(Atomics.add(i64, 0, 5n), 10n);
|
|
||||||
assertEq(Atomics.load(i64, 0), 15n);
|
|
||||||
assertEq(Atomics.sub(i64, 0, 20n), 15n);
|
|
||||||
assertEq(Atomics.load(i64, 0), -5n);
|
|
||||||
assertEq(Atomics.and(u64, 0, 7n), 18446744073709551611n);
|
|
||||||
assertEq(Atomics.or(u64, 0, 8n), 3n);
|
|
||||||
assertEq(Atomics.xor(u64, 0, 15n), 11n);
|
|
||||||
|
|
||||||
assertThrowsInstanceOf(() => Atomics.waitAsync(u64, 0, 0n), TypeError);
|
|
||||||
|
|
||||||
result = Atomics.waitAsync(i64, 1, 1n, 10);
|
|
||||||
assertEq(result.async, false);
|
|
||||||
assertEq(result.value, "not-equal");
|
|
||||||
|
|
||||||
result = Atomics.waitAsync(i64, 1, 0n, 0);
|
|
||||||
assertEq(result.async, false);
|
|
||||||
assertEq(result.value, "timed-out");
|
|
||||||
|
|
||||||
let offsetView = new BigInt64Array(bigSab, 8);
|
|
||||||
result = Atomics.waitAsync(offsetView, 0, 0n);
|
|
||||||
assertEq(result.async, true);
|
|
||||||
notified = undefined;
|
|
||||||
result.value.then(value => {
|
|
||||||
notified = value;
|
|
||||||
});
|
|
||||||
assertEq(Atomics.notify(i64, 1, 1), 1);
|
|
||||||
drainJobQueue();
|
|
||||||
assertEq(notified, "ok");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof reportCompare === "function")
|
|
||||||
reportCompare(true, true);
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
// |reftest| skip-if(!Promise.withResolvers)
|
|
||||||
|
|
||||||
var desc = Object.getOwnPropertyDescriptor(Promise, "withResolvers");
|
|
||||||
assertEq(desc.enumerable, false);
|
|
||||||
assertEq(desc.configurable, true);
|
|
||||||
assertEq(desc.writable, true);
|
|
||||||
assertEq(Promise.withResolvers.length, 0);
|
|
||||||
assertEq(Promise.withResolvers.name, "withResolvers");
|
|
||||||
|
|
||||||
var capability = Promise.withResolvers();
|
|
||||||
assertEq(capability.promise instanceof Promise, true);
|
|
||||||
assertEq(typeof capability.resolve, "function");
|
|
||||||
assertEq(typeof capability.reject, "function");
|
|
||||||
assertEqArray(Object.keys(capability), ["promise", "resolve", "reject"]);
|
|
||||||
|
|
||||||
capability.resolve(42);
|
|
||||||
capability.promise.then(v => assertEq(v, 42));
|
|
||||||
|
|
||||||
class MyPromise extends Promise {}
|
|
||||||
var subCapability = Promise.withResolvers.call(MyPromise);
|
|
||||||
assertEq(subCapability.promise instanceof MyPromise, true);
|
|
||||||
subCapability.reject("rejected");
|
|
||||||
subCapability.promise.then(
|
|
||||||
() => { throw new Error("expected rejection"); },
|
|
||||||
reason => assertEq(reason, "rejected")
|
|
||||||
);
|
|
||||||
|
|
||||||
assertThrowsInstanceOf(() => Promise.withResolvers.call({}), TypeError);
|
|
||||||
|
|
||||||
if (typeof reportCompare === "function")
|
|
||||||
reportCompare(0, 0);
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
// |reftest| skip-if(!this.SharedArrayBuffer)
|
|
||||||
|
|
||||||
if (typeof SharedArrayBuffer === "function") {
|
|
||||||
const fixed = new SharedArrayBuffer(4);
|
|
||||||
assertEq(fixed.byteLength, 4);
|
|
||||||
assertEq(fixed.maxByteLength, 4);
|
|
||||||
assertEq(fixed.growable, false);
|
|
||||||
assertThrowsInstanceOf(() => fixed.grow(4), TypeError);
|
|
||||||
|
|
||||||
assertThrowsInstanceOf(() => new SharedArrayBuffer(-1), RangeError);
|
|
||||||
assertThrowsInstanceOf(() => new SharedArrayBuffer(8, {maxByteLength: 4}), RangeError);
|
|
||||||
|
|
||||||
let optionGetterCalled = false;
|
|
||||||
const growable = new SharedArrayBuffer(4, {
|
|
||||||
get maxByteLength() {
|
|
||||||
optionGetterCalled = true;
|
|
||||||
return 16;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
assertEq(optionGetterCalled, true);
|
|
||||||
assertEq(growable.byteLength, 4);
|
|
||||||
assertEq(growable.maxByteLength, 16);
|
|
||||||
assertEq(growable.growable, true);
|
|
||||||
|
|
||||||
const before = new Uint8Array(growable);
|
|
||||||
before[0] = 37;
|
|
||||||
assertEq(growable.grow(12), undefined);
|
|
||||||
assertEq(growable.byteLength, 12);
|
|
||||||
assertEq(growable.maxByteLength, 16);
|
|
||||||
|
|
||||||
const after = new Uint8Array(growable);
|
|
||||||
assertEq(after.length, 12);
|
|
||||||
assertEq(after[0], 37);
|
|
||||||
|
|
||||||
assertThrowsInstanceOf(() => growable.grow(11), RangeError);
|
|
||||||
assertThrowsInstanceOf(() => growable.grow(17), RangeError);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof reportCompare === "function")
|
|
||||||
reportCompare(true, true);
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
// |reftest| skip-if(!String.prototype.isWellFormed||!String.prototype.toWellFormed)
|
|
||||||
|
|
||||||
assertEq("".isWellFormed(), true);
|
|
||||||
assertEq("abc".isWellFormed(), true);
|
|
||||||
assertEq("\uD83D\uDE00".isWellFormed(), true);
|
|
||||||
assertEq("\uD800".isWellFormed(), false);
|
|
||||||
assertEq("\uDC00".isWellFormed(), false);
|
|
||||||
assertEq("\uD800a".isWellFormed(), false);
|
|
||||||
assertEq("a\uDC00".isWellFormed(), false);
|
|
||||||
assertEq("\uD800\uD800\uDC00".isWellFormed(), false);
|
|
||||||
|
|
||||||
assertEq("abc".toWellFormed(), "abc");
|
|
||||||
assertEq("\uD83D\uDE00".toWellFormed(), "\uD83D\uDE00");
|
|
||||||
assertEq("\uD800".toWellFormed(), "\uFFFD");
|
|
||||||
assertEq("\uDC00".toWellFormed(), "\uFFFD");
|
|
||||||
assertEq("\uD800a\uDC00".toWellFormed(), "\uFFFDa\uFFFD");
|
|
||||||
assertEq("\uD800\uD800\uDC00".toWellFormed(), "\uFFFD\uD800\uDC00");
|
|
||||||
|
|
||||||
assertEq(String.prototype.isWellFormed.call(123), true);
|
|
||||||
assertEq(String.prototype.toWellFormed.call({ toString() { return "\uD800x"; } }), "\uFFFDx");
|
|
||||||
|
|
||||||
assertThrowsInstanceOf(() => String.prototype.isWellFormed.call(null), TypeError);
|
|
||||||
assertThrowsInstanceOf(() => String.prototype.toWellFormed.call(undefined), TypeError);
|
|
||||||
|
|
||||||
if (typeof reportCompare === "function")
|
|
||||||
reportCompare(0, 0);
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
var key = Symbol("weak");
|
|
||||||
var map = new WeakMap();
|
|
||||||
assertEq(map.has(key), false);
|
|
||||||
assertEq(map.get(key), undefined);
|
|
||||||
assertEq(map.set(key, 13), map);
|
|
||||||
assertEq(map.has(key), true);
|
|
||||||
assertEq(map.get(key), 13);
|
|
||||||
assertEq(map.delete(key), true);
|
|
||||||
assertEq(map.has(key), false);
|
|
||||||
|
|
||||||
var constructedKey = Symbol("constructed");
|
|
||||||
var constructed = new WeakMap([[constructedKey, 7]]);
|
|
||||||
assertEq(constructed.get(constructedKey), 7);
|
|
||||||
|
|
||||||
var registered = Symbol.for("registered");
|
|
||||||
assertEq(map.has(registered), false);
|
|
||||||
assertEq(map.get(registered), undefined);
|
|
||||||
assertEq(map.delete(registered), false);
|
|
||||||
assertThrowsInstanceOf(() => map.set(registered, 1), TypeError);
|
|
||||||
assertThrowsInstanceOf(() => new WeakMap([[registered, 1]]), TypeError);
|
|
||||||
|
|
||||||
var setKey = Symbol("set");
|
|
||||||
var set = new WeakSet([setKey]);
|
|
||||||
assertEq(set.has(setKey), true);
|
|
||||||
assertEq(set.delete(setKey), true);
|
|
||||||
assertEq(set.has(setKey), false);
|
|
||||||
assertEq(set.add(setKey), set);
|
|
||||||
assertEq(set.has(setKey), true);
|
|
||||||
|
|
||||||
assertEq(set.has(registered), false);
|
|
||||||
assertEq(set.delete(registered), false);
|
|
||||||
assertThrowsInstanceOf(() => set.add(registered), TypeError);
|
|
||||||
assertThrowsInstanceOf(() => new WeakSet([registered]), TypeError);
|
|
||||||
|
|
||||||
if (typeof reportCompare === "function")
|
|
||||||
reportCompare(0, 0);
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
// |reftest| skip-if(!Object.groupBy||!Map.groupBy)
|
|
||||||
|
|
||||||
var objectGroups = Object.groupBy(["a", "bb", "c"], value => value.length);
|
|
||||||
assertEq(Object.getPrototypeOf(objectGroups), null);
|
|
||||||
assertEqArray(objectGroups["1"], ["a", "c"]);
|
|
||||||
assertEqArray(objectGroups["2"], ["bb"]);
|
|
||||||
|
|
||||||
var symbol = Symbol();
|
|
||||||
var symbolGroups = Object.groupBy([1, 2], value => value === 1 ? symbol : "__proto__");
|
|
||||||
assertEqArray(symbolGroups[symbol], [1]);
|
|
||||||
assertEqArray(symbolGroups.__proto__, [2]);
|
|
||||||
|
|
||||||
var indexes = [];
|
|
||||||
var mapGroups = Map.groupBy(["a", "bb", "c"], (value, index) => {
|
|
||||||
indexes.push(index);
|
|
||||||
return value.length;
|
|
||||||
});
|
|
||||||
assertEq(mapGroups instanceof Map, true);
|
|
||||||
assertEqArray(indexes, [0, 1, 2]);
|
|
||||||
assertEqArray(mapGroups.get(1), ["a", "c"]);
|
|
||||||
assertEqArray(mapGroups.get(2), ["bb"]);
|
|
||||||
|
|
||||||
var key = {};
|
|
||||||
var objectKeyGroups = Map.groupBy([1, 2], value => value === 1 ? key : NaN);
|
|
||||||
assertEqArray(objectKeyGroups.get(key), [1]);
|
|
||||||
assertEqArray(objectKeyGroups.get(NaN), [2]);
|
|
||||||
|
|
||||||
assertThrowsInstanceOf(() => Object.groupBy(null, x => x), TypeError);
|
|
||||||
assertThrowsInstanceOf(() => Map.groupBy(undefined, x => x), TypeError);
|
|
||||||
assertThrowsInstanceOf(() => Object.groupBy([], null), TypeError);
|
|
||||||
assertThrowsInstanceOf(() => Map.groupBy([], null), TypeError);
|
|
||||||
|
|
||||||
if (typeof reportCompare === "function")
|
|
||||||
reportCompare(0, 0);
|
|
||||||
|
|
@ -22,7 +22,6 @@
|
||||||
# include <valgrind/memcheck.h>
|
# include <valgrind/memcheck.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include "jsapi.h"
|
#include "jsapi.h"
|
||||||
#include "jsarray.h"
|
#include "jsarray.h"
|
||||||
#include "jscntxt.h"
|
#include "jscntxt.h"
|
||||||
|
|
@ -46,7 +45,6 @@
|
||||||
#include "vm/Interpreter.h"
|
#include "vm/Interpreter.h"
|
||||||
#include "vm/SelfHosting.h"
|
#include "vm/SelfHosting.h"
|
||||||
#include "vm/SharedArrayObject.h"
|
#include "vm/SharedArrayObject.h"
|
||||||
#include "vm/TypedArrayObject.h"
|
|
||||||
#include "vm/WrapperObject.h"
|
#include "vm/WrapperObject.h"
|
||||||
#include "wasm/WasmSignalHandlers.h"
|
#include "wasm/WasmSignalHandlers.h"
|
||||||
#include "wasm/WasmTypes.h"
|
#include "wasm/WasmTypes.h"
|
||||||
|
|
@ -172,18 +170,12 @@ static const JSPropertySpec static_properties[] = {
|
||||||
|
|
||||||
|
|
||||||
static const JSFunctionSpec prototype_functions[] = {
|
static const JSFunctionSpec prototype_functions[] = {
|
||||||
JS_FN("resize", ArrayBufferObject::fun_resize, 1, 0),
|
|
||||||
JS_SELF_HOSTED_FN("slice", "ArrayBufferSlice", 2, 0),
|
JS_SELF_HOSTED_FN("slice", "ArrayBufferSlice", 2, 0),
|
||||||
JS_FN("transfer", ArrayBufferObject::fun_transfer, 0, 0),
|
|
||||||
JS_FN("transferToFixedLength", ArrayBufferObject::fun_transferToFixedLength, 0, 0),
|
|
||||||
JS_FS_END
|
JS_FS_END
|
||||||
};
|
};
|
||||||
|
|
||||||
static const JSPropertySpec prototype_properties[] = {
|
static const JSPropertySpec prototype_properties[] = {
|
||||||
JS_PSG("byteLength", ArrayBufferObject::byteLengthGetter, 0),
|
JS_PSG("byteLength", ArrayBufferObject::byteLengthGetter, 0),
|
||||||
JS_PSG("detached", ArrayBufferObject::detachedGetter, 0),
|
|
||||||
JS_PSG("maxByteLength", ArrayBufferObject::maxByteLengthGetter, 0),
|
|
||||||
JS_PSG("resizable", ArrayBufferObject::resizableGetter, 0),
|
|
||||||
JS_STRING_SYM_PS(toStringTag, "ArrayBuffer", JSPROP_READONLY),
|
JS_STRING_SYM_PS(toStringTag, "ArrayBuffer", JSPROP_READONLY),
|
||||||
JS_PS_END
|
JS_PS_END
|
||||||
};
|
};
|
||||||
|
|
@ -260,52 +252,6 @@ ArrayBufferObject::byteLengthGetter(JSContext* cx, unsigned argc, Value* vp)
|
||||||
return CallNonGenericMethod<IsArrayBuffer, byteLengthGetterImpl>(cx, args);
|
return CallNonGenericMethod<IsArrayBuffer, byteLengthGetterImpl>(cx, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_ALWAYS_INLINE bool
|
|
||||||
ArrayBufferObject::detachedGetterImpl(JSContext* cx, const CallArgs& args)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(IsArrayBuffer(args.thisv()));
|
|
||||||
args.rval().setBoolean(args.thisv().toObject().as<ArrayBufferObject>().isDetached());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ArrayBufferObject::detachedGetter(JSContext* cx, unsigned argc, Value* vp)
|
|
||||||
{
|
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
|
||||||
return CallNonGenericMethod<IsArrayBuffer, detachedGetterImpl>(cx, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ALWAYS_INLINE bool
|
|
||||||
ArrayBufferObject::maxByteLengthGetterImpl(JSContext* cx, const CallArgs& args)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(IsArrayBuffer(args.thisv()));
|
|
||||||
ArrayBufferObject& buffer = args.thisv().toObject().as<ArrayBufferObject>();
|
|
||||||
args.rval().setInt32(buffer.isDetached() ? 0 : int32_t(buffer.maxByteLength()));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ArrayBufferObject::maxByteLengthGetter(JSContext* cx, unsigned argc, Value* vp)
|
|
||||||
{
|
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
|
||||||
return CallNonGenericMethod<IsArrayBuffer, maxByteLengthGetterImpl>(cx, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ALWAYS_INLINE bool
|
|
||||||
ArrayBufferObject::resizableGetterImpl(JSContext* cx, const CallArgs& args)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(IsArrayBuffer(args.thisv()));
|
|
||||||
args.rval().setBoolean(args.thisv().toObject().as<ArrayBufferObject>().isResizable());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ArrayBufferObject::resizableGetter(JSContext* cx, unsigned argc, Value* vp)
|
|
||||||
{
|
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
|
||||||
return CallNonGenericMethod<IsArrayBuffer, resizableGetterImpl>(cx, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ArrayBuffer.isView(obj); ES6 (Dec 2013 draft) 24.1.3.1
|
* ArrayBuffer.isView(obj); ES6 (Dec 2013 draft) 24.1.3.1
|
||||||
*/
|
*/
|
||||||
|
|
@ -318,39 +264,6 @@ ArrayBufferObject::fun_isView(JSContext* cx, unsigned argc, Value* vp)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
|
||||||
GetArrayBufferMaxByteLengthOption(JSContext* cx, HandleValue options,
|
|
||||||
uint32_t byteLength, uint32_t* maxByteLength,
|
|
||||||
bool* resizable)
|
|
||||||
{
|
|
||||||
*maxByteLength = byteLength;
|
|
||||||
*resizable = false;
|
|
||||||
|
|
||||||
if (!options.isObject())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
RootedObject opts(cx, &options.toObject());
|
|
||||||
RootedValue maxByteLengthValue(cx);
|
|
||||||
if (!GetProperty(cx, opts, opts, cx->names().maxByteLength, &maxByteLengthValue))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (maxByteLengthValue.isUndefined())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
uint64_t max;
|
|
||||||
if (!ToIndex(cx, maxByteLengthValue, &max))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (max > INT32_MAX || max < byteLength) {
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
*maxByteLength = uint32_t(max);
|
|
||||||
*resizable = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ES2017 draft 24.1.2.1
|
// ES2017 draft 24.1.2.1
|
||||||
bool
|
bool
|
||||||
|
|
@ -374,22 +287,12 @@ ArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value* vp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3.
|
// Step 3.
|
||||||
uint32_t maxByteLength;
|
|
||||||
bool resizable;
|
|
||||||
if (!GetArrayBufferMaxByteLengthOption(cx, args.get(1), uint32_t(byteLength),
|
|
||||||
&maxByteLength, &resizable))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 4.
|
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
RootedObject newTarget(cx, &args.newTarget().toObject());
|
RootedObject newTarget(cx, &args.newTarget().toObject());
|
||||||
if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
|
if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
JSObject* bufobj = create(cx, uint32_t(byteLength), BufferContents::createPlain(nullptr),
|
JSObject* bufobj = create(cx, uint32_t(byteLength), proto);
|
||||||
OwnsData, proto, GenericObject, maxByteLength, resizable);
|
|
||||||
if (!bufobj)
|
if (!bufobj)
|
||||||
return false;
|
return false;
|
||||||
args.rval().setObject(*bufobj);
|
args.rval().setObject(*bufobj);
|
||||||
|
|
@ -399,66 +302,13 @@ ArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value* vp)
|
||||||
static ArrayBufferObject::BufferContents
|
static ArrayBufferObject::BufferContents
|
||||||
AllocateArrayBufferContents(JSContext* cx, uint32_t nbytes)
|
AllocateArrayBufferContents(JSContext* cx, uint32_t nbytes)
|
||||||
{
|
{
|
||||||
uint8_t* p = cx->runtime()->pod_callocCanGC<uint8_t>(nbytes ? nbytes : 1);
|
uint8_t* p = cx->runtime()->pod_callocCanGC<uint8_t>(nbytes);
|
||||||
if (!p)
|
if (!p)
|
||||||
ReportOutOfMemory(cx);
|
ReportOutOfMemory(cx);
|
||||||
|
|
||||||
return ArrayBufferObject::BufferContents::create<ArrayBufferObject::PLAIN>(p);
|
return ArrayBufferObject::BufferContents::create<ArrayBufferObject::PLAIN>(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
|
||||||
ReportArrayBufferNotResizable(JSContext* cx)
|
|
||||||
{
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARRAYBUFFER_NOT_RESIZABLE);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
ReportArrayBufferCannotDetach(JSContext* cx)
|
|
||||||
{
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARRAYBUFFER_CANNOT_DETACH);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
ReportArrayBufferLengthOutOfRange(JSContext* cx)
|
|
||||||
{
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
ArrayBufferViewFits(ArrayBufferViewObject* view, uint32_t newByteLength)
|
|
||||||
{
|
|
||||||
if (view->is<DataViewObject>()) {
|
|
||||||
DataViewObject& dataView = view->as<DataViewObject>();
|
|
||||||
uint32_t byteOffset = dataView.byteOffsetMaybeOutOfBounds();
|
|
||||||
if (byteOffset > newByteLength)
|
|
||||||
return false;
|
|
||||||
uint32_t byteLength = dataView.isLengthTracking()
|
|
||||||
? newByteLength - byteOffset
|
|
||||||
: dataView.fixedByteLengthMaybeOutOfBounds();
|
|
||||||
return byteOffset <= newByteLength && byteLength <= newByteLength - byteOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (view->is<TypedArrayObject>()) {
|
|
||||||
TypedArrayObject& typedArray = view->as<TypedArrayObject>();
|
|
||||||
if (typedArray.isSharedMemory())
|
|
||||||
return true;
|
|
||||||
uint32_t byteOffset = typedArray.byteOffsetMaybeOutOfBounds();
|
|
||||||
if (byteOffset > newByteLength)
|
|
||||||
return false;
|
|
||||||
uint32_t byteLength = typedArray.isLengthTracking()
|
|
||||||
? newByteLength - byteOffset
|
|
||||||
: typedArray.fixedLengthMaybeOutOfBounds() *
|
|
||||||
typedArray.bytesPerElement();
|
|
||||||
return byteOffset <= newByteLength && byteLength <= newByteLength - byteOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Outline typed objects don't have a recoverable fixed byte range here.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
NoteViewBufferWasDetached(ArrayBufferViewObject* view,
|
NoteViewBufferWasDetached(ArrayBufferViewObject* view,
|
||||||
ArrayBufferObject::BufferContents newContents,
|
ArrayBufferObject::BufferContents newContents,
|
||||||
|
|
@ -541,8 +391,7 @@ ArrayBufferObject::setNewData(FreeOp* fop, BufferContents newContents, OwnsState
|
||||||
|
|
||||||
void
|
void
|
||||||
ArrayBufferObject::changeViewContents(JSContext* cx, ArrayBufferViewObject* view,
|
ArrayBufferObject::changeViewContents(JSContext* cx, ArrayBufferViewObject* view,
|
||||||
uint8_t* oldDataPointer, BufferContents newContents,
|
uint8_t* oldDataPointer, BufferContents newContents)
|
||||||
uint32_t newByteLength)
|
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!view->isSharedMemory());
|
MOZ_ASSERT(!view->isSharedMemory());
|
||||||
|
|
||||||
|
|
@ -553,18 +402,7 @@ ArrayBufferObject::changeViewContents(JSContext* cx, ArrayBufferViewObject* view
|
||||||
uint8_t* viewDataPointer = view->dataPointerUnshared(nogc);
|
uint8_t* viewDataPointer = view->dataPointerUnshared(nogc);
|
||||||
if (viewDataPointer) {
|
if (viewDataPointer) {
|
||||||
MOZ_ASSERT(newContents);
|
MOZ_ASSERT(newContents);
|
||||||
uint32_t offset;
|
ptrdiff_t offset = viewDataPointer - oldDataPointer;
|
||||||
if (view->is<DataViewObject>()) {
|
|
||||||
offset = view->as<DataViewObject>().byteOffsetMaybeOutOfBounds();
|
|
||||||
} else if (view->is<TypedArrayObject>()) {
|
|
||||||
offset = view->as<TypedArrayObject>().byteOffsetMaybeOutOfBounds();
|
|
||||||
} else {
|
|
||||||
ptrdiff_t oldOffset = viewDataPointer - oldDataPointer;
|
|
||||||
MOZ_ASSERT(oldOffset >= 0);
|
|
||||||
offset = uint32_t(oldOffset);
|
|
||||||
}
|
|
||||||
if (offset > newByteLength)
|
|
||||||
offset = 0;
|
|
||||||
viewDataPointer = static_cast<uint8_t*>(newContents.data()) + offset;
|
viewDataPointer = static_cast<uint8_t*>(newContents.data()) + offset;
|
||||||
view->setDataPointerUnshared(viewDataPointer);
|
view->setDataPointerUnshared(viewDataPointer);
|
||||||
}
|
}
|
||||||
|
|
@ -590,180 +428,10 @@ ArrayBufferObject::changeContents(JSContext* cx, BufferContents newContents,
|
||||||
auto& innerViews = cx->compartment()->innerViews.get();
|
auto& innerViews = cx->compartment()->innerViews.get();
|
||||||
if (InnerViewTable::ViewVector* views = innerViews.maybeViewsUnbarriered(this)) {
|
if (InnerViewTable::ViewVector* views = innerViews.maybeViewsUnbarriered(this)) {
|
||||||
for (size_t i = 0; i < views->length(); i++)
|
for (size_t i = 0; i < views->length(); i++)
|
||||||
changeViewContents(cx, (*views)[i], oldDataPointer, newContents, byteLength());
|
changeViewContents(cx, (*views)[i], oldDataPointer, newContents);
|
||||||
}
|
}
|
||||||
if (firstView())
|
if (firstView())
|
||||||
changeViewContents(cx, firstView(), oldDataPointer, newContents, byteLength());
|
changeViewContents(cx, firstView(), oldDataPointer, newContents);
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ArrayBufferObject::changeContentsForResize(JSContext* cx, BufferContents newContents,
|
|
||||||
OwnsState ownsState, uint32_t newByteLength)
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(!isWasm());
|
|
||||||
MOZ_ASSERT(!forInlineTypedObject());
|
|
||||||
|
|
||||||
uint8_t* oldDataPointer = dataPointer();
|
|
||||||
setNewData(cx->runtime()->defaultFreeOp(), newContents, ownsState);
|
|
||||||
setByteLength(newByteLength);
|
|
||||||
|
|
||||||
auto& innerViews = cx->compartment()->innerViews.get();
|
|
||||||
if (InnerViewTable::ViewVector* views = innerViews.maybeViewsUnbarriered(this)) {
|
|
||||||
for (size_t i = 0; i < views->length(); i++) {
|
|
||||||
ArrayBufferViewObject* view = (*views)[i];
|
|
||||||
if (view->is<DataViewObject>() || view->is<TypedArrayObject>())
|
|
||||||
changeViewContents(cx, view, oldDataPointer, newContents, newByteLength);
|
|
||||||
else if (ArrayBufferViewFits(view, newByteLength))
|
|
||||||
changeViewContents(cx, view, oldDataPointer, newContents, newByteLength);
|
|
||||||
else
|
|
||||||
NoteViewBufferWasDetached(view, newContents, cx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (firstView()) {
|
|
||||||
if (firstView()->is<DataViewObject>() || firstView()->is<TypedArrayObject>())
|
|
||||||
changeViewContents(cx, firstView(), oldDataPointer, newContents, newByteLength);
|
|
||||||
else if (ArrayBufferViewFits(firstView(), newByteLength))
|
|
||||||
changeViewContents(cx, firstView(), oldDataPointer, newContents, newByteLength);
|
|
||||||
else
|
|
||||||
NoteViewBufferWasDetached(firstView(), newContents, cx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
ResizeArrayBuffer(JSContext* cx, Handle<ArrayBufferObject*> buffer, uint32_t newByteLength)
|
|
||||||
{
|
|
||||||
if (!buffer->isResizable())
|
|
||||||
return ReportArrayBufferNotResizable(cx);
|
|
||||||
|
|
||||||
if (buffer->isDetached()) {
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newByteLength > buffer->maxByteLength())
|
|
||||||
return ReportArrayBufferLengthOutOfRange(cx);
|
|
||||||
|
|
||||||
if (!buffer->isPlain() || buffer->isPreparedForAsmJS() || buffer->forInlineTypedObject())
|
|
||||||
return ReportArrayBufferCannotDetach(cx);
|
|
||||||
|
|
||||||
if (newByteLength == buffer->byteLength())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
ArrayBufferObject::BufferContents newContents = AllocateArrayBufferContents(cx, newByteLength);
|
|
||||||
if (!newContents)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint32_t copyLength = std::min(newByteLength, buffer->byteLength());
|
|
||||||
if (copyLength > 0)
|
|
||||||
memcpy(newContents.data(), buffer->dataPointer(), copyLength);
|
|
||||||
|
|
||||||
buffer->changeContentsForResize(cx, newContents, ArrayBufferObject::OwnsData, newByteLength);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ArrayBufferObject::fun_resize_impl(JSContext* cx, const CallArgs& args)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(IsArrayBuffer(args.thisv()));
|
|
||||||
|
|
||||||
Rooted<ArrayBufferObject*> buffer(cx, &args.thisv().toObject().as<ArrayBufferObject>());
|
|
||||||
if (!buffer->isResizable())
|
|
||||||
return ReportArrayBufferNotResizable(cx);
|
|
||||||
|
|
||||||
uint64_t newByteLength;
|
|
||||||
if (!ToIndex(cx, args.get(0), &newByteLength))
|
|
||||||
return false;
|
|
||||||
if (newByteLength > INT32_MAX)
|
|
||||||
return ReportArrayBufferLengthOutOfRange(cx);
|
|
||||||
|
|
||||||
if (!ResizeArrayBuffer(cx, buffer, uint32_t(newByteLength)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
args.rval().setUndefined();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ArrayBufferObject::fun_resize(JSContext* cx, unsigned argc, Value* vp)
|
|
||||||
{
|
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
|
||||||
return CallNonGenericMethod<IsArrayBuffer, fun_resize_impl>(cx, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
ArrayBufferTransfer(JSContext* cx, const CallArgs& args, bool preserveResizability)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(IsArrayBuffer(args.thisv()));
|
|
||||||
Rooted<ArrayBufferObject*> buffer(cx, &args.thisv().toObject().as<ArrayBufferObject>());
|
|
||||||
|
|
||||||
uint32_t newByteLength = buffer->byteLength();
|
|
||||||
if (args.hasDefined(0)) {
|
|
||||||
uint64_t newLength;
|
|
||||||
if (!ToIndex(cx, args.get(0), &newLength))
|
|
||||||
return false;
|
|
||||||
if (newLength > INT32_MAX)
|
|
||||||
return ReportArrayBufferLengthOutOfRange(cx);
|
|
||||||
newByteLength = uint32_t(newLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer->isDetached()) {
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer->isWasm() || buffer->isPreparedForAsmJS())
|
|
||||||
return ReportArrayBufferCannotDetach(cx);
|
|
||||||
|
|
||||||
bool newResizable = preserveResizability && buffer->isResizable();
|
|
||||||
uint32_t newMaxByteLength = newResizable ? buffer->maxByteLength() : newByteLength;
|
|
||||||
if (newResizable && newByteLength > newMaxByteLength)
|
|
||||||
return ReportArrayBufferLengthOutOfRange(cx);
|
|
||||||
|
|
||||||
Rooted<ArrayBufferObject*> newBuffer(cx,
|
|
||||||
ArrayBufferObject::create(cx, newByteLength, ArrayBufferObject::BufferContents::createPlain(nullptr),
|
|
||||||
ArrayBufferObject::OwnsData, nullptr, GenericObject,
|
|
||||||
newMaxByteLength, newResizable));
|
|
||||||
if (!newBuffer)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint32_t copyLength = std::min(newByteLength, buffer->byteLength());
|
|
||||||
if (copyLength > 0)
|
|
||||||
memcpy(newBuffer->dataPointer(), buffer->dataPointer(), copyLength);
|
|
||||||
|
|
||||||
ArrayBufferObject::BufferContents detachedContents =
|
|
||||||
buffer->hasStealableContents() ? ArrayBufferObject::BufferContents::createPlain(nullptr)
|
|
||||||
: buffer->contents();
|
|
||||||
ArrayBufferObject::detach(cx, buffer, detachedContents);
|
|
||||||
|
|
||||||
args.rval().setObject(*newBuffer);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ArrayBufferObject::fun_transfer_impl(JSContext* cx, const CallArgs& args)
|
|
||||||
{
|
|
||||||
return ArrayBufferTransfer(cx, args, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ArrayBufferObject::fun_transfer(JSContext* cx, unsigned argc, Value* vp)
|
|
||||||
{
|
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
|
||||||
return CallNonGenericMethod<IsArrayBuffer, fun_transfer_impl>(cx, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ArrayBufferObject::fun_transferToFixedLength_impl(JSContext* cx, const CallArgs& args)
|
|
||||||
{
|
|
||||||
return ArrayBufferTransfer(cx, args, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ArrayBufferObject::fun_transferToFixedLength(JSContext* cx, unsigned argc, Value* vp)
|
|
||||||
{
|
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
|
||||||
return CallNonGenericMethod<IsArrayBuffer, fun_transferToFixedLength_impl>(cx, args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -1219,14 +887,6 @@ ArrayBufferObject::byteLength() const
|
||||||
return getSlot(BYTE_LENGTH_SLOT).toInt32();
|
return getSlot(BYTE_LENGTH_SLOT).toInt32();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t
|
|
||||||
ArrayBufferObject::maxByteLength() const
|
|
||||||
{
|
|
||||||
if (!isResizable())
|
|
||||||
return byteLength();
|
|
||||||
return getSlot(MAX_BYTE_LENGTH_SLOT).toInt32();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ArrayBufferObject::setByteLength(uint32_t length)
|
ArrayBufferObject::setByteLength(uint32_t length)
|
||||||
{
|
{
|
||||||
|
|
@ -1269,7 +929,7 @@ js::WasmArrayBufferMaxSize(const ArrayBufferObjectMaybeShared* buf)
|
||||||
if (buf->is<ArrayBufferObject>())
|
if (buf->is<ArrayBufferObject>())
|
||||||
return buf->as<ArrayBufferObject>().wasmMaxSize();
|
return buf->as<ArrayBufferObject>().wasmMaxSize();
|
||||||
|
|
||||||
return Some(buf->as<SharedArrayBufferObject>().maxByteLength());
|
return Some(buf->as<SharedArrayBufferObject>().byteLength());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ bool
|
/* static */ bool
|
||||||
|
|
@ -1375,12 +1035,9 @@ ArrayBufferObject*
|
||||||
ArrayBufferObject::create(JSContext* cx, uint32_t nbytes, BufferContents contents,
|
ArrayBufferObject::create(JSContext* cx, uint32_t nbytes, BufferContents contents,
|
||||||
OwnsState ownsState /* = OwnsData */,
|
OwnsState ownsState /* = OwnsData */,
|
||||||
HandleObject proto /* = nullptr */,
|
HandleObject proto /* = nullptr */,
|
||||||
NewObjectKind newKind /* = GenericObject */,
|
NewObjectKind newKind /* = GenericObject */)
|
||||||
uint32_t maxByteLength /* = 0 */,
|
|
||||||
bool resizable /* = false */)
|
|
||||||
{
|
{
|
||||||
MOZ_ASSERT_IF(contents.kind() == MAPPED, contents);
|
MOZ_ASSERT_IF(contents.kind() == MAPPED, contents);
|
||||||
MOZ_ASSERT_IF(resizable, maxByteLength >= nbytes);
|
|
||||||
|
|
||||||
// 24.1.1.1, step 3 (Inlined 6.2.6.1 CreateByteDataBlock, step 2).
|
// 24.1.1.1, step 3 (Inlined 6.2.6.1 CreateByteDataBlock, step 2).
|
||||||
// Refuse to allocate too large buffers, currently limited to ~2 GiB.
|
// Refuse to allocate too large buffers, currently limited to ~2 GiB.
|
||||||
|
|
@ -1389,6 +1046,10 @@ ArrayBufferObject::create(JSContext* cx, uint32_t nbytes, BufferContents content
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we need to allocate data, try to use a larger object size class so
|
||||||
|
// that the array buffer's data can be allocated inline with the object.
|
||||||
|
// The extra space will be left unused by the object's fixed slots and
|
||||||
|
// available for the buffer's data, see NewObject().
|
||||||
size_t reservedSlots = JSCLASS_RESERVED_SLOTS(&class_);
|
size_t reservedSlots = JSCLASS_RESERVED_SLOTS(&class_);
|
||||||
|
|
||||||
size_t nslots = reservedSlots;
|
size_t nslots = reservedSlots;
|
||||||
|
|
@ -1405,10 +1066,18 @@ ArrayBufferObject::create(JSContext* cx, uint32_t nbytes, BufferContents content
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
MOZ_ASSERT(ownsState == OwnsData);
|
MOZ_ASSERT(ownsState == OwnsData);
|
||||||
contents = AllocateArrayBufferContents(cx, nbytes);
|
size_t usableSlots = NativeObject::MAX_FIXED_SLOTS - reservedSlots;
|
||||||
if (!contents)
|
if (nbytes <= usableSlots * sizeof(Value)) {
|
||||||
return nullptr;
|
int newSlots = (nbytes - 1) / sizeof(Value) + 1;
|
||||||
allocated = true;
|
MOZ_ASSERT(int(nbytes) <= newSlots * int(sizeof(Value)));
|
||||||
|
nslots = reservedSlots + newSlots;
|
||||||
|
contents = BufferContents::createPlain(nullptr);
|
||||||
|
} else {
|
||||||
|
contents = AllocateArrayBufferContents(cx, nbytes);
|
||||||
|
if (!contents)
|
||||||
|
return nullptr;
|
||||||
|
allocated = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_ASSERT(!(class_.flags & JSCLASS_HAS_PRIVATE));
|
MOZ_ASSERT(!(class_.flags & JSCLASS_HAS_PRIVATE));
|
||||||
|
|
@ -1428,11 +1097,10 @@ ArrayBufferObject::create(JSContext* cx, uint32_t nbytes, BufferContents content
|
||||||
|
|
||||||
if (!contents) {
|
if (!contents) {
|
||||||
void* data = obj->inlineDataPointer();
|
void* data = obj->inlineDataPointer();
|
||||||
memset(data, 0, nbytes);
|
js_memset(data, 0, nbytes);
|
||||||
obj->initialize(nbytes, BufferContents::createPlain(data), DoesntOwnData,
|
obj->initialize(nbytes, BufferContents::createPlain(data), DoesntOwnData);
|
||||||
maxByteLength, resizable);
|
|
||||||
} else {
|
} else {
|
||||||
obj->initialize(nbytes, contents, ownsState, maxByteLength, resizable);
|
obj->initialize(nbytes, contents, ownsState);
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
|
|
@ -1462,28 +1130,25 @@ ArrayBufferObject::createEmpty(JSContext* cx)
|
||||||
bool
|
bool
|
||||||
ArrayBufferObject::createDataViewForThisImpl(JSContext* cx, const CallArgs& args)
|
ArrayBufferObject::createDataViewForThisImpl(JSContext* cx, const CallArgs& args)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(IsAnyArrayBuffer(args.thisv()));
|
MOZ_ASSERT(IsArrayBuffer(args.thisv()));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This method is only called for |DataView(alienBuf, ...)| which calls
|
* This method is only called for |DataView(alienBuf, ...)| which calls
|
||||||
* this as |createDataViewForThis.call(alienBuf, byteOffset, byteLength,
|
* this as |createDataViewForThis.call(alienBuf, byteOffset, byteLength,
|
||||||
* DataView.prototype, lengthTracking)|,
|
* DataView.prototype)|,
|
||||||
* ergo there must be exactly 4 arguments.
|
* ergo there must be exactly 3 arguments.
|
||||||
*/
|
*/
|
||||||
MOZ_ASSERT(args.length() == 4);
|
MOZ_ASSERT(args.length() == 3);
|
||||||
|
|
||||||
uint32_t byteOffset = args[0].toPrivateUint32();
|
uint32_t byteOffset = args[0].toPrivateUint32();
|
||||||
uint32_t byteLength = args[1].toPrivateUint32();
|
uint32_t byteLength = args[1].toPrivateUint32();
|
||||||
bool lengthTracking = args[3].toBoolean();
|
Rooted<ArrayBufferObject*> buffer(cx, &args.thisv().toObject().as<ArrayBufferObject>());
|
||||||
Rooted<ArrayBufferObjectMaybeShared*> buffer(cx,
|
|
||||||
&args.thisv().toObject().as<ArrayBufferObjectMaybeShared>());
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pop off the passed-along prototype and delegate to normal DataViewObject
|
* Pop off the passed-along prototype and delegate to normal DataViewObject
|
||||||
* construction.
|
* construction.
|
||||||
*/
|
*/
|
||||||
JSObject* obj = DataViewObject::create(cx, byteOffset, byteLength, buffer,
|
JSObject* obj = DataViewObject::create(cx, byteOffset, byteLength, buffer, &args[2].toObject());
|
||||||
&args[2].toObject(), lengthTracking);
|
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return false;
|
return false;
|
||||||
args.rval().setObject(*obj);
|
args.rval().setObject(*obj);
|
||||||
|
|
@ -1494,7 +1159,7 @@ bool
|
||||||
ArrayBufferObject::createDataViewForThis(JSContext* cx, unsigned argc, Value* vp)
|
ArrayBufferObject::createDataViewForThis(JSContext* cx, unsigned argc, Value* vp)
|
||||||
{
|
{
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
return CallNonGenericMethod<IsAnyArrayBuffer, createDataViewForThisImpl>(cx, args);
|
return CallNonGenericMethod<IsArrayBuffer, createDataViewForThisImpl>(cx, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ ArrayBufferObject::BufferContents
|
/* static */ ArrayBufferObject::BufferContents
|
||||||
|
|
@ -1863,8 +1528,6 @@ ArrayBufferViewObject::trace(JSTracer* trc, JSObject* objArg)
|
||||||
// The data may or may not be inline with the buffer. The buffer
|
// The data may or may not be inline with the buffer. The buffer
|
||||||
// can only move during a compacting GC, in which case its
|
// can only move during a compacting GC, in which case its
|
||||||
// objectMoved hook has already updated the buffer's data pointer.
|
// objectMoved hook has already updated the buffer's data pointer.
|
||||||
if (offset > buf.byteLength())
|
|
||||||
offset = 0;
|
|
||||||
obj->initPrivate(buf.dataPointer() + offset);
|
obj->initPrivate(buf.dataPointer() + offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1915,8 +1578,6 @@ ArrayBufferViewObject::dataPointerUnshared(const JS::AutoRequireNoGC& nogc)
|
||||||
bool
|
bool
|
||||||
ArrayBufferViewObject::isSharedMemory()
|
ArrayBufferViewObject::isSharedMemory()
|
||||||
{
|
{
|
||||||
if (is<DataViewObject>())
|
|
||||||
return as<DataViewObject>().isSharedMemory();
|
|
||||||
if (is<TypedArrayObject>())
|
if (is<TypedArrayObject>())
|
||||||
return as<TypedArrayObject>().isSharedMemory();
|
return as<TypedArrayObject>().isSharedMemory();
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -1948,7 +1609,7 @@ ArrayBufferViewObject::bufferObject(JSContext* cx, Handle<ArrayBufferViewObject*
|
||||||
return thisObject->as<TypedArrayObject>().bufferEither();
|
return thisObject->as<TypedArrayObject>().bufferEither();
|
||||||
}
|
}
|
||||||
MOZ_ASSERT(thisObject->is<DataViewObject>());
|
MOZ_ASSERT(thisObject->is<DataViewObject>());
|
||||||
return &thisObject->as<DataViewObject>().arrayBufferEither();
|
return &thisObject->as<DataViewObject>().arrayBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* JS Friend API */
|
/* JS Friend API */
|
||||||
|
|
@ -2199,7 +1860,7 @@ JS_GetArrayBufferViewData(JSObject* obj, bool* isSharedMemory, const JS::AutoChe
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (obj->is<DataViewObject>()) {
|
if (obj->is<DataViewObject>()) {
|
||||||
*isSharedMemory = obj->as<DataViewObject>().isSharedMemory();
|
*isSharedMemory = false;
|
||||||
return obj->as<DataViewObject>().dataPointer();
|
return obj->as<DataViewObject>().dataPointer();
|
||||||
}
|
}
|
||||||
TypedArrayObject& ta = obj->as<TypedArrayObject>();
|
TypedArrayObject& ta = obj->as<TypedArrayObject>();
|
||||||
|
|
@ -2269,7 +1930,7 @@ js::GetArrayBufferViewLengthAndData(JSObject* obj, uint32_t* length, bool* isSha
|
||||||
: obj->as<TypedArrayObject>().byteLength();
|
: obj->as<TypedArrayObject>().byteLength();
|
||||||
|
|
||||||
if (obj->is<DataViewObject>()) {
|
if (obj->is<DataViewObject>()) {
|
||||||
*isSharedMemory = obj->as<DataViewObject>().isSharedMemory();
|
*isSharedMemory = false;
|
||||||
*data = static_cast<uint8_t*>(obj->as<DataViewObject>().dataPointer());
|
*data = static_cast<uint8_t*>(obj->as<DataViewObject>().dataPointer());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ ArrayBufferObjectMaybeShared& AsAnyArrayBuffer(HandleValue val);
|
||||||
class ArrayBufferObjectMaybeShared : public NativeObject
|
class ArrayBufferObjectMaybeShared : public NativeObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
uint32_t byteLength() const {
|
uint32_t byteLength() {
|
||||||
return AnyArrayBufferByteLength(this);
|
return AnyArrayBufferByteLength(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -128,22 +128,15 @@ typedef MutableHandle<ArrayBufferObjectMaybeShared*> MutableHandleArrayBufferObj
|
||||||
class ArrayBufferObject : public ArrayBufferObjectMaybeShared
|
class ArrayBufferObject : public ArrayBufferObjectMaybeShared
|
||||||
{
|
{
|
||||||
static bool byteLengthGetterImpl(JSContext* cx, const CallArgs& args);
|
static bool byteLengthGetterImpl(JSContext* cx, const CallArgs& args);
|
||||||
static bool maxByteLengthGetterImpl(JSContext* cx, const CallArgs& args);
|
|
||||||
static bool resizableGetterImpl(JSContext* cx, const CallArgs& args);
|
|
||||||
static bool detachedGetterImpl(JSContext* cx, const CallArgs& args);
|
|
||||||
static bool fun_slice_impl(JSContext* cx, const CallArgs& args);
|
static bool fun_slice_impl(JSContext* cx, const CallArgs& args);
|
||||||
static bool fun_resize_impl(JSContext* cx, const CallArgs& args);
|
|
||||||
static bool fun_transfer_impl(JSContext* cx, const CallArgs& args);
|
|
||||||
static bool fun_transferToFixedLength_impl(JSContext* cx, const CallArgs& args);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const uint8_t DATA_SLOT = 0;
|
static const uint8_t DATA_SLOT = 0;
|
||||||
static const uint8_t BYTE_LENGTH_SLOT = 1;
|
static const uint8_t BYTE_LENGTH_SLOT = 1;
|
||||||
static const uint8_t FIRST_VIEW_SLOT = 2;
|
static const uint8_t FIRST_VIEW_SLOT = 2;
|
||||||
static const uint8_t FLAGS_SLOT = 3;
|
static const uint8_t FLAGS_SLOT = 3;
|
||||||
static const uint8_t MAX_BYTE_LENGTH_SLOT = 4;
|
|
||||||
|
|
||||||
static const uint8_t RESERVED_SLOTS = 5;
|
static const uint8_t RESERVED_SLOTS = 4;
|
||||||
|
|
||||||
static const size_t ARRAY_BUFFER_ALIGNMENT = 8;
|
static const size_t ARRAY_BUFFER_ALIGNMENT = 8;
|
||||||
|
|
||||||
|
|
@ -196,11 +189,7 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
|
||||||
|
|
||||||
// This PLAIN or WASM buffer has been prepared for asm.js and cannot
|
// This PLAIN or WASM buffer has been prepared for asm.js and cannot
|
||||||
// henceforth be transferred/detached.
|
// henceforth be transferred/detached.
|
||||||
FOR_ASMJS = 0x40,
|
FOR_ASMJS = 0x40
|
||||||
|
|
||||||
// This buffer was created with [[ArrayBufferMaxByteLength]] and can
|
|
||||||
// be resized up to that maximum.
|
|
||||||
RESIZABLE = 0x80
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(JS_ARRAYBUFFER_DETACHED_FLAG == DETACHED,
|
static_assert(JS_ARRAYBUFFER_DETACHED_FLAG == DETACHED,
|
||||||
|
|
@ -241,14 +230,8 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
|
||||||
static const Class class_;
|
static const Class class_;
|
||||||
|
|
||||||
static bool byteLengthGetter(JSContext* cx, unsigned argc, Value* vp);
|
static bool byteLengthGetter(JSContext* cx, unsigned argc, Value* vp);
|
||||||
static bool maxByteLengthGetter(JSContext* cx, unsigned argc, Value* vp);
|
|
||||||
static bool resizableGetter(JSContext* cx, unsigned argc, Value* vp);
|
|
||||||
static bool detachedGetter(JSContext* cx, unsigned argc, Value* vp);
|
|
||||||
|
|
||||||
static bool fun_slice(JSContext* cx, unsigned argc, Value* vp);
|
static bool fun_slice(JSContext* cx, unsigned argc, Value* vp);
|
||||||
static bool fun_resize(JSContext* cx, unsigned argc, Value* vp);
|
|
||||||
static bool fun_transfer(JSContext* cx, unsigned argc, Value* vp);
|
|
||||||
static bool fun_transferToFixedLength(JSContext* cx, unsigned argc, Value* vp);
|
|
||||||
|
|
||||||
static bool fun_isView(JSContext* cx, unsigned argc, Value* vp);
|
static bool fun_isView(JSContext* cx, unsigned argc, Value* vp);
|
||||||
|
|
||||||
|
|
@ -260,9 +243,7 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
|
||||||
BufferContents contents,
|
BufferContents contents,
|
||||||
OwnsState ownsState = OwnsData,
|
OwnsState ownsState = OwnsData,
|
||||||
HandleObject proto = nullptr,
|
HandleObject proto = nullptr,
|
||||||
NewObjectKind newKind = GenericObject,
|
NewObjectKind newKind = GenericObject);
|
||||||
uint32_t maxByteLength = 0,
|
|
||||||
bool resizable = false);
|
|
||||||
static ArrayBufferObject* create(JSContext* cx, uint32_t nbytes,
|
static ArrayBufferObject* create(JSContext* cx, uint32_t nbytes,
|
||||||
HandleObject proto = nullptr,
|
HandleObject proto = nullptr,
|
||||||
NewObjectKind newKind = GenericObject);
|
NewObjectKind newKind = GenericObject);
|
||||||
|
|
@ -313,8 +294,6 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
|
||||||
|
|
||||||
void setNewData(FreeOp* fop, BufferContents newContents, OwnsState ownsState);
|
void setNewData(FreeOp* fop, BufferContents newContents, OwnsState ownsState);
|
||||||
void changeContents(JSContext* cx, BufferContents newContents, OwnsState ownsState);
|
void changeContents(JSContext* cx, BufferContents newContents, OwnsState ownsState);
|
||||||
void changeContentsForResize(JSContext* cx, BufferContents newContents,
|
|
||||||
OwnsState ownsState, uint32_t newByteLength);
|
|
||||||
|
|
||||||
// Detach this buffer from its original memory. (This necessarily makes
|
// Detach this buffer from its original memory. (This necessarily makes
|
||||||
// views of this buffer unusable for modifying that original memory.)
|
// views of this buffer unusable for modifying that original memory.)
|
||||||
|
|
@ -323,8 +302,7 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void changeViewContents(JSContext* cx, ArrayBufferViewObject* view,
|
void changeViewContents(JSContext* cx, ArrayBufferViewObject* view,
|
||||||
uint8_t* oldDataPointer, BufferContents newContents,
|
uint8_t* oldDataPointer, BufferContents newContents);
|
||||||
uint32_t newByteLength);
|
|
||||||
void setFirstView(ArrayBufferViewObject* view);
|
void setFirstView(ArrayBufferViewObject* view);
|
||||||
|
|
||||||
uint8_t* inlineDataPointer() const;
|
uint8_t* inlineDataPointer() const;
|
||||||
|
|
@ -333,7 +311,6 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
|
||||||
uint8_t* dataPointer() const;
|
uint8_t* dataPointer() const;
|
||||||
SharedMem<uint8_t*> dataPointerShared() const;
|
SharedMem<uint8_t*> dataPointerShared() const;
|
||||||
uint32_t byteLength() const;
|
uint32_t byteLength() const;
|
||||||
uint32_t maxByteLength() const;
|
|
||||||
|
|
||||||
BufferContents contents() const {
|
BufferContents contents() const {
|
||||||
return BufferContents(dataPointer(), bufferKind());
|
return BufferContents(dataPointer(), bufferKind());
|
||||||
|
|
@ -357,7 +334,6 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
|
||||||
bool isWasm() const { return bufferKind() == WASM; }
|
bool isWasm() const { return bufferKind() == WASM; }
|
||||||
bool isMapped() const { return bufferKind() == MAPPED; }
|
bool isMapped() const { return bufferKind() == MAPPED; }
|
||||||
bool isDetached() const { return flags() & DETACHED; }
|
bool isDetached() const { return flags() & DETACHED; }
|
||||||
bool isResizable() const { return flags() & RESIZABLE; }
|
|
||||||
bool isPreparedForAsmJS() const { return flags() & FOR_ASMJS; }
|
bool isPreparedForAsmJS() const { return flags() & FOR_ASMJS; }
|
||||||
|
|
||||||
// WebAssembly support:
|
// WebAssembly support:
|
||||||
|
|
@ -415,17 +391,12 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
|
||||||
|
|
||||||
void setIsDetached() { setFlags(flags() | DETACHED); }
|
void setIsDetached() { setFlags(flags() | DETACHED); }
|
||||||
void setIsPreparedForAsmJS() { setFlags(flags() | FOR_ASMJS); }
|
void setIsPreparedForAsmJS() { setFlags(flags() | FOR_ASMJS); }
|
||||||
void setIsResizable() { setFlags(flags() | RESIZABLE); }
|
|
||||||
|
|
||||||
void initialize(size_t byteLength, BufferContents contents, OwnsState ownsState,
|
void initialize(size_t byteLength, BufferContents contents, OwnsState ownsState) {
|
||||||
uint32_t maxByteLength = 0, bool resizable = false) {
|
|
||||||
setByteLength(byteLength);
|
setByteLength(byteLength);
|
||||||
setFlags(0);
|
setFlags(0);
|
||||||
setFixedSlot(MAX_BYTE_LENGTH_SLOT, Int32Value(maxByteLength ? maxByteLength : byteLength));
|
|
||||||
setFirstView(nullptr);
|
setFirstView(nullptr);
|
||||||
setDataPointer(contents, ownsState);
|
setDataPointer(contents, ownsState);
|
||||||
if (resizable)
|
|
||||||
setIsResizable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: initialize() may be called after initEmpty(); initEmpty() must
|
// Note: initialize() may be called after initEmpty(); initEmpty() must
|
||||||
|
|
@ -433,7 +404,6 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
|
||||||
void initEmpty() {
|
void initEmpty() {
|
||||||
setByteLength(0);
|
setByteLength(0);
|
||||||
setFlags(0);
|
setFlags(0);
|
||||||
setFixedSlot(MAX_BYTE_LENGTH_SLOT, Int32Value(0));
|
|
||||||
setFirstView(nullptr);
|
setFirstView(nullptr);
|
||||||
setDataPointer(BufferContents::createPlain(nullptr), DoesntOwnData);
|
setDataPointer(BufferContents::createPlain(nullptr), DoesntOwnData);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -248,7 +248,6 @@
|
||||||
macro(lookupSetter, lookupSetter, "__lookupSetter__") \
|
macro(lookupSetter, lookupSetter, "__lookupSetter__") \
|
||||||
macro(MapConstructorInit, MapConstructorInit, "MapConstructorInit") \
|
macro(MapConstructorInit, MapConstructorInit, "MapConstructorInit") \
|
||||||
macro(MapIterator, MapIterator, "Map Iterator") \
|
macro(MapIterator, MapIterator, "Map Iterator") \
|
||||||
macro(maxByteLength, maxByteLength, "maxByteLength") \
|
|
||||||
macro(maximumFractionDigits, maximumFractionDigits, "maximumFractionDigits") \
|
macro(maximumFractionDigits, maximumFractionDigits, "maximumFractionDigits") \
|
||||||
macro(maximumSignificantDigits, maximumSignificantDigits, "maximumSignificantDigits") \
|
macro(maximumSignificantDigits, maximumSignificantDigits, "maximumSignificantDigits") \
|
||||||
macro(message, message, "message") \
|
macro(message, message, "message") \
|
||||||
|
|
@ -430,7 +429,6 @@
|
||||||
macro(toJSON, toJSON, "toJSON") \
|
macro(toJSON, toJSON, "toJSON") \
|
||||||
macro(toLocaleString, toLocaleString, "toLocaleString") \
|
macro(toLocaleString, toLocaleString, "toLocaleString") \
|
||||||
macro(toSource, toSource, "toSource") \
|
macro(toSource, toSource, "toSource") \
|
||||||
macro(toSorted, toSorted, "toSorted") \
|
|
||||||
macro(toString, toString, "toString") \
|
macro(toString, toString, "toString") \
|
||||||
macro(toUTCString, toUTCString, "toUTCString") \
|
macro(toUTCString, toUTCString, "toUTCString") \
|
||||||
macro(true, true_, "true") \
|
macro(true, true_, "true") \
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@
|
||||||
#include "builtin/SymbolObject.h"
|
#include "builtin/SymbolObject.h"
|
||||||
#include "builtin/TypedObject.h"
|
#include "builtin/TypedObject.h"
|
||||||
#include "builtin/WeakMapObject.h"
|
#include "builtin/WeakMapObject.h"
|
||||||
#include "builtin/WeakRefObject.h"
|
|
||||||
#include "builtin/WeakSetObject.h"
|
#include "builtin/WeakSetObject.h"
|
||||||
#include "vm/Debugger.h"
|
#include "vm/Debugger.h"
|
||||||
#include "vm/EnvironmentObject.h"
|
#include "vm/EnvironmentObject.h"
|
||||||
|
|
@ -465,7 +464,6 @@ GlobalObject::initStandardClasses(JSContext* cx, Handle<GlobalObject*> global)
|
||||||
if (!ensureConstructor(cx, global, static_cast<JSProtoKey>(k)))
|
if (!ensureConstructor(cx, global, static_cast<JSProtoKey>(k)))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -540,7 +538,6 @@ GlobalObject::initSelfHostingBuiltins(JSContext* cx, Handle<GlobalObject*> globa
|
||||||
InitBareBuiltinCtor(cx, global, JSProto_Int32Array) &&
|
InitBareBuiltinCtor(cx, global, JSProto_Int32Array) &&
|
||||||
InitBareSymbolCtor(cx, global) &&
|
InitBareSymbolCtor(cx, global) &&
|
||||||
InitBareWeakMapCtor(cx, global) &&
|
InitBareWeakMapCtor(cx, global) &&
|
||||||
InitBareWeakRefCtor(cx, global) &&
|
|
||||||
InitStopIterationClass(cx, global) &&
|
InitStopIterationClass(cx, global) &&
|
||||||
DefineFunctions(cx, global, builtins, AsIntrinsic);
|
DefineFunctions(cx, global, builtins, AsIntrinsic);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,22 +43,6 @@ static const ObjectElements emptyElementsHeaderShared(0, 0, ObjectElements::Shar
|
||||||
HeapSlot* const js::emptyObjectElementsShared =
|
HeapSlot* const js::emptyObjectElementsShared =
|
||||||
reinterpret_cast<HeapSlot*>(uintptr_t(&emptyElementsHeaderShared) + sizeof(ObjectElements));
|
reinterpret_cast<HeapSlot*>(uintptr_t(&emptyElementsHeaderShared) + sizeof(ObjectElements));
|
||||||
|
|
||||||
static const ObjectElements emptyElementsHeaderResizableOrGrowable(
|
|
||||||
0, 0, ObjectElements::RESIZABLE_OR_GROWABLE_BUFFER);
|
|
||||||
|
|
||||||
/* Objects with no elements share one empty set of elements. */
|
|
||||||
HeapSlot* const js::emptyObjectElementsResizableOrGrowable =
|
|
||||||
reinterpret_cast<HeapSlot*>(uintptr_t(&emptyElementsHeaderResizableOrGrowable) +
|
|
||||||
sizeof(ObjectElements));
|
|
||||||
|
|
||||||
static const ObjectElements emptyElementsHeaderSharedResizableOrGrowable(
|
|
||||||
0, 0, ObjectElements::SHARED_MEMORY | ObjectElements::RESIZABLE_OR_GROWABLE_BUFFER);
|
|
||||||
|
|
||||||
/* Objects with no elements share one empty set of elements. */
|
|
||||||
HeapSlot* const js::emptyObjectElementsSharedResizableOrGrowable =
|
|
||||||
reinterpret_cast<HeapSlot*>(uintptr_t(&emptyElementsHeaderSharedResizableOrGrowable) +
|
|
||||||
sizeof(ObjectElements));
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
||||||
|
|
@ -77,12 +61,10 @@ ObjectElements::ConvertElementsToDoubles(JSContext* cx, uintptr_t elementsPtr)
|
||||||
* This function is infallible, but has a fallible interface so that it can
|
* This function is infallible, but has a fallible interface so that it can
|
||||||
* be called directly from Ion code. Only arrays can have their dense
|
* be called directly from Ion code. Only arrays can have their dense
|
||||||
* elements converted to doubles, and arrays never have empty elements.
|
* elements converted to doubles, and arrays never have empty elements.
|
||||||
*/
|
*/
|
||||||
HeapSlot* elementsHeapPtr = (HeapSlot*) elementsPtr;
|
HeapSlot* elementsHeapPtr = (HeapSlot*) elementsPtr;
|
||||||
MOZ_ASSERT(elementsHeapPtr != emptyObjectElements &&
|
MOZ_ASSERT(elementsHeapPtr != emptyObjectElements &&
|
||||||
elementsHeapPtr != emptyObjectElementsShared &&
|
elementsHeapPtr != emptyObjectElementsShared);
|
||||||
elementsHeapPtr != emptyObjectElementsResizableOrGrowable &&
|
|
||||||
elementsHeapPtr != emptyObjectElementsSharedResizableOrGrowable);
|
|
||||||
|
|
||||||
ObjectElements* header = ObjectElements::fromElements(elementsHeapPtr);
|
ObjectElements* header = ObjectElements::fromElements(elementsHeapPtr);
|
||||||
MOZ_ASSERT(!header->shouldConvertDoubleElements());
|
MOZ_ASSERT(!header->shouldConvertDoubleElements());
|
||||||
|
|
|
||||||
|
|
@ -185,11 +185,6 @@ class ObjectElements
|
||||||
|
|
||||||
// These elements are set to integrity level "frozen".
|
// These elements are set to integrity level "frozen".
|
||||||
FROZEN = 0x10,
|
FROZEN = 0x10,
|
||||||
|
|
||||||
// For TypedArrays only: this TypedArray views a resizable
|
|
||||||
// ArrayBuffer or growable SharedArrayBuffer. JIT fast paths with
|
|
||||||
// cached length/data assumptions must fall back for these objects.
|
|
||||||
RESIZABLE_OR_GROWABLE_BUFFER = 0x20,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -260,10 +255,6 @@ class ObjectElements
|
||||||
: flags(SHARED_MEMORY), initializedLength(0), capacity(capacity), length(length)
|
: flags(SHARED_MEMORY), initializedLength(0), capacity(capacity), length(length)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
constexpr ObjectElements(uint32_t capacity, uint32_t length, uint32_t flags)
|
|
||||||
: flags(flags), initializedLength(0), capacity(capacity), length(length)
|
|
||||||
{}
|
|
||||||
|
|
||||||
HeapSlot* elements() {
|
HeapSlot* elements() {
|
||||||
return reinterpret_cast<HeapSlot*>(uintptr_t(this) + sizeof(ObjectElements));
|
return reinterpret_cast<HeapSlot*>(uintptr_t(this) + sizeof(ObjectElements));
|
||||||
}
|
}
|
||||||
|
|
@ -278,10 +269,6 @@ class ObjectElements
|
||||||
return flags & SHARED_MEMORY;
|
return flags & SHARED_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasResizableOrGrowableBuffer() const {
|
|
||||||
return flags & RESIZABLE_OR_GROWABLE_BUFFER;
|
|
||||||
}
|
|
||||||
|
|
||||||
GCPtrNativeObject& ownerObject() const {
|
GCPtrNativeObject& ownerObject() const {
|
||||||
MOZ_ASSERT(isCopyOnWrite());
|
MOZ_ASSERT(isCopyOnWrite());
|
||||||
return *(GCPtrNativeObject*)(&elements()[initializedLength]);
|
return *(GCPtrNativeObject*)(&elements()[initializedLength]);
|
||||||
|
|
@ -339,8 +326,6 @@ static_assert(ObjectElements::VALUES_PER_HEADER * sizeof(HeapSlot) == sizeof(Obj
|
||||||
*/
|
*/
|
||||||
extern HeapSlot* const emptyObjectElements;
|
extern HeapSlot* const emptyObjectElements;
|
||||||
extern HeapSlot* const emptyObjectElementsShared;
|
extern HeapSlot* const emptyObjectElementsShared;
|
||||||
extern HeapSlot* const emptyObjectElementsResizableOrGrowable;
|
|
||||||
extern HeapSlot* const emptyObjectElementsSharedResizableOrGrowable;
|
|
||||||
|
|
||||||
struct Class;
|
struct Class;
|
||||||
class GCMarker;
|
class GCMarker;
|
||||||
|
|
@ -495,12 +480,6 @@ class NativeObject : public ShapedObject
|
||||||
elements_ = emptyObjectElementsShared;
|
elements_ = emptyObjectElementsShared;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setHasResizableOrGrowableBuffer() {
|
|
||||||
MOZ_ASSERT(elements_ == emptyObjectElements || elements_ == emptyObjectElementsShared);
|
|
||||||
elements_ = isSharedMemory() ? emptyObjectElementsSharedResizableOrGrowable
|
|
||||||
: emptyObjectElementsResizableOrGrowable;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isInWholeCellBuffer() const {
|
bool isInWholeCellBuffer() const {
|
||||||
const gc::TenuredCell* cell = &asTenured();
|
const gc::TenuredCell* cell = &asTenured();
|
||||||
gc::ArenaCellSet* cells = cell->arena()->bufferedCells;
|
gc::ArenaCellSet* cells = cell->arena()->bufferedCells;
|
||||||
|
|
@ -1275,10 +1254,7 @@ class NativeObject : public ShapedObject
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool hasEmptyElements() const {
|
inline bool hasEmptyElements() const {
|
||||||
return elements_ == emptyObjectElements ||
|
return elements_ == emptyObjectElements || elements_ == emptyObjectElementsShared;
|
||||||
elements_ == emptyObjectElementsShared ||
|
|
||||||
elements_ == emptyObjectElementsResizableOrGrowable ||
|
|
||||||
elements_ == emptyObjectElementsSharedResizableOrGrowable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,6 @@
|
||||||
#include "builtin/SelfHostingDefines.h"
|
#include "builtin/SelfHostingDefines.h"
|
||||||
#include "builtin/Stream.h"
|
#include "builtin/Stream.h"
|
||||||
#include "builtin/TypedObject.h"
|
#include "builtin/TypedObject.h"
|
||||||
#include "builtin/WeakRefObject.h"
|
|
||||||
#include "builtin/WeakSetObject.h"
|
#include "builtin/WeakSetObject.h"
|
||||||
#include "gc/Marking.h"
|
#include "gc/Marking.h"
|
||||||
#include "gc/Policy.h"
|
#include "gc/Policy.h"
|
||||||
|
|
@ -106,14 +105,6 @@ intrinsic_IsObject(JSContext* cx, unsigned argc, Value* vp)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
|
||||||
intrinsic_CanBeHeldWeakly(JSContext* cx, unsigned argc, Value* vp)
|
|
||||||
{
|
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
|
||||||
args.rval().setBoolean(CanBeHeldWeakly(args.get(0)));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
intrinsic_IsArray(JSContext* cx, unsigned argc, Value* vp)
|
intrinsic_IsArray(JSContext* cx, unsigned argc, Value* vp)
|
||||||
{
|
{
|
||||||
|
|
@ -279,20 +270,6 @@ intrinsic_GetBuiltinConstructor(JSContext* cx, unsigned argc, Value* vp)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
|
||||||
intrinsic_NewMap(JSContext* cx, unsigned argc, Value* vp)
|
|
||||||
{
|
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
|
||||||
MOZ_ASSERT(args.length() == 0);
|
|
||||||
|
|
||||||
Rooted<MapObject*> map(cx, MapObject::create(cx));
|
|
||||||
if (!map)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
args.rval().setObject(*map);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
intrinsic_SubstringKernel(JSContext* cx, unsigned argc, Value* vp)
|
intrinsic_SubstringKernel(JSContext* cx, unsigned argc, Value* vp)
|
||||||
{
|
{
|
||||||
|
|
@ -1310,36 +1287,6 @@ intrinsic_PossiblyWrappedTypedArrayHasDetachedBuffer(JSContext* cx, unsigned arg
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
|
||||||
intrinsic_TypedArrayIsOutOfBounds(JSContext* cx, unsigned argc, Value* vp)
|
|
||||||
{
|
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
|
||||||
MOZ_ASSERT(args.length() == 1);
|
|
||||||
|
|
||||||
RootedObject obj(cx, &args[0].toObject());
|
|
||||||
MOZ_ASSERT(obj->is<TypedArrayObject>());
|
|
||||||
args.rval().setBoolean(obj->as<TypedArrayObject>().isOutOfBounds());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
intrinsic_PossiblyWrappedTypedArrayIsOutOfBounds(JSContext* cx, unsigned argc, Value* vp)
|
|
||||||
{
|
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
|
||||||
MOZ_ASSERT(args.length() == 1);
|
|
||||||
MOZ_ASSERT(args[0].isObject());
|
|
||||||
|
|
||||||
JSObject* obj = CheckedUnwrap(&args[0].toObject());
|
|
||||||
if (!obj) {
|
|
||||||
JS_ReportErrorASCII(cx, "Permission denied to access object");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(obj->is<TypedArrayObject>());
|
|
||||||
args.rval().setBoolean(obj->as<TypedArrayObject>().isOutOfBounds());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
intrinsic_MoveTypedArrayElements(JSContext* cx, unsigned argc, Value* vp)
|
intrinsic_MoveTypedArrayElements(JSContext* cx, unsigned argc, Value* vp)
|
||||||
{
|
{
|
||||||
|
|
@ -1462,10 +1409,6 @@ intrinsic_SetFromTypedArrayApproach(JSContext* cx, unsigned argc, Value* vp)
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
|
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (unsafeTypedArrayCrossCompartment->isOutOfBounds()) {
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Steps 21, 23.
|
// Steps 21, 23.
|
||||||
uint32_t unsafeSrcLengthCrossCompartment = unsafeTypedArrayCrossCompartment->length();
|
uint32_t unsafeSrcLengthCrossCompartment = unsafeTypedArrayCrossCompartment->length();
|
||||||
|
|
@ -2325,10 +2268,7 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
||||||
JS_INLINABLE_FN("std_Math_min", math_min, 2,0, MathMin),
|
JS_INLINABLE_FN("std_Math_min", math_min, 2,0, MathMin),
|
||||||
JS_INLINABLE_FN("std_Math_abs", math_abs, 1,0, MathAbs),
|
JS_INLINABLE_FN("std_Math_abs", math_abs, 1,0, MathAbs),
|
||||||
|
|
||||||
JS_FN("std_Map_create", intrinsic_NewMap, 0,0),
|
|
||||||
JS_FN("std_Map_get", MapObject::get, 1,0),
|
|
||||||
JS_FN("std_Map_has", MapObject::has, 1,0),
|
JS_FN("std_Map_has", MapObject::has, 1,0),
|
||||||
JS_FN("std_Map_set", MapObject::set, 2,0),
|
|
||||||
JS_FN("std_Map_iterator", MapObject::entries, 0,0),
|
JS_FN("std_Map_iterator", MapObject::entries, 0,0),
|
||||||
|
|
||||||
JS_FN("std_Number_valueOf", num_valueOf, 0,0),
|
JS_FN("std_Number_valueOf", num_valueOf, 0,0),
|
||||||
|
|
@ -2376,7 +2316,6 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
||||||
// Helper funtions after this point.
|
// Helper funtions after this point.
|
||||||
JS_INLINABLE_FN("ToObject", intrinsic_ToObject, 1,0, IntrinsicToObject),
|
JS_INLINABLE_FN("ToObject", intrinsic_ToObject, 1,0, IntrinsicToObject),
|
||||||
JS_INLINABLE_FN("IsObject", intrinsic_IsObject, 1,0, IntrinsicIsObject),
|
JS_INLINABLE_FN("IsObject", intrinsic_IsObject, 1,0, IntrinsicIsObject),
|
||||||
JS_FN("CanBeHeldWeakly", intrinsic_CanBeHeldWeakly, 1,0),
|
|
||||||
JS_INLINABLE_FN("IsArray", intrinsic_IsArray, 1,0, ArrayIsArray),
|
JS_INLINABLE_FN("IsArray", intrinsic_IsArray, 1,0, ArrayIsArray),
|
||||||
JS_INLINABLE_FN("IsWrappedArrayConstructor", intrinsic_IsWrappedArrayConstructor, 1,0,
|
JS_INLINABLE_FN("IsWrappedArrayConstructor", intrinsic_IsWrappedArrayConstructor, 1,0,
|
||||||
IntrinsicIsWrappedArrayConstructor),
|
IntrinsicIsWrappedArrayConstructor),
|
||||||
|
|
@ -2536,10 +2475,6 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
||||||
1, 0, IntrinsicPossiblyWrappedTypedArrayLength),
|
1, 0, IntrinsicPossiblyWrappedTypedArrayLength),
|
||||||
JS_FN("PossiblyWrappedTypedArrayHasDetachedBuffer",
|
JS_FN("PossiblyWrappedTypedArrayHasDetachedBuffer",
|
||||||
intrinsic_PossiblyWrappedTypedArrayHasDetachedBuffer, 1, 0),
|
intrinsic_PossiblyWrappedTypedArrayHasDetachedBuffer, 1, 0),
|
||||||
JS_FN("TypedArrayIsOutOfBounds",
|
|
||||||
intrinsic_TypedArrayIsOutOfBounds, 1, 0),
|
|
||||||
JS_FN("PossiblyWrappedTypedArrayIsOutOfBounds",
|
|
||||||
intrinsic_PossiblyWrappedTypedArrayIsOutOfBounds, 1, 0),
|
|
||||||
|
|
||||||
JS_FN("MoveTypedArrayElements", intrinsic_MoveTypedArrayElements, 4,0),
|
JS_FN("MoveTypedArrayElements", intrinsic_MoveTypedArrayElements, 4,0),
|
||||||
JS_FN("SetFromTypedArrayApproach",intrinsic_SetFromTypedArrayApproach, 4, 0),
|
JS_FN("SetFromTypedArrayApproach",intrinsic_SetFromTypedArrayApproach, 4, 0),
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@
|
||||||
#include "mozilla/Atomics.h"
|
#include "mozilla/Atomics.h"
|
||||||
|
|
||||||
#include "jsfriendapi.h"
|
#include "jsfriendapi.h"
|
||||||
#include "jsnum.h"
|
|
||||||
#include "jsprf.h"
|
#include "jsprf.h"
|
||||||
|
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
|
|
@ -105,18 +104,15 @@ SharedArrayAllocSize(uint32_t length)
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedArrayRawBuffer*
|
SharedArrayRawBuffer*
|
||||||
SharedArrayRawBuffer::New(JSContext* cx, uint32_t length, uint32_t maxLength, bool growable)
|
SharedArrayRawBuffer::New(JSContext* cx, uint32_t length)
|
||||||
{
|
{
|
||||||
// The value (uint32_t)-1 is used as a signal in various places,
|
// The value (uint32_t)-1 is used as a signal in various places,
|
||||||
// so guard against it on principle.
|
// so guard against it on principle.
|
||||||
MOZ_ASSERT(length != (uint32_t)-1);
|
MOZ_ASSERT(length != (uint32_t)-1);
|
||||||
MOZ_ASSERT(maxLength != (uint32_t)-1);
|
|
||||||
MOZ_ASSERT(maxLength >= length);
|
|
||||||
|
|
||||||
// Add a page for the header and round to a page boundary.
|
// Add a page for the header and round to a page boundary.
|
||||||
uint32_t allocationLength = growable ? maxLength : length;
|
uint32_t allocSize = SharedArrayAllocSize(length);
|
||||||
uint32_t allocSize = SharedArrayAllocSize(allocationLength);
|
if (allocSize <= length)
|
||||||
if (allocSize <= allocationLength)
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// Test >= to guard against the case where multiple extant runtimes
|
// Test >= to guard against the case where multiple extant runtimes
|
||||||
|
|
@ -131,8 +127,7 @@ SharedArrayRawBuffer::New(JSContext* cx, uint32_t length, uint32_t maxLength, bo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool preparedForAsmJS =
|
bool preparedForAsmJS = jit::JitOptions.asmJSAtomicsEnable && IsValidAsmJSHeapLength(length);
|
||||||
!growable && jit::JitOptions.asmJSAtomicsEnable && IsValidAsmJSHeapLength(length);
|
|
||||||
|
|
||||||
void* p = nullptr;
|
void* p = nullptr;
|
||||||
if (preparedForAsmJS) {
|
if (preparedForAsmJS) {
|
||||||
|
|
@ -166,9 +161,8 @@ SharedArrayRawBuffer::New(JSContext* cx, uint32_t length, uint32_t maxLength, bo
|
||||||
|
|
||||||
uint8_t* buffer = reinterpret_cast<uint8_t*>(p) + gc::SystemPageSize();
|
uint8_t* buffer = reinterpret_cast<uint8_t*>(p) + gc::SystemPageSize();
|
||||||
uint8_t* base = buffer - sizeof(SharedArrayRawBuffer);
|
uint8_t* base = buffer - sizeof(SharedArrayRawBuffer);
|
||||||
SharedArrayRawBuffer* rawbuf =
|
SharedArrayRawBuffer* rawbuf = new (base) SharedArrayRawBuffer(buffer, length, preparedForAsmJS);
|
||||||
new (base) SharedArrayRawBuffer(buffer, length, maxLength, growable, preparedForAsmJS);
|
MOZ_ASSERT(rawbuf->length == length); // Deallocation needs this
|
||||||
MOZ_ASSERT(rawbuf->allocatedByteLength() == allocationLength); // Deallocation needs this.
|
|
||||||
return rawbuf;
|
return rawbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -207,7 +201,7 @@ SharedArrayRawBuffer::dropReference()
|
||||||
MOZ_ASSERT(p.asValue() % gc::SystemPageSize() == 0);
|
MOZ_ASSERT(p.asValue() % gc::SystemPageSize() == 0);
|
||||||
|
|
||||||
uint8_t* address = p.unwrap(/*safe - only reference*/);
|
uint8_t* address = p.unwrap(/*safe - only reference*/);
|
||||||
uint32_t allocSize = SharedArrayAllocSize(this->allocatedByteLength());
|
uint32_t allocSize = SharedArrayAllocSize(this->length);
|
||||||
|
|
||||||
if (this->preparedForAsmJS) {
|
if (this->preparedForAsmJS) {
|
||||||
uint32_t mappedSize = SharedArrayMappedSize(allocSize);
|
uint32_t mappedSize = SharedArrayMappedSize(allocSize);
|
||||||
|
|
@ -227,23 +221,6 @@ SharedArrayRawBuffer::dropReference()
|
||||||
numLive--;
|
numLive--;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
SharedArrayRawBuffer::growTo(uint32_t newLength)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(growable);
|
|
||||||
MOZ_ASSERT(newLength <= maxLength);
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
uint32_t oldLength = length;
|
|
||||||
if (newLength < oldLength)
|
|
||||||
return false;
|
|
||||||
if (newLength == oldLength)
|
|
||||||
return true;
|
|
||||||
if (length.compareExchange(oldLength, newLength))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
MOZ_ALWAYS_INLINE bool
|
MOZ_ALWAYS_INLINE bool
|
||||||
SharedArrayBufferObject::byteLengthGetterImpl(JSContext* cx, const CallArgs& args)
|
SharedArrayBufferObject::byteLengthGetterImpl(JSContext* cx, const CallArgs& args)
|
||||||
|
|
@ -260,112 +237,6 @@ SharedArrayBufferObject::byteLengthGetter(JSContext* cx, unsigned argc, Value* v
|
||||||
return CallNonGenericMethod<IsSharedArrayBuffer, byteLengthGetterImpl>(cx, args);
|
return CallNonGenericMethod<IsSharedArrayBuffer, byteLengthGetterImpl>(cx, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_ALWAYS_INLINE bool
|
|
||||||
SharedArrayBufferObject::maxByteLengthGetterImpl(JSContext* cx, const CallArgs& args)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(IsSharedArrayBuffer(args.thisv()));
|
|
||||||
args.rval().setInt32(args.thisv().toObject().as<SharedArrayBufferObject>().maxByteLength());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
SharedArrayBufferObject::maxByteLengthGetter(JSContext* cx, unsigned argc, Value* vp)
|
|
||||||
{
|
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
|
||||||
return CallNonGenericMethod<IsSharedArrayBuffer, maxByteLengthGetterImpl>(cx, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ALWAYS_INLINE bool
|
|
||||||
SharedArrayBufferObject::growableGetterImpl(JSContext* cx, const CallArgs& args)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(IsSharedArrayBuffer(args.thisv()));
|
|
||||||
args.rval().setBoolean(args.thisv().toObject().as<SharedArrayBufferObject>().isGrowable());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
SharedArrayBufferObject::growableGetter(JSContext* cx, unsigned argc, Value* vp)
|
|
||||||
{
|
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
|
||||||
return CallNonGenericMethod<IsSharedArrayBuffer, growableGetterImpl>(cx, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
ReportSharedArrayBufferNotGrowable(JSContext* cx)
|
|
||||||
{
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SHARED_ARRAY_NOT_GROWABLE);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
ReportSharedArrayBufferLengthOutOfRange(JSContext* cx)
|
|
||||||
{
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SHARED_ARRAY_BAD_LENGTH);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
GetSharedArrayBufferMaxByteLengthOption(JSContext* cx, HandleValue options,
|
|
||||||
uint32_t byteLength, uint32_t* maxByteLength,
|
|
||||||
bool* growable)
|
|
||||||
{
|
|
||||||
*maxByteLength = byteLength;
|
|
||||||
*growable = false;
|
|
||||||
|
|
||||||
if (!options.isObject())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
RootedObject opts(cx, &options.toObject());
|
|
||||||
RootedValue maxByteLengthValue(cx);
|
|
||||||
if (!GetProperty(cx, opts, opts, cx->names().maxByteLength, &maxByteLengthValue))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (maxByteLengthValue.isUndefined())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
uint64_t max;
|
|
||||||
if (!ToIndex(cx, maxByteLengthValue, &max))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (max > INT32_MAX || max < byteLength)
|
|
||||||
return ReportSharedArrayBufferLengthOutOfRange(cx);
|
|
||||||
|
|
||||||
*maxByteLength = uint32_t(max);
|
|
||||||
*growable = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ALWAYS_INLINE bool
|
|
||||||
SharedArrayBufferObject::fun_grow_impl(JSContext* cx, const CallArgs& args)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(IsSharedArrayBuffer(args.thisv()));
|
|
||||||
|
|
||||||
Rooted<SharedArrayBufferObject*> buffer(cx,
|
|
||||||
&args.thisv().toObject().as<SharedArrayBufferObject>());
|
|
||||||
if (!buffer->isGrowable())
|
|
||||||
return ReportSharedArrayBufferNotGrowable(cx);
|
|
||||||
|
|
||||||
uint64_t newByteLength;
|
|
||||||
if (!ToIndex(cx, args.get(0), &newByteLength))
|
|
||||||
return false;
|
|
||||||
if (newByteLength > INT32_MAX)
|
|
||||||
return ReportSharedArrayBufferLengthOutOfRange(cx);
|
|
||||||
|
|
||||||
uint32_t newLength = uint32_t(newByteLength);
|
|
||||||
if (newLength > buffer->maxByteLength() || !buffer->growTo(newLength))
|
|
||||||
return ReportSharedArrayBufferLengthOutOfRange(cx);
|
|
||||||
|
|
||||||
args.rval().setUndefined();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
SharedArrayBufferObject::fun_grow(JSContext* cx, unsigned argc, Value* vp)
|
|
||||||
{
|
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
|
||||||
return CallNonGenericMethod<IsSharedArrayBuffer, fun_grow_impl>(cx, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SharedArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value* vp)
|
SharedArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value* vp)
|
||||||
{
|
{
|
||||||
|
|
@ -374,19 +245,11 @@ SharedArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value*
|
||||||
if (!ThrowIfNotConstructing(cx, args, "SharedArrayBuffer"))
|
if (!ThrowIfNotConstructing(cx, args, "SharedArrayBuffer"))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
uint64_t length64;
|
|
||||||
if (!ToIndex(cx, args.get(0), &length64))
|
|
||||||
return false;
|
|
||||||
// Bugs 1068458, 1161298: Limit length to 2^31-1.
|
// Bugs 1068458, 1161298: Limit length to 2^31-1.
|
||||||
if (length64 > INT32_MAX)
|
uint32_t length;
|
||||||
return ReportSharedArrayBufferLengthOutOfRange(cx);
|
bool overflow_unused;
|
||||||
uint32_t length = uint32_t(length64);
|
if (!ToLengthClamped(cx, args.get(0), &length, &overflow_unused) || length > INT32_MAX) {
|
||||||
|
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SHARED_ARRAY_BAD_LENGTH);
|
||||||
uint32_t maxByteLength;
|
|
||||||
bool growable;
|
|
||||||
if (!GetSharedArrayBufferMaxByteLengthOption(cx, args.get(1), length,
|
|
||||||
&maxByteLength, &growable))
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -395,7 +258,7 @@ SharedArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value*
|
||||||
if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
|
if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
JSObject* bufobj = New(cx, length, maxByteLength, growable, proto);
|
JSObject* bufobj = New(cx, length, proto);
|
||||||
if (!bufobj)
|
if (!bufobj)
|
||||||
return false;
|
return false;
|
||||||
args.rval().setObject(*bufobj);
|
args.rval().setObject(*bufobj);
|
||||||
|
|
@ -403,10 +266,9 @@ SharedArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value*
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedArrayBufferObject*
|
SharedArrayBufferObject*
|
||||||
SharedArrayBufferObject::New(JSContext* cx, uint32_t length, uint32_t maxLength, bool growable,
|
SharedArrayBufferObject::New(JSContext* cx, uint32_t length, HandleObject proto)
|
||||||
HandleObject proto)
|
|
||||||
{
|
{
|
||||||
SharedArrayRawBuffer* buffer = SharedArrayRawBuffer::New(cx, length, maxLength, growable);
|
SharedArrayRawBuffer* buffer = SharedArrayRawBuffer::New(cx, length);
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
|
@ -479,7 +341,7 @@ SharedArrayBufferObject::addSizeOfExcludingThis(JSObject* obj, mozilla::MallocSi
|
||||||
// just live with the risk.
|
// just live with the risk.
|
||||||
const SharedArrayBufferObject& buf = obj->as<SharedArrayBufferObject>();
|
const SharedArrayBufferObject& buf = obj->as<SharedArrayBufferObject>();
|
||||||
info->objectsNonHeapElementsShared +=
|
info->objectsNonHeapElementsShared +=
|
||||||
buf.rawBufferObject()->allocatedByteLength() / buf.rawBufferObject()->refcount();
|
buf.byteLength() / buf.rawBufferObject()->refcount();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ void
|
/* static */ void
|
||||||
|
|
@ -547,15 +409,12 @@ static const JSPropertySpec static_properties[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static const JSFunctionSpec prototype_functions[] = {
|
static const JSFunctionSpec prototype_functions[] = {
|
||||||
JS_FN("grow", SharedArrayBufferObject::fun_grow, 1, 0),
|
|
||||||
JS_SELF_HOSTED_FN("slice", "SharedArrayBufferSlice", 2, 0),
|
JS_SELF_HOSTED_FN("slice", "SharedArrayBufferSlice", 2, 0),
|
||||||
JS_FS_END
|
JS_FS_END
|
||||||
};
|
};
|
||||||
|
|
||||||
static const JSPropertySpec prototype_properties[] = {
|
static const JSPropertySpec prototype_properties[] = {
|
||||||
JS_PSG("byteLength", SharedArrayBufferObject::byteLengthGetter, 0),
|
JS_PSG("byteLength", SharedArrayBufferObject::byteLengthGetter, 0),
|
||||||
JS_PSG("growable", SharedArrayBufferObject::growableGetter, 0),
|
|
||||||
JS_PSG("maxByteLength", SharedArrayBufferObject::maxByteLengthGetter, 0),
|
|
||||||
JS_STRING_SYM_PS(toStringTag, "SharedArrayBuffer", JSPROP_READONLY),
|
JS_STRING_SYM_PS(toStringTag, "SharedArrayBuffer", JSPROP_READONLY),
|
||||||
JS_PS_END
|
JS_PS_END
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -44,9 +44,7 @@ class SharedArrayRawBuffer
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> refcount_;
|
mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> refcount_;
|
||||||
mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> length;
|
uint32_t length;
|
||||||
uint32_t maxLength;
|
|
||||||
bool growable;
|
|
||||||
bool preparedForAsmJS;
|
bool preparedForAsmJS;
|
||||||
|
|
||||||
// A list of structures representing tasks waiting on some
|
// A list of structures representing tasks waiting on some
|
||||||
|
|
@ -54,12 +52,9 @@ class SharedArrayRawBuffer
|
||||||
FutexWaiter* waiters_;
|
FutexWaiter* waiters_;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SharedArrayRawBuffer(uint8_t* buffer, uint32_t length, uint32_t maxLength, bool growable,
|
SharedArrayRawBuffer(uint8_t* buffer, uint32_t length, bool preparedForAsmJS)
|
||||||
bool preparedForAsmJS)
|
|
||||||
: refcount_(1),
|
: refcount_(1),
|
||||||
length(length),
|
length(length),
|
||||||
maxLength(maxLength),
|
|
||||||
growable(growable),
|
|
||||||
preparedForAsmJS(preparedForAsmJS),
|
preparedForAsmJS(preparedForAsmJS),
|
||||||
waiters_(nullptr)
|
waiters_(nullptr)
|
||||||
{
|
{
|
||||||
|
|
@ -67,11 +62,7 @@ class SharedArrayRawBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static SharedArrayRawBuffer* New(JSContext* cx, uint32_t length, uint32_t maxLength,
|
static SharedArrayRawBuffer* New(JSContext* cx, uint32_t length);
|
||||||
bool growable);
|
|
||||||
static SharedArrayRawBuffer* New(JSContext* cx, uint32_t length) {
|
|
||||||
return New(cx, length, length, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This may be called from multiple threads. The caller must take
|
// This may be called from multiple threads. The caller must take
|
||||||
// care of mutual exclusion.
|
// care of mutual exclusion.
|
||||||
|
|
@ -94,20 +85,6 @@ class SharedArrayRawBuffer
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t maxByteLength() const {
|
|
||||||
return growable ? maxLength : byteLength();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t allocatedByteLength() const {
|
|
||||||
return growable ? maxLength : byteLength();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isGrowable() const {
|
|
||||||
return growable;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool growTo(uint32_t newLength);
|
|
||||||
|
|
||||||
bool isPreparedForAsmJS() const {
|
bool isPreparedForAsmJS() const {
|
||||||
return preparedForAsmJS;
|
return preparedForAsmJS;
|
||||||
}
|
}
|
||||||
|
|
@ -140,9 +117,6 @@ class SharedArrayRawBuffer
|
||||||
class SharedArrayBufferObject : public ArrayBufferObjectMaybeShared
|
class SharedArrayBufferObject : public ArrayBufferObjectMaybeShared
|
||||||
{
|
{
|
||||||
static bool byteLengthGetterImpl(JSContext* cx, const CallArgs& args);
|
static bool byteLengthGetterImpl(JSContext* cx, const CallArgs& args);
|
||||||
static bool maxByteLengthGetterImpl(JSContext* cx, const CallArgs& args);
|
|
||||||
static bool growableGetterImpl(JSContext* cx, const CallArgs& args);
|
|
||||||
static bool fun_grow_impl(JSContext* cx, const CallArgs& args);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// RAWBUF_SLOT holds a pointer (as "private" data) to the
|
// RAWBUF_SLOT holds a pointer (as "private" data) to the
|
||||||
|
|
@ -154,23 +128,13 @@ class SharedArrayBufferObject : public ArrayBufferObjectMaybeShared
|
||||||
static const Class class_;
|
static const Class class_;
|
||||||
|
|
||||||
static bool byteLengthGetter(JSContext* cx, unsigned argc, Value* vp);
|
static bool byteLengthGetter(JSContext* cx, unsigned argc, Value* vp);
|
||||||
static bool maxByteLengthGetter(JSContext* cx, unsigned argc, Value* vp);
|
|
||||||
static bool growableGetter(JSContext* cx, unsigned argc, Value* vp);
|
|
||||||
static bool fun_grow(JSContext* cx, unsigned argc, Value* vp);
|
|
||||||
|
|
||||||
static bool class_constructor(JSContext* cx, unsigned argc, Value* vp);
|
static bool class_constructor(JSContext* cx, unsigned argc, Value* vp);
|
||||||
|
|
||||||
// Create a SharedArrayBufferObject with a new SharedArrayRawBuffer.
|
// Create a SharedArrayBufferObject with a new SharedArrayRawBuffer.
|
||||||
static SharedArrayBufferObject* New(JSContext* cx,
|
static SharedArrayBufferObject* New(JSContext* cx,
|
||||||
uint32_t length,
|
uint32_t length,
|
||||||
uint32_t maxLength,
|
|
||||||
bool growable,
|
|
||||||
HandleObject proto = nullptr);
|
HandleObject proto = nullptr);
|
||||||
static SharedArrayBufferObject* New(JSContext* cx,
|
|
||||||
uint32_t length,
|
|
||||||
HandleObject proto = nullptr) {
|
|
||||||
return New(cx, length, length, false, proto);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a SharedArrayBufferObject using an existing SharedArrayRawBuffer.
|
// Create a SharedArrayBufferObject using an existing SharedArrayRawBuffer.
|
||||||
static SharedArrayBufferObject* New(JSContext* cx,
|
static SharedArrayBufferObject* New(JSContext* cx,
|
||||||
|
|
@ -200,15 +164,6 @@ class SharedArrayBufferObject : public ArrayBufferObjectMaybeShared
|
||||||
uint32_t byteLength() const {
|
uint32_t byteLength() const {
|
||||||
return rawBufferObject()->byteLength();
|
return rawBufferObject()->byteLength();
|
||||||
}
|
}
|
||||||
uint32_t maxByteLength() const {
|
|
||||||
return rawBufferObject()->maxByteLength();
|
|
||||||
}
|
|
||||||
bool isGrowable() const {
|
|
||||||
return rawBufferObject()->isGrowable();
|
|
||||||
}
|
|
||||||
[[nodiscard]] bool growTo(uint32_t newLength) {
|
|
||||||
return rawBufferObject()->growTo(newLength);
|
|
||||||
}
|
|
||||||
bool isPreparedForAsmJS() const {
|
bool isPreparedForAsmJS() const {
|
||||||
return rawBufferObject()->isPreparedForAsmJS();
|
return rawBufferObject()->isPreparedForAsmJS();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,6 @@
|
||||||
#include "builtin/MapObject.h"
|
#include "builtin/MapObject.h"
|
||||||
#include "js/Date.h"
|
#include "js/Date.h"
|
||||||
#include "js/GCHashTable.h"
|
#include "js/GCHashTable.h"
|
||||||
#include "vm/ArrayBufferObject-inl.h"
|
|
||||||
#include "vm/SavedFrame.h"
|
#include "vm/SavedFrame.h"
|
||||||
#include "vm/SharedArrayObject.h"
|
#include "vm/SharedArrayObject.h"
|
||||||
#include "vm/TypedArrayObject.h"
|
#include "vm/TypedArrayObject.h"
|
||||||
|
|
|
||||||
|
|
@ -1065,40 +1065,16 @@ class TypedArrayMethods
|
||||||
if (!ToInt32(cx, args[1], &offset))
|
if (!ToInt32(cx, args[1], &offset))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (offset < 0) {
|
if (offset < 0 || uint32_t(offset) > target->length()) {
|
||||||
|
// the given offset is bogus
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
|
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target->hasDetachedBuffer()) {
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (target->isOutOfBounds()) {
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t targetLength = target->length();
|
|
||||||
if (uint32_t(offset) > targetLength) {
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
RootedObject arg0(cx, &args[0].toObject());
|
RootedObject arg0(cx, &args[0].toObject());
|
||||||
if (arg0->is<TypedArrayObject>()) {
|
if (arg0->is<TypedArrayObject>()) {
|
||||||
Rooted<TypedArrayObject*> source(cx, &arg0->as<TypedArrayObject>());
|
if (arg0->as<TypedArrayObject>().length() > target->length() - offset) {
|
||||||
if (source->hasDetachedBuffer()) {
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (source->isOutOfBounds()) {
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (source->length() > targetLength - offset) {
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
|
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -1110,7 +1086,7 @@ class TypedArrayMethods
|
||||||
if (!GetLengthProperty(cx, arg0, &len))
|
if (!GetLengthProperty(cx, arg0, &len))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (len > targetLength - offset) {
|
if (uint32_t(offset) > target->length() || len > target->length() - offset) {
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
|
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -1123,32 +1099,13 @@ class TypedArrayMethods
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
setFromTypedArray(JSContext* cx, Handle<SomeTypedArray*> target, HandleObject source,
|
setFromTypedArray(JSContext* cx, Handle<SomeTypedArray*> target, HandleObject source,
|
||||||
uint32_t offset = 0)
|
uint32_t offset = 0)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(source->is<TypedArrayObject>(), "use setFromNonTypedArray");
|
MOZ_ASSERT(source->is<TypedArrayObject>(), "use setFromNonTypedArray");
|
||||||
|
|
||||||
if (target->hasDetachedBuffer()) {
|
bool isShared = target->isSharedMemory() || source->as<TypedArrayObject>().isSharedMemory();
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (target->isOutOfBounds()) {
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Rooted<TypedArrayObject*> sourceArray(cx, &source->as<TypedArrayObject>());
|
|
||||||
if (sourceArray->hasDetachedBuffer()) {
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (sourceArray->isOutOfBounds()) {
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isShared = target->isSharedMemory() || sourceArray->isSharedMemory();
|
|
||||||
|
|
||||||
switch (target->type()) {
|
switch (target->type()) {
|
||||||
case Scalar::Int8:
|
case Scalar::Int8:
|
||||||
|
|
|
||||||
|
|
@ -484,9 +484,8 @@ class TypedArrayObjectTemplate : public TypedArrayObject
|
||||||
}
|
}
|
||||||
|
|
||||||
static TypedArrayObject*
|
static TypedArrayObject*
|
||||||
makeInstance(JSContext* cx, Handle<ArrayBufferObjectMaybeShared*> buffer,
|
makeInstance(JSContext* cx, Handle<ArrayBufferObjectMaybeShared*> buffer, uint32_t byteOffset, uint32_t len,
|
||||||
uint32_t byteOffset, uint32_t len, HandleObject proto,
|
HandleObject proto)
|
||||||
bool lengthTracking = false)
|
|
||||||
{
|
{
|
||||||
MOZ_ASSERT_IF(!buffer, byteOffset == 0);
|
MOZ_ASSERT_IF(!buffer, byteOffset == 0);
|
||||||
|
|
||||||
|
|
@ -511,19 +510,12 @@ class TypedArrayObjectTemplate : public TypedArrayObject
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
bool isSharedMemory = buffer && IsSharedArrayBuffer(buffer.get());
|
bool isSharedMemory = buffer && IsSharedArrayBuffer(buffer.get());
|
||||||
bool hasResizableOrGrowableBuffer =
|
|
||||||
buffer &&
|
|
||||||
((buffer->is<ArrayBufferObject>() && buffer->as<ArrayBufferObject>().isResizable()) ||
|
|
||||||
(buffer->is<SharedArrayBufferObject>() &&
|
|
||||||
buffer->as<SharedArrayBufferObject>().isGrowable()));
|
|
||||||
|
|
||||||
obj->setFixedSlot(TypedArrayObject::BUFFER_SLOT, ObjectOrNullValue(buffer));
|
obj->setFixedSlot(TypedArrayObject::BUFFER_SLOT, ObjectOrNullValue(buffer));
|
||||||
// This is invariant. Self-hosting code that sets BUFFER_SLOT
|
// This is invariant. Self-hosting code that sets BUFFER_SLOT
|
||||||
// (if it does) must maintain it, should it need to.
|
// (if it does) must maintain it, should it need to.
|
||||||
if (isSharedMemory)
|
if (isSharedMemory)
|
||||||
obj->setIsSharedMemory();
|
obj->setIsSharedMemory();
|
||||||
if (hasResizableOrGrowableBuffer)
|
|
||||||
obj->setHasResizableOrGrowableBuffer();
|
|
||||||
|
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
obj->initViewData(buffer->dataPointerEither() + byteOffset);
|
obj->initViewData(buffer->dataPointerEither() + byteOffset);
|
||||||
|
|
@ -557,9 +549,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
obj->setFixedSlot(TypedArrayObject::LENGTH_SLOT,
|
obj->setFixedSlot(TypedArrayObject::LENGTH_SLOT, Int32Value(len));
|
||||||
Int32Value(lengthTracking ? TypedArrayObject::LENGTH_TRACKING
|
|
||||||
: int32_t(len)));
|
|
||||||
obj->setFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT, Int32Value(byteOffset));
|
obj->setFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT, Int32Value(byteOffset));
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
@ -908,7 +898,6 @@ class TypedArrayObjectTemplate : public TypedArrayObject
|
||||||
return nullptr; // invalid byteOffset
|
return nullptr; // invalid byteOffset
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lengthTracking = false;
|
|
||||||
uint32_t len;
|
uint32_t len;
|
||||||
if (lengthInt == -1) {
|
if (lengthInt == -1) {
|
||||||
len = (buffer->byteLength() - byteOffset) / sizeof(NativeType);
|
len = (buffer->byteLength() - byteOffset) / sizeof(NativeType);
|
||||||
|
|
@ -917,12 +906,6 @@ class TypedArrayObjectTemplate : public TypedArrayObject
|
||||||
JSMSG_TYPED_ARRAY_CONSTRUCT_BOUNDS);
|
JSMSG_TYPED_ARRAY_CONSTRUCT_BOUNDS);
|
||||||
return nullptr; // given byte array doesn't map exactly to sizeof(NativeType) * N
|
return nullptr; // given byte array doesn't map exactly to sizeof(NativeType) * N
|
||||||
}
|
}
|
||||||
if ((buffer->is<ArrayBufferObject>() && buffer->as<ArrayBufferObject>().isResizable()) ||
|
|
||||||
(buffer->is<SharedArrayBufferObject>() &&
|
|
||||||
buffer->as<SharedArrayBufferObject>().isGrowable()))
|
|
||||||
{
|
|
||||||
lengthTracking = true;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
len = uint32_t(lengthInt);
|
len = uint32_t(lengthInt);
|
||||||
}
|
}
|
||||||
|
|
@ -941,7 +924,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject
|
||||||
return nullptr; // byteOffset + len is too big for the arraybuffer
|
return nullptr; // byteOffset + len is too big for the arraybuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
return makeInstance(cx, buffer, byteOffset, len, proto, lengthTracking);
|
return makeInstance(cx, buffer, byteOffset, len, proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
|
@ -1337,10 +1320,6 @@ TypedArrayObjectTemplate<T>::fromTypedArray(JSContext* cx, HandleObject other, b
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
|
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (srcArray->isOutOfBounds()) {
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 9.
|
// Step 9.
|
||||||
uint32_t elementLength = srcArray->length();
|
uint32_t elementLength = srcArray->length();
|
||||||
|
|
@ -1880,8 +1859,7 @@ DataViewNewObjectKind(JSContext* cx, uint32_t byteLength, JSObject* proto)
|
||||||
|
|
||||||
DataViewObject*
|
DataViewObject*
|
||||||
DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
|
DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
|
||||||
Handle<ArrayBufferObjectMaybeShared*> arrayBuffer, JSObject* protoArg,
|
Handle<ArrayBufferObject*> arrayBuffer, JSObject* protoArg)
|
||||||
bool lengthTracking)
|
|
||||||
{
|
{
|
||||||
if (arrayBuffer->isDetached()) {
|
if (arrayBuffer->isDetached()) {
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
|
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
|
||||||
|
|
@ -1890,18 +1868,8 @@ DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
|
||||||
|
|
||||||
MOZ_ASSERT(byteOffset <= INT32_MAX);
|
MOZ_ASSERT(byteOffset <= INT32_MAX);
|
||||||
MOZ_ASSERT(byteLength <= INT32_MAX);
|
MOZ_ASSERT(byteLength <= INT32_MAX);
|
||||||
|
MOZ_ASSERT(byteOffset + byteLength < UINT32_MAX);
|
||||||
uint32_t bufferByteLength = arrayBuffer->byteLength();
|
MOZ_ASSERT(!arrayBuffer || !arrayBuffer->is<SharedArrayBufferObject>());
|
||||||
if (byteOffset > bufferByteLength ||
|
|
||||||
(!lengthTracking && byteLength > bufferByteLength - byteOffset))
|
|
||||||
{
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE,
|
|
||||||
"1");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lengthTracking)
|
|
||||||
byteLength = bufferByteLength - byteOffset;
|
|
||||||
|
|
||||||
RootedObject proto(cx, protoArg);
|
RootedObject proto(cx, protoArg);
|
||||||
RootedObject obj(cx);
|
RootedObject obj(cx);
|
||||||
|
|
@ -1925,72 +1893,57 @@ DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Caller should have established these preconditions, and no
|
||||||
|
// (non-self-hosted) JS code has had an opportunity to run so nothing can
|
||||||
|
// have invalidated them.
|
||||||
MOZ_ASSERT(byteOffset <= arrayBuffer->byteLength());
|
MOZ_ASSERT(byteOffset <= arrayBuffer->byteLength());
|
||||||
MOZ_ASSERT(byteOffset + byteLength <= arrayBuffer->byteLength());
|
MOZ_ASSERT(byteOffset + byteLength <= arrayBuffer->byteLength());
|
||||||
|
|
||||||
DataViewObject& dvobj = obj->as<DataViewObject>();
|
DataViewObject& dvobj = obj->as<DataViewObject>();
|
||||||
dvobj.setFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT, Int32Value(byteOffset));
|
dvobj.setFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT, Int32Value(byteOffset));
|
||||||
dvobj.setFixedSlot(TypedArrayObject::LENGTH_SLOT,
|
dvobj.setFixedSlot(TypedArrayObject::LENGTH_SLOT, Int32Value(byteLength));
|
||||||
Int32Value(lengthTracking ? TypedArrayObject::LENGTH_TRACKING
|
|
||||||
: int32_t(byteLength)));
|
|
||||||
dvobj.setFixedSlot(TypedArrayObject::BUFFER_SLOT, ObjectValue(*arrayBuffer));
|
dvobj.setFixedSlot(TypedArrayObject::BUFFER_SLOT, ObjectValue(*arrayBuffer));
|
||||||
auto dataPointer = arrayBuffer->dataPointerEither();
|
dvobj.initPrivate(arrayBuffer->dataPointer() + byteOffset);
|
||||||
dvobj.initPrivate((dataPointer + byteOffset).unwrap(/*safe - stored as private data*/));
|
|
||||||
|
|
||||||
// Include a barrier if the data view's data pointer is in the nursery, as
|
// Include a barrier if the data view's data pointer is in the nursery, as
|
||||||
// is done for typed arrays.
|
// is done for typed arrays.
|
||||||
if (arrayBuffer->is<ArrayBufferObject>() &&
|
if (!IsInsideNursery(obj) && cx->runtime()->gc.nursery.isInside(arrayBuffer->dataPointer()))
|
||||||
!IsInsideNursery(obj) &&
|
|
||||||
cx->runtime()->gc.nursery.isInside(dataPointer))
|
|
||||||
{
|
|
||||||
cx->runtime()->gc.storeBuffer.putWholeCell(obj);
|
cx->runtime()->gc.storeBuffer.putWholeCell(obj);
|
||||||
}
|
|
||||||
|
|
||||||
// Verify that the private slot is at the expected place
|
// Verify that the private slot is at the expected place
|
||||||
MOZ_ASSERT(dvobj.numFixedSlots() == TypedArrayObject::DATA_SLOT);
|
MOZ_ASSERT(dvobj.numFixedSlots() == TypedArrayObject::DATA_SLOT);
|
||||||
|
|
||||||
if (arrayBuffer->is<ArrayBufferObject>()) {
|
if (!arrayBuffer->addView(cx, &dvobj))
|
||||||
if (!arrayBuffer->as<ArrayBufferObject>().addView(cx, &dvobj))
|
return nullptr;
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return &dvobj;
|
return &dvobj;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
DataViewObject::getAndCheckConstructorArgs(JSContext* cx, JSObject* bufobj, const CallArgs& args,
|
DataViewObject::getAndCheckConstructorArgs(JSContext* cx, JSObject* bufobj, const CallArgs& args,
|
||||||
uint32_t* byteOffsetPtr, uint32_t* byteLengthPtr,
|
uint32_t* byteOffsetPtr, uint32_t* byteLengthPtr)
|
||||||
bool* lengthTrackingPtr)
|
|
||||||
{
|
{
|
||||||
if (!IsAnyArrayBuffer(bufobj)) {
|
if (!IsArrayBuffer(bufobj)) {
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
|
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
|
||||||
"DataView", "ArrayBuffer or SharedArrayBuffer",
|
"DataView", "ArrayBuffer", bufobj->getClass()->name);
|
||||||
bufobj->getClass()->name);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rooted<ArrayBufferObjectMaybeShared*> buffer(cx, &bufobj->as<ArrayBufferObjectMaybeShared>());
|
Rooted<ArrayBufferObject*> buffer(cx, &AsArrayBuffer(bufobj));
|
||||||
uint32_t byteOffset = 0;
|
uint32_t byteOffset = 0;
|
||||||
uint32_t byteLength = buffer->byteLength();
|
uint32_t byteLength = buffer->byteLength();
|
||||||
bool isResizableOrGrowable =
|
|
||||||
(buffer->is<ArrayBufferObject>() && buffer->as<ArrayBufferObject>().isResizable()) ||
|
|
||||||
(buffer->is<SharedArrayBufferObject>() &&
|
|
||||||
buffer->as<SharedArrayBufferObject>().isGrowable());
|
|
||||||
bool lengthTracking = isResizableOrGrowable && !args.hasDefined(2);
|
|
||||||
|
|
||||||
if (args.length() > 1) {
|
if (args.length() > 1) {
|
||||||
uint64_t offset;
|
if (!ToUint32(cx, args[1], &byteOffset))
|
||||||
if (!ToIndex(cx, args[1], &offset))
|
|
||||||
return false;
|
return false;
|
||||||
if (offset > INT32_MAX) {
|
if (byteOffset > INT32_MAX) {
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE,
|
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE,
|
||||||
"1");
|
"1");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
byteOffset = uint32_t(offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer->is<ArrayBufferObject>() && buffer->as<ArrayBufferObject>().isDetached()) {
|
if (buffer->isDetached()) {
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
|
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -2004,18 +1957,14 @@ DataViewObject::getAndCheckConstructorArgs(JSContext* cx, JSObject* bufobj, cons
|
||||||
|
|
||||||
if (args.get(2).isUndefined()) {
|
if (args.get(2).isUndefined()) {
|
||||||
byteLength -= byteOffset;
|
byteLength -= byteOffset;
|
||||||
lengthTracking = isResizableOrGrowable;
|
|
||||||
} else {
|
} else {
|
||||||
uint64_t viewByteLength;
|
if (!ToUint32(cx, args[2], &byteLength))
|
||||||
if (!ToIndex(cx, args[2], &viewByteLength))
|
|
||||||
return false;
|
return false;
|
||||||
lengthTracking = false;
|
if (byteLength > INT32_MAX) {
|
||||||
if (viewByteLength > INT32_MAX) {
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||||
JSMSG_ARG_INDEX_OUT_OF_RANGE, "2");
|
JSMSG_ARG_INDEX_OUT_OF_RANGE, "2");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
byteLength = uint32_t(viewByteLength);
|
|
||||||
|
|
||||||
MOZ_ASSERT(byteOffset + byteLength >= byteOffset,
|
MOZ_ASSERT(byteOffset + byteLength >= byteOffset,
|
||||||
"can't overflow: both numbers are less than INT32_MAX");
|
"can't overflow: both numbers are less than INT32_MAX");
|
||||||
|
|
@ -2034,7 +1983,6 @@ DataViewObject::getAndCheckConstructorArgs(JSContext* cx, JSObject* bufobj, cons
|
||||||
|
|
||||||
*byteOffsetPtr = byteOffset;
|
*byteOffsetPtr = byteOffset;
|
||||||
*byteLengthPtr = byteLength;
|
*byteLengthPtr = byteLength;
|
||||||
*lengthTrackingPtr = lengthTracking;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -2046,8 +1994,7 @@ DataViewObject::constructSameCompartment(JSContext* cx, HandleObject bufobj, con
|
||||||
assertSameCompartment(cx, bufobj);
|
assertSameCompartment(cx, bufobj);
|
||||||
|
|
||||||
uint32_t byteOffset, byteLength;
|
uint32_t byteOffset, byteLength;
|
||||||
bool lengthTracking;
|
if (!getAndCheckConstructorArgs(cx, bufobj, args, &byteOffset, &byteLength))
|
||||||
if (!getAndCheckConstructorArgs(cx, bufobj, args, &byteOffset, &byteLength, &lengthTracking))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
|
|
@ -2055,9 +2002,8 @@ DataViewObject::constructSameCompartment(JSContext* cx, HandleObject bufobj, con
|
||||||
if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
|
if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Rooted<ArrayBufferObjectMaybeShared*> buffer(cx, &bufobj->as<ArrayBufferObjectMaybeShared>());
|
Rooted<ArrayBufferObject*> buffer(cx, &AsArrayBuffer(bufobj));
|
||||||
JSObject* obj = DataViewObject::create(cx, byteOffset, byteLength, buffer, proto,
|
JSObject* obj = DataViewObject::create(cx, byteOffset, byteLength, buffer, proto);
|
||||||
lengthTracking);
|
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return false;
|
return false;
|
||||||
args.rval().setObject(*obj);
|
args.rval().setObject(*obj);
|
||||||
|
|
@ -2097,12 +2043,8 @@ DataViewObject::constructWrapped(JSContext* cx, HandleObject bufobj, const CallA
|
||||||
|
|
||||||
// NB: This entails the IsArrayBuffer check
|
// NB: This entails the IsArrayBuffer check
|
||||||
uint32_t byteOffset, byteLength;
|
uint32_t byteOffset, byteLength;
|
||||||
bool lengthTracking;
|
if (!getAndCheckConstructorArgs(cx, unwrapped, args, &byteOffset, &byteLength))
|
||||||
if (!getAndCheckConstructorArgs(cx, unwrapped, args, &byteOffset, &byteLength,
|
|
||||||
&lengthTracking))
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure to get the [[Prototype]] for the created view from this
|
// Make sure to get the [[Prototype]] for the created view from this
|
||||||
// compartment.
|
// compartment.
|
||||||
|
|
@ -2118,12 +2060,11 @@ DataViewObject::constructWrapped(JSContext* cx, HandleObject bufobj, const CallA
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
FixedInvokeArgs<4> args2(cx);
|
FixedInvokeArgs<3> args2(cx);
|
||||||
|
|
||||||
args2[0].set(PrivateUint32Value(byteOffset));
|
args2[0].set(PrivateUint32Value(byteOffset));
|
||||||
args2[1].set(PrivateUint32Value(byteLength));
|
args2[1].set(PrivateUint32Value(byteLength));
|
||||||
args2[2].setObject(*proto);
|
args2[2].setObject(*proto);
|
||||||
args2[3].setBoolean(lengthTracking);
|
|
||||||
|
|
||||||
RootedValue fval(cx, global->createDataViewForThis());
|
RootedValue fval(cx, global->createDataViewForThis());
|
||||||
RootedValue thisv(cx, ObjectValue(*bufobj));
|
RootedValue thisv(cx, ObjectValue(*bufobj));
|
||||||
|
|
@ -2151,11 +2092,6 @@ template <typename NativeType>
|
||||||
/* static */ uint8_t*
|
/* static */ uint8_t*
|
||||||
DataViewObject::getDataPointer(JSContext* cx, Handle<DataViewObject*> obj, uint64_t offset)
|
DataViewObject::getDataPointer(JSContext* cx, Handle<DataViewObject*> obj, uint64_t offset)
|
||||||
{
|
{
|
||||||
if (obj->isOutOfBounds()) {
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DATA_VIEW_OUT_OF_BOUNDS);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t TypeSize = sizeof(NativeType);
|
const size_t TypeSize = sizeof(NativeType);
|
||||||
if (offset > UINT32_MAX - TypeSize || offset + TypeSize > obj->byteLength()) {
|
if (offset > UINT32_MAX - TypeSize || offset + TypeSize > obj->byteLength()) {
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE,
|
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE,
|
||||||
|
|
@ -2319,7 +2255,7 @@ DataViewObject::read(JSContext* cx, Handle<DataViewObject*> obj,
|
||||||
bool isLittleEndian = args.length() >= 2 && ToBoolean(args[1]);
|
bool isLittleEndian = args.length() >= 2 && ToBoolean(args[1]);
|
||||||
|
|
||||||
// Steps 6-7.
|
// Steps 6-7.
|
||||||
if (obj->arrayBufferEither().isDetached()) {
|
if (obj->arrayBuffer().isDetached()) {
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
|
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -2418,7 +2354,7 @@ DataViewObject::write(JSContext* cx, Handle<DataViewObject*> obj,
|
||||||
bool isLittleEndian = args.length() >= 3 && ToBoolean(args[2]);
|
bool isLittleEndian = args.length() >= 3 && ToBoolean(args[2]);
|
||||||
|
|
||||||
// Steps 7-8.
|
// Steps 7-8.
|
||||||
if (obj->arrayBufferEither().isDetached()) {
|
if (obj->arrayBuffer().isDetached()) {
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
|
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -3243,13 +3179,7 @@ template<Value ValueGetter(DataViewObject* view)>
|
||||||
bool
|
bool
|
||||||
DataViewObject::getterImpl(JSContext* cx, const CallArgs& args)
|
DataViewObject::getterImpl(JSContext* cx, const CallArgs& args)
|
||||||
{
|
{
|
||||||
Rooted<DataViewObject*> view(cx, &args.thisv().toObject().as<DataViewObject>());
|
args.rval().set(ValueGetter(&args.thisv().toObject().as<DataViewObject>()));
|
||||||
if (ValueGetter != bufferValue && view->isOutOfBounds()) {
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DATA_VIEW_OUT_OF_BOUNDS);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
args.rval().set(ValueGetter(view));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,8 +52,6 @@ class TypedArrayObject : public NativeObject
|
||||||
"right buffer slot");
|
"right buffer slot");
|
||||||
|
|
||||||
// Slot containing length of the view in number of typed elements.
|
// Slot containing length of the view in number of typed elements.
|
||||||
// Length-tracking views on resizable/growable buffers store
|
|
||||||
// LENGTH_TRACKING here and compute their visible length from the buffer.
|
|
||||||
static const size_t LENGTH_SLOT = 1;
|
static const size_t LENGTH_SLOT = 1;
|
||||||
static_assert(LENGTH_SLOT == JS_TYPEDARRAYLAYOUT_LENGTH_SLOT,
|
static_assert(LENGTH_SLOT == JS_TYPEDARRAYLAYOUT_LENGTH_SLOT,
|
||||||
"self-hosted code with burned-in constants must get the "
|
"self-hosted code with burned-in constants must get the "
|
||||||
|
|
@ -67,8 +65,6 @@ class TypedArrayObject : public NativeObject
|
||||||
|
|
||||||
static const size_t RESERVED_SLOTS = 3;
|
static const size_t RESERVED_SLOTS = 3;
|
||||||
|
|
||||||
static const int32_t LENGTH_TRACKING = -1;
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
static const uint8_t ZeroLengthArrayData = 0x4A;
|
static const uint8_t ZeroLengthArrayData = 0x4A;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -143,13 +139,15 @@ class TypedArrayObject : public NativeObject
|
||||||
return tarr->getFixedSlot(BUFFER_SLOT);
|
return tarr->getFixedSlot(BUFFER_SLOT);
|
||||||
}
|
}
|
||||||
static Value byteOffsetValue(TypedArrayObject* tarr) {
|
static Value byteOffsetValue(TypedArrayObject* tarr) {
|
||||||
return Int32Value(tarr->byteOffset());
|
Value v = tarr->getFixedSlot(BYTEOFFSET_SLOT);
|
||||||
|
MOZ_ASSERT(v.toInt32() >= 0);
|
||||||
|
return v;
|
||||||
}
|
}
|
||||||
static Value byteLengthValue(TypedArrayObject* tarr) {
|
static Value byteLengthValue(TypedArrayObject* tarr) {
|
||||||
return Int32Value(tarr->byteLength());
|
return Int32Value(tarr->getFixedSlot(LENGTH_SLOT).toInt32() * tarr->bytesPerElement());
|
||||||
}
|
}
|
||||||
static Value lengthValue(TypedArrayObject* tarr) {
|
static Value lengthValue(TypedArrayObject* tarr) {
|
||||||
return Int32Value(tarr->length());
|
return tarr->getFixedSlot(LENGTH_SLOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
|
@ -161,70 +159,14 @@ class TypedArrayObject : public NativeObject
|
||||||
JSObject* bufferObject() const {
|
JSObject* bufferObject() const {
|
||||||
return bufferValue(const_cast<TypedArrayObject*>(this)).toObjectOrNull();
|
return bufferValue(const_cast<TypedArrayObject*>(this)).toObjectOrNull();
|
||||||
}
|
}
|
||||||
bool isLengthTracking() const {
|
|
||||||
return getFixedSlot(LENGTH_SLOT).toInt32() == LENGTH_TRACKING;
|
|
||||||
}
|
|
||||||
bool hasResizableOrGrowableBuffer() const {
|
|
||||||
if (!hasBuffer())
|
|
||||||
return false;
|
|
||||||
if (isSharedMemory())
|
|
||||||
return bufferShared()->isGrowable();
|
|
||||||
return bufferUnshared()->isResizable();
|
|
||||||
}
|
|
||||||
uint32_t byteOffsetMaybeOutOfBounds() const {
|
|
||||||
Value v = getFixedSlot(BYTEOFFSET_SLOT);
|
|
||||||
MOZ_ASSERT(v.toInt32() >= 0);
|
|
||||||
return v.toInt32();
|
|
||||||
}
|
|
||||||
uint32_t fixedLengthMaybeOutOfBounds() const {
|
|
||||||
int32_t length = getFixedSlot(LENGTH_SLOT).toInt32();
|
|
||||||
MOZ_ASSERT(length >= 0);
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
uint32_t bufferByteLength() const {
|
|
||||||
MOZ_ASSERT(hasBuffer());
|
|
||||||
if (isSharedMemory())
|
|
||||||
return bufferShared()->byteLength();
|
|
||||||
return bufferUnshared()->byteLength();
|
|
||||||
}
|
|
||||||
bool isOutOfBounds() const {
|
|
||||||
if (!hasBuffer())
|
|
||||||
return false;
|
|
||||||
if (hasDetachedBuffer())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
uint32_t bufferByteLength = this->bufferByteLength();
|
|
||||||
uint32_t offset = byteOffsetMaybeOutOfBounds();
|
|
||||||
if (offset > bufferByteLength)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (isLengthTracking())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint32_t byteLength = fixedLengthMaybeOutOfBounds() * bytesPerElement();
|
|
||||||
return byteLength > bufferByteLength - offset;
|
|
||||||
}
|
|
||||||
uint32_t byteOffset() const {
|
uint32_t byteOffset() const {
|
||||||
if (isOutOfBounds())
|
return byteOffsetValue(const_cast<TypedArrayObject*>(this)).toInt32();
|
||||||
return 0;
|
|
||||||
return byteOffsetMaybeOutOfBounds();
|
|
||||||
}
|
}
|
||||||
uint32_t byteLength() const {
|
uint32_t byteLength() const {
|
||||||
return length() * bytesPerElement();
|
return byteLengthValue(const_cast<TypedArrayObject*>(this)).toInt32();
|
||||||
}
|
}
|
||||||
uint32_t length() const {
|
uint32_t length() const {
|
||||||
if (!isLengthTracking()) {
|
return lengthValue(const_cast<TypedArrayObject*>(this)).toInt32();
|
||||||
if (isOutOfBounds())
|
|
||||||
return 0;
|
|
||||||
return fixedLengthMaybeOutOfBounds();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isOutOfBounds())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
uint32_t bufferByteLength = this->bufferByteLength();
|
|
||||||
uint32_t offset = byteOffsetMaybeOutOfBounds();
|
|
||||||
return (bufferByteLength - offset) / bytesPerElement();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasInlineElements() const;
|
bool hasInlineElements() const;
|
||||||
|
|
@ -524,26 +466,28 @@ class DataViewObject : public NativeObject
|
||||||
defineGetter(JSContext* cx, PropertyName* name, HandleNativeObject proto);
|
defineGetter(JSContext* cx, PropertyName* name, HandleNativeObject proto);
|
||||||
|
|
||||||
static bool getAndCheckConstructorArgs(JSContext* cx, JSObject* bufobj, const CallArgs& args,
|
static bool getAndCheckConstructorArgs(JSContext* cx, JSObject* bufobj, const CallArgs& args,
|
||||||
uint32_t *byteOffset, uint32_t* byteLength,
|
uint32_t *byteOffset, uint32_t* byteLength);
|
||||||
bool* lengthTracking);
|
|
||||||
static bool constructSameCompartment(JSContext* cx, HandleObject bufobj, const CallArgs& args);
|
static bool constructSameCompartment(JSContext* cx, HandleObject bufobj, const CallArgs& args);
|
||||||
static bool constructWrapped(JSContext* cx, HandleObject bufobj, const CallArgs& args);
|
static bool constructWrapped(JSContext* cx, HandleObject bufobj, const CallArgs& args);
|
||||||
|
|
||||||
friend bool ArrayBufferObject::createDataViewForThisImpl(JSContext* cx, const CallArgs& args);
|
friend bool ArrayBufferObject::createDataViewForThisImpl(JSContext* cx, const CallArgs& args);
|
||||||
static DataViewObject*
|
static DataViewObject*
|
||||||
create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
|
create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
|
||||||
Handle<ArrayBufferObjectMaybeShared*> arrayBuffer, JSObject* proto,
|
Handle<ArrayBufferObject*> arrayBuffer, JSObject* proto);
|
||||||
bool lengthTracking = false);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const Class class_;
|
static const Class class_;
|
||||||
|
|
||||||
static Value byteOffsetValue(DataViewObject* view) {
|
static Value byteOffsetValue(DataViewObject* view) {
|
||||||
return Int32Value(view->byteOffset());
|
Value v = view->getFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT);
|
||||||
|
MOZ_ASSERT(v.toInt32() >= 0);
|
||||||
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Value byteLengthValue(DataViewObject* view) {
|
static Value byteLengthValue(DataViewObject* view) {
|
||||||
return Int32Value(view->byteLength());
|
Value v = view->getFixedSlot(TypedArrayObject::LENGTH_SLOT);
|
||||||
|
MOZ_ASSERT(v.toInt32() >= 0);
|
||||||
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Value bufferValue(DataViewObject* view) {
|
static Value bufferValue(DataViewObject* view) {
|
||||||
|
|
@ -551,66 +495,21 @@ class DataViewObject : public NativeObject
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t byteOffset() const {
|
uint32_t byteOffset() const {
|
||||||
if (isOutOfBounds())
|
return byteOffsetValue(const_cast<DataViewObject*>(this)).toInt32();
|
||||||
return 0;
|
|
||||||
return byteOffsetMaybeOutOfBounds();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t byteLength() const {
|
uint32_t byteLength() const {
|
||||||
if (isOutOfBounds())
|
return byteLengthValue(const_cast<DataViewObject*>(this)).toInt32();
|
||||||
return 0;
|
|
||||||
if (isLengthTracking())
|
|
||||||
return arrayBufferEither().byteLength() - byteOffsetMaybeOutOfBounds();
|
|
||||||
return fixedByteLengthMaybeOutOfBounds();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayBufferObjectMaybeShared& arrayBufferEither() const {
|
ArrayBufferObject& arrayBuffer() const {
|
||||||
return bufferValue(const_cast<DataViewObject*>(this)).
|
return bufferValue(const_cast<DataViewObject*>(this)).toObject().as<ArrayBufferObject>();
|
||||||
toObject().as<ArrayBufferObjectMaybeShared>();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isSharedMemory() const {
|
|
||||||
return bufferValue(const_cast<DataViewObject*>(this)).
|
|
||||||
toObject().is<SharedArrayBufferObject>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void* dataPointer() const {
|
void* dataPointer() const {
|
||||||
return getPrivate();
|
return getPrivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isLengthTracking() const {
|
|
||||||
return getFixedSlot(TypedArrayObject::LENGTH_SLOT).toInt32() ==
|
|
||||||
TypedArrayObject::LENGTH_TRACKING;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t byteOffsetMaybeOutOfBounds() const {
|
|
||||||
Value v = getFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT);
|
|
||||||
MOZ_ASSERT(v.toInt32() >= 0);
|
|
||||||
return v.toInt32();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t fixedByteLengthMaybeOutOfBounds() const {
|
|
||||||
int32_t length = getFixedSlot(TypedArrayObject::LENGTH_SLOT).toInt32();
|
|
||||||
MOZ_ASSERT(length >= 0);
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isOutOfBounds() const {
|
|
||||||
const ArrayBufferObjectMaybeShared& buffer = arrayBufferEither();
|
|
||||||
if (buffer.isDetached())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
uint32_t bufferByteLength = buffer.byteLength();
|
|
||||||
uint32_t offset = byteOffsetMaybeOutOfBounds();
|
|
||||||
if (offset > bufferByteLength)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (isLengthTracking())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return fixedByteLengthMaybeOutOfBounds() > bufferByteLength - offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool class_constructor(JSContext* cx, unsigned argc, Value* vp);
|
static bool class_constructor(JSContext* cx, unsigned argc, Value* vp);
|
||||||
|
|
||||||
static bool getInt8Impl(JSContext* cx, const CallArgs& args);
|
static bool getInt8Impl(JSContext* cx, const CallArgs& args);
|
||||||
|
|
|
||||||
|
|
@ -1446,7 +1446,6 @@ ReloadPrefsCallback(const char* pref, void* data)
|
||||||
bool extraWarnings = Preferences::GetBool(JS_OPTIONS_DOT_STR "strict");
|
bool extraWarnings = Preferences::GetBool(JS_OPTIONS_DOT_STR "strict");
|
||||||
|
|
||||||
bool streams = Preferences::GetBool(JS_OPTIONS_DOT_STR "streams");
|
bool streams = Preferences::GetBool(JS_OPTIONS_DOT_STR "streams");
|
||||||
bool weakRefs = Preferences::GetBool(JS_OPTIONS_DOT_STR "weakrefs");
|
|
||||||
|
|
||||||
bool unboxedObjects = Preferences::GetBool(JS_OPTIONS_DOT_STR "unboxed_objects");
|
bool unboxedObjects = Preferences::GetBool(JS_OPTIONS_DOT_STR "unboxed_objects");
|
||||||
|
|
||||||
|
|
@ -1473,8 +1472,7 @@ ReloadPrefsCallback(const char* pref, void* data)
|
||||||
.setWerror(werror)
|
.setWerror(werror)
|
||||||
.setExtraWarnings(extraWarnings)
|
.setExtraWarnings(extraWarnings)
|
||||||
.setArrayProtoValues(arrayProtoValues)
|
.setArrayProtoValues(arrayProtoValues)
|
||||||
.setStreams(streams)
|
.setStreams(streams);
|
||||||
.setWeakRefs(weakRefs);
|
|
||||||
|
|
||||||
JS_SetParallelParsingEnabled(cx, parallelParsing);
|
JS_SetParallelParsingEnabled(cx, parallelParsing);
|
||||||
JS_SetOffthreadIonCompilationEnabled(cx, offthreadIonCompilation);
|
JS_SetOffthreadIonCompilationEnabled(cx, offthreadIonCompilation);
|
||||||
|
|
|
||||||
|
|
@ -1,960 +0,0 @@
|
||||||
/* -*- 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 "CSSNestingFlattener.h"
|
|
||||||
|
|
||||||
#include "mozilla/Assertions.h"
|
|
||||||
#include "nsString.h"
|
|
||||||
#include "nsTArray.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace css {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class CSSNestingFlattener final
|
|
||||||
{
|
|
||||||
using SelectorList = nsTArray<nsString>;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit CSSNestingFlattener(const nsAString& aInput)
|
|
||||||
: mInput(aInput)
|
|
||||||
, mPos(0)
|
|
||||||
, mSawNesting(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Flatten(nsAString& aOutput)
|
|
||||||
{
|
|
||||||
nsAutoString flattened;
|
|
||||||
if (!ProcessStylesheet(flattened, false)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SkipWhitespaceAndComments();
|
|
||||||
if (mPos != mInput.Length() || !mSawNesting) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
aOutput.Assign(flattened);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static bool
|
|
||||||
IsCSSWhitespace(char16_t aChar)
|
|
||||||
{
|
|
||||||
return aChar == ' ' || aChar == '\t' || aChar == '\r' ||
|
|
||||||
aChar == '\n' || aChar == '\f';
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
AtEnd() const
|
|
||||||
{
|
|
||||||
return mPos >= mInput.Length();
|
|
||||||
}
|
|
||||||
|
|
||||||
char16_t
|
|
||||||
Peek() const
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(!AtEnd(), "cannot peek past end");
|
|
||||||
return mInput.CharAt(mPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
StartsWithComment() const
|
|
||||||
{
|
|
||||||
return mPos + 1 < mInput.Length() &&
|
|
||||||
mInput.CharAt(mPos) == '/' &&
|
|
||||||
mInput.CharAt(mPos + 1) == '*';
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
SkipComment()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(StartsWithComment(), "expected comment");
|
|
||||||
|
|
||||||
mPos += 2;
|
|
||||||
while (mPos + 1 < mInput.Length()) {
|
|
||||||
if (mInput.CharAt(mPos) == '*' && mInput.CharAt(mPos + 1) == '/') {
|
|
||||||
mPos += 2;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
++mPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SkipWhitespaceAndComments()
|
|
||||||
{
|
|
||||||
while (!AtEnd()) {
|
|
||||||
if (IsCSSWhitespace(Peek())) {
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (StartsWithComment()) {
|
|
||||||
if (!SkipComment()) {
|
|
||||||
mPos = mInput.Length();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
SkipString(char16_t aQuote)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(!AtEnd() && Peek() == aQuote, "expected string start");
|
|
||||||
|
|
||||||
++mPos;
|
|
||||||
while (!AtEnd()) {
|
|
||||||
char16_t c = Peek();
|
|
||||||
++mPos;
|
|
||||||
if (c == aQuote) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (c == '\\' && !AtEnd()) {
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '\n' || c == '\r' || c == '\f') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
TrimWhitespace(nsAString& aText)
|
|
||||||
{
|
|
||||||
uint32_t start = 0;
|
|
||||||
uint32_t end = aText.Length();
|
|
||||||
|
|
||||||
while (start < end && IsCSSWhitespace(aText.CharAt(start))) {
|
|
||||||
++start;
|
|
||||||
}
|
|
||||||
while (end > start && IsCSSWhitespace(aText.CharAt(end - 1))) {
|
|
||||||
--end;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (start == 0 && end == aText.Length()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
aText.Assign(Substring(aText, start, end - start));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
SplitSelectorList(const nsAString& aSelectorText, SelectorList& aSelectors)
|
|
||||||
{
|
|
||||||
uint32_t itemStart = 0;
|
|
||||||
int32_t parenDepth = 0;
|
|
||||||
int32_t bracketDepth = 0;
|
|
||||||
bool inComment = false;
|
|
||||||
char16_t stringQuote = 0;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < aSelectorText.Length(); ++i) {
|
|
||||||
char16_t c = aSelectorText.CharAt(i);
|
|
||||||
|
|
||||||
if (inComment) {
|
|
||||||
if (c == '*' && i + 1 < aSelectorText.Length() &&
|
|
||||||
aSelectorText.CharAt(i + 1) == '/') {
|
|
||||||
inComment = false;
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stringQuote) {
|
|
||||||
if (c == '\\') {
|
|
||||||
++i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == stringQuote) {
|
|
||||||
stringQuote = 0;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '/' && i + 1 < aSelectorText.Length() &&
|
|
||||||
aSelectorText.CharAt(i + 1) == '*') {
|
|
||||||
inComment = true;
|
|
||||||
++i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '"' || c == '\'') {
|
|
||||||
stringQuote = c;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '(') {
|
|
||||||
++parenDepth;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == ')' && parenDepth > 0) {
|
|
||||||
--parenDepth;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '[') {
|
|
||||||
++bracketDepth;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == ']' && bracketDepth > 0) {
|
|
||||||
--bracketDepth;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == ',' && parenDepth == 0 && bracketDepth == 0) {
|
|
||||||
nsAutoString selector;
|
|
||||||
selector.Assign(Substring(aSelectorText, itemStart, i - itemStart));
|
|
||||||
TrimWhitespace(selector);
|
|
||||||
if (!selector.IsEmpty()) {
|
|
||||||
aSelectors.AppendElement(selector);
|
|
||||||
}
|
|
||||||
itemStart = i + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoString selector;
|
|
||||||
selector.Assign(Substring(aSelectorText, itemStart));
|
|
||||||
TrimWhitespace(selector);
|
|
||||||
if (!selector.IsEmpty()) {
|
|
||||||
aSelectors.AppendElement(selector);
|
|
||||||
}
|
|
||||||
|
|
||||||
return !aSelectors.IsEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
SelectorHasAmpersand(const nsAString& aSelector) const
|
|
||||||
{
|
|
||||||
bool inComment = false;
|
|
||||||
char16_t stringQuote = 0;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < aSelector.Length(); ++i) {
|
|
||||||
char16_t c = aSelector.CharAt(i);
|
|
||||||
|
|
||||||
if (inComment) {
|
|
||||||
if (c == '*' && i + 1 < aSelector.Length() &&
|
|
||||||
aSelector.CharAt(i + 1) == '/') {
|
|
||||||
inComment = false;
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stringQuote) {
|
|
||||||
if (c == '\\') {
|
|
||||||
++i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == stringQuote) {
|
|
||||||
stringQuote = 0;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '/' && i + 1 < aSelector.Length() &&
|
|
||||||
aSelector.CharAt(i + 1) == '*') {
|
|
||||||
inComment = true;
|
|
||||||
++i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '"' || c == '\'') {
|
|
||||||
stringQuote = c;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '&') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ReplaceAmpersands(const nsAString& aSelector,
|
|
||||||
const nsAString& aParent,
|
|
||||||
nsAString& aOutput) const
|
|
||||||
{
|
|
||||||
bool inComment = false;
|
|
||||||
char16_t stringQuote = 0;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < aSelector.Length(); ++i) {
|
|
||||||
char16_t c = aSelector.CharAt(i);
|
|
||||||
|
|
||||||
if (inComment) {
|
|
||||||
aOutput.Append(c);
|
|
||||||
if (c == '*' && i + 1 < aSelector.Length() &&
|
|
||||||
aSelector.CharAt(i + 1) == '/') {
|
|
||||||
aOutput.Append('/');
|
|
||||||
inComment = false;
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stringQuote) {
|
|
||||||
aOutput.Append(c);
|
|
||||||
if (c == '\\' && i + 1 < aSelector.Length()) {
|
|
||||||
aOutput.Append(aSelector.CharAt(i + 1));
|
|
||||||
++i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == stringQuote) {
|
|
||||||
stringQuote = 0;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '/' && i + 1 < aSelector.Length() &&
|
|
||||||
aSelector.CharAt(i + 1) == '*') {
|
|
||||||
aOutput.AppendLiteral("/*");
|
|
||||||
inComment = true;
|
|
||||||
++i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '"' || c == '\'') {
|
|
||||||
aOutput.Append(c);
|
|
||||||
stringQuote = c;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '&') {
|
|
||||||
aOutput.Append(aParent);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
aOutput.Append(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ExpandNestedSelectors(const SelectorList& aParents,
|
|
||||||
const nsAString& aNestedSelectorText,
|
|
||||||
SelectorList& aSelectors)
|
|
||||||
{
|
|
||||||
SelectorList nestedSelectors;
|
|
||||||
if (!SplitSelectorList(aNestedSelectorText, nestedSelectors)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const nsString& nestedSelector : nestedSelectors) {
|
|
||||||
bool hasAmpersand = SelectorHasAmpersand(nestedSelector);
|
|
||||||
for (const nsString& parentSelector : aParents) {
|
|
||||||
nsAutoString combined;
|
|
||||||
if (hasAmpersand) {
|
|
||||||
ReplaceAmpersands(nestedSelector, parentSelector, combined);
|
|
||||||
} else {
|
|
||||||
combined.Assign(parentSelector);
|
|
||||||
if (!combined.IsEmpty()) {
|
|
||||||
combined.Append(' ');
|
|
||||||
}
|
|
||||||
combined.Append(nestedSelector);
|
|
||||||
}
|
|
||||||
TrimWhitespace(combined);
|
|
||||||
if (!combined.IsEmpty()) {
|
|
||||||
aSelectors.AppendElement(combined);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return !aSelectors.IsEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
AppendSelectors(const SelectorList& aSelectors, nsAString& aOutput)
|
|
||||||
{
|
|
||||||
for (uint32_t i = 0; i < aSelectors.Length(); ++i) {
|
|
||||||
if (i) {
|
|
||||||
aOutput.AppendLiteral(", ");
|
|
||||||
}
|
|
||||||
aOutput.Append(aSelectors[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
StartsNestedSelector(char16_t aChar)
|
|
||||||
{
|
|
||||||
switch (aChar) {
|
|
||||||
case '.':
|
|
||||||
case '#':
|
|
||||||
case '[':
|
|
||||||
case ':':
|
|
||||||
case '&':
|
|
||||||
case '|':
|
|
||||||
case '>':
|
|
||||||
case '+':
|
|
||||||
case '~':
|
|
||||||
case '*':
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
StartsPotentialTypeSelector(char16_t aChar)
|
|
||||||
{
|
|
||||||
return (aChar >= 'a' && aChar <= 'z') ||
|
|
||||||
(aChar >= 'A' && aChar <= 'Z') ||
|
|
||||||
aChar == '_' ||
|
|
||||||
aChar == '\\' ||
|
|
||||||
aChar >= 0x80;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
LooksLikeTypeSelectorRule() const
|
|
||||||
{
|
|
||||||
if (AtEnd() || !StartsPotentialTypeSelector(Peek())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t pos = mPos;
|
|
||||||
int32_t parenDepth = 0;
|
|
||||||
int32_t bracketDepth = 0;
|
|
||||||
bool inComment = false;
|
|
||||||
char16_t stringQuote = 0;
|
|
||||||
|
|
||||||
while (pos < mInput.Length()) {
|
|
||||||
char16_t c = mInput.CharAt(pos);
|
|
||||||
|
|
||||||
if (inComment) {
|
|
||||||
if (c == '*' && pos + 1 < mInput.Length() &&
|
|
||||||
mInput.CharAt(pos + 1) == '/') {
|
|
||||||
inComment = false;
|
|
||||||
++pos;
|
|
||||||
}
|
|
||||||
++pos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stringQuote) {
|
|
||||||
if (c == '\\' && pos + 1 < mInput.Length()) {
|
|
||||||
pos += 2;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == stringQuote) {
|
|
||||||
stringQuote = 0;
|
|
||||||
}
|
|
||||||
++pos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '/' && pos + 1 < mInput.Length() &&
|
|
||||||
mInput.CharAt(pos + 1) == '*') {
|
|
||||||
inComment = true;
|
|
||||||
pos += 2;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '"' || c == '\'') {
|
|
||||||
stringQuote = c;
|
|
||||||
++pos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '(') {
|
|
||||||
++parenDepth;
|
|
||||||
++pos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == ')' && parenDepth > 0) {
|
|
||||||
--parenDepth;
|
|
||||||
++pos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '[') {
|
|
||||||
++bracketDepth;
|
|
||||||
++pos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == ']' && bracketDepth > 0) {
|
|
||||||
--bracketDepth;
|
|
||||||
++pos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parenDepth == 0 && bracketDepth == 0) {
|
|
||||||
if (c == '{') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (c == ';' || c == '}') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
++pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
IsAtRuleNameChar(char16_t aChar)
|
|
||||||
{
|
|
||||||
return (aChar >= 'a' && aChar <= 'z') ||
|
|
||||||
(aChar >= 'A' && aChar <= 'Z') ||
|
|
||||||
(aChar >= '0' && aChar <= '9') ||
|
|
||||||
aChar == '-';
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
LowercaseASCII(nsACString& aText)
|
|
||||||
{
|
|
||||||
for (uint32_t i = 0; i < aText.Length(); ++i) {
|
|
||||||
char c = aText.CharAt(i);
|
|
||||||
if (c >= 'A' && c <= 'Z') {
|
|
||||||
aText.BeginWriting()[i] = c - 'A' + 'a';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
ShouldProcessGroupRule(const nsACString& aName)
|
|
||||||
{
|
|
||||||
return aName.EqualsLiteral("media") ||
|
|
||||||
aName.EqualsLiteral("supports") ||
|
|
||||||
aName.EqualsLiteral("document") ||
|
|
||||||
aName.EqualsLiteral("layer");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
FlushDeclarations(const SelectorList& aSelectors,
|
|
||||||
nsAString& aDeclarations,
|
|
||||||
nsAString& aOutput)
|
|
||||||
{
|
|
||||||
nsAutoString declarations;
|
|
||||||
declarations.Assign(aDeclarations);
|
|
||||||
TrimWhitespace(declarations);
|
|
||||||
aDeclarations.Truncate();
|
|
||||||
|
|
||||||
if (declarations.IsEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
AppendSelectors(aSelectors, aOutput);
|
|
||||||
aOutput.AppendLiteral(" { ");
|
|
||||||
aOutput.Append(declarations);
|
|
||||||
aOutput.AppendLiteral(" }\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ReadRawBlockBody(nsAString& aBody)
|
|
||||||
{
|
|
||||||
uint32_t start = mPos;
|
|
||||||
int32_t depth = 0;
|
|
||||||
|
|
||||||
while (!AtEnd()) {
|
|
||||||
char16_t c = Peek();
|
|
||||||
if (c == '"' || c == '\'') {
|
|
||||||
if (!SkipString(c)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (StartsWithComment()) {
|
|
||||||
if (!SkipComment()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '{') {
|
|
||||||
++depth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '}') {
|
|
||||||
if (depth == 0) {
|
|
||||||
aBody.Assign(Substring(mInput, start, mPos - start));
|
|
||||||
++mPos;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
--depth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
++mPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ReadQualifiedRulePrelude(nsAString& aPrelude)
|
|
||||||
{
|
|
||||||
uint32_t start = mPos;
|
|
||||||
int32_t parenDepth = 0;
|
|
||||||
int32_t bracketDepth = 0;
|
|
||||||
|
|
||||||
while (!AtEnd()) {
|
|
||||||
char16_t c = Peek();
|
|
||||||
if (c == '"' || c == '\'') {
|
|
||||||
if (!SkipString(c)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (StartsWithComment()) {
|
|
||||||
if (!SkipComment()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '(') {
|
|
||||||
++parenDepth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == ')' && parenDepth > 0) {
|
|
||||||
--parenDepth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '[') {
|
|
||||||
++bracketDepth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == ']' && bracketDepth > 0) {
|
|
||||||
--bracketDepth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '{' && parenDepth == 0 && bracketDepth == 0) {
|
|
||||||
aPrelude.Assign(Substring(mInput, start, mPos - start));
|
|
||||||
TrimWhitespace(aPrelude);
|
|
||||||
++mPos;
|
|
||||||
return !aPrelude.IsEmpty();
|
|
||||||
}
|
|
||||||
if ((c == ';' || c == '}') && parenDepth == 0 && bracketDepth == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
++mPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ReadAtRulePrelude(nsAString& aPrelude, nsACString& aName, bool& aHasBlock)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(!AtEnd() && Peek() == '@', "expected at-rule");
|
|
||||||
|
|
||||||
uint32_t start = mPos;
|
|
||||||
++mPos;
|
|
||||||
aName.Truncate();
|
|
||||||
while (!AtEnd() && IsAtRuleNameChar(Peek())) {
|
|
||||||
char16_t c = Peek();
|
|
||||||
aName.Append(char(c <= 0x7f ? c : '?'));
|
|
||||||
++mPos;
|
|
||||||
}
|
|
||||||
LowercaseASCII(aName);
|
|
||||||
|
|
||||||
int32_t parenDepth = 0;
|
|
||||||
int32_t bracketDepth = 0;
|
|
||||||
while (!AtEnd()) {
|
|
||||||
char16_t c = Peek();
|
|
||||||
if (c == '"' || c == '\'') {
|
|
||||||
if (!SkipString(c)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (StartsWithComment()) {
|
|
||||||
if (!SkipComment()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '(') {
|
|
||||||
++parenDepth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == ')' && parenDepth > 0) {
|
|
||||||
--parenDepth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '[') {
|
|
||||||
++bracketDepth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == ']' && bracketDepth > 0) {
|
|
||||||
--bracketDepth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (parenDepth == 0 && bracketDepth == 0) {
|
|
||||||
if (c == ';') {
|
|
||||||
aPrelude.Assign(Substring(mInput, start, mPos - start));
|
|
||||||
TrimWhitespace(aPrelude);
|
|
||||||
++mPos;
|
|
||||||
aHasBlock = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (c == '{') {
|
|
||||||
aPrelude.Assign(Substring(mInput, start, mPos - start));
|
|
||||||
TrimWhitespace(aPrelude);
|
|
||||||
++mPos;
|
|
||||||
aHasBlock = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
++mPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ConsumeDeclaration(nsAString& aDeclaration)
|
|
||||||
{
|
|
||||||
uint32_t start = mPos;
|
|
||||||
int32_t parenDepth = 0;
|
|
||||||
int32_t bracketDepth = 0;
|
|
||||||
int32_t braceDepth = 0;
|
|
||||||
|
|
||||||
while (!AtEnd()) {
|
|
||||||
char16_t c = Peek();
|
|
||||||
if (c == '"' || c == '\'') {
|
|
||||||
if (!SkipString(c)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (StartsWithComment()) {
|
|
||||||
if (!SkipComment()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '(') {
|
|
||||||
++parenDepth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == ')' && parenDepth > 0) {
|
|
||||||
--parenDepth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '[') {
|
|
||||||
++bracketDepth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == ']' && bracketDepth > 0) {
|
|
||||||
--bracketDepth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '{') {
|
|
||||||
++braceDepth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '}') {
|
|
||||||
if (braceDepth == 0 && parenDepth == 0 && bracketDepth == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (braceDepth > 0) {
|
|
||||||
--braceDepth;
|
|
||||||
}
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == ';' && parenDepth == 0 && bracketDepth == 0 &&
|
|
||||||
braceDepth == 0) {
|
|
||||||
++mPos;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++mPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
aDeclaration.Assign(Substring(mInput, start, mPos - start));
|
|
||||||
TrimWhitespace(aDeclaration);
|
|
||||||
if (aDeclaration.IsEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (aDeclaration.Last() != ';') {
|
|
||||||
aDeclaration.Append(';');
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ParseAtRule(nsAString& aOutput, const SelectorList* aParents)
|
|
||||||
{
|
|
||||||
nsAutoString prelude;
|
|
||||||
nsAutoCString name;
|
|
||||||
bool hasBlock = false;
|
|
||||||
if (!ReadAtRulePrelude(prelude, name, hasBlock)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasBlock) {
|
|
||||||
aOutput.Append(prelude);
|
|
||||||
aOutput.AppendLiteral(";\n");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ShouldProcessGroupRule(name)) {
|
|
||||||
nsAutoString body;
|
|
||||||
if (!ReadRawBlockBody(body)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
aOutput.Append(prelude);
|
|
||||||
aOutput.AppendLiteral(" {");
|
|
||||||
aOutput.Append(body);
|
|
||||||
aOutput.AppendLiteral("}\n");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoString inner;
|
|
||||||
if (aParents) {
|
|
||||||
mSawNesting = true;
|
|
||||||
if (!ProcessStyleContext(*aParents, inner)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!ProcessStylesheet(inner, true)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
aOutput.Append(prelude);
|
|
||||||
aOutput.AppendLiteral(" {\n");
|
|
||||||
aOutput.Append(inner);
|
|
||||||
aOutput.AppendLiteral("}\n");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ParseQualifiedRule(nsAString& aOutput, const SelectorList* aParents)
|
|
||||||
{
|
|
||||||
nsAutoString prelude;
|
|
||||||
if (!ReadQualifiedRulePrelude(prelude)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SelectorList selectors;
|
|
||||||
if (aParents) {
|
|
||||||
mSawNesting = true;
|
|
||||||
if (!ExpandNestedSelectors(*aParents, prelude, selectors)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (!SplitSelectorList(prelude, selectors)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ProcessStyleContext(selectors, aOutput);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ProcessStyleContext(const SelectorList& aSelectors, nsAString& aOutput)
|
|
||||||
{
|
|
||||||
nsAutoString declarations;
|
|
||||||
|
|
||||||
while (!AtEnd()) {
|
|
||||||
SkipWhitespaceAndComments();
|
|
||||||
if (AtEnd()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
char16_t c = Peek();
|
|
||||||
if (c == '}') {
|
|
||||||
++mPos;
|
|
||||||
FlushDeclarations(aSelectors, declarations, aOutput);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '@') {
|
|
||||||
FlushDeclarations(aSelectors, declarations, aOutput);
|
|
||||||
if (!ParseAtRule(aOutput, &aSelectors)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StartsNestedSelector(c) || LooksLikeTypeSelectorRule()) {
|
|
||||||
FlushDeclarations(aSelectors, declarations, aOutput);
|
|
||||||
if (!ParseQualifiedRule(aOutput, &aSelectors)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoString declaration;
|
|
||||||
if (!ConsumeDeclaration(declaration)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!declarations.IsEmpty()) {
|
|
||||||
declarations.Append(' ');
|
|
||||||
}
|
|
||||||
declarations.Append(declaration);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ProcessStylesheet(nsAString& aOutput, bool aStopAtBlockEnd)
|
|
||||||
{
|
|
||||||
while (!AtEnd()) {
|
|
||||||
SkipWhitespaceAndComments();
|
|
||||||
if (AtEnd()) {
|
|
||||||
return !aStopAtBlockEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Peek() == '}') {
|
|
||||||
if (!aStopAtBlockEnd) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
++mPos;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Peek() == '@') {
|
|
||||||
if (!ParseAtRule(aOutput, nullptr)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!ParseQualifiedRule(aOutput, nullptr)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return !aStopAtBlockEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
const nsAString& mInput;
|
|
||||||
uint32_t mPos;
|
|
||||||
bool mSawNesting;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
bool
|
|
||||||
FlattenBasicCSSNesting(const nsAString& aInput, nsAString& aOutput)
|
|
||||||
{
|
|
||||||
CSSNestingFlattener flattener(aInput);
|
|
||||||
return flattener.Flatten(aOutput);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace css
|
|
||||||
} // namespace mozilla
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
/* -*- 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 CSSNestingFlattener_h
|
|
||||||
#define CSSNestingFlattener_h
|
|
||||||
|
|
||||||
class nsAString;
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace css {
|
|
||||||
|
|
||||||
bool FlattenBasicCSSNesting(const nsAString& aInput, nsAString& aOutput);
|
|
||||||
|
|
||||||
} // namespace css
|
|
||||||
} // namespace mozilla
|
|
||||||
|
|
||||||
#endif // CSSNestingFlattener_h
|
|
||||||
|
|
@ -885,10 +885,9 @@ SheetLoadData::OnStreamComplete(nsIUnicharStreamLoader* aLoader,
|
||||||
}
|
}
|
||||||
|
|
||||||
// In standards mode, a style sheet must have one of these MIME
|
// In standards mode, a style sheet must have one of these MIME
|
||||||
// types to be processed at all, unless it is same-origin.
|
// types to be processed at all. In quirks mode, we accept any
|
||||||
// For same-origin sheets, we accept any MIME type to match modern
|
// MIME type, but only if the style sheet is same-origin with the
|
||||||
// browser behavior (Chrome, Firefox). Cross-origin sheets require
|
// requesting document or parent sheet. See bug 524223.
|
||||||
// a valid CSS MIME type for security.
|
|
||||||
|
|
||||||
bool validType = contentType.EqualsLiteral("text/css") ||
|
bool validType = contentType.EqualsLiteral("text/css") ||
|
||||||
contentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE) ||
|
contentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE) ||
|
||||||
|
|
@ -907,7 +906,7 @@ SheetLoadData::OnStreamComplete(nsIUnicharStreamLoader* aLoader,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sameOrigin) {
|
if (sameOrigin && mLoader->mCompatMode == eCompatibility_NavQuirks) {
|
||||||
errorMessage = "MimeNotCssWarn";
|
errorMessage = "MimeNotCssWarn";
|
||||||
errorFlag = nsIScriptError::warningFlag;
|
errorFlag = nsIScriptError::warningFlag;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,6 @@ UNIFIED_SOURCES += [
|
||||||
'CounterStyleManager.cpp',
|
'CounterStyleManager.cpp',
|
||||||
'CSS.cpp',
|
'CSS.cpp',
|
||||||
'CSSLexer.cpp',
|
'CSSLexer.cpp',
|
||||||
'CSSNestingFlattener.cpp',
|
|
||||||
'CSSRuleList.cpp',
|
'CSSRuleList.cpp',
|
||||||
'CSSStyleSheet.cpp',
|
'CSSStyleSheet.cpp',
|
||||||
'CSSVariableDeclarations.cpp',
|
'CSSVariableDeclarations.cpp',
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
#include "mozilla/ArrayUtils.h"
|
#include "mozilla/ArrayUtils.h"
|
||||||
#include "mozilla/DebugOnly.h"
|
#include "mozilla/DebugOnly.h"
|
||||||
#include "mozilla/Maybe.h"
|
|
||||||
#include "mozilla/Move.h"
|
#include "mozilla/Move.h"
|
||||||
#include "mozilla/MathAlgorithms.h"
|
#include "mozilla/MathAlgorithms.h"
|
||||||
#include "mozilla/TypedEnumBits.h"
|
#include "mozilla/TypedEnumBits.h"
|
||||||
|
|
@ -18,7 +17,6 @@
|
||||||
#include <regex> // for std::regex and std::regex_match
|
#include <regex> // for std::regex and std::regex_match
|
||||||
|
|
||||||
#include "nsCSSParser.h"
|
#include "nsCSSParser.h"
|
||||||
#include "CSSNestingFlattener.h"
|
|
||||||
#include "nsAlgorithm.h"
|
#include "nsAlgorithm.h"
|
||||||
#include "nsCSSProps.h"
|
#include "nsCSSProps.h"
|
||||||
#include "nsCSSKeywords.h"
|
#include "nsCSSKeywords.h"
|
||||||
|
|
@ -73,7 +71,6 @@ static bool sMozGradientsEnabled;
|
||||||
static bool sControlCharVisibility;
|
static bool sControlCharVisibility;
|
||||||
static bool sLegacyNegationPseudoClassEnabled;
|
static bool sLegacyNegationPseudoClassEnabled;
|
||||||
static bool sCascadeLayersEnabled;
|
static bool sCascadeLayersEnabled;
|
||||||
static bool sNestingEnabled;
|
|
||||||
|
|
||||||
const uint32_t
|
const uint32_t
|
||||||
nsCSSProps::kParserVariantTable[eCSSProperty_COUNT_no_shorthands] = {
|
nsCSSProps::kParserVariantTable[eCSSProperty_COUNT_no_shorthands] = {
|
||||||
|
|
@ -1826,14 +1823,7 @@ CSSParserImpl::ParseSheet(const nsAString& aInput,
|
||||||
"Sheet principal does not match passed principal");
|
"Sheet principal does not match passed principal");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
nsAutoString flattenedInput;
|
nsCSSScanner scanner(aInput, aLineNumber);
|
||||||
const nsAString* input = &aInput;
|
|
||||||
if (sNestingEnabled &&
|
|
||||||
mozilla::css::FlattenBasicCSSNesting(aInput, flattenedInput)) {
|
|
||||||
input = &flattenedInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCSSScanner scanner(*input, aLineNumber);
|
|
||||||
css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aSheetURI);
|
css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aSheetURI);
|
||||||
InitScanner(scanner, reporter, aSheetURI, aBaseURI, aSheetPrincipal);
|
InitScanner(scanner, reporter, aSheetURI, aBaseURI, aSheetPrincipal);
|
||||||
|
|
||||||
|
|
@ -18997,8 +18987,6 @@ nsCSSParser::Startup()
|
||||||
"layout.css.legacy-negation-pseudo.enabled");
|
"layout.css.legacy-negation-pseudo.enabled");
|
||||||
Preferences::AddBoolVarCache(&sCascadeLayersEnabled,
|
Preferences::AddBoolVarCache(&sCascadeLayersEnabled,
|
||||||
"layout.css.cascade-layers.enabled");
|
"layout.css.cascade-layers.enabled");
|
||||||
Preferences::AddBoolVarCache(&sNestingEnabled,
|
|
||||||
"layout.css.nesting.enabled");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCSSParser::nsCSSParser(mozilla::css::Loader* aLoader,
|
nsCSSParser::nsCSSParser(mozilla::css::Loader* aLoader,
|
||||||
|
|
|
||||||
|
|
@ -72,9 +72,6 @@ support-files = file_animations_with_disabled_properties.html
|
||||||
[test_attribute_selector_eof_behavior.html]
|
[test_attribute_selector_eof_behavior.html]
|
||||||
[test_aspect_ratio_property.html]
|
[test_aspect_ratio_property.html]
|
||||||
[test_background_blend_mode.html]
|
[test_background_blend_mode.html]
|
||||||
[test_basic_nesting_flattening.html]
|
|
||||||
[test_nesting_flattening_parser_edges.html]
|
|
||||||
[test_nesting_flattening_recovery.html]
|
|
||||||
[test_box_size_keywords.html]
|
[test_box_size_keywords.html]
|
||||||
[test_bug73586.html]
|
[test_bug73586.html]
|
||||||
[test_css_math_functions.html]
|
[test_css_math_functions.html]
|
||||||
|
|
|
||||||
|
|
@ -1,146 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>Test for Basic CSS Nesting Flattening</title>
|
|
||||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
|
||||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="scope" class="scope order">
|
|
||||||
<span id="desc" class="desc"></span>
|
|
||||||
</div>
|
|
||||||
<div id="button" class="button active"></div>
|
|
||||||
<pre id="standalone-log"></pre>
|
|
||||||
<script>
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
function colorOf(win, element, property) {
|
|
||||||
return win.getComputedStyle(element).getPropertyValue(property);
|
|
||||||
}
|
|
||||||
|
|
||||||
function appendTestSheet() {
|
|
||||||
var style = document.createElement("style");
|
|
||||||
style.textContent =
|
|
||||||
".scope {\n" +
|
|
||||||
" color: rgb(1, 2, 3);\n" +
|
|
||||||
" .desc {\n" +
|
|
||||||
" color: rgb(4, 5, 6);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" span {\n" +
|
|
||||||
" border-left-style: solid;\n" +
|
|
||||||
" border-left-color: rgb(19, 20, 21);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" span:first-child, span:last-child {\n" +
|
|
||||||
" border-bottom-style: solid;\n" +
|
|
||||||
" border-bottom-color: rgb(22, 23, 24);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" background-color: rgb(7, 8, 9);\n" +
|
|
||||||
"}\n" +
|
|
||||||
"\n" +
|
|
||||||
".button {\n" +
|
|
||||||
" &.active {\n" +
|
|
||||||
" color: rgb(10, 11, 12);\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}\n" +
|
|
||||||
"\n" +
|
|
||||||
".order {\n" +
|
|
||||||
" border-top-style: solid;\n" +
|
|
||||||
" @media all {\n" +
|
|
||||||
" & {\n" +
|
|
||||||
" border-top-color: rgb(13, 14, 15);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" border-right-style: solid;\n" +
|
|
||||||
" border-right-color: rgb(16, 17, 18);\n" +
|
|
||||||
"}\n";
|
|
||||||
document.head.appendChild(style);
|
|
||||||
return style;
|
|
||||||
}
|
|
||||||
|
|
||||||
function runChecks(style, report) {
|
|
||||||
var scope = document.getElementById("scope");
|
|
||||||
var desc = document.getElementById("desc");
|
|
||||||
var button = document.getElementById("button");
|
|
||||||
|
|
||||||
report(colorOf(window, scope, "color") === "rgb(1, 2, 3)",
|
|
||||||
"outer rule declarations should apply",
|
|
||||||
colorOf(window, scope, "color"),
|
|
||||||
"rgb(1, 2, 3)");
|
|
||||||
report(colorOf(window, desc, "color") === "rgb(4, 5, 6)",
|
|
||||||
"nested descendant rule should be flattened",
|
|
||||||
colorOf(window, desc, "color"),
|
|
||||||
"rgb(4, 5, 6)");
|
|
||||||
report(colorOf(window, desc, "border-left-color") === "rgb(19, 20, 21)",
|
|
||||||
"nested type selector rule should be flattened",
|
|
||||||
colorOf(window, desc, "border-left-color"),
|
|
||||||
"rgb(19, 20, 21)");
|
|
||||||
report(colorOf(window, desc, "border-bottom-color") === "rgb(22, 23, 24)",
|
|
||||||
"nested type selector pseudos should be flattened",
|
|
||||||
colorOf(window, desc, "border-bottom-color"),
|
|
||||||
"rgb(22, 23, 24)");
|
|
||||||
report(colorOf(window, scope, "background-color") === "rgb(7, 8, 9)",
|
|
||||||
"declarations after a nested rule should preserve order",
|
|
||||||
colorOf(window, scope, "background-color"),
|
|
||||||
"rgb(7, 8, 9)");
|
|
||||||
report(colorOf(window, button, "color") === "rgb(10, 11, 12)",
|
|
||||||
"ampersand selectors should be expanded",
|
|
||||||
colorOf(window, button, "color"),
|
|
||||||
"rgb(10, 11, 12)");
|
|
||||||
report(colorOf(window, scope, "border-top-color") === "rgb(13, 14, 15)",
|
|
||||||
"nested group rules should target the parent selector",
|
|
||||||
colorOf(window, scope, "border-top-color"),
|
|
||||||
"rgb(13, 14, 15)");
|
|
||||||
report(colorOf(window, scope, "border-right-color") === "rgb(16, 17, 18)",
|
|
||||||
"declarations after nested group rules should still apply",
|
|
||||||
colorOf(window, scope, "border-right-color"),
|
|
||||||
"rgb(16, 17, 18)");
|
|
||||||
report(style.sheet.cssRules.length === 9,
|
|
||||||
"flattening should produce flat top-level rules",
|
|
||||||
String(style.sheet.cssRules.length),
|
|
||||||
"9");
|
|
||||||
}
|
|
||||||
|
|
||||||
function runStandalone() {
|
|
||||||
var log = document.getElementById("standalone-log");
|
|
||||||
var lines = [
|
|
||||||
"Standalone mode.",
|
|
||||||
"This page only demonstrates nesting if layout.css.nesting.enabled is already true in the browser.",
|
|
||||||
""
|
|
||||||
];
|
|
||||||
var style = appendTestSheet();
|
|
||||||
|
|
||||||
runChecks(style, function(pass, message, actual, expected) {
|
|
||||||
lines.push((pass ? "PASS" : "FAIL") + ": " + message);
|
|
||||||
if (!pass) {
|
|
||||||
lines.push(" expected: " + expected);
|
|
||||||
lines.push(" actual: " + actual);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
log.textContent = lines.join("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
function runMochitest() {
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
|
||||||
SpecialPowers.pushPrefEnv({
|
|
||||||
set: [["layout.css.nesting.enabled", true]]
|
|
||||||
}, function() {
|
|
||||||
var style = appendTestSheet();
|
|
||||||
|
|
||||||
runChecks(style, function(pass, message, actual, expected) {
|
|
||||||
is(actual, expected, message);
|
|
||||||
});
|
|
||||||
|
|
||||||
SimpleTest.finish();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof SimpleTest !== "undefined" && typeof SpecialPowers !== "undefined") {
|
|
||||||
runMochitest();
|
|
||||||
} else {
|
|
||||||
runStandalone();
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,161 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>Test CSS Nesting Flattening Parser Edges</title>
|
|
||||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
|
||||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="scope" class="scope">
|
|
||||||
<span id="firstSpan" class="desc"></span>
|
|
||||||
<span id="middleSpan" class="middle"></span>
|
|
||||||
<span id="escapedSpan" class="1foo"></span>
|
|
||||||
<svg id="svgRoot" xmlns="http://www.w3.org/2000/svg" width="10" height="10">
|
|
||||||
<rect id="nsRect" width="10" height="10"></rect>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<div id="afterMalformed" class="after-malformed"></div>
|
|
||||||
<div id="afterTarget" class="after-target"></div>
|
|
||||||
<pre id="standalone-log"></pre>
|
|
||||||
<script>
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
function propOf(win, element, property) {
|
|
||||||
return win.getComputedStyle(element).getPropertyValue(property);
|
|
||||||
}
|
|
||||||
|
|
||||||
function appendTestSheet() {
|
|
||||||
var style = document.createElement("style");
|
|
||||||
style.textContent =
|
|
||||||
"@namespace svg url(http://www.w3.org/2000/svg);\n" +
|
|
||||||
".scope {\n" +
|
|
||||||
" --payload: { alpha: 1; beta: 2; };\n" +
|
|
||||||
" color: rgb(1, 2, 3);\n" +
|
|
||||||
" span:first-of-type, span:last-of-type {\n" +
|
|
||||||
" color: rgb(30, 31, 32);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" .\\31 foo {\n" +
|
|
||||||
" border-left-style: solid;\n" +
|
|
||||||
" border-left-color: rgb(40, 41, 42);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" svg|rect {\n" +
|
|
||||||
" stroke: rgb(50, 51, 52);\n" +
|
|
||||||
" stroke-width: 1px;\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}\n" +
|
|
||||||
"\n" +
|
|
||||||
".after-malformed {\n" +
|
|
||||||
" color: rgb(60, 61, 62);\n" +
|
|
||||||
" : {\n" +
|
|
||||||
" color: rgb(70, 71, 72);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" background-color: rgb(80, 81, 82);\n" +
|
|
||||||
"}\n" +
|
|
||||||
"\n" +
|
|
||||||
".after-target {\n" +
|
|
||||||
" color: rgb(90, 91, 92);\n" +
|
|
||||||
"}\n";
|
|
||||||
document.head.appendChild(style);
|
|
||||||
return style;
|
|
||||||
}
|
|
||||||
|
|
||||||
function runChecks(style, report) {
|
|
||||||
var scope = document.getElementById("scope");
|
|
||||||
var firstSpan = document.getElementById("firstSpan");
|
|
||||||
var middleSpan = document.getElementById("middleSpan");
|
|
||||||
var escapedSpan = document.getElementById("escapedSpan");
|
|
||||||
var rect = document.getElementById("nsRect");
|
|
||||||
var afterMalformed = document.getElementById("afterMalformed");
|
|
||||||
var afterTarget = document.getElementById("afterTarget");
|
|
||||||
|
|
||||||
var payload = propOf(window, scope, "--payload");
|
|
||||||
report(payload.indexOf("alpha") !== -1 && payload.indexOf("beta") !== -1,
|
|
||||||
"custom property payload should survive flattening",
|
|
||||||
payload,
|
|
||||||
"contains alpha and beta");
|
|
||||||
|
|
||||||
report(propOf(window, scope, "color") === "rgb(1, 2, 3)",
|
|
||||||
"base declaration should apply",
|
|
||||||
propOf(window, scope, "color"),
|
|
||||||
"rgb(1, 2, 3)");
|
|
||||||
report(propOf(window, firstSpan, "color") === "rgb(30, 31, 32)",
|
|
||||||
"nested pseudo selector should style first span",
|
|
||||||
propOf(window, firstSpan, "color"),
|
|
||||||
"rgb(30, 31, 32)");
|
|
||||||
report(propOf(window, escapedSpan, "color") === "rgb(30, 31, 32)",
|
|
||||||
"nested pseudo selector should style last span",
|
|
||||||
propOf(window, escapedSpan, "color"),
|
|
||||||
"rgb(30, 31, 32)");
|
|
||||||
report(propOf(window, middleSpan, "color") === "rgb(1, 2, 3)",
|
|
||||||
"middle span should keep inherited scope color",
|
|
||||||
propOf(window, middleSpan, "color"),
|
|
||||||
"rgb(1, 2, 3)");
|
|
||||||
|
|
||||||
report(propOf(window, escapedSpan, "border-left-color") === "rgb(40, 41, 42)",
|
|
||||||
"escaped class selector should match",
|
|
||||||
propOf(window, escapedSpan, "border-left-color"),
|
|
||||||
"rgb(40, 41, 42)");
|
|
||||||
|
|
||||||
report(propOf(window, rect, "stroke") === "rgb(50, 51, 52)",
|
|
||||||
"namespace selector should match nested SVG rect",
|
|
||||||
propOf(window, rect, "stroke"),
|
|
||||||
"rgb(50, 51, 52)");
|
|
||||||
|
|
||||||
report(propOf(window, afterMalformed, "color") === "rgb(60, 61, 62)",
|
|
||||||
"declaration before malformed nested selector should apply",
|
|
||||||
propOf(window, afterMalformed, "color"),
|
|
||||||
"rgb(60, 61, 62)");
|
|
||||||
report(propOf(window, afterMalformed, "background-color") === "rgb(80, 81, 82)",
|
|
||||||
"declaration after malformed nested selector should still apply",
|
|
||||||
propOf(window, afterMalformed, "background-color"),
|
|
||||||
"rgb(80, 81, 82)");
|
|
||||||
report(propOf(window, afterTarget, "color") === "rgb(90, 91, 92)",
|
|
||||||
"subsequent top-level rules should still parse",
|
|
||||||
propOf(window, afterTarget, "color"),
|
|
||||||
"rgb(90, 91, 92)");
|
|
||||||
}
|
|
||||||
|
|
||||||
function runStandalone() {
|
|
||||||
var log = document.getElementById("standalone-log");
|
|
||||||
var lines = [
|
|
||||||
"Standalone mode.",
|
|
||||||
"This page only demonstrates nesting if layout.css.nesting.enabled is already true in the browser.",
|
|
||||||
""
|
|
||||||
];
|
|
||||||
var style = appendTestSheet();
|
|
||||||
|
|
||||||
runChecks(style, function(pass, message, actual, expected) {
|
|
||||||
lines.push((pass ? "PASS" : "FAIL") + ": " + message);
|
|
||||||
if (!pass) {
|
|
||||||
lines.push(" expected: " + expected);
|
|
||||||
lines.push(" actual: " + actual);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
log.textContent = lines.join("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
function runMochitest() {
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
|
||||||
SpecialPowers.pushPrefEnv({
|
|
||||||
set: [["layout.css.nesting.enabled", true]]
|
|
||||||
}, function() {
|
|
||||||
var style = appendTestSheet();
|
|
||||||
|
|
||||||
runChecks(style, function(pass, message, actual, expected) {
|
|
||||||
ok(pass, message + " (expected: " + expected + ", actual: " + actual + ")");
|
|
||||||
});
|
|
||||||
|
|
||||||
SimpleTest.finish();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof SimpleTest !== "undefined" && typeof SpecialPowers !== "undefined") {
|
|
||||||
runMochitest();
|
|
||||||
} else {
|
|
||||||
runStandalone();
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,149 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>Test CSS Nesting Flattening Recovery Paths</title>
|
|
||||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
|
||||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="recBase" class="rec-base"><span id="recBaseChild"></span></div>
|
|
||||||
<div id="recMalformed" class="rec-malformed"></div>
|
|
||||||
<div id="recGroup" class="rec-group"></div>
|
|
||||||
<div id="recTail" class="rec-tail"></div>
|
|
||||||
<pre id="standalone-log"></pre>
|
|
||||||
<script>
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
function propOf(win, element, property) {
|
|
||||||
return win.getComputedStyle(element).getPropertyValue(property);
|
|
||||||
}
|
|
||||||
|
|
||||||
function appendTestSheet() {
|
|
||||||
var style = document.createElement("style");
|
|
||||||
style.textContent =
|
|
||||||
".rec-base {\n" +
|
|
||||||
" color: rgb(1, 2, 3);\n" +
|
|
||||||
" |* {\n" +
|
|
||||||
" color: rgb(4, 5, 6);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" background-color: rgb(7, 8, 9);\n" +
|
|
||||||
"}\n" +
|
|
||||||
"\n" +
|
|
||||||
".rec-malformed {\n" +
|
|
||||||
" color: rgb(20, 21, 22);\n" +
|
|
||||||
" : {\n" +
|
|
||||||
" color: rgb(23, 24, 25);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" border-top-style: solid;\n" +
|
|
||||||
" border-top-color: rgb(26, 27, 28);\n" +
|
|
||||||
"}\n" +
|
|
||||||
"\n" +
|
|
||||||
".rec-group {\n" +
|
|
||||||
" color: rgb(32, 33, 34);\n" +
|
|
||||||
" @counter-style rec-counter {\n" +
|
|
||||||
" system: fixed;\n" +
|
|
||||||
" symbols: a;\n" +
|
|
||||||
" }\n" +
|
|
||||||
" background-color: rgb(35, 36, 37);\n" +
|
|
||||||
"}\n" +
|
|
||||||
"\n" +
|
|
||||||
".rec-tail {\n" +
|
|
||||||
" color: rgb(50, 51, 52);\n" +
|
|
||||||
"}\n";
|
|
||||||
document.head.appendChild(style);
|
|
||||||
return style;
|
|
||||||
}
|
|
||||||
|
|
||||||
function runChecks(style, report) {
|
|
||||||
var recBase = document.getElementById("recBase");
|
|
||||||
var recBaseChild = document.getElementById("recBaseChild");
|
|
||||||
var recMalformed = document.getElementById("recMalformed");
|
|
||||||
var recGroup = document.getElementById("recGroup");
|
|
||||||
var recTail = document.getElementById("recTail");
|
|
||||||
|
|
||||||
report(propOf(window, recBase, "color") === "rgb(1, 2, 3)",
|
|
||||||
"unsupported nested selector should not wipe earlier declarations",
|
|
||||||
propOf(window, recBase, "color"),
|
|
||||||
"rgb(1, 2, 3)");
|
|
||||||
report(propOf(window, recBase, "background-color") === "rgb(7, 8, 9)",
|
|
||||||
"unsupported nested selector should not wipe later declarations",
|
|
||||||
propOf(window, recBase, "background-color"),
|
|
||||||
"rgb(7, 8, 9)");
|
|
||||||
report(propOf(window, recBaseChild, "color") === "rgb(1, 2, 3)",
|
|
||||||
"unsupported nested selector should not restyle descendants unexpectedly",
|
|
||||||
propOf(window, recBaseChild, "color"),
|
|
||||||
"rgb(1, 2, 3)");
|
|
||||||
|
|
||||||
report(propOf(window, recMalformed, "color") === "rgb(20, 21, 22)",
|
|
||||||
"malformed nested selector should keep declaration before it",
|
|
||||||
propOf(window, recMalformed, "color"),
|
|
||||||
"rgb(20, 21, 22)");
|
|
||||||
report(propOf(window, recMalformed, "border-top-color") === "rgb(26, 27, 28)",
|
|
||||||
"malformed nested selector should keep declaration after it",
|
|
||||||
propOf(window, recMalformed, "border-top-color"),
|
|
||||||
"rgb(26, 27, 28)");
|
|
||||||
|
|
||||||
report(propOf(window, recGroup, "color") === "rgb(32, 33, 34)",
|
|
||||||
"nested unsupported at-rule should keep declaration before it",
|
|
||||||
propOf(window, recGroup, "color"),
|
|
||||||
"rgb(32, 33, 34)");
|
|
||||||
report(propOf(window, recGroup, "background-color") === "rgb(35, 36, 37)",
|
|
||||||
"nested unsupported at-rule should keep declaration after it",
|
|
||||||
propOf(window, recGroup, "background-color"),
|
|
||||||
"rgb(35, 36, 37)");
|
|
||||||
|
|
||||||
report(propOf(window, recTail, "color") === "rgb(50, 51, 52)",
|
|
||||||
"rules after recovery scenarios should still parse",
|
|
||||||
propOf(window, recTail, "color"),
|
|
||||||
"rgb(50, 51, 52)");
|
|
||||||
|
|
||||||
report(style.sheet.cssRules.length >= 4,
|
|
||||||
"stylesheet should remain parseable after recovery scenarios",
|
|
||||||
String(style.sheet.cssRules.length),
|
|
||||||
">= 4");
|
|
||||||
}
|
|
||||||
|
|
||||||
function runStandalone() {
|
|
||||||
var log = document.getElementById("standalone-log");
|
|
||||||
var lines = [
|
|
||||||
"Standalone mode.",
|
|
||||||
"This page only demonstrates nesting if layout.css.nesting.enabled is already true in the browser.",
|
|
||||||
""
|
|
||||||
];
|
|
||||||
var style = appendTestSheet();
|
|
||||||
|
|
||||||
runChecks(style, function(pass, message, actual, expected) {
|
|
||||||
lines.push((pass ? "PASS" : "FAIL") + ": " + message);
|
|
||||||
if (!pass) {
|
|
||||||
lines.push(" expected: " + expected);
|
|
||||||
lines.push(" actual: " + actual);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
log.textContent = lines.join("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
function runMochitest() {
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
|
||||||
SpecialPowers.pushPrefEnv({
|
|
||||||
set: [["layout.css.nesting.enabled", true]]
|
|
||||||
}, function() {
|
|
||||||
var style = appendTestSheet();
|
|
||||||
|
|
||||||
runChecks(style, function(pass, message, actual, expected) {
|
|
||||||
ok(pass, message + " (expected: " + expected + ", actual: " + actual + ")");
|
|
||||||
});
|
|
||||||
|
|
||||||
SimpleTest.finish();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof SimpleTest !== "undefined" && typeof SpecialPowers !== "undefined") {
|
|
||||||
runMochitest();
|
|
||||||
} else {
|
|
||||||
runStandalone();
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
*
|
*
|
||||||
* Platform-specific #ifdefs at the end of this file override the generic
|
* Platform-specific #ifdefs at the end of this file override the generic
|
||||||
* entries at the top.
|
* entries at the top.
|
||||||
*
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SYNTAX HINTS:
|
* SYNTAX HINTS:
|
||||||
|
|
@ -639,7 +639,7 @@ pref("layout.event-regions.enabled", false);
|
||||||
// gfx/layers/apz/src/AsyncPanZoomController.cpp.
|
// gfx/layers/apz/src/AsyncPanZoomController.cpp.
|
||||||
pref("apz.allow_checkerboarding", true);
|
pref("apz.allow_checkerboarding", true);
|
||||||
pref("apz.allow_immediate_handoff", true);
|
pref("apz.allow_immediate_handoff", true);
|
||||||
pref("apz.allow_zooming", true);
|
pref("apz.allow_zooming", false);
|
||||||
|
|
||||||
// Whether to lock touch scrolling to one axis at a time
|
// Whether to lock touch scrolling to one axis at a time
|
||||||
// 0 = FREE (No locking at all)
|
// 0 = FREE (No locking at all)
|
||||||
|
|
@ -651,7 +651,7 @@ pref("apz.axis_lock.breakout_threshold", "0.03125"); // 1/32 inches
|
||||||
pref("apz.axis_lock.breakout_angle", "0.3926991"); // PI / 8 (22.5 degrees)
|
pref("apz.axis_lock.breakout_angle", "0.3926991"); // PI / 8 (22.5 degrees)
|
||||||
pref("apz.axis_lock.direct_pan_angle", "1.047197"); // PI / 3 (60 degrees)
|
pref("apz.axis_lock.direct_pan_angle", "1.047197"); // PI / 3 (60 degrees)
|
||||||
pref("apz.content_response_timeout", 400);
|
pref("apz.content_response_timeout", 400);
|
||||||
pref("apz.drag.enabled", true);
|
pref("apz.drag.enabled", false);
|
||||||
pref("apz.danger_zone_x", 50);
|
pref("apz.danger_zone_x", 50);
|
||||||
pref("apz.danger_zone_y", 100);
|
pref("apz.danger_zone_y", 100);
|
||||||
pref("apz.disable_for_scroll_linked_effects", false);
|
pref("apz.disable_for_scroll_linked_effects", false);
|
||||||
|
|
@ -710,7 +710,7 @@ pref("apz.zoom_animation_duration_ms", 250);
|
||||||
pref("apz.scale_repaint_delay_ms", 500);
|
pref("apz.scale_repaint_delay_ms", 500);
|
||||||
|
|
||||||
#if !defined(MOZ_WIDGET_UIKIT)
|
#if !defined(MOZ_WIDGET_UIKIT)
|
||||||
pref("apz.desktop.enabled", true);
|
pref("apz.desktop.enabled", false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef XP_MACOSX
|
#ifdef XP_MACOSX
|
||||||
|
|
@ -1348,9 +1348,6 @@ pref("javascript.options.dynamicImport", true);
|
||||||
// Streams API
|
// Streams API
|
||||||
pref("javascript.options.streams", true);
|
pref("javascript.options.streams", true);
|
||||||
|
|
||||||
// Enable garbage collection of weakrefed objects
|
|
||||||
pref("javascript.options.weakrefs", false);
|
|
||||||
|
|
||||||
// advanced prefs
|
// advanced prefs
|
||||||
pref("advanced.mailftp", false);
|
pref("advanced.mailftp", false);
|
||||||
pref("image.animation_mode", "normal");
|
pref("image.animation_mode", "normal");
|
||||||
|
|
@ -2728,9 +2725,6 @@ pref("layout.css.resizeobserver.enabled", true);
|
||||||
// Is support for cascade layers enabled?
|
// Is support for cascade layers enabled?
|
||||||
pref("layout.css.cascade-layers.enabled", true);
|
pref("layout.css.cascade-layers.enabled", true);
|
||||||
|
|
||||||
// Is support for basic CSS nesting lowering enabled?
|
|
||||||
pref("layout.css.nesting.enabled", true);
|
|
||||||
|
|
||||||
// Should rules in imported style sheets be added based on the order
|
// Should rules in imported style sheets be added based on the order
|
||||||
// of appearance of their respective @import rules in the parent
|
// of appearance of their respective @import rules in the parent
|
||||||
// style sheet? Otherwise, they are added before rules preceding
|
// style sheet? Otherwise, they are added before rules preceding
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,5 @@
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# 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/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
FINAL_TARGET_FILES.fonts += ['TwemojiMozilla.ttf']
|
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3'):
|
||||||
|
FINAL_TARGET_FILES.fonts += ['TwemojiMozilla.ttf']
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
Dactyloidae Milsko Toolkit (WIP)
|
|
||||||
|
|
||||||
This is a modified version of Milsko 1.4 (latest release as of 28/7/26, DD/MM/YY),
|
|
||||||
adapted for use on you know, a web browser.
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
---
|
|
||||||
UseTab: Always
|
|
||||||
TabWidth: 8
|
|
||||||
AlignConsecutiveAssignments:
|
|
||||||
Enabled: true
|
|
||||||
AlignConsecutiveDeclarations:
|
|
||||||
Enabled: true
|
|
||||||
AccessModifierOffset: -4
|
|
||||||
NamespaceIndentation: All
|
|
||||||
IndentWidth: 8
|
|
||||||
PointerAlignment: Left
|
|
||||||
ColumnLimit: 0
|
|
||||||
AllowShortIfStatementsOnASingleLine: Always
|
|
||||||
AllowShortBlocksOnASingleLine: Never
|
|
||||||
AllowShortFunctionsOnASingleLine: Empty
|
|
||||||
AllowShortLoopsOnASingleLine: true
|
|
||||||
BreakBeforeBraces: Custom
|
|
||||||
BraceWrapping:
|
|
||||||
AfterCaseLabel: true
|
|
||||||
SpaceBeforeParens: Never
|
|
||||||
AlignEscapedNewlines: DontAlign
|
|
||||||
SortIncludes: false
|
|
||||||
AllowShortEnumsOnASingleLine: false
|
|
||||||
#IndentPPDirectives: AfterHash
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
Completion:
|
|
||||||
HeaderInsertion: Never
|
|
||||||
ClangFormat: Tab
|
|
||||||
17
widget/milsko/milskosrc/.gitattributes
vendored
17
widget/milsko/milskosrc/.gitattributes
vendored
|
|
@ -1,17 +0,0 @@
|
||||||
/external/*.h linguist-generated
|
|
||||||
/external/*.c linguist-generated
|
|
||||||
/external/libjpeg/include/*.h linguist-generated
|
|
||||||
/external/libjpeg/src/*.c linguist-generated
|
|
||||||
/external/libjpeg/src/*.h linguist-generated
|
|
||||||
/external/libz/include/*.h linguist-generated
|
|
||||||
/external/libz/src/*.c linguist-generated
|
|
||||||
/external/libz/src/*.h linguist-generated
|
|
||||||
/external/libpng/include/*.h linguist-generated
|
|
||||||
/external/libpng/src/*.c linguist-generated
|
|
||||||
/external/libpng/src/*.h linguist-generated
|
|
||||||
/resource/doxygen-theme/* linguist-generated
|
|
||||||
/src/icon/*.c linguist-generated
|
|
||||||
/src/font/*.c linguist-generated
|
|
||||||
/BorMakefile linguist-generated
|
|
||||||
/WatMakefile linguist-generated
|
|
||||||
/NTMakefile linguist-generated
|
|
||||||
33
widget/milsko/milskosrc/.gitignore
vendored
33
widget/milsko/milskosrc/.gitignore
vendored
|
|
@ -1,33 +0,0 @@
|
||||||
examples/*
|
|
||||||
examples/*.exe
|
|
||||||
examples/*/*
|
|
||||||
examples/*/*.exe
|
|
||||||
!examples/*/
|
|
||||||
!examples/*.*
|
|
||||||
!examples/*/*.*
|
|
||||||
*.exe
|
|
||||||
*.o
|
|
||||||
*.obj
|
|
||||||
*.core
|
|
||||||
*.so
|
|
||||||
*.dll
|
|
||||||
*.lib
|
|
||||||
*.dylib
|
|
||||||
*.a
|
|
||||||
/Makefile
|
|
||||||
/build
|
|
||||||
compile_flags.txt
|
|
||||||
.cache
|
|
||||||
.DS_Store
|
|
||||||
/vms
|
|
||||||
/BorMakefile
|
|
||||||
*.err
|
|
||||||
*.zip
|
|
||||||
|
|
||||||
*.pef
|
|
||||||
*.dsk
|
|
||||||
*.bin
|
|
||||||
*.rsrc
|
|
||||||
*.finf
|
|
||||||
*.gdb
|
|
||||||
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
========================= 1.4 =========================
|
|
||||||
- CMakeLists.txt downgraded to version 3.13 to allow compiling on Windows XP
|
|
||||||
- CMake build now generates a pkgconfig file.
|
|
||||||
- GDI backend now natively uses GDI for text rendering
|
|
||||||
- Widgets can now be disabled with MwNdisabled
|
|
||||||
- Added `MwTabFocus` for letting a tab widget steal focus.
|
|
||||||
- New table widget (`MwTableClass`).
|
|
||||||
- Added `MwWindowShouldClose` for letting custom loops know when a window should close.
|
|
||||||
- Remove VMS build files
|
|
||||||
- Entry widgets now have blinking cursor that appears only when you hover over the widget.
|
|
||||||
- Wayland backend:
|
|
||||||
- Can now create layer surfaces (Use `MwLLMakeToolWindow` on a parentless window)
|
|
||||||
- Now properly handles keys being held down
|
|
||||||
- has drastically improved CSD (functionality wise)
|
|
||||||
- Uses KMSDRM directly for the OpenGL widget instead of wl_egl for a smoother experience
|
|
||||||
- Various overall performance improvements putting it on the same level as the X11 backend finally
|
|
||||||
- Menu widget works better under compositors that use CSD.
|
|
||||||
|
|
@ -1,508 +0,0 @@
|
||||||
cmake_minimum_required(VERSION 3.13)
|
|
||||||
project(
|
|
||||||
milsko
|
|
||||||
)
|
|
||||||
|
|
||||||
include(CheckIncludeFiles)
|
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
|
||||||
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}")
|
|
||||||
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
|
|
||||||
|
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
set(CMAKE_STATIC_LIBRARY_PREFIX "")
|
|
||||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
option(MW_CLASSIC_THEME "Use classic theme" OFF)
|
|
||||||
option(MW_BUILD_EXAMPLES "Build examples" OFF)
|
|
||||||
option(MW_USE_STB_IMAGE "Use stb_image" ON)
|
|
||||||
option(MW_USE_STB_TRUETYPE "Use stb_truetype" OFF)
|
|
||||||
|
|
||||||
if(${CMAKE_SYSTEM_NAME} MATCHES Retro)
|
|
||||||
option(MW_BUILD_SHARED "Build a shared library" OFF)
|
|
||||||
option(MW_BUILD_STATIC "Build a static library" ON)
|
|
||||||
option(MW_TRY_OPENGL "Try to compile OpenGL widget or not" OFF)
|
|
||||||
option(MW_TRY_VULKAN "Try to compile Vulkan widget or not" OFF)
|
|
||||||
else()
|
|
||||||
option(MW_BUILD_SHARED "Build a shared library" ON)
|
|
||||||
option(MW_BUILD_STATIC "Build a static library" OFF)
|
|
||||||
option(MW_TRY_OPENGL "Try to compile OpenGL widget or not" ON)
|
|
||||||
option(MW_TRY_VULKAN "Try to compile Vulkan widget or not" ON)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
option(MW_INSTALL_HEADERS "Install headers" ON)
|
|
||||||
|
|
||||||
if( ${CMAKE_SYSTEM_NAME} STREQUAL Darwin
|
|
||||||
OR ${CMAKE_SYSTEM_NAME} MATCHES Retro
|
|
||||||
OR ${CMAKE_SYSTEM_NAME} MATCHES Windows)
|
|
||||||
option(MW_USE_FREETYPE2 "Use FreeType 2" OFF)
|
|
||||||
else()
|
|
||||||
option(MW_USE_FREETYPE2 "Use FreeType 2" ON)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(${CMAKE_SYSTEM_NAME} STREQUAL Windows)
|
|
||||||
option(MW_USE_GDI_TEXT "Use GDI for text rendering" ON)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(${CMAKE_SYSTEM_NAME} STREQUAL Linux OR ${CMAKE_SYSTEM_NAME} STREQUAL FreeBSD)
|
|
||||||
option(MW_USE_WAYLAND "Enable Wayland backend" ON)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
file(
|
|
||||||
GLOB
|
|
||||||
SOURCES
|
|
||||||
external/libz/src/*.c src/*.c src/cursor/*.c src/icon/*.c src/widget/*.c src/text/*.c src/text/font/*.c src/dialog/*.c src/abstract/*.c external/*.c
|
|
||||||
)
|
|
||||||
|
|
||||||
if(NOT MW_USE_STB_IMAGE)
|
|
||||||
list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/external/stb_image.c")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOT MW_USE_STB_TRUETYPE)
|
|
||||||
list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/external/stb_truetype.c")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(CMAKE_SYSTEM_NAME STREQUAL "NetBSD")
|
|
||||||
list(APPEND CMAKE_REQUIRED_INCLUDES "/usr/X11R7/include")
|
|
||||||
list(APPEND CMAKE_REQUIRED_INCLUDES "/usr/pkg/include")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(MW_TRY_OPENGL)
|
|
||||||
find_package(OpenGL)
|
|
||||||
if(OpenGL_FOUND AND NOT APPLE)
|
|
||||||
set(MW_BUILD_OPENGL ON)
|
|
||||||
message(STATUS "OpenGL widget has been enabled")
|
|
||||||
else()
|
|
||||||
message(WARNING "OpenGL widget has been disabled")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(MW_TRY_VULKAN)
|
|
||||||
find_package(Vulkan)
|
|
||||||
if(${Vulkan_FOUND})
|
|
||||||
set(MW_BUILD_VULKAN ON)
|
|
||||||
message(STATUS "Vulkan widget has been enabled")
|
|
||||||
else()
|
|
||||||
message(WARNING "Vulkan widget has been disabled")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(MW_BUILD_STATIC)
|
|
||||||
message(STATUS "Building Milsko as a static library")
|
|
||||||
add_library(
|
|
||||||
Mw
|
|
||||||
${SOURCES}
|
|
||||||
)
|
|
||||||
elseif(MW_BUILD_SHARED)
|
|
||||||
message(STATUS "Building Milsko as a shared library")
|
|
||||||
add_library(
|
|
||||||
Mw
|
|
||||||
SHARED
|
|
||||||
${SOURCES}
|
|
||||||
)
|
|
||||||
else()
|
|
||||||
message(ERROR "Must either build a shared library or a static library")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(MW_USE_STB_IMAGE)
|
|
||||||
target_compile_definitions(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
USE_STB_IMAGE
|
|
||||||
)
|
|
||||||
else()
|
|
||||||
file(
|
|
||||||
GLOB
|
|
||||||
IMAGE_SOURCES
|
|
||||||
external/libjpeg/src/*.c external/libpng/src/*.c
|
|
||||||
)
|
|
||||||
target_sources(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
${MW_IMAGE_SOURCES}
|
|
||||||
)
|
|
||||||
target_include_directories(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
external/libjpeg/include external/libpng/include
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(MW_USE_STB_TRUETYPE)
|
|
||||||
target_compile_definitions(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
USE_STB_TRUETYPE
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(MW_USE_FREETYPE2)
|
|
||||||
find_package(Freetype)
|
|
||||||
if(Freetype_FOUND)
|
|
||||||
message(STATUS "FreeType2 found")
|
|
||||||
target_compile_definitions(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
USE_FREETYPE2
|
|
||||||
)
|
|
||||||
|
|
||||||
list(APPEND INCLUDE_DIRS ${FREETYPE_INCLUDE_DIRS})
|
|
||||||
list(APPEND LIBRARY_DIRS ${FREETYPE_LIBRARY_DIRS})
|
|
||||||
else()
|
|
||||||
message(WARNING "FreeType2 not found")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|
||||||
if(MW_USE_GDI_TEXT)
|
|
||||||
target_compile_definitions(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
USE_GDI_TEXT
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(MW_USE_WAYLAND)
|
|
||||||
function(scan_wayland_protocol_core)
|
|
||||||
execute_process(
|
|
||||||
COMMAND wayland-scanner private-code /usr/share/wayland/wayland.xml ${CMAKE_CURRENT_SOURCE_DIR}/src/backend/wayland/wayland-core-protocol.c
|
|
||||||
OUTPUT_VARIABLE WAYLAND_SCANNER_OUTPUT
|
|
||||||
ERROR_VARIABLE WAYLAND_SCANNER_ERROR
|
|
||||||
ECHO_OUTPUT_VARIABLE
|
|
||||||
ECHO_ERROR_VARIABLE
|
|
||||||
COMMAND_ECHO STDOUT
|
|
||||||
)
|
|
||||||
target_sources(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/backend/wayland/wayland-core-protocol.c
|
|
||||||
)
|
|
||||||
execute_process(
|
|
||||||
COMMAND wayland-scanner client-header /usr/share/wayland/wayland.xml ${CMAKE_CURRENT_SOURCE_DIR}/include/Mw/LowLevel/Wayland/wayland-core-protocol.h
|
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
|
||||||
OUTPUT_VARIABLE WAYLAND_SCANNER_OUTPUT
|
|
||||||
ERROR_VARIABLE WAYLAND_SCANNER_ERROR
|
|
||||||
ECHO_OUTPUT_VARIABLE
|
|
||||||
ECHO_ERROR_VARIABLE
|
|
||||||
COMMAND_ECHO STDOUT
|
|
||||||
)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(scan_wayland_protocol tier proto ver)
|
|
||||||
SET(proto_c ${CMAKE_CURRENT_SOURCE_DIR}/src/backend/wayland/wayland-${proto}-protocol.c)
|
|
||||||
execute_process(
|
|
||||||
COMMAND wayland-scanner private-code /usr/share/wayland-protocols/${tier}/${proto}/${proto}${ver}.xml ${proto_c}
|
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
|
||||||
OUTPUT_VARIABLE WAYLAND_SCANNER_OUTPUT
|
|
||||||
ERROR_VARIABLE WAYLAND_SCANNER_ERROR
|
|
||||||
ECHO_OUTPUT_VARIABLE
|
|
||||||
ECHO_ERROR_VARIABLE
|
|
||||||
COMMAND_ECHO STDOUT
|
|
||||||
)
|
|
||||||
target_sources(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
${proto_c}
|
|
||||||
)
|
|
||||||
execute_process(
|
|
||||||
COMMAND wayland-scanner client-header /usr/share/wayland-protocols/${tier}/${proto}/${proto}${ver}.xml ${CMAKE_CURRENT_SOURCE_DIR}/include/Mw/LowLevel/Wayland/${proto}-client-protocol.h
|
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
|
||||||
OUTPUT_VARIABLE WAYLAND_SCANNER_OUTPUT
|
|
||||||
ERROR_VARIABLE WAYLAND_SCANNER_ERROR
|
|
||||||
ECHO_OUTPUT_VARIABLE
|
|
||||||
ECHO_ERROR_VARIABLE
|
|
||||||
COMMAND_ECHO STDOUT
|
|
||||||
)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(scan_wayland_protocol_from_file proto file)
|
|
||||||
SET(proto_c ${CMAKE_CURRENT_SOURCE_DIR}/src/backend/wayland/wayland-${proto}-protocol.c)
|
|
||||||
execute_process(
|
|
||||||
COMMAND wayland-scanner private-code ${CMAKE_CURRENT_SOURCE_DIR}/resource/wayland/${file} ${proto_c}
|
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
|
||||||
OUTPUT_VARIABLE WAYLAND_SCANNER_OUTPUT
|
|
||||||
ERROR_VARIABLE WAYLAND_SCANNER_ERROR
|
|
||||||
ECHO_OUTPUT_VARIABLE
|
|
||||||
ECHO_ERROR_VARIABLE
|
|
||||||
COMMAND_ECHO STDOUT
|
|
||||||
)
|
|
||||||
target_sources(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
${proto_c}
|
|
||||||
)
|
|
||||||
execute_process(
|
|
||||||
COMMAND wayland-scanner client-header ${CMAKE_CURRENT_SOURCE_DIR}/resource/wayland/${file} ${CMAKE_CURRENT_SOURCE_DIR}/include/Mw/LowLevel/Wayland/${proto}-client-protocol.h
|
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
|
||||||
OUTPUT_VARIABLE WAYLAND_SCANNER_OUTPUT
|
|
||||||
ERROR_VARIABLE WAYLAND_SCANNER_ERROR
|
|
||||||
ECHO_OUTPUT_VARIABLE
|
|
||||||
ECHO_ERROR_VARIABLE
|
|
||||||
COMMAND_ECHO STDOUT
|
|
||||||
)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
check_include_files(wayland-client.h HAVE_WL_H)
|
|
||||||
check_include_files(xkbcommon/xkbcommon.h HAVE_XKBCOMMON_H)
|
|
||||||
check_include_files(cairo/cairo.h HAVE_CAIRO_H)
|
|
||||||
if(HAVE_WL_H)
|
|
||||||
if(HAVE_XKBCOMMON_H)
|
|
||||||
if(HAVE_CAIRO_H)
|
|
||||||
scan_wayland_protocol_core()
|
|
||||||
scan_wayland_protocol("stable" "xdg-shell" "")
|
|
||||||
scan_wayland_protocol("stable" "viewporter" "")
|
|
||||||
scan_wayland_protocol("stable" "tablet" "-v2")
|
|
||||||
scan_wayland_protocol("staging" "xdg-toplevel-icon" "-v1")
|
|
||||||
scan_wayland_protocol("staging" "cursor-shape" "-v1")
|
|
||||||
scan_wayland_protocol("unstable" "xdg-decoration" "-unstable-v1")
|
|
||||||
scan_wayland_protocol("unstable" "primary-selection" "-unstable-v1")
|
|
||||||
scan_wayland_protocol("unstable" "pointer-constraints" "-unstable-v1")
|
|
||||||
scan_wayland_protocol("unstable" "relative-pointer" "-unstable-v1")
|
|
||||||
scan_wayland_protocol_from_file("wlr-layer-shell" "wlr-layer-shell-unstable-v1.xml")
|
|
||||||
|
|
||||||
target_sources(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
src/backend/cairo.c
|
|
||||||
src/backend/wayland/wayland.c
|
|
||||||
src/backend/wayland/buffer.c
|
|
||||||
src/backend/wayland/interfaces.c
|
|
||||||
src/backend/wayland/region.c
|
|
||||||
)
|
|
||||||
target_compile_definitions(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
USE_WAYLAND
|
|
||||||
)
|
|
||||||
message(STATUS "Wayland backend has been enabled")
|
|
||||||
else()
|
|
||||||
message(WARNING "Wayland backend has been disabled")
|
|
||||||
endif()
|
|
||||||
else()
|
|
||||||
message(WARNING "Wayland backend has been disabled")
|
|
||||||
endif()
|
|
||||||
else()
|
|
||||||
message(WARNING "Wayland backend has been disabled")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(APPLE AND MW_BUILD_OPENGL)
|
|
||||||
target_compile_definitions(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
GL_SILENCE_DEPRECATION
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_include_directories(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
external/libz/include
|
|
||||||
)
|
|
||||||
|
|
||||||
target_include_directories(
|
|
||||||
Mw
|
|
||||||
PUBLIC
|
|
||||||
include
|
|
||||||
)
|
|
||||||
|
|
||||||
if(MW_CLASSIC_THEME)
|
|
||||||
target_compile_definitions(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
USE_CLASSIC_THEME
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
message("Building Milsko for ${CMAKE_SYSTEM_NAME}")
|
|
||||||
if(CMAKE_SYSTEM_NAME STREQUAL "Windows" OR CMAKE_SYSTEM_NAME STREQUAL "MSYS")
|
|
||||||
target_sources(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
src/backend/gdi.c
|
|
||||||
)
|
|
||||||
target_compile_definitions(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
USE_GDI
|
|
||||||
)
|
|
||||||
list(APPEND LIBRARIES gdi32 winmm)
|
|
||||||
target_link_options(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
-static-libgcc
|
|
||||||
)
|
|
||||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
|
||||||
# target_sources(
|
|
||||||
# Mw
|
|
||||||
# PRIVATE
|
|
||||||
# src/backend/cocoa.m
|
|
||||||
# )
|
|
||||||
target_sources(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
src/backend/nococoa.m
|
|
||||||
)
|
|
||||||
# target_compile_definitions(
|
|
||||||
# Mw
|
|
||||||
# PRIVATE
|
|
||||||
# USE_COCOA
|
|
||||||
# )
|
|
||||||
list(APPEND LIBRARIES objc)
|
|
||||||
target_link_options(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
-framework Cocoa
|
|
||||||
)
|
|
||||||
elseif(CMAKE_SYSTEM_NAME MATCHES "Retro")
|
|
||||||
|
|
||||||
target_sources(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
src/backend/classicmacos.c
|
|
||||||
)
|
|
||||||
if(PLATFORM MATCHES retroppc)
|
|
||||||
set_target_properties(Mw PROPERTIES COMPILE_FLAGS "-ffunction-sections -mcpu=601 -Os -Wall -Wextra -Wno-unused-parameter")
|
|
||||||
set_target_properties(Mw PROPERTIES LINK_FLAGS "-Wl,-gc-sections")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
list(APPEND LIBRARIES InterfaceLib WindowsLib ThreadsLib)
|
|
||||||
|
|
||||||
target_compile_definitions(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
CLASSIC_MAC_OS
|
|
||||||
)
|
|
||||||
else()
|
|
||||||
|
|
||||||
find_package(PkgConfig)
|
|
||||||
find_package(X11)
|
|
||||||
pkg_check_modules(DBUS dbus-1)
|
|
||||||
|
|
||||||
target_sources(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
src/backend/x11.c
|
|
||||||
)
|
|
||||||
|
|
||||||
if(${X11_FOUND})
|
|
||||||
list(APPEND INCLUDE_DIRS ${X11_INCLUDE_DIRS})
|
|
||||||
list(APPEND LIBRARY_DIRS ${X11_LIBRARY_DIRS})
|
|
||||||
target_compile_definitions(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
USE_X11
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
if(${X11_Xrender_FOUND})
|
|
||||||
list(APPEND INCLUDE_DIRS ${XRENDER_INCLUDE_DIRS})
|
|
||||||
list(APPEND LIBRARY_DIRS ${XRENDER_LIBRARY_DIRS})
|
|
||||||
target_compile_definitions(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
USE_XRENDER
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
|
||||||
list(APPEND LIBRARIES dl)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
find_package(DBus1)
|
|
||||||
|
|
||||||
if(${DBus1_FOUND})
|
|
||||||
list(APPEND INCLUDE_DIRS ${DBUS_INCLUDE_DIRS})
|
|
||||||
list(APPEND LIBRARY_DIRS ${DBUS_LIBRARY_DIRS})
|
|
||||||
target_compile_definitions(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
USE_DBUS
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if(UNIX)
|
|
||||||
list(APPEND LIBRARIES m)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_include_directories(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
${INCLUDE_DIRS}
|
|
||||||
)
|
|
||||||
target_link_directories(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
${LIBRARY_DIRS}
|
|
||||||
)
|
|
||||||
target_link_libraries(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
${LIBRARIES}
|
|
||||||
)
|
|
||||||
|
|
||||||
if(MW_BUILD_OPENGL)
|
|
||||||
target_compile_definitions(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
MW_OPENGL
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(MW_BUILD_VULKAN)
|
|
||||||
check_include_files(vulkan/vk_enum_string_helper.h HAS_VK_ENUM_STRING_HELPER)
|
|
||||||
if(HAS_VK_ENUM_STRING_HELPER)
|
|
||||||
target_compile_definitions(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
HAS_VK_ENUM_STRING_HELPER
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_compile_definitions(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
MW_VULKAN
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_compile_definitions(
|
|
||||||
Mw
|
|
||||||
PRIVATE
|
|
||||||
_MILSKO _MILSKO_BUILD
|
|
||||||
)
|
|
||||||
|
|
||||||
install(
|
|
||||||
TARGETS Mw
|
|
||||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
|
||||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
||||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
configure_file(
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/resource/${PROJECT_NAME}.pc.in
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc
|
|
||||||
@ONLY
|
|
||||||
)
|
|
||||||
|
|
||||||
install(
|
|
||||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc
|
|
||||||
DESTINATION $ENV{MINGW_PREFIX}/${CMAKE_INSTALL_DATADIR}/pkgconfig
|
|
||||||
)
|
|
||||||
|
|
||||||
if(MW_INSTALL_HEADERS)
|
|
||||||
install(
|
|
||||||
DIRECTORY include/
|
|
||||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
|
||||||
FILES_MATCHING PATTERN "*.h"
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(MW_BUILD_EXAMPLES)
|
|
||||||
add_subdirectory(examples)
|
|
||||||
endif()
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
PROJECT_LOGO = resource/logo/logo64.png
|
|
||||||
PROJECT_NAME = Milsko
|
|
||||||
PROJECT_BRIEF = "Lightweight and fast GUI toolkit"
|
|
||||||
OUTPUT_DIRECTORY = doxygen
|
|
||||||
TAB_SIZE = 8
|
|
||||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
|
||||||
MARKDOWN_SUPPORT = YES
|
|
||||||
FILE_PATTERNS = *.h *.md
|
|
||||||
INPUT = include/Mw
|
|
||||||
INPUT += doc
|
|
||||||
RECURSIVE = YES
|
|
||||||
SOURCE_BROWSER = YES
|
|
||||||
HTML_DYNAMIC_MENUS = YES
|
|
||||||
GENERATE_TREEVIEW = YES
|
|
||||||
FULL_SIDEBAR = NO
|
|
||||||
DISABLE_INDEX = NO
|
|
||||||
HAVE_DOT = YES
|
|
||||||
FULL_PATH_NAMES = YES
|
|
||||||
STRIP_FROM_PATH = include/ doc/
|
|
||||||
ENABLED_SECTIONS = YES
|
|
||||||
OUTPUT_LANGUAGE = English
|
|
||||||
GENERATE_LATEX = NO
|
|
||||||
EXTRACT_ALL = YES
|
|
||||||
|
|
||||||
HTML_EXTRA_STYLESHEET = resource/doxygen-theme/doxygen-awesome.css
|
|
||||||
HTML_COLORSTYLE = LIGHT
|
|
||||||
105
widget/milsko/milskosrc/Jenkinsfile
vendored
105
widget/milsko/milskosrc/Jenkinsfile
vendored
|
|
@ -1,105 +0,0 @@
|
||||||
pipeline {
|
|
||||||
agent {
|
|
||||||
label "built-in"
|
|
||||||
}
|
|
||||||
stages {
|
|
||||||
stage("Build document") {
|
|
||||||
when {
|
|
||||||
branch "master"
|
|
||||||
}
|
|
||||||
agent {
|
|
||||||
label "built-in"
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
sh("rm -rf include/Mw/LowLevel/Wayland")
|
|
||||||
sh("doxygen")
|
|
||||||
sh("rm -rf /var/www/milsko-doxygen")
|
|
||||||
sh("mv doxygen/html /var/www/milsko-doxygen")
|
|
||||||
}
|
|
||||||
post {
|
|
||||||
always {
|
|
||||||
notifyDiscord()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage("Build") {
|
|
||||||
parallel {
|
|
||||||
stage("Build for Linux 64-bit") {
|
|
||||||
agent {
|
|
||||||
label "built-in"
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
sh("git clean -dfx")
|
|
||||||
sh("./configure --enable-opengl --enable-vulkan --without-vulkan-string-helper")
|
|
||||||
sh("make -j4")
|
|
||||||
sh("mv src/libMw.so libMw64.so")
|
|
||||||
archiveArtifacts("libMw64.so")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage("Build for Windows 32-bit") {
|
|
||||||
agent {
|
|
||||||
label "built-in"
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
sh("git clean -dfx")
|
|
||||||
sh("./configure --enable-opengl --enable-stb-truetype --disable-freetype2 --cross --target=Windows --host=i686-w64-mingw32")
|
|
||||||
sh("make -j4")
|
|
||||||
sh("mv src/Mw.dll Mw32.dll")
|
|
||||||
sh("mv src/libMw.dll.a libMw32.dll.a")
|
|
||||||
archiveArtifacts("Mw32.dll,libMw32.dll.a")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage("Build for Windows 64-bit") {
|
|
||||||
agent {
|
|
||||||
label "built-in"
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
sh("git clean -dfx")
|
|
||||||
sh("./configure --enable-opengl --enable-stb-truetype --disable-freetype2 --cross --target=Windows --host=x86_64-w64-mingw32")
|
|
||||||
sh("make -j4")
|
|
||||||
sh("mv src/Mw.dll Mw64.dll")
|
|
||||||
sh("mv src/libMw.dll.a libMw64.dll.a")
|
|
||||||
archiveArtifacts("Mw64.dll,libMw64.dll.a")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage("Build for Windows 32-bit (MSVC)") {
|
|
||||||
agent {
|
|
||||||
label "2012r2"
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
bat("git clean -dfx")
|
|
||||||
bat("nmake -f NTMakefile")
|
|
||||||
bat("move /y src\\Mw.dll MwMSVC32.dll")
|
|
||||||
bat("move /y src\\Mw.lib MwMSVC32.lib")
|
|
||||||
archiveArtifacts("MwMSVC32.dll,MwMSVC32.lib")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage("Build for Windows 32-bit (Watcom)") {
|
|
||||||
agent {
|
|
||||||
label "built-in"
|
|
||||||
}
|
|
||||||
environment {
|
|
||||||
WATCOM = "/usr/watcom"
|
|
||||||
INCLUDE = "/usr/watcom/h:/usr/watcom/h/nt"
|
|
||||||
PATH = "/usr/watcom/binl64:${env.PATH}"
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
sh("git clean -dfx")
|
|
||||||
sh("wmake -f WatMakefile")
|
|
||||||
sh("mv src/Mw.dll MwWat32.dll")
|
|
||||||
sh("mv src/Mw.lib MwWat32.lib")
|
|
||||||
archiveArtifacts("MwWat32.dll,MwWat32.lib")
|
|
||||||
sh("./tools/watcom-pack.sh")
|
|
||||||
sh("mv milsko-examples.zip milsko-examples-win32.zip")
|
|
||||||
archiveArtifacts("milsko-examples-win32.zip")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
post {
|
|
||||||
always {
|
|
||||||
notifyDiscord()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
Copyright (c) 2025-2026, Pyrite development team
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
* Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
* Neither the name of the <organization> nor the names of its contributors
|
|
||||||
may be used to endorse or promote products derived from this software
|
|
||||||
without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
|
||||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
@ -1,328 +0,0 @@
|
||||||
CC = cl /TC /c /nologo
|
|
||||||
LD = link /nologo
|
|
||||||
|
|
||||||
MW_CFLAGS = /Iinclude /Iexternal\libz\include /D_MILSKO /D_MILSKO_BUILD /DUSE_GDI /DUSE_STB_IMAGE /DSTBI_NO_SIMD /DUSE_GDI_TEXT
|
|
||||||
MW_LDFLAGS = /DLL
|
|
||||||
EXE_CFLAGS = /Iinclude
|
|
||||||
EXE_LDFLAGS =
|
|
||||||
.SUFFIXES: .obj .c
|
|
||||||
all: src\Mw.dll examples\basic\box.exe examples\basic\calculator.exe examples\basic\checkbox.exe examples\basic\clipboard.exe examples\basic\colorpicker.exe examples\basic\combobox.exe examples\basic\example.exe examples\basic\filechooser.exe examples\basic\image.exe examples\basic\listbox.exe examples\basic\messagebox.exe examples\basic\periodic.exe examples\basic\progressbar.exe examples\basic\radiobox.exe examples\basic\rotate.exe examples\basic\scrollbar.exe examples\basic\sevensegment.exe examples\basic\subwindow.exe examples\basic\tab.exe examples\basic\treeview.exe examples\basic\viewport.exe examples\gldemos\boing.exe examples\gldemos\clock.exe examples\gldemos\cube.exe examples\gldemos\gears.exe examples\gldemos\triangle.exe examples\gldemos\tripaint.exe
|
|
||||||
lib: src\Mw.dll
|
|
||||||
examples: examples\basic\box.exe examples\basic\calculator.exe examples\basic\checkbox.exe examples\basic\clipboard.exe examples\basic\colorpicker.exe examples\basic\combobox.exe examples\basic\example.exe examples\basic\filechooser.exe examples\basic\image.exe examples\basic\listbox.exe examples\basic\messagebox.exe examples\basic\periodic.exe examples\basic\progressbar.exe examples\basic\radiobox.exe examples\basic\rotate.exe examples\basic\scrollbar.exe examples\basic\sevensegment.exe examples\basic\subwindow.exe examples\basic\tab.exe examples\basic\treeview.exe examples\basic\viewport.exe examples\gldemos\boing.exe examples\gldemos\clock.exe examples\gldemos\cube.exe examples\gldemos\gears.exe examples\gldemos\triangle.exe examples\gldemos\tripaint.exe
|
|
||||||
clean:
|
|
||||||
del /f /q external\libz\src\adler32.obj
|
|
||||||
del /f /q external\libz\src\compress.obj
|
|
||||||
del /f /q external\libz\src\crc32.obj
|
|
||||||
del /f /q external\libz\src\deflate.obj
|
|
||||||
del /f /q external\libz\src\gzclose.obj
|
|
||||||
del /f /q external\libz\src\gzlib.obj
|
|
||||||
del /f /q external\libz\src\gzread.obj
|
|
||||||
del /f /q external\libz\src\gzwrite.obj
|
|
||||||
del /f /q external\libz\src\infback.obj
|
|
||||||
del /f /q external\libz\src\inffast.obj
|
|
||||||
del /f /q external\libz\src\inflate.obj
|
|
||||||
del /f /q external\libz\src\inftrees.obj
|
|
||||||
del /f /q external\libz\src\trees.obj
|
|
||||||
del /f /q external\libz\src\uncompr.obj
|
|
||||||
del /f /q external\libz\src\zutil.obj
|
|
||||||
del /f /q external\stb_ds.obj
|
|
||||||
del /f /q external\stb_image.obj
|
|
||||||
del /f /q external\stb_truetype.obj
|
|
||||||
del /f /q src\abstract\charset.obj
|
|
||||||
del /f /q src\abstract\directory.obj
|
|
||||||
del /f /q src\abstract\dynamic.obj
|
|
||||||
del /f /q src\abstract\time.obj
|
|
||||||
del /f /q src\backend\gdi.obj
|
|
||||||
del /f /q src\color.obj
|
|
||||||
del /f /q src\core.obj
|
|
||||||
del /f /q src\cursor\arrow.obj
|
|
||||||
del /f /q src\cursor\cross.obj
|
|
||||||
del /f /q src\cursor\default.obj
|
|
||||||
del /f /q src\cursor\hidden.obj
|
|
||||||
del /f /q src\cursor\text.obj
|
|
||||||
del /f /q src\default.obj
|
|
||||||
del /f /q src\dialog\colorpicker.obj
|
|
||||||
del /f /q src\dialog\directorychooser.obj
|
|
||||||
del /f /q src\dialog\filechooser.obj
|
|
||||||
del /f /q src\dialog\messagebox.obj
|
|
||||||
del /f /q src\draw.obj
|
|
||||||
del /f /q src\icon\back.obj
|
|
||||||
del /f /q src\icon\clock.obj
|
|
||||||
del /f /q src\icon\computer.obj
|
|
||||||
del /f /q src\icon\directory.obj
|
|
||||||
del /f /q src\icon\down.obj
|
|
||||||
del /f /q src\icon\error.obj
|
|
||||||
del /f /q src\icon\file.obj
|
|
||||||
del /f /q src\icon\forward.obj
|
|
||||||
del /f /q src\icon\info.obj
|
|
||||||
del /f /q src\icon\left.obj
|
|
||||||
del /f /q src\icon\news.obj
|
|
||||||
del /f /q src\icon\note.obj
|
|
||||||
del /f /q src\icon\right.obj
|
|
||||||
del /f /q src\icon\search.obj
|
|
||||||
del /f /q src\icon\up.obj
|
|
||||||
del /f /q src\icon\warning.obj
|
|
||||||
del /f /q src\lowlevel.obj
|
|
||||||
del /f /q src\string.obj
|
|
||||||
del /f /q src\text\font\boldfont.obj
|
|
||||||
del /f /q src\text\font\boldmonottf.obj
|
|
||||||
del /f /q src\text\font\boldttf.obj
|
|
||||||
del /f /q src\text\font\font.obj
|
|
||||||
del /f /q src\text\font\monottf.obj
|
|
||||||
del /f /q src\text\font\ttf.obj
|
|
||||||
del /f /q src\text\ft2.obj
|
|
||||||
del /f /q src\text\gdi.obj
|
|
||||||
del /f /q src\text\stbtt.obj
|
|
||||||
del /f /q src\text\text.obj
|
|
||||||
del /f /q src\truetype.obj
|
|
||||||
del /f /q src\unicode.obj
|
|
||||||
del /f /q src\widget\box.obj
|
|
||||||
del /f /q src\widget\button.obj
|
|
||||||
del /f /q src\widget\calendar.obj
|
|
||||||
del /f /q src\widget\checkbox.obj
|
|
||||||
del /f /q src\widget\combobox.obj
|
|
||||||
del /f /q src\widget\entry.obj
|
|
||||||
del /f /q src\widget\frame.obj
|
|
||||||
del /f /q src\widget\image.obj
|
|
||||||
del /f /q src\widget\label.obj
|
|
||||||
del /f /q src\widget\listbox.obj
|
|
||||||
del /f /q src\widget\menu.obj
|
|
||||||
del /f /q src\widget\numberentry.obj
|
|
||||||
del /f /q src\widget\opengl.obj
|
|
||||||
del /f /q src\widget\progressbar.obj
|
|
||||||
del /f /q src\widget\radiobox.obj
|
|
||||||
del /f /q src\widget\scrollbar.obj
|
|
||||||
del /f /q src\widget\separator.obj
|
|
||||||
del /f /q src\widget\submenu.obj
|
|
||||||
del /f /q src\widget\subwindow.obj
|
|
||||||
del /f /q src\widget\tab.obj
|
|
||||||
del /f /q src\widget\table.obj
|
|
||||||
del /f /q src\widget\treeview.obj
|
|
||||||
del /f /q src\widget\viewport.obj
|
|
||||||
del /f /q src\widget\window.obj
|
|
||||||
del /f /q src\Mw.dll
|
|
||||||
del /f /q src\Mw.lib
|
|
||||||
del /f /q examples\basic\box.obj
|
|
||||||
del /f /q examples\basic\calculator.obj
|
|
||||||
del /f /q examples\basic\checkbox.obj
|
|
||||||
del /f /q examples\basic\clipboard.obj
|
|
||||||
del /f /q examples\basic\colorpicker.obj
|
|
||||||
del /f /q examples\basic\combobox.obj
|
|
||||||
del /f /q examples\basic\example.obj
|
|
||||||
del /f /q examples\basic\filechooser.obj
|
|
||||||
del /f /q examples\basic\image.obj
|
|
||||||
del /f /q examples\basic\listbox.obj
|
|
||||||
del /f /q examples\basic\messagebox.obj
|
|
||||||
del /f /q examples\basic\periodic.obj
|
|
||||||
del /f /q examples\basic\progressbar.obj
|
|
||||||
del /f /q examples\basic\radiobox.obj
|
|
||||||
del /f /q examples\basic\rotate.obj
|
|
||||||
del /f /q examples\basic\scrollbar.obj
|
|
||||||
del /f /q examples\basic\sevensegment.obj
|
|
||||||
del /f /q examples\basic\subwindow.obj
|
|
||||||
del /f /q examples\basic\tab.obj
|
|
||||||
del /f /q examples\basic\treeview.obj
|
|
||||||
del /f /q examples\basic\viewport.obj
|
|
||||||
del /f /q examples\gldemos\boing.obj
|
|
||||||
del /f /q examples\gldemos\clock.obj
|
|
||||||
del /f /q examples\gldemos\cube.obj
|
|
||||||
del /f /q examples\gldemos\gears.obj
|
|
||||||
del /f /q examples\gldemos\triangle.obj
|
|
||||||
del /f /q examples\gldemos\tripaint.obj
|
|
||||||
del /f /q examples\basic\box.exe
|
|
||||||
del /f /q examples\basic\calculator.exe
|
|
||||||
del /f /q examples\basic\checkbox.exe
|
|
||||||
del /f /q examples\basic\clipboard.exe
|
|
||||||
del /f /q examples\basic\colorpicker.exe
|
|
||||||
del /f /q examples\basic\combobox.exe
|
|
||||||
del /f /q examples\basic\example.exe
|
|
||||||
del /f /q examples\basic\filechooser.exe
|
|
||||||
del /f /q examples\basic\image.exe
|
|
||||||
del /f /q examples\basic\listbox.exe
|
|
||||||
del /f /q examples\basic\messagebox.exe
|
|
||||||
del /f /q examples\basic\periodic.exe
|
|
||||||
del /f /q examples\basic\progressbar.exe
|
|
||||||
del /f /q examples\basic\radiobox.exe
|
|
||||||
del /f /q examples\basic\rotate.exe
|
|
||||||
del /f /q examples\basic\scrollbar.exe
|
|
||||||
del /f /q examples\basic\sevensegment.exe
|
|
||||||
del /f /q examples\basic\subwindow.exe
|
|
||||||
del /f /q examples\basic\tab.exe
|
|
||||||
del /f /q examples\basic\treeview.exe
|
|
||||||
del /f /q examples\basic\viewport.exe
|
|
||||||
del /f /q examples\gldemos\boing.exe
|
|
||||||
del /f /q examples\gldemos\clock.exe
|
|
||||||
del /f /q examples\gldemos\cube.exe
|
|
||||||
del /f /q examples\gldemos\gears.exe
|
|
||||||
del /f /q examples\gldemos\triangle.exe
|
|
||||||
del /f /q examples\gldemos\tripaint.exe
|
|
||||||
|
|
||||||
examples\basic\box.exe: examples\basic\box.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\box.obj src\Mw.lib
|
|
||||||
|
|
||||||
examples\basic\box.obj: examples/basic/box.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/box.c
|
|
||||||
|
|
||||||
examples\basic\calculator.exe: examples\basic\calculator.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\calculator.obj src\Mw.lib
|
|
||||||
|
|
||||||
examples\basic\calculator.obj: examples/basic/calculator.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/calculator.c
|
|
||||||
|
|
||||||
examples\basic\checkbox.exe: examples\basic\checkbox.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\checkbox.obj src\Mw.lib
|
|
||||||
|
|
||||||
examples\basic\checkbox.obj: examples/basic/checkbox.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/checkbox.c
|
|
||||||
|
|
||||||
examples\basic\clipboard.exe: examples\basic\clipboard.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\clipboard.obj src\Mw.lib
|
|
||||||
|
|
||||||
examples\basic\clipboard.obj: examples/basic/clipboard.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/clipboard.c
|
|
||||||
|
|
||||||
examples\basic\colorpicker.exe: examples\basic\colorpicker.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\colorpicker.obj src\Mw.lib
|
|
||||||
|
|
||||||
examples\basic\colorpicker.obj: examples/basic/colorpicker.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/colorpicker.c
|
|
||||||
|
|
||||||
examples\basic\combobox.exe: examples\basic\combobox.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\combobox.obj src\Mw.lib
|
|
||||||
|
|
||||||
examples\basic\combobox.obj: examples/basic/combobox.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/combobox.c
|
|
||||||
|
|
||||||
examples\basic\example.exe: examples\basic\example.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\example.obj src\Mw.lib
|
|
||||||
|
|
||||||
examples\basic\example.obj: examples/basic/example.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/example.c
|
|
||||||
|
|
||||||
examples\basic\filechooser.exe: examples\basic\filechooser.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\filechooser.obj src\Mw.lib
|
|
||||||
|
|
||||||
examples\basic\filechooser.obj: examples/basic/filechooser.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/filechooser.c
|
|
||||||
|
|
||||||
examples\basic\image.exe: examples\basic\image.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\image.obj src\Mw.lib
|
|
||||||
|
|
||||||
examples\basic\image.obj: examples/basic/image.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/image.c
|
|
||||||
|
|
||||||
examples\basic\listbox.exe: examples\basic\listbox.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\listbox.obj src\Mw.lib
|
|
||||||
|
|
||||||
examples\basic\listbox.obj: examples/basic/listbox.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/listbox.c
|
|
||||||
|
|
||||||
examples\basic\messagebox.exe: examples\basic\messagebox.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\messagebox.obj src\Mw.lib
|
|
||||||
|
|
||||||
examples\basic\messagebox.obj: examples/basic/messagebox.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/messagebox.c
|
|
||||||
|
|
||||||
examples\basic\periodic.exe: examples\basic\periodic.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\periodic.obj src\Mw.lib
|
|
||||||
|
|
||||||
examples\basic\periodic.obj: examples/basic/periodic.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/periodic.c
|
|
||||||
|
|
||||||
examples\basic\progressbar.exe: examples\basic\progressbar.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\progressbar.obj src\Mw.lib
|
|
||||||
|
|
||||||
examples\basic\progressbar.obj: examples/basic/progressbar.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/progressbar.c
|
|
||||||
|
|
||||||
examples\basic\radiobox.exe: examples\basic\radiobox.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\radiobox.obj src\Mw.lib
|
|
||||||
|
|
||||||
examples\basic\radiobox.obj: examples/basic/radiobox.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/radiobox.c
|
|
||||||
|
|
||||||
examples\basic\rotate.exe: examples\basic\rotate.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\rotate.obj src\Mw.lib
|
|
||||||
|
|
||||||
examples\basic\rotate.obj: examples/basic/rotate.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/rotate.c
|
|
||||||
|
|
||||||
examples\basic\scrollbar.exe: examples\basic\scrollbar.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\scrollbar.obj src\Mw.lib
|
|
||||||
|
|
||||||
examples\basic\scrollbar.obj: examples/basic/scrollbar.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/scrollbar.c
|
|
||||||
|
|
||||||
examples\basic\sevensegment.exe: examples\basic\sevensegment.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\sevensegment.obj src\Mw.lib
|
|
||||||
|
|
||||||
examples\basic\sevensegment.obj: examples/basic/sevensegment.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/sevensegment.c
|
|
||||||
|
|
||||||
examples\basic\subwindow.exe: examples\basic\subwindow.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\subwindow.obj src\Mw.lib
|
|
||||||
|
|
||||||
examples\basic\subwindow.obj: examples/basic/subwindow.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/subwindow.c
|
|
||||||
|
|
||||||
examples\basic\tab.exe: examples\basic\tab.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\tab.obj src\Mw.lib
|
|
||||||
|
|
||||||
examples\basic\tab.obj: examples/basic/tab.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/tab.c
|
|
||||||
|
|
||||||
examples\basic\treeview.exe: examples\basic\treeview.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\treeview.obj src\Mw.lib
|
|
||||||
|
|
||||||
examples\basic\treeview.obj: examples/basic/treeview.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/treeview.c
|
|
||||||
|
|
||||||
examples\basic\viewport.exe: examples\basic\viewport.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\viewport.obj src\Mw.lib
|
|
||||||
|
|
||||||
examples\basic\viewport.obj: examples/basic/viewport.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/viewport.c
|
|
||||||
|
|
||||||
examples\gldemos\boing.exe: examples\gldemos\boing.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\gldemos\boing.obj src\Mw.lib opengl32.lib glu32.lib
|
|
||||||
|
|
||||||
examples\gldemos\boing.obj: examples/gldemos/boing.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/gldemos/boing.c
|
|
||||||
|
|
||||||
examples\gldemos\clock.exe: examples\gldemos\clock.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\gldemos\clock.obj src\Mw.lib opengl32.lib glu32.lib
|
|
||||||
|
|
||||||
examples\gldemos\clock.obj: examples/gldemos/clock.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/gldemos/clock.c
|
|
||||||
|
|
||||||
examples\gldemos\cube.exe: examples\gldemos\cube.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\gldemos\cube.obj src\Mw.lib opengl32.lib glu32.lib
|
|
||||||
|
|
||||||
examples\gldemos\cube.obj: examples/gldemos/cube.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/gldemos/cube.c
|
|
||||||
|
|
||||||
examples\gldemos\gears.exe: examples\gldemos\gears.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\gldemos\gears.obj src\Mw.lib opengl32.lib glu32.lib
|
|
||||||
|
|
||||||
examples\gldemos\gears.obj: examples/gldemos/gears.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/gldemos/gears.c
|
|
||||||
|
|
||||||
examples\gldemos\triangle.exe: examples\gldemos\triangle.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\gldemos\triangle.obj src\Mw.lib opengl32.lib glu32.lib
|
|
||||||
|
|
||||||
examples\gldemos\triangle.obj: examples/gldemos/triangle.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/gldemos/triangle.c
|
|
||||||
|
|
||||||
examples\gldemos\tripaint.exe: examples\gldemos\tripaint.obj src\Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) /OUT:$@ examples\gldemos\tripaint.obj src\Mw.lib opengl32.lib glu32.lib
|
|
||||||
|
|
||||||
examples\gldemos\tripaint.obj: examples/gldemos/tripaint.c
|
|
||||||
$(CC) $(EXE_CFLAGS) /Fo$@ examples/gldemos/tripaint.c
|
|
||||||
|
|
||||||
|
|
||||||
src\Mw.dll: external\libz\src\adler32.obj external\libz\src\compress.obj external\libz\src\crc32.obj external\libz\src\deflate.obj external\libz\src\gzclose.obj external\libz\src\gzlib.obj external\libz\src\gzread.obj external\libz\src\gzwrite.obj external\libz\src\infback.obj external\libz\src\inffast.obj external\libz\src\inflate.obj external\libz\src\inftrees.obj external\libz\src\trees.obj external\libz\src\uncompr.obj external\libz\src\zutil.obj external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\charset.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\font\boldfont.obj src\text\font\boldmonottf.obj src\text\font\boldttf.obj src\text\font\font.obj src\text\font\monottf.obj src\text\font\ttf.obj src\text\ft2.obj src\text\gdi.obj src\text\stbtt.obj src\text\text.obj src\truetype.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\calendar.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\subwindow.obj src\widget\tab.obj src\widget\table.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj
|
|
||||||
$(LD) $(MW_LDFLAGS) /OUT:$@ external\libz\src\adler32.obj external\libz\src\compress.obj external\libz\src\crc32.obj external\libz\src\deflate.obj external\libz\src\gzclose.obj external\libz\src\gzlib.obj external\libz\src\gzread.obj external\libz\src\gzwrite.obj external\libz\src\infback.obj external\libz\src\inffast.obj external\libz\src\inflate.obj external\libz\src\inftrees.obj external\libz\src\trees.obj external\libz\src\uncompr.obj external\libz\src\zutil.obj external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\charset.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\font\boldfont.obj src\text\font\boldmonottf.obj src\text\font\boldttf.obj src\text\font\font.obj src\text\font\monottf.obj src\text\font\ttf.obj src\text\ft2.obj src\text\gdi.obj src\text\stbtt.obj src\text\text.obj src\truetype.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\calendar.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\subwindow.obj src\widget\tab.obj src\widget\table.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj opengl32.lib gdi32.lib winmm.lib user32.lib advapi32.lib
|
|
||||||
|
|
||||||
|
|
||||||
.c.obj:
|
|
||||||
$(CC) $(MW_CFLAGS) /Fo$@ $<
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
|
|
||||||
Greetings - Welcome to the Milsko GUI Toolkit (Version 1.4)
|
|
||||||
|
|
||||||
This document contains a brief summary of the contents of this source
|
|
||||||
distributions and building instructions for Milsko GUI Toolkit.
|
|
||||||
|
|
||||||
Requirements
|
|
||||||
|
|
||||||
Milsko requires either
|
|
||||||
* A Windows environment with GDI (so anything NT or 9x)
|
|
||||||
* A Unix-like environment with Wayland and/or X11 for runtime.
|
|
||||||
|
|
||||||
To build Milsko for Windows, you must have one of following compilers:
|
|
||||||
* Visual C++ 6.0 or newer
|
|
||||||
* Borland C++ 5.5 or newer
|
|
||||||
* Open Watcom 2.0 or newer
|
|
||||||
* MinGW-w64
|
|
||||||
|
|
||||||
and for Unix-like and MacOS:
|
|
||||||
* GNU C Compiler
|
|
||||||
* Clang
|
|
||||||
|
|
||||||
|
|
||||||
Contents
|
|
||||||
|
|
||||||
At the top level of this hierarchy there are seven directories:
|
|
||||||
|
|
||||||
src - Contains the source for Milsko library
|
|
||||||
|
|
||||||
include - Contains the headers for Milsko
|
|
||||||
|
|
||||||
doc - Contains the documentation for Milsko
|
|
||||||
|
|
||||||
external - Contains the external dependency that Milsko uses
|
|
||||||
|
|
||||||
resource - Contains the resources used by maintainers
|
|
||||||
|
|
||||||
tools - Contains the tools used by maintainers
|
|
||||||
|
|
||||||
|
|
||||||
Building Milsko
|
|
||||||
|
|
||||||
Building Milsko depends on the platform you use, and the compiler you use.
|
|
||||||
|
|
||||||
A. Visual C++
|
|
||||||
-------------
|
|
||||||
|
|
||||||
1) Run `nmake -f NTMakefile'.
|
|
||||||
|
|
||||||
B. Borland C++
|
|
||||||
--------------
|
|
||||||
|
|
||||||
1) Run `make -f BorMakefile'.
|
|
||||||
|
|
||||||
C. Open Watcom
|
|
||||||
--------------
|
|
||||||
|
|
||||||
1) Run `wmake -f WatMakefile'.
|
|
||||||
|
|
||||||
D. MinGW-w64/GCC/Clang
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
1) Determine if you need Vulkan and/or OpenGL.
|
|
||||||
|
|
||||||
2) Either:
|
|
||||||
a.) Run `./configure'. For help, run `./configure --help'.
|
|
||||||
b.) Use CMake; i.e. `cmake -B build`. (if contributing, name the build
|
|
||||||
folder build as that's what's included in the .gitignore)
|
|
||||||
|
|
||||||
3) Run `make'.
|
|
||||||
|
|
||||||
-- Nishi (nishi@nishi.boats)
|
|
||||||
|
|
@ -1,506 +0,0 @@
|
||||||
CC = wcc386 -bt=nt -q
|
|
||||||
LD = wlink option quiet
|
|
||||||
|
|
||||||
MW_CFLAGS = -bd -i=include -i=external/libz/include -d_MILSKO -d_MILSKO_BUILD -dUSE_GDI -dUSE_STB_IMAGE -dSTBI_NO_SIMD -dUSE_GDI_TEXT
|
|
||||||
MW_LDFLAGS = system nt_dll
|
|
||||||
EXE_CFLAGS = -i=include
|
|
||||||
EXE_LDFLAGS = system nt
|
|
||||||
all: src/Mw.dll examples/basic/box.exe examples/basic/calculator.exe examples/basic/checkbox.exe examples/basic/clipboard.exe examples/basic/colorpicker.exe examples/basic/combobox.exe examples/basic/example.exe examples/basic/filechooser.exe examples/basic/image.exe examples/basic/listbox.exe examples/basic/messagebox.exe examples/basic/periodic.exe examples/basic/progressbar.exe examples/basic/radiobox.exe examples/basic/rotate.exe examples/basic/scrollbar.exe examples/basic/sevensegment.exe examples/basic/subwindow.exe examples/basic/tab.exe examples/basic/treeview.exe examples/basic/viewport.exe examples/gldemos/boing.exe examples/gldemos/clock.exe examples/gldemos/cube.exe examples/gldemos/gears.exe examples/gldemos/triangle.exe examples/gldemos/tripaint.exe
|
|
||||||
lib: src/Mw.dll
|
|
||||||
examples: examples/basic/box.exe examples/basic/calculator.exe examples/basic/checkbox.exe examples/basic/clipboard.exe examples/basic/colorpicker.exe examples/basic/combobox.exe examples/basic/example.exe examples/basic/filechooser.exe examples/basic/image.exe examples/basic/listbox.exe examples/basic/messagebox.exe examples/basic/periodic.exe examples/basic/progressbar.exe examples/basic/radiobox.exe examples/basic/rotate.exe examples/basic/scrollbar.exe examples/basic/sevensegment.exe examples/basic/subwindow.exe examples/basic/tab.exe examples/basic/treeview.exe examples/basic/viewport.exe examples/gldemos/boing.exe examples/gldemos/clock.exe examples/gldemos/cube.exe examples/gldemos/gears.exe examples/gldemos/triangle.exe examples/gldemos/tripaint.exe
|
|
||||||
clean: .SYMBOLIC
|
|
||||||
%erase external/libz/src/adler32.obj
|
|
||||||
%erase external/libz/src/compress.obj
|
|
||||||
%erase external/libz/src/crc32.obj
|
|
||||||
%erase external/libz/src/deflate.obj
|
|
||||||
%erase external/libz/src/gzclose.obj
|
|
||||||
%erase external/libz/src/gzlib.obj
|
|
||||||
%erase external/libz/src/gzread.obj
|
|
||||||
%erase external/libz/src/gzwrite.obj
|
|
||||||
%erase external/libz/src/infback.obj
|
|
||||||
%erase external/libz/src/inffast.obj
|
|
||||||
%erase external/libz/src/inflate.obj
|
|
||||||
%erase external/libz/src/inftrees.obj
|
|
||||||
%erase external/libz/src/trees.obj
|
|
||||||
%erase external/libz/src/uncompr.obj
|
|
||||||
%erase external/libz/src/zutil.obj
|
|
||||||
%erase external/stb_ds.obj
|
|
||||||
%erase external/stb_image.obj
|
|
||||||
%erase external/stb_truetype.obj
|
|
||||||
%erase src/abstract/charset.obj
|
|
||||||
%erase src/abstract/directory.obj
|
|
||||||
%erase src/abstract/dynamic.obj
|
|
||||||
%erase src/abstract/time.obj
|
|
||||||
%erase src/backend/gdi.obj
|
|
||||||
%erase src/color.obj
|
|
||||||
%erase src/core.obj
|
|
||||||
%erase src/cursor/arrow.obj
|
|
||||||
%erase src/cursor/cross.obj
|
|
||||||
%erase src/cursor/default.obj
|
|
||||||
%erase src/cursor/hidden.obj
|
|
||||||
%erase src/cursor/text.obj
|
|
||||||
%erase src/default.obj
|
|
||||||
%erase src/dialog/colorpicker.obj
|
|
||||||
%erase src/dialog/directorychooser.obj
|
|
||||||
%erase src/dialog/filechooser.obj
|
|
||||||
%erase src/dialog/messagebox.obj
|
|
||||||
%erase src/draw.obj
|
|
||||||
%erase src/icon/back.obj
|
|
||||||
%erase src/icon/clock.obj
|
|
||||||
%erase src/icon/computer.obj
|
|
||||||
%erase src/icon/directory.obj
|
|
||||||
%erase src/icon/down.obj
|
|
||||||
%erase src/icon/error.obj
|
|
||||||
%erase src/icon/file.obj
|
|
||||||
%erase src/icon/forward.obj
|
|
||||||
%erase src/icon/info.obj
|
|
||||||
%erase src/icon/left.obj
|
|
||||||
%erase src/icon/news.obj
|
|
||||||
%erase src/icon/note.obj
|
|
||||||
%erase src/icon/right.obj
|
|
||||||
%erase src/icon/search.obj
|
|
||||||
%erase src/icon/up.obj
|
|
||||||
%erase src/icon/warning.obj
|
|
||||||
%erase src/lowlevel.obj
|
|
||||||
%erase src/string.obj
|
|
||||||
%erase src/text/font/boldfont.obj
|
|
||||||
%erase src/text/font/boldmonottf.obj
|
|
||||||
%erase src/text/font/boldttf.obj
|
|
||||||
%erase src/text/font/font.obj
|
|
||||||
%erase src/text/font/monottf.obj
|
|
||||||
%erase src/text/font/ttf.obj
|
|
||||||
%erase src/text/ft2.obj
|
|
||||||
%erase src/text/gdi.obj
|
|
||||||
%erase src/text/stbtt.obj
|
|
||||||
%erase src/text/text.obj
|
|
||||||
%erase src/truetype.obj
|
|
||||||
%erase src/unicode.obj
|
|
||||||
%erase src/widget/box.obj
|
|
||||||
%erase src/widget/button.obj
|
|
||||||
%erase src/widget/calendar.obj
|
|
||||||
%erase src/widget/checkbox.obj
|
|
||||||
%erase src/widget/combobox.obj
|
|
||||||
%erase src/widget/entry.obj
|
|
||||||
%erase src/widget/frame.obj
|
|
||||||
%erase src/widget/image.obj
|
|
||||||
%erase src/widget/label.obj
|
|
||||||
%erase src/widget/listbox.obj
|
|
||||||
%erase src/widget/menu.obj
|
|
||||||
%erase src/widget/numberentry.obj
|
|
||||||
%erase src/widget/opengl.obj
|
|
||||||
%erase src/widget/progressbar.obj
|
|
||||||
%erase src/widget/radiobox.obj
|
|
||||||
%erase src/widget/scrollbar.obj
|
|
||||||
%erase src/widget/separator.obj
|
|
||||||
%erase src/widget/submenu.obj
|
|
||||||
%erase src/widget/subwindow.obj
|
|
||||||
%erase src/widget/tab.obj
|
|
||||||
%erase src/widget/table.obj
|
|
||||||
%erase src/widget/treeview.obj
|
|
||||||
%erase src/widget/viewport.obj
|
|
||||||
%erase src/widget/window.obj
|
|
||||||
%erase src/Mw.dll
|
|
||||||
%erase src/Mw.lib
|
|
||||||
%erase examples/basic/box.obj
|
|
||||||
%erase examples/basic/calculator.obj
|
|
||||||
%erase examples/basic/checkbox.obj
|
|
||||||
%erase examples/basic/clipboard.obj
|
|
||||||
%erase examples/basic/colorpicker.obj
|
|
||||||
%erase examples/basic/combobox.obj
|
|
||||||
%erase examples/basic/example.obj
|
|
||||||
%erase examples/basic/filechooser.obj
|
|
||||||
%erase examples/basic/image.obj
|
|
||||||
%erase examples/basic/listbox.obj
|
|
||||||
%erase examples/basic/messagebox.obj
|
|
||||||
%erase examples/basic/periodic.obj
|
|
||||||
%erase examples/basic/progressbar.obj
|
|
||||||
%erase examples/basic/radiobox.obj
|
|
||||||
%erase examples/basic/rotate.obj
|
|
||||||
%erase examples/basic/scrollbar.obj
|
|
||||||
%erase examples/basic/sevensegment.obj
|
|
||||||
%erase examples/basic/subwindow.obj
|
|
||||||
%erase examples/basic/tab.obj
|
|
||||||
%erase examples/basic/treeview.obj
|
|
||||||
%erase examples/basic/viewport.obj
|
|
||||||
%erase examples/gldemos/boing.obj
|
|
||||||
%erase examples/gldemos/clock.obj
|
|
||||||
%erase examples/gldemos/cube.obj
|
|
||||||
%erase examples/gldemos/gears.obj
|
|
||||||
%erase examples/gldemos/triangle.obj
|
|
||||||
%erase examples/gldemos/tripaint.obj
|
|
||||||
%erase examples/basic/box.exe
|
|
||||||
%erase examples/basic/calculator.exe
|
|
||||||
%erase examples/basic/checkbox.exe
|
|
||||||
%erase examples/basic/clipboard.exe
|
|
||||||
%erase examples/basic/colorpicker.exe
|
|
||||||
%erase examples/basic/combobox.exe
|
|
||||||
%erase examples/basic/example.exe
|
|
||||||
%erase examples/basic/filechooser.exe
|
|
||||||
%erase examples/basic/image.exe
|
|
||||||
%erase examples/basic/listbox.exe
|
|
||||||
%erase examples/basic/messagebox.exe
|
|
||||||
%erase examples/basic/periodic.exe
|
|
||||||
%erase examples/basic/progressbar.exe
|
|
||||||
%erase examples/basic/radiobox.exe
|
|
||||||
%erase examples/basic/rotate.exe
|
|
||||||
%erase examples/basic/scrollbar.exe
|
|
||||||
%erase examples/basic/sevensegment.exe
|
|
||||||
%erase examples/basic/subwindow.exe
|
|
||||||
%erase examples/basic/tab.exe
|
|
||||||
%erase examples/basic/treeview.exe
|
|
||||||
%erase examples/basic/viewport.exe
|
|
||||||
%erase examples/gldemos/boing.exe
|
|
||||||
%erase examples/gldemos/clock.exe
|
|
||||||
%erase examples/gldemos/cube.exe
|
|
||||||
%erase examples/gldemos/gears.exe
|
|
||||||
%erase examples/gldemos/triangle.exe
|
|
||||||
%erase examples/gldemos/tripaint.exe
|
|
||||||
|
|
||||||
examples/basic/box.exe: examples/basic/box.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/basic/box.obj library clib3r.lib library src/Mw.lib
|
|
||||||
|
|
||||||
examples/basic/box.obj: examples/basic/box.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/box.c
|
|
||||||
|
|
||||||
examples/basic/calculator.exe: examples/basic/calculator.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/basic/calculator.obj library clib3r.lib library src/Mw.lib
|
|
||||||
|
|
||||||
examples/basic/calculator.obj: examples/basic/calculator.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/calculator.c
|
|
||||||
|
|
||||||
examples/basic/checkbox.exe: examples/basic/checkbox.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/basic/checkbox.obj library clib3r.lib library src/Mw.lib
|
|
||||||
|
|
||||||
examples/basic/checkbox.obj: examples/basic/checkbox.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/checkbox.c
|
|
||||||
|
|
||||||
examples/basic/clipboard.exe: examples/basic/clipboard.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/basic/clipboard.obj library clib3r.lib library src/Mw.lib
|
|
||||||
|
|
||||||
examples/basic/clipboard.obj: examples/basic/clipboard.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/clipboard.c
|
|
||||||
|
|
||||||
examples/basic/colorpicker.exe: examples/basic/colorpicker.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/basic/colorpicker.obj library clib3r.lib library src/Mw.lib
|
|
||||||
|
|
||||||
examples/basic/colorpicker.obj: examples/basic/colorpicker.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/colorpicker.c
|
|
||||||
|
|
||||||
examples/basic/combobox.exe: examples/basic/combobox.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/basic/combobox.obj library clib3r.lib library src/Mw.lib
|
|
||||||
|
|
||||||
examples/basic/combobox.obj: examples/basic/combobox.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/combobox.c
|
|
||||||
|
|
||||||
examples/basic/example.exe: examples/basic/example.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/basic/example.obj library clib3r.lib library src/Mw.lib
|
|
||||||
|
|
||||||
examples/basic/example.obj: examples/basic/example.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/example.c
|
|
||||||
|
|
||||||
examples/basic/filechooser.exe: examples/basic/filechooser.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/basic/filechooser.obj library clib3r.lib library src/Mw.lib
|
|
||||||
|
|
||||||
examples/basic/filechooser.obj: examples/basic/filechooser.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/filechooser.c
|
|
||||||
|
|
||||||
examples/basic/image.exe: examples/basic/image.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/basic/image.obj library clib3r.lib library src/Mw.lib
|
|
||||||
|
|
||||||
examples/basic/image.obj: examples/basic/image.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/image.c
|
|
||||||
|
|
||||||
examples/basic/listbox.exe: examples/basic/listbox.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/basic/listbox.obj library clib3r.lib library src/Mw.lib
|
|
||||||
|
|
||||||
examples/basic/listbox.obj: examples/basic/listbox.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/listbox.c
|
|
||||||
|
|
||||||
examples/basic/messagebox.exe: examples/basic/messagebox.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/basic/messagebox.obj library clib3r.lib library src/Mw.lib
|
|
||||||
|
|
||||||
examples/basic/messagebox.obj: examples/basic/messagebox.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/messagebox.c
|
|
||||||
|
|
||||||
examples/basic/periodic.exe: examples/basic/periodic.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/basic/periodic.obj library clib3r.lib library src/Mw.lib
|
|
||||||
|
|
||||||
examples/basic/periodic.obj: examples/basic/periodic.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/periodic.c
|
|
||||||
|
|
||||||
examples/basic/progressbar.exe: examples/basic/progressbar.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/basic/progressbar.obj library clib3r.lib library src/Mw.lib
|
|
||||||
|
|
||||||
examples/basic/progressbar.obj: examples/basic/progressbar.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/progressbar.c
|
|
||||||
|
|
||||||
examples/basic/radiobox.exe: examples/basic/radiobox.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/basic/radiobox.obj library clib3r.lib library src/Mw.lib
|
|
||||||
|
|
||||||
examples/basic/radiobox.obj: examples/basic/radiobox.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/radiobox.c
|
|
||||||
|
|
||||||
examples/basic/rotate.exe: examples/basic/rotate.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/basic/rotate.obj library clib3r.lib library src/Mw.lib
|
|
||||||
|
|
||||||
examples/basic/rotate.obj: examples/basic/rotate.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/rotate.c
|
|
||||||
|
|
||||||
examples/basic/scrollbar.exe: examples/basic/scrollbar.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/basic/scrollbar.obj library clib3r.lib library src/Mw.lib
|
|
||||||
|
|
||||||
examples/basic/scrollbar.obj: examples/basic/scrollbar.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/scrollbar.c
|
|
||||||
|
|
||||||
examples/basic/sevensegment.exe: examples/basic/sevensegment.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/basic/sevensegment.obj library clib3r.lib library src/Mw.lib
|
|
||||||
|
|
||||||
examples/basic/sevensegment.obj: examples/basic/sevensegment.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/sevensegment.c
|
|
||||||
|
|
||||||
examples/basic/subwindow.exe: examples/basic/subwindow.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/basic/subwindow.obj library clib3r.lib library src/Mw.lib
|
|
||||||
|
|
||||||
examples/basic/subwindow.obj: examples/basic/subwindow.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/subwindow.c
|
|
||||||
|
|
||||||
examples/basic/tab.exe: examples/basic/tab.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/basic/tab.obj library clib3r.lib library src/Mw.lib
|
|
||||||
|
|
||||||
examples/basic/tab.obj: examples/basic/tab.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/tab.c
|
|
||||||
|
|
||||||
examples/basic/treeview.exe: examples/basic/treeview.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/basic/treeview.obj library clib3r.lib library src/Mw.lib
|
|
||||||
|
|
||||||
examples/basic/treeview.obj: examples/basic/treeview.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/treeview.c
|
|
||||||
|
|
||||||
examples/basic/viewport.exe: examples/basic/viewport.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/basic/viewport.obj library clib3r.lib library src/Mw.lib
|
|
||||||
|
|
||||||
examples/basic/viewport.obj: examples/basic/viewport.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/viewport.c
|
|
||||||
|
|
||||||
examples/gldemos/boing.exe: examples/gldemos/boing.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/gldemos/boing.obj library clib3r.lib library src/Mw.lib library opengl32.lib library glu32.lib
|
|
||||||
|
|
||||||
examples/gldemos/boing.obj: examples/gldemos/boing.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/gldemos/boing.c
|
|
||||||
|
|
||||||
examples/gldemos/clock.exe: examples/gldemos/clock.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/gldemos/clock.obj library clib3r.lib library src/Mw.lib library opengl32.lib library glu32.lib
|
|
||||||
|
|
||||||
examples/gldemos/clock.obj: examples/gldemos/clock.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/gldemos/clock.c
|
|
||||||
|
|
||||||
examples/gldemos/cube.exe: examples/gldemos/cube.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/gldemos/cube.obj library clib3r.lib library src/Mw.lib library opengl32.lib library glu32.lib
|
|
||||||
|
|
||||||
examples/gldemos/cube.obj: examples/gldemos/cube.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/gldemos/cube.c
|
|
||||||
|
|
||||||
examples/gldemos/gears.exe: examples/gldemos/gears.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/gldemos/gears.obj library clib3r.lib library src/Mw.lib library opengl32.lib library glu32.lib
|
|
||||||
|
|
||||||
examples/gldemos/gears.obj: examples/gldemos/gears.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/gldemos/gears.c
|
|
||||||
|
|
||||||
examples/gldemos/triangle.exe: examples/gldemos/triangle.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/gldemos/triangle.obj library clib3r.lib library src/Mw.lib library opengl32.lib library glu32.lib
|
|
||||||
|
|
||||||
examples/gldemos/triangle.obj: examples/gldemos/triangle.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/gldemos/triangle.c
|
|
||||||
|
|
||||||
examples/gldemos/tripaint.exe: examples/gldemos/tripaint.obj src/Mw.dll
|
|
||||||
$(LD) $(EXE_LDFLAGS) name $@ file examples/gldemos/tripaint.obj library clib3r.lib library src/Mw.lib library opengl32.lib library glu32.lib
|
|
||||||
|
|
||||||
examples/gldemos/tripaint.obj: examples/gldemos/tripaint.c
|
|
||||||
$(CC) $(EXE_CFLAGS) -fo=$@ examples/gldemos/tripaint.c
|
|
||||||
|
|
||||||
|
|
||||||
src/Mw.dll: external/libz/src/adler32.obj external/libz/src/compress.obj external/libz/src/crc32.obj external/libz/src/deflate.obj external/libz/src/gzclose.obj external/libz/src/gzlib.obj external/libz/src/gzread.obj external/libz/src/gzwrite.obj external/libz/src/infback.obj external/libz/src/inffast.obj external/libz/src/inflate.obj external/libz/src/inftrees.obj external/libz/src/trees.obj external/libz/src/uncompr.obj external/libz/src/zutil.obj external/stb_ds.obj external/stb_image.obj external/stb_truetype.obj src/abstract/charset.obj src/abstract/directory.obj src/abstract/dynamic.obj src/abstract/time.obj src/backend/gdi.obj src/color.obj src/core.obj src/cursor/arrow.obj src/cursor/cross.obj src/cursor/default.obj src/cursor/hidden.obj src/cursor/text.obj src/default.obj src/dialog/colorpicker.obj src/dialog/directorychooser.obj src/dialog/filechooser.obj src/dialog/messagebox.obj src/draw.obj src/icon/back.obj src/icon/clock.obj src/icon/computer.obj src/icon/directory.obj src/icon/down.obj src/icon/error.obj src/icon/file.obj src/icon/forward.obj src/icon/info.obj src/icon/left.obj src/icon/news.obj src/icon/note.obj src/icon/right.obj src/icon/search.obj src/icon/up.obj src/icon/warning.obj src/lowlevel.obj src/string.obj src/text/font/boldfont.obj src/text/font/boldmonottf.obj src/text/font/boldttf.obj src/text/font/font.obj src/text/font/monottf.obj src/text/font/ttf.obj src/text/ft2.obj src/text/gdi.obj src/text/stbtt.obj src/text/text.obj src/truetype.obj src/unicode.obj src/widget/box.obj src/widget/button.obj src/widget/calendar.obj src/widget/checkbox.obj src/widget/combobox.obj src/widget/entry.obj src/widget/frame.obj src/widget/image.obj src/widget/label.obj src/widget/listbox.obj src/widget/menu.obj src/widget/numberentry.obj src/widget/opengl.obj src/widget/progressbar.obj src/widget/radiobox.obj src/widget/scrollbar.obj src/widget/separator.obj src/widget/submenu.obj src/widget/subwindow.obj src/widget/tab.obj src/widget/table.obj src/widget/treeview.obj src/widget/viewport.obj src/widget/window.obj
|
|
||||||
$(LD) $(MW_LDFLAGS) option implib=src/Mw.lib name $@ file external/libz/src/adler32.obj file external/libz/src/compress.obj file external/libz/src/crc32.obj file external/libz/src/deflate.obj file external/libz/src/gzclose.obj file external/libz/src/gzlib.obj file external/libz/src/gzread.obj file external/libz/src/gzwrite.obj file external/libz/src/infback.obj file external/libz/src/inffast.obj file external/libz/src/inflate.obj file external/libz/src/inftrees.obj file external/libz/src/trees.obj file external/libz/src/uncompr.obj file external/libz/src/zutil.obj file external/stb_ds.obj file external/stb_image.obj file external/stb_truetype.obj file src/abstract/charset.obj file src/abstract/directory.obj file src/abstract/dynamic.obj file src/abstract/time.obj file src/backend/gdi.obj file src/color.obj file src/core.obj file src/cursor/arrow.obj file src/cursor/cross.obj file src/cursor/default.obj file src/cursor/hidden.obj file src/cursor/text.obj file src/default.obj file src/dialog/colorpicker.obj file src/dialog/directorychooser.obj file src/dialog/filechooser.obj file src/dialog/messagebox.obj file src/draw.obj file src/icon/back.obj file src/icon/clock.obj file src/icon/computer.obj file src/icon/directory.obj file src/icon/down.obj file src/icon/error.obj file src/icon/file.obj file src/icon/forward.obj file src/icon/info.obj file src/icon/left.obj file src/icon/news.obj file src/icon/note.obj file src/icon/right.obj file src/icon/search.obj file src/icon/up.obj file src/icon/warning.obj file src/lowlevel.obj file src/string.obj file src/text/font/boldfont.obj file src/text/font/boldmonottf.obj file src/text/font/boldttf.obj file src/text/font/font.obj file src/text/font/monottf.obj file src/text/font/ttf.obj file src/text/ft2.obj file src/text/gdi.obj file src/text/stbtt.obj file src/text/text.obj file src/truetype.obj file src/unicode.obj file src/widget/box.obj file src/widget/button.obj file src/widget/calendar.obj file src/widget/checkbox.obj file src/widget/combobox.obj file src/widget/entry.obj file src/widget/frame.obj file src/widget/image.obj file src/widget/label.obj file src/widget/listbox.obj file src/widget/menu.obj file src/widget/numberentry.obj file src/widget/opengl.obj file src/widget/progressbar.obj file src/widget/radiobox.obj file src/widget/scrollbar.obj file src/widget/separator.obj file src/widget/submenu.obj file src/widget/subwindow.obj file src/widget/tab.obj file src/widget/table.obj file src/widget/treeview.obj file src/widget/viewport.obj file src/widget/window.obj library clib3r.lib library opengl32.lib library gdi32.lib library winmm.lib library user32.lib library advapi32.lib
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
external/libz/src/adler32.obj: external/libz/src/adler32.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/adler32.c
|
|
||||||
external/libz/src/compress.obj: external/libz/src/compress.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/compress.c
|
|
||||||
external/libz/src/crc32.obj: external/libz/src/crc32.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/crc32.c
|
|
||||||
external/libz/src/deflate.obj: external/libz/src/deflate.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/deflate.c
|
|
||||||
external/libz/src/gzclose.obj: external/libz/src/gzclose.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/gzclose.c
|
|
||||||
external/libz/src/gzlib.obj: external/libz/src/gzlib.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/gzlib.c
|
|
||||||
external/libz/src/gzread.obj: external/libz/src/gzread.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/gzread.c
|
|
||||||
external/libz/src/gzwrite.obj: external/libz/src/gzwrite.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/gzwrite.c
|
|
||||||
external/libz/src/infback.obj: external/libz/src/infback.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/infback.c
|
|
||||||
external/libz/src/inffast.obj: external/libz/src/inffast.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/inffast.c
|
|
||||||
external/libz/src/inflate.obj: external/libz/src/inflate.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/inflate.c
|
|
||||||
external/libz/src/inftrees.obj: external/libz/src/inftrees.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/inftrees.c
|
|
||||||
external/libz/src/trees.obj: external/libz/src/trees.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/trees.c
|
|
||||||
external/libz/src/uncompr.obj: external/libz/src/uncompr.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/uncompr.c
|
|
||||||
external/libz/src/zutil.obj: external/libz/src/zutil.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/zutil.c
|
|
||||||
external/stb_ds.obj: external/stb_ds.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ external/stb_ds.c
|
|
||||||
external/stb_image.obj: external/stb_image.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ external/stb_image.c
|
|
||||||
external/stb_truetype.obj: external/stb_truetype.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ external/stb_truetype.c
|
|
||||||
src/abstract/charset.obj: src/abstract/charset.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/abstract/charset.c
|
|
||||||
src/abstract/directory.obj: src/abstract/directory.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/abstract/directory.c
|
|
||||||
src/abstract/dynamic.obj: src/abstract/dynamic.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/abstract/dynamic.c
|
|
||||||
src/abstract/time.obj: src/abstract/time.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/abstract/time.c
|
|
||||||
src/backend/gdi.obj: src/backend/gdi.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/backend/gdi.c
|
|
||||||
src/color.obj: src/color.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/color.c
|
|
||||||
src/core.obj: src/core.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/core.c
|
|
||||||
src/cursor/arrow.obj: src/cursor/arrow.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/cursor/arrow.c
|
|
||||||
src/cursor/cross.obj: src/cursor/cross.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/cursor/cross.c
|
|
||||||
src/cursor/default.obj: src/cursor/default.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/cursor/default.c
|
|
||||||
src/cursor/hidden.obj: src/cursor/hidden.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/cursor/hidden.c
|
|
||||||
src/cursor/text.obj: src/cursor/text.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/cursor/text.c
|
|
||||||
src/default.obj: src/default.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/default.c
|
|
||||||
src/dialog/colorpicker.obj: src/dialog/colorpicker.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/dialog/colorpicker.c
|
|
||||||
src/dialog/directorychooser.obj: src/dialog/directorychooser.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/dialog/directorychooser.c
|
|
||||||
src/dialog/filechooser.obj: src/dialog/filechooser.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/dialog/filechooser.c
|
|
||||||
src/dialog/messagebox.obj: src/dialog/messagebox.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/dialog/messagebox.c
|
|
||||||
src/draw.obj: src/draw.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/draw.c
|
|
||||||
src/icon/back.obj: src/icon/back.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/icon/back.c
|
|
||||||
src/icon/clock.obj: src/icon/clock.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/icon/clock.c
|
|
||||||
src/icon/computer.obj: src/icon/computer.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/icon/computer.c
|
|
||||||
src/icon/directory.obj: src/icon/directory.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/icon/directory.c
|
|
||||||
src/icon/down.obj: src/icon/down.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/icon/down.c
|
|
||||||
src/icon/error.obj: src/icon/error.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/icon/error.c
|
|
||||||
src/icon/file.obj: src/icon/file.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/icon/file.c
|
|
||||||
src/icon/forward.obj: src/icon/forward.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/icon/forward.c
|
|
||||||
src/icon/info.obj: src/icon/info.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/icon/info.c
|
|
||||||
src/icon/left.obj: src/icon/left.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/icon/left.c
|
|
||||||
src/icon/news.obj: src/icon/news.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/icon/news.c
|
|
||||||
src/icon/note.obj: src/icon/note.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/icon/note.c
|
|
||||||
src/icon/right.obj: src/icon/right.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/icon/right.c
|
|
||||||
src/icon/search.obj: src/icon/search.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/icon/search.c
|
|
||||||
src/icon/up.obj: src/icon/up.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/icon/up.c
|
|
||||||
src/icon/warning.obj: src/icon/warning.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/icon/warning.c
|
|
||||||
src/lowlevel.obj: src/lowlevel.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/lowlevel.c
|
|
||||||
src/string.obj: src/string.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/string.c
|
|
||||||
src/text/font/boldfont.obj: src/text/font/boldfont.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/text/font/boldfont.c
|
|
||||||
src/text/font/boldmonottf.obj: src/text/font/boldmonottf.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/text/font/boldmonottf.c
|
|
||||||
src/text/font/boldttf.obj: src/text/font/boldttf.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/text/font/boldttf.c
|
|
||||||
src/text/font/font.obj: src/text/font/font.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/text/font/font.c
|
|
||||||
src/text/font/monottf.obj: src/text/font/monottf.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/text/font/monottf.c
|
|
||||||
src/text/font/ttf.obj: src/text/font/ttf.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/text/font/ttf.c
|
|
||||||
src/text/ft2.obj: src/text/ft2.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/text/ft2.c
|
|
||||||
src/text/gdi.obj: src/text/gdi.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/text/gdi.c
|
|
||||||
src/text/stbtt.obj: src/text/stbtt.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/text/stbtt.c
|
|
||||||
src/text/text.obj: src/text/text.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/text/text.c
|
|
||||||
src/truetype.obj: src/truetype.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/truetype.c
|
|
||||||
src/unicode.obj: src/unicode.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/unicode.c
|
|
||||||
src/widget/box.obj: src/widget/box.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/widget/box.c
|
|
||||||
src/widget/button.obj: src/widget/button.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/widget/button.c
|
|
||||||
src/widget/calendar.obj: src/widget/calendar.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/widget/calendar.c
|
|
||||||
src/widget/checkbox.obj: src/widget/checkbox.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/widget/checkbox.c
|
|
||||||
src/widget/combobox.obj: src/widget/combobox.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/widget/combobox.c
|
|
||||||
src/widget/entry.obj: src/widget/entry.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/widget/entry.c
|
|
||||||
src/widget/frame.obj: src/widget/frame.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/widget/frame.c
|
|
||||||
src/widget/image.obj: src/widget/image.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/widget/image.c
|
|
||||||
src/widget/label.obj: src/widget/label.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/widget/label.c
|
|
||||||
src/widget/listbox.obj: src/widget/listbox.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/widget/listbox.c
|
|
||||||
src/widget/menu.obj: src/widget/menu.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/widget/menu.c
|
|
||||||
src/widget/numberentry.obj: src/widget/numberentry.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/widget/numberentry.c
|
|
||||||
src/widget/opengl.obj: src/widget/opengl.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/widget/opengl.c
|
|
||||||
src/widget/progressbar.obj: src/widget/progressbar.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/widget/progressbar.c
|
|
||||||
src/widget/radiobox.obj: src/widget/radiobox.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/widget/radiobox.c
|
|
||||||
src/widget/scrollbar.obj: src/widget/scrollbar.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/widget/scrollbar.c
|
|
||||||
src/widget/separator.obj: src/widget/separator.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/widget/separator.c
|
|
||||||
src/widget/submenu.obj: src/widget/submenu.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/widget/submenu.c
|
|
||||||
src/widget/subwindow.obj: src/widget/subwindow.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/widget/subwindow.c
|
|
||||||
src/widget/tab.obj: src/widget/tab.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/widget/tab.c
|
|
||||||
src/widget/table.obj: src/widget/table.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/widget/table.c
|
|
||||||
src/widget/treeview.obj: src/widget/treeview.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/widget/treeview.c
|
|
||||||
src/widget/viewport.obj: src/widget/viewport.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/widget/viewport.c
|
|
||||||
src/widget/window.obj: src/widget/window.c
|
|
||||||
$(CC) $(MW_CFLAGS) -fo=$@ src/widget/window.c
|
|
||||||
363
widget/milsko/milskosrc/configure
vendored
363
widget/milsko/milskosrc/configure
vendored
|
|
@ -1,363 +0,0 @@
|
||||||
#!/usr/bin/env perl
|
|
||||||
our $target = `uname -s`;
|
|
||||||
$target =~ s/\r?\n$//;
|
|
||||||
|
|
||||||
# MSYS with MinGW gives us some other shit idk
|
|
||||||
if (index($target, "MINGW") != -1) {
|
|
||||||
$target = "Windows";
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach my $l (@ARGV) {
|
|
||||||
if ($l =~ /^--.+$/) {
|
|
||||||
}
|
|
||||||
elsif ($l =~ /^(.+)=(.+)$/) {
|
|
||||||
$ENV{$1} = $2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
our $prefix = "/usr/local";
|
|
||||||
our $cc = defined($ENV{CC}) ? $ENV{CC} : "*host*gcc";
|
|
||||||
our $cxx = defined($ENV{CXX}) ? $ENV{CXX} : "*host*g++";
|
|
||||||
our $ar = defined($ENV{AR}) ? $ENV{AR} : "*host*ar";
|
|
||||||
our $incdir = "-I include";
|
|
||||||
our $incdir2 = "";
|
|
||||||
our $cflags = "-fPIC -D_MILSKO -D_MILSKO_BUILD -fvisibility=hidden";
|
|
||||||
our $libdir = "";
|
|
||||||
our $ldflags = "";
|
|
||||||
our $math = "-lm";
|
|
||||||
our @shared = "-shared";
|
|
||||||
our @backends = ();
|
|
||||||
|
|
||||||
our $library_prefix = "lib";
|
|
||||||
our $library_suffix = ".so";
|
|
||||||
our $object_suffix = ".o";
|
|
||||||
our $executable_suffix = "";
|
|
||||||
|
|
||||||
our @library_targets = ();
|
|
||||||
our @examples_targets = ();
|
|
||||||
our %examples_libs = ();
|
|
||||||
|
|
||||||
our $cross = 0;
|
|
||||||
our $host = "";
|
|
||||||
|
|
||||||
require("./pl/utils.pl");
|
|
||||||
|
|
||||||
param_set("classic-theme", 0);
|
|
||||||
param_set("stb-image", 1);
|
|
||||||
param_set("opengl", 0);
|
|
||||||
param_set("vulkan", 0);
|
|
||||||
param_set("vulkan-string-helper", 1);
|
|
||||||
param_set("shared", 1);
|
|
||||||
param_set("static", 1);
|
|
||||||
param_set("examples", 1);
|
|
||||||
|
|
||||||
# (option that only makes sense on x11)
|
|
||||||
param_set("allow-sloppy-focus", 0);
|
|
||||||
|
|
||||||
my %features = (
|
|
||||||
"classic-theme" => "use classic theme",
|
|
||||||
"stb-image" => "use stb_image, instead use libjpeg/libpng",
|
|
||||||
"stb-truetype" => "use stb_truetype",
|
|
||||||
"freetype2" => "use FreeType2",
|
|
||||||
"gdi-text" => "(Windows only) use GDI Text",
|
|
||||||
"xrender" => "(X11 only) use XRender",
|
|
||||||
"opengl" => "build OpenGL widget",
|
|
||||||
"vulkan" => "build Vulkan widget",
|
|
||||||
"vulkan-string-helper" => "use Vulkan string helper",
|
|
||||||
"shared" => "build shared library",
|
|
||||||
"static" => "build static library",
|
|
||||||
"wayland" => "enable wayland backend",
|
|
||||||
"gnustep" => "use gnustep",
|
|
||||||
"dbus" => "use DBus on supported platform",
|
|
||||||
"allow-sloppy-focus" => "prevent the x11 backend from using XSetInputFocus to enforce click-to-focus"
|
|
||||||
);
|
|
||||||
my @features_keys = (
|
|
||||||
"1classic-theme", "1stb-image",
|
|
||||||
"1stb-truetype", "1freetype2", "1gdi-text",
|
|
||||||
"1opengl", "2xrender",
|
|
||||||
"1vulkan", "2vulkan-string-helper",
|
|
||||||
"1shared", "1static",
|
|
||||||
"1wayland", "1gnustep",
|
|
||||||
"1dbus"
|
|
||||||
);
|
|
||||||
|
|
||||||
sub def_platform {
|
|
||||||
if($target eq "Windows") {
|
|
||||||
param_set("freetype2", 0);
|
|
||||||
param_set("stb-truetype", 0);
|
|
||||||
} elsif($target ne "Darwin" and $target ne "ClassicMacOS" and $target ne "Haiku") {
|
|
||||||
param_set("freetype2", 1);
|
|
||||||
param_set("stb-truetype", 0);
|
|
||||||
} else {
|
|
||||||
param_set("freetype2", 0);
|
|
||||||
param_set("stb-truetype", 1);
|
|
||||||
}
|
|
||||||
if($target eq "Linux" || $target eq "FreeBSD") {
|
|
||||||
param_set("x11", 1);
|
|
||||||
param_set("xrender", 1);
|
|
||||||
if(!param_get("tiny")){
|
|
||||||
param_set("wayland", 1);
|
|
||||||
}
|
|
||||||
param_set("dbus", 1);
|
|
||||||
}
|
|
||||||
if($target eq "NetBSD" || $target eq "OpenBSD") {
|
|
||||||
param_set("x11", 1);
|
|
||||||
}
|
|
||||||
if($target eq "Windows") {
|
|
||||||
param_set("gdi-text", 1);
|
|
||||||
} else {
|
|
||||||
param_set("gdi-text", 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach my $l (@ARGV) {
|
|
||||||
if ($l =~ /^--target=(.+)$/) {
|
|
||||||
$target = $1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def_platform();
|
|
||||||
|
|
||||||
|
|
||||||
foreach my $l (@ARGV) {
|
|
||||||
if ($l =~ /^--with-([^=]+)=(.+)$/) {
|
|
||||||
param_set($1, $2);
|
|
||||||
}
|
|
||||||
elsif ($l =~ /^--(?:with|enable)-(.+)$/) {
|
|
||||||
param_set($1, 1);
|
|
||||||
}
|
|
||||||
elsif ($l =~ /^--(?:without|disable)-(.+)$/) {
|
|
||||||
param_set($1, 0);
|
|
||||||
}
|
|
||||||
elsif ($l =~ /^--host=(.+)$/) {
|
|
||||||
$host = $1 . "-";
|
|
||||||
}
|
|
||||||
elsif ($l =~ /^--cflags=(.+)$/) {
|
|
||||||
add_cflags($1);
|
|
||||||
}
|
|
||||||
elsif ($l eq "--cross") {
|
|
||||||
$cross = 1;
|
|
||||||
}
|
|
||||||
elsif ($l eq "--tiny") {
|
|
||||||
param_set("tiny",1);
|
|
||||||
}
|
|
||||||
elsif (($l eq "-h") or ($l eq "--help")) {
|
|
||||||
print("Milsko Toolkit Configuration Utility\n");
|
|
||||||
print("\n");
|
|
||||||
print("Usage: $0 [options]\n");
|
|
||||||
print("\n");
|
|
||||||
print("Options:\n");
|
|
||||||
print(" -h --help Display this help\n");
|
|
||||||
print(" --prefix=PREFIX Installation prefix\n");
|
|
||||||
print(" --host=TARGET Host for compiler/archiver\n");
|
|
||||||
print(" --target=TARGET Specify target\n");
|
|
||||||
print(" --cflags=CFLAGS Add cflags\n");
|
|
||||||
print(" --tiny Build smallest possible library\n");
|
|
||||||
print(" --cross Indicate cross compilation\n");
|
|
||||||
print("\n");
|
|
||||||
print("Features:\n");
|
|
||||||
print(" --enable-FEATURE Use FEATURE\n");
|
|
||||||
print(" --with-FEATURE Use FEATURE\n");
|
|
||||||
print(" --disable-FEATURE Do not use FEATURE\n");
|
|
||||||
print(" --without-FEATURE Do not use FEATURE\n");
|
|
||||||
|
|
||||||
foreach my $l (@features_keys) {
|
|
||||||
my $flag = (
|
|
||||||
(substr($l, 0, 1) eq '1')
|
|
||||||
? (param_get(substr($l, 1)) ? "--disable-" : "--enable-")
|
|
||||||
: (param_get(substr($l, 1)) ? "--without-" : "--with-")
|
|
||||||
) . substr($l, 1);
|
|
||||||
my $do = param_get(substr($l, 1)) ? "Do not " : "";
|
|
||||||
my $feat = $features{ substr($l, 1) };
|
|
||||||
if (not(param_get(substr($l, 1)))) {
|
|
||||||
$feat = uc(substr($feat, 0, 1)) . substr($feat, 1);
|
|
||||||
}
|
|
||||||
print(" $flag" . (" " x (32 - length($flag))) . "${do}${feat}\n");
|
|
||||||
}
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (-f "./pl/ostype/${target}.pl") {
|
|
||||||
require("./pl/ostype/${target}.pl");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
print(
|
|
||||||
"Perl file (pl/ostype/${target}.pl) was not found for your target. Please add one.\n"
|
|
||||||
);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
require("./pl/rules.pl");
|
|
||||||
|
|
||||||
print("Target : " . $target . "\n");
|
|
||||||
|
|
||||||
my @l = ();
|
|
||||||
foreach my $e (param_list()) {
|
|
||||||
if (not(param_get($e))) {
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
if (($e eq "vulkan-string-helper") and param_get("vulkan")) {
|
|
||||||
push(@l, $e);
|
|
||||||
}
|
|
||||||
elsif (($e eq "xrender") and ($backend eq "x11")) {
|
|
||||||
push(@l, $e);
|
|
||||||
}
|
|
||||||
elsif (not($e eq "vulkan-string-helper") and not($e eq "xrender")) {
|
|
||||||
push(@l, $e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
print("Enabled: " . join(" ", @l) . "\n");
|
|
||||||
|
|
||||||
$cc =~ s/\*host\*/$host/;
|
|
||||||
$cxx =~ s/\*host\*/$host/;
|
|
||||||
$ar =~ s/\*host\*/$host/;
|
|
||||||
|
|
||||||
open(OUT, ">", "Makefile");
|
|
||||||
print(OUT "PREFIX = ${prefix}\n");
|
|
||||||
print(OUT "AR = ${ar}\n");
|
|
||||||
print(OUT "CC = ${cc}\n");
|
|
||||||
print(OUT "CXX = ${cxx}\n");
|
|
||||||
print(OUT "INCDIR = ${incdir} ${incdir2}\n");
|
|
||||||
print(OUT "CFLAGS = ${cflags}\n");
|
|
||||||
print(OUT "LIBDIR = ${libdir}\n");
|
|
||||||
print(OUT "LDFLAGS = ${ldflags}\n");
|
|
||||||
print(OUT "LIBS = ${math} ${libs}\n");
|
|
||||||
print(OUT "MATH = ${math}\n");
|
|
||||||
print(OUT "SHARED = @{shared}\n");
|
|
||||||
print(OUT "\n");
|
|
||||||
print(OUT ".PHONY: all format clean distclean lib examples install\n");
|
|
||||||
print(OUT "\n");
|
|
||||||
print(OUT "all: lib examples\n");
|
|
||||||
print(OUT "\n");
|
|
||||||
print(OUT "install: lib\n");
|
|
||||||
print(OUT
|
|
||||||
" mkdir -p \$(DESTDIR)\$(PREFIX)/lib \$(DESTDIR)\$(PREFIX)/include\n");
|
|
||||||
print(OUT
|
|
||||||
" -cp src/${library_prefix}Mw${library_suffix} \$(DESTDIR)\$(PREFIX)/lib/\n"
|
|
||||||
);
|
|
||||||
print(OUT " -cp src/libMw.a \$(DESTDIR)\$(PREFIX)/lib/\n");
|
|
||||||
print(OUT " cp -rf include \$(DESTDIR)\$(PREFIX)/\n");
|
|
||||||
print(OUT "\n");
|
|
||||||
print(OUT "format:\n");
|
|
||||||
print(OUT
|
|
||||||
" clang-format --verbose -i `find tools src include examples \"(\" -name \"*.c\" -or -name \"*.cc\" -or -name \"*.h\" -or -name \"*.m\" \")\" -and -not -name \"*ttf.c\"`\n"
|
|
||||||
);
|
|
||||||
print(OUT
|
|
||||||
" perltidy -b -bext=\"/\" --paren-tightness=2 `find tools pl configure -name \"*.pl\"`\n"
|
|
||||||
);
|
|
||||||
print(OUT "\n");
|
|
||||||
print(OUT "lib:");
|
|
||||||
|
|
||||||
if (param_get("shared")) {
|
|
||||||
print(OUT " src/${library_prefix}Mw${library_suffix}");
|
|
||||||
}
|
|
||||||
if (param_get("static")) {
|
|
||||||
print(OUT " src/libMw.a");
|
|
||||||
}
|
|
||||||
print(OUT "\n");
|
|
||||||
print(OUT "\n");
|
|
||||||
if (param_get("shared")) {
|
|
||||||
my $linker = "CC";
|
|
||||||
if (grep(/^haiku$/, @backends)) {
|
|
||||||
$linker = "CXX";
|
|
||||||
}
|
|
||||||
print( OUT "src/${library_prefix}Mw${library_suffix}: "
|
|
||||||
. join(" ", @library_targets)
|
|
||||||
. "\n");
|
|
||||||
print(OUT
|
|
||||||
" \$($linker) \$(SHARED) \$(LDFLAGS\) \$(LIBDIR) -o src/${library_prefix}Mw${library_suffix} "
|
|
||||||
. join(" ", @library_targets)
|
|
||||||
. " \$(LIBS)\n");
|
|
||||||
print(OUT "\n");
|
|
||||||
}
|
|
||||||
if (param_get("static")) {
|
|
||||||
print(OUT "src/libMw.a: " . join(" ", @library_targets) . "\n");
|
|
||||||
print(OUT " \$(AR) rcs src/libMw.a " . join(" ", @library_targets) . "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach my $l (@library_targets) {
|
|
||||||
my $warn = "-Wall -Wextra -Wno-sign-compare -Wno-unused-value";
|
|
||||||
my $s = $l;
|
|
||||||
my $compiler = "CC";
|
|
||||||
my $o = $object_suffix;
|
|
||||||
$o =~ s/\./\\\./g;
|
|
||||||
|
|
||||||
if ($l =~ /cocoa/) {
|
|
||||||
$s =~ s/$o$/.m/;
|
|
||||||
}
|
|
||||||
elsif ($l =~ /haiku/) {
|
|
||||||
$s =~ s/$o$/.cc/;
|
|
||||||
$compiler = "CXX";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$s =~ s/$o$/.c/;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($l =~ /^external\//) {
|
|
||||||
$warn = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
print(OUT "${l}: ${s}\n");
|
|
||||||
print(OUT " \$($compiler) $warn \$\(INCDIR) \$(CFLAGS\) -c -o ${l} ${s}\n");
|
|
||||||
}
|
|
||||||
print(OUT "\n");
|
|
||||||
print(OUT "\n");
|
|
||||||
if (param_get("examples")) {
|
|
||||||
print(OUT "examples: " . join(" ", @examples_targets) . "\n");
|
|
||||||
print(OUT "\n");
|
|
||||||
foreach my $l (@examples_targets) {
|
|
||||||
my $libs = "";
|
|
||||||
my $s = $l;
|
|
||||||
my $o = $executable_suffix;
|
|
||||||
$o =~ s/\./\\\./g;
|
|
||||||
$s =~ s/$o$//;
|
|
||||||
|
|
||||||
if (defined($examples_libs{$l})) {
|
|
||||||
$libs = $examples_libs{$l};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (param_get("shared")) {
|
|
||||||
print(OUT
|
|
||||||
"${l}: ${s}${object_suffix} src/${library_prefix}Mw${library_suffix}\n"
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
print(OUT
|
|
||||||
"${l}: ${s}${object_suffix} src/${library_prefix}Mw.a\n"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (grep(/^cocoa$/, @backends)) {
|
|
||||||
print(OUT
|
|
||||||
" \$(CC) -L./src \$\(LIBDIR) -o ${l} ${s}${object_suffix} -lMw ${math} ${libs}\n"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
print(OUT
|
|
||||||
" \$(CC) -L src -Wl,-R./src \$\(LIBDIR) -o ${l} ${s}${object_suffix} -lMw ${math} ${libs}\n"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if($target eq "ClassicMacOS") {
|
|
||||||
print(OUT
|
|
||||||
" ".$ENV{RETRO68_TOOLCHAIN_PATH}."/bin/MakePEF ${l} -o ${s}.pef\n");
|
|
||||||
print(OUT
|
|
||||||
" Rez -I ".$ENV{RETRO68_TOOLCHAIN_PATH}."/RIncludes ".$ENV{RETRO68_TOOLCHAIN_PATH}."/RIncludes/Retro68APPL.r -DCFRAG_NAME=\"example\" --data ${l}.pef --cc ${l}.dsk -t APPL\n"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
print(OUT "${s}${object_suffix}: ${s}.c\n");
|
|
||||||
print(OUT
|
|
||||||
" \$(CC) -c \$\(INCDIR) -o ${s}${object_suffix} ${s}.c -lMw ${math}\n"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
print(OUT "\n");
|
|
||||||
print(OUT "clean:\n");
|
|
||||||
print(OUT
|
|
||||||
" rm -f */*.o */*/*.o */*/*/*.o */*.exe */*/*.exe */*/*/*.exe src/*.so src/*.dll src/*.dylib src/*.a "
|
|
||||||
. join(" ", @examples_targets)
|
|
||||||
. "\n");
|
|
||||||
print(OUT "\n");
|
|
||||||
print(OUT "distclean: clean\n");
|
|
||||||
print(OUT " rm -f Makefile\n");
|
|
||||||
close(OUT);
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
# Backend dev
|
|
||||||
|
|
||||||
The basic process of creating a new Milsko backend is
|
|
||||||
|
|
||||||
- Adding a new include header into `include/Mw/LowLevel`. It must include;
|
|
||||||
- `struct _MwLLBackendName`: Any details about a window or a subwidget
|
|
||||||
- `struct _MwLLBackendNameColor`: An 8-bit RGB Color. You'll probably never impl this, this is for platforms like X11/GDI where they have a secondary color representation that can be stored.
|
|
||||||
- `struct _MwLLBackendNamePixmap`: Self-explanatory. This is also used for the soft gradients in the modern theme.
|
|
||||||
- `MwLLBackendNameCallInitImpl(void)` called by `MwLibraryInit` to address and platform globals.
|
|
||||||
- Note that all of those structs are actually unions. They should all start with their `MwLLCommon...` equivalants.
|
|
||||||
- Fill out `Mw/LowLevel.h` appopriately, adding an include to your new file and the structs in the appropriate unions. These need to be guarded by a `USE_BACKENDNAME` macro which you'll define later when you modify the build system.
|
|
||||||
- Creating a new impl file in `src/backend`
|
|
||||||
- Backends actually return a table of function pointers that you have to implement with static functions. Your file should end with `#include "call.c"` and then `CALL(BackendName);`, and somewhere you should have the impl for `MwLLBackendNameCallInitImpl(void)`.
|
|
||||||
- Prefer to keep the backend file to one file if you can, though obviously exceptions like the Wayland backend exist because it's simply too complex to sanely stuff into one file.
|
|
||||||
- Add `MwLLBackendNameCallInitImpl` to the `MwLibraryInit` impl in `src/core.c`.
|
|
||||||
- Add a new enum variation to `MwLLBackends` in `Mw/Include/LowLevel.h`; your impl of `MwLLCreateImpl` will set `common.type` to this so the user can check which backend they're on (important for platforms with multiple supported backends).
|
|
||||||
- Either
|
|
||||||
- a.) Modify `CMakeLists.txt` for your platform.
|
|
||||||
- b.) Add a new perl file in `pl/ostype` that `./configure` can reference, and modify `pl/rules.pl`; If you don't know how to use perl it's fine, just copy a file like the `Linux.pl` or `Windows.pl`, the functions you'll have to change for your platform are self explanatory. Ensure it ends with `1;`.
|
|
||||||
- c.) Both.
|
|
||||||
- Both are recommended, but some platforms like Classic Mac OS can't be used with the `./configure` script, and that's fine.
|
|
||||||
|
|
||||||
The functions you'll have to impl are too many to list here so you should start by just copying `x11.c` and then replacing all the function impls with your own.
|
|
||||||
|
|
||||||
\*\*Pay attention to some of these functions' comments in LowLevel.h as they might not be as you expect; for example, `MwLLSetDarkThemeImpl` is for setting the accent color to dark theme on platforms like modern Windows (dark theme itself is set with `MwSetInteger(handle, MwNdarktheme, 1)`).
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
# Writing a new widget
|
|
||||||
@warning This is mainly for developers
|
|
||||||
|
|
||||||
1. Create new file in src/widget with lower case
|
|
||||||
2. Create new header in include/Mw/Widget with pascal case
|
|
||||||
3. Add the header include to include/Mw/Milsko.h, if new widget does not require some extension (like OpenGL and Vulkan)
|
|
||||||
4. See another widget for example
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
# Tiers
|
|
||||||
|
|
||||||
Ports of Milsko are grouped into three "tiers" in terms of their support.
|
|
||||||
|
|
||||||
- **Tier 1**: Before every new release of Milsko, these platforms will be tested to make sure they have full support, and the CI will test them.
|
|
||||||
- **Tier 2**: These might be outdated or not updated in awhile, they might only compile under a specific version/commit of Milsko. Authors of these backends will be made aware of these updates.
|
|
||||||
- **Tier 3**: These are outright unfinished. Only use these if you're a developer.
|
|
||||||
|
|
||||||
Currently, the Tier 1 backends are:
|
|
||||||
|
|
||||||
- Windows 9x+/NT 4.0+
|
|
||||||
- Any Unix/Linux system that supports X11 or Wayland.
|
|
||||||
|
|
||||||
There are currently no Tier 2 backends.
|
|
||||||
|
|
||||||
Tier 3 backends are:
|
|
||||||
|
|
||||||
- Mac OS X 10.4+ with Cocoa
|
|
||||||
- Mac OS 7-9, PowerPC (68k support not planned).
|
|
||||||
- Haiku
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue