[JSC] Use internal object field mechanism to implement JSStringIterator
https://bugs.webkit.org/show_bug.cgi?id=206144

Reviewed by Ross Kirsling.

JSTests:

* stress/string-iterators.js:
* stress/tailCallForwardArguments.js:
(putFuncToPrivateName.createBuiltin):
(createTailCallForwardingFuncWith):

Source/JavaScriptCore:

This patch uses internal object field mechanism to implement JSStringIterator,
and we also put JSStringIterator into IsoSubspace.

* builtins/BuiltinNames.h:
* builtins/StringIteratorPrototype.js:
(next):
* bytecode/BytecodeIntrinsicRegistry.cpp:
(JSC::BytecodeIntrinsicRegistry::BytecodeIntrinsicRegistry):
* bytecode/BytecodeIntrinsicRegistry.h:
* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::emitIsStringIterator):
* bytecompiler/NodesCodegen.cpp:
(JSC::stringIteratorInternalFieldIndex):
(JSC::BytecodeIntrinsicNode::emit_intrinsic_getStringIteratorInternalField):
(JSC::BytecodeIntrinsicNode::emit_intrinsic_putStringIteratorInternalField):
* inspector/JSInjectedScriptHost.cpp:
(Inspector::JSInjectedScriptHost::getInternalProperties):
* runtime/JSCast.h:
* runtime/JSStringIterator.cpp:
(JSC::JSStringIterator::finishCreation):
(JSC::JSStringIterator::clone):
(JSC::JSStringIterator::visitChildren):
(JSC::JSStringIterator::iteratedValue const): Deleted.
* runtime/JSStringIterator.h:
* runtime/JSType.cpp:
(WTF::printInternal):
* runtime/JSType.h:
* runtime/StringPrototype.cpp:
(JSC::stringProtoFuncIterator):
* runtime/VM.cpp:
* runtime/VM.h:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@254420 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog
index 8c647a2..53aeebf 100644
--- a/JSTests/ChangeLog
+++ b/JSTests/ChangeLog
@@ -1,3 +1,15 @@
+2020-01-12  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [JSC] Use internal object field mechanism to implement JSStringIterator
+        https://bugs.webkit.org/show_bug.cgi?id=206144
+
+        Reviewed by Ross Kirsling.
+
+        * stress/string-iterators.js:
+        * stress/tailCallForwardArguments.js:
+        (putFuncToPrivateName.createBuiltin):
+        (createTailCallForwardingFuncWith):
+
 2020-01-10  Yusuke Suzuki  <ysuzuki@apple.com>
 
         [JSC] Flush old tables in End phase
diff --git a/JSTests/stress/string-iterators.js b/JSTests/stress/string-iterators.js
index f66b620..c5c7fee1 100644
--- a/JSTests/stress/string-iterators.js
+++ b/JSTests/stress/string-iterators.js
@@ -181,8 +181,6 @@
     if (!didThrow)
         throw "Error: no error thrown";
     var message = 'TypeError: %StringIteratorPrototype%.next requires that |this| be a String Iterator instance';
-    if (primitive == null)
-        message = 'TypeError: %StringIteratorPrototype%.next requires that |this| not be null or undefined'
     if (String(didThrow) !== message)
         throw "Error: bad error thrown: " + didThrow;
 }
diff --git a/JSTests/stress/tailCallForwardArguments.js b/JSTests/stress/tailCallForwardArguments.js
index 6972552..e584df1 100644
--- a/JSTests/stress/tailCallForwardArguments.js
+++ b/JSTests/stress/tailCallForwardArguments.js
@@ -3,7 +3,7 @@
 var createBuiltin = $vm.createBuiltin;
 
 // This is pretty bad but I need a private name.
-var putFuncToPrivateName = createBuiltin(`(function (func) { @arrayIteratorIsDone = func })`)
+var putFuncToPrivateName = createBuiltin(`(function (func) { @generatorThis = func })`)
 putFuncToPrivateName(function (a,b) { return b; })
 
 function createTailCallForwardingFuncWith(body, thisValue) {
@@ -12,7 +12,7 @@
 
         ${body}
 
-        return @tailCallForwardArguments(@arrayIteratorIsDone, ${thisValue});
+        return @tailCallForwardArguments(@generatorThis, ${thisValue});
     })`);
 }
 
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 05db9bc..0880783 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,5 +1,44 @@
 2020-01-12  Yusuke Suzuki  <ysuzuki@apple.com>
 
+        [JSC] Use internal object field mechanism to implement JSStringIterator
+        https://bugs.webkit.org/show_bug.cgi?id=206144
+
+        Reviewed by Ross Kirsling.
+
+        This patch uses internal object field mechanism to implement JSStringIterator,
+        and we also put JSStringIterator into IsoSubspace.
+
+        * builtins/BuiltinNames.h:
+        * builtins/StringIteratorPrototype.js:
+        (next):
+        * bytecode/BytecodeIntrinsicRegistry.cpp:
+        (JSC::BytecodeIntrinsicRegistry::BytecodeIntrinsicRegistry):
+        * bytecode/BytecodeIntrinsicRegistry.h:
+        * bytecompiler/BytecodeGenerator.h:
+        (JSC::BytecodeGenerator::emitIsStringIterator):
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::stringIteratorInternalFieldIndex):
+        (JSC::BytecodeIntrinsicNode::emit_intrinsic_getStringIteratorInternalField):
+        (JSC::BytecodeIntrinsicNode::emit_intrinsic_putStringIteratorInternalField):
+        * inspector/JSInjectedScriptHost.cpp:
+        (Inspector::JSInjectedScriptHost::getInternalProperties):
+        * runtime/JSCast.h:
+        * runtime/JSStringIterator.cpp:
+        (JSC::JSStringIterator::finishCreation):
+        (JSC::JSStringIterator::clone):
+        (JSC::JSStringIterator::visitChildren):
+        (JSC::JSStringIterator::iteratedValue const): Deleted.
+        * runtime/JSStringIterator.h:
+        * runtime/JSType.cpp:
+        (WTF::printInternal):
+        * runtime/JSType.h:
+        * runtime/StringPrototype.cpp:
+        (JSC::stringProtoFuncIterator):
+        * runtime/VM.cpp:
+        * runtime/VM.h:
+
+2020-01-12  Yusuke Suzuki  <ysuzuki@apple.com>
+
         [JSC] Remove IsDone from JSArrayIterator
         https://bugs.webkit.org/show_bug.cgi?id=206140
 
diff --git a/Source/JavaScriptCore/builtins/BuiltinNames.h b/Source/JavaScriptCore/builtins/BuiltinNames.h
index b0b7868..154fff8 100644
--- a/Source/JavaScriptCore/builtins/BuiltinNames.h
+++ b/Source/JavaScriptCore/builtins/BuiltinNames.h
@@ -46,11 +46,6 @@
     JSC_COMMON_BYTECODE_INTRINSIC_CONSTANTS_EACH_NAME(macro) \
     macro(add) \
     macro(applyFunction) \
-    macro(arrayIteratorNextIndex) \
-    macro(arrayIterationKind) \
-    macro(arrayIteratorNext) \
-    macro(arrayIteratorIsDone) \
-    macro(arrayIteratorKind) \
     macro(arraySpeciesCreate) \
     macro(assert) \
     macro(callFunction) \
@@ -59,7 +54,6 @@
     macro(isView) \
     macro(iteratedObject) \
     macro(iteratedString) \
-    macro(stringIteratorNextIndex) \
     macro(promise) \
     macro(promiseOrCapability) \
     macro(Object) \
diff --git a/Source/JavaScriptCore/builtins/StringIteratorPrototype.js b/Source/JavaScriptCore/builtins/StringIteratorPrototype.js
index d122de8..6dbdb76 100644
--- a/Source/JavaScriptCore/builtins/StringIteratorPrototype.js
+++ b/Source/JavaScriptCore/builtins/StringIteratorPrototype.js
@@ -27,21 +27,18 @@
 {
     "use strict";
 
-    if (@isUndefinedOrNull(this))
-        @throwTypeError("%StringIteratorPrototype%.next requires that |this| not be null or undefined");
-
-    var position = @getByIdDirectPrivate(this, "stringIteratorNextIndex");
-    if (position === @undefined)
+    if (!@isStringIterator(this))
         @throwTypeError("%StringIteratorPrototype%.next requires that |this| be a String Iterator instance");
 
     var done = true;
     var value = @undefined;
 
-    var string = @getByIdDirectPrivate(this, "iteratedString");
-    if (string !== @undefined) {
+    var position = @getStringIteratorInternalField(this, @stringIteratorFieldIndex);
+    if (position !== -1) {
+        var string = @getStringIteratorInternalField(this, @stringIteratorFieldIteratedString);
         var length = string.length >>> 0;
         if (position >= length)
-            @putByIdDirectPrivate(this, "iteratedString", @undefined);
+            @putStringIteratorInternalField(this, @stringIteratorFieldIndex, -1);
         else {
             done = false;
 
@@ -55,8 +52,7 @@
                 else
                     value = string[position] + string[position + 1];
             }
-
-            @putByIdDirectPrivate(this, "stringIteratorNextIndex", position + value.length);
+            @putStringIteratorInternalField(this, @stringIteratorFieldIndex, position + value.length);
         }
     }
 
diff --git a/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.cpp b/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.cpp
index 73cc87f..32aaf87 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.cpp
+++ b/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.cpp
@@ -38,6 +38,7 @@
 #include "JSGlobalObject.h"
 #include "JSModuleLoader.h"
 #include "JSPromise.h"
+#include "JSStringIterator.h"
 #include "Nodes.h"
 #include "StrongInlines.h"
 
@@ -91,6 +92,8 @@
     m_arrayIteratorFieldIteratedObject.set(m_vm, jsNumber(static_cast<int32_t>(JSArrayIterator::Field::IteratedObject)));
     m_arrayIteratorFieldIndex.set(m_vm, jsNumber(static_cast<int32_t>(JSArrayIterator::Field::Index)));
     m_arrayIteratorFieldKind.set(m_vm, jsNumber(static_cast<int32_t>(JSArrayIterator::Field::Kind)));
+    m_stringIteratorFieldIndex.set(m_vm, jsNumber(static_cast<int32_t>(JSStringIterator::Field::Index)));
+    m_stringIteratorFieldIteratedString.set(m_vm, jsNumber(static_cast<int32_t>(JSStringIterator::Field::IteratedString)));
     m_asyncGeneratorFieldSuspendReason.set(m_vm, jsNumber(static_cast<unsigned>(JSAsyncGenerator::Field::SuspendReason)));
     m_asyncGeneratorFieldQueueFirst.set(m_vm, jsNumber(static_cast<unsigned>(JSAsyncGenerator::Field::QueueFirst)));
     m_asyncGeneratorFieldQueueLast.set(m_vm, jsNumber(static_cast<unsigned>(JSAsyncGenerator::Field::QueueLast)));
diff --git a/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.h b/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.h
index 0abd1c8..cf1c382 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.h
+++ b/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.h
@@ -46,6 +46,7 @@
     macro(getGeneratorInternalField) \
     macro(getAsyncGeneratorInternalField) \
     macro(getArrayIteratorInternalField) \
+    macro(getStringIteratorInternalField) \
     macro(idWithProfile) \
     macro(isObject) \
     macro(isJSArray) \
@@ -57,6 +58,7 @@
     macro(isRegExpObject) \
     macro(isMap) \
     macro(isSet) \
+    macro(isStringIterator) \
     macro(isArrayIterator) \
     macro(isUndefinedOrNull) \
     macro(tailCallForwardArguments) \
@@ -71,6 +73,7 @@
     macro(putGeneratorInternalField) \
     macro(putAsyncGeneratorInternalField) \
     macro(putArrayIteratorInternalField) \
+    macro(putStringIteratorInternalField) \
     macro(toNumber) \
     macro(toString) \
     macro(toObject) \
@@ -122,6 +125,8 @@
     macro(arrayIteratorFieldIsDone) \
     macro(arrayIteratorFieldIteratedObject) \
     macro(arrayIteratorFieldKind) \
+    macro(stringIteratorFieldIndex) \
+    macro(stringIteratorFieldIteratedString) \
     macro(asyncGeneratorFieldSuspendReason) \
     macro(asyncGeneratorFieldQueueFirst) \
     macro(asyncGeneratorFieldQueueLast) \
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
index 62d5cbb..a5f366b 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
@@ -878,6 +878,7 @@
         RegisterID* emitIsRegExpObject(RegisterID* dst, RegisterID* src) { return emitIsCellWithType(dst, src, RegExpObjectType); }
         RegisterID* emitIsMap(RegisterID* dst, RegisterID* src) { return emitIsCellWithType(dst, src, JSMapType); }
         RegisterID* emitIsSet(RegisterID* dst, RegisterID* src) { return emitIsCellWithType(dst, src, JSSetType); }
+        RegisterID* emitIsStringIterator(RegisterID* dst, RegisterID* src) { return emitIsCellWithType(dst, src, JSStringIteratorType); }
         RegisterID* emitIsArrayIterator(RegisterID* dst, RegisterID* src) { return emitIsCellWithType(dst, src, JSArrayIteratorType); }
         RegisterID* emitIsObject(RegisterID* dst, RegisterID* src);
         RegisterID* emitIsNumber(RegisterID* dst, RegisterID* src);
diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index 6c1a4e2..3326fb3 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -40,6 +40,7 @@
 #include "JSGenerator.h"
 #include "JSGlobalObject.h"
 #include "JSImmutableButterfly.h"
+#include "JSStringIterator.h"
 #include "LabelScope.h"
 #include "Lexer.h"
 #include "Parser.h"
@@ -1077,6 +1078,17 @@
     return JSArrayIterator::Field::Index;
 }
 
+static JSStringIterator::Field stringIteratorInternalFieldIndex(BytecodeIntrinsicNode* node)
+{
+    ASSERT(node->entry().type() == BytecodeIntrinsicRegistry::Type::Emitter);
+    if (node->entry().emitter() == &BytecodeIntrinsicNode::emit_intrinsic_stringIteratorFieldIndex)
+        return JSStringIterator::Field::Index;
+    if (node->entry().emitter() == &BytecodeIntrinsicNode::emit_intrinsic_stringIteratorFieldIteratedString)
+        return JSStringIterator::Field::IteratedString;
+    RELEASE_ASSERT_NOT_REACHED();
+    return JSStringIterator::Field::Index;
+}
+
 RegisterID* BytecodeIntrinsicNode::emit_intrinsic_getPromiseInternalField(BytecodeGenerator& generator, RegisterID* dst)
 {
     ArgumentListNode* node = m_args->m_listNode;
@@ -1129,6 +1141,19 @@
     return generator.emitGetInternalField(generator.finalDestination(dst), base.get(), index);
 }
 
+RegisterID* BytecodeIntrinsicNode::emit_intrinsic_getStringIteratorInternalField(BytecodeGenerator& generator, RegisterID* dst)
+{
+    ArgumentListNode* node = m_args->m_listNode;
+    RefPtr<RegisterID> base = generator.emitNode(node);
+    node = node->m_next;
+    RELEASE_ASSERT(node->m_expr->isBytecodeIntrinsicNode());
+    unsigned index = static_cast<unsigned>(stringIteratorInternalFieldIndex(static_cast<BytecodeIntrinsicNode*>(node->m_expr)));
+    ASSERT(index < JSStringIterator::numberOfInternalFields);
+    ASSERT(!node->m_next);
+
+    return generator.emitGetInternalField(generator.finalDestination(dst), base.get(), index);
+}
+
 RegisterID* BytecodeIntrinsicNode::emit_intrinsic_argument(BytecodeGenerator& generator, RegisterID* dst)
 {
     ArgumentListNode* node = m_args->m_listNode;
@@ -1262,6 +1287,22 @@
     return generator.move(dst, generator.emitPutInternalField(base.get(), index, value.get()));
 }
 
+RegisterID* BytecodeIntrinsicNode::emit_intrinsic_putStringIteratorInternalField(BytecodeGenerator& generator, RegisterID* dst)
+{
+    ArgumentListNode* node = m_args->m_listNode;
+    RefPtr<RegisterID> base = generator.emitNode(node);
+    node = node->m_next;
+    RELEASE_ASSERT(node->m_expr->isBytecodeIntrinsicNode());
+    unsigned index = static_cast<unsigned>(stringIteratorInternalFieldIndex(static_cast<BytecodeIntrinsicNode*>(node->m_expr)));
+    ASSERT(index < JSStringIterator::numberOfInternalFields);
+    node = node->m_next;
+    RefPtr<RegisterID> value = generator.emitNode(node);
+
+    ASSERT(!node->m_next);
+
+    return generator.move(dst, generator.emitPutInternalField(base.get(), index, value.get()));
+}
+
 RegisterID* BytecodeIntrinsicNode::emit_intrinsic_tailCallForwardArguments(BytecodeGenerator& generator, RegisterID* dst)
 {
     ArgumentListNode* node = m_args->m_listNode;
@@ -1395,6 +1436,7 @@
 CREATE_INTRINSIC_FOR_BRAND_CHECK(isRegExpObject, IsRegExpObject)
 CREATE_INTRINSIC_FOR_BRAND_CHECK(isMap, IsMap)
 CREATE_INTRINSIC_FOR_BRAND_CHECK(isSet, IsSet)
+CREATE_INTRINSIC_FOR_BRAND_CHECK(isStringIterator, IsStringIterator)
 CREATE_INTRINSIC_FOR_BRAND_CHECK(isArrayIterator, IsArrayIterator)
 CREATE_INTRINSIC_FOR_BRAND_CHECK(isUndefinedOrNull, IsUndefinedOrNull)
 
diff --git a/Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp b/Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp
index ef2c410..f14578d 100644
--- a/Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp
+++ b/Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp
@@ -431,7 +431,7 @@
         JSArray* array = constructEmptyArray(globalObject, nullptr, 1);
         RETURN_IF_EXCEPTION(scope, JSValue());
         scope.release();
-        array->putDirectIndex(globalObject, index++, constructInternalProperty(globalObject, "string", stringIterator->iteratedValue(globalObject)));
+        array->putDirectIndex(globalObject, index++, constructInternalProperty(globalObject, "string", stringIterator->iteratedString()));
         return array;
     }
 
diff --git a/Source/JavaScriptCore/runtime/JSCast.h b/Source/JavaScriptCore/runtime/JSCast.h
index f8f3a4f..673e01c 100644
--- a/Source/JavaScriptCore/runtime/JSCast.h
+++ b/Source/JavaScriptCore/runtime/JSCast.h
@@ -48,6 +48,8 @@
 // Specific type overloads.
 #define FOR_EACH_JS_DYNAMIC_CAST_JS_TYPE_OVERLOAD(macro) \
     macro(JSImmutableButterfly, JSType::JSImmutableButterflyType, JSType::JSImmutableButterflyType) \
+    macro(JSArrayIterator, JSType::JSArrayIteratorType, JSType::JSArrayIteratorType) \
+    macro(JSStringIterator, JSType::JSStringIteratorType, JSType::JSStringIteratorType) \
     macro(JSObject, FirstObjectType, LastObjectType) \
     macro(JSFinalObject, JSType::FinalObjectType, JSType::FinalObjectType) \
     macro(JSFunction, JSType::JSFunctionType, JSType::JSFunctionType) \
diff --git a/Source/JavaScriptCore/runtime/JSStringIterator.cpp b/Source/JavaScriptCore/runtime/JSStringIterator.cpp
index 351d470..16bf5dd 100644
--- a/Source/JavaScriptCore/runtime/JSStringIterator.cpp
+++ b/Source/JavaScriptCore/runtime/JSStringIterator.cpp
@@ -27,35 +27,35 @@
 #include "config.h"
 #include "JSStringIterator.h"
 
-#include "BuiltinNames.h"
 #include "JSCInlines.h"
+#include "JSInternalFieldObjectImplInlines.h"
 
 namespace JSC {
 
 const ClassInfo JSStringIterator::s_info = { "String Iterator", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSStringIterator) };
 
-void JSStringIterator::finishCreation(VM& vm, JSGlobalObject*, JSString* iteratedString)
+void JSStringIterator::finishCreation(VM& vm, JSString* iteratedString)
 {
     Base::finishCreation(vm);
     ASSERT(inherits(vm, info()));
-    putDirect(vm, vm.propertyNames->builtinNames().iteratedStringPrivateName(), iteratedString);
-    putDirect(vm, vm.propertyNames->builtinNames().stringIteratorNextIndexPrivateName(), jsNumber(0));
-}
-
-JSValue JSStringIterator::iteratedValue(JSGlobalObject* globalObject) const
-{
-    return getDirect(globalObject->vm(), globalObject->vm().propertyNames->builtinNames().iteratedStringPrivateName());
+    internalField(Field::Index).set(vm, this, jsNumber(0));
+    internalField(Field::IteratedString).set(vm, this, iteratedString);
 }
 
 JSStringIterator* JSStringIterator::clone(JSGlobalObject* globalObject)
 {
     VM& vm = globalObject->vm();
-    JSValue iteratedString = getDirect(vm, vm.propertyNames->builtinNames().iteratedStringPrivateName());
-    JSValue nextIndex = getDirect(vm, vm.propertyNames->builtinNames().stringIteratorNextIndexPrivateName());
-
-    auto clone = JSStringIterator::create(globalObject, globalObject->stringIteratorStructure(), asString(iteratedString));
-    clone->putDirect(vm, vm.propertyNames->builtinNames().stringIteratorNextIndexPrivateName(), nextIndex);
+    JSString* iteratedString = jsCast<JSString*>(this->iteratedString());
+    auto* clone = JSStringIterator::create(vm, globalObject->stringIteratorStructure(), iteratedString);
+    clone->internalField(Field::Index).set(vm, clone, this->index());
     return clone;
 }
 
+void JSStringIterator::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+    auto* thisObject = jsCast<JSStringIterator*>(cell);
+    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+    Base::visitChildren(thisObject, visitor);
+}
+
 } // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSStringIterator.h b/Source/JavaScriptCore/runtime/JSStringIterator.h
index bfd9716..b48b7a8 100644
--- a/Source/JavaScriptCore/runtime/JSStringIterator.h
+++ b/Source/JavaScriptCore/runtime/JSStringIterator.h
@@ -29,35 +29,65 @@
 
 namespace JSC {
 
-class JSStringIterator final : public JSNonFinalObject {
+class JSStringIterator final : public JSInternalFieldObjectImpl<2> {
 public:
-    typedef JSNonFinalObject Base;
+    using Base = JSInternalFieldObjectImpl<2>;
+
+    enum class Field : uint8_t {
+        Index = 0,
+        IteratedString,
+    };
 
     DECLARE_EXPORT_INFO;
 
-    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+    static size_t allocationSize(Checked<size_t> inlineCapacity)
     {
-        return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+        ASSERT_UNUSED(inlineCapacity, inlineCapacity == 0U);
+        return sizeof(JSStringIterator);
     }
 
-    static JSStringIterator* create(JSGlobalObject* globalObject, Structure* structure, JSString* iteratedString)
+    template<typename CellType, SubspaceAccess mode>
+    static IsoSubspace* subspaceFor(VM& vm)
     {
-        VM& vm = getVM(globalObject);
+        return vm.stringIteratorSpace<mode>();
+    }
+
+    static std::array<JSValue, numberOfInternalFields> initialValues()
+    {
+        return { {
+            jsNumber(0),
+            jsNull(),
+        } };
+    }
+
+    const WriteBarrier<Unknown>& internalField(Field field) const { return Base::internalField(static_cast<uint32_t>(field)); }
+    WriteBarrier<Unknown>& internalField(Field field) { return Base::internalField(static_cast<uint32_t>(field)); }
+
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+    {
+        return Structure::create(vm, globalObject, prototype, TypeInfo(JSStringIteratorType, StructureFlags), info());
+    }
+
+    static JSStringIterator* create(VM& vm, Structure* structure, JSString* iteratedString)
+    {
         JSStringIterator* instance = new (NotNull, allocateCell<JSStringIterator>(vm.heap)) JSStringIterator(vm, structure);
-        instance->finishCreation(vm, structure->globalObject(), iteratedString);
+        instance->finishCreation(vm, iteratedString);
         return instance;
     }
 
-    JSValue iteratedValue(JSGlobalObject*) const;
+    JSValue iteratedString() const { return internalField(Field::IteratedString).get(); }
+    JSValue index() const { return internalField(Field::Index).get(); }
     JSStringIterator* clone(JSGlobalObject*);
 
+    static void visitChildren(JSCell*, SlotVisitor&);
+
 private:
     JSStringIterator(VM& vm, Structure* structure)
         : Base(vm, structure)
     {
     }
 
-    void finishCreation(VM&, JSGlobalObject*, JSString* iteratedString);
+    void finishCreation(VM&, JSString* iteratedString);
 };
 
 } // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSType.cpp b/Source/JavaScriptCore/runtime/JSType.cpp
index 1038dc5..b02b347 100644
--- a/Source/JavaScriptCore/runtime/JSType.cpp
+++ b/Source/JavaScriptCore/runtime/JSType.cpp
@@ -100,6 +100,7 @@
     CASE(JSGeneratorType)
     CASE(JSAsyncGeneratorType)
     CASE(JSArrayIteratorType)
+    CASE(JSStringIteratorType)
     CASE(JSPromiseType)
     CASE(JSMapType)
     CASE(JSSetType)
diff --git a/Source/JavaScriptCore/runtime/JSType.h b/Source/JavaScriptCore/runtime/JSType.h
index 2d1d308..1479925 100644
--- a/Source/JavaScriptCore/runtime/JSType.h
+++ b/Source/JavaScriptCore/runtime/JSType.h
@@ -111,6 +111,7 @@
     JSGeneratorType,
     JSAsyncGeneratorType,
     JSArrayIteratorType,
+    JSStringIteratorType,
     JSPromiseType,
     JSMapType,
     JSSetType,
diff --git a/Source/JavaScriptCore/runtime/StringPrototype.cpp b/Source/JavaScriptCore/runtime/StringPrototype.cpp
index 470aac1..53b8778 100644
--- a/Source/JavaScriptCore/runtime/StringPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/StringPrototype.cpp
@@ -1860,7 +1860,7 @@
         return throwVMTypeError(globalObject, scope);
     JSString* string = thisValue.toString(globalObject);
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
-    return JSValue::encode(JSStringIterator::create(globalObject, globalObject->stringIteratorStructure(), string));
+    return JSValue::encode(JSStringIterator::create(vm, globalObject->stringIteratorStructure(), string));
 }
 
 enum class NormalizationForm { NFC, NFD, NFKC, NFKD };
diff --git a/Source/JavaScriptCore/runtime/VM.cpp b/Source/JavaScriptCore/runtime/VM.cpp
index ac234dd..4752aa0 100644
--- a/Source/JavaScriptCore/runtime/VM.cpp
+++ b/Source/JavaScriptCore/runtime/VM.cpp
@@ -116,6 +116,7 @@
 #include "JSSet.h"
 #include "JSSetIterator.h"
 #include "JSSourceCode.h"
+#include "JSStringIterator.h"
 #include "JSTemplateObjectDescriptor.h"
 #include "JSToWasmICCallee.h"
 #include "JSTypedArrays.h"
@@ -1441,6 +1442,7 @@
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(apiGlobalObjectSpace, apiGlobalObjectHeapCellType.get(), JSAPIGlobalObject)
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(apiValueWrapperSpace, cellHeapCellType.get(), JSAPIValueWrapper)
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(arrayBufferSpace, cellHeapCellType.get(), JSArrayBuffer)
+DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(arrayIteratorSpace, cellHeapCellType.get(), JSArrayIterator)
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(asyncGeneratorSpace, cellHeapCellType.get(), JSAsyncGenerator)
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(bigIntObjectSpace, cellHeapCellType.get(), BigIntObject)
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(booleanObjectSpace, cellHeapCellType.get(), BooleanObject)
@@ -1457,7 +1459,6 @@
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(float64ArraySpace, cellHeapCellType.get(), JSFloat64Array)
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(functionRareDataSpace, destructibleCellHeapCellType.get(), FunctionRareData)
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(generatorSpace, cellHeapCellType.get(), JSGenerator)
-DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(arrayIteratorSpace, cellHeapCellType.get(), JSArrayIterator)
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(globalObjectSpace, globalObjectHeapCellType.get(), JSGlobalObject)
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(jsModuleRecordSpace, jsModuleRecordHeapCellType.get(), JSModuleRecord)
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(int8ArraySpace, cellHeapCellType.get(), JSInt8Array)
@@ -1477,6 +1478,7 @@
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(setIteratorSpace, cellHeapCellType.get(), JSSetIterator)
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(setSpace, cellHeapCellType.get(), JSSet)
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(strictEvalActivationSpace, cellHeapCellType.get(), StrictEvalActivation)
+DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(stringIteratorSpace, cellHeapCellType.get(), JSStringIterator)
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(sourceCodeSpace, destructibleCellHeapCellType.get(), JSSourceCode)
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(symbolSpace, destructibleCellHeapCellType.get(), Symbol)
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(symbolObjectSpace, cellHeapCellType.get(), SymbolObject)
diff --git a/Source/JavaScriptCore/runtime/VM.h b/Source/JavaScriptCore/runtime/VM.h
index 824769c..9c2a16c 100644
--- a/Source/JavaScriptCore/runtime/VM.h
+++ b/Source/JavaScriptCore/runtime/VM.h
@@ -493,6 +493,7 @@
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(apiGlobalObjectSpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(apiValueWrapperSpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(arrayBufferSpace)
+    DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(arrayIteratorSpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(asyncGeneratorSpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(bigIntObjectSpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(booleanObjectSpace)
@@ -509,7 +510,6 @@
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(float64ArraySpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(functionRareDataSpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(generatorSpace)
-    DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(arrayIteratorSpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(globalObjectSpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(int8ArraySpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(int16ArraySpace)
@@ -529,6 +529,7 @@
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(setIteratorSpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(setSpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(strictEvalActivationSpace)
+    DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(stringIteratorSpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(sourceCodeSpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(symbolSpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(symbolObjectSpace)