GeezerVison is showing github.com — src: fix cppgc incompatibility in v8 · nodejs/node@f071028
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: src/base_object.h +4-2Lines changed: 4 additions & 2 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -38,11 +38,13 @@ namespace worker { | 38 | 38 | class TransferData; | 39 | 39 | } | 40 | 40 |
| | 41 | +extern uint16_t kNodeEmbedderId; | | 42 | + | 41 | 43 | class BaseObject : public MemoryRetainer { | 42 | 44 | public: | 43 | | - enum InternalFields { kSlot, kInternalFieldCount }; | | 45 | + enum InternalFields { kEmbedderType, kSlot, kInternalFieldCount }; | 44 | 46 |
| 45 | | - // Associates this object with `object`. It uses the 0th internal field for | | 47 | + // Associates this object with `object`. It uses the 1st internal field for | 46 | 48 | // that, and in particular aborts if there is no such field. | 47 | 49 | BaseObject(Environment* env, v8::Local<v8::Object> object); | 48 | 50 | ~BaseObject() override; | |
Collapse file Copy file name to clipboardExpand all lines: src/env.cc +14-2Lines changed: 14 additions & 2 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -1738,6 +1738,7 @@ void Environment::EnqueueDeserializeRequest(DeserializeRequestCallback cb, | 1738 | 1738 | Local<Object> holder, | 1739 | 1739 | int index, | 1740 | 1740 | InternalFieldInfo* info) { | | 1741 | + DCHECK_EQ(index, BaseObject::kEmbedderType); | 1741 | 1742 | DeserializeRequest request{cb, {isolate(), holder}, index, info}; | 1742 | 1743 | deserialize_requests_.push_back(std::move(request)); | 1743 | 1744 | } | @@ -2017,7 +2018,9 @@ void Environment::RunWeakRefCleanup() { | 2017 | 2018 | BaseObject::BaseObject(Environment* env, Local<Object> object) | 2018 | 2019 | : persistent_handle_(env->isolate(), object), env_(env) { | 2019 | 2020 | CHECK_EQ(false, object.IsEmpty()); | 2020 | | - CHECK_GT(object->InternalFieldCount(), 0); | | 2021 | + CHECK_GE(object->InternalFieldCount(), BaseObject::kInternalFieldCount); | | 2022 | + object->SetAlignedPointerInInternalField(BaseObject::kEmbedderType, | | 2023 | + &kNodeEmbedderId); | 2021 | 2024 | object->SetAlignedPointerInInternalField(BaseObject::kSlot, | 2022 | 2025 | static_cast<void*>(this)); | 2023 | 2026 | env->AddCleanupHook(DeleteMe, static_cast<void*>(this)); | @@ -2068,10 +2071,19 @@ void BaseObject::MakeWeak() { | 2068 | 2071 | WeakCallbackType::kParameter); | 2069 | 2072 | } | 2070 | 2073 |
| | 2074 | +// This just has to be different from the Chromium ones: | | 2075 | +// https://source.chromium.org/chromium/chromium/src/+/main:gin/public/gin_embedders.h;l=18-23;drc=5a758a97032f0b656c3c36a3497560762495501a | | 2076 | +// Otherwise, when Node is loaded in an isolate which uses cppgc, cppgc will | | 2077 | +// misinterpret the data stored in the embedder fields and try to garbage | | 2078 | +// collect them. | | 2079 | +uint16_t kNodeEmbedderId = 0x90de; | | 2080 | + | 2071 | 2081 | void BaseObject::LazilyInitializedJSTemplateConstructor( | 2072 | 2082 | const FunctionCallbackInfo<Value>& args) { | 2073 | 2083 | DCHECK(args.IsConstructCall()); | 2074 | | - DCHECK_GT(args.This()->InternalFieldCount(), 0); | | 2084 | + CHECK_GE(args.This()->InternalFieldCount(), BaseObject::kInternalFieldCount); | | 2085 | + args.This()->SetAlignedPointerInInternalField(BaseObject::kEmbedderType, | | 2086 | + &kNodeEmbedderId); | 2075 | 2087 | args.This()->SetAlignedPointerInInternalField(BaseObject::kSlot, nullptr); | 2076 | 2088 | } | 2077 | 2089 |
| |
Collapse file Copy file name to clipboardExpand all lines: src/node_blob.cc +2-2Lines changed: 2 additions & 2 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -465,7 +465,7 @@ void BlobBindingData::Deserialize( | 465 | 465 | Local<Object> holder, | 466 | 466 | int index, | 467 | 467 | InternalFieldInfo* info) { | 468 | | - DCHECK_EQ(index, BaseObject::kSlot); | | 468 | + DCHECK_EQ(index, BaseObject::kEmbedderType); | 469 | 469 | HandleScope scope(context->GetIsolate()); | 470 | 470 | Environment* env = Environment::GetCurrent(context); | 471 | 471 | BlobBindingData* binding = | @@ -480,7 +480,7 @@ void BlobBindingData::PrepareForSerialization( | 480 | 480 | } | 481 | 481 |
| 482 | 482 | InternalFieldInfo* BlobBindingData::Serialize(int index) { | 483 | | - DCHECK_EQ(index, BaseObject::kSlot); | | 483 | + DCHECK_EQ(index, BaseObject::kEmbedderType); | 484 | 484 | InternalFieldInfo* info = InternalFieldInfo::New(type()); | 485 | 485 | return info; | 486 | 486 | } | |
Collapse file Copy file name to clipboardExpand all lines: src/node_file.cc +2-2Lines changed: 2 additions & 2 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -2567,7 +2567,7 @@ void BindingData::Deserialize(Local<Context> context, | 2567 | 2567 | Local<Object> holder, | 2568 | 2568 | int index, | 2569 | 2569 | InternalFieldInfo* info) { | 2570 | | - DCHECK_EQ(index, BaseObject::kSlot); | | 2570 | + DCHECK_EQ(index, BaseObject::kEmbedderType); | 2571 | 2571 | HandleScope scope(context->GetIsolate()); | 2572 | 2572 | Environment* env = Environment::GetCurrent(context); | 2573 | 2573 | BindingData* binding = env->AddBindingData<BindingData>(context, holder); | @@ -2584,7 +2584,7 @@ void BindingData::PrepareForSerialization(Local<Context> context, | 2584 | 2584 | } | 2585 | 2585 |
| 2586 | 2586 | InternalFieldInfo* BindingData::Serialize(int index) { | 2587 | | - DCHECK_EQ(index, BaseObject::kSlot); | | 2587 | + DCHECK_EQ(index, BaseObject::kEmbedderType); | 2588 | 2588 | InternalFieldInfo* info = InternalFieldInfo::New(type()); | 2589 | 2589 | return info; | 2590 | 2590 | } | |
Collapse file Copy file name to clipboardExpand all lines: src/node_process_methods.cc +2-2Lines changed: 2 additions & 2 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -532,7 +532,7 @@ void BindingData::PrepareForSerialization(Local<Context> context, | 532 | 532 | } | 533 | 533 |
| 534 | 534 | InternalFieldInfo* BindingData::Serialize(int index) { | 535 | | - DCHECK_EQ(index, BaseObject::kSlot); | | 535 | + DCHECK_EQ(index, BaseObject::kEmbedderType); | 536 | 536 | InternalFieldInfo* info = InternalFieldInfo::New(type()); | 537 | 537 | return info; | 538 | 538 | } | @@ -541,7 +541,7 @@ void BindingData::Deserialize(Local<Context> context, | 541 | 541 | Local<Object> holder, | 542 | 542 | int index, | 543 | 543 | InternalFieldInfo* info) { | 544 | | - DCHECK_EQ(index, BaseObject::kSlot); | | 544 | + DCHECK_EQ(index, BaseObject::kEmbedderType); | 545 | 545 | v8::HandleScope scope(context->GetIsolate()); | 546 | 546 | Environment* env = Environment::GetCurrent(context); | 547 | 547 | // Recreate the buffer in the constructor. | |
Collapse file Copy file name to clipboardExpand all lines: src/node_snapshotable.cc +40-6Lines changed: 40 additions & 6 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -1119,10 +1119,20 @@ void DeserializeNodeInternalFields(Local<Object> holder, | 1119 | 1119 | static_cast<int>(index), | 1120 | 1120 | (*holder), | 1121 | 1121 | static_cast<int>(payload.raw_size)); | | 1122 | + | | 1123 | + if (payload.raw_size == 0) { | | 1124 | + holder->SetAlignedPointerInInternalField(index, nullptr); | | 1125 | + return; | | 1126 | + } | | 1127 | + | | 1128 | + DCHECK_EQ(index, BaseObject::kEmbedderType); | | 1129 | + | 1122 | 1130 | Environment* env_ptr = static_cast<Environment*>(env); | 1123 | 1131 | const InternalFieldInfo* info = | 1124 | 1132 | reinterpret_cast<const InternalFieldInfo*>(payload.data); | 1125 | | - | | 1133 | + // TODO(joyeecheung): we can add a constant kNodeEmbedderId to the | | 1134 | + // beginning of every InternalFieldInfo to ensure that we don't | | 1135 | + // step on payloads that were not serialized by Node.js. | 1126 | 1136 | switch (info->type) { | 1127 | 1137 | #define V(PropertyName, NativeTypeName) \ | 1128 | 1138 | case EmbedderObjectType::k_##PropertyName: { \ | @@ -1143,21 +1153,44 @@ void DeserializeNodeInternalFields(Local<Object> holder, | 1143 | 1153 | StartupData SerializeNodeContextInternalFields(Local<Object> holder, | 1144 | 1154 | int index, | 1145 | 1155 | void* env) { | 1146 | | - void* ptr = holder->GetAlignedPointerFromInternalField(BaseObject::kSlot); | 1147 | | - if (ptr == nullptr) { | | 1156 | + // We only do one serialization for the kEmbedderType slot, the result | | 1157 | + // contains everything necessary for deserializing the entire object, | | 1158 | + // including the fields whose index is bigger than kEmbedderType | | 1159 | + // (most importantly, BaseObject::kSlot). | | 1160 | + // For Node.js this design is enough for all the native binding that are | | 1161 | + // serializable. | | 1162 | + if (index != BaseObject::kEmbedderType) { | | 1163 | + return StartupData{nullptr, 0}; | | 1164 | + } | | 1165 | + | | 1166 | + void* type_ptr = holder->GetAlignedPointerFromInternalField(index); | | 1167 | + if (type_ptr == nullptr) { | | 1168 | + return StartupData{nullptr, 0}; | | 1169 | + } | | 1170 | + | | 1171 | + uint16_t type = *(static_cast<uint16_t*>(type_ptr)); | | 1172 | + per_process::Debug(DebugCategory::MKSNAPSHOT, "type = 0x%x\n", type); | | 1173 | + if (type != kNodeEmbedderId) { | 1148 | 1174 | return StartupData{nullptr, 0}; | 1149 | 1175 | } | | 1176 | + | 1150 | 1177 | per_process::Debug(DebugCategory::MKSNAPSHOT, | 1151 | 1178 | "Serialize internal field, index=%d, holder=%p\n", | 1152 | 1179 | static_cast<int>(index), | 1153 | 1180 | *holder); | 1154 | | - DCHECK(static_cast<BaseObject*>(ptr)->is_snapshotable()); | 1155 | | - SnapshotableObject* obj = static_cast<SnapshotableObject*>(ptr); | | 1181 | + | | 1182 | + void* binding_ptr = | | 1183 | + holder->GetAlignedPointerFromInternalField(BaseObject::kSlot); | | 1184 | + per_process::Debug(DebugCategory::MKSNAPSHOT, "binding = %p\n", binding_ptr); | | 1185 | + DCHECK(static_cast<BaseObject*>(binding_ptr)->is_snapshotable()); | | 1186 | + SnapshotableObject* obj = static_cast<SnapshotableObject*>(binding_ptr); | | 1187 | + | 1156 | 1188 | per_process::Debug(DebugCategory::MKSNAPSHOT, | 1157 | 1189 | "Object %p is %s, ", | 1158 | 1190 | *holder, | 1159 | 1191 | obj->GetTypeNameChars()); | 1160 | 1192 | InternalFieldInfo* info = obj->Serialize(index); | | 1193 | + | 1161 | 1194 | per_process::Debug(DebugCategory::MKSNAPSHOT, | 1162 | 1195 | "payload size=%d\n", | 1163 | 1196 | static_cast<int>(info->length)); | @@ -1172,8 +1205,9 @@ void SerializeBindingData(Environment* env, | 1172 | 1205 | env->ForEachBindingData([&](FastStringKey key, | 1173 | 1206 | BaseObjectPtr<BaseObject> binding) { | 1174 | 1207 | per_process::Debug(DebugCategory::MKSNAPSHOT, | 1175 | | - "Serialize binding %i, %p, type=%s\n", | | 1208 | + "Serialize binding %i (%p), object=%p, type=%s\n", | 1176 | 1209 | static_cast<int>(i), | | 1210 | + binding.get(), | 1177 | 1211 | *(binding->object()), | 1178 | 1212 | key.c_str()); | 1179 | 1213 |
| |
Collapse file Copy file name to clipboardExpand all lines: src/node_snapshotable.h -5Lines changed: 0 additions & 5 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -30,11 +30,6 @@ enum class EmbedderObjectType : uint8_t { | 30 | 30 | // When serializing an embedder object, we'll serialize the native states | 31 | 31 | // into a chunk that can be mapped into a subclass of InternalFieldInfo, | 32 | 32 | // and pass it into the V8 callback as the payload of StartupData. | 33 | | -// TODO(joyeecheung): the classification of types seem to be wrong. | 34 | | -// We'd need a type for each field of each class of native object. | 35 | | -// Maybe it's fine - we'll just use the type to invoke BaseObject constructors | 36 | | -// and specify that the BaseObject has only one field for us to serialize. | 37 | | -// And for non-BaseObject embedder objects, we'll use field-wise types. | 38 | 33 | // The memory chunk looks like this: | 39 | 34 | // | 40 | 35 | // [ type ] - EmbedderObjectType (a uint8_t) | |
Collapse file Copy file name to clipboardExpand all lines: src/node_v8.cc +2-2Lines changed: 2 additions & 2 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -124,15 +124,15 @@ void BindingData::Deserialize(Local<Context> context, | 124 | 124 | Local<Object> holder, | 125 | 125 | int index, | 126 | 126 | InternalFieldInfo* info) { | 127 | | - DCHECK_EQ(index, BaseObject::kSlot); | | 127 | + DCHECK_EQ(index, BaseObject::kEmbedderType); | 128 | 128 | HandleScope scope(context->GetIsolate()); | 129 | 129 | Environment* env = Environment::GetCurrent(context); | 130 | 130 | BindingData* binding = env->AddBindingData<BindingData>(context, holder); | 131 | 131 | CHECK_NOT_NULL(binding); | 132 | 132 | } | 133 | 133 |
| 134 | 134 | InternalFieldInfo* BindingData::Serialize(int index) { | 135 | | - DCHECK_EQ(index, BaseObject::kSlot); | | 135 | + DCHECK_EQ(index, BaseObject::kEmbedderType); | 136 | 136 | InternalFieldInfo* info = InternalFieldInfo::New(type()); | 137 | 137 | return info; | 138 | 138 | } | |
|