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