in src/bun.js/bindings/webcore/SerializedScriptValue.cpp [4988:5169]
DeserializationResult CloneDeserializer::deserialize()
{
VM& vm = m_lexicalGlobalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
Vector<uint32_t, 16> indexStack;
Vector<Identifier, 16> propertyNameStack;
MarkedVector<JSObject*, 32> outputObjectStack;
MarkedVector<JSValue, 4> mapKeyStack;
MarkedVector<JSMap*, 4> mapStack;
MarkedVector<JSSet*, 4> setStack;
Vector<WalkerState, 16> stateStack;
WalkerState state = StateUnknown;
JSValue outValue;
while (1) {
switch (state) {
arrayStartState:
case ArrayStartState: {
uint32_t length;
if (!read(length)) {
fail();
goto error;
}
JSArray* outArray = constructEmptyArray(m_globalObject, static_cast<JSC::ArrayAllocationProfile*>(nullptr), length);
if (UNLIKELY(scope.exception()))
goto error;
m_gcBuffer.appendWithCrashOnOverflow(outArray);
outputObjectStack.append(outArray);
}
arrayStartVisitMember:
FALLTHROUGH;
case ArrayStartVisitMember: {
uint32_t index;
if (!read(index)) {
fail();
goto error;
}
if (index == TerminatorTag) {
JSObject* outArray = outputObjectStack.last();
outValue = outArray;
outputObjectStack.removeLast();
break;
} else if (index == NonIndexPropertiesTag) {
goto objectStartVisitMember;
}
if (JSValue terminal = readTerminal()) {
putProperty(outputObjectStack.last(), index, terminal);
goto arrayStartVisitMember;
}
if (m_failed)
goto error;
indexStack.append(index);
stateStack.append(ArrayEndVisitMember);
goto stateUnknown;
}
case ArrayEndVisitMember: {
JSObject* outArray = outputObjectStack.last();
putProperty(outArray, indexStack.last(), outValue);
indexStack.removeLast();
goto arrayStartVisitMember;
}
objectStartState:
case ObjectStartState: {
if (outputObjectStack.size() > maximumFilterRecursion)
return std::make_pair(JSValue(), SerializationReturnCode::StackOverflowError);
JSObject* outObject = constructEmptyObject(m_lexicalGlobalObject, m_globalObject->objectPrototype());
m_gcBuffer.appendWithCrashOnOverflow(outObject);
outputObjectStack.append(outObject);
}
objectStartVisitMember:
FALLTHROUGH;
case ObjectStartVisitMember: {
CachedStringRef cachedString;
bool wasTerminator = false;
if (!readIdentifierData(vm, cachedString, wasTerminator)) {
if (!wasTerminator)
goto error;
JSObject* outObject = outputObjectStack.last();
outValue = outObject;
outputObjectStack.removeLast();
break;
}
if (JSValue terminal = readTerminal()) {
putProperty(outputObjectStack.last(), cachedString->identifier(vm), terminal);
goto objectStartVisitMember;
}
stateStack.append(ObjectEndVisitMember);
propertyNameStack.append(cachedString->identifier(vm));
goto stateUnknown;
}
case ObjectEndVisitMember: {
putProperty(outputObjectStack.last(), propertyNameStack.last(), outValue);
propertyNameStack.removeLast();
goto objectStartVisitMember;
}
mapObjectStartState : {
if (outputObjectStack.size() > maximumFilterRecursion)
return std::make_pair(JSValue(), SerializationReturnCode::StackOverflowError);
JSMap* map = JSMap::create(m_lexicalGlobalObject->vm(), m_globalObject->mapStructure());
m_gcBuffer.appendWithCrashOnOverflow(map);
outputObjectStack.append(map);
mapStack.append(map);
goto mapDataStartVisitEntry;
}
mapDataStartVisitEntry:
case MapDataStartVisitEntry: {
if (consumeCollectionDataTerminationIfPossible<NonMapPropertiesTag>()) {
mapStack.removeLast();
goto objectStartVisitMember;
}
stateStack.append(MapDataEndVisitKey);
goto stateUnknown;
}
case MapDataEndVisitKey: {
mapKeyStack.append(outValue);
stateStack.append(MapDataEndVisitValue);
goto stateUnknown;
}
case MapDataEndVisitValue: {
mapStack.last()->set(m_lexicalGlobalObject, mapKeyStack.last(), outValue);
mapKeyStack.removeLast();
goto mapDataStartVisitEntry;
}
setObjectStartState : {
if (outputObjectStack.size() > maximumFilterRecursion)
return std::make_pair(JSValue(), SerializationReturnCode::StackOverflowError);
JSSet* set = JSSet::create(m_lexicalGlobalObject->vm(), m_globalObject->setStructure());
m_gcBuffer.appendWithCrashOnOverflow(set);
outputObjectStack.append(set);
setStack.append(set);
goto setDataStartVisitEntry;
}
setDataStartVisitEntry:
case SetDataStartVisitEntry: {
if (consumeCollectionDataTerminationIfPossible<NonSetPropertiesTag>()) {
setStack.removeLast();
goto objectStartVisitMember;
}
stateStack.append(SetDataEndVisitKey);
goto stateUnknown;
}
case SetDataEndVisitKey: {
JSSet* set = setStack.last();
set->add(m_lexicalGlobalObject, outValue);
goto setDataStartVisitEntry;
}
stateUnknown:
case StateUnknown:
if (JSValue terminal = readTerminal()) {
outValue = terminal;
break;
}
SerializationTag tag = readTag();
if (tag == ArrayTag)
goto arrayStartState;
if (tag == ObjectTag)
goto objectStartState;
if (tag == MapObjectTag)
goto mapObjectStartState;
if (tag == SetObjectTag)
goto setObjectStartState;
goto error;
}
if (stateStack.isEmpty())
break;
state = stateStack.last();
stateStack.removeLast();
}
ASSERT(outValue);
ASSERT(!m_failed);
return std::make_pair(outValue, SerializationReturnCode::SuccessfullyCompleted);
error:
fail();
return std::make_pair(JSValue(), SerializationReturnCode::ValidationError);
}