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