Skip to content

Commit

Permalink
Implement basic of Iterator helper and Iterator.prototype.map
Browse files Browse the repository at this point in the history
Signed-off-by: Seonghyun Kim <[email protected]>
  • Loading branch information
ksh8281 authored and clover2123 committed Aug 9, 2024
1 parent 23ef579 commit 2ec730b
Show file tree
Hide file tree
Showing 10 changed files with 444 additions and 70 deletions.
279 changes: 279 additions & 0 deletions src/builtins/BuiltinIterator.cpp

Large diffs are not rendered by default.

34 changes: 0 additions & 34 deletions src/runtime/GlobalObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -834,16 +834,6 @@ static Value builtinArrayToString(ExecutionState& state, Value thisValue, size_t
return Object::call(state, toString, thisObject, 0, nullptr);
}

static Value builtinGenericIteratorNext(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
if (!thisValue.isObject() || !thisValue.asObject()->isGenericIteratorObject()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, String::fromASCII("Iterator"), true, state.context()->staticStrings().next.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver);
}

IteratorObject* iter = thisValue.asObject()->asIteratorObject();
return iter->next(state);
}

void GlobalObject::initializeOthers(ExecutionState& state)
{
// Other prerequisite builtins should be installed at the start time
Expand Down Expand Up @@ -904,7 +894,6 @@ void GlobalObject::installOthers(ExecutionState& state)
NativeFunctionInfo(strings->unescape, builtinUnescape, 1, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));

// shared builtin methods
m_parseInt = new NativeFunctionObject(state, NativeFunctionInfo(strings->parseInt, builtinParseInt, 2, NativeFunctionInfo::Strict));
defineOwnProperty(state, ObjectPropertyName(strings->parseInt),
ObjectPropertyDescriptor(m_parseInt,
Expand All @@ -917,29 +906,6 @@ void GlobalObject::installOthers(ExecutionState& state)

m_arrayToString = new NativeFunctionObject(state, NativeFunctionInfo(strings->toString, builtinArrayToString, 0, NativeFunctionInfo::Strict));

// shared builtin objects
m_asyncIteratorPrototype = new PrototypeObject(state);
m_asyncIteratorPrototype->setGlobalIntrinsicObject(state, true);
// https://www.ecma-international.org/ecma-262/10.0/index.html#sec-asynciteratorprototype-asynciterator
m_asyncIteratorPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().asyncIterator),
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(AtomicString(state, String::fromASCII("[Symbol.asyncIterator]")), builtinSpeciesGetter, 0, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));

m_iteratorPrototype = new PrototypeObject(state);
m_iteratorPrototype->setGlobalIntrinsicObject(state, true);
// https://www.ecma-international.org/ecma-262/10.0/index.html#sec-%iteratorprototype%-@@iterator
m_iteratorPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().iterator),
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(AtomicString(state, String::fromASCII("[Symbol.iterator]")), builtinSpeciesGetter, 0, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));

m_genericIteratorPrototype = new PrototypeObject(state, m_iteratorPrototype);
m_genericIteratorPrototype->setGlobalIntrinsicObject(state, true);

m_genericIteratorPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().next),
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().next, builtinGenericIteratorNext, 0, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_genericIteratorPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().toStringTag),
ObjectPropertyDescriptor(Value(String::fromASCII("Iterator")), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent)));

#if defined(ESCARGOT_ENABLE_TEST)
AtomicString isFunctionAllocatedOnStackFunctionName(state, "isFunctionAllocatedOnStack");
defineOwnProperty(state, ObjectPropertyName(isFunctionAllocatedOnStackFunctionName),
Expand Down
7 changes: 6 additions & 1 deletion src/runtime/GlobalObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,10 @@ class FunctionObject;
F(finalizationRegistryPrototype, Object, objName)
#define GLOBALOBJECT_BUILTIN_TEMPORAL(F, objName) \
F(temporal, Object, objName)
#define GLOBALOBJECT_BUILTIN_ITERATOR(F, objName) \
F(iterator, FunctionObject, objName) \
F(wrapForValidIteratorPrototype, Object, objName) \
F(iteratorHelperPrototype, Object, objName)

#if defined(ENABLE_THREADING)
#define GLOBALOBJECT_BUILTIN_ATOMICS(F, objName) \
Expand Down Expand Up @@ -282,9 +286,11 @@ class FunctionObject;
F(DATAVIEW, DataView, ARG) \
F(DATE, Date, ARG) \
F(ERROR, Error, ARG) \
F(FINALIZATIONREGISTRY, FinalizationRegistry, ARG) \
F(FUNCTION, Function, ARG) \
F(GENERATOR, Generator, ARG) \
F(INTL, Intl, ARG) \
F(ITERATOR, Iterator, ARG) \
F(JSON, JSON, ARG) \
F(MAP, Map, ARG) \
F(MATH, Math, ARG) \
Expand All @@ -305,7 +311,6 @@ class FunctionObject;
F(WEAKMAP, WeakMap, ARG) \
F(WEAKSET, WeakSet, ARG) \
F(WEAKREF, WeakRef, ARG) \
F(FINALIZATIONREGISTRY, FinalizationRegistry, ARG) \
F(WASM, WebAssembly, ARG)


Expand Down
74 changes: 74 additions & 0 deletions src/runtime/IteratorObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,31 @@ Optional<Object*> IteratorObject::iteratorStep(ExecutionState& state, IteratorRe
return done ? nullptr : result;
}

// https://tc39.es/ecma262/#sec-iteratorstepvalue
Optional<Value> IteratorObject::iteratorStepValue(ExecutionState& state, IteratorRecord* iteratorRecord)
{
// Let result be ? IteratorStep(iteratorRecord).
auto result = iteratorStep(state, iteratorRecord);
// If result is done, then
if (!result) {
// Return done.
return nullptr;
}

Value value;
// Let value be Completion(IteratorValue(result)).
try {
value = iteratorValue(state, result.value());
} catch (const Value& e) {
// If value is a throw completion, then
// Set iteratorRecord.[[Done]] to true.
iteratorRecord->m_done = true;
throw e;
}
// Return ? value.
return value;
}

// https://www.ecma-international.org/ecma-262/10.0/#sec-iteratorclose
Value IteratorObject::iteratorClose(ExecutionState& state, IteratorRecord* iteratorRecord, const Value& completionValue, bool hasThrowOnCompletionType)
{
Expand Down Expand Up @@ -326,4 +351,53 @@ IteratorObject::KeyedGroupVector IteratorObject::groupBy(ExecutionState& state,
}
}

IteratorHelperObject::IteratorHelperObject(ExecutionState& state, IteratorHelperObjectCallback callback,
IteratorRecord* underlyingIterator, void* data)
: IteratorObject(state, state.context()->globalObject()->iteratorHelperPrototype())
, m_isRunning(false)
, m_callback(callback)
, m_underlyingIterator(underlyingIterator)
, m_data(data)
{
}

void* IteratorHelperObject::operator new(size_t size)
{
static MAY_THREAD_LOCAL bool typeInited = false;
static MAY_THREAD_LOCAL GC_descr descr;
if (!typeInited) {
GC_word obj_bitmap[GC_BITMAP_SIZE(IteratorHelperObject)] = { 0 };
IteratorObject::fillGCDescriptor(obj_bitmap);
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(IteratorHelperObject, m_data));
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(IteratorHelperObject, m_underlyingIterator));
descr = GC_make_descriptor(obj_bitmap, GC_WORD_LEN(IteratorHelperObject));
typeInited = true;
}
return GC_MALLOC_EXPLICITLY_TYPED(size, descr);
}

std::pair<Value, bool> IteratorHelperObject::advance(ExecutionState& state)
{
struct IteratorHelperObjectRunningStateChanger {
IteratorHelperObject& obj;
IteratorHelperObjectRunningStateChanger(IteratorHelperObject& obj)
: obj(obj)
{
ASSERT(!obj.m_isRunning);
obj.m_isRunning = true;
}
~IteratorHelperObjectRunningStateChanger()
{
obj.m_isRunning = false;
}
};

if (m_isRunning) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "You cannot call Iterator helper advance function recursively");
}

IteratorHelperObjectRunningStateChanger changeRunningState(*this);
return m_callback(state, this, m_data);
}

} // namespace Escargot
64 changes: 64 additions & 0 deletions src/runtime/IteratorObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class StringIteratorObject;
class RegExpStringIteratorObject;
class MapIteratorObject;
class SetIteratorObject;
class IteratorHelperObject;
class IteratorObject;

class IteratorRecord : public PointerValue {
Expand Down Expand Up @@ -90,6 +91,12 @@ class IteratorObject : public DerivedObject {
return (SetIteratorObject*)this;
}

IteratorHelperObject* asIteratorHelperObject()
{
ASSERT(isIteratorHelperObject());
return (IteratorHelperObject*)this;
}

Value next(ExecutionState& state);

virtual std::pair<Value, bool> advance(ExecutionState& state) = 0;
Expand All @@ -100,6 +107,8 @@ class IteratorObject : public DerivedObject {
static Value iteratorValue(ExecutionState& state, Object* iterResult);
// this function return empty Optional value instead of Value(false)
static Optional<Object*> iteratorStep(ExecutionState& state, IteratorRecord* iteratorRecord);
// return null option value when iterator done
static Optional<Value> iteratorStepValue(ExecutionState& state, IteratorRecord* iteratorRecord);
static Value iteratorClose(ExecutionState& state, IteratorRecord* iteratorRecord, const Value& completionValue, bool hasThrowOnCompletionType);
static Object* createIterResultObject(ExecutionState& state, const Value& value, bool done);
// https://www.ecma-international.org/ecma-262/10.0/#sec-iterabletolist
Expand All @@ -117,6 +126,61 @@ class IteratorObject : public DerivedObject {
typedef Vector<KeyedGroup*, GCUtil::gc_malloc_allocator<KeyedGroup*>> KeyedGroupVector;
static KeyedGroupVector groupBy(ExecutionState& state, const Value& items, const Value& callbackfn, GroupByKeyCoercion keyCoercion);
};

class IteratorHelperObject : public IteratorObject {
public:
typedef std::pair<Value, bool> (*IteratorHelperObjectCallback)(ExecutionState& state, IteratorHelperObject* obj, void* data);
IteratorHelperObject(ExecutionState& state, IteratorHelperObjectCallback callback, IteratorRecord* underlyingIterator, void* data);

virtual bool isIteratorHelperObject() const override
{
return true;
}

virtual std::pair<Value, bool> advance(ExecutionState& state) override;

void* operator new(size_t size);
void* operator new[](size_t size) = delete;

bool isRunning() const
{
return m_isRunning;
}

IteratorRecord* underlyingIterator() const
{
return m_underlyingIterator;
}

private:
bool m_isRunning;
IteratorHelperObjectCallback m_callback;
IteratorRecord* m_underlyingIterator;
void* m_data;
};

class WrapForValidIteratorObject : public DerivedObject {
public:
explicit WrapForValidIteratorObject(ExecutionState& state, Object* proto, IteratorRecord* iterated)
: DerivedObject(state, proto)
, m_iterated(iterated)
{
}

virtual bool isWrapForValidIteratorObject() const override
{
return true;
}

IteratorRecord* iterated() const
{
return m_iterated;
}

private:
IteratorRecord* m_iterated;
};

} // namespace Escargot

#endif
17 changes: 17 additions & 0 deletions src/runtime/PointerValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class DoubleInEncodedValue;
class JSGetterSetter;
class IteratorRecord;
class IteratorObject;
class WrapForValidIteratorObject;
class GenericIteratorObject;
class MapObject;
class SetObject;
Expand Down Expand Up @@ -471,11 +472,21 @@ class PointerValue : public gc {
return false;
}

virtual bool isWrapForValidIteratorObject() const
{
return false;
}

virtual bool isGenericIteratorObject() const
{
return false;
}

virtual bool isIteratorHelperObject() const
{
return false;
}

virtual bool isEnumerateObject() const
{
return false;
Expand Down Expand Up @@ -919,6 +930,12 @@ class PointerValue : public gc {
return (IteratorObject*)this;
}

WrapForValidIteratorObject* asWrapForValidIteratorObject()
{
ASSERT(isWrapForValidIteratorObject());
return (WrapForValidIteratorObject*)this;
}

GenericIteratorObject* asGenericIteratorObject()
{
ASSERT(isGenericIteratorObject());
Expand Down
1 change: 1 addition & 0 deletions src/runtime/StaticStrings.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ namespace Escargot {
F(Int32Array) \
F(Int8Array) \
F(Intl) \
F(Iterator) \
F(JSON) \
F(LN10) \
F(LN2) \
Expand Down
2 changes: 1 addition & 1 deletion test/vendortest
34 changes: 0 additions & 34 deletions tools/test/test262/excludelist.orig.xml
Original file line number Diff line number Diff line change
Expand Up @@ -381,40 +381,6 @@
<test id="built-ins/Iterator/prototype/forEach/this-non-object"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/forEach/this-plain-iterator"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/initial-value"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/argument-effect-order"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/callable"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/exhaustion-does-not-call-return"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/get-next-method-only-once"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/get-next-method-throws"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/get-return-method-throws"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/is-function"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/iterator-already-exhausted"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/iterator-return-method-throws"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/length"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/mapper-args"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/mapper-this"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/mapper-throws"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/mapper-throws-then-closing-iterator-also-throws"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/name"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/next-method-returns-non-object"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/next-method-returns-throwing-done"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/next-method-returns-throwing-value"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/next-method-returns-throwing-value-done"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/next-method-throws"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/non-constructible"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/prop-desc"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/proto"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/result-is-iterator"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/return-is-forwarded-to-underlying-iterator"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/return-is-not-forwarded-after-exhaustion"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/returned-iterator-yields-mapper-return-values"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/this-non-callable-next"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/this-non-object"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/this-plain-iterator"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/throws-typeerror-when-generator-is-running"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/underlying-iterator-advanced-in-parallel"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/underlying-iterator-closed"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/map/underlying-iterator-closed-in-parallel"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/reduce/argument-effect-order"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/reduce/callable"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/reduce/get-next-method-only-once"><reason>TODO</reason></test>
Expand Down
2 changes: 2 additions & 0 deletions tools/test/v8/v8.mjsunit.status
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,8 @@

# outdated
'invalid-lhs': [SKIP],
'es6/string-iterator': [SKIP],
'es6/iterator-prototype': [SKIP],

# can't set prototype of this object
'getter-in-prototype': [SKIP],
Expand Down

0 comments on commit 2ec730b

Please sign in to comment.