TL;DR: I tried adding a new Object defined exclusively in Torque and use it as a new member for the Name
class. This resulted in compilation failures due to function used but never defined errors, pertaining to a function that IS defined in torque-generated files, however for some reason not properly included.
I am unsure how to proceed and trying to just include different combinations of the torque-generated files in the appropriate locations simply led to redefinition errors.
The question: Is it possible to define a new object and use it in the way I intend to, without adding C++ class definitions (that inherit from the torque-generated classes and so forth) and if yes, where do I seem to be going wrong. In the following I will describe the steps I took so far:
myClass.tq/
file to src/objects
that includes a definition of my class along the lines of:@export
@generateBodyDescriptors
class MyClass extends HeapObject {
macro SomeMacro(): Boolean {...}
macro Set(): void { this.i = 1 }
i: uint32;
}
BUILD.gn
I then tried to use this new type to add a member to an existing type (the abstract Name
type):
src/objects/name.tq
torque-generated/src/objects/myClass.tq
in src/objects/name.h
String
inherits from Name
so i had to modify two "constructors" methods in src/objects/string.tq
to include the new memberString
objects in include/v8-interal.h
to account for the new memberName
that actually use the new member (check if its internal uint is non-zero and set the value to one)And lastly I added two methods to the String prototype that I defined as javascript builtins, so that I can verify my changes work.
Concretely, the resulting errors complained about the TorqueGeneratedMyClass::cast(Object)
method being used but never defined. This error results from the myClass-tq.inc
file. However, the method is defined, in the corresponding myClass-tq-inl.inc
file.
I'm not sure if I described the issue concretely enough, but I'm happy to clarify uncertainties and appreciate every help.
Edit:
Complete Changes:
// 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",
Error:
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
Yes.
where do I seem to be going wrong
This part seems suspicious:
the method is defined, in the corresponding myClass-tq-inl.inc file
All generated *.inc files have to be #include
d somewhere. There's likely some *.cc
file that needs it (you didn't provide enough details, so I can't tell for sure).
A couple of more general points:
Name
objects will be an unpopular proposition, I expect), or use only the public API (which isn't perfectly stable, but much more stable than random internals). Of course, the latter won't allow you to modify internally used objects; since you didn't describe your higher-level goal I can't tell whether that's a dealbreaker or whether there could be alternative approaches.