v8  3.14.5(node0.10.28)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
scopeinfo.cc
Go to the documentation of this file.
1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #include <stdlib.h>
29 
30 #include "v8.h"
31 
32 #include "scopeinfo.h"
33 #include "scopes.h"
34 
35 #include "allocation-inl.h"
36 
37 namespace v8 {
38 namespace internal {
39 
40 
42  // Collect stack and context locals.
43  ZoneList<Variable*> stack_locals(scope->StackLocalCount(), zone);
44  ZoneList<Variable*> context_locals(scope->ContextLocalCount(), zone);
45  scope->CollectStackAndContextLocals(&stack_locals, &context_locals);
46  const int stack_local_count = stack_locals.length();
47  const int context_local_count = context_locals.length();
48  // Make sure we allocate the correct amount.
49  ASSERT(scope->StackLocalCount() == stack_local_count);
50  ASSERT(scope->ContextLocalCount() == context_local_count);
51 
52  // Determine use and location of the function variable if it is present.
53  FunctionVariableInfo function_name_info;
54  VariableMode function_variable_mode;
55  if (scope->is_function_scope() && scope->function() != NULL) {
56  Variable* var = scope->function()->proxy()->var();
57  if (!var->is_used()) {
58  function_name_info = UNUSED;
59  } else if (var->IsContextSlot()) {
60  function_name_info = CONTEXT;
61  } else {
62  ASSERT(var->IsStackLocal());
63  function_name_info = STACK;
64  }
65  function_variable_mode = var->mode();
66  } else {
67  function_name_info = NONE;
68  function_variable_mode = VAR;
69  }
70 
71  const bool has_function_name = function_name_info != NONE;
72  const int parameter_count = scope->num_parameters();
73  const int length = kVariablePartIndex
74  + parameter_count + stack_local_count + 2 * context_local_count
75  + (has_function_name ? 2 : 0);
76 
77  Handle<ScopeInfo> scope_info = FACTORY->NewScopeInfo(length);
78 
79  // Encode the flags.
80  int flags = TypeField::encode(scope->type()) |
81  CallsEvalField::encode(scope->calls_eval()) |
82  LanguageModeField::encode(scope->language_mode()) |
83  FunctionVariableField::encode(function_name_info) |
84  FunctionVariableMode::encode(function_variable_mode);
85  scope_info->SetFlags(flags);
86  scope_info->SetParameterCount(parameter_count);
87  scope_info->SetStackLocalCount(stack_local_count);
88  scope_info->SetContextLocalCount(context_local_count);
89 
90  int index = kVariablePartIndex;
91  // Add parameters.
92  ASSERT(index == scope_info->ParameterEntriesIndex());
93  for (int i = 0; i < parameter_count; ++i) {
94  scope_info->set(index++, *scope->parameter(i)->name());
95  }
96 
97  // Add stack locals' names. We are assuming that the stack locals'
98  // slots are allocated in increasing order, so we can simply add
99  // them to the ScopeInfo object.
100  ASSERT(index == scope_info->StackLocalEntriesIndex());
101  for (int i = 0; i < stack_local_count; ++i) {
102  ASSERT(stack_locals[i]->index() == i);
103  scope_info->set(index++, *stack_locals[i]->name());
104  }
105 
106  // Due to usage analysis, context-allocated locals are not necessarily in
107  // increasing order: Some of them may be parameters which are allocated before
108  // the non-parameter locals. When the non-parameter locals are sorted
109  // according to usage, the allocated slot indices may not be in increasing
110  // order with the variable list anymore. Thus, we first need to sort them by
111  // context slot index before adding them to the ScopeInfo object.
112  context_locals.Sort(&Variable::CompareIndex);
113 
114  // Add context locals' names.
115  ASSERT(index == scope_info->ContextLocalNameEntriesIndex());
116  for (int i = 0; i < context_local_count; ++i) {
117  scope_info->set(index++, *context_locals[i]->name());
118  }
119 
120  // Add context locals' info.
121  ASSERT(index == scope_info->ContextLocalInfoEntriesIndex());
122  for (int i = 0; i < context_local_count; ++i) {
123  Variable* var = context_locals[i];
124  uint32_t value = ContextLocalMode::encode(var->mode()) |
125  ContextLocalInitFlag::encode(var->initialization_flag());
126  scope_info->set(index++, Smi::FromInt(value));
127  }
128 
129  // If present, add the function variable name and its index.
130  ASSERT(index == scope_info->FunctionNameEntryIndex());
131  if (has_function_name) {
132  int var_index = scope->function()->proxy()->var()->index();
133  scope_info->set(index++, *scope->function()->proxy()->name());
134  scope_info->set(index++, Smi::FromInt(var_index));
135  ASSERT(function_name_info != STACK ||
136  (var_index == scope_info->StackLocalCount() &&
137  var_index == scope_info->StackSlotCount() - 1));
138  ASSERT(function_name_info != CONTEXT ||
139  var_index == scope_info->ContextLength() - 1);
140  }
141 
142  ASSERT(index == scope_info->length());
143  ASSERT(scope->num_parameters() == scope_info->ParameterCount());
144  ASSERT(scope->num_stack_slots() == scope_info->StackSlotCount());
145  ASSERT(scope->num_heap_slots() == scope_info->ContextLength() ||
146  (scope->num_heap_slots() == kVariablePartIndex &&
147  scope_info->ContextLength() == 0));
148  return scope_info;
149 }
150 
151 
153  return reinterpret_cast<ScopeInfo*>(HEAP->empty_fixed_array());
154 }
155 
156 
158  ASSERT(length() > 0);
159  return TypeField::decode(Flags());
160 }
161 
162 
164  return length() > 0 && CallsEvalField::decode(Flags());
165 }
166 
167 
169  return length() > 0 ? LanguageModeField::decode(Flags()) : CLASSIC_MODE;
170 }
171 
172 
174  return StackLocalCount() + ContextLocalCount();
175 }
176 
177 
179  if (length() > 0) {
180  bool function_name_stack_slot =
181  FunctionVariableField::decode(Flags()) == STACK;
182  return StackLocalCount() + (function_name_stack_slot ? 1 : 0);
183  }
184  return 0;
185 }
186 
187 
189  if (length() > 0) {
190  int context_locals = ContextLocalCount();
191  bool function_name_context_slot =
192  FunctionVariableField::decode(Flags()) == CONTEXT;
193  bool has_context = context_locals > 0 ||
194  function_name_context_slot ||
195  Type() == WITH_SCOPE ||
196  (Type() == FUNCTION_SCOPE && CallsEval()) ||
197  Type() == MODULE_SCOPE;
198  if (has_context) {
199  return Context::MIN_CONTEXT_SLOTS + context_locals +
200  (function_name_context_slot ? 1 : 0);
201  }
202  }
203  return 0;
204 }
205 
206 
208  if (length() > 0) {
209  return NONE != FunctionVariableField::decode(Flags());
210  } else {
211  return false;
212  }
213 }
214 
215 
217  if (length() > 0) {
218  return ContextLocalCount() > 0;
219  } else {
220  return false;
221  }
222 }
223 
224 
226  return ContextLength() > 0;
227 }
228 
229 
232  return String::cast(get(FunctionNameEntryIndex()));
233 }
234 
235 
237  ASSERT(0 <= var && var < ParameterCount());
238  int info_index = ParameterEntriesIndex() + var;
239  return String::cast(get(info_index));
240 }
241 
242 
244  ASSERT(0 <= var && var < LocalCount());
245  ASSERT(StackLocalEntriesIndex() + StackLocalCount() ==
246  ContextLocalNameEntriesIndex());
247  int info_index = StackLocalEntriesIndex() + var;
248  return String::cast(get(info_index));
249 }
250 
251 
253  ASSERT(0 <= var && var < StackLocalCount());
254  int info_index = StackLocalEntriesIndex() + var;
255  return String::cast(get(info_index));
256 }
257 
258 
260  ASSERT(0 <= var && var < ContextLocalCount());
261  int info_index = ContextLocalNameEntriesIndex() + var;
262  return String::cast(get(info_index));
263 }
264 
265 
267  ASSERT(0 <= var && var < ContextLocalCount());
268  int info_index = ContextLocalInfoEntriesIndex() + var;
269  int value = Smi::cast(get(info_index))->value();
270  return ContextLocalMode::decode(value);
271 }
272 
273 
275  ASSERT(0 <= var && var < ContextLocalCount());
276  int info_index = ContextLocalInfoEntriesIndex() + var;
277  int value = Smi::cast(get(info_index))->value();
278  return ContextLocalInitFlag::decode(value);
279 }
280 
281 
283  ASSERT(name->IsSymbol());
284  if (length() > 0) {
285  int start = StackLocalEntriesIndex();
286  int end = StackLocalEntriesIndex() + StackLocalCount();
287  for (int i = start; i < end; ++i) {
288  if (name == get(i)) {
289  return i - start;
290  }
291  }
292  }
293  return -1;
294 }
295 
296 
298  VariableMode* mode,
299  InitializationFlag* init_flag) {
300  ASSERT(name->IsSymbol());
301  ASSERT(mode != NULL);
302  ASSERT(init_flag != NULL);
303  if (length() > 0) {
304  ContextSlotCache* context_slot_cache = GetIsolate()->context_slot_cache();
305  int result = context_slot_cache->Lookup(this, name, mode, init_flag);
306  if (result != ContextSlotCache::kNotFound) {
307  ASSERT(result < ContextLength());
308  return result;
309  }
310 
311  int start = ContextLocalNameEntriesIndex();
312  int end = ContextLocalNameEntriesIndex() + ContextLocalCount();
313  for (int i = start; i < end; ++i) {
314  if (name == get(i)) {
315  int var = i - start;
316  *mode = ContextLocalMode(var);
317  *init_flag = ContextLocalInitFlag(var);
318  result = Context::MIN_CONTEXT_SLOTS + var;
319  context_slot_cache->Update(this, name, *mode, *init_flag, result);
320  ASSERT(result < ContextLength());
321  return result;
322  }
323  }
324  context_slot_cache->Update(this, name, INTERNAL, kNeedsInitialization, -1);
325  }
326  return -1;
327 }
328 
329 
331  ASSERT(name->IsSymbol());
332  if (length() > 0) {
333  // We must read parameters from the end since for
334  // multiply declared parameters the value of the
335  // last declaration of that parameter is used
336  // inside a function (and thus we need to look
337  // at the last index). Was bug# 1110337.
338  int start = ParameterEntriesIndex();
339  int end = ParameterEntriesIndex() + ParameterCount();
340  for (int i = end - 1; i >= start; --i) {
341  if (name == get(i)) {
342  return i - start;
343  }
344  }
345  }
346  return -1;
347 }
348 
349 
351  ASSERT(name->IsSymbol());
352  ASSERT(mode != NULL);
353  if (length() > 0) {
354  if (FunctionVariableField::decode(Flags()) == CONTEXT &&
355  FunctionName() == name) {
356  *mode = FunctionVariableMode::decode(Flags());
357  return Smi::cast(get(FunctionNameEntryIndex() + 1))->value();
358  }
359  }
360  return -1;
361 }
362 
363 
364 int ScopeInfo::ParameterEntriesIndex() {
365  ASSERT(length() > 0);
366  return kVariablePartIndex;
367 }
368 
369 
370 int ScopeInfo::StackLocalEntriesIndex() {
371  return ParameterEntriesIndex() + ParameterCount();
372 }
373 
374 
375 int ScopeInfo::ContextLocalNameEntriesIndex() {
376  return StackLocalEntriesIndex() + StackLocalCount();
377 }
378 
379 
380 int ScopeInfo::ContextLocalInfoEntriesIndex() {
381  return ContextLocalNameEntriesIndex() + ContextLocalCount();
382 }
383 
384 
385 int ScopeInfo::FunctionNameEntryIndex() {
386  return ContextLocalInfoEntriesIndex() + ContextLocalCount();
387 }
388 
389 
390 int ContextSlotCache::Hash(Object* data, String* name) {
391  // Uses only lower 32 bits if pointers are larger.
392  uintptr_t addr_hash =
393  static_cast<uint32_t>(reinterpret_cast<uintptr_t>(data)) >> 2;
394  return static_cast<int>((addr_hash ^ name->Hash()) % kLength);
395 }
396 
397 
399  String* name,
400  VariableMode* mode,
401  InitializationFlag* init_flag) {
402  int index = Hash(data, name);
403  Key& key = keys_[index];
404  if ((key.data == data) && key.name->Equals(name)) {
405  Value result(values_[index]);
406  if (mode != NULL) *mode = result.mode();
407  if (init_flag != NULL) *init_flag = result.initialization_flag();
408  return result.index() + kNotFound;
409  }
410  return kNotFound;
411 }
412 
413 
415  String* name,
416  VariableMode mode,
417  InitializationFlag init_flag,
418  int slot_index) {
419  String* symbol;
420  ASSERT(slot_index > kNotFound);
421  if (HEAP->LookupSymbolIfExists(name, &symbol)) {
422  int index = Hash(data, symbol);
423  Key& key = keys_[index];
424  key.data = data;
425  key.name = symbol;
426  // Please note value only takes a uint as index.
427  values_[index] = Value(mode, init_flag, slot_index - kNotFound).raw();
428 #ifdef DEBUG
429  ValidateEntry(data, name, mode, init_flag, slot_index);
430 #endif
431  }
432 }
433 
434 
436  for (int index = 0; index < kLength; index++) keys_[index].data = NULL;
437 }
438 
439 
440 #ifdef DEBUG
441 
442 void ContextSlotCache::ValidateEntry(Object* data,
443  String* name,
444  VariableMode mode,
445  InitializationFlag init_flag,
446  int slot_index) {
447  String* symbol;
448  if (HEAP->LookupSymbolIfExists(name, &symbol)) {
449  int index = Hash(data, name);
450  Key& key = keys_[index];
451  ASSERT(key.data == data);
452  ASSERT(key.name->Equals(name));
453  Value result(values_[index]);
454  ASSERT(result.mode() == mode);
455  ASSERT(result.initialization_flag() == init_flag);
456  ASSERT(result.index() + kNotFound == slot_index);
457  }
458 }
459 
460 
461 static void PrintList(const char* list_name,
462  int nof_internal_slots,
463  int start,
464  int end,
465  ScopeInfo* scope_info) {
466  if (start < end) {
467  PrintF("\n // %s\n", list_name);
468  if (nof_internal_slots > 0) {
469  PrintF(" %2d - %2d [internal slots]\n", 0 , nof_internal_slots - 1);
470  }
471  for (int i = nof_internal_slots; start < end; ++i, ++start) {
472  PrintF(" %2d ", i);
473  String::cast(scope_info->get(start))->ShortPrint();
474  PrintF("\n");
475  }
476  }
477 }
478 
479 
480 void ScopeInfo::Print() {
481  PrintF("ScopeInfo ");
482  if (HasFunctionName()) {
484  } else {
485  PrintF("/* no function name */");
486  }
487  PrintF("{");
488 
489  PrintList("parameters", 0,
490  ParameterEntriesIndex(),
491  ParameterEntriesIndex() + ParameterCount(),
492  this);
493  PrintList("stack slots", 0,
494  StackLocalEntriesIndex(),
495  StackLocalEntriesIndex() + StackLocalCount(),
496  this);
497  PrintList("context slots",
499  ContextLocalNameEntriesIndex(),
500  ContextLocalNameEntriesIndex() + ContextLocalCount(),
501  this);
502 
503  PrintF("}\n");
504 }
505 #endif // DEBUG
506 
507 } } // namespace v8::internal
int StackSlotIndex(String *name)
Definition: scopeinfo.cc:282
ContextSlotCache * context_slot_cache()
Definition: isolate.h:853
VariableDeclaration * function() const
Definition: scopes.h:324
bool calls_eval() const
Definition: scopes.h:297
void PrintF(const char *format,...)
Definition: v8utils.cc:40
static String * cast(Object *obj)
Definition: v8.h:869
static Smi * FromInt(int value)
Definition: objects-inl.h:981
void CollectStackAndContextLocals(ZoneList< Variable * > *stack_locals, ZoneList< Variable * > *context_locals)
Definition: scopes.cc:613
int ContextSlotIndex(String *name, VariableMode *mode, InitializationFlag *init_flag)
Definition: scopeinfo.cc:297
int ParameterIndex(String *name)
Definition: scopeinfo.cc:330
int Lookup(Object *data, String *name, VariableMode *mode, InitializationFlag *init_flag)
Definition: scopeinfo.cc:398
static const int kNotFound
Definition: scopeinfo.h:61
InitializationFlag initialization_flag() const
Definition: variables.h:148
#define ASSERT(condition)
Definition: checks.h:270
v8::Handle< v8::Value > Print(const v8::Arguments &args)
InitializationFlag ContextLocalInitFlag(int var)
Definition: scopeinfo.cc:274
Variable * parameter(int index) const
Definition: scopes.h:331
Handle< String > name() const
Definition: ast.h:1410
Handle< String > name() const
Definition: variables.h:96
static Smi * cast(Object *object)
static Handle< ScopeInfo > Create(Scope *scope, Zone *zone)
Definition: scopeinfo.cc:41
Variable * var() const
Definition: ast.h:1411
VariableProxy * proxy() const
Definition: ast.h:443
VariableMode mode() const
Definition: variables.h:97
int num_stack_slots() const
Definition: scopes.h:366
ScopeType type() const
Definition: scopes.h:314
static int CompareIndex(Variable *const *v, Variable *const *w)
Definition: variables.cc:92
int index() const
Definition: variables.h:147
void Update(Object *data, String *name, VariableMode mode, InitializationFlag init_flag, int slot_index)
Definition: scopeinfo.cc:414
bool IsContextSlot() const
Definition: variables.h:119
int num_parameters() const
Definition: scopes.h:336
static ScopeInfo * Empty()
Definition: scopeinfo.cc:152
int FunctionContextSlotIndex(String *name, VariableMode *mode)
Definition: scopeinfo.cc:350
bool IsStackLocal() const
Definition: variables.h:117
int StackLocalCount() const
Definition: scopes.cc:1345
int num_heap_slots() const
Definition: scopes.h:367
String * StackLocalName(int var)
Definition: scopeinfo.cc:252
VariableMode ContextLocalMode(int var)
Definition: scopeinfo.cc:266
String * LocalName(int var)
Definition: scopeinfo.cc:243
String * ContextLocalName(int var)
Definition: scopeinfo.cc:259
#define HEAP
Definition: isolate.h:1433
int ContextLocalCount() const
Definition: scopes.cc:1351
String * ParameterName(int var)
Definition: scopeinfo.cc:236
#define FACTORY
Definition: isolate.h:1434
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 and VFP2 enable use of VFP2 instructions if available enable use of SDIV and UDIV instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of MIPS FPU instructions if NULL
Definition: flags.cc:301
LanguageMode language_mode() const
Definition: scopes.h:317
bool is_function_scope() const
Definition: scopes.h:276
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 and VFP2 enable use of VFP2 instructions if available enable use of SDIV and UDIV instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of MIPS FPU instructions if expose natives in global object expose gc extension number of stack frames to capture disable builtin natives files print a stack trace if an assertion failure occurs use random jit cookie to mask large constants trace lazy optimization use adaptive optimizations prepare for turning on always opt minimum length for automatic enable preparsing maximum number of optimization attempts before giving up cache prototype transitions automatically set the debug break flag when debugger commands are in the queue always cause a debug break before aborting maximum length of function source code printed in a stack trace max size of the new max size of the old max size of executable always perform global GCs print one trace line following each garbage collection do not print trace line after scavenger collection print more details following each garbage collection print amount of external allocated memory after each time it is adjusted flush code that we expect not to use again before full gc do incremental marking steps track object counts and memory usage use caching Perform compaction on every full GC Never perform compaction on full GC testing only Compact code space on full incremental collections Default seed for initializing random allows verbose printing trace parsing and preparsing Check icache flushes in ARM and MIPS simulator Stack alingment in bytes in print stack trace when throwing exceptions randomize hashes to avoid predictable hash Fixed seed to use to hash property activate a timer that switches between V8 threads testing_bool_flag float flag Seed used for threading test randomness A filename with extra code to be included in the Print usage including flags
Definition: flags.cc:495
LanguageMode language_mode()
Definition: scopeinfo.cc:168