GeezerVison is showing github.com — src: fix cppgc incompatibility in v8 · nodejs/node@c51d85e
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 |
|---|
@@ -1884,6 +1884,7 @@ void Environment::EnqueueDeserializeRequest(DeserializeRequestCallback cb, | 1884 | 1884 | Local<Object> holder, | 1885 | 1885 | int index, | 1886 | 1886 | InternalFieldInfo* info) { | | 1887 | + DCHECK_EQ(index, BaseObject::kEmbedderType); | 1887 | 1888 | DeserializeRequest request{cb, {isolate(), holder}, index, info}; | 1888 | 1889 | deserialize_requests_.push_back(std::move(request)); | 1889 | 1890 | } | @@ -2166,7 +2167,9 @@ void Environment::RunWeakRefCleanup() { | 2166 | 2167 | BaseObject::BaseObject(Environment* env, Local<Object> object) | 2167 | 2168 | : persistent_handle_(env->isolate(), object), env_(env) { | 2168 | 2169 | CHECK_EQ(false, object.IsEmpty()); | 2169 | | - CHECK_GT(object->InternalFieldCount(), 0); | | 2170 | + CHECK_GE(object->InternalFieldCount(), BaseObject::kInternalFieldCount); | | 2171 | + object->SetAlignedPointerInInternalField(BaseObject::kEmbedderType, | | 2172 | + &kNodeEmbedderId); | 2170 | 2173 | object->SetAlignedPointerInInternalField(BaseObject::kSlot, | 2171 | 2174 | static_cast<void*>(this)); | 2172 | 2175 | env->AddCleanupHook(DeleteMe, static_cast<void*>(this)); | @@ -2217,10 +2220,19 @@ void BaseObject::MakeWeak() { | 2217 | 2220 | WeakCallbackType::kParameter); | 2218 | 2221 | } | 2219 | 2222 |
| | 2223 | +// This just has to be different from the Chromium ones: | | 2224 | +// https://source.chromium.org/chromium/chromium/src/+/main:gin/public/gin_embedders.h;l=18-23;drc=5a758a97032f0b656c3c36a3497560762495501a | | 2225 | +// Otherwise, when Node is loaded in an isolate which uses cppgc, cppgc will | | 2226 | +// misinterpret the data stored in the embedder fields and try to garbage | | 2227 | +// collect them. | | 2228 | +uint16_t kNodeEmbedderId = 0x90de; | | 2229 | + | 2220 | 2230 | void BaseObject::LazilyInitializedJSTemplateConstructor( | 2221 | 2231 | const FunctionCallbackInfo<Value>& args) { | 2222 | 2232 | DCHECK(args.IsConstructCall()); | 2223 | | - DCHECK_GT(args.This()->InternalFieldCount(), 0); | | 2233 | + CHECK_GE(args.This()->InternalFieldCount(), BaseObject::kInternalFieldCount); | | 2234 | + args.This()->SetAlignedPointerInInternalField(BaseObject::kEmbedderType, | | 2235 | + &kNodeEmbedderId); | 2224 | 2236 | args.This()->SetAlignedPointerInInternalField(BaseObject::kSlot, nullptr); | 2225 | 2237 | } | 2226 | 2238 |
| |
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 |
|---|
@@ -464,7 +464,7 @@ void BlobBindingData::Deserialize( | 464 | 464 | Local<Object> holder, | 465 | 465 | int index, | 466 | 466 | InternalFieldInfo* info) { | 467 | | - DCHECK_EQ(index, BaseObject::kSlot); | | 467 | + DCHECK_EQ(index, BaseObject::kEmbedderType); | 468 | 468 | HandleScope scope(context->GetIsolate()); | 469 | 469 | Environment* env = Environment::GetCurrent(context); | 470 | 470 | BlobBindingData* binding = | @@ -479,7 +479,7 @@ void BlobBindingData::PrepareForSerialization( | 479 | 479 | } | 480 | 480 |
| 481 | 481 | InternalFieldInfo* BlobBindingData::Serialize(int index) { | 482 | | - DCHECK_EQ(index, BaseObject::kSlot); | | 482 | + DCHECK_EQ(index, BaseObject::kEmbedderType); | 483 | 483 | InternalFieldInfo* info = InternalFieldInfo::New(type()); | 484 | 484 | return info; | 485 | 485 | } | |
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 |
|---|
@@ -2401,7 +2401,7 @@ void BindingData::Deserialize(Local<Context> context, | 2401 | 2401 | Local<Object> holder, | 2402 | 2402 | int index, | 2403 | 2403 | InternalFieldInfo* info) { | 2404 | | - DCHECK_EQ(index, BaseObject::kSlot); | | 2404 | + DCHECK_EQ(index, BaseObject::kEmbedderType); | 2405 | 2405 | HandleScope scope(context->GetIsolate()); | 2406 | 2406 | Environment* env = Environment::GetCurrent(context); | 2407 | 2407 | BindingData* binding = env->AddBindingData<BindingData>(context, holder); | @@ -2418,7 +2418,7 @@ void BindingData::PrepareForSerialization(Local<Context> context, | 2418 | 2418 | } | 2419 | 2419 |
| 2420 | 2420 | InternalFieldInfo* BindingData::Serialize(int index) { | 2421 | | - DCHECK_EQ(index, BaseObject::kSlot); | | 2421 | + DCHECK_EQ(index, BaseObject::kEmbedderType); | 2422 | 2422 | InternalFieldInfo* info = InternalFieldInfo::New(type()); | 2423 | 2423 | return info; | 2424 | 2424 | } | |
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 |
|---|
@@ -531,7 +531,7 @@ void BindingData::PrepareForSerialization(Local<Context> context, | 531 | 531 | } | 532 | 532 |
| 533 | 533 | InternalFieldInfo* BindingData::Serialize(int index) { | 534 | | - DCHECK_EQ(index, BaseObject::kSlot); | | 534 | + DCHECK_EQ(index, BaseObject::kEmbedderType); | 535 | 535 | InternalFieldInfo* info = InternalFieldInfo::New(type()); | 536 | 536 | return info; | 537 | 537 | } | @@ -540,7 +540,7 @@ void BindingData::Deserialize(Local<Context> context, | 540 | 540 | Local<Object> holder, | 541 | 541 | int index, | 542 | 542 | InternalFieldInfo* info) { | 543 | | - DCHECK_EQ(index, BaseObject::kSlot); | | 543 | + DCHECK_EQ(index, BaseObject::kEmbedderType); | 544 | 544 | v8::HandleScope scope(context->GetIsolate()); | 545 | 545 | Environment* env = Environment::GetCurrent(context); | 546 | 546 | // 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 |
|---|
@@ -1089,10 +1089,20 @@ void DeserializeNodeInternalFields(Local<Object> holder, | 1089 | 1089 | static_cast<int>(index), | 1090 | 1090 | (*holder), | 1091 | 1091 | static_cast<int>(payload.raw_size)); | | 1092 | + | | 1093 | + if (payload.raw_size == 0) { | | 1094 | + holder->SetAlignedPointerInInternalField(index, nullptr); | | 1095 | + return; | | 1096 | + } | | 1097 | + | | 1098 | + DCHECK_EQ(index, BaseObject::kEmbedderType); | | 1099 | + | 1092 | 1100 | Environment* env_ptr = static_cast<Environment*>(env); | 1093 | 1101 | const InternalFieldInfo* info = | 1094 | 1102 | reinterpret_cast<const InternalFieldInfo*>(payload.data); | 1095 | | - | | 1103 | + // TODO(joyeecheung): we can add a constant kNodeEmbedderId to the | | 1104 | + // beginning of every InternalFieldInfo to ensure that we don't | | 1105 | + // step on payloads that were not serialized by Node.js. | 1096 | 1106 | switch (info->type) { | 1097 | 1107 | #define V(PropertyName, NativeTypeName) \ | 1098 | 1108 | case EmbedderObjectType::k_##PropertyName: { \ | @@ -1113,21 +1123,44 @@ void DeserializeNodeInternalFields(Local<Object> holder, | 1113 | 1123 | StartupData SerializeNodeContextInternalFields(Local<Object> holder, | 1114 | 1124 | int index, | 1115 | 1125 | void* env) { | 1116 | | - void* ptr = holder->GetAlignedPointerFromInternalField(BaseObject::kSlot); | 1117 | | - if (ptr == nullptr) { | | 1126 | + // We only do one serialization for the kEmbedderType slot, the result | | 1127 | + // contains everything necessary for deserializing the entire object, | | 1128 | + // including the fields whose index is bigger than kEmbedderType | | 1129 | + // (most importantly, BaseObject::kSlot). | | 1130 | + // For Node.js this design is enough for all the native binding that are | | 1131 | + // serializable. | | 1132 | + if (index != BaseObject::kEmbedderType) { | | 1133 | + return StartupData{nullptr, 0}; | | 1134 | + } | | 1135 | + | | 1136 | + void* type_ptr = holder->GetAlignedPointerFromInternalField(index); | | 1137 | + if (type_ptr == nullptr) { | | 1138 | + return StartupData{nullptr, 0}; | | 1139 | + } | | 1140 | + | | 1141 | + uint16_t type = *(static_cast<uint16_t*>(type_ptr)); | | 1142 | + per_process::Debug(DebugCategory::MKSNAPSHOT, "type = 0x%x\n", type); | | 1143 | + if (type != kNodeEmbedderId) { | 1118 | 1144 | return StartupData{nullptr, 0}; | 1119 | 1145 | } | | 1146 | + | 1120 | 1147 | per_process::Debug(DebugCategory::MKSNAPSHOT, | 1121 | 1148 | "Serialize internal field, index=%d, holder=%p\n", | 1122 | 1149 | static_cast<int>(index), | 1123 | 1150 | *holder); | 1124 | | - DCHECK(static_cast<BaseObject*>(ptr)->is_snapshotable()); | 1125 | | - SnapshotableObject* obj = static_cast<SnapshotableObject*>(ptr); | | 1151 | + | | 1152 | + void* binding_ptr = | | 1153 | + holder->GetAlignedPointerFromInternalField(BaseObject::kSlot); | | 1154 | + per_process::Debug(DebugCategory::MKSNAPSHOT, "binding = %p\n", binding_ptr); | | 1155 | + DCHECK(static_cast<BaseObject*>(binding_ptr)->is_snapshotable()); | | 1156 | + SnapshotableObject* obj = static_cast<SnapshotableObject*>(binding_ptr); | | 1157 | + | 1126 | 1158 | per_process::Debug(DebugCategory::MKSNAPSHOT, | 1127 | 1159 | "Object %p is %s, ", | 1128 | 1160 | *holder, | 1129 | 1161 | obj->GetTypeNameChars()); | 1130 | 1162 | InternalFieldInfo* info = obj->Serialize(index); | | 1163 | + | 1131 | 1164 | per_process::Debug(DebugCategory::MKSNAPSHOT, | 1132 | 1165 | "payload size=%d\n", | 1133 | 1166 | static_cast<int>(info->length)); | @@ -1142,8 +1175,9 @@ void SerializeBindingData(Environment* env, | 1142 | 1175 | env->ForEachBindingData([&](FastStringKey key, | 1143 | 1176 | BaseObjectPtr<BaseObject> binding) { | 1144 | 1177 | per_process::Debug(DebugCategory::MKSNAPSHOT, | 1145 | | - "Serialize binding %i, %p, type=%s\n", | | 1178 | + "Serialize binding %i (%p), object=%p, type=%s\n", | 1146 | 1179 | static_cast<int>(i), | | 1180 | + binding.get(), | 1147 | 1181 | *(binding->object()), | 1148 | 1182 | key.c_str()); | 1149 | 1183 |
| |
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 | } | |
|