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 
9 #include "src/ast/compile-time-value.h"
10 #include "src/ast/prettyprinter.h"
11 #include "src/ast/scopes.h"
12 #include "src/base/hashmap.h"
13 #include "src/builtins/builtins.h"
14 #include "src/code-stubs.h"
15 #include "src/contexts.h"
16 #include "src/conversions.h"
17 #include "src/elements.h"
18 #include "src/property-details.h"
19 #include "src/property.h"
20 #include "src/string-stream.h"
21 #include "src/type-info.h"
22 
23 namespace v8 {
24 namespace internal {
25 
26 // ----------------------------------------------------------------------------
27 // Implementation of other node functionality.
28 
29 #ifdef DEBUG
30 
Print(Isolate * isolate)31 void AstNode::Print(Isolate* isolate) {
32   AstPrinter::PrintOut(isolate, this);
33 }
34 
35 
36 #endif  // DEBUG
37 
38 #define RETURN_NODE(Node) \
39   case k##Node:           \
40     return static_cast<Node*>(this);
41 
AsIterationStatement()42 IterationStatement* AstNode::AsIterationStatement() {
43   switch (node_type()) {
44     ITERATION_NODE_LIST(RETURN_NODE);
45     default:
46       return nullptr;
47   }
48 }
49 
AsBreakableStatement()50 BreakableStatement* AstNode::AsBreakableStatement() {
51   switch (node_type()) {
52     BREAKABLE_NODE_LIST(RETURN_NODE);
53     ITERATION_NODE_LIST(RETURN_NODE);
54     default:
55       return nullptr;
56   }
57 }
58 
AsMaterializedLiteral()59 MaterializedLiteral* AstNode::AsMaterializedLiteral() {
60   switch (node_type()) {
61     LITERAL_NODE_LIST(RETURN_NODE);
62     default:
63       return nullptr;
64   }
65 }
66 
67 #undef RETURN_NODE
68 
IsSmiLiteral() const69 bool Expression::IsSmiLiteral() const {
70   return IsLiteral() && AsLiteral()->raw_value()->IsSmi();
71 }
72 
IsStringLiteral() const73 bool Expression::IsStringLiteral() const {
74   return IsLiteral() && AsLiteral()->raw_value()->IsString();
75 }
76 
IsPropertyName() const77 bool Expression::IsPropertyName() const {
78   return IsLiteral() && AsLiteral()->IsPropertyName();
79 }
80 
IsNullLiteral() const81 bool Expression::IsNullLiteral() const {
82   if (!IsLiteral()) return false;
83   return AsLiteral()->raw_value()->IsNull();
84 }
85 
IsUndefinedLiteral() const86 bool Expression::IsUndefinedLiteral() const {
87   if (IsLiteral() && AsLiteral()->raw_value()->IsUndefined()) return true;
88 
89   const VariableProxy* var_proxy = AsVariableProxy();
90   if (var_proxy == nullptr) return false;
91   Variable* var = var_proxy->var();
92   // The global identifier "undefined" is immutable. Everything
93   // else could be reassigned.
94   return var != NULL && var->IsUnallocated() &&
95          var_proxy->raw_name()->IsOneByteEqualTo("undefined");
96 }
97 
ToBooleanIsTrue() const98 bool Expression::ToBooleanIsTrue() const {
99   return IsLiteral() && AsLiteral()->ToBooleanIsTrue();
100 }
101 
ToBooleanIsFalse() const102 bool Expression::ToBooleanIsFalse() const {
103   return IsLiteral() && AsLiteral()->ToBooleanIsFalse();
104 }
105 
IsValidReferenceExpression() const106 bool Expression::IsValidReferenceExpression() const {
107   // We don't want expressions wrapped inside RewritableExpression to be
108   // considered as valid reference expressions, as they will be rewritten
109   // to something (most probably involving a do expression).
110   if (IsRewritableExpression()) return false;
111   return IsProperty() ||
112          (IsVariableProxy() && AsVariableProxy()->IsValidReferenceExpression());
113 }
114 
IsValidReferenceExpressionOrThis() const115 bool Expression::IsValidReferenceExpressionOrThis() const {
116   return IsValidReferenceExpression() ||
117          (IsVariableProxy() && AsVariableProxy()->is_this());
118 }
119 
IsAnonymousFunctionDefinition() const120 bool Expression::IsAnonymousFunctionDefinition() const {
121   return (IsFunctionLiteral() &&
122           AsFunctionLiteral()->IsAnonymousFunctionDefinition()) ||
123          (IsDoExpression() &&
124           AsDoExpression()->IsAnonymousFunctionDefinition());
125 }
126 
MarkTail()127 void Expression::MarkTail() {
128   if (IsConditional()) {
129     AsConditional()->MarkTail();
130   } else if (IsCall()) {
131     AsCall()->MarkTail();
132   } else if (IsBinaryOperation()) {
133     AsBinaryOperation()->MarkTail();
134   }
135 }
136 
IsAnonymousFunctionDefinition() const137 bool DoExpression::IsAnonymousFunctionDefinition() const {
138   // This is specifically to allow DoExpressions to represent ClassLiterals.
139   return represented_function_ != nullptr &&
140          represented_function_->raw_name()->length() == 0;
141 }
142 
IsJump() const143 bool Statement::IsJump() const {
144   switch (node_type()) {
145 #define JUMP_NODE_LIST(V) \
146   V(Block)                \
147   V(ExpressionStatement)  \
148   V(ContinueStatement)    \
149   V(BreakStatement)       \
150   V(ReturnStatement)      \
151   V(IfStatement)
152 #define GENERATE_CASE(Node) \
153   case k##Node:             \
154     return static_cast<const Node*>(this)->IsJump();
155     JUMP_NODE_LIST(GENERATE_CASE)
156 #undef GENERATE_CASE
157 #undef JUMP_NODE_LIST
158     default:
159       return false;
160   }
161 }
162 
VariableProxy(Variable * var,int start_position)163 VariableProxy::VariableProxy(Variable* var, int start_position)
164     : Expression(start_position, kVariableProxy),
165       raw_name_(var->raw_name()),
166       next_unresolved_(nullptr) {
167   bit_field_ |= IsThisField::encode(var->is_this()) |
168                 IsAssignedField::encode(false) |
169                 IsResolvedField::encode(false) |
170                 HoleCheckModeField::encode(HoleCheckMode::kElided);
171   BindTo(var);
172 }
173 
VariableProxy(const AstRawString * name,VariableKind variable_kind,int start_position)174 VariableProxy::VariableProxy(const AstRawString* name,
175                              VariableKind variable_kind, int start_position)
176     : Expression(start_position, kVariableProxy),
177       raw_name_(name),
178       next_unresolved_(nullptr) {
179   bit_field_ |= IsThisField::encode(variable_kind == THIS_VARIABLE) |
180                 IsAssignedField::encode(false) |
181                 IsResolvedField::encode(false) |
182                 HoleCheckModeField::encode(HoleCheckMode::kElided);
183 }
184 
VariableProxy(const VariableProxy * copy_from)185 VariableProxy::VariableProxy(const VariableProxy* copy_from)
186     : Expression(copy_from->position(), kVariableProxy),
187       next_unresolved_(nullptr) {
188   bit_field_ = copy_from->bit_field_;
189   DCHECK(!copy_from->is_resolved());
190   raw_name_ = copy_from->raw_name_;
191 }
192 
BindTo(Variable * var)193 void VariableProxy::BindTo(Variable* var) {
194   DCHECK((is_this() && var->is_this()) || raw_name() == var->raw_name());
195   set_var(var);
196   set_is_resolved();
197   var->set_is_used();
198 }
199 
200 
AssignFeedbackVectorSlots(Isolate * isolate,FeedbackVectorSpec * spec,FeedbackVectorSlotCache * cache)201 void VariableProxy::AssignFeedbackVectorSlots(Isolate* isolate,
202                                               FeedbackVectorSpec* spec,
203                                               FeedbackVectorSlotCache* cache) {
204   if (UsesVariableFeedbackSlot()) {
205     // VariableProxies that point to the same Variable within a function can
206     // make their loads from the same IC slot.
207     if (var()->IsUnallocated() || var()->mode() == DYNAMIC_GLOBAL) {
208       ZoneHashMap::Entry* entry = cache->Get(var());
209       if (entry != NULL) {
210         variable_feedback_slot_ = FeedbackVectorSlot(
211             static_cast<int>(reinterpret_cast<intptr_t>(entry->value)));
212         return;
213       }
214       variable_feedback_slot_ = spec->AddLoadGlobalICSlot(var()->name());
215       cache->Put(var(), variable_feedback_slot_);
216     } else {
217       variable_feedback_slot_ = spec->AddLoadICSlot();
218     }
219   }
220 }
221 
222 
AssignVectorSlots(Expression * expr,FeedbackVectorSpec * spec,FeedbackVectorSlot * out_slot)223 static void AssignVectorSlots(Expression* expr, FeedbackVectorSpec* spec,
224                               FeedbackVectorSlot* out_slot) {
225   Property* property = expr->AsProperty();
226   LhsKind assign_type = Property::GetAssignType(property);
227   if ((assign_type == VARIABLE &&
228        expr->AsVariableProxy()->var()->IsUnallocated()) ||
229       assign_type == NAMED_PROPERTY || assign_type == KEYED_PROPERTY) {
230     // TODO(ishell): consider using ICSlotCache for variables here.
231     FeedbackVectorSlotKind kind = assign_type == KEYED_PROPERTY
232                                       ? FeedbackVectorSlotKind::KEYED_STORE_IC
233                                       : FeedbackVectorSlotKind::STORE_IC;
234     *out_slot = spec->AddSlot(kind);
235   }
236 }
237 
AssignFeedbackVectorSlots(Isolate * isolate,FeedbackVectorSpec * spec,FeedbackVectorSlotCache * cache)238 void ForInStatement::AssignFeedbackVectorSlots(Isolate* isolate,
239                                                FeedbackVectorSpec* spec,
240                                                FeedbackVectorSlotCache* cache) {
241   AssignVectorSlots(each(), spec, &each_slot_);
242   for_in_feedback_slot_ = spec->AddGeneralSlot();
243 }
244 
Assignment(Token::Value op,Expression * target,Expression * value,int pos)245 Assignment::Assignment(Token::Value op, Expression* target, Expression* value,
246                        int pos)
247     : Expression(pos, kAssignment),
248       target_(target),
249       value_(value),
250       binary_operation_(NULL) {
251   bit_field_ |= IsUninitializedField::encode(false) |
252                 KeyTypeField::encode(ELEMENT) |
253                 StoreModeField::encode(STANDARD_STORE) | TokenField::encode(op);
254 }
255 
AssignFeedbackVectorSlots(Isolate * isolate,FeedbackVectorSpec * spec,FeedbackVectorSlotCache * cache)256 void Assignment::AssignFeedbackVectorSlots(Isolate* isolate,
257                                            FeedbackVectorSpec* spec,
258                                            FeedbackVectorSlotCache* cache) {
259   AssignVectorSlots(target(), spec, &slot_);
260 }
261 
262 
AssignFeedbackVectorSlots(Isolate * isolate,FeedbackVectorSpec * spec,FeedbackVectorSlotCache * cache)263 void CountOperation::AssignFeedbackVectorSlots(Isolate* isolate,
264                                                FeedbackVectorSpec* spec,
265                                                FeedbackVectorSlotCache* cache) {
266   AssignVectorSlots(expression(), spec, &slot_);
267   // Assign a slot to collect feedback about binary operations. Used only in
268   // ignition. Fullcodegen uses AstId to record type feedback.
269   binary_operation_slot_ = spec->AddInterpreterBinaryOpICSlot();
270 }
271 
272 
binary_op() const273 Token::Value Assignment::binary_op() const {
274   switch (op()) {
275     case Token::ASSIGN_BIT_OR: return Token::BIT_OR;
276     case Token::ASSIGN_BIT_XOR: return Token::BIT_XOR;
277     case Token::ASSIGN_BIT_AND: return Token::BIT_AND;
278     case Token::ASSIGN_SHL: return Token::SHL;
279     case Token::ASSIGN_SAR: return Token::SAR;
280     case Token::ASSIGN_SHR: return Token::SHR;
281     case Token::ASSIGN_ADD: return Token::ADD;
282     case Token::ASSIGN_SUB: return Token::SUB;
283     case Token::ASSIGN_MUL: return Token::MUL;
284     case Token::ASSIGN_DIV: return Token::DIV;
285     case Token::ASSIGN_MOD: return Token::MOD;
286     default: UNREACHABLE();
287   }
288   return Token::ILLEGAL;
289 }
290 
ShouldEagerCompile() const291 bool FunctionLiteral::ShouldEagerCompile() const {
292   return scope()->ShouldEagerCompile();
293 }
294 
SetShouldEagerCompile()295 void FunctionLiteral::SetShouldEagerCompile() {
296   scope()->set_should_eager_compile();
297 }
298 
AllowsLazyCompilation()299 bool FunctionLiteral::AllowsLazyCompilation() {
300   return scope()->AllowsLazyCompilation();
301 }
302 
303 
start_position() const304 int FunctionLiteral::start_position() const {
305   return scope()->start_position();
306 }
307 
308 
end_position() const309 int FunctionLiteral::end_position() const {
310   return scope()->end_position();
311 }
312 
313 
language_mode() const314 LanguageMode FunctionLiteral::language_mode() const {
315   return scope()->language_mode();
316 }
317 
kind() const318 FunctionKind FunctionLiteral::kind() const { return scope()->function_kind(); }
319 
NeedsHomeObject(Expression * expr)320 bool FunctionLiteral::NeedsHomeObject(Expression* expr) {
321   if (expr == nullptr || !expr->IsFunctionLiteral()) return false;
322   DCHECK_NOT_NULL(expr->AsFunctionLiteral()->scope());
323   return expr->AsFunctionLiteral()->scope()->NeedsHomeObject();
324 }
325 
ObjectLiteralProperty(Expression * key,Expression * value,Kind kind,bool is_computed_name)326 ObjectLiteralProperty::ObjectLiteralProperty(Expression* key, Expression* value,
327                                              Kind kind, bool is_computed_name)
328     : LiteralProperty(key, value, is_computed_name),
329       kind_(kind),
330       emit_store_(true) {}
331 
ObjectLiteralProperty(AstValueFactory * ast_value_factory,Expression * key,Expression * value,bool is_computed_name)332 ObjectLiteralProperty::ObjectLiteralProperty(AstValueFactory* ast_value_factory,
333                                              Expression* key, Expression* value,
334                                              bool is_computed_name)
335     : LiteralProperty(key, value, is_computed_name), emit_store_(true) {
336   if (!is_computed_name &&
337       key->AsLiteral()->raw_value()->EqualsString(
338           ast_value_factory->proto_string())) {
339     kind_ = PROTOTYPE;
340   } else if (value_->AsMaterializedLiteral() != NULL) {
341     kind_ = MATERIALIZED_LITERAL;
342   } else if (value_->IsLiteral()) {
343     kind_ = CONSTANT;
344   } else {
345     kind_ = COMPUTED;
346   }
347 }
348 
NeedsSetFunctionName() const349 bool LiteralProperty::NeedsSetFunctionName() const {
350   return is_computed_name_ &&
351          (value_->IsAnonymousFunctionDefinition() ||
352           (value_->IsFunctionLiteral() &&
353            IsConciseMethod(value_->AsFunctionLiteral()->kind())));
354 }
355 
ClassLiteralProperty(Expression * key,Expression * value,Kind kind,bool is_static,bool is_computed_name)356 ClassLiteralProperty::ClassLiteralProperty(Expression* key, Expression* value,
357                                            Kind kind, bool is_static,
358                                            bool is_computed_name)
359     : LiteralProperty(key, value, is_computed_name),
360       kind_(kind),
361       is_static_(is_static) {}
362 
AssignFeedbackVectorSlots(Isolate * isolate,FeedbackVectorSpec * spec,FeedbackVectorSlotCache * cache)363 void ClassLiteral::AssignFeedbackVectorSlots(Isolate* isolate,
364                                              FeedbackVectorSpec* spec,
365                                              FeedbackVectorSlotCache* cache) {
366   // This logic that computes the number of slots needed for vector store
367   // ICs must mirror FullCodeGenerator::VisitClassLiteral.
368   prototype_slot_ = spec->AddLoadICSlot();
369   if (NeedsProxySlot()) {
370     proxy_slot_ = spec->AddStoreICSlot();
371   }
372 
373   for (int i = 0; i < properties()->length(); i++) {
374     ClassLiteral::Property* property = properties()->at(i);
375     Expression* value = property->value();
376     if (FunctionLiteral::NeedsHomeObject(value)) {
377       property->SetSlot(spec->AddStoreICSlot());
378     }
379   }
380 }
381 
IsCompileTimeValue() const382 bool ObjectLiteral::Property::IsCompileTimeValue() const {
383   return kind_ == CONSTANT ||
384       (kind_ == MATERIALIZED_LITERAL &&
385        CompileTimeValue::IsCompileTimeValue(value_));
386 }
387 
388 
set_emit_store(bool emit_store)389 void ObjectLiteral::Property::set_emit_store(bool emit_store) {
390   emit_store_ = emit_store;
391 }
392 
emit_store() const393 bool ObjectLiteral::Property::emit_store() const { return emit_store_; }
394 
AssignFeedbackVectorSlots(Isolate * isolate,FeedbackVectorSpec * spec,FeedbackVectorSlotCache * cache)395 void ObjectLiteral::AssignFeedbackVectorSlots(Isolate* isolate,
396                                               FeedbackVectorSpec* spec,
397                                               FeedbackVectorSlotCache* cache) {
398   // This logic that computes the number of slots needed for vector store
399   // ics must mirror FullCodeGenerator::VisitObjectLiteral.
400   int property_index = 0;
401   for (; property_index < properties()->length(); property_index++) {
402     ObjectLiteral::Property* property = properties()->at(property_index);
403     if (property->is_computed_name()) break;
404     if (property->IsCompileTimeValue()) continue;
405 
406     Literal* key = property->key()->AsLiteral();
407     Expression* value = property->value();
408     switch (property->kind()) {
409       case ObjectLiteral::Property::CONSTANT:
410         UNREACHABLE();
411       case ObjectLiteral::Property::MATERIALIZED_LITERAL:
412       // Fall through.
413       case ObjectLiteral::Property::COMPUTED:
414         // It is safe to use [[Put]] here because the boilerplate already
415         // contains computed properties with an uninitialized value.
416         if (key->value()->IsInternalizedString()) {
417           if (property->emit_store()) {
418             property->SetSlot(spec->AddStoreICSlot());
419             if (FunctionLiteral::NeedsHomeObject(value)) {
420               property->SetSlot(spec->AddStoreICSlot(), 1);
421             }
422           }
423           break;
424         }
425         if (property->emit_store() && FunctionLiteral::NeedsHomeObject(value)) {
426           property->SetSlot(spec->AddStoreICSlot());
427         }
428         break;
429       case ObjectLiteral::Property::PROTOTYPE:
430         break;
431       case ObjectLiteral::Property::GETTER:
432         if (property->emit_store() && FunctionLiteral::NeedsHomeObject(value)) {
433           property->SetSlot(spec->AddStoreICSlot());
434         }
435         break;
436       case ObjectLiteral::Property::SETTER:
437         if (property->emit_store() && FunctionLiteral::NeedsHomeObject(value)) {
438           property->SetSlot(spec->AddStoreICSlot());
439         }
440         break;
441     }
442   }
443 
444   for (; property_index < properties()->length(); property_index++) {
445     ObjectLiteral::Property* property = properties()->at(property_index);
446 
447     Expression* value = property->value();
448     if (property->kind() != ObjectLiteral::Property::PROTOTYPE) {
449       if (FunctionLiteral::NeedsHomeObject(value)) {
450         property->SetSlot(spec->AddStoreICSlot());
451       }
452     }
453   }
454 }
455 
456 
CalculateEmitStore(Zone * zone)457 void ObjectLiteral::CalculateEmitStore(Zone* zone) {
458   const auto GETTER = ObjectLiteral::Property::GETTER;
459   const auto SETTER = ObjectLiteral::Property::SETTER;
460 
461   ZoneAllocationPolicy allocator(zone);
462 
463   CustomMatcherZoneHashMap table(
464       Literal::Match, ZoneHashMap::kDefaultHashMapCapacity, allocator);
465   for (int i = properties()->length() - 1; i >= 0; i--) {
466     ObjectLiteral::Property* property = properties()->at(i);
467     if (property->is_computed_name()) continue;
468     if (property->kind() == ObjectLiteral::Property::PROTOTYPE) continue;
469     Literal* literal = property->key()->AsLiteral();
470     DCHECK(!literal->IsNullLiteral());
471 
472     // If there is an existing entry do not emit a store unless the previous
473     // entry was also an accessor.
474     uint32_t hash = literal->Hash();
475     ZoneHashMap::Entry* entry = table.LookupOrInsert(literal, hash, allocator);
476     if (entry->value != NULL) {
477       auto previous_kind =
478           static_cast<ObjectLiteral::Property*>(entry->value)->kind();
479       if (!((property->kind() == GETTER && previous_kind == SETTER) ||
480             (property->kind() == SETTER && previous_kind == GETTER))) {
481         property->set_emit_store(false);
482       }
483     }
484     entry->value = property;
485   }
486 }
487 
488 
IsBoilerplateProperty(ObjectLiteral::Property * property)489 bool ObjectLiteral::IsBoilerplateProperty(ObjectLiteral::Property* property) {
490   return property != NULL &&
491          property->kind() != ObjectLiteral::Property::PROTOTYPE;
492 }
493 
494 
BuildConstantProperties(Isolate * isolate)495 void ObjectLiteral::BuildConstantProperties(Isolate* isolate) {
496   if (!constant_properties_.is_null()) return;
497 
498   // Allocate a fixed array to hold all the constant properties.
499   Handle<FixedArray> constant_properties = isolate->factory()->NewFixedArray(
500       boilerplate_properties_ * 2, TENURED);
501 
502   int position = 0;
503   // Accumulate the value in local variables and store it at the end.
504   bool is_simple = true;
505   int depth_acc = 1;
506   uint32_t max_element_index = 0;
507   uint32_t elements = 0;
508   for (int i = 0; i < properties()->length(); i++) {
509     ObjectLiteral::Property* property = properties()->at(i);
510     if (!IsBoilerplateProperty(property)) {
511       is_simple = false;
512       continue;
513     }
514 
515     if (static_cast<uint32_t>(position) == boilerplate_properties_ * 2) {
516       DCHECK(property->is_computed_name());
517       is_simple = false;
518       break;
519     }
520     DCHECK(!property->is_computed_name());
521 
522     MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral();
523     if (m_literal != NULL) {
524       m_literal->BuildConstants(isolate);
525       if (m_literal->depth() >= depth_acc) depth_acc = m_literal->depth() + 1;
526     }
527 
528     // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined
529     // value for COMPUTED properties, the real value is filled in at
530     // runtime. The enumeration order is maintained.
531     Handle<Object> key = property->key()->AsLiteral()->value();
532     Handle<Object> value = GetBoilerplateValue(property->value(), isolate);
533 
534     // Ensure objects that may, at any point in time, contain fields with double
535     // representation are always treated as nested objects. This is true for
536     // computed fields (value is undefined), and smi and double literals
537     // (value->IsNumber()).
538     // TODO(verwaest): Remove once we can store them inline.
539     if (FLAG_track_double_fields &&
540         (value->IsNumber() || value->IsUninitialized(isolate))) {
541       bit_field_ = MayStoreDoublesField::update(bit_field_, true);
542     }
543 
544     is_simple = is_simple && !value->IsUninitialized(isolate);
545 
546     // Keep track of the number of elements in the object literal and
547     // the largest element index.  If the largest element index is
548     // much larger than the number of elements, creating an object
549     // literal with fast elements will be a waste of space.
550     uint32_t element_index = 0;
551     if (key->IsString() && String::cast(*key)->AsArrayIndex(&element_index)) {
552       max_element_index = Max(element_index, max_element_index);
553       elements++;
554       key = isolate->factory()->NewNumberFromUint(element_index);
555     } else if (key->ToArrayIndex(&element_index)) {
556       max_element_index = Max(element_index, max_element_index);
557       elements++;
558     } else if (key->IsNumber()) {
559       key = isolate->factory()->NumberToString(key);
560     }
561 
562     // Add name, value pair to the fixed array.
563     constant_properties->set(position++, *key);
564     constant_properties->set(position++, *value);
565   }
566 
567   constant_properties_ = constant_properties;
568   bit_field_ = FastElementsField::update(
569       bit_field_,
570       (max_element_index <= 32) || ((2 * elements) >= max_element_index));
571   bit_field_ = HasElementsField::update(bit_field_, elements > 0);
572 
573   set_is_simple(is_simple);
574   set_depth(depth_acc);
575 }
576 
577 
BuildConstantElements(Isolate * isolate)578 void ArrayLiteral::BuildConstantElements(Isolate* isolate) {
579   DCHECK_LT(first_spread_index_, 0);
580 
581   if (!constant_elements_.is_null()) return;
582 
583   int constants_length = values()->length();
584   ElementsKind kind = FIRST_FAST_ELEMENTS_KIND;
585   Handle<FixedArray> fixed_array =
586       isolate->factory()->NewFixedArrayWithHoles(constants_length);
587 
588   // Fill in the literals.
589   bool is_simple = true;
590   int depth_acc = 1;
591   bool is_holey = false;
592   int array_index = 0;
593   for (; array_index < constants_length; array_index++) {
594     Expression* element = values()->at(array_index);
595     DCHECK(!element->IsSpread());
596     MaterializedLiteral* m_literal = element->AsMaterializedLiteral();
597     if (m_literal != NULL) {
598       m_literal->BuildConstants(isolate);
599       if (m_literal->depth() + 1 > depth_acc) {
600         depth_acc = m_literal->depth() + 1;
601       }
602     }
603 
604     // New handle scope here, needs to be after BuildContants().
605     HandleScope scope(isolate);
606     Handle<Object> boilerplate_value = GetBoilerplateValue(element, isolate);
607     if (boilerplate_value->IsTheHole(isolate)) {
608       is_holey = true;
609       continue;
610     }
611 
612     if (boilerplate_value->IsUninitialized(isolate)) {
613       boilerplate_value = handle(Smi::kZero, isolate);
614       is_simple = false;
615     }
616 
617     kind = GetMoreGeneralElementsKind(kind,
618                                       boilerplate_value->OptimalElementsKind());
619     fixed_array->set(array_index, *boilerplate_value);
620   }
621 
622   if (is_holey) kind = GetHoleyElementsKind(kind);
623 
624   // Simple and shallow arrays can be lazily copied, we transform the
625   // elements array to a copy-on-write array.
626   if (is_simple && depth_acc == 1 && array_index > 0 &&
627       IsFastSmiOrObjectElementsKind(kind)) {
628     fixed_array->set_map(isolate->heap()->fixed_cow_array_map());
629   }
630 
631   Handle<FixedArrayBase> elements = fixed_array;
632   if (IsFastDoubleElementsKind(kind)) {
633     ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
634     elements = isolate->factory()->NewFixedDoubleArray(constants_length);
635     // We are copying from non-fast-double to fast-double.
636     ElementsKind from_kind = TERMINAL_FAST_ELEMENTS_KIND;
637     accessor->CopyElements(fixed_array, from_kind, elements, constants_length);
638   }
639 
640   // Remember both the literal's constant values as well as the ElementsKind
641   // in a 2-element FixedArray.
642   Handle<FixedArray> literals = isolate->factory()->NewFixedArray(2, TENURED);
643   literals->set(0, Smi::FromInt(kind));
644   literals->set(1, *elements);
645 
646   constant_elements_ = literals;
647   set_is_simple(is_simple);
648   set_depth(depth_acc);
649 }
650 
651 
AssignFeedbackVectorSlots(Isolate * isolate,FeedbackVectorSpec * spec,FeedbackVectorSlotCache * cache)652 void ArrayLiteral::AssignFeedbackVectorSlots(Isolate* isolate,
653                                              FeedbackVectorSpec* spec,
654                                              FeedbackVectorSlotCache* cache) {
655   // This logic that computes the number of slots needed for vector store
656   // ics must mirror FullCodeGenerator::VisitArrayLiteral.
657   for (int array_index = 0; array_index < values()->length(); array_index++) {
658     Expression* subexpr = values()->at(array_index);
659     DCHECK(!subexpr->IsSpread());
660     if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
661 
662     // We'll reuse the same literal slot for all of the non-constant
663     // subexpressions that use a keyed store IC.
664     literal_slot_ = spec->AddKeyedStoreICSlot();
665     return;
666   }
667 }
668 
669 
GetBoilerplateValue(Expression * expression,Isolate * isolate)670 Handle<Object> MaterializedLiteral::GetBoilerplateValue(Expression* expression,
671                                                         Isolate* isolate) {
672   if (expression->IsLiteral()) {
673     return expression->AsLiteral()->value();
674   }
675   if (CompileTimeValue::IsCompileTimeValue(expression)) {
676     return CompileTimeValue::GetValue(isolate, expression);
677   }
678   return isolate->factory()->uninitialized_value();
679 }
680 
681 
BuildConstants(Isolate * isolate)682 void MaterializedLiteral::BuildConstants(Isolate* isolate) {
683   if (IsArrayLiteral()) {
684     return AsArrayLiteral()->BuildConstantElements(isolate);
685   }
686   if (IsObjectLiteral()) {
687     return AsObjectLiteral()->BuildConstantProperties(isolate);
688   }
689   DCHECK(IsRegExpLiteral());
690   DCHECK(depth() >= 1);  // Depth should be initialized.
691 }
692 
693 
RecordToBooleanTypeFeedback(TypeFeedbackOracle * oracle)694 void UnaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
695   // TODO(olivf) If this Operation is used in a test context, then the
696   // expression has a ToBoolean stub and we want to collect the type
697   // information. However the GraphBuilder expects it to be on the instruction
698   // corresponding to the TestContext, therefore we have to store it here and
699   // not on the operand.
700   set_to_boolean_types(oracle->ToBooleanTypes(expression()->test_id()));
701 }
702 
703 
RecordToBooleanTypeFeedback(TypeFeedbackOracle * oracle)704 void BinaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
705   // TODO(olivf) If this Operation is used in a test context, then the right
706   // hand side has a ToBoolean stub and we want to collect the type information.
707   // However the GraphBuilder expects it to be on the instruction corresponding
708   // to the TestContext, therefore we have to store it here and not on the
709   // right hand operand.
710   set_to_boolean_types(oracle->ToBooleanTypes(right()->test_id()));
711 }
712 
AssignFeedbackVectorSlots(Isolate * isolate,FeedbackVectorSpec * spec,FeedbackVectorSlotCache * cache)713 void BinaryOperation::AssignFeedbackVectorSlots(
714     Isolate* isolate, FeedbackVectorSpec* spec,
715     FeedbackVectorSlotCache* cache) {
716   // Feedback vector slot is only used by interpreter for binary operations.
717   // Full-codegen uses AstId to record type feedback.
718   switch (op()) {
719     // Comma, logical_or and logical_and do not collect type feedback.
720     case Token::COMMA:
721     case Token::AND:
722     case Token::OR:
723       return;
724     default:
725       type_feedback_slot_ = spec->AddInterpreterBinaryOpICSlot();
726       return;
727   }
728 }
729 
IsTypeof(Expression * expr)730 static bool IsTypeof(Expression* expr) {
731   UnaryOperation* maybe_unary = expr->AsUnaryOperation();
732   return maybe_unary != NULL && maybe_unary->op() == Token::TYPEOF;
733 }
734 
AssignFeedbackVectorSlots(Isolate * isolate,FeedbackVectorSpec * spec,FeedbackVectorSlotCache * cache_)735 void CompareOperation::AssignFeedbackVectorSlots(
736     Isolate* isolate, FeedbackVectorSpec* spec,
737     FeedbackVectorSlotCache* cache_) {
738   // Feedback vector slot is only used by interpreter for binary operations.
739   // Full-codegen uses AstId to record type feedback.
740   switch (op()) {
741     // instanceof and in do not collect type feedback.
742     case Token::INSTANCEOF:
743     case Token::IN:
744       return;
745     default:
746       type_feedback_slot_ = spec->AddInterpreterCompareICSlot();
747   }
748 }
749 
750 // Check for the pattern: typeof <expression> equals <string literal>.
MatchLiteralCompareTypeof(Expression * left,Token::Value op,Expression * right,Expression ** expr,Handle<String> * check)751 static bool MatchLiteralCompareTypeof(Expression* left,
752                                       Token::Value op,
753                                       Expression* right,
754                                       Expression** expr,
755                                       Handle<String>* check) {
756   if (IsTypeof(left) && right->IsStringLiteral() && Token::IsEqualityOp(op)) {
757     *expr = left->AsUnaryOperation()->expression();
758     *check = Handle<String>::cast(right->AsLiteral()->value());
759     return true;
760   }
761   return false;
762 }
763 
764 
IsLiteralCompareTypeof(Expression ** expr,Handle<String> * check)765 bool CompareOperation::IsLiteralCompareTypeof(Expression** expr,
766                                               Handle<String>* check) {
767   return MatchLiteralCompareTypeof(left_, op(), right_, expr, check) ||
768          MatchLiteralCompareTypeof(right_, op(), left_, expr, check);
769 }
770 
771 
IsVoidOfLiteral(Expression * expr)772 static bool IsVoidOfLiteral(Expression* expr) {
773   UnaryOperation* maybe_unary = expr->AsUnaryOperation();
774   return maybe_unary != NULL &&
775       maybe_unary->op() == Token::VOID &&
776       maybe_unary->expression()->IsLiteral();
777 }
778 
779 
780 // Check for the pattern: void <literal> equals <expression> or
781 // undefined equals <expression>
MatchLiteralCompareUndefined(Expression * left,Token::Value op,Expression * right,Expression ** expr)782 static bool MatchLiteralCompareUndefined(Expression* left,
783                                          Token::Value op,
784                                          Expression* right,
785                                          Expression** expr) {
786   if (IsVoidOfLiteral(left) && Token::IsEqualityOp(op)) {
787     *expr = right;
788     return true;
789   }
790   if (left->IsUndefinedLiteral() && Token::IsEqualityOp(op)) {
791     *expr = right;
792     return true;
793   }
794   return false;
795 }
796 
IsLiteralCompareUndefined(Expression ** expr)797 bool CompareOperation::IsLiteralCompareUndefined(Expression** expr) {
798   return MatchLiteralCompareUndefined(left_, op(), right_, expr) ||
799          MatchLiteralCompareUndefined(right_, op(), left_, expr);
800 }
801 
802 
803 // Check for the pattern: null equals <expression>
MatchLiteralCompareNull(Expression * left,Token::Value op,Expression * right,Expression ** expr)804 static bool MatchLiteralCompareNull(Expression* left,
805                                     Token::Value op,
806                                     Expression* right,
807                                     Expression** expr) {
808   if (left->IsNullLiteral() && Token::IsEqualityOp(op)) {
809     *expr = right;
810     return true;
811   }
812   return false;
813 }
814 
815 
IsLiteralCompareNull(Expression ** expr)816 bool CompareOperation::IsLiteralCompareNull(Expression** expr) {
817   return MatchLiteralCompareNull(left_, op(), right_, expr) ||
818          MatchLiteralCompareNull(right_, op(), left_, expr);
819 }
820 
821 
822 // ----------------------------------------------------------------------------
823 // Recording of type feedback
824 
825 // TODO(rossberg): all RecordTypeFeedback functions should disappear
826 // once we use the common type field in the AST consistently.
827 
RecordToBooleanTypeFeedback(TypeFeedbackOracle * oracle)828 void Expression::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
829   if (IsUnaryOperation()) {
830     AsUnaryOperation()->RecordToBooleanTypeFeedback(oracle);
831   } else if (IsBinaryOperation()) {
832     AsBinaryOperation()->RecordToBooleanTypeFeedback(oracle);
833   } else {
834     set_to_boolean_types(oracle->ToBooleanTypes(test_id()));
835   }
836 }
837 
GetReceiverTypes()838 SmallMapList* Expression::GetReceiverTypes() {
839   switch (node_type()) {
840 #define NODE_LIST(V)    \
841   PROPERTY_NODE_LIST(V) \
842   V(Call)
843 #define GENERATE_CASE(Node) \
844   case k##Node:             \
845     return static_cast<Node*>(this)->GetReceiverTypes();
846     NODE_LIST(GENERATE_CASE)
847 #undef NODE_LIST
848 #undef GENERATE_CASE
849     default:
850       UNREACHABLE();
851       return nullptr;
852   }
853 }
854 
GetStoreMode() const855 KeyedAccessStoreMode Expression::GetStoreMode() const {
856   switch (node_type()) {
857 #define GENERATE_CASE(Node) \
858   case k##Node:             \
859     return static_cast<const Node*>(this)->GetStoreMode();
860     PROPERTY_NODE_LIST(GENERATE_CASE)
861 #undef GENERATE_CASE
862     default:
863       UNREACHABLE();
864       return STANDARD_STORE;
865   }
866 }
867 
GetKeyType() const868 IcCheckType Expression::GetKeyType() const {
869   switch (node_type()) {
870 #define GENERATE_CASE(Node) \
871   case k##Node:             \
872     return static_cast<const Node*>(this)->GetKeyType();
873     PROPERTY_NODE_LIST(GENERATE_CASE)
874 #undef GENERATE_CASE
875     default:
876       UNREACHABLE();
877       return PROPERTY;
878   }
879 }
880 
IsMonomorphic() const881 bool Expression::IsMonomorphic() const {
882   switch (node_type()) {
883 #define GENERATE_CASE(Node) \
884   case k##Node:             \
885     return static_cast<const Node*>(this)->IsMonomorphic();
886     PROPERTY_NODE_LIST(GENERATE_CASE)
887     CALL_NODE_LIST(GENERATE_CASE)
888 #undef GENERATE_CASE
889     default:
890       UNREACHABLE();
891       return false;
892   }
893 }
894 
AssignFeedbackVectorSlots(Isolate * isolate,FeedbackVectorSpec * spec,FeedbackVectorSlotCache * cache)895 void Call::AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
896                                      FeedbackVectorSlotCache* cache) {
897   ic_slot_ = spec->AddCallICSlot();
898 }
899 
GetCallType() const900 Call::CallType Call::GetCallType() const {
901   VariableProxy* proxy = expression()->AsVariableProxy();
902   if (proxy != NULL) {
903     if (proxy->var()->IsUnallocated()) {
904       return GLOBAL_CALL;
905     } else if (proxy->var()->IsLookupSlot()) {
906       // Calls going through 'with' always use DYNAMIC rather than DYNAMIC_LOCAL
907       // or DYNAMIC_GLOBAL.
908       return proxy->var()->mode() == DYNAMIC ? WITH_CALL : OTHER_CALL;
909     }
910   }
911 
912   if (expression()->IsSuperCallReference()) return SUPER_CALL;
913 
914   Property* property = expression()->AsProperty();
915   if (property != nullptr) {
916     bool is_super = property->IsSuperAccess();
917     if (property->key()->IsPropertyName()) {
918       return is_super ? NAMED_SUPER_PROPERTY_CALL : NAMED_PROPERTY_CALL;
919     } else {
920       return is_super ? KEYED_SUPER_PROPERTY_CALL : KEYED_PROPERTY_CALL;
921     }
922   }
923 
924   return OTHER_CALL;
925 }
926 
CaseClause(Expression * label,ZoneList<Statement * > * statements,int pos)927 CaseClause::CaseClause(Expression* label, ZoneList<Statement*>* statements,
928                        int pos)
929     : Expression(pos, kCaseClause),
930       label_(label),
931       statements_(statements),
932       compare_type_(AstType::None()) {}
933 
AssignFeedbackVectorSlots(Isolate * isolate,FeedbackVectorSpec * spec,FeedbackVectorSlotCache * cache)934 void CaseClause::AssignFeedbackVectorSlots(Isolate* isolate,
935                                            FeedbackVectorSpec* spec,
936                                            FeedbackVectorSlotCache* cache) {
937   type_feedback_slot_ = spec->AddInterpreterCompareICSlot();
938 }
939 
Hash()940 uint32_t Literal::Hash() {
941   return raw_value()->IsString()
942              ? raw_value()->AsString()->hash()
943              : ComputeLongHash(double_to_uint64(raw_value()->AsNumber()));
944 }
945 
946 
947 // static
Match(void * literal1,void * literal2)948 bool Literal::Match(void* literal1, void* literal2) {
949   const AstValue* x = static_cast<Literal*>(literal1)->raw_value();
950   const AstValue* y = static_cast<Literal*>(literal2)->raw_value();
951   return (x->IsString() && y->IsString() && x->AsString() == y->AsString()) ||
952          (x->IsNumber() && y->IsNumber() && x->AsNumber() == y->AsNumber());
953 }
954 
955 }  // namespace internal
956 }  // namespace v8
957