BioDynaMo  v1.03.58-27764645
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 <experimental/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 fs = std::experimental::filesystem;
29 
30 namespace bdm {
31 
32 // -----------------------------------------------------------------------------
33 std::vector<TClass*> FindClassSlow(const std::string& class_name) {
34  bool cn_has_scope = class_name.find("::") != std::string::npos;
35  std::string cn_with_scope_prefix = std::string("::") + class_name;
36  char* current = 0;
37  uint64_t idx = 0;
38  std::vector<TClass*> tclasses;
39  while ((current = TClassTable::At(idx++)) != nullptr) {
40  std::string scurrent(current);
41  if (scurrent.find("::") == std::string::npos) {
42  // current does not contain a scope operator -> full match
43  if (std::string(current).compare(class_name) == 0) {
44  tclasses.push_back(TClassTable::GetDict(current)());
45  }
46  } else {
47  if (cn_has_scope) {
48  if (EndsWith(scurrent, class_name)) {
49  tclasses.push_back(TClassTable::GetDict(current)());
50  }
51  } else {
52  if (EndsWith(scurrent, cn_with_scope_prefix)) {
53  tclasses.push_back(TClassTable::GetDict(current)());
54  }
55  }
56  }
57  }
58  return tclasses;
59 }
60 
61 // -----------------------------------------------------------------------------
62 std::vector<TDataMember*> FindDataMemberSlow(TClass* tclass,
63  const std::string& data_member) {
64  std::vector<TDataMember*> ret_val;
65 
66  bool dm_has_scope = data_member.find("::") != std::string::npos;
67  std::string class_name = "";
68  std::string dm_only_name = data_member;
69  if (dm_has_scope) {
70  auto idx = data_member.find_last_of("::");
71  class_name = data_member.substr(0, idx - 1);
72  dm_only_name = data_member.substr(idx + 1, data_member.size());
73  }
74 
75  std::stack<TClass*> tc_stack;
76  tc_stack.push(tclass);
77 
78  while (tc_stack.size() != 0) {
79  auto* current_tc = tc_stack.top();
80  tc_stack.pop();
81  for (const auto&& base : *current_tc->GetListOfBases()) {
82  auto get_dict_functor = TClassTable::GetDict(base->GetName());
83  if (get_dict_functor != nullptr) {
84  tc_stack.push(get_dict_functor());
85  }
86  }
87 
88  for (int i = 0; i < current_tc->GetListOfDataMembers()->GetSize(); ++i) {
89  auto* dm =
90  static_cast<TDataMember*>(current_tc->GetListOfDataMembers()->At(i));
91  if (dm_has_scope) {
92  if (dm_only_name.compare(dm->GetName()) == 0 &&
93  EndsWith(std::string(current_tc->GetName()), class_name)) {
94  ret_val.push_back(dm);
95  }
96  } else {
97  if (data_member.compare(dm->GetName()) == 0) {
98  ret_val.push_back(dm);
99  }
100  }
101  }
102  }
103 
104  return ret_val;
105 }
106 
107 // -----------------------------------------------------------------------------
109  TClass* tclass, const std::vector<std::string>& dm_names,
110  const std::string& functor_name,
111  const std::function<std::string(
112  const std::string&, const std::vector<TDataMember*>&)>& code_generator)
113  : functor_name_(Concat(functor_name, counter_++)),
114  code_generator_(code_generator) {
115  data_members_.reserve(dm_names.size());
116  for (auto& dm : dm_names) {
117  auto candidates = FindDataMemberSlow(tclass, dm);
118  if (candidates.size() == 1) {
119  data_members_.push_back(candidates[0]);
120  } else if (candidates.size() == 0) {
121  Log::Fatal("JitForEachDataMemberFunctor::JitForEachDataMemberFunctor",
122  "Could not find data member ", dm);
123  } else {
124  Log::Fatal("JitForEachDataMemberFunctor::JitForEachDataMemberFunctor",
125  "Data member name (", dm, ") is ambigous");
126  }
127  }
128 }
129 
130 // -----------------------------------------------------------------------------
133  gInterpreter->Declare(code_generator_(functor_name_, data_members_).c_str());
134 }
135 
136 // -----------------------------------------------------------------------------
137 void* JitForEachDataMemberFunctor::New(const std::string& parameter) {
138  auto cmd = Concat("#pragma cling optimize(3)\nnew bdm::", functor_name_, "(",
139  parameter, ")");
140  return reinterpret_cast<void*>(gInterpreter->Calc(cmd.c_str()));
141 }
142 
143 // -----------------------------------------------------------------------------
145 
146 // -----------------------------------------------------------------------------
147 void JitHeaders::Register(const std::string& header) {
148  headers_.push_back(header);
149 }
150 
151 // -----------------------------------------------------------------------------
152 namespace {
153 
154 bool ExistsInIncludePath(const std::string& header) {
155  // "-I"/path/1 -I"/path/2"
156  std::string inc_dir_flags = gInterpreter->GetIncludePath();
157  // remove leading `-I"`, trailing `""` and split into separate tokens
158  auto include_dirs =
159  Split(inc_dir_flags.substr(3, inc_dir_flags.length() - 4), "\" -I\"");
160  // postprocess
161  std::string slash_header = Concat("/", header);
162  for (auto& dir : include_dirs) {
163  fs::path hpath = dir;
164  hpath += slash_header;
165  if (fs::exists(hpath)) {
166  return true;
167  }
168  }
169  return false;
170 }
171 
172 std::string GetIncludePaths() {
173  std::string inc_dir_flags = gInterpreter->GetIncludePath();
174  auto dirs =
175  Split(inc_dir_flags.substr(3, inc_dir_flags.length() - 4), "\" -I\"");
176  std::stringstream sstr;
177  for (auto& dir : dirs) {
178  sstr << dir << std::endl;
179  }
180  return sstr.str();
181 }
182 
183 } // namespace
184 
185 // -----------------------------------------------------------------------------
187  for (auto& header : headers_) {
188  fs::path hpath = header;
189  if (hpath.is_absolute()) {
190  if (fs::exists(hpath)) {
191  gInterpreter->Declare(Concat("#include \"", header, "\"").c_str());
192  } else {
193  Log::Fatal("JitHeaders::Declare",
194  Concat("Header file ", header, " does not exist."));
195  }
196  } else {
197  if (ExistsInIncludePath(header)) {
198  gInterpreter->Declare(Concat("#include \"", header, "\"").c_str());
199  } else {
200  Log::Fatal("JitHeaders::Declare",
201  Concat("Header file ", header,
202  " does not exist in any of the following include "
203  "directories.\n\n",
204  GetIncludePaths()));
205  }
206  }
207  }
208  headers_.clear();
209 }
210 
211 // -----------------------------------------------------------------------------
212 std::vector<std::string> JitHeaders::headers_;
213 
214 } // namespace bdm
bdm::JitHeaders::IncludeIntoCling
static void IncludeIntoCling()
Definition: jit.cc:186
bdm::JitHeaders::Register
static void Register(const std::string &header)
Definition: jit.cc:147
bdm::JitForEachDataMemberFunctor::functor_name_
std::string functor_name_
Definition: jit.h:70
bdm
Definition: agent.cc:39
string.h
bdm::JitForEachDataMemberFunctor::Compile
void Compile()
Definition: jit.cc:131
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:108
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:137
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:33
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:19
log.h
bdm::FindDataMemberSlow
std::vector< TDataMember * > FindDataMemberSlow(TClass *tclass, const std::string &data_member)
Definition: jit.cc:62
bdm::JitForEachDataMemberFunctor::data_members_
std::vector< TDataMember * > data_members_
Definition: jit.h:71