使用 Torque 将新对象添加到 V8

Adding a new Object to V8 using Torque

TL;DR:我尝试添加一个专门在 Torque 中定义的新对象,并将其用作 Name class 的新成员。由于 function used but never defined 错误导致编译失败,与 IS 在扭矩生成的文件中定义的函数有关,但是对于某些未正确包含原因。

我不确定如何继续并试图在适当的位置包含扭矩生成文件的不同组合只会导致 重新定义 错误。

问题:是否可以定义一个新对象并按我打算的方式使用它,而不添加 C++ class 定义(继承自扭矩产生的 classes 等等),如果是,我似乎哪里出错了。在下文中,我将描述到目前为止我采取的步骤:

@export
@generateBodyDescriptors
class MyClass extends HeapObject {
    macro SomeMacro(): Boolean {...}
    macro Set(): void { this.i = 1 }
    i: uint32;
}

然后我尝试使用这个新类型将成员添加到现有类型(抽象 Name 类型):

最后,我将两个方法添加到我定义为 javascript 内置函数的字符串原型中,以便我可以验证我的更改是否有效。

具体来说,由此产​​生的错误抱怨正在使用但从未定义的 TorqueGeneratedMyClass::cast(Object) 方法。此错误是由 myClass-tq.inc 文件引起的。然而,方法 在相应的 myClass-tq-inl.inc 文件中定义的。

我不确定我是否足够具体地描述了这个问题,但我很乐意澄清不确定性并感谢您的帮助。

编辑:

完成更改:

// src/objects/myClass.tq
@export
@generateBodyDescriptors
class MyClass extends HeapObject {
    macro IsSet(): Boolean {
        return this.i == 0 ? False : True;
    }
    macro Set(): void { this.i = 1 }
    i: uint32;
}

// src/objects/name.h

@@ -16,6 +17,7 @@
 namespace v8 {
 namespace internal {

+#include "torque-generated/src/objects/taint-tq.inc"
 #include "torque-generated/src/objects/name-tq.inc"

// src/objects/name.tq
@@ -4,7 +4,18 @@

 @abstract
 extern class Name extends PrimitiveHeapObject {
+  macro IsSet(): Boolean {
+    return this.test.IsSet();
+  }
+
+  macro Set(): void {
+    this.test.Set();
+  }
+
+  test: MyClass;
   raw_hash_field: NameHash;

}

// src/objects/string.tq
@@ -135,7 +135,10 @@ macro AllocateNonEmptySeqOneByteString<Iterator: type>(
   dcheck(length != 0 && length <= kStringMaxLength);
   return new SeqOneByteString{
     map: kOneByteStringMap,
+    test: new StringTaint{tainted: 0},
     raw_hash_field: kNameEmptyHashField,
     length: Signed(length),
     chars: ...content
   };
@@ -146,7 +149,10 @@ macro AllocateNonEmptySeqTwoByteString<Iterator: type>(
   dcheck(length > 0 && length <= kStringMaxLength);
   return new SeqTwoByteString{
     map: kStringMap,
+    test: new StringTaint{tainted: 0},
     raw_hash_field: kNameEmptyHashField,
     length: Signed(length),
     chars: ...content
   };

// src/builtins/string-test.tq

namespace string {
    transitioning javascript builtin StringPrototypeIsSet(js-implicit context: NativeContext, receiver: JSAny)(): Boolean {
        const string: String = ToThisString(receiver, 'String.prototype.testIsSet');
        return string.IsSet();
    }

    transitioning javascript builtin StringPrototypeSet(js-implicit context: NativeContext, receiver: JSAny)(): JSAny {
        const string: String = ToThisString(receiver, 'String.prototype.testSet');
        string.Set();

        return Undefined;
    }
}

// src/init/bootstrapper.cc

@@ -2078,6 +2078,10 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
                           Builtin::kStringPrototypeSup, 0, false);
     SimpleInstallFunction(isolate_, prototype, "startsWith",
                           Builtin::kStringPrototypeStartsWith, 1, false);
+    SimpleInstallFunction(isolate_, prototype, "testSet",
+                          Builtin::kStringPrototypeTaint, 0, true);
+    SimpleInstallFunction(isolate_, prototype, "testIsSet",
+                          Builtin::kStringPrototypeIsTainted, 0, true);
     SimpleInstallFunction(isolate_, prototype, "toString",
                           Builtin::kStringPrototypeToString, 0, true);
     SimpleInstallFunction(isolate_, prototype, "trim",

// BUILD.gn

@@ -1698,6 +1698,7 @@ torque_files = [
   "src/builtins/string-startswith.tq",
   "src/builtins/string-substr.tq",
   "src/builtins/string-substring.tq",
+  "src/builtins/string-test.tq",
   "src/builtins/string-trim.tq",
   "src/builtins/symbol.tq",
   "src/builtins/torque-internal.tq",
@@ -1781,6 +1782,7 @@ torque_files = [
   "src/objects/swiss-hash-table-helpers.tq",
   "src/objects/swiss-name-dictionary.tq",
   "src/objects/synthetic-module.tq",
+  "src/objects/myClass.tq",
   "src/objects/template-objects.tq",
   "src/objects/templates.tq",
   "src/objects/torque-defined-classes.tq",

错误:

In file included from ../deps/v8/src/objects/name.h:20,
                 from ../deps/v8/src/objects/string.h:15,
                 from ../deps/v8/src/heap/factory.h:25,
                 from ../deps/v8/src/execution/isolate.h:33,
                 from ../deps/v8/src/logging/log.h:16,
                 from ../deps/v8/src/heap/base-space.h:12,
                 from ../deps/v8/src/heap/spaces.h:16,
                 from ../deps/v8/src/heap/marking-visitor.h:13,
                 from ../deps/v8/src/heap/concurrent-marking.h:14,
                 from ../deps/v8/src/heap/concurrent-marking.cc:5:
/home/ccloud/sap_node/out/Release/obj/gen/torque-generated/src/objects/myClass-tq.inc:26:22: warning: inline function ‘static D v8::internal::TorqueGeneratedMyClass<D, P>::cast(v8::internal::Object) [with D = v8::internal::MyClass; P = v8::internal::HeapObject]’ used but never defined
   26 |   V8_INLINE static D cast(Object object);
      |                      ^~~~
/home/ccloud/sap_node/out/Release/obj/gen/torque-generated/src/objects/myClass-tq.inc: In static member function ‘static T v8::internal::ConcurrentMarkingVisitor::Cast(v8::internal::HeapObject) [with T = v8::internal::MyClass]’:
/home/ccloud/sap_node/out/Release/obj/gen/torque-generated/src/objects/myClass-tq.inc:26:22: error: inlining failed in call to always_inline ‘static D v8::internal::TorqueGeneratedMyClass<D, P>::cast(v8::internal::Object) [with D = v8::internal::MyClass; P = v8::internal::HeapObject]’: function body not available
../deps/v8/src/heap/concurrent-marking.cc:103:19: note: called from here
  103 |     return T::cast(object);
      |            ~~~~~~~^~~~~~~~
make[1]: *** [tools/v8_gypfiles/v8_base_without_compiler.target.mk:1000: /home/ccloud/sap_node/out/Release/obj.target/v8_base_without_compiler/deps/v8/src/heap/concurrent-marking.o] Error 1
make[1]: *** Waiting for unfinished jobs....
In file included from ../deps/v8/src/objects/name.h:20,
                 from ../deps/v8/src/objects/string.h:15,
                 from ../deps/v8/src/heap/factory.h:25,
                 from ../deps/v8/src/execution/isolate.h:33,
                 from ../deps/v8/src/common/ptr-compr-inl.h:10,
                 from ../deps/v8/src/execution/isolate-utils-inl.h:8,
                 from ../deps/v8/src/diagnostics/objects-printer.cc:11:
/home/ccloud/sap_node/out/Release/obj/gen/torque-generated/src/objects/myClass-tq.inc:26:22: warning: inline function ‘static D v8::internal::TorqueGeneratedMyClass<D, P>::cast(v8::internal::Object) [with D = v8::internal::MyClass; P = v8::internal::HeapObject]’ used but never defined
   26 |   V8_INLINE static D cast(Object object);
      |                      ^~~~
/home/ccloud/sap_node/out/Release/obj/gen/torque-generated/src/objects/myClass-tq.inc: In member function ‘void v8::internal::HeapObject::HeapObjectPrint(std::ostream&)’:
/home/ccloud/sap_node/out/Release/obj/gen/torque-generated/src/objects/myClass-tq.inc:26:22: error: inlining failed in call to always_inline ‘static D v8::internal::TorqueGeneratedMyClass<D, P>::cast(v8::internal::Object) [with D = v8::internal::MyClass; P = v8::internal::HeapObject]’: function body not available
../deps/v8/src/diagnostics/objects-printer.cc:216:21: note: called from here
  216 |     Name::cast(*this).Name##Print(os); \
      |                     ^
/home/ccloud/sap_node/out/Release/obj/gen/torque-generated/instance-types.h:637:3: note: in expansion of macro ‘MAKE_TORQUE_CASE’
  637 |   V(MyClass, MY_CLASS_TYPE) /* src/objects/myClass.tq?l=1&c=1 */ \
      |   ^
../deps/v8/src/diagnostics/objects-printer.cc:220:7: note: in expansion of macro ‘TORQUE_INSTANCE_CHECKERS_SINGLE_FULLY_DEFINED’
  220 |       TORQUE_INSTANCE_CHECKERS_SINGLE_FULLY_DEFINED(MAKE_TORQUE_CASE)
      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from ../deps/v8/src/objects/name.h:20,
                 from ../deps/v8/src/objects/string.h:15,
                 from ../deps/v8/src/heap/factory.h:25,
                 from ../deps/v8/src/execution/isolate.h:33,
                 from ../deps/v8/src/common/ptr-compr-inl.h:10,
                 from ../deps/v8/src/execution/isolate-utils-inl.h:8,
                 from ../deps/v8/src/diagnostics/objects-printer.cc:11:
/home/ccloud/sap_node/out/Release/obj/gen/torque-generated/src/objects/myClass-tq.inc:26:22: error: inlining failed in call to always_inline ‘static D v8::internal::TorqueGeneratedMyClass<D, P>::cast(v8::internal::Object) [with D = v8::internal::MyClass; P = v8::internal::HeapObject]’: function body not available
   26 |   V8_INLINE static D cast(Object object);
      |                      ^~~~
../deps/v8/src/diagnostics/objects-printer.cc:216:21: note: called from here
  216 |     Name::cast(*this).Name##Print(os); \
      |                     ^
/home/ccloud/sap_node/out/Release/obj/gen/torque-generated/instance-types.h:637:3: note: in expansion of macro ‘MAKE_TORQUE_CASE’
  637 |   V(MyClass, MY_CLASS_TYPE) /* src/objects/myClass.tq?l=1&c=1 */ \
      |   ^
../deps/v8/src/diagnostics/objects-printer.cc:220:7: note: in expansion of macro ‘TORQUE_INSTANCE_CHECKERS_SINGLE_FULLY_DEFINED’
  220 |       TORQUE_INSTANCE_CHECKERS_SINGLE_FULLY_DEFINED(MAKE_TORQUE_CASE)
      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Is it possible to define a new object and use it in the way I intend to, without adding C++ class definitions

是的。

where do I seem to be going wrong

这部分看起来很可疑:

the method is defined, in the corresponding myClass-tq-inl.inc file

所有生成的 *.inc 文件都必须 #included 在某处。可能有一些 *.cc 文件需要它(您没有提供足够的详细信息,所以我不能确定)。


几个更一般的要点:

  • 当寻求编程帮助(任何地方!)时,提供可重现的代码(在这种情况下:您的完整补丁,而不仅仅是它的散文描述)。
  • 询问编译器错误时,请提供完整的错误消息,而不仅仅是像“错误抱怨...”这样的模糊摘要。
  • 虽然您当然可以自由地分叉 V8 并破坏其内部结构,但请注意:当您更新到较新的 V8 版本时,此类修改可能非常 labor-intensive 需要维护(并且您 想要更新到更新的 V8 版本,如果这不仅仅是一些一次性实验)。为了使您的工作更多 future-proof,要么尝试将其向上游(在这种情况下这可能很困难,因为增加 Name 对象的大小将是一个不受欢迎的提议,我预计),或者仅使用public API(不是完全稳定,但 比随机内部更稳定)。当然,后者不允许您修改内部使用的对象;由于您没有描述您的 higher-level 目标,我无法判断这是否会破坏交易或是否有其他方法。