mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1129313 - Part 2: self-host MapIteratorObject#next(). r=jandem
This commit is contained in:
parent
9441be443e
commit
ba57452f87
@ -624,21 +624,13 @@ function ArrayIncludes(searchElement, fromIndex = 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#define ARRAY_ITERATOR_SLOT_ITERATED_OBJECT 0
|
||||
#define ARRAY_ITERATOR_SLOT_NEXT_INDEX 1
|
||||
#define ARRAY_ITERATOR_SLOT_ITEM_KIND 2
|
||||
|
||||
#define ITEM_KIND_VALUE 0
|
||||
#define ITEM_KIND_KEY_AND_VALUE 1
|
||||
#define ITEM_KIND_KEY 2
|
||||
|
||||
// ES6 draft specification, section 22.1.5.1, version 2013-09-05.
|
||||
function CreateArrayIteratorAt(obj, kind, n) {
|
||||
var iteratedObject = ToObject(obj);
|
||||
var iterator = NewArrayIterator();
|
||||
UnsafeSetReservedSlot(iterator, ARRAY_ITERATOR_SLOT_ITERATED_OBJECT, iteratedObject);
|
||||
UnsafeSetReservedSlot(iterator, ARRAY_ITERATOR_SLOT_NEXT_INDEX, n);
|
||||
UnsafeSetReservedSlot(iterator, ARRAY_ITERATOR_SLOT_ITEM_KIND, kind);
|
||||
UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_TARGET, iteratedObject);
|
||||
UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_NEXT_INDEX, n);
|
||||
UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_ITEM_KIND, kind);
|
||||
return iterator;
|
||||
}
|
||||
function CreateArrayIterator(obj, kind) {
|
||||
@ -655,22 +647,22 @@ function ArrayIteratorNext() {
|
||||
"ArrayIteratorNext");
|
||||
}
|
||||
|
||||
var a = UnsafeGetObjectFromReservedSlot(this, ARRAY_ITERATOR_SLOT_ITERATED_OBJECT);
|
||||
var a = UnsafeGetObjectFromReservedSlot(this, ITERATOR_SLOT_TARGET);
|
||||
// The index might not be an integer, so we have to do a generic get here.
|
||||
var index = UnsafeGetReservedSlot(this, ARRAY_ITERATOR_SLOT_NEXT_INDEX);
|
||||
var itemKind = UnsafeGetInt32FromReservedSlot(this, ARRAY_ITERATOR_SLOT_ITEM_KIND);
|
||||
var index = UnsafeGetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX);
|
||||
var itemKind = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_ITEM_KIND);
|
||||
var result = { value: undefined, done: false };
|
||||
|
||||
// FIXME: This should be ToLength, which clamps at 2**53. Bug 924058.
|
||||
if (index >= TO_UINT32(a.length)) {
|
||||
// When the above is changed to ToLength, use +1/0 here instead
|
||||
// of MAX_UINT32.
|
||||
UnsafeSetReservedSlot(this, ARRAY_ITERATOR_SLOT_NEXT_INDEX, 0xffffffff);
|
||||
UnsafeSetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX, 0xffffffff);
|
||||
result.done = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
UnsafeSetReservedSlot(this, ARRAY_ITERATOR_SLOT_NEXT_INDEX, index + 1);
|
||||
UnsafeSetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX, index + 1);
|
||||
|
||||
if (itemKind === ITEM_KIND_VALUE) {
|
||||
result.value = a[index];
|
||||
|
@ -33,6 +33,59 @@ function MapForEach(callbackfn, thisArg = undefined) {
|
||||
}
|
||||
}
|
||||
|
||||
var iteratorTemp = { mapIterationResultPair : null };
|
||||
|
||||
function MapIteratorNext() {
|
||||
// Step 1.
|
||||
var O = this;
|
||||
|
||||
// Steps 2-3.
|
||||
if (!IsObject(O) || !IsMapIterator(O))
|
||||
return callFunction(CallMapIteratorMethodIfWrapped, O, "MapIteratorNext");
|
||||
|
||||
// Steps 4-5 (implemented in _GetNextMapEntryForIterator).
|
||||
// Steps 8-9 (omitted).
|
||||
|
||||
var mapIterationResultPair = iteratorTemp.mapIterationResultPair;
|
||||
if (!mapIterationResultPair) {
|
||||
mapIterationResultPair = iteratorTemp.mapIterationResultPair = NewDenseArray(2);
|
||||
mapIterationResultPair[0] = null;
|
||||
mapIterationResultPair[1] = null;
|
||||
}
|
||||
|
||||
var retVal = {value: undefined, done: true};
|
||||
|
||||
// Step 10.a, 11.
|
||||
var done = _GetNextMapEntryForIterator(O, mapIterationResultPair);
|
||||
if (!done) {
|
||||
// Steps 10.b-c (omitted).
|
||||
|
||||
// Step 6.
|
||||
var itemKind = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_ITEM_KIND);
|
||||
|
||||
var result;
|
||||
if (itemKind === ITEM_KIND_KEY) {
|
||||
// Step 10.d.i.
|
||||
result = mapIterationResultPair[0];
|
||||
} else if (itemKind === ITEM_KIND_VALUE) {
|
||||
// Step 10.d.ii.
|
||||
result = mapIterationResultPair[1];
|
||||
} else {
|
||||
// Step 10.d.iii.
|
||||
assert(itemKind === ITEM_KIND_KEY_AND_VALUE, itemKind);
|
||||
result = [mapIterationResultPair[0], mapIterationResultPair[1]];
|
||||
}
|
||||
|
||||
mapIterationResultPair[0] = null;
|
||||
mapIterationResultPair[1] = null;
|
||||
retVal.value = result;
|
||||
retVal.done = false;
|
||||
}
|
||||
|
||||
// Steps 7, 12.
|
||||
return retVal;
|
||||
}
|
||||
|
||||
// ES6 final draft 23.1.2.2.
|
||||
function MapSpecies() {
|
||||
// Step 1.
|
||||
|
@ -102,25 +102,6 @@ HashableValue::mark(JSTracer* trc) const
|
||||
|
||||
namespace {
|
||||
|
||||
class MapIteratorObject : public NativeObject
|
||||
{
|
||||
public:
|
||||
static const Class class_;
|
||||
|
||||
enum { TargetSlot, KindSlot, RangeSlot, SlotCount };
|
||||
static const JSFunctionSpec methods[];
|
||||
static MapIteratorObject* create(JSContext* cx, HandleObject mapobj, ValueMap* data,
|
||||
MapObject::IteratorKind kind);
|
||||
static bool next(JSContext* cx, unsigned argc, Value* vp);
|
||||
static void finalize(FreeOp* fop, JSObject* obj);
|
||||
|
||||
private:
|
||||
static inline bool is(HandleValue v);
|
||||
inline ValueMap::Range* range();
|
||||
inline MapObject::IteratorKind kind() const;
|
||||
static bool next_impl(JSContext* cx, CallArgs args);
|
||||
};
|
||||
|
||||
} /* anonymous namespace */
|
||||
|
||||
const Class MapIteratorObject::class_ = {
|
||||
@ -140,14 +121,15 @@ const Class MapIteratorObject::class_ = {
|
||||
|
||||
const JSFunctionSpec MapIteratorObject::methods[] = {
|
||||
JS_SELF_HOSTED_SYM_FN(iterator, "IteratorIdentity", 0, 0),
|
||||
JS_FN("next", next, 0, 0),
|
||||
JS_SELF_HOSTED_FN("next", "MapIteratorNext", 0, 0),
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
inline ValueMap::Range*
|
||||
MapIteratorObject::range()
|
||||
static inline ValueMap::Range*
|
||||
MapIteratorObjectRange(NativeObject* obj)
|
||||
{
|
||||
return static_cast<ValueMap::Range*>(getSlot(RangeSlot).toPrivate());
|
||||
MOZ_ASSERT(obj->is<MapIteratorObject>());
|
||||
return static_cast<ValueMap::Range*>(obj->getSlot(MapIteratorObject::RangeSlot).toPrivate());
|
||||
}
|
||||
|
||||
inline MapObject::IteratorKind
|
||||
@ -194,75 +176,46 @@ MapIteratorObject::create(JSContext* cx, HandleObject mapobj, ValueMap* data,
|
||||
return nullptr;
|
||||
}
|
||||
iterobj->setSlot(TargetSlot, ObjectValue(*mapobj));
|
||||
iterobj->setSlot(KindSlot, Int32Value(int32_t(kind)));
|
||||
iterobj->setSlot(RangeSlot, PrivateValue(range));
|
||||
iterobj->setSlot(KindSlot, Int32Value(int32_t(kind)));
|
||||
return iterobj;
|
||||
}
|
||||
|
||||
void
|
||||
MapIteratorObject::finalize(FreeOp* fop, JSObject* obj)
|
||||
{
|
||||
fop->delete_(obj->as<MapIteratorObject>().range());
|
||||
fop->delete_(MapIteratorObjectRange(static_cast<NativeObject*>(obj)));
|
||||
}
|
||||
|
||||
bool
|
||||
MapIteratorObject::is(HandleValue v)
|
||||
MapIteratorObject::next(JSContext* cx, Handle<MapIteratorObject*> mapIterator,
|
||||
HandleArrayObject resultPairObj)
|
||||
{
|
||||
return v.isObject() && v.toObject().hasClass(&class_);
|
||||
}
|
||||
|
||||
bool
|
||||
MapIteratorObject::next_impl(JSContext* cx, CallArgs args)
|
||||
{
|
||||
MapIteratorObject& thisobj = args.thisv().toObject().as<MapIteratorObject>();
|
||||
ValueMap::Range* range = thisobj.range();
|
||||
RootedValue value(cx);
|
||||
bool done;
|
||||
MOZ_ASSERT(resultPairObj->getDenseInitializedLength() == 2);
|
||||
|
||||
ValueMap::Range* range = MapIteratorObjectRange(mapIterator);
|
||||
if (!range || range->empty()) {
|
||||
js_delete(range);
|
||||
thisobj.setReservedSlot(RangeSlot, PrivateValue(nullptr));
|
||||
value.setUndefined();
|
||||
done = true;
|
||||
} else {
|
||||
switch (thisobj.kind()) {
|
||||
case MapObject::Keys:
|
||||
value = range->front().key.get();
|
||||
break;
|
||||
|
||||
case MapObject::Values:
|
||||
value = range->front().value;
|
||||
break;
|
||||
|
||||
case MapObject::Entries: {
|
||||
JS::AutoValueArray<2> pair(cx);
|
||||
pair[0].set(range->front().key.get());
|
||||
pair[1].set(range->front().value);
|
||||
|
||||
JSObject* pairobj = NewDenseCopiedArray(cx, pair.length(), pair.begin());
|
||||
if (!pairobj)
|
||||
return false;
|
||||
value.setObject(*pairobj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
range->popFront();
|
||||
done = false;
|
||||
mapIterator->setReservedSlot(RangeSlot, PrivateValue(nullptr));
|
||||
return true;
|
||||
}
|
||||
switch (mapIterator->kind()) {
|
||||
case MapObject::Keys:
|
||||
resultPairObj->setDenseElementWithType(cx, 0, range->front().key.get());
|
||||
break;
|
||||
|
||||
RootedObject result(cx, CreateItrResultObject(cx, value, done));
|
||||
if (!result)
|
||||
return false;
|
||||
args.rval().setObject(*result);
|
||||
case MapObject::Values:
|
||||
resultPairObj->setDenseElementWithType(cx, 1, range->front().value);
|
||||
break;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MapIteratorObject::next(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, next_impl, args);
|
||||
case MapObject::Entries: {
|
||||
resultPairObj->setDenseElementWithType(cx, 0, range->front().key.get());
|
||||
resultPairObj->setDenseElementWithType(cx, 1, range->front().value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
range->popFront();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -1455,7 +1408,6 @@ js::InitSetClass(JSContext* cx, HandleObject obj)
|
||||
}
|
||||
|
||||
const JSFunctionSpec selfhosting_collection_iterator_methods[] = {
|
||||
JS_FN("std_Map_iterator_next", MapIteratorObject::next, 0, 0),
|
||||
JS_FN("std_Set_iterator_next", SetIteratorObject::next, 0, 0),
|
||||
JS_FS_END
|
||||
};
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "jsobj.h"
|
||||
|
||||
#include "builtin/SelfHostingDefines.h"
|
||||
#include "vm/Runtime.h"
|
||||
|
||||
namespace js {
|
||||
@ -88,6 +89,13 @@ typedef OrderedHashSet<HashableValue,
|
||||
class MapObject : public NativeObject {
|
||||
public:
|
||||
enum IteratorKind { Keys, Values, Entries };
|
||||
static_assert(Keys == ITEM_KIND_KEY,
|
||||
"IteratorKind Keys must match self-hosting define for item kind key.");
|
||||
static_assert(Values == ITEM_KIND_VALUE,
|
||||
"IteratorKind Values must match self-hosting define for item kind value.");
|
||||
static_assert(Entries == ITEM_KIND_KEY_AND_VALUE,
|
||||
"IteratorKind Entries must match self-hosting define for item kind "
|
||||
"key-and-value.");
|
||||
|
||||
static JSObject* initClass(JSContext* cx, JSObject* obj);
|
||||
static const Class class_;
|
||||
@ -146,6 +154,32 @@ class MapObject : public NativeObject {
|
||||
static bool clear(JSContext* cx, unsigned argc, Value* vp);
|
||||
};
|
||||
|
||||
class MapIteratorObject : public NativeObject
|
||||
{
|
||||
public:
|
||||
static const Class class_;
|
||||
|
||||
enum { TargetSlot, RangeSlot, KindSlot, SlotCount };
|
||||
|
||||
static_assert(TargetSlot == ITERATOR_SLOT_TARGET,
|
||||
"TargetSlot must match self-hosting define for iterated object slot.");
|
||||
static_assert(RangeSlot == ITERATOR_SLOT_RANGE,
|
||||
"RangeSlot must match self-hosting define for range or index slot.");
|
||||
static_assert(KindSlot == ITERATOR_SLOT_ITEM_KIND,
|
||||
"KindSlot must match self-hosting define for item kind slot.");
|
||||
|
||||
static const JSFunctionSpec methods[];
|
||||
static MapIteratorObject* create(JSContext* cx, HandleObject mapobj, ValueMap* data,
|
||||
MapObject::IteratorKind kind);
|
||||
static void finalize(FreeOp* fop, JSObject* obj);
|
||||
|
||||
static bool next(JSContext* cx, Handle<MapIteratorObject*> mapIterator,
|
||||
HandleArrayObject resultPairObj);
|
||||
|
||||
private:
|
||||
inline MapObject::IteratorKind kind() const;
|
||||
};
|
||||
|
||||
class SetObject : public NativeObject {
|
||||
public:
|
||||
enum IteratorKind { Values, Entries };
|
||||
|
@ -13,6 +13,7 @@
|
||||
#define TO_INT32(x) ((x) | 0)
|
||||
#define TO_UINT32(x) ((x) >>> 0)
|
||||
#define IS_UINT32(x) ((x) >>> 0 === (x))
|
||||
#define MAX_NUMERIC_INDEX 0x1fffffffffffff // == Math.pow(2, 53) - 1
|
||||
|
||||
// Unforgeable versions of ARRAY.push(ELEMENT) and ARRAY.slice.
|
||||
#define ARRAY_PUSH(ARRAY, ELEMENT) \
|
||||
@ -32,4 +33,15 @@
|
||||
// Stores the private WeakMap slot used for WeakSets
|
||||
#define WEAKSET_MAP_SLOT 0
|
||||
|
||||
#define ITERATOR_SLOT_TARGET 0
|
||||
// Used for collection iterators.
|
||||
#define ITERATOR_SLOT_RANGE 1
|
||||
// Used for list, i.e. Array and String, iterators.
|
||||
#define ITERATOR_SLOT_NEXT_INDEX 1
|
||||
#define ITERATOR_SLOT_ITEM_KIND 2
|
||||
|
||||
#define ITEM_KIND_KEY 0
|
||||
#define ITEM_KIND_VALUE 1
|
||||
#define ITEM_KIND_KEY_AND_VALUE 2
|
||||
|
||||
#endif
|
||||
|
@ -189,16 +189,13 @@ function String_repeat(count) {
|
||||
return T;
|
||||
}
|
||||
|
||||
#define STRING_ITERATOR_SLOT_ITERATED_STRING 0
|
||||
#define STRING_ITERATOR_SLOT_NEXT_INDEX 1
|
||||
|
||||
// ES6 draft specification, section 21.1.3.27, version 2013-09-27.
|
||||
function String_iterator() {
|
||||
RequireObjectCoercible(this);
|
||||
var S = ToString(this);
|
||||
var iterator = NewStringIterator();
|
||||
UnsafeSetReservedSlot(iterator, STRING_ITERATOR_SLOT_ITERATED_STRING, S);
|
||||
UnsafeSetReservedSlot(iterator, STRING_ITERATOR_SLOT_NEXT_INDEX, 0);
|
||||
UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_TARGET, S);
|
||||
UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_NEXT_INDEX, 0);
|
||||
return iterator;
|
||||
}
|
||||
|
||||
@ -212,11 +209,11 @@ function StringIteratorNext() {
|
||||
"StringIteratorNext");
|
||||
}
|
||||
|
||||
var S = UnsafeGetStringFromReservedSlot(this, STRING_ITERATOR_SLOT_ITERATED_STRING);
|
||||
var S = UnsafeGetStringFromReservedSlot(this, ITERATOR_SLOT_TARGET);
|
||||
// We know that JSString::MAX_LENGTH <= INT32_MAX (and assert this in
|
||||
// SelfHostring.cpp) so our current index can never be anything other than
|
||||
// an Int32Value.
|
||||
var index = UnsafeGetInt32FromReservedSlot(this, STRING_ITERATOR_SLOT_NEXT_INDEX);
|
||||
var index = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX);
|
||||
var size = S.length;
|
||||
var result = { value: undefined, done: false };
|
||||
|
||||
@ -234,7 +231,7 @@ function StringIteratorNext() {
|
||||
}
|
||||
}
|
||||
|
||||
UnsafeSetReservedSlot(this, STRING_ITERATOR_SLOT_NEXT_INDEX, index + charCount);
|
||||
UnsafeSetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX, index + charCount);
|
||||
result.value = callFunction(std_String_substring, S, index, index + charCount);
|
||||
|
||||
return result;
|
||||
|
@ -44,6 +44,7 @@ var std_String_substring = String_substring;
|
||||
var std_WeakMap = WeakMap;
|
||||
// StopIteration is a bare constructor without properties or methods.
|
||||
var std_StopIteration = StopIteration;
|
||||
var std_Map_iterator_next = MapIteratorNext;
|
||||
|
||||
|
||||
/********** List specification type **********/
|
||||
|
@ -224,6 +224,8 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target)
|
||||
return inlineSubstringKernel(callInfo);
|
||||
if (native == intrinsic_IsArrayIterator)
|
||||
return inlineHasClass(callInfo, &ArrayIteratorObject::class_);
|
||||
if (native == intrinsic_IsMapIterator)
|
||||
return inlineHasClass(callInfo, &MapIteratorObject::class_);
|
||||
if (native == intrinsic_IsStringIterator)
|
||||
return inlineHasClass(callInfo, &StringIteratorObject::class_);
|
||||
|
||||
|
@ -769,6 +769,7 @@ bool intrinsic_IsPackedArray(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
bool intrinsic_IsSuspendedStarGenerator(JSContext* cx, unsigned argc, Value* vp);
|
||||
bool intrinsic_IsArrayIterator(JSContext* cx, unsigned argc, Value* vp);
|
||||
bool intrinsic_IsMapIterator(JSContext* cx, unsigned argc, Value* vp);
|
||||
bool intrinsic_IsStringIterator(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
bool intrinsic_IsArrayBuffer(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "selfhosted.out.h"
|
||||
|
||||
#include "builtin/Intl.h"
|
||||
#include "builtin/MapObject.h"
|
||||
#include "builtin/Object.h"
|
||||
#include "builtin/Reflect.h"
|
||||
#include "builtin/SelfHostingDefines.h"
|
||||
@ -479,6 +480,32 @@ js::intrinsic_IsArrayIterator(JSContext* cx, unsigned argc, Value* vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::intrinsic_IsMapIterator(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 1);
|
||||
MOZ_ASSERT(args[0].isObject());
|
||||
|
||||
args.rval().setBoolean(args[0].toObject().is<MapIteratorObject>());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
intrinsic_GetNextMapEntryForIterator(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 2);
|
||||
MOZ_ASSERT(args[0].toObject().is<MapIteratorObject>());
|
||||
MOZ_ASSERT(args[1].isObject());
|
||||
|
||||
Rooted<MapIteratorObject*> mapIterator(cx, &args[0].toObject().as<MapIteratorObject>());
|
||||
RootedArrayObject result(cx, &args[1].toObject().as<ArrayObject>());
|
||||
|
||||
args.rval().setBoolean(MapIteratorObject::next(cx, mapIterator, result));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
intrinsic_NewStringIterator(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
@ -1341,6 +1368,11 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
||||
JS_FN("CallArrayIteratorMethodIfWrapped",
|
||||
CallNonGenericSelfhostedMethod<Is<ArrayIteratorObject>>, 2,0),
|
||||
|
||||
JS_FN("IsMapIterator", intrinsic_IsMapIterator, 1,0),
|
||||
JS_FN("_GetNextMapEntryForIterator", intrinsic_GetNextMapEntryForIterator, 3,0),
|
||||
JS_FN("CallMapIteratorMethodIfWrapped",
|
||||
CallNonGenericSelfhostedMethod<Is<MapIteratorObject>>, 2,0),
|
||||
|
||||
|
||||
JS_FN("NewStringIterator", intrinsic_NewStringIterator, 0,0),
|
||||
JS_FN("IsStringIterator", intrinsic_IsStringIterator, 1,0),
|
||||
|
Loading…
Reference in New Issue
Block a user