BioDynaMo  v1.05.119-a4ff3934
jit.cc
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------
2 //
3 // Copyright (C) 2021 CERN & University of Surrey for the benefit of the
4 // BioDynaMo collaboration. All Rights Reserved.
5 //
6 // Licensed under the Apache License, Version 2.0 (the "License");
7 // you may not use this file except in compliance with the License.
8 //
9 // See the LICENSE file distributed with this work for details.
10 // See the NOTICE file distributed with this work for additional information
11 // regarding copyright ownership.
12 //
13 // -----------------------------------------------------------------------------
14 
15 #include <filesystem>
16 #include <stack>
17 
18 #include <TClass.h>
19 #include <TClassTable.h>
20 #include <TDataMember.h>
21 #include <TInterpreter.h>
22 #include <TList.h>
23 
24 #include "core/util/jit.h"
25 #include "core/util/log.h"
26 #include "core/util/string.h"
27 
28 namespace bdm {
29 
30 // -----------------------------------------------------------------------------
31 std::vector<TClass*> FindClassSlow(const std::string& class_name) {
32  bool cn_has_scope = class_name.find("::") != std::string::npos;
33  std::string cn_with_scope_prefix = std::string("::") + class_name;
34  char* current = 0;
35  uint64_t idx = 0;
36  std::vector<TClass*> tclasses;
37  while ((current = TClassTable::At(idx++)) != nullptr) {
38  std::string scurrent(current);
39  if (scurrent.find("::") == std::string::npos) {
40  // current does not contain a scope operator -> full match
41  if (std::string(current).compare(class_name) == 0) {
42  tclasses.push_back(TClassTable::GetDict(current)());
43  }
44  } else {
45  if (cn_has_scope) {
46  if (EndsWith(scurrent, class_name)) {
47  tclasses.push_back(TClassTable::GetDict(current)());
48  }
49  } else {
50  if (EndsWith(scurrent, cn_with_scope_prefix)) {
51  tclasses.push_back(TClassTable::GetDict(current)());
52  }
53  }
54  }
55  }
56  return tclasses;
57 }
58 
59 // -----------------------------------------------------------------------------
60 std::vector<TDataMember*> FindDataMemberSlow(TClass* tclass,
61  const std::string& data_member) {
62  std::vector<TDataMember*> ret_val;
63 
64  bool dm_has_scope = data_member.find("::") != std::string::npos;
65  std::string class_name = "";
66  std::string dm_only_name = data_member;
67  if (dm_has_scope) {
68  auto idx = data_member.find_last_of("::");
69  class_name = data_member.substr(0, idx - 1);
70  dm_only_name = data_member.substr(idx + 1, data_member.size());
71  }
72 
73  std::stack<TClass*> tc_stack;
74  tc_stack.push(tclass);
75 
76  while (tc_stack.size() != 0) {
77  auto* current_tc = tc_stack.top();
78  tc_stack.pop();
79  for (const auto&& base : *current_tc->GetListOfBases()) {
80  auto get_dict_functor = TClassTable::GetDict(base->GetName());
81  if (get_dict_functor != nullptr) {
82  tc_stack.push(get_dict_functor());
83  }
84  }
85 
86  for (int i = 0; i < current_tc->GetListOfDataMembers()->GetSize(); ++i) {
87  auto* dm =
88  static_cast<TDataMember*>(current_tc->GetListOfDataMembers()->At(i));
89  if (dm_has_scope) {
90  if (dm_only_name.compare(dm->GetName()) == 0 &&
91  EndsWith(std::string(current_tc->GetName()), class_name)) {
92  ret_val.push_back(dm);
93  }
94  } else {
95  if (data_member.compare(dm->GetName()) == 0) {
96  ret_val.push_back(dm);
97  }
98  }
99  }
100  }
101 
102  return ret_val;
103 }
104 
105 // -----------------------------------------------------------------------------
107  TClass* tclass, const std::vector<std::string>& dm_names,
108  const std::string& functor_name,
109  const std::function<std::string(
110  const std::string&, const std::vector<TDataMember*>&)>& code_generator)
111  : functor_name_(Concat(functor_name, counter_++)),
112  code_generator_(code_generator) {
113  data_members_.reserve(dm_names.size());
114  for (auto& dm : dm_names) {
115  auto candidates = FindDataMemberSlow(tclass, dm);
116  if (candidates.size() == 1) {
117  data_members_.push_back(candidates[0]);
118  } else if (candidates.size() == 0) {
119  Log::Fatal("JitForEachDataMemberFunctor::JitForEachDataMemberFunctor",
120  "Could not find data member ", dm);
121  } else {
122  Log::Fatal("JitForEachDataMemberFunctor::JitForEachDataMemberFunctor",
123  "Data member name (", dm, ") is ambiguous");
124  }
125  }
126 }
127 
128 // -----------------------------------------------------------------------------
131  gInterpreter->Declare(code_generator_(functor_name_, data_members_).c_str());
132 }
133 
134 // -----------------------------------------------------------------------------
135 void* JitForEachDataMemberFunctor::New(const std::string& parameter) {
136  auto cmd = Concat("#pragma cling optimize(3)\nnew bdm::", functor_name_, "(",
137  parameter, ")");
138  return reinterpret_cast<void*>(gInterpreter->Calc(cmd.c_str()));
139 }
140 
141 // -----------------------------------------------------------------------------
143 
144 // -----------------------------------------------------------------------------
145 void JitHeaders::Register(const std::string& header) {
146  headers_.push_back(header);
147 }
148 
149 // -----------------------------------------------------------------------------
150 namespace {
151 
152 bool ExistsInIncludePath(const std::string& header) {
153  // "-I"/path/1 -I"/path/2"
154  std::string inc_dir_flags = gInterpreter->GetIncludePath();
155  // remove leading `-I"`, trailing `""` and split into separate tokens
156  auto include_dirs =
157  Split(inc_dir_flags.substr(3, inc_dir_flags.length() - 4), "\" -I\"");
158  // postprocess
159  std::string slash_header = Concat("/", header);
160  for (auto& dir : include_dirs) {
161  std::filesystem::path hpath = dir;
162  hpath += slash_header;
163  if (std::filesystem::exists(hpath)) {
164  return true;
165  }
166  }
167  return false;
168 }
169 
170 std::string GetIncludePaths() {
171  std::string inc_dir_flags = gInterpreter->GetIncludePath();
172  auto dirs =
173  Split(inc_dir_flags.substr(3, inc_dir_flags.length() - 4), "\" -I\"");
174  std::stringstream sstr;
175  for (auto& dir : dirs) {
176  sstr << dir << std::endl;
177  }
178  return sstr.str();
179 }
180 
181 } // namespace
182 
183 // -----------------------------------------------------------------------------
185  for (auto& header : headers_) {
186  std::filesystem::path hpath = header;
187  if (hpath.is_absolute()) {
188  if (std::filesystem::exists(hpath)) {
189  gInterpreter->Declare(Concat("#include \"", header, "\"").c_str());
190  } else {
191  Log::Fatal("JitHeaders::Declare",
192  Concat("Header file ", header, " does not exist."));
193  }
194  } else {
195  if (ExistsInIncludePath(header)) {
196  gInterpreter->Declare(Concat("#include \"", header, "\"").c_str());
197  } else {
198  Log::Fatal("JitHeaders::Declare",
199  Concat("Header file ", header,
200  " does not exist in any of the following include "
201  "directories.\n\n",
202  GetIncludePaths()));
203  }
204  }
205  }
206  headers_.clear();
207 }
208 
209 // -----------------------------------------------------------------------------
210 std::vector<std::string> JitHeaders::headers_;
211 
212 } // namespace bdm
bdm::JitHeaders::IncludeIntoCling
static void IncludeIntoCling()
Definition: jit.cc:184
bdm::JitHeaders::Register
static void Register(const std::string &header)
Definition: jit.cc:145
bdm::JitForEachDataMemberFunctor::functor_name_
std::string functor_name_
Definition: jit.h:70
bdm
Definition: agent.cc:39
string.h
bdm::JitForEachDataMemberFunctor::JitForEachDataMemberFunctor
JitForEachDataMemberFunctor(TClass *tclass, const std::vector< std::string > &dm_names, const std::string &functor_name, const std::function< std::string(const std::string &, const std::vector< TDataMember * > &)> &code_generation)
Definition: jit.cc:106
bdm::JitForEachDataMemberFunctor::code_generator_
std::function< std::string(const std::string &, const std::vector< TDataMember * > &)> code_generator_
Definition: jit.h:74
jit.h
bdm::JitForEachDataMemberFunctor::New
void * New(const std::string &parameter="")
Definition: jit.cc:135
bdm::JitForEachDataMemberFunctor::counter_
static std::atomic< int > counter_
The counter value is appended to the functor_name to obtain unique names.
Definition: jit.h:69
bdm::JitHeaders::headers_
static std::vector< std::string > headers_
Definition: jit.h:88
bdm::FindClassSlow
std::vector< TClass * > FindClassSlow(const std::string &class_name)
Definition: jit.cc:31
bdm::JitForEachDataMemberFunctor::Compile
void Compile() const
Definition: jit.cc:129
bdm::EndsWith
bool EndsWith(const std::string &str, const std::string &suffix)
Definition: string.h:25
bdm::Concat
std::string Concat(const Args &... parts)
Concatenates all arguments into a string. Equivalent to streaming all arguments into a stringstream a...
Definition: string.h:70
bdm::Log::Fatal
static void Fatal(const std::string &location, const Args &... parts)
Prints fatal error message.
Definition: log.h:115
bdm::Split
std::vector< std::string > Split(const std::string &s, const std::string &delimiter)
Definition: string.cc:21
log.h
bdm::FindDataMemberSlow
std::vector< TDataMember * > FindDataMemberSlow(TClass *tclass, const std::string &data_member)
Definition: jit.cc:60
bdm::JitForEachDataMemberFunctor::data_members_
std::vector< TDataMember * > data_members_
Definition: jit.h:71