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