V8 Project
ast.cc
Go to the documentation of this file.
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/ast.h"
6 
7 #include <cmath> // For isfinite.
8 #include "src/builtins.h"
9 #include "src/code-stubs.h"
10 #include "src/contexts.h"
11 #include "src/conversions.h"
12 #include "src/hashmap.h"
13 #include "src/parser.h"
14 #include "src/property.h"
15 #include "src/property-details.h"
16 #include "src/scopes.h"
17 #include "src/string-stream.h"
18 #include "src/type-info.h"
19 
20 namespace v8 {
21 namespace internal {
22 
23 // ----------------------------------------------------------------------------
24 // All the Accept member functions for each syntax tree node type.
25 
26 #define DECL_ACCEPT(type) \
27  void type::Accept(AstVisitor* v) { v->Visit##type(this); }
29 #undef DECL_ACCEPT
30 
31 
32 // ----------------------------------------------------------------------------
33 // Implementation of other node functionality.
34 
35 
37  return IsLiteral() && AsLiteral()->value()->IsSmi();
38 }
39 
40 
42  return IsLiteral() && AsLiteral()->value()->IsString();
43 }
44 
45 
47  return IsLiteral() && AsLiteral()->value()->IsNull();
48 }
49 
50 
52  const VariableProxy* var_proxy = AsVariableProxy();
53  if (var_proxy == NULL) return false;
54  Variable* var = var_proxy->var();
55  // The global identifier "undefined" is immutable. Everything
56  // else could be reassigned.
57  return var != NULL && var->location() == Variable::UNALLOCATED &&
58  var_proxy->raw_name()->IsOneByteEqualTo("undefined");
59 }
60 
61 
62 VariableProxy::VariableProxy(Zone* zone, Variable* var, int position,
63  IdGen* id_gen)
64  : Expression(zone, position, id_gen),
65  name_(var->raw_name()),
66  var_(NULL), // Will be set by the call to BindTo.
67  is_this_(var->is_this()),
68  is_assigned_(false),
69  interface_(var->interface()),
70  variable_feedback_slot_(kInvalidFeedbackSlot) {
71  BindTo(var);
72 }
73 
74 
75 VariableProxy::VariableProxy(Zone* zone, const AstRawString* name, bool is_this,
76  Interface* interface, int position, IdGen* id_gen)
77  : Expression(zone, position, id_gen),
78  name_(name),
79  var_(NULL),
80  is_this_(is_this),
81  is_assigned_(false),
82  interface_(interface),
83  variable_feedback_slot_(kInvalidFeedbackSlot) {}
84 
85 
86 void VariableProxy::BindTo(Variable* var) {
87  DCHECK(var_ == NULL); // must be bound only once
88  DCHECK(var != NULL); // must bind
89  DCHECK(!FLAG_harmony_modules || interface_->IsUnified(var->interface()));
90  DCHECK((is_this() && var->is_this()) || name_ == var->raw_name());
91  // Ideally CONST-ness should match. However, this is very hard to achieve
92  // because we don't know the exact semantics of conflicting (const and
93  // non-const) multiple variable declarations, const vars introduced via
94  // eval() etc. Const-ness and variable declarations are a complete mess
95  // in JS. Sigh...
96  var_ = var;
97  var->set_is_used();
98 }
99 
100 
101 Assignment::Assignment(Zone* zone, Token::Value op, Expression* target,
102  Expression* value, int pos, IdGen* id_gen)
103  : Expression(zone, pos, id_gen),
104  op_(op),
105  target_(target),
106  value_(value),
107  binary_operation_(NULL),
108  assignment_id_(id_gen->GetNextId()),
109  is_uninitialized_(false),
110  store_mode_(STANDARD_STORE) {}
111 
112 
113 Token::Value Assignment::binary_op() const {
114  switch (op_) {
115  case Token::ASSIGN_BIT_OR: return Token::BIT_OR;
116  case Token::ASSIGN_BIT_XOR: return Token::BIT_XOR;
117  case Token::ASSIGN_BIT_AND: return Token::BIT_AND;
118  case Token::ASSIGN_SHL: return Token::SHL;
119  case Token::ASSIGN_SAR: return Token::SAR;
120  case Token::ASSIGN_SHR: return Token::SHR;
121  case Token::ASSIGN_ADD: return Token::ADD;
122  case Token::ASSIGN_SUB: return Token::SUB;
123  case Token::ASSIGN_MUL: return Token::MUL;
124  case Token::ASSIGN_DIV: return Token::DIV;
125  case Token::ASSIGN_MOD: return Token::MOD;
126  default: UNREACHABLE();
127  }
128  return Token::ILLEGAL;
129 }
130 
131 
132 bool FunctionLiteral::AllowsLazyCompilation() {
133  return scope()->AllowsLazyCompilation();
134 }
135 
136 
137 bool FunctionLiteral::AllowsLazyCompilationWithoutContext() {
138  return scope()->AllowsLazyCompilationWithoutContext();
139 }
140 
141 
142 int FunctionLiteral::start_position() const {
143  return scope()->start_position();
144 }
145 
146 
147 int FunctionLiteral::end_position() const {
148  return scope()->end_position();
149 }
150 
151 
152 StrictMode FunctionLiteral::strict_mode() const {
153  return scope()->strict_mode();
154 }
155 
156 
157 void FunctionLiteral::InitializeSharedInfo(
158  Handle<Code> unoptimized_code) {
159  for (RelocIterator it(*unoptimized_code); !it.done(); it.next()) {
160  RelocInfo* rinfo = it.rinfo();
161  if (rinfo->rmode() != RelocInfo::EMBEDDED_OBJECT) continue;
162  Object* obj = rinfo->target_object();
163  if (obj->IsSharedFunctionInfo()) {
164  SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
165  if (shared->start_position() == start_position()) {
166  shared_info_ = Handle<SharedFunctionInfo>(shared);
167  break;
168  }
169  }
170  }
171 }
172 
173 
174 ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone,
175  AstValueFactory* ast_value_factory,
176  Literal* key, Expression* value,
177  bool is_static) {
178  emit_store_ = true;
179  key_ = key;
180  value_ = value;
181  is_static_ = is_static;
182  if (key->raw_value()->EqualsString(ast_value_factory->proto_string())) {
183  kind_ = PROTOTYPE;
184  } else if (value_->AsMaterializedLiteral() != NULL) {
185  kind_ = MATERIALIZED_LITERAL;
186  } else if (value_->IsLiteral()) {
187  kind_ = CONSTANT;
188  } else {
189  kind_ = COMPUTED;
190  }
191 }
192 
193 
194 ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone, bool is_getter,
195  FunctionLiteral* value,
196  bool is_static) {
197  emit_store_ = true;
198  value_ = value;
199  kind_ = is_getter ? GETTER : SETTER;
200  is_static_ = is_static;
201 }
202 
203 
204 bool ObjectLiteral::Property::IsCompileTimeValue() {
205  return kind_ == CONSTANT ||
206  (kind_ == MATERIALIZED_LITERAL &&
208 }
209 
210 
211 void ObjectLiteral::Property::set_emit_store(bool emit_store) {
212  emit_store_ = emit_store;
213 }
214 
215 
216 bool ObjectLiteral::Property::emit_store() {
217  return emit_store_;
218 }
219 
220 
221 void ObjectLiteral::CalculateEmitStore(Zone* zone) {
222  ZoneAllocationPolicy allocator(zone);
223 
225  allocator);
226  for (int i = properties()->length() - 1; i >= 0; i--) {
227  ObjectLiteral::Property* property = properties()->at(i);
228  Literal* literal = property->key();
229  if (literal->value()->IsNull()) continue;
230  uint32_t hash = literal->Hash();
231  // If the key of a computed property is in the table, do not emit
232  // a store for the property later.
233  if ((property->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL ||
234  property->kind() == ObjectLiteral::Property::COMPUTED) &&
235  table.Lookup(literal, hash, false, allocator) != NULL) {
236  property->set_emit_store(false);
237  } else {
238  // Add key to the table.
239  table.Lookup(literal, hash, true, allocator);
240  }
241  }
242 }
243 
244 
245 bool ObjectLiteral::IsBoilerplateProperty(ObjectLiteral::Property* property) {
246  return property != NULL &&
247  property->kind() != ObjectLiteral::Property::PROTOTYPE;
248 }
249 
250 
251 void ObjectLiteral::BuildConstantProperties(Isolate* isolate) {
252  if (!constant_properties_.is_null()) return;
253 
254  // Allocate a fixed array to hold all the constant properties.
255  Handle<FixedArray> constant_properties = isolate->factory()->NewFixedArray(
256  boilerplate_properties_ * 2, TENURED);
257 
258  int position = 0;
259  // Accumulate the value in local variables and store it at the end.
260  bool is_simple = true;
261  int depth_acc = 1;
262  uint32_t max_element_index = 0;
263  uint32_t elements = 0;
264  for (int i = 0; i < properties()->length(); i++) {
265  ObjectLiteral::Property* property = properties()->at(i);
266  if (!IsBoilerplateProperty(property)) {
267  is_simple = false;
268  continue;
269  }
270  MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral();
271  if (m_literal != NULL) {
272  m_literal->BuildConstants(isolate);
273  if (m_literal->depth() >= depth_acc) depth_acc = m_literal->depth() + 1;
274  }
275 
276  // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined
277  // value for COMPUTED properties, the real value is filled in at
278  // runtime. The enumeration order is maintained.
279  Handle<Object> key = property->key()->value();
280  Handle<Object> value = GetBoilerplateValue(property->value(), isolate);
281 
282  // Ensure objects that may, at any point in time, contain fields with double
283  // representation are always treated as nested objects. This is true for
284  // computed fields (value is undefined), and smi and double literals
285  // (value->IsNumber()).
286  // TODO(verwaest): Remove once we can store them inline.
287  if (FLAG_track_double_fields &&
288  (value->IsNumber() || value->IsUninitialized())) {
289  may_store_doubles_ = true;
290  }
291 
292  is_simple = is_simple && !value->IsUninitialized();
293 
294  // Keep track of the number of elements in the object literal and
295  // the largest element index. If the largest element index is
296  // much larger than the number of elements, creating an object
297  // literal with fast elements will be a waste of space.
298  uint32_t element_index = 0;
299  if (key->IsString()
300  && Handle<String>::cast(key)->AsArrayIndex(&element_index)
301  && element_index > max_element_index) {
302  max_element_index = element_index;
303  elements++;
304  } else if (key->IsSmi()) {
305  int key_value = Smi::cast(*key)->value();
306  if (key_value > 0
307  && static_cast<uint32_t>(key_value) > max_element_index) {
308  max_element_index = key_value;
309  }
310  elements++;
311  }
312 
313  // Add name, value pair to the fixed array.
314  constant_properties->set(position++, *key);
315  constant_properties->set(position++, *value);
316  }
317 
318  constant_properties_ = constant_properties;
319  fast_elements_ =
320  (max_element_index <= 32) || ((2 * elements) >= max_element_index);
321  set_is_simple(is_simple);
322  set_depth(depth_acc);
323 }
324 
325 
326 void ArrayLiteral::BuildConstantElements(Isolate* isolate) {
327  if (!constant_elements_.is_null()) return;
328 
329  // Allocate a fixed array to hold all the object literals.
330  Handle<JSArray> array =
331  isolate->factory()->NewJSArray(0, FAST_HOLEY_SMI_ELEMENTS);
332  JSArray::Expand(array, values()->length());
333 
334  // Fill in the literals.
335  bool is_simple = true;
336  int depth_acc = 1;
337  bool is_holey = false;
338  for (int i = 0, n = values()->length(); i < n; i++) {
339  Expression* element = values()->at(i);
340  MaterializedLiteral* m_literal = element->AsMaterializedLiteral();
341  if (m_literal != NULL) {
342  m_literal->BuildConstants(isolate);
343  if (m_literal->depth() + 1 > depth_acc) {
344  depth_acc = m_literal->depth() + 1;
345  }
346  }
347  Handle<Object> boilerplate_value = GetBoilerplateValue(element, isolate);
348  if (boilerplate_value->IsTheHole()) {
349  is_holey = true;
350  } else if (boilerplate_value->IsUninitialized()) {
351  is_simple = false;
353  array, i, handle(Smi::FromInt(0), isolate), SLOPPY).Assert();
354  } else {
355  JSObject::SetOwnElement(array, i, boilerplate_value, SLOPPY).Assert();
356  }
357  }
358 
359  Handle<FixedArrayBase> element_values(array->elements());
360 
361  // Simple and shallow arrays can be lazily copied, we transform the
362  // elements array to a copy-on-write array.
363  if (is_simple && depth_acc == 1 && values()->length() > 0 &&
364  array->HasFastSmiOrObjectElements()) {
365  element_values->set_map(isolate->heap()->fixed_cow_array_map());
366  }
367 
368  // Remember both the literal's constant values as well as the ElementsKind
369  // in a 2-element FixedArray.
370  Handle<FixedArray> literals = isolate->factory()->NewFixedArray(2, TENURED);
371 
372  ElementsKind kind = array->GetElementsKind();
373  kind = is_holey ? GetHoleyElementsKind(kind) : GetPackedElementsKind(kind);
374 
375  literals->set(0, Smi::FromInt(kind));
376  literals->set(1, *element_values);
377 
378  constant_elements_ = literals;
379  set_is_simple(is_simple);
380  set_depth(depth_acc);
381 }
382 
383 
385  Isolate* isolate) {
386  if (expression->IsLiteral()) {
387  return expression->AsLiteral()->value();
388  }
389  if (CompileTimeValue::IsCompileTimeValue(expression)) {
390  return CompileTimeValue::GetValue(isolate, expression);
391  }
392  return isolate->factory()->uninitialized_value();
393 }
394 
395 
397  if (IsArrayLiteral()) {
398  return AsArrayLiteral()->BuildConstantElements(isolate);
399  }
400  if (IsObjectLiteral()) {
401  return AsObjectLiteral()->BuildConstantProperties(isolate);
402  }
403  DCHECK(IsRegExpLiteral());
404  DCHECK(depth() >= 1); // Depth should be initialized.
405 }
406 
407 
408 void TargetCollector::AddTarget(Label* target, Zone* zone) {
409  // Add the label to the collector, but discard duplicates.
410  int length = targets_.length();
411  for (int i = 0; i < length; i++) {
412  if (targets_[i] == target) return;
413  }
414  targets_.Add(target, zone);
415 }
416 
417 
418 void UnaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
419  // TODO(olivf) If this Operation is used in a test context, then the
420  // expression has a ToBoolean stub and we want to collect the type
421  // information. However the GraphBuilder expects it to be on the instruction
422  // corresponding to the TestContext, therefore we have to store it here and
423  // not on the operand.
424  set_to_boolean_types(oracle->ToBooleanTypes(expression()->test_id()));
425 }
426 
427 
428 void BinaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
429  // TODO(olivf) If this Operation is used in a test context, then the right
430  // hand side has a ToBoolean stub and we want to collect the type information.
431  // However the GraphBuilder expects it to be on the instruction corresponding
432  // to the TestContext, therefore we have to store it here and not on the
433  // right hand operand.
434  set_to_boolean_types(oracle->ToBooleanTypes(right()->test_id()));
435 }
436 
437 
438 bool BinaryOperation::ResultOverwriteAllowed() const {
439  switch (op_) {
440  case Token::COMMA:
441  case Token::OR:
442  case Token::AND:
443  return false;
444  case Token::BIT_OR:
445  case Token::BIT_XOR:
446  case Token::BIT_AND:
447  case Token::SHL:
448  case Token::SAR:
449  case Token::SHR:
450  case Token::ADD:
451  case Token::SUB:
452  case Token::MUL:
453  case Token::DIV:
454  case Token::MOD:
455  return true;
456  default:
457  UNREACHABLE();
458  }
459  return false;
460 }
461 
462 
463 static bool IsTypeof(Expression* expr) {
464  UnaryOperation* maybe_unary = expr->AsUnaryOperation();
465  return maybe_unary != NULL && maybe_unary->op() == Token::TYPEOF;
466 }
467 
468 
469 // Check for the pattern: typeof <expression> equals <string literal>.
471  Token::Value op,
472  Expression* right,
473  Expression** expr,
474  Handle<String>* check) {
475  if (IsTypeof(left) && right->IsStringLiteral() && Token::IsEqualityOp(op)) {
476  *expr = left->AsUnaryOperation()->expression();
477  *check = Handle<String>::cast(right->AsLiteral()->value());
478  return true;
479  }
480  return false;
481 }
482 
483 
484 bool CompareOperation::IsLiteralCompareTypeof(Expression** expr,
485  Handle<String>* check) {
486  return MatchLiteralCompareTypeof(left_, op_, right_, expr, check) ||
487  MatchLiteralCompareTypeof(right_, op_, left_, expr, check);
488 }
489 
490 
491 static bool IsVoidOfLiteral(Expression* expr) {
492  UnaryOperation* maybe_unary = expr->AsUnaryOperation();
493  return maybe_unary != NULL &&
494  maybe_unary->op() == Token::VOID &&
495  maybe_unary->expression()->IsLiteral();
496 }
497 
498 
499 // Check for the pattern: void <literal> equals <expression> or
500 // undefined equals <expression>
502  Token::Value op,
503  Expression* right,
504  Expression** expr,
505  Isolate* isolate) {
506  if (IsVoidOfLiteral(left) && Token::IsEqualityOp(op)) {
507  *expr = right;
508  return true;
509  }
510  if (left->IsUndefinedLiteral(isolate) && Token::IsEqualityOp(op)) {
511  *expr = right;
512  return true;
513  }
514  return false;
515 }
516 
517 
518 bool CompareOperation::IsLiteralCompareUndefined(
519  Expression** expr, Isolate* isolate) {
520  return MatchLiteralCompareUndefined(left_, op_, right_, expr, isolate) ||
521  MatchLiteralCompareUndefined(right_, op_, left_, expr, isolate);
522 }
523 
524 
525 // Check for the pattern: null equals <expression>
527  Token::Value op,
528  Expression* right,
529  Expression** expr) {
530  if (left->IsNullLiteral() && Token::IsEqualityOp(op)) {
531  *expr = right;
532  return true;
533  }
534  return false;
535 }
536 
537 
538 bool CompareOperation::IsLiteralCompareNull(Expression** expr) {
539  return MatchLiteralCompareNull(left_, op_, right_, expr) ||
540  MatchLiteralCompareNull(right_, op_, left_, expr);
541 }
542 
543 
544 // ----------------------------------------------------------------------------
545 // Inlining support
546 
548  return proxy()->var()->IsStackAllocated();
549 }
550 
551 bool FunctionDeclaration::IsInlineable() const {
552  return false;
553 }
554 
555 
556 // ----------------------------------------------------------------------------
557 // Recording of type feedback
558 
559 // TODO(rossberg): all RecordTypeFeedback functions should disappear
560 // once we use the common type field in the AST consistently.
561 
564 }
565 
566 
567 bool Call::IsUsingCallFeedbackSlot(Isolate* isolate) const {
568  CallType call_type = GetCallType(isolate);
569  return (call_type != POSSIBLY_EVAL_CALL);
570 }
571 
572 
573 Call::CallType Call::GetCallType(Isolate* isolate) const {
574  VariableProxy* proxy = expression()->AsVariableProxy();
575  if (proxy != NULL) {
576  if (proxy->var()->is_possibly_eval(isolate)) {
577  return POSSIBLY_EVAL_CALL;
578  } else if (proxy->var()->IsUnallocated()) {
579  return GLOBAL_CALL;
580  } else if (proxy->var()->IsLookupSlot()) {
581  return LOOKUP_SLOT_CALL;
582  }
583  }
584 
585  Property* property = expression()->AsProperty();
586  return property != NULL ? PROPERTY_CALL : OTHER_CALL;
587 }
588 
589 
590 bool Call::ComputeGlobalTarget(Handle<GlobalObject> global,
591  LookupIterator* it) {
592  target_ = Handle<JSFunction>::null();
593  cell_ = Handle<Cell>::null();
594  DCHECK(it->IsFound() && it->GetHolder<JSObject>().is_identical_to(global));
595  cell_ = it->GetPropertyCell();
596  if (cell_->value()->IsJSFunction()) {
597  Handle<JSFunction> candidate(JSFunction::cast(cell_->value()));
598  // If the function is in new space we assume it's more likely to
599  // change and thus prefer the general IC code.
600  if (!it->isolate()->heap()->InNewSpace(*candidate)) {
601  target_ = candidate;
602  return true;
603  }
604  }
605  return false;
606 }
607 
608 
609 void CallNew::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
610  int allocation_site_feedback_slot = FLAG_pretenuring_call_new
611  ? AllocationSiteFeedbackSlot()
612  : CallNewFeedbackSlot();
613  allocation_site_ =
614  oracle->GetCallNewAllocationSite(allocation_site_feedback_slot);
615  is_monomorphic_ = oracle->CallNewIsMonomorphic(CallNewFeedbackSlot());
616  if (is_monomorphic_) {
617  target_ = oracle->GetCallNewTarget(CallNewFeedbackSlot());
618  }
619 }
620 
621 
622 void ObjectLiteral::Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
623  TypeFeedbackId id = key()->LiteralFeedbackId();
624  SmallMapList maps;
625  oracle->CollectReceiverTypes(id, &maps);
626  receiver_type_ = maps.length() == 1 ? maps.at(0)
627  : Handle<Map>::null();
628 }
629 
630 
631 // ----------------------------------------------------------------------------
632 // Implementation of AstVisitor
633 
634 void AstVisitor::VisitDeclarations(ZoneList<Declaration*>* declarations) {
635  for (int i = 0; i < declarations->length(); i++) {
636  Visit(declarations->at(i));
637  }
638 }
639 
640 
641 void AstVisitor::VisitStatements(ZoneList<Statement*>* statements) {
642  for (int i = 0; i < statements->length(); i++) {
643  Statement* stmt = statements->at(i);
644  Visit(stmt);
645  if (stmt->IsJump()) break;
646  }
647 }
648 
649 
650 void AstVisitor::VisitExpressions(ZoneList<Expression*>* expressions) {
651  for (int i = 0; i < expressions->length(); i++) {
652  // The variable statement visiting code may pass NULL expressions
653  // to this code. Maybe this should be handled by introducing an
654  // undefined expression or literal? Revisit this code if this
655  // changes
656  Expression* expression = expressions->at(i);
657  if (expression != NULL) Visit(expression);
658  }
659 }
660 
661 
662 // ----------------------------------------------------------------------------
663 // Regular expressions
664 
665 #define MAKE_ACCEPT(Name) \
666  void* RegExp##Name::Accept(RegExpVisitor* visitor, void* data) { \
667  return visitor->Visit##Name(this, data); \
668  }
670 #undef MAKE_ACCEPT
671 
672 #define MAKE_TYPE_CASE(Name) \
673  RegExp##Name* RegExpTree::As##Name() { \
674  return NULL; \
675  } \
676  bool RegExpTree::Is##Name() { return false; }
678 #undef MAKE_TYPE_CASE
679 
680 #define MAKE_TYPE_CASE(Name) \
681  RegExp##Name* RegExp##Name::As##Name() { \
682  return this; \
683  } \
684  bool RegExp##Name::Is##Name() { return true; }
686 #undef MAKE_TYPE_CASE
687 
688 
690  Interval result = Interval::Empty();
691  for (int i = 0; i < children->length(); i++)
692  result = result.Union(children->at(i)->CaptureRegisters());
693  return result;
694 }
695 
696 
697 Interval RegExpAlternative::CaptureRegisters() {
698  return ListCaptureRegisters(nodes());
699 }
700 
701 
702 Interval RegExpDisjunction::CaptureRegisters() {
703  return ListCaptureRegisters(alternatives());
704 }
705 
706 
707 Interval RegExpLookahead::CaptureRegisters() {
708  return body()->CaptureRegisters();
709 }
710 
711 
712 Interval RegExpCapture::CaptureRegisters() {
713  Interval self(StartRegister(index()), EndRegister(index()));
714  return self.Union(body()->CaptureRegisters());
715 }
716 
717 
718 Interval RegExpQuantifier::CaptureRegisters() {
719  return body()->CaptureRegisters();
720 }
721 
722 
723 bool RegExpAssertion::IsAnchoredAtStart() {
724  return assertion_type() == RegExpAssertion::START_OF_INPUT;
725 }
726 
727 
728 bool RegExpAssertion::IsAnchoredAtEnd() {
729  return assertion_type() == RegExpAssertion::END_OF_INPUT;
730 }
731 
732 
733 bool RegExpAlternative::IsAnchoredAtStart() {
734  ZoneList<RegExpTree*>* nodes = this->nodes();
735  for (int i = 0; i < nodes->length(); i++) {
736  RegExpTree* node = nodes->at(i);
737  if (node->IsAnchoredAtStart()) { return true; }
738  if (node->max_match() > 0) { return false; }
739  }
740  return false;
741 }
742 
743 
744 bool RegExpAlternative::IsAnchoredAtEnd() {
745  ZoneList<RegExpTree*>* nodes = this->nodes();
746  for (int i = nodes->length() - 1; i >= 0; i--) {
747  RegExpTree* node = nodes->at(i);
748  if (node->IsAnchoredAtEnd()) { return true; }
749  if (node->max_match() > 0) { return false; }
750  }
751  return false;
752 }
753 
754 
755 bool RegExpDisjunction::IsAnchoredAtStart() {
756  ZoneList<RegExpTree*>* alternatives = this->alternatives();
757  for (int i = 0; i < alternatives->length(); i++) {
758  if (!alternatives->at(i)->IsAnchoredAtStart())
759  return false;
760  }
761  return true;
762 }
763 
764 
765 bool RegExpDisjunction::IsAnchoredAtEnd() {
766  ZoneList<RegExpTree*>* alternatives = this->alternatives();
767  for (int i = 0; i < alternatives->length(); i++) {
768  if (!alternatives->at(i)->IsAnchoredAtEnd())
769  return false;
770  }
771  return true;
772 }
773 
774 
775 bool RegExpLookahead::IsAnchoredAtStart() {
776  return is_positive() && body()->IsAnchoredAtStart();
777 }
778 
779 
780 bool RegExpCapture::IsAnchoredAtStart() {
781  return body()->IsAnchoredAtStart();
782 }
783 
784 
785 bool RegExpCapture::IsAnchoredAtEnd() {
786  return body()->IsAnchoredAtEnd();
787 }
788 
789 
790 // Convert regular expression trees to a simple sexp representation.
791 // This representation should be different from the input grammar
792 // in as many cases as possible, to make it more difficult for incorrect
793 // parses to look as correct ones which is likely if the input and
794 // output formats are alike.
795 class RegExpUnparser FINAL : public RegExpVisitor {
796  public:
797  RegExpUnparser(OStream& os, Zone* zone) : os_(os), zone_(zone) {}
799 #define MAKE_CASE(Name) virtual void* Visit##Name(RegExp##Name*, \
800  void* data) OVERRIDE;
802 #undef MAKE_CASE
803  private:
805  Zone* zone_;
806 };
807 
808 
809 void* RegExpUnparser::VisitDisjunction(RegExpDisjunction* that, void* data) {
810  os_ << "(|";
811  for (int i = 0; i < that->alternatives()->length(); i++) {
812  os_ << " ";
813  that->alternatives()->at(i)->Accept(this, data);
814  }
815  os_ << ")";
816  return NULL;
817 }
818 
819 
820 void* RegExpUnparser::VisitAlternative(RegExpAlternative* that, void* data) {
821  os_ << "(:";
822  for (int i = 0; i < that->nodes()->length(); i++) {
823  os_ << " ";
824  that->nodes()->at(i)->Accept(this, data);
825  }
826  os_ << ")";
827  return NULL;
828 }
829 
830 
831 void RegExpUnparser::VisitCharacterRange(CharacterRange that) {
832  os_ << AsUC16(that.from());
833  if (!that.IsSingleton()) {
834  os_ << "-" << AsUC16(that.to());
835  }
836 }
837 
838 
839 
840 void* RegExpUnparser::VisitCharacterClass(RegExpCharacterClass* that,
841  void* data) {
842  if (that->is_negated()) os_ << "^";
843  os_ << "[";
844  for (int i = 0; i < that->ranges(zone_)->length(); i++) {
845  if (i > 0) os_ << " ";
846  VisitCharacterRange(that->ranges(zone_)->at(i));
847  }
848  os_ << "]";
849  return NULL;
850 }
851 
852 
853 void* RegExpUnparser::VisitAssertion(RegExpAssertion* that, void* data) {
854  switch (that->assertion_type()) {
855  case RegExpAssertion::START_OF_INPUT:
856  os_ << "@^i";
857  break;
858  case RegExpAssertion::END_OF_INPUT:
859  os_ << "@$i";
860  break;
861  case RegExpAssertion::START_OF_LINE:
862  os_ << "@^l";
863  break;
864  case RegExpAssertion::END_OF_LINE:
865  os_ << "@$l";
866  break;
867  case RegExpAssertion::BOUNDARY:
868  os_ << "@b";
869  break;
870  case RegExpAssertion::NON_BOUNDARY:
871  os_ << "@B";
872  break;
873  }
874  return NULL;
875 }
876 
877 
878 void* RegExpUnparser::VisitAtom(RegExpAtom* that, void* data) {
879  os_ << "'";
880  Vector<const uc16> chardata = that->data();
881  for (int i = 0; i < chardata.length(); i++) {
882  os_ << AsUC16(chardata[i]);
883  }
884  os_ << "'";
885  return NULL;
886 }
887 
888 
889 void* RegExpUnparser::VisitText(RegExpText* that, void* data) {
890  if (that->elements()->length() == 1) {
891  that->elements()->at(0).tree()->Accept(this, data);
892  } else {
893  os_ << "(!";
894  for (int i = 0; i < that->elements()->length(); i++) {
895  os_ << " ";
896  that->elements()->at(i).tree()->Accept(this, data);
897  }
898  os_ << ")";
899  }
900  return NULL;
901 }
902 
903 
904 void* RegExpUnparser::VisitQuantifier(RegExpQuantifier* that, void* data) {
905  os_ << "(# " << that->min() << " ";
906  if (that->max() == RegExpTree::kInfinity) {
907  os_ << "- ";
908  } else {
909  os_ << that->max() << " ";
910  }
911  os_ << (that->is_greedy() ? "g " : that->is_possessive() ? "p " : "n ");
912  that->body()->Accept(this, data);
913  os_ << ")";
914  return NULL;
915 }
916 
917 
918 void* RegExpUnparser::VisitCapture(RegExpCapture* that, void* data) {
919  os_ << "(^ ";
920  that->body()->Accept(this, data);
921  os_ << ")";
922  return NULL;
923 }
924 
925 
926 void* RegExpUnparser::VisitLookahead(RegExpLookahead* that, void* data) {
927  os_ << "(-> " << (that->is_positive() ? "+ " : "- ");
928  that->body()->Accept(this, data);
929  os_ << ")";
930  return NULL;
931 }
932 
933 
934 void* RegExpUnparser::VisitBackReference(RegExpBackReference* that,
935  void* data) {
936  os_ << "(<- " << that->index() << ")";
937  return NULL;
938 }
939 
940 
941 void* RegExpUnparser::VisitEmpty(RegExpEmpty* that, void* data) {
942  os_ << '%';
943  return NULL;
944 }
945 
946 
947 OStream& RegExpTree::Print(OStream& os, Zone* zone) { // NOLINT
948  RegExpUnparser unparser(os, zone);
949  Accept(&unparser, NULL);
950  return os;
951 }
952 
953 
954 RegExpDisjunction::RegExpDisjunction(ZoneList<RegExpTree*>* alternatives)
955  : alternatives_(alternatives) {
956  DCHECK(alternatives->length() > 1);
957  RegExpTree* first_alternative = alternatives->at(0);
958  min_match_ = first_alternative->min_match();
959  max_match_ = first_alternative->max_match();
960  for (int i = 1; i < alternatives->length(); i++) {
961  RegExpTree* alternative = alternatives->at(i);
962  min_match_ = Min(min_match_, alternative->min_match());
963  max_match_ = Max(max_match_, alternative->max_match());
964  }
965 }
966 
967 
968 static int IncreaseBy(int previous, int increase) {
969  if (RegExpTree::kInfinity - previous < increase) {
970  return RegExpTree::kInfinity;
971  } else {
972  return previous + increase;
973  }
974 }
975 
976 RegExpAlternative::RegExpAlternative(ZoneList<RegExpTree*>* nodes)
977  : nodes_(nodes) {
978  DCHECK(nodes->length() > 1);
979  min_match_ = 0;
980  max_match_ = 0;
981  for (int i = 0; i < nodes->length(); i++) {
982  RegExpTree* node = nodes->at(i);
983  int node_min_match = node->min_match();
984  min_match_ = IncreaseBy(min_match_, node_min_match);
985  int node_max_match = node->max_match();
986  max_match_ = IncreaseBy(max_match_, node_max_match);
987  }
988 }
989 
990 
991 CaseClause::CaseClause(Zone* zone, Expression* label,
992  ZoneList<Statement*>* statements, int pos, IdGen* id_gen)
993  : Expression(zone, pos, id_gen),
994  label_(label),
995  statements_(statements),
996  compare_type_(Type::None(zone)),
997  compare_id_(id_gen->GetNextId()),
998  entry_id_(id_gen->GetNextId()) {}
999 
1000 
1001 #define REGULAR_NODE(NodeType) \
1002  void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
1003  increase_node_count(); \
1004  }
1005 #define REGULAR_NODE_WITH_FEEDBACK_SLOTS(NodeType) \
1006  void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
1007  increase_node_count(); \
1008  add_slot_node(node); \
1009  }
1010 #define DONT_OPTIMIZE_NODE(NodeType) \
1011  void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
1012  increase_node_count(); \
1013  set_dont_crankshaft_reason(k##NodeType); \
1014  add_flag(kDontSelfOptimize); \
1015  }
1016 #define DONT_OPTIMIZE_NODE_WITH_FEEDBACK_SLOTS(NodeType) \
1017  void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
1018  increase_node_count(); \
1019  add_slot_node(node); \
1020  set_dont_crankshaft_reason(k##NodeType); \
1021  add_flag(kDontSelfOptimize); \
1022  }
1023 #define DONT_TURBOFAN_NODE(NodeType) \
1024  void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
1025  increase_node_count(); \
1026  set_dont_crankshaft_reason(k##NodeType); \
1027  set_dont_turbofan_reason(k##NodeType); \
1028  add_flag(kDontSelfOptimize); \
1029  }
1030 #define DONT_SELFOPTIMIZE_NODE(NodeType) \
1031  void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
1032  increase_node_count(); \
1033  add_flag(kDontSelfOptimize); \
1034  }
1035 #define DONT_SELFOPTIMIZE_NODE_WITH_FEEDBACK_SLOTS(NodeType) \
1036  void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
1037  increase_node_count(); \
1038  add_slot_node(node); \
1039  add_flag(kDontSelfOptimize); \
1040  }
1041 #define DONT_CACHE_NODE(NodeType) \
1042  void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
1043  increase_node_count(); \
1044  set_dont_crankshaft_reason(k##NodeType); \
1045  add_flag(kDontSelfOptimize); \
1046  add_flag(kDontCache); \
1047  }
1048 
1049 REGULAR_NODE(VariableDeclaration)
1050 REGULAR_NODE(FunctionDeclaration)
1051 REGULAR_NODE(Block)
1052 REGULAR_NODE(ExpressionStatement)
1053 REGULAR_NODE(EmptyStatement)
1054 REGULAR_NODE(IfStatement)
1055 REGULAR_NODE(ContinueStatement)
1056 REGULAR_NODE(BreakStatement)
1057 REGULAR_NODE(ReturnStatement)
1058 REGULAR_NODE(SwitchStatement)
1059 REGULAR_NODE(CaseClause)
1060 REGULAR_NODE(Conditional)
1061 REGULAR_NODE(Literal)
1062 REGULAR_NODE(ArrayLiteral)
1063 REGULAR_NODE(ObjectLiteral)
1064 REGULAR_NODE(RegExpLiteral)
1065 REGULAR_NODE(FunctionLiteral)
1066 REGULAR_NODE(Assignment)
1068 REGULAR_NODE(UnaryOperation)
1069 REGULAR_NODE(CountOperation)
1070 REGULAR_NODE(BinaryOperation)
1071 REGULAR_NODE(CompareOperation)
1072 REGULAR_NODE(ThisFunction)
1073 
1077 // In theory, for VariableProxy we'd have to add:
1078 // if (node->var()->IsLookupSlot())
1079 // set_dont_optimize_reason(kReferenceToAVariableWhichRequiresDynamicLookup);
1080 // But node->var() is usually not bound yet at VariableProxy creation time, and
1081 // LOOKUP variables only result from constructs that cannot be inlined anyway.
1082 REGULAR_NODE_WITH_FEEDBACK_SLOTS(VariableProxy)
1083 
1084 // We currently do not optimize any modules.
1085 DONT_OPTIMIZE_NODE(ModuleDeclaration)
1086 DONT_OPTIMIZE_NODE(ImportDeclaration)
1087 DONT_OPTIMIZE_NODE(ExportDeclaration)
1088 DONT_OPTIMIZE_NODE(ModuleVariable)
1089 DONT_OPTIMIZE_NODE(ModulePath)
1090 DONT_OPTIMIZE_NODE(ModuleUrl)
1091 DONT_OPTIMIZE_NODE(ModuleStatement)
1092 DONT_OPTIMIZE_NODE(WithStatement)
1093 DONT_OPTIMIZE_NODE(DebuggerStatement)
1094 DONT_OPTIMIZE_NODE(ClassLiteral)
1095 DONT_OPTIMIZE_NODE(NativeFunctionLiteral)
1096 DONT_OPTIMIZE_NODE(SuperReference)
1097 
1099 
1100 // TODO(turbofan): Remove the dont_turbofan_reason once this list is empty.
1101 DONT_TURBOFAN_NODE(ForOfStatement)
1102 DONT_TURBOFAN_NODE(TryCatchStatement)
1103 DONT_TURBOFAN_NODE(TryFinallyStatement)
1104 
1105 DONT_SELFOPTIMIZE_NODE(DoWhileStatement)
1106 DONT_SELFOPTIMIZE_NODE(WhileStatement)
1107 DONT_SELFOPTIMIZE_NODE(ForStatement)
1108 
1110 
1111 DONT_CACHE_NODE(ModuleLiteral)
1112 
1113 
1114 void AstConstructionVisitor::VisitCallRuntime(CallRuntime* node) {
1115  increase_node_count();
1116  add_slot_node(node);
1117  if (node->is_jsruntime()) {
1118  // Don't try to optimize JS runtime calls because we bailout on them.
1119  set_dont_crankshaft_reason(kCallToAJavaScriptRuntimeFunction);
1120  }
1121 }
1122 
1123 #undef REGULAR_NODE
1124 #undef DONT_OPTIMIZE_NODE
1125 #undef DONT_SELFOPTIMIZE_NODE
1126 #undef DONT_CACHE_NODE
1127 
1128 
1129 Handle<String> Literal::ToString() {
1130  if (value_->IsString()) return value_->AsString()->string();
1131  DCHECK(value_->IsNumber());
1132  char arr[100];
1133  Vector<char> buffer(arr, arraysize(arr));
1134  const char* str;
1135  if (value()->IsSmi()) {
1136  // Optimization only, the heap number case would subsume this.
1137  SNPrintF(buffer, "%d", Smi::cast(*value())->value());
1138  str = arr;
1139  } else {
1140  str = DoubleToCString(value()->Number(), buffer);
1141  }
1142  return isolate_->factory()->NewStringFromAsciiChecked(str);
1143 }
1144 
1145 
1146 } } // namespace v8::internal
#define MAKE_CASE(Name)
Definition: ast.cc:799
#define DECL_ACCEPT(type)
Definition: ast.cc:26
#define MAKE_ACCEPT(Name)
Definition: ast.cc:665
#define DONT_TURBOFAN_NODE(NodeType)
Definition: ast.cc:1023
#define DONT_CACHE_NODE(NodeType)
Definition: ast.cc:1041
#define DONT_OPTIMIZE_NODE_WITH_FEEDBACK_SLOTS(NodeType)
Definition: ast.cc:1016
#define DONT_SELFOPTIMIZE_NODE(NodeType)
Definition: ast.cc:1030
#define DONT_OPTIMIZE_NODE(NodeType)
Definition: ast.cc:1010
#define REGULAR_NODE_WITH_FEEDBACK_SLOTS(NodeType)
Definition: ast.cc:1005
#define DONT_SELFOPTIMIZE_NODE_WITH_FEEDBACK_SLOTS(NodeType)
Definition: ast.cc:1035
#define REGULAR_NODE(NodeType)
Definition: ast.cc:1001
#define MAKE_TYPE_CASE(Name)
Definition: ast.cc:680
#define AST_NODE_LIST(V)
Definition: ast.h:102
An object reference managed by the v8 garbage collector.
Definition: v8.h:198
Isolate represents an isolated instance of the V8 engine.
Definition: v8.h:4356
static bool IsCompileTimeValue(Expression *expression)
Definition: parser.cc:3331
static Handle< FixedArray > GetValue(Isolate *isolate, Expression *expression)
Definition: parser.cc:3338
VariableProxy * proxy() const
Definition: ast.h:489
virtual bool IsInlineable() const
Definition: ast.cc:547
bool IsUndefinedLiteral(Isolate *isolate) const
Definition: ast.cc:51
virtual void RecordToBooleanTypeFeedback(TypeFeedbackOracle *oracle)
Definition: ast.cc:562
TypeFeedbackId test_id() const
Definition: ast.h:380
bool IsStringLiteral() const
Definition: ast.cc:41
bool IsNullLiteral() const
Definition: ast.cc:46
bool IsSmiLiteral() const
Definition: ast.cc:36
RegExpUnparser(OStream &os, Zone *zone)
Definition: ast.cc:797
OStream & os_
Definition: ast.cc:804
void VisitCharacterRange(CharacterRange that)
static Handle< T > cast(Handle< S > that)
Definition: handles.h:116
static Handle< T > null()
Definition: handles.h:123
static Interval Empty()
Definition: jsregexp.h:715
Interval Union(Interval that)
Definition: jsregexp.h:701
Factory * factory()
Definition: isolate.h:982
static void Expand(Handle< JSArray > array, int minimum_size_of_backing_fixed_array)
Definition: objects.cc:11090
static MUST_USE_RESULT MaybeHandle< Object > SetOwnElement(Handle< JSObject > object, uint32_t index, Handle< Object > value, StrictMode strict_mode)
Definition: objects.cc:12327
T & at(int i) const
Definition: list.h:69
Handle< Object > GetBoilerplateValue(Expression *expression, Isolate *isolate)
Definition: ast.cc:384
void BuildConstants(Isolate *isolate)
Definition: ast.cc:396
OStream & Print(OStream &os, Zone *zone)
Definition: ast.cc:947
virtual void * Accept(RegExpVisitor *visitor, void *data)=0
virtual int min_match()=0
static const int kInfinity
Definition: ast.h:2597
virtual int max_match()=0
static Smi * FromInt(int value)
Definition: objects-inl.h:1321
static bool IsEqualityOp(Value op)
Definition: token.h:210
byte ToBooleanTypes(TypeFeedbackId id)
Definition: type-info.cc:381
Location location() const
Definition: variables.h:124
#define FINAL
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be expose gc extension under the specified name show built in functions in stack traces use random jit cookie to mask large constants minimum length for automatic enable preparsing CPU profiler sampling interval in microseconds trace out of bounds accesses to external arrays default size of stack region v8 is allowed to maximum length of function source code printed in a stack trace min size of a semi the new space consists of two semi spaces print one trace line following each garbage collection do not print trace line after scavenger collection print cumulative GC statistics in name
enable harmony numeric literals(0o77, 0b11)") DEFINE_BOOL(harmony_object_literals
#define COMMA
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
#define FOR_EACH_REG_EXP_TREE_TYPE(VISIT)
Definition: jsregexp.h:391
#define UNREACHABLE()
Definition: logging.h:30
#define DCHECK(condition)
Definition: logging.h:205
#define arraysize(array)
Definition: macros.h:86
static bool MatchLiteralCompareNull(Expression *left, Token::Value op, Expression *right, Expression **expr)
Definition: ast.cc:526
TypeImpl< ZoneTypeConfig > Type
static LifetimePosition Min(LifetimePosition a, LifetimePosition b)
static Interval ListCaptureRegisters(ZoneList< RegExpTree * > *children)
Definition: ast.cc:689
ElementsKind GetPackedElementsKind(ElementsKind holey_kind)
@ STANDARD_STORE
Definition: objects.h:154
int SNPrintF(Vector< char > str, const char *format,...)
Definition: utils.cc:105
TemplateHashMapImpl< ZoneAllocationPolicy > ZoneHashMap
Definition: zone.h:245
kSerializedDataOffset Object
Definition: objects-inl.h:5322
@ FAST_HOLEY_SMI_ELEMENTS
Definition: elements-kind.h:17
Handle< T > handle(T *t, Isolate *isolate)
Definition: handles.h:146
static int IncreaseBy(int previous, int increase)
Definition: ast.cc:968
ElementsKind GetHoleyElementsKind(ElementsKind packed_kind)
static LifetimePosition Max(LifetimePosition a, LifetimePosition b)
static bool IsVoidOfLiteral(Expression *expr)
Definition: ast.cc:491
static bool IsTypeof(Expression *expr)
Definition: ast.cc:463
const char * DoubleToCString(double v, Vector< char > buffer)
Definition: conversions.cc:121
static bool MatchLiteralCompareUndefined(Expression *left, Token::Value op, Expression *right, Expression **expr, Isolate *isolate)
Definition: ast.cc:501
static bool MatchLiteralCompareTypeof(Expression *left, Token::Value op, Expression *right, Expression **expr, Handle< String > *check)
Definition: ast.cc:470
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20
@ None
Definition: v8.h:2211
static Handle< Value > Throw(Isolate *isolate, const char *message)
Definition: d8.cc:72
#define VOID