GeezerVison is showing github.com — src: fix cppgc incompatibility in v8 · nodejs/node@8b0e5b1
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 |
|---|
@@ -1744,6 +1744,7 @@ void Environment::EnqueueDeserializeRequest(DeserializeRequestCallback cb, | 1744 | 1744 | Local<Object> holder, | 1745 | 1745 | int index, | 1746 | 1746 | InternalFieldInfo* info) { | | 1747 | + DCHECK_EQ(index, BaseObject::kEmbedderType); | 1747 | 1748 | DeserializeRequest request{cb, {isolate(), holder}, index, info}; | 1748 | 1749 | deserialize_requests_.push_back(std::move(request)); | 1749 | 1750 | } | @@ -2026,7 +2027,9 @@ void Environment::RunWeakRefCleanup() { | 2026 | 2027 | BaseObject::BaseObject(Environment* env, Local<Object> object) | 2027 | 2028 | : persistent_handle_(env->isolate(), object), env_(env) { | 2028 | 2029 | CHECK_EQ(false, object.IsEmpty()); | 2029 | | - CHECK_GT(object->InternalFieldCount(), 0); | | 2030 | + CHECK_GE(object->InternalFieldCount(), BaseObject::kInternalFieldCount); | | 2031 | + object->SetAlignedPointerInInternalField(BaseObject::kEmbedderType, | | 2032 | + &kNodeEmbedderId); | 2030 | 2033 | object->SetAlignedPointerInInternalField(BaseObject::kSlot, | 2031 | 2034 | static_cast<void*>(this)); | 2032 | 2035 | env->AddCleanupHook(DeleteMe, static_cast<void*>(this)); | @@ -2077,10 +2080,19 @@ void BaseObject::MakeWeak() { | 2077 | 2080 | WeakCallbackType::kParameter); | 2078 | 2081 | } | 2079 | 2082 |
| | 2083 | +// This just has to be different from the Chromium ones: | | 2084 | +// https://source.chromium.org/chromium/chromium/src/+/main:gin/public/gin_embedders.h;l=18-23;drc=5a758a97032f0b656c3c36a3497560762495501a | | 2085 | +// Otherwise, when Node is loaded in an isolate which uses cppgc, cppgc will | | 2086 | +// misinterpret the data stored in the embedder fields and try to garbage | | 2087 | +// collect them. | | 2088 | +uint16_t kNodeEmbedderId = 0x90de; | | 2089 | + | 2080 | 2090 | void BaseObject::LazilyInitializedJSTemplateConstructor( | 2081 | 2091 | const FunctionCallbackInfo<Value>& args) { | 2082 | 2092 | DCHECK(args.IsConstructCall()); | 2083 | | - DCHECK_GT(args.This()->InternalFieldCount(), 0); | | 2093 | + CHECK_GE(args.This()->InternalFieldCount(), BaseObject::kInternalFieldCount); | | 2094 | + args.This()->SetAlignedPointerInInternalField(BaseObject::kEmbedderType, | | 2095 | + &kNodeEmbedderId); | 2084 | 2096 | args.This()->SetAlignedPointerInInternalField(BaseObject::kSlot, nullptr); | 2085 | 2097 | } | 2086 | 2098 |
| |
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 |
|---|
@@ -467,7 +467,7 @@ void BlobBindingData::Deserialize( | 467 | 467 | Local<Object> holder, | 468 | 468 | int index, | 469 | 469 | InternalFieldInfo* info) { | 470 | | - DCHECK_EQ(index, BaseObject::kSlot); | | 470 | + DCHECK_EQ(index, BaseObject::kEmbedderType); | 471 | 471 | HandleScope scope(context->GetIsolate()); | 472 | 472 | Environment* env = Environment::GetCurrent(context); | 473 | 473 | BlobBindingData* binding = | @@ -482,7 +482,7 @@ void BlobBindingData::PrepareForSerialization( | 482 | 482 | } | 483 | 483 |
| 484 | 484 | InternalFieldInfo* BlobBindingData::Serialize(int index) { | 485 | | - DCHECK_EQ(index, BaseObject::kSlot); | | 485 | + DCHECK_EQ(index, BaseObject::kEmbedderType); | 486 | 486 | InternalFieldInfo* info = InternalFieldInfo::New(type()); | 487 | 487 | return info; | 488 | 488 | } | |
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 |
|---|
@@ -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 |
|---|
@@ -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 | } | |
|