diff options
-rw-r--r-- | bench/snippets/serialize.mjs | 121 | ||||
-rw-r--r-- | src/bun.js/bindings/webcore/SerializedScriptValue.cpp | 88 |
2 files changed, 197 insertions, 12 deletions
diff --git a/bench/snippets/serialize.mjs b/bench/snippets/serialize.mjs index 9db60b4b1..1a3646f79 100644 --- a/bench/snippets/serialize.mjs +++ b/bench/snippets/serialize.mjs @@ -1,15 +1,112 @@ import { serialize, deserialize } from "node:v8"; import { bench, run } from "./runner.mjs"; const obj = { - a: { - b: { - c: 1, - d: new Date(), - e: /foo/g, - f: new Map([[1, 2]]), - g: new Set([1, 2]), - h: new ArrayBuffer(), - j: new Uint8Array([1, 2, 3]), + "id": 1296269, + "node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5", + "name": "Hello-World", + "full_name": "octocat/Hello-World", + "owner": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false, + }, + "private": false, + "html_url": "https://github.com/octocat/Hello-World", + "description": "This your first repo!", + "fork": false, + "url": "https://api.github.com/repos/octocat/Hello-World", + "archive_url": "https://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}", + "assignees_url": "https://api.github.com/repos/octocat/Hello-World/assignees{/user}", + "blobs_url": "https://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}", + "branches_url": "https://api.github.com/repos/octocat/Hello-World/branches{/branch}", + "collaborators_url": "https://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}", + "comments_url": "https://api.github.com/repos/octocat/Hello-World/comments{/number}", + "commits_url": "https://api.github.com/repos/octocat/Hello-World/commits{/sha}", + "compare_url": "https://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}", + "contents_url": "https://api.github.com/repos/octocat/Hello-World/contents/{+path}", + "contributors_url": "https://api.github.com/repos/octocat/Hello-World/contributors", + "deployments_url": "https://api.github.com/repos/octocat/Hello-World/deployments", + "downloads_url": "https://api.github.com/repos/octocat/Hello-World/downloads", + "events_url": "https://api.github.com/repos/octocat/Hello-World/events", + "forks_url": "https://api.github.com/repos/octocat/Hello-World/forks", + "git_commits_url": "https://api.github.com/repos/octocat/Hello-World/git/commits{/sha}", + "git_refs_url": "https://api.github.com/repos/octocat/Hello-World/git/refs{/sha}", + "git_tags_url": "https://api.github.com/repos/octocat/Hello-World/git/tags{/sha}", + "git_url": "git:github.com/octocat/Hello-World.git", + "issue_comment_url": "https://api.github.com/repos/octocat/Hello-World/issues/comments{/number}", + "issue_events_url": "https://api.github.com/repos/octocat/Hello-World/issues/events{/number}", + "issues_url": "https://api.github.com/repos/octocat/Hello-World/issues{/number}", + "keys_url": "https://api.github.com/repos/octocat/Hello-World/keys{/key_id}", + "labels_url": "https://api.github.com/repos/octocat/Hello-World/labels{/name}", + "languages_url": "https://api.github.com/repos/octocat/Hello-World/languages", + "merges_url": "https://api.github.com/repos/octocat/Hello-World/merges", + "milestones_url": "https://api.github.com/repos/octocat/Hello-World/milestones{/number}", + "notifications_url": "https://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}", + "pulls_url": "https://api.github.com/repos/octocat/Hello-World/pulls{/number}", + "releases_url": "https://api.github.com/repos/octocat/Hello-World/releases{/id}", + "ssh_url": "git@github.com:octocat/Hello-World.git", + "stargazers_url": "https://api.github.com/repos/octocat/Hello-World/stargazers", + "statuses_url": "https://api.github.com/repos/octocat/Hello-World/statuses/{sha}", + "subscribers_url": "https://api.github.com/repos/octocat/Hello-World/subscribers", + "subscription_url": "https://api.github.com/repos/octocat/Hello-World/subscription", + "tags_url": "https://api.github.com/repos/octocat/Hello-World/tags", + "teams_url": "https://api.github.com/repos/octocat/Hello-World/teams", + "trees_url": "https://api.github.com/repos/octocat/Hello-World/git/trees{/sha}", + "clone_url": "https://github.com/octocat/Hello-World.git", + "mirror_url": "git:git.example.com/octocat/Hello-World", + "hooks_url": "https://api.github.com/repos/octocat/Hello-World/hooks", + "svn_url": "https://svn.github.com/octocat/Hello-World", + "homepage": "https://github.com", + "language": null, + "forks_count": 9, + "stargazers_count": 80, + "watchers_count": 80, + "size": 108, + "default_branch": "master", + "open_issues_count": 0, + "is_template": false, + "topics": ["octocat", "atom", "electron", "api"], + "has_issues": true, + "has_projects": true, + "has_wiki": true, + "has_pages": false, + "has_downloads": true, + "has_discussions": false, + "archived": false, + "disabled": false, + "visibility": "public", + "pushed_at": "2011-01-26T19:06:43Z", + "created_at": "2011-01-26T19:01:12Z", + "updated_at": "2011-01-26T19:14:43Z", + "permissions": { + "admin": false, + "push": false, + "pull": true, + }, + "security_and_analysis": { + "advanced_security": { + "status": "enabled", + }, + "secret_scanning": { + "status": "enabled", + }, + "secret_scanning_push_protection": { + "status": "disabled", }, }, }; @@ -22,4 +119,10 @@ bench("deserialize", () => { deserialize(serialized); }); +if (typeof Bun !== "undefined") { + if (!Bun.deepEquals(obj, deserialize(serialized))) { + throw new Error("not equal"); + } +} + await run(); diff --git a/src/bun.js/bindings/webcore/SerializedScriptValue.cpp b/src/bun.js/bindings/webcore/SerializedScriptValue.cpp index 60729ea65..176e805b8 100644 --- a/src/bun.js/bindings/webcore/SerializedScriptValue.cpp +++ b/src/bun.js/bindings/webcore/SerializedScriptValue.cpp @@ -2571,6 +2571,19 @@ private: { } + CachedString(const Identifier& identifier) + : m_identifier(identifier) + , m_string(identifier.string()) + { + } + + Identifier identifier(JSC::VM& vm) + { + if (m_identifier.isEmpty()) + m_identifier = Identifier::fromString(vm, string()); + return m_identifier; + } + JSValue jsString(JSGlobalObject* lexicalGlobalObject) { if (!m_jsString) @@ -2583,6 +2596,7 @@ private: private: String m_string; JSValue m_jsString; + Identifier m_identifier; }; struct CachedStringRef { @@ -2956,6 +2970,38 @@ private: return true; } + static bool readIdentifier(JSC::VM& vm, const uint8_t*& ptr, const uint8_t* end, Identifier& str, unsigned length, bool is8Bit) + { + if (length >= std::numeric_limits<int32_t>::max() / sizeof(UChar)) + return false; + + if (is8Bit) { + if ((end - ptr) < static_cast<int>(length)) + return false; + str = Identifier::fromString(vm, reinterpret_cast<const LChar*>(ptr), length); + ptr += length; + return true; + } + + unsigned size = length * sizeof(UChar); + if ((end - ptr) < static_cast<int>(size)) + return false; + +#if ASSUME_LITTLE_ENDIAN + str = Identifier::fromString(vm, reinterpret_cast<const UChar*>(ptr), length); + ptr += length * sizeof(UChar); +#else + UChar* characters; + str = String::createUninitialized(length, characters); + for (unsigned i = 0; i < length; ++i) { + uint16_t c; + readLittleEndian(ptr, end, c); + characters[i] = c; + } +#endif + return true; + } + bool readStringData(CachedStringRef& cachedString) { bool scratch; @@ -2998,6 +3044,42 @@ private: return true; } + bool readIdentifierData(JSC::VM& vm, CachedStringRef& cachedString, bool& wasTerminator) + { + if (m_failed) + return false; + uint32_t length = 0; + if (!read(length)) + return false; + if (length == TerminatorTag) { + wasTerminator = true; + return false; + } + if (length == StringPoolTag) { + unsigned index = 0; + if (!readStringIndex(index)) { + fail(); + return false; + } + if (index >= m_constantPool.size()) { + fail(); + return false; + } + cachedString = CachedStringRef(&m_constantPool, index); + return true; + } + bool is8Bit = length & StringDataIs8BitFlag; + length &= ~StringDataIs8BitFlag; + Identifier identifier; + if (!readIdentifier(vm, m_ptr, m_end, identifier, length, is8Bit)) { + fail(); + return false; + } + m_constantPool.append(identifier); + cachedString = CachedStringRef(&m_constantPool, m_constantPool.size() - 1); + return true; + } + SerializationTag readTag() { if (m_ptr >= m_end) @@ -4658,7 +4740,7 @@ DeserializationResult CloneDeserializer::deserialize() case ObjectStartVisitMember: { CachedStringRef cachedString; bool wasTerminator = false; - if (!readStringData(cachedString, wasTerminator)) { + if (!readIdentifierData(vm, cachedString, wasTerminator)) { if (!wasTerminator) goto error; @@ -4669,11 +4751,11 @@ DeserializationResult CloneDeserializer::deserialize() } if (JSValue terminal = readTerminal()) { - putProperty(outputObjectStack.last(), Identifier::fromString(vm, cachedString->string()), terminal); + putProperty(outputObjectStack.last(), cachedString->identifier(vm), terminal); goto objectStartVisitMember; } stateStack.append(ObjectEndVisitMember); - propertyNameStack.append(Identifier::fromString(vm, cachedString->string())); + propertyNameStack.append(cachedString->identifier(vm)); goto stateUnknown; } case ObjectEndVisitMember: { |