| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 70bb6a3 commit c51d85e
8 files changed
| 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; | |
| 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 | ||
| 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 | } | |
| 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 | } | |
| 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. | |
| 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 | ||
| 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) | |
| 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 | } | |
| Back | FazBrowse Home | New Git URL |
0 commit comments