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