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/base/logging.h"
14 #include "src/builtins/builtins-constructor.h"
15 #include "src/builtins/builtins.h"
16 #include "src/common/assert-scope.h"
17 #include "src/execution/off-thread-isolate.h"
18 #include "src/heap/off-thread-factory-inl.h"
19 #include "src/numbers/conversions-inl.h"
20 #include "src/numbers/double.h"
21 #include "src/objects/contexts.h"
22 #include "src/objects/elements-kind.h"
23 #include "src/objects/elements.h"
24 #include "src/objects/fixed-array.h"
25 #include "src/objects/literal-objects-inl.h"
26 #include "src/objects/literal-objects.h"
27 #include "src/objects/map.h"
28 #include "src/objects/objects-inl.h"
29 #include "src/objects/property-details.h"
30 #include "src/objects/property.h"
31 #include "src/strings/string-stream.h"
32 #include "src/zone/zone-list-inl.h"
33
34 namespace v8 {
35 namespace internal {
36
37 // ----------------------------------------------------------------------------
38 // Implementation of other node functionality.
39
40 #ifdef DEBUG
41
NameForNativeContextIntrinsicIndex(uint32_t idx)42 static const char* NameForNativeContextIntrinsicIndex(uint32_t idx) {
43 switch (idx) {
44 #define NATIVE_CONTEXT_FIELDS_IDX(NAME, Type, name) \
45 case Context::NAME: \
46 return #name;
47
48 NATIVE_CONTEXT_FIELDS(NATIVE_CONTEXT_FIELDS_IDX)
49 #undef NATIVE_CONTEXT_FIELDS_IDX
50
51 default:
52 break;
53 }
54
55 return "UnknownIntrinsicIndex";
56 }
57
Print(Isolate * isolate)58 void AstNode::Print(Isolate* isolate) {
59 AllowHandleDereference allow_deref;
60 AstPrinter::PrintOut(isolate, this);
61 }
62
63 #endif // DEBUG
64
65 #define RETURN_NODE(Node) \
66 case k##Node: \
67 return static_cast<Node*>(this);
68
AsIterationStatement()69 IterationStatement* AstNode::AsIterationStatement() {
70 switch (node_type()) {
71 ITERATION_NODE_LIST(RETURN_NODE);
72 default:
73 return nullptr;
74 }
75 }
76
AsMaterializedLiteral()77 MaterializedLiteral* AstNode::AsMaterializedLiteral() {
78 switch (node_type()) {
79 LITERAL_NODE_LIST(RETURN_NODE);
80 default:
81 return nullptr;
82 }
83 }
84
85 #undef RETURN_NODE
86
IsSmiLiteral() const87 bool Expression::IsSmiLiteral() const {
88 return IsLiteral() && AsLiteral()->type() == Literal::kSmi;
89 }
90
IsNumberLiteral() const91 bool Expression::IsNumberLiteral() const {
92 return IsLiteral() && AsLiteral()->IsNumber();
93 }
94
IsStringLiteral() const95 bool Expression::IsStringLiteral() const {
96 return IsLiteral() && AsLiteral()->type() == Literal::kString;
97 }
98
IsPropertyName() const99 bool Expression::IsPropertyName() const {
100 return IsLiteral() && AsLiteral()->IsPropertyName();
101 }
102
IsNullLiteral() const103 bool Expression::IsNullLiteral() const {
104 return IsLiteral() && AsLiteral()->type() == Literal::kNull;
105 }
106
IsTheHoleLiteral() const107 bool Expression::IsTheHoleLiteral() const {
108 return IsLiteral() && AsLiteral()->type() == Literal::kTheHole;
109 }
110
IsCompileTimeValue()111 bool Expression::IsCompileTimeValue() {
112 if (IsLiteral()) return true;
113 MaterializedLiteral* literal = AsMaterializedLiteral();
114 if (literal == nullptr) return false;
115 return literal->IsSimple();
116 }
117
IsUndefinedLiteral() const118 bool Expression::IsUndefinedLiteral() const {
119 if (IsLiteral() && AsLiteral()->type() == Literal::kUndefined) return true;
120
121 const VariableProxy* var_proxy = AsVariableProxy();
122 if (var_proxy == nullptr) return false;
123 Variable* var = var_proxy->var();
124 // The global identifier "undefined" is immutable. Everything
125 // else could be reassigned.
126 return var != nullptr && var->IsUnallocated() &&
127 var_proxy->raw_name()->IsOneByteEqualTo("undefined");
128 }
129
IsLiteralButNotNullOrUndefined() const130 bool Expression::IsLiteralButNotNullOrUndefined() const {
131 return IsLiteral() && !IsNullOrUndefinedLiteral();
132 }
133
ToBooleanIsTrue() const134 bool Expression::ToBooleanIsTrue() const {
135 return IsLiteral() && AsLiteral()->ToBooleanIsTrue();
136 }
137
ToBooleanIsFalse() const138 bool Expression::ToBooleanIsFalse() const {
139 return IsLiteral() && AsLiteral()->ToBooleanIsFalse();
140 }
141
IsPrivateName() const142 bool Expression::IsPrivateName() const {
143 return IsVariableProxy() && AsVariableProxy()->IsPrivateName();
144 }
145
IsValidReferenceExpression() const146 bool Expression::IsValidReferenceExpression() const {
147 return IsProperty() ||
148 (IsVariableProxy() && AsVariableProxy()->IsValidReferenceExpression());
149 }
150
IsAnonymousFunctionDefinition() const151 bool Expression::IsAnonymousFunctionDefinition() const {
152 return (IsFunctionLiteral() &&
153 AsFunctionLiteral()->IsAnonymousFunctionDefinition()) ||
154 (IsClassLiteral() &&
155 AsClassLiteral()->IsAnonymousFunctionDefinition());
156 }
157
IsConciseMethodDefinition() const158 bool Expression::IsConciseMethodDefinition() const {
159 return IsFunctionLiteral() && IsConciseMethod(AsFunctionLiteral()->kind());
160 }
161
IsAccessorFunctionDefinition() const162 bool Expression::IsAccessorFunctionDefinition() const {
163 return IsFunctionLiteral() && IsAccessorFunction(AsFunctionLiteral()->kind());
164 }
165
VariableProxy(Variable * var,int start_position)166 VariableProxy::VariableProxy(Variable* var, int start_position)
167 : Expression(start_position, kVariableProxy),
168 raw_name_(var->raw_name()),
169 next_unresolved_(nullptr) {
170 DCHECK(!var->is_this());
171 bit_field_ |= IsAssignedField::encode(false) |
172 IsResolvedField::encode(false) |
173 HoleCheckModeField::encode(HoleCheckMode::kElided);
174 BindTo(var);
175 }
176
VariableProxy(const VariableProxy * copy_from)177 VariableProxy::VariableProxy(const VariableProxy* copy_from)
178 : Expression(copy_from->position(), kVariableProxy),
179 next_unresolved_(nullptr) {
180 bit_field_ = copy_from->bit_field_;
181 DCHECK(!copy_from->is_resolved());
182 raw_name_ = copy_from->raw_name_;
183 }
184
BindTo(Variable * var)185 void VariableProxy::BindTo(Variable* var) {
186 DCHECK_EQ(raw_name(), var->raw_name());
187 set_var(var);
188 set_is_resolved();
189 var->set_is_used();
190 if (is_assigned()) var->SetMaybeAssigned();
191 }
192
Assignment(NodeType node_type,Token::Value op,Expression * target,Expression * value,int pos)193 Assignment::Assignment(NodeType node_type, Token::Value op, Expression* target,
194 Expression* value, int pos)
195 : Expression(pos, node_type), target_(target), value_(value) {
196 bit_field_ |= TokenField::encode(op);
197 }
198
set_inferred_name(Handle<String> inferred_name)199 void FunctionLiteral::set_inferred_name(Handle<String> inferred_name) {
200 DCHECK(!inferred_name.is_null());
201 inferred_name_ = inferred_name;
202 DCHECK(raw_inferred_name_ == nullptr || raw_inferred_name_->IsEmpty());
203 raw_inferred_name_ = nullptr;
204 scope()->set_has_inferred_function_name(true);
205 }
206
set_raw_inferred_name(AstConsString * raw_inferred_name)207 void FunctionLiteral::set_raw_inferred_name(AstConsString* raw_inferred_name) {
208 DCHECK_NOT_NULL(raw_inferred_name);
209 raw_inferred_name_ = raw_inferred_name;
210 DCHECK(inferred_name_.is_null());
211 inferred_name_ = Handle<String>();
212 scope()->set_has_inferred_function_name(true);
213 }
214
ShouldEagerCompile() const215 bool FunctionLiteral::ShouldEagerCompile() const {
216 return scope()->ShouldEagerCompile();
217 }
218
SetShouldEagerCompile()219 void FunctionLiteral::SetShouldEagerCompile() {
220 scope()->set_should_eager_compile();
221 }
222
AllowsLazyCompilation()223 bool FunctionLiteral::AllowsLazyCompilation() {
224 return scope()->AllowsLazyCompilation();
225 }
226
SafeToSkipArgumentsAdaptor() const227 bool FunctionLiteral::SafeToSkipArgumentsAdaptor() const {
228 return language_mode() == LanguageMode::kStrict &&
229 scope()->arguments() == nullptr &&
230 scope()->rest_parameter() == nullptr;
231 }
232
start_position() const233 int FunctionLiteral::start_position() const {
234 return scope()->start_position();
235 }
236
end_position() const237 int FunctionLiteral::end_position() const { return scope()->end_position(); }
238
language_mode() const239 LanguageMode FunctionLiteral::language_mode() const {
240 return scope()->language_mode();
241 }
242
kind() const243 FunctionKind FunctionLiteral::kind() const { return scope()->function_kind(); }
244
NeedsHomeObject(Expression * expr)245 bool FunctionLiteral::NeedsHomeObject(Expression* expr) {
246 if (expr == nullptr || !expr->IsFunctionLiteral()) return false;
247 DCHECK_NOT_NULL(expr->AsFunctionLiteral()->scope());
248 return expr->AsFunctionLiteral()->scope()->NeedsHomeObject();
249 }
250
GetDebugName() const251 std::unique_ptr<char[]> FunctionLiteral::GetDebugName() const {
252 const AstConsString* cons_string;
253 if (raw_name_ != nullptr && !raw_name_->IsEmpty()) {
254 cons_string = raw_name_;
255 } else if (raw_inferred_name_ != nullptr && !raw_inferred_name_->IsEmpty()) {
256 cons_string = raw_inferred_name_;
257 } else if (!inferred_name_.is_null()) {
258 AllowHandleDereference allow_deref;
259 return inferred_name_->ToCString();
260 } else {
261 char* empty_str = new char[1];
262 empty_str[0] = 0;
263 return std::unique_ptr<char[]>(empty_str);
264 }
265
266 // TODO(rmcilroy): Deal with two-character strings.
267 std::vector<char> result_vec;
268 std::forward_list<const AstRawString*> strings = cons_string->ToRawStrings();
269 for (const AstRawString* string : strings) {
270 if (!string->is_one_byte()) break;
271 for (int i = 0; i < string->length(); i++) {
272 result_vec.push_back(string->raw_data()[i]);
273 }
274 }
275 std::unique_ptr<char[]> result(new char[result_vec.size() + 1]);
276 memcpy(result.get(), result_vec.data(), result_vec.size());
277 result[result_vec.size()] = '\0';
278 return result;
279 }
280
private_name_lookup_skips_outer_class() const281 bool FunctionLiteral::private_name_lookup_skips_outer_class() const {
282 return scope()->private_name_lookup_skips_outer_class();
283 }
284
ObjectLiteralProperty(Expression * key,Expression * value,Kind kind,bool is_computed_name)285 ObjectLiteralProperty::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
ObjectLiteralProperty(AstValueFactory * ast_value_factory,Expression * key,Expression * value,bool is_computed_name)291 ObjectLiteralProperty::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
NeedsSetFunctionName() const307 bool LiteralProperty::NeedsSetFunctionName() const {
308 return is_computed_name() && (value_->IsAnonymousFunctionDefinition() ||
309 value_->IsConciseMethodDefinition() ||
310 value_->IsAccessorFunctionDefinition());
311 }
312
ClassLiteralProperty(Expression * key,Expression * value,Kind kind,bool is_static,bool is_computed_name,bool is_private)313 ClassLiteralProperty::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
IsCompileTimeValue() const323 bool ObjectLiteral::Property::IsCompileTimeValue() const {
324 return kind_ == CONSTANT ||
325 (kind_ == MATERIALIZED_LITERAL && value_->IsCompileTimeValue());
326 }
327
set_emit_store(bool emit_store)328 void ObjectLiteral::Property::set_emit_store(bool emit_store) {
329 emit_store_ = emit_store;
330 }
331
emit_store() const332 bool ObjectLiteral::Property::emit_store() const { return emit_store_; }
333
CalculateEmitStore(Zone * zone)334 void ObjectLiteral::CalculateEmitStore(Zone* zone) {
335 const auto GETTER = ObjectLiteral::Property::GETTER;
336 const auto SETTER = ObjectLiteral::Property::SETTER;
337
338 ZoneAllocationPolicy allocator(zone);
339
340 CustomMatcherZoneHashMap table(
341 Literal::Match, ZoneHashMap::kDefaultHashMapCapacity, allocator);
342 for (int i = properties()->length() - 1; i >= 0; i--) {
343 ObjectLiteral::Property* property = properties()->at(i);
344 if (property->is_computed_name()) continue;
345 if (property->IsPrototype()) continue;
346 Literal* literal = property->key()->AsLiteral();
347 DCHECK(!literal->IsNullLiteral());
348
349 uint32_t hash = literal->Hash();
350 ZoneHashMap::Entry* entry = table.LookupOrInsert(literal, hash, allocator);
351 if (entry->value == nullptr) {
352 entry->value = property;
353 } else {
354 // We already have a later definition of this property, so we don't need
355 // to emit a store for the current one.
356 //
357 // There are two subtleties here.
358 //
359 // (1) Emitting a store might actually be incorrect. For example, in {get
360 // foo() {}, foo: 42}, the getter store would override the data property
361 // (which, being a non-computed compile-time valued property, is already
362 // part of the initial literal object.
363 //
364 // (2) If the later definition is an accessor (say, a getter), and the
365 // current definition is a complementary accessor (here, a setter), then
366 // we still must emit a store for the current definition.
367
368 auto later_kind =
369 static_cast<ObjectLiteral::Property*>(entry->value)->kind();
370 bool complementary_accessors =
371 (property->kind() == GETTER && later_kind == SETTER) ||
372 (property->kind() == SETTER && later_kind == GETTER);
373 if (!complementary_accessors) {
374 property->set_emit_store(false);
375 if (later_kind == GETTER || later_kind == SETTER) {
376 entry->value = property;
377 }
378 }
379 }
380 }
381 }
382
InitFlagsForPendingNullPrototype(int i)383 void ObjectLiteral::InitFlagsForPendingNullPrototype(int i) {
384 // We still check for __proto__:null after computed property names.
385 for (; i < properties()->length(); i++) {
386 if (properties()->at(i)->IsNullPrototype()) {
387 set_has_null_protoype(true);
388 break;
389 }
390 }
391 }
392
InitDepthAndFlags()393 int ObjectLiteral::InitDepthAndFlags() {
394 if (is_initialized()) return depth();
395 bool is_simple = true;
396 bool has_seen_prototype = false;
397 bool needs_initial_allocation_site = false;
398 int depth_acc = 1;
399 uint32_t nof_properties = 0;
400 uint32_t elements = 0;
401 uint32_t max_element_index = 0;
402 for (int i = 0; i < properties()->length(); i++) {
403 ObjectLiteral::Property* property = properties()->at(i);
404 if (property->IsPrototype()) {
405 has_seen_prototype = true;
406 // __proto__:null has no side-effects and is set directly on the
407 // boilerplate.
408 if (property->IsNullPrototype()) {
409 set_has_null_protoype(true);
410 continue;
411 }
412 DCHECK(!has_null_prototype());
413 is_simple = false;
414 continue;
415 }
416 if (nof_properties == boilerplate_properties_) {
417 DCHECK(property->is_computed_name());
418 is_simple = false;
419 if (!has_seen_prototype) InitFlagsForPendingNullPrototype(i);
420 break;
421 }
422 DCHECK(!property->is_computed_name());
423
424 MaterializedLiteral* literal = property->value()->AsMaterializedLiteral();
425 if (literal != nullptr) {
426 int subliteral_depth = literal->InitDepthAndFlags() + 1;
427 if (subliteral_depth > depth_acc) depth_acc = subliteral_depth;
428 needs_initial_allocation_site |= literal->NeedsInitialAllocationSite();
429 }
430
431 Literal* key = property->key()->AsLiteral();
432 Expression* value = property->value();
433
434 bool is_compile_time_value = value->IsCompileTimeValue();
435 is_simple = is_simple && is_compile_time_value;
436
437 // Keep track of the number of elements in the object literal and
438 // the largest element index. If the largest element index is
439 // much larger than the number of elements, creating an object
440 // literal with fast elements will be a waste of space.
441 uint32_t element_index = 0;
442 if (key->AsArrayIndex(&element_index)) {
443 max_element_index = Max(element_index, max_element_index);
444 elements++;
445 } else {
446 DCHECK(key->IsPropertyName());
447 }
448
449 nof_properties++;
450 }
451
452 set_depth(depth_acc);
453 set_is_simple(is_simple);
454 set_needs_initial_allocation_site(needs_initial_allocation_site);
455 set_has_elements(elements > 0);
456 set_fast_elements((max_element_index <= 32) ||
457 ((2 * elements) >= max_element_index));
458 return depth_acc;
459 }
460
461 template <typename LocalIsolate>
BuildBoilerplateDescription(LocalIsolate * isolate)462 void ObjectLiteral::BuildBoilerplateDescription(LocalIsolate* 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()
508 ->template NewNumberFromUint<AllocationType::kOld>(
509 element_index)
510 : Handle<Object>::cast(key_literal->AsRawPropertyName()->string());
511
512 Handle<Object> value = GetBoilerplateValue(property->value(), isolate);
513
514 // Add name, value pair to the fixed array.
515 boilerplate_description->set_key_value(position++, *key, *value);
516 }
517
518 boilerplate_description->set_flags(EncodeLiteralType());
519
520 boilerplate_description_ = boilerplate_description;
521 }
522 template EXPORT_TEMPLATE_DEFINE(V8_BASE_EXPORT) void ObjectLiteral::
523 BuildBoilerplateDescription(Isolate* isolate);
524 template EXPORT_TEMPLATE_DEFINE(V8_BASE_EXPORT) void ObjectLiteral::
525 BuildBoilerplateDescription(OffThreadIsolate* isolate);
526
IsFastCloningSupported() const527 bool ObjectLiteral::IsFastCloningSupported() const {
528 // The CreateShallowObjectLiteratal builtin doesn't copy elements, and object
529 // literals don't support copy-on-write (COW) elements for now.
530 // TODO(mvstanton): make object literals support COW elements.
531 return fast_elements() && is_shallow() &&
532 properties_count() <=
533 ConstructorBuiltins::kMaximumClonedShallowObjectProperties;
534 }
535
InitDepthAndFlags()536 int ArrayLiteral::InitDepthAndFlags() {
537 if (is_initialized()) return depth();
538
539 int constants_length =
540 first_spread_index_ >= 0 ? first_spread_index_ : values()->length();
541
542 // Fill in the literals.
543 bool is_simple = first_spread_index_ < 0;
544 bool is_holey = false;
545 ElementsKind kind = FIRST_FAST_ELEMENTS_KIND;
546 int depth_acc = 1;
547 int array_index = 0;
548 for (; array_index < constants_length; array_index++) {
549 Expression* element = values()->at(array_index);
550 MaterializedLiteral* literal = element->AsMaterializedLiteral();
551 if (literal != nullptr) {
552 int subliteral_depth = literal->InitDepthAndFlags() + 1;
553 if (subliteral_depth > depth_acc) depth_acc = subliteral_depth;
554 }
555
556 if (!element->IsCompileTimeValue()) {
557 is_simple = false;
558
559 // Don't change kind here: non-compile time values resolve to an unknown
560 // elements kind, so we allow them to be considered as any one of them.
561
562 // TODO(leszeks): It would be nice to DCHECK here that GetBoilerplateValue
563 // will return IsUninitialized, but that would require being on the main
564 // thread which we may not be.
565 } else {
566 Literal* literal = element->AsLiteral();
567
568 if (!literal) {
569 // Only arrays and objects are compile-time values but not (primitive)
570 // literals.
571 DCHECK(element->IsObjectLiteral() || element->IsArrayLiteral());
572 kind = PACKED_ELEMENTS;
573 } else {
574 switch (literal->type()) {
575 case Literal::kTheHole:
576 is_holey = true;
577 // The hole is allowed in holey double arrays (and holey Smi
578 // arrays), so ignore it as far as is_all_number is concerned.
579 break;
580 case Literal::kHeapNumber:
581 if (kind == PACKED_SMI_ELEMENTS) kind = PACKED_DOUBLE_ELEMENTS;
582 DCHECK_EQ(kind,
583 GetMoreGeneralElementsKind(kind, PACKED_DOUBLE_ELEMENTS));
584 break;
585 case Literal::kSmi:
586 DCHECK_EQ(kind,
587 GetMoreGeneralElementsKind(kind, PACKED_SMI_ELEMENTS));
588 break;
589 case Literal::kBigInt:
590 case Literal::kString:
591 case Literal::kSymbol:
592 case Literal::kBoolean:
593 case Literal::kUndefined:
594 case Literal::kNull:
595 kind = PACKED_ELEMENTS;
596 break;
597 }
598 }
599 }
600 }
601
602 if (is_holey) {
603 kind = GetHoleyElementsKind(kind);
604 }
605
606 set_depth(depth_acc);
607 set_is_simple(is_simple);
608 set_boilerplate_descriptor_kind(kind);
609
610 // Array literals always need an initial allocation site to properly track
611 // elements transitions.
612 set_needs_initial_allocation_site(true);
613 return depth_acc;
614 }
615
616 template <typename LocalIsolate>
BuildBoilerplateDescription(LocalIsolate * isolate)617 void ArrayLiteral::BuildBoilerplateDescription(LocalIsolate* isolate) {
618 if (!boilerplate_description_.is_null()) return;
619
620 int constants_length =
621 first_spread_index_ >= 0 ? first_spread_index_ : values()->length();
622 ElementsKind kind = boilerplate_descriptor_kind();
623 bool use_doubles = IsDoubleElementsKind(kind);
624
625 Handle<FixedArrayBase> elements;
626 if (use_doubles) {
627 elements = isolate->factory()->NewFixedDoubleArray(constants_length,
628 AllocationType::kOld);
629 } else {
630 elements = isolate->factory()->NewFixedArrayWithHoles(constants_length,
631 AllocationType::kOld);
632 }
633
634 // Fill in the literals.
635 int array_index = 0;
636 for (; array_index < constants_length; array_index++) {
637 Expression* element = values()->at(array_index);
638 DCHECK(!element->IsSpread());
639 if (use_doubles) {
640 Literal* literal = element->AsLiteral();
641
642 if (literal && literal->type() == Literal::kTheHole) {
643 DCHECK(IsHoleyElementsKind(kind));
644 DCHECK(GetBoilerplateValue(element, isolate)->IsTheHole(isolate));
645 FixedDoubleArray::cast(*elements).set_the_hole(array_index);
646 continue;
647 } else if (literal && literal->IsNumber()) {
648 FixedDoubleArray::cast(*elements).set(array_index, literal->AsNumber());
649 } else {
650 DCHECK(GetBoilerplateValue(element, isolate)->IsUninitialized(isolate));
651 FixedDoubleArray::cast(*elements).set(array_index, 0);
652 }
653
654 } else {
655 MaterializedLiteral* m_literal = element->AsMaterializedLiteral();
656 if (m_literal != nullptr) {
657 m_literal->BuildConstants(isolate);
658 }
659
660 // New handle scope here, needs to be after BuildContants().
661 typename LocalIsolate::HandleScopeType scope(isolate);
662
663 Object boilerplate_value = *GetBoilerplateValue(element, isolate);
664 // We shouldn't allocate after creating the boilerplate value.
665 DisallowHeapAllocation no_gc;
666
667 if (boilerplate_value.IsTheHole(isolate)) {
668 DCHECK(IsHoleyElementsKind(kind));
669 continue;
670 }
671
672 if (boilerplate_value.IsUninitialized(isolate)) {
673 boilerplate_value = Smi::zero();
674 }
675
676 DCHECK_EQ(
677 boilerplate_descriptor_kind(),
678 GetMoreGeneralElementsKind(boilerplate_descriptor_kind(),
679 boilerplate_value.OptimalElementsKind(
680 GetIsolateForPtrCompr(*elements))));
681
682 FixedArray::cast(*elements).set(array_index, boilerplate_value);
683 }
684 } // namespace internal
685
686 // Simple and shallow arrays can be lazily copied, we transform the
687 // elements array to a copy-on-write array.
688 if (is_simple() && depth() == 1 && array_index > 0 &&
689 IsSmiOrObjectElementsKind(kind)) {
690 elements->set_map(ReadOnlyRoots(isolate).fixed_cow_array_map());
691 }
692
693 boilerplate_description_ =
694 isolate->factory()->NewArrayBoilerplateDescription(kind, elements);
695 }
696 template EXPORT_TEMPLATE_DEFINE(
697 V8_BASE_EXPORT) void ArrayLiteral::BuildBoilerplateDescription(Isolate*
698 isolate);
699 template EXPORT_TEMPLATE_DEFINE(V8_BASE_EXPORT) void ArrayLiteral::
700 BuildBoilerplateDescription(OffThreadIsolate* isolate);
701
IsFastCloningSupported() const702 bool ArrayLiteral::IsFastCloningSupported() const {
703 return depth() <= 1 &&
704 values_.length() <=
705 ConstructorBuiltins::kMaximumClonedShallowArrayElements;
706 }
707
IsSimple() const708 bool MaterializedLiteral::IsSimple() const {
709 if (IsArrayLiteral()) return AsArrayLiteral()->is_simple();
710 if (IsObjectLiteral()) return AsObjectLiteral()->is_simple();
711 DCHECK(IsRegExpLiteral());
712 return false;
713 }
714
715 template <typename LocalIsolate>
GetBoilerplateValue(Expression * expression,LocalIsolate * isolate)716 Handle<Object> MaterializedLiteral::GetBoilerplateValue(Expression* expression,
717 LocalIsolate* isolate) {
718 if (expression->IsLiteral()) {
719 return expression->AsLiteral()->BuildValue(isolate);
720 }
721 if (expression->IsCompileTimeValue()) {
722 if (expression->IsObjectLiteral()) {
723 ObjectLiteral* object_literal = expression->AsObjectLiteral();
724 DCHECK(object_literal->is_simple());
725 return object_literal->boilerplate_description();
726 } else {
727 DCHECK(expression->IsArrayLiteral());
728 ArrayLiteral* array_literal = expression->AsArrayLiteral();
729 DCHECK(array_literal->is_simple());
730 return array_literal->boilerplate_description();
731 }
732 }
733 return isolate->factory()->uninitialized_value();
734 }
735 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
736 Handle<Object> MaterializedLiteral::GetBoilerplateValue(
737 Expression* expression, Isolate* isolate);
738 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
739 Handle<Object> MaterializedLiteral::GetBoilerplateValue(
740 Expression* expression, OffThreadIsolate* isolate);
741
InitDepthAndFlags()742 int MaterializedLiteral::InitDepthAndFlags() {
743 if (IsArrayLiteral()) return AsArrayLiteral()->InitDepthAndFlags();
744 if (IsObjectLiteral()) return AsObjectLiteral()->InitDepthAndFlags();
745 DCHECK(IsRegExpLiteral());
746 return 1;
747 }
748
NeedsInitialAllocationSite()749 bool MaterializedLiteral::NeedsInitialAllocationSite() {
750 if (IsArrayLiteral()) {
751 return AsArrayLiteral()->needs_initial_allocation_site();
752 }
753 if (IsObjectLiteral()) {
754 return AsObjectLiteral()->needs_initial_allocation_site();
755 }
756 DCHECK(IsRegExpLiteral());
757 return false;
758 }
759
760 template <typename LocalIsolate>
BuildConstants(LocalIsolate * isolate)761 void MaterializedLiteral::BuildConstants(LocalIsolate* isolate) {
762 if (IsArrayLiteral()) {
763 AsArrayLiteral()->BuildBoilerplateDescription(isolate);
764 return;
765 }
766 if (IsObjectLiteral()) {
767 AsObjectLiteral()->BuildBoilerplateDescription(isolate);
768 return;
769 }
770 DCHECK(IsRegExpLiteral());
771 }
772 template EXPORT_TEMPLATE_DEFINE(
773 V8_BASE_EXPORT) void MaterializedLiteral::BuildConstants(Isolate* isolate);
774 template EXPORT_TEMPLATE_DEFINE(
775 V8_BASE_EXPORT) void MaterializedLiteral::BuildConstants(OffThreadIsolate*
776 isolate);
777
778 template <typename LocalIsolate>
GetOrBuildDescription(LocalIsolate * isolate)779 Handle<TemplateObjectDescription> GetTemplateObject::GetOrBuildDescription(
780 LocalIsolate* isolate) {
781 Handle<FixedArray> raw_strings = isolate->factory()->NewFixedArray(
782 this->raw_strings()->length(), AllocationType::kOld);
783 bool raw_and_cooked_match = true;
784 for (int i = 0; i < raw_strings->length(); ++i) {
785 if (this->raw_strings()->at(i) != this->cooked_strings()->at(i)) {
786 // If the AstRawStrings don't match, then neither should the allocated
787 // Strings, since the AstValueFactory should have deduplicated them
788 // already.
789 DCHECK_IMPLIES(this->cooked_strings()->at(i) != nullptr,
790 *this->cooked_strings()->at(i)->string() !=
791 *this->raw_strings()->at(i)->string());
792
793 raw_and_cooked_match = false;
794 }
795 raw_strings->set(i, *this->raw_strings()->at(i)->string());
796 }
797 Handle<FixedArray> cooked_strings = raw_strings;
798 if (!raw_and_cooked_match) {
799 cooked_strings = isolate->factory()->NewFixedArray(
800 this->cooked_strings()->length(), AllocationType::kOld);
801 for (int i = 0; i < cooked_strings->length(); ++i) {
802 if (this->cooked_strings()->at(i) != nullptr) {
803 cooked_strings->set(i, *this->cooked_strings()->at(i)->string());
804 } else {
805 cooked_strings->set(i, ReadOnlyRoots(isolate).undefined_value());
806 }
807 }
808 }
809 return isolate->factory()->NewTemplateObjectDescription(raw_strings,
810 cooked_strings);
811 }
812 template EXPORT_TEMPLATE_DEFINE(V8_BASE_EXPORT)
813 Handle<TemplateObjectDescription> GetTemplateObject::GetOrBuildDescription(
814 Isolate* isolate);
815 template EXPORT_TEMPLATE_DEFINE(V8_BASE_EXPORT)
816 Handle<TemplateObjectDescription> GetTemplateObject::GetOrBuildDescription(
817 OffThreadIsolate* isolate);
818
IsCommutativeOperationWithSmiLiteral(Token::Value op)819 static bool IsCommutativeOperationWithSmiLiteral(Token::Value op) {
820 // Add is not commutative due to potential for string addition.
821 return op == Token::MUL || op == Token::BIT_AND || op == Token::BIT_OR ||
822 op == Token::BIT_XOR;
823 }
824
825 // Check for the pattern: x + 1.
MatchSmiLiteralOperation(Expression * left,Expression * right,Expression ** expr,Smi * literal)826 static bool MatchSmiLiteralOperation(Expression* left, Expression* right,
827 Expression** expr, Smi* literal) {
828 if (right->IsSmiLiteral()) {
829 *expr = left;
830 *literal = right->AsLiteral()->AsSmiLiteral();
831 return true;
832 }
833 return false;
834 }
835
IsSmiLiteralOperation(Expression ** subexpr,Smi * literal)836 bool BinaryOperation::IsSmiLiteralOperation(Expression** subexpr,
837 Smi* literal) {
838 return MatchSmiLiteralOperation(left_, right_, subexpr, literal) ||
839 (IsCommutativeOperationWithSmiLiteral(op()) &&
840 MatchSmiLiteralOperation(right_, left_, subexpr, literal));
841 }
842
IsTypeof(Expression * expr)843 static bool IsTypeof(Expression* expr) {
844 UnaryOperation* maybe_unary = expr->AsUnaryOperation();
845 return maybe_unary != nullptr && maybe_unary->op() == Token::TYPEOF;
846 }
847
848 // Check for the pattern: typeof <expression> equals <string literal>.
MatchLiteralCompareTypeof(Expression * left,Token::Value op,Expression * right,Expression ** expr,Literal ** literal)849 static bool MatchLiteralCompareTypeof(Expression* left, Token::Value op,
850 Expression* right, Expression** expr,
851 Literal** literal) {
852 if (IsTypeof(left) && right->IsStringLiteral() && Token::IsEqualityOp(op)) {
853 *expr = left->AsUnaryOperation()->expression();
854 *literal = right->AsLiteral();
855 return true;
856 }
857 return false;
858 }
859
IsLiteralCompareTypeof(Expression ** expr,Literal ** literal)860 bool CompareOperation::IsLiteralCompareTypeof(Expression** expr,
861 Literal** literal) {
862 return MatchLiteralCompareTypeof(left_, op(), right_, expr, literal) ||
863 MatchLiteralCompareTypeof(right_, op(), left_, expr, literal);
864 }
865
IsVoidOfLiteral(Expression * expr)866 static bool IsVoidOfLiteral(Expression* expr) {
867 UnaryOperation* maybe_unary = expr->AsUnaryOperation();
868 return maybe_unary != nullptr && maybe_unary->op() == Token::VOID &&
869 maybe_unary->expression()->IsLiteral();
870 }
871
872 // Check for the pattern: void <literal> equals <expression> or
873 // undefined equals <expression>
MatchLiteralCompareUndefined(Expression * left,Token::Value op,Expression * right,Expression ** expr)874 static bool MatchLiteralCompareUndefined(Expression* left, Token::Value op,
875 Expression* right, Expression** expr) {
876 if (IsVoidOfLiteral(left) && Token::IsEqualityOp(op)) {
877 *expr = right;
878 return true;
879 }
880 if (left->IsUndefinedLiteral() && Token::IsEqualityOp(op)) {
881 *expr = right;
882 return true;
883 }
884 return false;
885 }
886
IsLiteralCompareUndefined(Expression ** expr)887 bool CompareOperation::IsLiteralCompareUndefined(Expression** expr) {
888 return MatchLiteralCompareUndefined(left_, op(), right_, expr) ||
889 MatchLiteralCompareUndefined(right_, op(), left_, expr);
890 }
891
892 // Check for the pattern: null equals <expression>
MatchLiteralCompareNull(Expression * left,Token::Value op,Expression * right,Expression ** expr)893 static bool MatchLiteralCompareNull(Expression* left, Token::Value op,
894 Expression* right, Expression** expr) {
895 if (left->IsNullLiteral() && Token::IsEqualityOp(op)) {
896 *expr = right;
897 return true;
898 }
899 return false;
900 }
901
IsLiteralCompareNull(Expression ** expr)902 bool CompareOperation::IsLiteralCompareNull(Expression** expr) {
903 return MatchLiteralCompareNull(left_, op(), right_, expr) ||
904 MatchLiteralCompareNull(right_, op(), left_, expr);
905 }
906
GetCallType() const907 Call::CallType Call::GetCallType() const {
908 VariableProxy* proxy = expression()->AsVariableProxy();
909 if (proxy != nullptr) {
910 if (proxy->var()->IsUnallocated()) {
911 return GLOBAL_CALL;
912 } else if (proxy->var()->IsLookupSlot()) {
913 // Calls going through 'with' always use VariableMode::kDynamic rather
914 // than VariableMode::kDynamicLocal or VariableMode::kDynamicGlobal.
915 return proxy->var()->mode() == VariableMode::kDynamic ? WITH_CALL
916 : OTHER_CALL;
917 }
918 }
919
920 if (expression()->IsSuperCallReference()) return SUPER_CALL;
921
922 Property* property = expression()->AsProperty();
923 bool is_optional_chain = false;
924 if (V8_UNLIKELY(property == nullptr && expression()->IsOptionalChain())) {
925 is_optional_chain = true;
926 property = expression()->AsOptionalChain()->expression()->AsProperty();
927 }
928 if (property != nullptr) {
929 if (property->IsPrivateReference()) {
930 return PRIVATE_CALL;
931 }
932 bool is_super = property->IsSuperAccess();
933 // `super?.` is not syntactically valid, so a property load cannot be both
934 // super and an optional chain.
935 DCHECK(!is_super || !is_optional_chain);
936 if (property->key()->IsPropertyName()) {
937 if (is_super) return NAMED_SUPER_PROPERTY_CALL;
938 if (is_optional_chain) return NAMED_OPTIONAL_CHAIN_PROPERTY_CALL;
939 return NAMED_PROPERTY_CALL;
940 } else {
941 if (is_super) return KEYED_SUPER_PROPERTY_CALL;
942 if (is_optional_chain) return KEYED_OPTIONAL_CHAIN_PROPERTY_CALL;
943 return KEYED_PROPERTY_CALL;
944 }
945 }
946
947 return OTHER_CALL;
948 }
949
CaseClause(Zone * zone,Expression * label,const ScopedPtrList<Statement> & statements)950 CaseClause::CaseClause(Zone* zone, Expression* label,
951 const ScopedPtrList<Statement>& statements)
952 : label_(label), statements_(0, nullptr) {
953 statements.CopyTo(&statements_, zone);
954 }
955
IsPropertyName() const956 bool Literal::IsPropertyName() const {
957 if (type() != kString) return false;
958 uint32_t index;
959 return !string_->AsArrayIndex(&index);
960 }
961
ToUint32(uint32_t * value) const962 bool Literal::ToUint32(uint32_t* value) const {
963 switch (type()) {
964 case kString:
965 return string_->AsArrayIndex(value);
966 case kSmi:
967 if (smi_ < 0) return false;
968 *value = static_cast<uint32_t>(smi_);
969 return true;
970 case kHeapNumber:
971 return DoubleToUint32IfEqualToSelf(AsNumber(), value);
972 default:
973 return false;
974 }
975 }
976
AsArrayIndex(uint32_t * value) const977 bool Literal::AsArrayIndex(uint32_t* value) const {
978 return ToUint32(value) && *value != kMaxUInt32;
979 }
980
981 template <typename LocalIsolate>
BuildValue(LocalIsolate * isolate) const982 Handle<Object> Literal::BuildValue(LocalIsolate* isolate) const {
983 switch (type()) {
984 case kSmi:
985 return handle(Smi::FromInt(smi_), isolate);
986 case kHeapNumber:
987 return isolate->factory()->template NewNumber<AllocationType::kOld>(
988 number_);
989 case kString:
990 return string_->string();
991 case kSymbol:
992 return isolate->factory()->home_object_symbol();
993 case kBoolean:
994 return isolate->factory()->ToBoolean(boolean_);
995 case kNull:
996 return isolate->factory()->null_value();
997 case kUndefined:
998 return isolate->factory()->undefined_value();
999 case kTheHole:
1000 return isolate->factory()->the_hole_value();
1001 case kBigInt:
1002 // This should never fail: the parser will never create a BigInt
1003 // literal that cannot be allocated.
1004 return BigIntLiteral(isolate, bigint_.c_str()).ToHandleChecked();
1005 }
1006 UNREACHABLE();
1007 }
1008 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
1009 Handle<Object> Literal::BuildValue(Isolate* isolate) const;
1010 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
1011 Handle<Object> Literal::BuildValue(OffThreadIsolate* isolate) const;
1012
ToBooleanIsTrue() const1013 bool Literal::ToBooleanIsTrue() const {
1014 switch (type()) {
1015 case kSmi:
1016 return smi_ != 0;
1017 case kHeapNumber:
1018 return DoubleToBoolean(number_);
1019 case kString:
1020 return !string_->IsEmpty();
1021 case kNull:
1022 case kUndefined:
1023 return false;
1024 case kBoolean:
1025 return boolean_;
1026 case kBigInt: {
1027 const char* bigint_str = bigint_.c_str();
1028 size_t length = strlen(bigint_str);
1029 DCHECK_GT(length, 0);
1030 if (length == 1 && bigint_str[0] == '0') return false;
1031 // Skip over any radix prefix; BigInts with length > 1 only
1032 // begin with zero if they include a radix.
1033 for (size_t i = (bigint_str[0] == '0') ? 2 : 0; i < length; ++i) {
1034 if (bigint_str[i] != '0') return true;
1035 }
1036 return false;
1037 }
1038 case kSymbol:
1039 return true;
1040 case kTheHole:
1041 UNREACHABLE();
1042 }
1043 UNREACHABLE();
1044 }
1045
Hash()1046 uint32_t Literal::Hash() {
1047 return IsString() ? AsRawString()->Hash()
1048 : ComputeLongHash(double_to_uint64(AsNumber()));
1049 }
1050
1051 // static
Match(void * a,void * b)1052 bool Literal::Match(void* a, void* b) {
1053 Literal* x = static_cast<Literal*>(a);
1054 Literal* y = static_cast<Literal*>(b);
1055 return (x->IsString() && y->IsString() &&
1056 x->AsRawString() == y->AsRawString()) ||
1057 (x->IsNumber() && y->IsNumber() && x->AsNumber() == y->AsNumber());
1058 }
1059
NewNumberLiteral(double number,int pos)1060 Literal* AstNodeFactory::NewNumberLiteral(double number, int pos) {
1061 int int_value;
1062 if (DoubleToSmiInteger(number, &int_value)) {
1063 return NewSmiLiteral(int_value, pos);
1064 }
1065 return new (zone_) Literal(number, pos);
1066 }
1067
debug_name()1068 const char* CallRuntime::debug_name() {
1069 #ifdef DEBUG
1070 return is_jsruntime() ? NameForNativeContextIntrinsicIndex(context_index_)
1071 : function_->name;
1072 #else
1073 return is_jsruntime() ? "(context function)" : function_->name;
1074 #endif // DEBUG
1075 }
1076
1077 } // namespace internal
1078 } // namespace v8
1079