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