V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
ast.cc
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/ast.h"
6 
7 #include <cmath> // For isfinite.
8 #include <vector>
9 
10 #include "src/ast/prettyprinter.h"
11 #include "src/ast/scopes.h"
12 #include "src/base/hashmap.h"
13 #include "src/builtins/builtins-constructor.h"
14 #include "src/builtins/builtins.h"
15 #include "src/code-stubs.h"
16 #include "src/contexts.h"
17 #include "src/conversions-inl.h"
18 #include "src/double.h"
19 #include "src/elements.h"
20 #include "src/objects-inl.h"
21 #include "src/objects/literal-objects-inl.h"
22 #include "src/objects/literal-objects.h"
23 #include "src/objects/map.h"
24 #include "src/property-details.h"
25 #include "src/property.h"
26 #include "src/string-stream.h"
27 
28 namespace v8 {
29 namespace internal {
30 
31 // ----------------------------------------------------------------------------
32 // Implementation of other node functionality.
33 
34 #ifdef DEBUG
35 
36 static const char* NameForNativeContextIntrinsicIndex(uint32_t idx) {
37  switch (idx) {
38 #define NATIVE_CONTEXT_FIELDS_IDX(NAME, Type, name) \
39  case Context::NAME: \
40  return #name;
41 
42  NATIVE_CONTEXT_FIELDS(NATIVE_CONTEXT_FIELDS_IDX)
43 #undef NATIVE_CONTEXT_FIELDS_IDX
44 
45  default:
46  break;
47  }
48 
49  return "UnknownIntrinsicIndex";
50 }
51 
52 void AstNode::Print() { Print(Isolate::Current()); }
53 
54 void AstNode::Print(Isolate* isolate) {
55  AllowHandleDereference allow_deref;
56  AstPrinter::PrintOut(isolate, this);
57 }
58 
59 
60 #endif // DEBUG
61 
62 #define RETURN_NODE(Node) \
63  case k##Node: \
64  return static_cast<Node*>(this);
65 
66 IterationStatement* AstNode::AsIterationStatement() {
67  switch (node_type()) {
68  ITERATION_NODE_LIST(RETURN_NODE);
69  default:
70  return nullptr;
71  }
72 }
73 
74 BreakableStatement* AstNode::AsBreakableStatement() {
75  switch (node_type()) {
76  BREAKABLE_NODE_LIST(RETURN_NODE);
77  ITERATION_NODE_LIST(RETURN_NODE);
78  default:
79  return nullptr;
80  }
81 }
82 
83 MaterializedLiteral* AstNode::AsMaterializedLiteral() {
84  switch (node_type()) {
85  LITERAL_NODE_LIST(RETURN_NODE);
86  default:
87  return nullptr;
88  }
89 }
90 
91 #undef RETURN_NODE
92 
93 bool Expression::IsSmiLiteral() const {
94  return IsLiteral() && AsLiteral()->type() == Literal::kSmi;
95 }
96 
97 bool Expression::IsNumberLiteral() const {
98  return IsLiteral() && AsLiteral()->IsNumber();
99 }
100 
101 bool Expression::IsStringLiteral() const {
102  return IsLiteral() && AsLiteral()->type() == Literal::kString;
103 }
104 
105 bool Expression::IsPropertyName() const {
106  return IsLiteral() && AsLiteral()->IsPropertyName();
107 }
108 
109 bool Expression::IsNullLiteral() const {
110  return IsLiteral() && AsLiteral()->type() == Literal::kNull;
111 }
112 
113 bool Expression::IsTheHoleLiteral() const {
114  return IsLiteral() && AsLiteral()->type() == Literal::kTheHole;
115 }
116 
117 bool Expression::IsCompileTimeValue() {
118  if (IsLiteral()) return true;
119  MaterializedLiteral* literal = AsMaterializedLiteral();
120  if (literal == nullptr) return false;
121  return literal->IsSimple();
122 }
123 
124 bool Expression::IsUndefinedLiteral() const {
125  if (IsLiteral() && AsLiteral()->type() == Literal::kUndefined) return true;
126 
127  const VariableProxy* var_proxy = AsVariableProxy();
128  if (var_proxy == nullptr) return false;
129  Variable* var = var_proxy->var();
130  // The global identifier "undefined" is immutable. Everything
131  // else could be reassigned.
132  return var != nullptr && var->IsUnallocated() &&
133  var_proxy->raw_name()->IsOneByteEqualTo("undefined");
134 }
135 
136 bool Expression::ToBooleanIsTrue() const {
137  return IsLiteral() && AsLiteral()->ToBooleanIsTrue();
138 }
139 
140 bool Expression::ToBooleanIsFalse() const {
141  return IsLiteral() && AsLiteral()->ToBooleanIsFalse();
142 }
143 
144 bool Expression::IsValidReferenceExpression() const {
145  return IsProperty() ||
146  (IsVariableProxy() && AsVariableProxy()->IsValidReferenceExpression());
147 }
148 
149 bool Expression::IsAnonymousFunctionDefinition() const {
150  return (IsFunctionLiteral() &&
151  AsFunctionLiteral()->IsAnonymousFunctionDefinition()) ||
152  (IsClassLiteral() &&
153  AsClassLiteral()->IsAnonymousFunctionDefinition());
154 }
155 
156 bool Expression::IsConciseMethodDefinition() const {
157  return IsFunctionLiteral() && IsConciseMethod(AsFunctionLiteral()->kind());
158 }
159 
160 bool Expression::IsAccessorFunctionDefinition() const {
161  return IsFunctionLiteral() && IsAccessorFunction(AsFunctionLiteral()->kind());
162 }
163 
164 bool Statement::IsJump() const {
165  switch (node_type()) {
166 #define JUMP_NODE_LIST(V) \
167  V(Block) \
168  V(ExpressionStatement) \
169  V(ContinueStatement) \
170  V(BreakStatement) \
171  V(ReturnStatement) \
172  V(IfStatement)
173 #define GENERATE_CASE(Node) \
174  case k##Node: \
175  return static_cast<const Node*>(this)->IsJump();
176  JUMP_NODE_LIST(GENERATE_CASE)
177 #undef GENERATE_CASE
178 #undef JUMP_NODE_LIST
179  default:
180  return false;
181  }
182 }
183 
184 VariableProxy::VariableProxy(Variable* var, int start_position)
185  : Expression(start_position, kVariableProxy),
186  raw_name_(var->raw_name()),
187  next_unresolved_(nullptr) {
188  bit_field_ |= IsThisField::encode(var->is_this()) |
189  IsAssignedField::encode(false) |
190  IsResolvedField::encode(false) |
191  HoleCheckModeField::encode(HoleCheckMode::kElided);
192  BindTo(var);
193 }
194 
195 VariableProxy::VariableProxy(const VariableProxy* copy_from)
196  : Expression(copy_from->position(), kVariableProxy),
197  next_unresolved_(nullptr) {
198  bit_field_ = copy_from->bit_field_;
199  DCHECK(!copy_from->is_resolved());
200  raw_name_ = copy_from->raw_name_;
201 }
202 
203 void VariableProxy::BindTo(Variable* var) {
204  DCHECK((is_this() && var->is_this()) || raw_name() == var->raw_name());
205  set_var(var);
206  set_is_resolved();
207  var->set_is_used();
208  if (is_assigned()) var->set_maybe_assigned();
209 }
210 
211 Assignment::Assignment(NodeType node_type, Token::Value op, Expression* target,
212  Expression* value, int pos)
213  : Expression(pos, node_type), target_(target), value_(value) {
214  bit_field_ |= TokenField::encode(op);
215 }
216 
217 void FunctionLiteral::set_inferred_name(Handle<String> inferred_name) {
218  DCHECK(!inferred_name.is_null());
219  inferred_name_ = inferred_name;
220  DCHECK(raw_inferred_name_ == nullptr || raw_inferred_name_->IsEmpty());
221  raw_inferred_name_ = nullptr;
222  scope()->set_has_inferred_function_name(true);
223 }
224 
225 void FunctionLiteral::set_raw_inferred_name(
226  const AstConsString* raw_inferred_name) {
227  DCHECK_NOT_NULL(raw_inferred_name);
228  raw_inferred_name_ = raw_inferred_name;
229  DCHECK(inferred_name_.is_null());
230  inferred_name_ = Handle<String>();
231  scope()->set_has_inferred_function_name(true);
232 }
233 
234 bool FunctionLiteral::ShouldEagerCompile() const {
235  return scope()->ShouldEagerCompile();
236 }
237 
238 void FunctionLiteral::SetShouldEagerCompile() {
239  scope()->set_should_eager_compile();
240 }
241 
242 bool FunctionLiteral::AllowsLazyCompilation() {
243  return scope()->AllowsLazyCompilation();
244 }
245 
246 Handle<String> FunctionLiteral::name(Isolate* isolate) const {
247  return raw_name_ ? raw_name_->string() : isolate->factory()->empty_string();
248 }
249 
250 int FunctionLiteral::start_position() const {
251  return scope()->start_position();
252 }
253 
254 
255 int FunctionLiteral::end_position() const {
256  return scope()->end_position();
257 }
258 
259 
260 LanguageMode FunctionLiteral::language_mode() const {
261  return scope()->language_mode();
262 }
263 
264 FunctionKind FunctionLiteral::kind() const { return scope()->function_kind(); }
265 
266 bool FunctionLiteral::NeedsHomeObject(Expression* expr) {
267  if (expr == nullptr || !expr->IsFunctionLiteral()) return false;
268  DCHECK_NOT_NULL(expr->AsFunctionLiteral()->scope());
269  return expr->AsFunctionLiteral()->scope()->NeedsHomeObject();
270 }
271 
272 std::unique_ptr<char[]> FunctionLiteral::GetDebugName() const {
273  const AstConsString* cons_string;
274  if (raw_name_ != nullptr && !raw_name_->IsEmpty()) {
275  cons_string = raw_name_;
276  } else if (raw_inferred_name_ != nullptr && !raw_inferred_name_->IsEmpty()) {
277  cons_string = raw_inferred_name_;
278  } else if (!inferred_name_.is_null()) {
279  AllowHandleDereference allow_deref;
280  return inferred_name_->ToCString();
281  } else {
282  char* empty_str = new char[1];
283  empty_str[0] = 0;
284  return std::unique_ptr<char[]>(empty_str);
285  }
286 
287  // TODO(rmcilroy): Deal with two-character strings.
288  std::vector<char> result_vec;
289  std::forward_list<const AstRawString*> strings = cons_string->ToRawStrings();
290  for (const AstRawString* string : strings) {
291  if (!string->is_one_byte()) break;
292  for (int i = 0; i < string->length(); i++) {
293  result_vec.push_back(string->raw_data()[i]);
294  }
295  }
296  std::unique_ptr<char[]> result(new char[result_vec.size() + 1]);
297  memcpy(result.get(), result_vec.data(), result_vec.size());
298  result[result_vec.size()] = '\0';
299  return result;
300 }
301 
302 ObjectLiteralProperty::ObjectLiteralProperty(Expression* key, Expression* value,
303  Kind kind, bool is_computed_name)
304  : LiteralProperty(key, value, is_computed_name),
305  kind_(kind),
306  emit_store_(true) {}
307 
308 ObjectLiteralProperty::ObjectLiteralProperty(AstValueFactory* ast_value_factory,
309  Expression* key, Expression* value,
310  bool is_computed_name)
311  : LiteralProperty(key, value, is_computed_name), emit_store_(true) {
312  if (!is_computed_name && key->AsLiteral()->IsString() &&
313  key->AsLiteral()->AsRawString() == ast_value_factory->proto_string()) {
314  kind_ = PROTOTYPE;
315  } else if (value_->AsMaterializedLiteral() != nullptr) {
316  kind_ = MATERIALIZED_LITERAL;
317  } else if (value_->IsLiteral()) {
318  kind_ = CONSTANT;
319  } else {
320  kind_ = COMPUTED;
321  }
322 }
323 
324 bool LiteralProperty::NeedsSetFunctionName() const {
325  return is_computed_name() && (value_->IsAnonymousFunctionDefinition() ||
326  value_->IsConciseMethodDefinition() ||
327  value_->IsAccessorFunctionDefinition());
328 }
329 
330 ClassLiteralProperty::ClassLiteralProperty(Expression* key, Expression* value,
331  Kind kind, bool is_static,
332  bool is_computed_name,
333  bool is_private)
334  : LiteralProperty(key, value, is_computed_name),
335  kind_(kind),
336  is_static_(is_static),
337  is_private_(is_private),
338  private_or_computed_name_var_(nullptr) {}
339 
340 bool ObjectLiteral::Property::IsCompileTimeValue() const {
341  return kind_ == CONSTANT ||
342  (kind_ == MATERIALIZED_LITERAL && value_->IsCompileTimeValue());
343 }
344 
345 
346 void ObjectLiteral::Property::set_emit_store(bool emit_store) {
347  emit_store_ = emit_store;
348 }
349 
350 bool ObjectLiteral::Property::emit_store() const { return emit_store_; }
351 
352 void ObjectLiteral::CalculateEmitStore(Zone* zone) {
353  const auto GETTER = ObjectLiteral::Property::GETTER;
354  const auto SETTER = ObjectLiteral::Property::SETTER;
355 
356  ZoneAllocationPolicy allocator(zone);
357 
358  CustomMatcherZoneHashMap table(
359  Literal::Match, ZoneHashMap::kDefaultHashMapCapacity, allocator);
360  for (int i = properties()->length() - 1; i >= 0; i--) {
361  ObjectLiteral::Property* property = properties()->at(i);
362  if (property->is_computed_name()) continue;
363  if (property->IsPrototype()) continue;
364  Literal* literal = property->key()->AsLiteral();
365  DCHECK(!literal->IsNullLiteral());
366 
367  uint32_t hash = literal->Hash();
368  ZoneHashMap::Entry* entry = table.LookupOrInsert(literal, hash, allocator);
369  if (entry->value == nullptr) {
370  entry->value = property;
371  } else {
372  // We already have a later definition of this property, so we don't need
373  // to emit a store for the current one.
374  //
375  // There are two subtleties here.
376  //
377  // (1) Emitting a store might actually be incorrect. For example, in {get
378  // foo() {}, foo: 42}, the getter store would override the data property
379  // (which, being a non-computed compile-time valued property, is already
380  // part of the initial literal object.
381  //
382  // (2) If the later definition is an accessor (say, a getter), and the
383  // current definition is a complementary accessor (here, a setter), then
384  // we still must emit a store for the current definition.
385 
386  auto later_kind =
387  static_cast<ObjectLiteral::Property*>(entry->value)->kind();
388  bool complementary_accessors =
389  (property->kind() == GETTER && later_kind == SETTER) ||
390  (property->kind() == SETTER && later_kind == GETTER);
391  if (!complementary_accessors) {
392  property->set_emit_store(false);
393  if (later_kind == GETTER || later_kind == SETTER) {
394  entry->value = property;
395  }
396  }
397  }
398  }
399 }
400 
401 void ObjectLiteral::InitFlagsForPendingNullPrototype(int i) {
402  // We still check for __proto__:null after computed property names.
403  for (; i < properties()->length(); i++) {
404  if (properties()->at(i)->IsNullPrototype()) {
405  set_has_null_protoype(true);
406  break;
407  }
408  }
409 }
410 
411 int ObjectLiteral::InitDepthAndFlags() {
412  if (is_initialized()) return depth();
413  bool is_simple = true;
414  bool has_seen_prototype = false;
415  bool needs_initial_allocation_site = false;
416  int depth_acc = 1;
417  uint32_t nof_properties = 0;
418  uint32_t elements = 0;
419  uint32_t max_element_index = 0;
420  for (int i = 0; i < properties()->length(); i++) {
421  ObjectLiteral::Property* property = properties()->at(i);
422  if (property->IsPrototype()) {
423  has_seen_prototype = true;
424  // __proto__:null has no side-effects and is set directly on the
425  // boilerplate.
426  if (property->IsNullPrototype()) {
427  set_has_null_protoype(true);
428  continue;
429  }
430  DCHECK(!has_null_prototype());
431  is_simple = false;
432  continue;
433  }
434  if (nof_properties == boilerplate_properties_) {
435  DCHECK(property->is_computed_name());
436  is_simple = false;
437  if (!has_seen_prototype) InitFlagsForPendingNullPrototype(i);
438  break;
439  }
440  DCHECK(!property->is_computed_name());
441 
442  MaterializedLiteral* literal = property->value()->AsMaterializedLiteral();
443  if (literal != nullptr) {
444  int subliteral_depth = literal->InitDepthAndFlags() + 1;
445  if (subliteral_depth > depth_acc) depth_acc = subliteral_depth;
446  needs_initial_allocation_site |= literal->NeedsInitialAllocationSite();
447  }
448 
449  Literal* key = property->key()->AsLiteral();
450  Expression* value = property->value();
451 
452  bool is_compile_time_value = value->IsCompileTimeValue();
453  is_simple = is_simple && is_compile_time_value;
454 
455  // Keep track of the number of elements in the object literal and
456  // the largest element index. If the largest element index is
457  // much larger than the number of elements, creating an object
458  // literal with fast elements will be a waste of space.
459  uint32_t element_index = 0;
460  if (key->AsArrayIndex(&element_index)) {
461  max_element_index = Max(element_index, max_element_index);
462  elements++;
463  } else {
464  DCHECK(key->IsPropertyName());
465  }
466 
467  nof_properties++;
468  }
469 
470  set_depth(depth_acc);
471  set_is_simple(is_simple);
472  set_needs_initial_allocation_site(needs_initial_allocation_site);
473  set_has_elements(elements > 0);
474  set_fast_elements((max_element_index <= 32) ||
475  ((2 * elements) >= max_element_index));
476  return depth_acc;
477 }
478 
479 void ObjectLiteral::BuildBoilerplateDescription(Isolate* isolate) {
480  if (!boilerplate_description_.is_null()) return;
481 
482  int index_keys = 0;
483  bool has_seen_proto = false;
484  for (int i = 0; i < properties()->length(); i++) {
485  ObjectLiteral::Property* property = properties()->at(i);
486  if (property->IsPrototype()) {
487  has_seen_proto = true;
488  continue;
489  }
490  if (property->is_computed_name()) {
491  continue;
492  }
493 
494  Literal* key = property->key()->AsLiteral();
495 
496  if (!key->IsPropertyName()) {
497  index_keys++;
498  }
499  }
500 
501  Handle<ObjectBoilerplateDescription> boilerplate_description =
502  isolate->factory()->NewObjectBoilerplateDescription(
503  boilerplate_properties_, properties()->length(), index_keys,
504  has_seen_proto);
505 
506  int position = 0;
507  for (int i = 0; i < properties()->length(); i++) {
508  ObjectLiteral::Property* property = properties()->at(i);
509  if (property->IsPrototype()) continue;
510 
511  if (static_cast<uint32_t>(position) == boilerplate_properties_) {
512  DCHECK(property->is_computed_name());
513  break;
514  }
515  DCHECK(!property->is_computed_name());
516 
517  MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral();
518  if (m_literal != nullptr) {
519  m_literal->BuildConstants(isolate);
520  }
521 
522  // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined
523  // value for COMPUTED properties, the real value is filled in at
524  // runtime. The enumeration order is maintained.
525  Literal* key_literal = property->key()->AsLiteral();
526  uint32_t element_index = 0;
527  Handle<Object> key =
528  key_literal->AsArrayIndex(&element_index)
529  ? isolate->factory()->NewNumberFromUint(element_index)
530  : Handle<Object>::cast(key_literal->AsRawPropertyName()->string());
531 
532  Handle<Object> value = GetBoilerplateValue(property->value(), isolate);
533 
534  // Add name, value pair to the fixed array.
535  boilerplate_description->set_key_value(position++, *key, *value);
536  }
537 
538  boilerplate_description->set_flags(EncodeLiteralType());
539 
540  boilerplate_description_ = boilerplate_description;
541 }
542 
543 bool ObjectLiteral::IsFastCloningSupported() const {
544  // The CreateShallowObjectLiteratal builtin doesn't copy elements, and object
545  // literals don't support copy-on-write (COW) elements for now.
546  // TODO(mvstanton): make object literals support COW elements.
547  return fast_elements() && is_shallow() &&
548  properties_count() <=
549  ConstructorBuiltins::kMaximumClonedShallowObjectProperties;
550 }
551 
552 int ArrayLiteral::InitDepthAndFlags() {
553  if (is_initialized()) return depth();
554 
555  int constants_length =
556  first_spread_index_ >= 0 ? first_spread_index_ : values()->length();
557 
558  // Fill in the literals.
559  bool is_simple = first_spread_index_ < 0;
560  int depth_acc = 1;
561  int array_index = 0;
562  for (; array_index < constants_length; array_index++) {
563  Expression* element = values()->at(array_index);
564  MaterializedLiteral* literal = element->AsMaterializedLiteral();
565  if (literal != nullptr) {
566  int subliteral_depth = literal->InitDepthAndFlags() + 1;
567  if (subliteral_depth > depth_acc) depth_acc = subliteral_depth;
568  }
569 
570  if (!element->IsCompileTimeValue()) {
571  is_simple = false;
572  }
573  }
574 
575  set_depth(depth_acc);
576  set_is_simple(is_simple);
577  // Array literals always need an initial allocation site to properly track
578  // elements transitions.
579  set_needs_initial_allocation_site(true);
580  return depth_acc;
581 }
582 
583 void ArrayLiteral::BuildBoilerplateDescription(Isolate* isolate) {
584  if (!boilerplate_description_.is_null()) return;
585 
586  int constants_length =
587  first_spread_index_ >= 0 ? first_spread_index_ : values()->length();
588  ElementsKind kind = FIRST_FAST_ELEMENTS_KIND;
589  Handle<FixedArray> fixed_array =
590  isolate->factory()->NewFixedArrayWithHoles(constants_length);
591 
592  // Fill in the literals.
593  bool is_holey = false;
594  int array_index = 0;
595  for (; array_index < constants_length; array_index++) {
596  Expression* element = values()->at(array_index);
597  DCHECK(!element->IsSpread());
598  MaterializedLiteral* m_literal = element->AsMaterializedLiteral();
599  if (m_literal != nullptr) {
600  m_literal->BuildConstants(isolate);
601  }
602 
603  // New handle scope here, needs to be after BuildContants().
604  HandleScope scope(isolate);
605  Handle<Object> boilerplate_value = GetBoilerplateValue(element, isolate);
606  if (boilerplate_value->IsTheHole(isolate)) {
607  is_holey = true;
608  continue;
609  }
610 
611  if (boilerplate_value->IsUninitialized(isolate)) {
612  boilerplate_value = handle(Smi::kZero, isolate);
613  }
614 
615  kind = GetMoreGeneralElementsKind(kind,
616  boilerplate_value->OptimalElementsKind());
617  fixed_array->set(array_index, *boilerplate_value);
618  }
619 
620  if (is_holey) kind = GetHoleyElementsKind(kind);
621 
622  // Simple and shallow arrays can be lazily copied, we transform the
623  // elements array to a copy-on-write array.
624  if (is_simple() && depth() == 1 && array_index > 0 &&
625  IsSmiOrObjectElementsKind(kind)) {
626  fixed_array->set_map(ReadOnlyRoots(isolate).fixed_cow_array_map());
627  }
628 
629  Handle<FixedArrayBase> elements = fixed_array;
630  if (IsDoubleElementsKind(kind)) {
631  ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
632  elements = isolate->factory()->NewFixedDoubleArray(constants_length);
633  // We are copying from non-fast-double to fast-double.
634  ElementsKind from_kind = TERMINAL_FAST_ELEMENTS_KIND;
635  accessor->CopyElements(isolate, fixed_array, from_kind, elements,
636  constants_length);
637  }
638 
639  boilerplate_description_ =
640  isolate->factory()->NewArrayBoilerplateDescription(kind, elements);
641 }
642 
643 bool ArrayLiteral::IsFastCloningSupported() const {
644  return depth() <= 1 &&
645  values_.length() <=
646  ConstructorBuiltins::kMaximumClonedShallowArrayElements;
647 }
648 
649 bool MaterializedLiteral::IsSimple() const {
650  if (IsArrayLiteral()) return AsArrayLiteral()->is_simple();
651  if (IsObjectLiteral()) return AsObjectLiteral()->is_simple();
652  DCHECK(IsRegExpLiteral());
653  return false;
654 }
655 
656 Handle<Object> MaterializedLiteral::GetBoilerplateValue(Expression* expression,
657  Isolate* isolate) {
658  if (expression->IsLiteral()) {
659  return expression->AsLiteral()->BuildValue(isolate);
660  }
661  if (expression->IsCompileTimeValue()) {
662  if (expression->IsObjectLiteral()) {
663  ObjectLiteral* object_literal = expression->AsObjectLiteral();
664  DCHECK(object_literal->is_simple());
665  return object_literal->boilerplate_description();
666  } else {
667  DCHECK(expression->IsArrayLiteral());
668  ArrayLiteral* array_literal = expression->AsArrayLiteral();
669  DCHECK(array_literal->is_simple());
670  return array_literal->boilerplate_description();
671  }
672  }
673  return isolate->factory()->uninitialized_value();
674 }
675 
676 int MaterializedLiteral::InitDepthAndFlags() {
677  if (IsArrayLiteral()) return AsArrayLiteral()->InitDepthAndFlags();
678  if (IsObjectLiteral()) return AsObjectLiteral()->InitDepthAndFlags();
679  DCHECK(IsRegExpLiteral());
680  return 1;
681 }
682 
683 bool MaterializedLiteral::NeedsInitialAllocationSite() {
684  if (IsArrayLiteral()) {
685  return AsArrayLiteral()->needs_initial_allocation_site();
686  }
687  if (IsObjectLiteral()) {
688  return AsObjectLiteral()->needs_initial_allocation_site();
689  }
690  DCHECK(IsRegExpLiteral());
691  return false;
692 }
693 
694 void MaterializedLiteral::BuildConstants(Isolate* isolate) {
695  if (IsArrayLiteral()) {
696  AsArrayLiteral()->BuildBoilerplateDescription(isolate);
697  return;
698  }
699  if (IsObjectLiteral()) {
700  AsObjectLiteral()->BuildBoilerplateDescription(isolate);
701  return;
702  }
703  DCHECK(IsRegExpLiteral());
704 }
705 
706 Handle<TemplateObjectDescription> GetTemplateObject::GetOrBuildDescription(
707  Isolate* isolate) {
708  Handle<FixedArray> raw_strings =
709  isolate->factory()->NewFixedArray(this->raw_strings()->length(), TENURED);
710  bool raw_and_cooked_match = true;
711  for (int i = 0; i < raw_strings->length(); ++i) {
712  if (this->cooked_strings()->at(i) == nullptr ||
713  *this->raw_strings()->at(i)->string() !=
714  *this->cooked_strings()->at(i)->string()) {
715  raw_and_cooked_match = false;
716  }
717  raw_strings->set(i, *this->raw_strings()->at(i)->string());
718  }
719  Handle<FixedArray> cooked_strings = raw_strings;
720  if (!raw_and_cooked_match) {
721  cooked_strings = isolate->factory()->NewFixedArray(
722  this->cooked_strings()->length(), TENURED);
723  for (int i = 0; i < cooked_strings->length(); ++i) {
724  if (this->cooked_strings()->at(i) != nullptr) {
725  cooked_strings->set(i, *this->cooked_strings()->at(i)->string());
726  } else {
727  cooked_strings->set(i, ReadOnlyRoots(isolate).undefined_value());
728  }
729  }
730  }
731  return isolate->factory()->NewTemplateObjectDescription(raw_strings,
732  cooked_strings);
733 }
734 
735 static bool IsCommutativeOperationWithSmiLiteral(Token::Value op) {
736  // Add is not commutative due to potential for string addition.
737  return op == Token::MUL || op == Token::BIT_AND || op == Token::BIT_OR ||
738  op == Token::BIT_XOR;
739 }
740 
741 // Check for the pattern: x + 1.
742 static bool MatchSmiLiteralOperation(Expression* left, Expression* right,
743  Expression** expr, Smi* literal) {
744  if (right->IsSmiLiteral()) {
745  *expr = left;
746  *literal = right->AsLiteral()->AsSmiLiteral();
747  return true;
748  }
749  return false;
750 }
751 
752 bool BinaryOperation::IsSmiLiteralOperation(Expression** subexpr,
753  Smi* literal) {
754  return MatchSmiLiteralOperation(left_, right_, subexpr, literal) ||
755  (IsCommutativeOperationWithSmiLiteral(op()) &&
756  MatchSmiLiteralOperation(right_, left_, subexpr, literal));
757 }
758 
759 static bool IsTypeof(Expression* expr) {
760  UnaryOperation* maybe_unary = expr->AsUnaryOperation();
761  return maybe_unary != nullptr && maybe_unary->op() == Token::TYPEOF;
762 }
763 
764 // Check for the pattern: typeof <expression> equals <string literal>.
765 static bool MatchLiteralCompareTypeof(Expression* left, Token::Value op,
766  Expression* right, Expression** expr,
767  Literal** literal) {
768  if (IsTypeof(left) && right->IsStringLiteral() && Token::IsEqualityOp(op)) {
769  *expr = left->AsUnaryOperation()->expression();
770  *literal = right->AsLiteral();
771  return true;
772  }
773  return false;
774 }
775 
776 bool CompareOperation::IsLiteralCompareTypeof(Expression** expr,
777  Literal** literal) {
778  return MatchLiteralCompareTypeof(left_, op(), right_, expr, literal) ||
779  MatchLiteralCompareTypeof(right_, op(), left_, expr, literal);
780 }
781 
782 
783 static bool IsVoidOfLiteral(Expression* expr) {
784  UnaryOperation* maybe_unary = expr->AsUnaryOperation();
785  return maybe_unary != nullptr && maybe_unary->op() == Token::VOID &&
786  maybe_unary->expression()->IsLiteral();
787 }
788 
789 
790 // Check for the pattern: void <literal> equals <expression> or
791 // undefined equals <expression>
792 static bool MatchLiteralCompareUndefined(Expression* left,
793  Token::Value op,
794  Expression* right,
795  Expression** expr) {
796  if (IsVoidOfLiteral(left) && Token::IsEqualityOp(op)) {
797  *expr = right;
798  return true;
799  }
800  if (left->IsUndefinedLiteral() && Token::IsEqualityOp(op)) {
801  *expr = right;
802  return true;
803  }
804  return false;
805 }
806 
807 bool CompareOperation::IsLiteralCompareUndefined(Expression** expr) {
808  return MatchLiteralCompareUndefined(left_, op(), right_, expr) ||
809  MatchLiteralCompareUndefined(right_, op(), left_, expr);
810 }
811 
812 // Check for the pattern: null equals <expression>
813 static bool MatchLiteralCompareNull(Expression* left,
814  Token::Value op,
815  Expression* right,
816  Expression** expr) {
817  if (left->IsNullLiteral() && Token::IsEqualityOp(op)) {
818  *expr = right;
819  return true;
820  }
821  return false;
822 }
823 
824 bool CompareOperation::IsLiteralCompareNull(Expression** expr) {
825  return MatchLiteralCompareNull(left_, op(), right_, expr) ||
826  MatchLiteralCompareNull(right_, op(), left_, expr);
827 }
828 
829 Call::CallType Call::GetCallType() const {
830  VariableProxy* proxy = expression()->AsVariableProxy();
831  if (proxy != nullptr) {
832  if (proxy->var()->IsUnallocated()) {
833  return GLOBAL_CALL;
834  } else if (proxy->var()->IsLookupSlot()) {
835  // Calls going through 'with' always use VariableMode::kDynamic rather
836  // than VariableMode::kDynamicLocal or VariableMode::kDynamicGlobal.
837  return proxy->var()->mode() == VariableMode::kDynamic ? WITH_CALL
838  : OTHER_CALL;
839  }
840  }
841 
842  if (expression()->IsSuperCallReference()) return SUPER_CALL;
843 
844  Property* property = expression()->AsProperty();
845  if (property != nullptr) {
846  bool is_super = property->IsSuperAccess();
847  if (property->key()->IsPropertyName()) {
848  return is_super ? NAMED_SUPER_PROPERTY_CALL : NAMED_PROPERTY_CALL;
849  } else {
850  return is_super ? KEYED_SUPER_PROPERTY_CALL : KEYED_PROPERTY_CALL;
851  }
852  }
853 
854  if (expression()->IsResolvedProperty()) {
855  return RESOLVED_PROPERTY_CALL;
856  }
857 
858  return OTHER_CALL;
859 }
860 
861 CaseClause::CaseClause(Zone* zone, Expression* label,
862  const ScopedPtrList<Statement>& statements)
863  : label_(label), statements_(0, nullptr) {
864  statements.CopyTo(&statements_, zone);
865 }
866 
867 bool Literal::IsPropertyName() const {
868  if (type() != kString) return false;
869  uint32_t index;
870  return !string_->AsArrayIndex(&index);
871 }
872 
873 bool Literal::ToUint32(uint32_t* value) const {
874  switch (type()) {
875  case kString:
876  return string_->AsArrayIndex(value);
877  case kSmi:
878  if (smi_ < 0) return false;
879  *value = static_cast<uint32_t>(smi_);
880  return true;
881  case kHeapNumber:
882  return DoubleToUint32IfEqualToSelf(AsNumber(), value);
883  default:
884  return false;
885  }
886 }
887 
888 bool Literal::AsArrayIndex(uint32_t* value) const {
889  return ToUint32(value) && *value != kMaxUInt32;
890 }
891 
892 Handle<Object> Literal::BuildValue(Isolate* isolate) const {
893  switch (type()) {
894  case kSmi:
895  return handle(Smi::FromInt(smi_), isolate);
896  case kHeapNumber:
897  return isolate->factory()->NewNumber(number_, TENURED);
898  case kString:
899  return string_->string();
900  case kSymbol:
901  return isolate->factory()->home_object_symbol();
902  case kBoolean:
903  return isolate->factory()->ToBoolean(boolean_);
904  case kNull:
905  return isolate->factory()->null_value();
906  case kUndefined:
907  return isolate->factory()->undefined_value();
908  case kTheHole:
909  return isolate->factory()->the_hole_value();
910  case kBigInt:
911  // This should never fail: the parser will never create a BigInt
912  // literal that cannot be allocated.
913  return BigIntLiteral(isolate, bigint_.c_str()).ToHandleChecked();
914  }
915  UNREACHABLE();
916 }
917 
918 bool Literal::ToBooleanIsTrue() const {
919  switch (type()) {
920  case kSmi:
921  return smi_ != 0;
922  case kHeapNumber:
923  return DoubleToBoolean(number_);
924  case kString:
925  return !string_->IsEmpty();
926  case kNull:
927  case kUndefined:
928  return false;
929  case kBoolean:
930  return boolean_;
931  case kBigInt: {
932  const char* bigint_str = bigint_.c_str();
933  size_t length = strlen(bigint_str);
934  DCHECK_GT(length, 0);
935  if (length == 1 && bigint_str[0] == '0') return false;
936  // Skip over any radix prefix; BigInts with length > 1 only
937  // begin with zero if they include a radix.
938  for (size_t i = (bigint_str[0] == '0') ? 2 : 0; i < length; ++i) {
939  if (bigint_str[i] != '0') return true;
940  }
941  return false;
942  }
943  case kSymbol:
944  return true;
945  case kTheHole:
946  UNREACHABLE();
947  }
948  UNREACHABLE();
949 }
950 
951 uint32_t Literal::Hash() {
952  return IsString() ? AsRawString()->Hash()
953  : ComputeLongHash(double_to_uint64(AsNumber()));
954 }
955 
956 
957 // static
958 bool Literal::Match(void* a, void* b) {
959  Literal* x = static_cast<Literal*>(a);
960  Literal* y = static_cast<Literal*>(b);
961  return (x->IsString() && y->IsString() &&
962  x->AsRawString() == y->AsRawString()) ||
963  (x->IsNumber() && y->IsNumber() && x->AsNumber() == y->AsNumber());
964 }
965 
966 Literal* AstNodeFactory::NewNumberLiteral(double number, int pos) {
967  int int_value;
968  if (DoubleToSmiInteger(number, &int_value)) {
969  return NewSmiLiteral(int_value, pos);
970  }
971  return new (zone_) Literal(number, pos);
972 }
973 
974 const char* CallRuntime::debug_name() {
975 #ifdef DEBUG
976  return is_jsruntime() ? NameForNativeContextIntrinsicIndex(context_index_)
977  : function_->name;
978 #else
979  return is_jsruntime() ? "(context function)" : function_->name;
980 #endif // DEBUG
981 }
982 
983 #define RETURN_LABELS(NodeType) \
984  case k##NodeType: \
985  return static_cast<const NodeType*>(this)->labels();
986 
987 ZonePtrList<const AstRawString>* BreakableStatement::labels() const {
988  switch (node_type()) {
989  BREAKABLE_NODE_LIST(RETURN_LABELS)
990  ITERATION_NODE_LIST(RETURN_LABELS)
991  default:
992  UNREACHABLE();
993  }
994 }
995 
996 #undef RETURN_LABELS
997 
998 } // namespace internal
999 } // namespace v8
Definition: libplatform.h:13