Adding a new Object to V8 using Torque - v8
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:
Add a 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;
}
Add this file to BUILD.gn
I then tried to use this new type to add a member to an existing type (the abstract Name type):
Added a new member in src/objects/name.tq
Included 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 member
Changed the expected size of String objects in include/v8-interal.h to account for the new member
Added some macros to Name 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 #included 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:
when asking for programming help (anywhere!), provide reproducible code (in this case: your complete patch, not just a prose description of it).
when asking about compiler errors, provide the complete error message, not just a vague summary like "the errors complained about ...".
while you are of course free to fork V8 and muck with its internals, a word of caution: such modifications are likely to be very labor-intensive to maintain as you update to newer V8 versions (and you will want to update to newer V8 versions, if this isn't just some throwaway experiment). To make your work more future-proof, either attempt to upstream it (which might be difficult in this case, as increasing the size of 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.
Related
Can't OR 2 enum values of the same type outside its enum class declaration
I am a newbie to both C++ and game programming. I am dealing with something I don't know how to make it work. I am coding along a game from a book, the authors didn't use enum class for his type but as recommended by most people, I am using enum class to remake it. It produces no error when I OR 2 enum value inside its enum class scope like this: // This is inside the "Category.h" header file namespace Category { enum class Type { None = 0, SceneAirLayer = 1 << 0, PlayerAircraft = 1 << 1, AlliedAircraft = 1 << 2, EnemyAircraft = 1 << 3, Pickup = 1 << 4, AlliedProjectile = 1 << 5, EnemyProjectile = 1 << 6, Aircraft = PlayerAircraft | AlliedAircraft | EnemyAircraft, Projectile = AlliedProjectile | EnemyProjectile }; } But when I try to OR them inside a function of another source file, the compiler produces an error, that is: "no operator "|" matches these operands operand type are Category::Type | Category::Type" and here is the code inside that function (the game works for the authors version enum without class) void World::destroyEntitiesOutsideView() { // This "command.category" just returns an "unsigned int" value Command command; // The error appears here command.category = static_cast<unsigned int>(Category::Type::Projectile | Category::Type::EnemyAircraft); // This is I just try to OR them alone but still the same error Category::Type::Aircraft | Category::Type::AlliedProjectile; } Please someone tell me why and how can I fix this error??? Thank you a lot!!!
It is because you are using enum class instead of just enum. "Class enum doesn’t allow implicit conversion to int, and also doesn’t compare enumerators from different enumerations"
G2O BlockSolver Initialization Crash on Unix System
I have a project which possesses and uses G2O library, it runs on both platforms(win/Unix). (WINDOW PASSED / UNIX CRASHED) We can see in both platforms, these lines: g2o::SparseOptimizer optimizer; g2o::BlockSolver_6_3::LinearSolverType * linearSolver; linearSolver = new g2o::LinearSolverDense<g2o::BlockSolver_6_3::PoseMatrixType>(); Next steps, in window os we have this: g2o::BlockSolver_6_3 * solver_ptr = new g2o::BlockSolver_6_3(linearSolver); g2o::OptimizationAlgorithmLevenberg* solver = new g2o::OptimizationAlgorithmLevenberg(solver_ptr); But Unix system can't compile those lines because it says my_file_G2o.cpp: *In member function 'int Refiner_G2O::refinePose(cv::Mat&, const std::vector >&, const std::vector&, const cv::Mat&, float, std::vector&)': my_file_G2o.cpp --> no matching function for call to 'g2o::BlockSolver::BlockSolver(g2o::BlockSolver::LinearSolverType&)'* ^ In file included from G2o/include/g2o/core/block_solver.h:199:0, G2o/include/g2o/core/block_solver.hpp:40:1: note: candidate: g2o::BlockSolver::BlockSolver(std::unique_ptr) [with Traits = g2o::BlockSolverTraits<6, 3>; typename Traits::LinearSolverType = g2o::LinearSolver >] BlockSolver::BlockSolver(std::unique_ptr linearSolver) When I see these errors, I complete my Unix code with this new block auto solver_ptr = g2o::make_unique<g2o::BlockSolver_6_3>(linearSolver); // [SEGFAULT LINE] auto solver = g2o::make_unique<g2o::OptimizationAlgorithmLevenberg>(solver_ptr); optimizer.setAlgorithm(solver.get()); So now, I can build/run but I meet a segfault on the line with [SEGFAULT LINE] tag. EDIT: After step to step debug with debug build I have a few news pieces of information: g2o::SparseOptimizer optimizer; // debug says: "optimize: g2o::SparseOptimize g2o::BlockSolver_6_3::LinearSolverType * linearSolver = NULL; // debug says : linearSolver: NULL linearSolver = new g2o::LinearSolverDense<g2o::BlockSolver_6_3::PoseMatrixType>(); // debug says: linear solver: 0x7fe39cba9140 if (linearSolver == NULL) // debug says : not null. exit (84); auto solver_ptr = g2o::make_unique<g2o::BlockSolver< g2o::BlockSolver_6_3 >>(linearSolver); // DEBUG --> And here, with "step into" he go to this "/usr/include/c++/6/bits/move.h" and in the ligne 48 we can see this function: `template<typename T, typename ...ArgTs> std::unique_ptr<T> make_unique(ArgTs&& ...args) //DEBUG says: args#0: -var-create: unable to create variable object. { return std::unique_ptr<T>(g2o::make_unique<T>(std::forward<ArgTs> (args)...)); };` And he segfault because she have a bad args. I don't understand, why? if someone has an idea I want to understand how in Window it works and not in Unix system, will feel wonderful if you help. LINUX Version: Ubuntu 16.04 CMAKE Version: 3.11.4 Best regards,
SOLVED: G2O optimise: g2o::SparseOptimizer optimizer; auto linearSolver = std::make_unique<g2o::LinearSolverDense<g2o::BlockSolver_6_3::PoseMatrixType>>(); auto solver = new g2o::OptimizationAlgorithmLevenberg(std::make_unique<g2o::BlockSolver_6_3>(std::move(linearSolver))); optimizer.setAlgorithm(solver); MISC.H: template<typename T, typename ...ArgTs> std::unique_ptr<T> make_unique(ArgTs&& ...args) { return std::unique_ptr<T>(new T(std::forward<ArgTs>(args)...)); };
How to create a global variable in ATS?
Basically, I am looking for something more or less equivalent to the following C code: int theGlobalCount = 0; int theGlobalCount_get() { return theGlobalCount; } void theGlobalCount_set(int n) { theGlobalCount = n; return; }
You could use a neat trick: declare a mutable global variable, and make a ref (aka mutable reference) point to it (no GC is required to make this work!). Then, implement functions to provide access to the mutable reference. local var theGlobalCount_var : int = 0 val theGlobalCount = ref_make_viewptr (view# theGlobalCount_var | addr# theGlobalCount_var) in // in of [local] fun theGlobalCount_get () : int = ref_get_elt (theGlobalCount) fun theGlobalCount_set (n: int): void = ref_set_elt (theGlobalCount, n) end // end of [local] Note that declarations inside local-in are visible only to code inside in-end. Therefore, neither theGlobalCount_var nor theGlobalCount are visible outside the scope of the local. Full code: glot.io
You can also use the extvar feature to update an external global variable (declared in the target language). This is very useful if you compile ATS to a language that does not support explicit pointers (e.g., JavaScript). Here is a running example that makes use of this feature: http://www.ats-lang.org/SERVER/MYCODE/Patsoptaas_serve.php?mycode_url=http://pastebin.com/raw/MsXhVE0A
F# compiler requires project reference, but method is private
The F# compiler gives an error saying I must add a project reference because the type I'm using has a method argument that lives in that project. But this method is private! I have the following project structure: Program -> Library -> SubLibrary SubLibrary contains this: namespace SubLibrary type Widget = { Value: int } Library contains this: namespace Library open SubLibrary type Banana = { Value: int } member private x.TakeWidget (w: Widget) = () Program contains this: open Library [<EntryPoint>] let main argv = printfn "%A" argv let banana = { Value = 42 } 0 I get this error: error FS0074: The type referenced through 'SubLibrary.Widget' is defined in an assembly that is not referenced. You must add a reference to assembly 'SubLibrary' But the TakeWidget method is private! I tried changing Banana into a class, rather than a record, but that made no difference. As an experiment, I created a C# version of Library, called CLibrary: using SubLibrary; namespace CLibrary { public class CBanana { int m_value; public CBanana(int value) { m_value = value; } private void TakeWidget(Widget w) { } } } Then I changed Program to use CBanana instead of Banana: open Library [<EntryPoint>] let main argv = printfn "%A" argv let banana = CBanana 42 0 Now I don't get an error. In fact, with C# I can make that method public, and so long as I don't try to compile a call to it, there is no error. Why is the compiler insisting I add a reference to SubLibrary? Sure, I could just go ahead and do what it tells me to do, for a quiet life, but SubLibrary is a private implementation detail of Library, which should not be exposed to Program.
Actually, when I tried with a class instead of record, it did the trick (F# 3.1): type BananaClass (value:int) = member private x.TakeWidget (w: Widget) = () member x.Value = value You can work around it with a record as well - you need to move the private member into a separate module and have it as a type augmentation: type Banana = { Value: int } module Ext = type Banana with member x.TakeWidget (w: Widget) = () Compiler won't complain about the missing dependency until you open the Ext module. I don't have a good idea why the compiler was complaining in the first place. Probably one of its quirks. I couldn't find anything seriously suspicious in the generated IL (other than a surprising fact that F# compiler marks both private and internal members as internal in the IL - this turned out to be of no consequence here).
Indeed this to me looks like an error I have raised an issue here, https://github.com/Microsoft/visualfsharp/issues/86. So you'll be able to track feedback from there.
C++ lambdas in Visual Studio 2013: capturing this pointer
Looks like if lambda is defined inside a member function and this is captured then inside lambda all class members can be accesses without using this keyword, that is I can do some_class_field = .... instead of this->some_class_field = .... Is it portable behavior or specific to Visual Studio? Thanks.
It is expected : § 5.1.2 paragraph 7 The lambda-expression’s compound-statement yields the function-body (8.4) of the function call operator, but for purposes of name lookup (3.4), determining the type and value of this (9.3.2) and transforming idexpressions referring to non-static class members into class member access expressions using (*this) (9.3.1), the compound-statement is considered in the context of the lambda-expression. [ Example: struct S1 { int x, y; int operator()(int); void f() { [=]()->int { return operator()(this->x + y); // equivalent to S1::operator()(this->x + (*this).y) // this has type S1* }; } };