зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1508346 - Add class ListObject. r=jandem
Differential Revision: https://phabricator.services.mozilla.com/D12326 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
f5eda35a8d
Коммит
de94cffe43
|
@ -173,7 +173,7 @@ inline static MOZ_MUST_USE bool
|
|||
SetNewList(JSContext* cx, HandleNativeObject unwrappedContainer, uint32_t slot)
|
||||
{
|
||||
AutoRealm ar(cx, unwrappedContainer);
|
||||
NativeObject* list = NewList(cx);
|
||||
ListObject* list = ListObject::create(cx);
|
||||
if (!list) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1488,8 +1488,8 @@ ReadableStreamCloseInternal(JSContext* cx, Handle<ReadableStream*> unwrappedStre
|
|||
|
||||
// Step a: Repeat for each readRequest that is an element of
|
||||
// reader.[[readRequests]],
|
||||
RootedNativeObject unwrappedReadRequests(cx, unwrappedReader->requests());
|
||||
uint32_t len = unwrappedReadRequests->getDenseInitializedLength();
|
||||
Rooted<ListObject*> unwrappedReadRequests(cx, unwrappedReader->requests());
|
||||
uint32_t len = unwrappedReadRequests->length();
|
||||
RootedObject readRequest(cx);
|
||||
RootedObject resultObj(cx);
|
||||
RootedValue resultVal(cx);
|
||||
|
@ -1497,7 +1497,7 @@ ReadableStreamCloseInternal(JSContext* cx, Handle<ReadableStream*> unwrappedStre
|
|||
// Step i: Resolve readRequest.[[promise]] with
|
||||
// ! ReadableStreamCreateReadResult(undefined, true,
|
||||
// readRequest.[[forAuthorCode]]).
|
||||
readRequest = &unwrappedReadRequests->getDenseElement(i).toObject();
|
||||
readRequest = &unwrappedReadRequests->getAs<JSObject>(i);
|
||||
if (!cx->compartment()->wrap(cx, &readRequest)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1615,13 +1615,13 @@ ReadableStreamErrorInternal(JSContext* cx, Handle<ReadableStream*> unwrappedStre
|
|||
// Steps 7,8: (Identical in our implementation.)
|
||||
// Step a: Repeat for each readRequest that is an element of
|
||||
// reader.[[readRequests]],
|
||||
RootedNativeObject unwrappedReadRequests(cx, unwrappedReader->requests());
|
||||
Rooted<ListObject*> unwrappedReadRequests(cx, unwrappedReader->requests());
|
||||
RootedObject readRequest(cx);
|
||||
RootedValue val(cx);
|
||||
uint32_t len = unwrappedReadRequests->getDenseInitializedLength();
|
||||
uint32_t len = unwrappedReadRequests->length();
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
// Step i: Reject readRequest.[[promise]] with e.
|
||||
val = unwrappedReadRequests->getDenseElement(i);
|
||||
val = unwrappedReadRequests->get(i);
|
||||
readRequest = &val.toObject();
|
||||
|
||||
// Responses have to be created in the compartment from which the
|
||||
|
@ -1706,8 +1706,8 @@ ReadableStreamFulfillReadOrReadIntoRequest(JSContext* cx,
|
|||
// Step 3: Remove readIntoRequest from reader.[[readIntoRequests]], shifting
|
||||
// all other elements downward (so that the second becomes the first,
|
||||
// and so on).
|
||||
RootedNativeObject unwrappedReadIntoRequests(cx, unwrappedReader->requests());
|
||||
RootedObject readIntoRequest(cx, ShiftFromList<JSObject>(cx, unwrappedReadIntoRequests));
|
||||
Rooted<ListObject*> unwrappedReadIntoRequests(cx, unwrappedReader->requests());
|
||||
RootedObject readIntoRequest(cx, &unwrappedReadIntoRequests->popFirstAs<JSObject>(cx));
|
||||
MOZ_ASSERT(readIntoRequest);
|
||||
if (!cx->compartment()->wrap(cx, &readIntoRequest)) {
|
||||
return false;
|
||||
|
@ -1746,7 +1746,7 @@ ReadableStreamGetNumReadRequests(ReadableStream* stream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
return reader->requests()->getDenseInitializedLength();
|
||||
return reader->requests()->length();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1983,9 +1983,8 @@ ReadableStreamDefaultReader_releaseLock(JSContext* cx, unsigned argc, Value* vp)
|
|||
// Step 3: If this.[[readRequests]] is not empty, throw a TypeError exception.
|
||||
Value val = reader->getFixedSlot(ReadableStreamReader::Slot_Requests);
|
||||
if (!val.isUndefined()) {
|
||||
NativeObject* readRequests = &val.toObject().as<NativeObject>();
|
||||
uint32_t len = readRequests->getDenseInitializedLength();
|
||||
if (len != 0) {
|
||||
ListObject* readRequests = &val.toObject().as<ListObject>();
|
||||
if (readRequests->length() != 0) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_READABLESTREAMREADER_NOT_EMPTY,
|
||||
"releaseLock");
|
||||
|
@ -2539,15 +2538,15 @@ ReadableStreamControllerCancelSteps(JSContext* cx,
|
|||
|
||||
// Step 1 of 3.10.5.1: If this.[[pendingPullIntos]] is not empty,
|
||||
if (!unwrappedController->is<ReadableStreamDefaultController>()) {
|
||||
RootedNativeObject unwrappedPendingPullIntos(cx,
|
||||
Rooted<ListObject*> unwrappedPendingPullIntos(cx,
|
||||
unwrappedController->as<ReadableByteStreamController>().pendingPullIntos());
|
||||
|
||||
if (unwrappedPendingPullIntos->getDenseInitializedLength() != 0) {
|
||||
if (unwrappedPendingPullIntos->length() != 0) {
|
||||
// Step a: Let firstDescriptor be the first element of
|
||||
// this.[[pendingPullIntos]].
|
||||
PullIntoDescriptor* unwrappedDescriptor =
|
||||
UnwrapAndDowncastObject<PullIntoDescriptor>(
|
||||
cx, PeekList<JSObject>(unwrappedPendingPullIntos));
|
||||
cx, &unwrappedPendingPullIntos->get(0).toObject());
|
||||
if (!unwrappedDescriptor) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -2631,13 +2630,13 @@ ReadableStreamDefaultControllerPullSteps(JSContext* cx,
|
|||
Rooted<ReadableStream*> unwrappedStream(cx, unwrappedController->stream());
|
||||
|
||||
// Step 2: If this.[[queue]] is not empty,
|
||||
RootedNativeObject unwrappedQueue(cx);
|
||||
Rooted<ListObject*> unwrappedQueue(cx);
|
||||
RootedValue val(cx, unwrappedController->getFixedSlot(StreamController::Slot_Queue));
|
||||
if (val.isObject()) {
|
||||
unwrappedQueue = &val.toObject().as<NativeObject>();
|
||||
unwrappedQueue = &val.toObject().as<ListObject>();
|
||||
}
|
||||
|
||||
if (unwrappedQueue && unwrappedQueue->getDenseInitializedLength() != 0) {
|
||||
if (unwrappedQueue && unwrappedQueue->length() != 0) {
|
||||
// Step a: Let chunk be ! DequeueValue(this.[[queue]]).
|
||||
RootedValue chunk(cx);
|
||||
if (!DequeueValue(cx, unwrappedController, &chunk)) {
|
||||
|
@ -2646,9 +2645,7 @@ ReadableStreamDefaultControllerPullSteps(JSContext* cx,
|
|||
|
||||
// Step b: If this.[[closeRequested]] is true and this.[[queue]] is empty,
|
||||
// perform ! ReadableStreamClose(stream).
|
||||
if (unwrappedController->closeRequested() &&
|
||||
unwrappedQueue->getDenseInitializedLength() == 0)
|
||||
{
|
||||
if (unwrappedController->closeRequested() && unwrappedQueue->length() == 0) {
|
||||
if (!ReadableStreamCloseInternal(cx, unwrappedStream)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -2926,8 +2923,8 @@ ReadableStreamDefaultControllerClose(JSContext* cx,
|
|||
|
||||
// Step 5: If controller.[[queue]] is empty, perform
|
||||
// ! ReadableStreamClose(stream).
|
||||
RootedNativeObject unwrappedQueue(cx, unwrappedController->queue());
|
||||
if (unwrappedQueue->getDenseInitializedLength() == 0) {
|
||||
Rooted<ListObject*> unwrappedQueue(cx, unwrappedController->queue());
|
||||
if (unwrappedQueue->length() == 0) {
|
||||
return ReadableStreamCloseInternal(cx, unwrappedStream);
|
||||
}
|
||||
|
||||
|
@ -3520,10 +3517,10 @@ ReadableByteStreamControllerPullSteps(JSContext* cx,
|
|||
// Step 3.c: Remove entry from this.[[queue]], shifting all other
|
||||
// elements downward (so that the second becomes the
|
||||
// first, and so on).
|
||||
RootedNativeObject unwrappedQueue(cx, unwrappedController->queue());
|
||||
Rooted<ListObject*> unwrappedQueue(cx, unwrappedController->queue());
|
||||
Rooted<ByteStreamChunk*> unwrappedEntry(cx,
|
||||
UnwrapAndDowncastObject<ByteStreamChunk>(
|
||||
cx, ShiftFromList<JSObject>(cx, unwrappedQueue)));
|
||||
cx, &unwrappedQueue->popFirstAs<JSObject>(cx)));
|
||||
if (!unwrappedEntry) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -3718,13 +3715,13 @@ ReadableByteStreamControllerClose(JSContext* cx,
|
|||
}
|
||||
|
||||
// Step 5: If controller.[[pendingPullIntos]] is not empty,
|
||||
RootedNativeObject unwrappedPendingPullIntos(cx, unwrappedController->pendingPullIntos());
|
||||
if (unwrappedPendingPullIntos->getDenseInitializedLength() != 0) {
|
||||
Rooted<ListObject*> unwrappedPendingPullIntos(cx, unwrappedController->pendingPullIntos());
|
||||
if (unwrappedPendingPullIntos->length() != 0) {
|
||||
// Step a: Let firstPendingPullInto be the first element of
|
||||
// controller.[[pendingPullIntos]].
|
||||
Rooted<PullIntoDescriptor*> unwrappedFirstPendingPullInto(cx,
|
||||
UnwrapAndDowncastObject<PullIntoDescriptor>(
|
||||
cx, PeekList<JSObject>(unwrappedPendingPullIntos)));
|
||||
cx, &unwrappedPendingPullIntos->get(0).toObject()));
|
||||
if (!unwrappedFirstPendingPullInto) {
|
||||
return false;
|
||||
}
|
||||
|
@ -3990,13 +3987,13 @@ DequeueValue(JSContext* cx, Handle<ReadableStreamController*> unwrappedContainer
|
|||
// Step 1: Assert: container has [[queue]] and [[queueTotalSize]] internal
|
||||
// slots (implicit).
|
||||
// Step 2: Assert: queue is not empty.
|
||||
RootedNativeObject unwrappedQueue(cx, unwrappedContainer->queue());
|
||||
MOZ_ASSERT(unwrappedQueue->getDenseInitializedLength() > 0);
|
||||
Rooted<ListObject*> unwrappedQueue(cx, unwrappedContainer->queue());
|
||||
MOZ_ASSERT(unwrappedQueue->length() > 0);
|
||||
|
||||
// Step 3. Let pair be the first element of queue.
|
||||
// Step 4. Remove pair from queue, shifting all other elements downward
|
||||
// (so that the second becomes the first, and so on).
|
||||
Rooted<QueueEntry*> unwrappedPair(cx, ShiftFromList<QueueEntry>(cx, unwrappedQueue));
|
||||
Rooted<QueueEntry*> unwrappedPair(cx, &unwrappedQueue->popFirstAs<QueueEntry>(cx));
|
||||
MOZ_ASSERT(unwrappedPair);
|
||||
|
||||
// Step 5: Set container.[[queueTotalSize]] to
|
||||
|
@ -4053,7 +4050,7 @@ EnqueueValueWithSize(JSContext* cx,
|
|||
// element of container.[[queue]].
|
||||
{
|
||||
AutoRealm ar(cx, unwrappedContainer);
|
||||
RootedNativeObject queue(cx, unwrappedContainer->queue());
|
||||
Rooted<ListObject*> queue(cx, unwrappedContainer->queue());
|
||||
RootedValue wrappedVal(cx, value);
|
||||
if (!cx->compartment()->wrap(cx, &wrappedVal)) {
|
||||
return false;
|
||||
|
@ -4064,7 +4061,7 @@ EnqueueValueWithSize(JSContext* cx,
|
|||
return false;
|
||||
}
|
||||
RootedValue val(cx, ObjectValue(*entry));
|
||||
if (!AppendToList(cx, queue, val)) {
|
||||
if (!queue->append(cx, val)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -4110,15 +4107,15 @@ AppendToListAtSlot(JSContext* cx,
|
|||
uint32_t slot,
|
||||
HandleObject obj)
|
||||
{
|
||||
RootedNativeObject list(cx,
|
||||
&unwrappedContainer->getFixedSlot(slot).toObject().as<NativeObject>());
|
||||
Rooted<ListObject*> list(cx,
|
||||
&unwrappedContainer->getFixedSlot(slot).toObject().as<ListObject>());
|
||||
|
||||
AutoRealm ar(cx, list);
|
||||
RootedValue val(cx, ObjectValue(*obj));
|
||||
if (!cx->compartment()->wrap(cx, &val)) {
|
||||
return false;
|
||||
}
|
||||
return AppendToList(cx, list, val);
|
||||
return list->append(cx, val);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
|
||||
#include "js/Stream.h"
|
||||
#include "builtin/Promise.h"
|
||||
#include "vm/List.h"
|
||||
#include "vm/NativeObject.h"
|
||||
|
||||
|
||||
namespace js {
|
||||
|
||||
class ReadableStreamReader;
|
||||
|
@ -175,8 +175,8 @@ class ReadableStreamReader : public NativeObject
|
|||
setFixedSlot(Slot_ForAuthorCode, BooleanValue(value == ForAuthorCodeBool::Yes));
|
||||
}
|
||||
|
||||
NativeObject* requests() const {
|
||||
return &getFixedSlot(Slot_Requests).toObject().as<NativeObject>();
|
||||
ListObject* requests() const {
|
||||
return &getFixedSlot(Slot_Requests).toObject().as<ListObject>();
|
||||
}
|
||||
void clearRequests() { setFixedSlot(Slot_Requests, UndefinedValue()); }
|
||||
|
||||
|
@ -219,7 +219,7 @@ class StreamController : public NativeObject
|
|||
SlotCount
|
||||
};
|
||||
|
||||
NativeObject* queue() const { return &getFixedSlot(Slot_Queue).toObject().as<NativeObject>(); }
|
||||
ListObject* queue() const { return &getFixedSlot(Slot_Queue).toObject().as<ListObject>(); }
|
||||
double queueTotalSize() const { return getFixedSlot(Slot_TotalSize).toNumber(); }
|
||||
void setQueueTotalSize(double size) { setFixedSlot(Slot_TotalSize, NumberValue(size)); }
|
||||
};
|
||||
|
@ -349,8 +349,8 @@ class ReadableByteStreamController : public ReadableStreamController
|
|||
|
||||
Value byobRequest() const { return getFixedSlot(Slot_BYOBRequest); }
|
||||
void clearBYOBRequest() { setFixedSlot(Slot_BYOBRequest, JS::UndefinedValue()); }
|
||||
NativeObject* pendingPullIntos() const {
|
||||
return &getFixedSlot(Slot_PendingPullIntos).toObject().as<NativeObject>();
|
||||
ListObject* pendingPullIntos() const {
|
||||
return &getFixedSlot(Slot_PendingPullIntos).toObject().as<ListObject>();
|
||||
}
|
||||
Value autoAllocateChunkSize() const { return getFixedSlot(Slot_AutoAllocateSize); }
|
||||
void setAutoAllocateChunkSize(const Value & size) {
|
||||
|
|
|
@ -275,6 +275,7 @@ UNIFIED_SOURCES += [
|
|||
'vm/JSONParser.cpp',
|
||||
'vm/JSONPrinter.cpp',
|
||||
'vm/JSScript.cpp',
|
||||
'vm/List.cpp',
|
||||
'vm/MemoryMetrics.cpp',
|
||||
'vm/NativeObject.cpp',
|
||||
'vm/ObjectGroup.cpp',
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include "vm/JSContext-inl.h"
|
||||
#include "vm/JSObject-inl.h"
|
||||
#include "vm/List-inl.h"
|
||||
#include "vm/NativeObject-inl.h"
|
||||
|
||||
using namespace js;
|
||||
|
||||
|
@ -339,17 +338,17 @@ AsyncGeneratorObject::enqueueRequest(JSContext* cx, Handle<AsyncGeneratorObject*
|
|||
return true;
|
||||
}
|
||||
|
||||
RootedNativeObject queue(cx, NewList(cx));
|
||||
Rooted<ListObject*> queue(cx, ListObject::create(cx));
|
||||
if (!queue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedValue requestVal(cx, ObjectValue(*asyncGenObj->singleQueueRequest()));
|
||||
if (!AppendToList(cx, queue, requestVal)) {
|
||||
if (!queue->append(cx, requestVal)) {
|
||||
return false;
|
||||
}
|
||||
requestVal = ObjectValue(*request);
|
||||
if (!AppendToList(cx, queue, requestVal)) {
|
||||
if (!queue->append(cx, requestVal)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -357,9 +356,9 @@ AsyncGeneratorObject::enqueueRequest(JSContext* cx, Handle<AsyncGeneratorObject*
|
|||
return true;
|
||||
}
|
||||
|
||||
RootedNativeObject queue(cx, asyncGenObj->queue());
|
||||
Rooted<ListObject*> queue(cx, asyncGenObj->queue());
|
||||
RootedValue requestVal(cx, ObjectValue(*request));
|
||||
return AppendToList(cx, queue, requestVal);
|
||||
return queue->append(cx, requestVal);
|
||||
}
|
||||
|
||||
/* static */ AsyncGeneratorRequest*
|
||||
|
@ -371,8 +370,8 @@ AsyncGeneratorObject::dequeueRequest(JSContext* cx, Handle<AsyncGeneratorObject*
|
|||
return request;
|
||||
}
|
||||
|
||||
RootedNativeObject queue(cx, asyncGenObj->queue());
|
||||
return ShiftFromList<AsyncGeneratorRequest>(cx, queue);
|
||||
Rooted<ListObject*> queue(cx, asyncGenObj->queue());
|
||||
return &queue->popFirstAs<AsyncGeneratorRequest>(cx);
|
||||
}
|
||||
|
||||
/* static */ AsyncGeneratorRequest*
|
||||
|
@ -382,7 +381,7 @@ AsyncGeneratorObject::peekRequest(Handle<AsyncGeneratorObject*> asyncGenObj)
|
|||
return asyncGenObj->singleQueueRequest();
|
||||
}
|
||||
|
||||
return PeekList<AsyncGeneratorRequest>(asyncGenObj->queue());
|
||||
return &asyncGenObj->queue()->getAs<AsyncGeneratorRequest>(0);
|
||||
}
|
||||
|
||||
const Class AsyncGeneratorRequest::class_ = {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "vm/GeneratorObject.h"
|
||||
#include "vm/JSContext.h"
|
||||
#include "vm/JSObject.h"
|
||||
#include "vm/List.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
|
@ -214,10 +215,10 @@ class AsyncGeneratorObject : public NativeObject
|
|||
return &getFixedSlot(Slot_QueueOrRequest).toObject().as<AsyncGeneratorRequest>();
|
||||
}
|
||||
|
||||
NativeObject* queue() const {
|
||||
return &getFixedSlot(Slot_QueueOrRequest).toObject().as<NativeObject>();
|
||||
ListObject* queue() const {
|
||||
return &getFixedSlot(Slot_QueueOrRequest).toObject().as<ListObject>();
|
||||
}
|
||||
void setQueue(JSObject* queue_) {
|
||||
void setQueue(ListObject* queue_) {
|
||||
setFixedSlot(Slot_QueueOrRequest, ObjectValue(*queue_));
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#ifndef vm_List_inl_h
|
||||
#define vm_List_inl_h
|
||||
|
||||
#include "vm/List.h"
|
||||
|
||||
#include "gc/Rooting.h"
|
||||
#include "vm/JSContext.h"
|
||||
#include "vm/NativeObject.h"
|
||||
|
@ -14,55 +16,47 @@
|
|||
#include "vm/JSObject-inl.h"
|
||||
#include "vm/NativeObject-inl.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
inline MOZ_MUST_USE NativeObject*
|
||||
NewList(JSContext* cx)
|
||||
inline /* static */ js::ListObject*
|
||||
js::ListObject::create(JSContext* cx)
|
||||
{
|
||||
return NewObjectWithNullTaggedProto<PlainObject>(cx);
|
||||
return NewObjectWithNullTaggedProto<ListObject>(cx);
|
||||
}
|
||||
|
||||
inline MOZ_MUST_USE bool
|
||||
AppendToList(JSContext* cx, HandleNativeObject list, HandleValue value)
|
||||
inline bool
|
||||
js::ListObject::append(JSContext* cx, HandleValue value)
|
||||
{
|
||||
uint32_t length = list->getDenseInitializedLength();
|
||||
uint32_t len = length();
|
||||
|
||||
if (!list->ensureElements(cx, length + 1)) {
|
||||
if (!ensureElements(cx, len + 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
list->ensureDenseInitializedLength(cx, length, 1);
|
||||
list->setDenseElementWithType(cx, length, value);
|
||||
|
||||
ensureDenseInitializedLength(cx, len, 1);
|
||||
setDenseElementWithType(cx, len, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline MOZ_MUST_USE T*
|
||||
PeekList(NativeObject* list)
|
||||
inline JS::Value
|
||||
js::ListObject::popFirst(JSContext* cx)
|
||||
{
|
||||
MOZ_ASSERT(list->getDenseInitializedLength() > 0);
|
||||
return &list->getDenseElement(0).toObject().as<T>();
|
||||
}
|
||||
uint32_t len = length();
|
||||
MOZ_ASSERT(len > 0);
|
||||
|
||||
template<class T>
|
||||
inline MOZ_MUST_USE T*
|
||||
ShiftFromList(JSContext* cx, HandleNativeObject list)
|
||||
{
|
||||
uint32_t length = list->getDenseInitializedLength();
|
||||
MOZ_ASSERT(length > 0);
|
||||
|
||||
Rooted<T*> entry(cx, &list->getDenseElement(0).toObject().as<T>());
|
||||
if (!list->tryShiftDenseElements(1)) {
|
||||
list->moveDenseElements(0, 1, length - 1);
|
||||
list->setDenseInitializedLength(length - 1);
|
||||
list->shrinkElements(cx, length - 1);
|
||||
Value entry = get(0);
|
||||
if (!tryShiftDenseElements(1)) {
|
||||
moveDenseElements(0, 1, len - 1);
|
||||
setDenseInitializedLength(len - 1);
|
||||
shrinkElements(cx, len - 1);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(list->getDenseInitializedLength() == length - 1);
|
||||
MOZ_ASSERT(length() == len - 1);
|
||||
return entry;
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
template <class T>
|
||||
inline T&
|
||||
js::ListObject::popFirstAs(JSContext* cx) {
|
||||
return popFirst(cx).toObject().as<T>();
|
||||
}
|
||||
|
||||
#endif /* vm_List_inl_h */
|
||||
#endif // vm_List_inl_h
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
#include "vm/List-inl.h"
|
||||
|
||||
using namespace js;
|
||||
|
||||
const Class ListObject::class_ = {
|
||||
"List"
|
||||
};
|
|
@ -0,0 +1,69 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef vm_List_h
|
||||
#define vm_List_h
|
||||
|
||||
#include "NamespaceImports.h"
|
||||
#include "js/Value.h"
|
||||
#include "vm/NativeObject.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
/**
|
||||
* The List specification type, ECMA-262 6.2.1.
|
||||
* <https://tc39.github.io/ecma262/#sec-list-and-record-specification-type>
|
||||
*
|
||||
* Lists are simple mutable sequences of values. Many standards use them.
|
||||
* Abstractly, they're not objects; they don't have properties or prototypes;
|
||||
* they're for internal specification use only. ListObject is our most direct
|
||||
* implementation of a List: store the values in the slots of a JSObject.
|
||||
*
|
||||
* We often implement Lists in other ways. For example, builtin/Utilities.js
|
||||
* contains a completely unrelated List constructor that's used in self-hosted
|
||||
* code. And AsyncGeneratorObject optimizes away the ListObject in the common
|
||||
* case where its internal queue never holds more than one element.
|
||||
*
|
||||
* ListObjects must not be exposed to content scripts.
|
||||
*/
|
||||
class ListObject : public NativeObject {
|
||||
public:
|
||||
static const Class class_;
|
||||
|
||||
inline static MOZ_MUST_USE ListObject* create(JSContext* cx);
|
||||
|
||||
uint32_t length() const { return getDenseInitializedLength(); }
|
||||
|
||||
const Value& get(uint32_t index) const { return getDenseElement(index); }
|
||||
|
||||
template <class T>
|
||||
T& getAs(uint32_t index) const { return get(index).toObject().as<T>(); }
|
||||
|
||||
/**
|
||||
* Add an element to the end of the list. Returns false on OOM.
|
||||
*/
|
||||
inline MOZ_MUST_USE bool append(JSContext* cx, HandleValue value);
|
||||
|
||||
/**
|
||||
* Remove and return the first element of the list.
|
||||
*
|
||||
* Precondition: This list is not empty.
|
||||
*/
|
||||
inline JS::Value popFirst(JSContext* cx);
|
||||
|
||||
/**
|
||||
* Remove and return the first element of the list.
|
||||
*
|
||||
* Precondition: This list is not empty, and the first element
|
||||
* is an object of class T.
|
||||
*/
|
||||
template <class T>
|
||||
inline T& popFirstAs(JSContext* cx);
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif // vm_List_h
|
Загрузка…
Ссылка в новой задаче