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/base/numbers/double.h"
15 #include "src/base/platform/wrappers.h"
16 #include "src/builtins/builtins-constructor.h"
17 #include "src/builtins/builtins.h"
18 #include "src/common/assert-scope.h"
19 #include "src/heap/local-factory-inl.h"
20 #include "src/numbers/conversions-inl.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 AstPrinter::PrintOut(isolate, this);
60 }
61
62 #endif // DEBUG
63
64 #define RETURN_NODE(Node) \
65 case k##Node: \
66 return static_cast<Node*>(this);
67
AsIterationStatement()68 IterationStatement* AstNode::AsIterationStatement() {
69 switch (node_type()) {
70 ITERATION_NODE_LIST(RETURN_NODE);
71 default:
72 return nullptr;
73 }
74 }
75
AsMaterializedLiteral()76 MaterializedLiteral* AstNode::AsMaterializedLiteral() {
77 switch (node_type()) {
78 LITERAL_NODE_LIST(RETURN_NODE);
79 default:
80 return nullptr;
81 }
82 }
83
84 #undef RETURN_NODE
85
IsSmiLiteral() const86 bool Expression::IsSmiLiteral() const {
87 return IsLiteral() && AsLiteral()->type() == Literal::kSmi;
88 }
89
IsNumberLiteral() const90 bool Expression::IsNumberLiteral() const {
91 return IsLiteral() && AsLiteral()->IsNumber();
92 }
93
IsStringLiteral() const94 bool Expression::IsStringLiteral() const {
95 return IsLiteral() && AsLiteral()->type() == Literal::kString;
96 }
97
IsPropertyName() const98 bool Expression::IsPropertyName() const {
99 return IsLiteral() && AsLiteral()->IsPropertyName();
100 }
101
IsNullLiteral() const102 bool Expression::IsNullLiteral() const {
103 return IsLiteral() && AsLiteral()->type() == Literal::kNull;
104 }
105
IsTheHoleLiteral() const106 bool Expression::IsTheHoleLiteral() const {
107 return IsLiteral() && AsLiteral()->type() == Literal::kTheHole;
108 }
109
IsCompileTimeValue()110 bool Expression::IsCompileTimeValue() {
111 if (IsLiteral()) return true;
112 MaterializedLiteral* literal = AsMaterializedLiteral();
113 if (literal == nullptr) return false;
114 return literal->IsSimple();
115 }
116
IsUndefinedLiteral() const117 bool Expression::IsUndefinedLiteral() const {
118 if (IsLiteral() && AsLiteral()->type() == Literal::kUndefined) return true;
119
120 const VariableProxy* var_proxy = AsVariableProxy();
121 if (var_proxy == nullptr) return false;
122 Variable* var = var_proxy->var();
123 // The global identifier "undefined" is immutable. Everything
124 // else could be reassigned.
125 return var != nullptr && var->IsUnallocated() &&
126 var_proxy->raw_name()->IsOneByteEqualTo("undefined");
127 }
128
IsLiteralButNotNullOrUndefined() const129 bool Expression::IsLiteralButNotNullOrUndefined() const {
130 return IsLiteral() && !IsNullOrUndefinedLiteral();
131 }
132
ToBooleanIsTrue() const133 bool Expression::ToBooleanIsTrue() const {
134 return IsLiteral() && AsLiteral()->ToBooleanIsTrue();
135 }
136
ToBooleanIsFalse() const137 bool Expression::ToBooleanIsFalse() const {
138 return IsLiteral() && AsLiteral()->ToBooleanIsFalse();
139 }
140
IsPrivateName() const141 bool Expression::IsPrivateName() const {
142 return IsVariableProxy() && AsVariableProxy()->IsPrivateName();
143 }
144
IsValidReferenceExpression() const145 bool Expression::IsValidReferenceExpression() const {
146 return IsProperty() ||
147 (IsVariableProxy() && AsVariableProxy()->IsValidReferenceExpression());
148 }
149
IsAnonymousFunctionDefinition() const150 bool Expression::IsAnonymousFunctionDefinition() const {
151 return (IsFunctionLiteral() &&
152 AsFunctionLiteral()->IsAnonymousFunctionDefinition()) ||
153 (IsClassLiteral() &&
154 AsClassLiteral()->IsAnonymousFunctionDefinition());
155 }
156
IsConciseMethodDefinition() const157 bool Expression::IsConciseMethodDefinition() const {
158 return IsFunctionLiteral() && IsConciseMethod(AsFunctionLiteral()->kind());
159 }
160
IsAccessorFunctionDefinition() const161 bool Expression::IsAccessorFunctionDefinition() const {
162 return IsFunctionLiteral() && IsAccessorFunction(AsFunctionLiteral()->kind());
163 }
164
VariableProxy(Variable * var,int start_position)165 VariableProxy::VariableProxy(Variable* var, int start_position)
166 : Expression(start_position, kVariableProxy),
167 raw_name_(var->raw_name()),
168 next_unresolved_(nullptr) {
169 DCHECK(!var->is_this());
170 bit_field_ |= IsAssignedField::encode(false) |
171 IsResolvedField::encode(false) |
172 HoleCheckModeField::encode(HoleCheckMode::kElided);
173 BindTo(var);
174 }
175
VariableProxy(const VariableProxy * copy_from)176 VariableProxy::VariableProxy(const VariableProxy* copy_from)
177 : Expression(copy_from->position(), kVariableProxy),
178 next_unresolved_(nullptr) {
179 bit_field_ = copy_from->bit_field_;
180 DCHECK(!copy_from->is_resolved());
181 raw_name_ = copy_from->raw_name_;
182 }
183
BindTo(Variable * var)184 void VariableProxy::BindTo(Variable* var) {
185 DCHECK_EQ(raw_name(), var->raw_name());
186 set_var(var);
187 set_is_resolved();
188 var->set_is_used();
189 if (is_assigned()) var->SetMaybeAssigned();
190 }
191
Assignment(NodeType node_type,Token::Value op,Expression * target,Expression * value,int pos)192 Assignment::Assignment(NodeType node_type, Token::Value op, Expression* target,
193 Expression* value, int pos)
194 : Expression(pos, node_type), target_(target), value_(value) {
195 bit_field_ |= TokenField::encode(op);
196 }
197
set_inferred_name(Handle<String> inferred_name)198 void FunctionLiteral::set_inferred_name(Handle<String> inferred_name) {
199 DCHECK(!inferred_name.is_null());
200 inferred_name_ = inferred_name;
201 DCHECK(raw_inferred_name_ == nullptr || raw_inferred_name_->IsEmpty());
202 raw_inferred_name_ = nullptr;
203 scope()->set_has_inferred_function_name(true);
204 }
205
set_raw_inferred_name(AstConsString * raw_inferred_name)206 void FunctionLiteral::set_raw_inferred_name(AstConsString* raw_inferred_name) {
207 DCHECK_NOT_NULL(raw_inferred_name);
208 raw_inferred_name_ = raw_inferred_name;
209 DCHECK(inferred_name_.is_null());
210 inferred_name_ = Handle<String>();
211 scope()->set_has_inferred_function_name(true);
212 }
213
ShouldEagerCompile() const214 bool FunctionLiteral::ShouldEagerCompile() const {
215 return scope()->ShouldEagerCompile();
216 }
217
SetShouldEagerCompile()218 void FunctionLiteral::SetShouldEagerCompile() {
219 scope()->set_should_eager_compile();
220 }
221
AllowsLazyCompilation()222 bool FunctionLiteral::AllowsLazyCompilation() {
223 return scope()->AllowsLazyCompilation();
224 }
225
start_position() const226 int FunctionLiteral::start_position() const {
227 return scope()->start_position();
228 }
229
end_position() const230 int FunctionLiteral::end_position() const { return scope()->end_position(); }
231
language_mode() const232 LanguageMode FunctionLiteral::language_mode() const {
233 return scope()->language_mode();
234 }
235
kind() const236 FunctionKind FunctionLiteral::kind() const { return scope()->function_kind(); }
237
GetDebugName() const238 std::unique_ptr<char[]> FunctionLiteral::GetDebugName() const {
239 const AstConsString* cons_string;
240 if (raw_name_ != nullptr && !raw_name_->IsEmpty()) {
241 cons_string = raw_name_;
242 } else if (raw_inferred_name_ != nullptr && !raw_inferred_name_->IsEmpty()) {
243 cons_string = raw_inferred_name_;
244 } else if (!inferred_name_.is_null()) {
245 return inferred_name_->ToCString();
246 } else {
247 char* empty_str = new char[1];
248 empty_str[0] = 0;
249 return std::unique_ptr<char[]>(empty_str);
250 }
251
252 // TODO(rmcilroy): Deal with two-character strings.
253 std::vector<char> result_vec;
254 std::forward_list<const AstRawString*> strings = cons_string->ToRawStrings();
255 for (const AstRawString* string : strings) {
256 if (!string->is_one_byte()) break;
257 for (int i = 0; i < string->length(); i++) {
258 result_vec.push_back(string->raw_data()[i]);
259 }
260 }
261 std::unique_ptr<char[]> result(new char[result_vec.size() + 1]);
262 memcpy(result.get(), result_vec.data(), result_vec.size());
263 result[result_vec.size()] = '\0';
264 return result;
265 }
266
private_name_lookup_skips_outer_class() const267 bool FunctionLiteral::private_name_lookup_skips_outer_class() const {
268 return scope()->private_name_lookup_skips_outer_class();
269 }
270
class_scope_has_private_brand() const271 bool FunctionLiteral::class_scope_has_private_brand() const {
272 return scope()->class_scope_has_private_brand();
273 }
274
set_class_scope_has_private_brand(bool value)275 void FunctionLiteral::set_class_scope_has_private_brand(bool value) {
276 return scope()->set_class_scope_has_private_brand(value);
277 }
278
ObjectLiteralProperty(Expression * key,Expression * value,Kind kind,bool is_computed_name)279 ObjectLiteralProperty::ObjectLiteralProperty(Expression* key, Expression* value,
280 Kind kind, bool is_computed_name)
281 : LiteralProperty(key, value, is_computed_name),
282 kind_(kind),
283 emit_store_(true) {}
284
ObjectLiteralProperty(AstValueFactory * ast_value_factory,Expression * key,Expression * value,bool is_computed_name)285 ObjectLiteralProperty::ObjectLiteralProperty(AstValueFactory* ast_value_factory,
286 Expression* key, Expression* value,
287 bool is_computed_name)
288 : LiteralProperty(key, value, is_computed_name), emit_store_(true) {
289 if (!is_computed_name && key->AsLiteral()->IsString() &&
290 key->AsLiteral()->AsRawString() == ast_value_factory->proto_string()) {
291 kind_ = PROTOTYPE;
292 } else if (value_->AsMaterializedLiteral() != nullptr) {
293 kind_ = MATERIALIZED_LITERAL;
294 } else if (value_->IsLiteral()) {
295 kind_ = CONSTANT;
296 } else {
297 kind_ = COMPUTED;
298 }
299 }
300
NeedsSetFunctionName() const301 bool LiteralProperty::NeedsSetFunctionName() const {
302 return is_computed_name() && (value_->IsAnonymousFunctionDefinition() ||
303 value_->IsConciseMethodDefinition() ||
304 value_->IsAccessorFunctionDefinition());
305 }
306
ClassLiteralProperty(Expression * key,Expression * value,Kind kind,bool is_static,bool is_computed_name,bool is_private)307 ClassLiteralProperty::ClassLiteralProperty(Expression* key, Expression* value,
308 Kind kind, bool is_static,
309 bool is_computed_name,
310 bool is_private)
311 : LiteralProperty(key, value, is_computed_name),
312 kind_(kind),
313 is_static_(is_static),
314 is_private_(is_private),
315 private_or_computed_name_var_(nullptr) {}
316
IsCompileTimeValue() const317 bool ObjectLiteral::Property::IsCompileTimeValue() const {
318 return kind_ == CONSTANT ||
319 (kind_ == MATERIALIZED_LITERAL && value_->IsCompileTimeValue());
320 }
321
set_emit_store(bool emit_store)322 void ObjectLiteral::Property::set_emit_store(bool emit_store) {
323 emit_store_ = emit_store;
324 }
325
emit_store() const326 bool ObjectLiteral::Property::emit_store() const { return emit_store_; }
327
CalculateEmitStore(Zone * zone)328 void ObjectLiteral::CalculateEmitStore(Zone* zone) {
329 const auto GETTER = ObjectLiteral::Property::GETTER;
330 const auto SETTER = ObjectLiteral::Property::SETTER;
331
332 CustomMatcherZoneHashMap table(Literal::Match,
333 ZoneHashMap::kDefaultHashMapCapacity,
334 ZoneAllocationPolicy(zone));
335 for (int i = properties()->length() - 1; i >= 0; i--) {
336 ObjectLiteral::Property* property = properties()->at(i);
337 if (property->is_computed_name()) continue;
338 if (property->IsPrototype()) continue;
339 Literal* literal = property->key()->AsLiteral();
340 DCHECK(!literal->IsNullLiteral());
341
342 uint32_t hash = literal->Hash();
343 ZoneHashMap::Entry* entry = table.LookupOrInsert(literal, hash);
344 if (entry->value == nullptr) {
345 entry->value = property;
346 } else {
347 // We already have a later definition of this property, so we don't need
348 // to emit a store for the current one.
349 //
350 // There are two subtleties here.
351 //
352 // (1) Emitting a store might actually be incorrect. For example, in {get
353 // foo() {}, foo: 42}, the getter store would override the data property
354 // (which, being a non-computed compile-time valued property, is already
355 // part of the initial literal object.
356 //
357 // (2) If the later definition is an accessor (say, a getter), and the
358 // current definition is a complementary accessor (here, a setter), then
359 // we still must emit a store for the current definition.
360
361 auto later_kind =
362 static_cast<ObjectLiteral::Property*>(entry->value)->kind();
363 bool complementary_accessors =
364 (property->kind() == GETTER && later_kind == SETTER) ||
365 (property->kind() == SETTER && later_kind == GETTER);
366 if (!complementary_accessors) {
367 property->set_emit_store(false);
368 if (later_kind == GETTER || later_kind == SETTER) {
369 entry->value = property;
370 }
371 }
372 }
373 }
374 }
375
ComputeFlags(bool disable_mementos) const376 int ObjectLiteralBoilerplateBuilder::ComputeFlags(bool disable_mementos) const {
377 int flags = LiteralBoilerplateBuilder::ComputeFlags(disable_mementos);
378 if (fast_elements()) flags |= ObjectLiteral::kFastElements;
379 if (has_null_prototype()) flags |= ObjectLiteral::kHasNullPrototype;
380 return flags;
381 }
382
InitFlagsForPendingNullPrototype(int i)383 void ObjectLiteralBoilerplateBuilder::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
EncodeLiteralType()393 int ObjectLiteralBoilerplateBuilder::EncodeLiteralType() {
394 int flags = AggregateLiteral::kNoFlags;
395 if (fast_elements()) flags |= ObjectLiteral::kFastElements;
396 if (has_null_prototype()) flags |= ObjectLiteral::kHasNullPrototype;
397 return flags;
398 }
399
InitDepthAndFlags()400 void ObjectLiteralBoilerplateBuilder::InitDepthAndFlags() {
401 if (is_initialized()) return;
402 bool is_simple = true;
403 bool has_seen_prototype = false;
404 bool needs_initial_allocation_site = false;
405 DepthKind depth_acc = kShallow;
406 uint32_t nof_properties = 0;
407 uint32_t elements = 0;
408 uint32_t max_element_index = 0;
409 for (int i = 0; i < properties()->length(); i++) {
410 ObjectLiteral::Property* property = properties()->at(i);
411 if (property->IsPrototype()) {
412 has_seen_prototype = true;
413 // __proto__:null has no side-effects and is set directly on the
414 // boilerplate.
415 if (property->IsNullPrototype()) {
416 set_has_null_protoype(true);
417 continue;
418 }
419 DCHECK(!has_null_prototype());
420 is_simple = false;
421 continue;
422 }
423 if (nof_properties == boilerplate_properties_) {
424 DCHECK(property->is_computed_name());
425 is_simple = false;
426 if (!has_seen_prototype) InitFlagsForPendingNullPrototype(i);
427 break;
428 }
429 DCHECK(!property->is_computed_name());
430
431 MaterializedLiteral* literal = property->value()->AsMaterializedLiteral();
432 if (literal != nullptr) {
433 LiteralBoilerplateBuilder::InitDepthAndFlags(literal);
434 depth_acc = kNotShallow;
435 needs_initial_allocation_site |= literal->NeedsInitialAllocationSite();
436 }
437
438 Literal* key = property->key()->AsLiteral();
439 Expression* value = property->value();
440
441 bool is_compile_time_value = value->IsCompileTimeValue();
442 is_simple = is_simple && is_compile_time_value;
443
444 // Keep track of the number of elements in the object literal and
445 // the largest element index. If the largest element index is
446 // much larger than the number of elements, creating an object
447 // literal with fast elements will be a waste of space.
448 uint32_t element_index = 0;
449 if (key->AsArrayIndex(&element_index)) {
450 max_element_index = std::max(element_index, max_element_index);
451 elements++;
452 } else {
453 DCHECK(key->IsPropertyName());
454 }
455
456 nof_properties++;
457 }
458
459 set_depth(depth_acc);
460 set_is_simple(is_simple);
461 set_needs_initial_allocation_site(needs_initial_allocation_site);
462 set_has_elements(elements > 0);
463 set_fast_elements((max_element_index <= 32) ||
464 ((2 * elements) >= max_element_index));
465 }
466
467 template <typename IsolateT>
BuildBoilerplateDescription(IsolateT * isolate)468 void ObjectLiteralBoilerplateBuilder::BuildBoilerplateDescription(
469 IsolateT* isolate) {
470 if (!boilerplate_description_.is_null()) return;
471
472 int index_keys = 0;
473 bool has_seen_proto = false;
474 for (int i = 0; i < properties()->length(); i++) {
475 ObjectLiteral::Property* property = properties()->at(i);
476 if (property->IsPrototype()) {
477 has_seen_proto = true;
478 continue;
479 }
480 if (property->is_computed_name()) continue;
481
482 Literal* key = property->key()->AsLiteral();
483 if (!key->IsPropertyName()) index_keys++;
484 }
485
486 Handle<ObjectBoilerplateDescription> boilerplate_description =
487 isolate->factory()->NewObjectBoilerplateDescription(
488 boilerplate_properties_, properties()->length(), index_keys,
489 has_seen_proto);
490
491 int position = 0;
492 for (int i = 0; i < properties()->length(); i++) {
493 ObjectLiteral::Property* property = properties()->at(i);
494 if (property->IsPrototype()) continue;
495
496 if (static_cast<uint32_t>(position) == boilerplate_properties_) {
497 DCHECK(property->is_computed_name());
498 break;
499 }
500 DCHECK(!property->is_computed_name());
501
502 MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral();
503 if (m_literal != nullptr) {
504 BuildConstants(isolate, m_literal);
505 }
506
507 // Add CONSTANT and COMPUTED properties to boilerplate. Use the
508 // 'uninitialized' Oddball for COMPUTED properties, the real value is filled
509 // in at runtime. The enumeration order is maintained.
510 Literal* key_literal = property->key()->AsLiteral();
511 uint32_t element_index = 0;
512 Handle<Object> key =
513 key_literal->AsArrayIndex(&element_index)
514 ? isolate->factory()
515 ->template NewNumberFromUint<AllocationType::kOld>(
516 element_index)
517 : Handle<Object>::cast(key_literal->AsRawPropertyName()->string());
518 Handle<Object> value = GetBoilerplateValue(property->value(), isolate);
519 boilerplate_description->set_key_value(position++, *key, *value);
520 }
521
522 boilerplate_description->set_flags(EncodeLiteralType());
523
524 boilerplate_description_ = boilerplate_description;
525 }
526 template EXPORT_TEMPLATE_DEFINE(
527 V8_BASE_EXPORT) void ObjectLiteralBoilerplateBuilder::
528 BuildBoilerplateDescription(Isolate* isolate);
529 template EXPORT_TEMPLATE_DEFINE(
530 V8_BASE_EXPORT) void ObjectLiteralBoilerplateBuilder::
531 BuildBoilerplateDescription(LocalIsolate* isolate);
532
IsFastCloningSupported() const533 bool ObjectLiteralBoilerplateBuilder::IsFastCloningSupported() const {
534 // The CreateShallowObjectLiteratal builtin doesn't copy elements, and object
535 // literals don't support copy-on-write (COW) elements for now.
536 // TODO(mvstanton): make object literals support COW elements.
537 return fast_elements() && is_shallow() &&
538 properties_count() <=
539 ConstructorBuiltins::kMaximumClonedShallowObjectProperties;
540 }
541
542 // static
543 template <typename IsolateT>
GetBoilerplateValue(Expression * expression,IsolateT * isolate)544 Handle<Object> LiteralBoilerplateBuilder::GetBoilerplateValue(
545 Expression* expression, IsolateT* isolate) {
546 if (expression->IsLiteral()) {
547 return expression->AsLiteral()->BuildValue(isolate);
548 }
549 if (expression->IsCompileTimeValue()) {
550 if (expression->IsObjectLiteral()) {
551 ObjectLiteral* object_literal = expression->AsObjectLiteral();
552 DCHECK(object_literal->builder()->is_simple());
553 return object_literal->builder()->boilerplate_description();
554 } else {
555 DCHECK(expression->IsArrayLiteral());
556 ArrayLiteral* array_literal = expression->AsArrayLiteral();
557 DCHECK(array_literal->builder()->is_simple());
558 return array_literal->builder()->boilerplate_description();
559 }
560 }
561 return isolate->factory()->uninitialized_value();
562 }
563 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
564 Handle<Object> LiteralBoilerplateBuilder::GetBoilerplateValue(
565 Expression* expression, Isolate* isolate);
566 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
567 Handle<Object> LiteralBoilerplateBuilder::GetBoilerplateValue(
568 Expression* expression, LocalIsolate* isolate);
569
InitDepthAndFlags()570 void ArrayLiteralBoilerplateBuilder::InitDepthAndFlags() {
571 if (is_initialized()) return;
572
573 int constants_length =
574 first_spread_index_ >= 0 ? first_spread_index_ : values_->length();
575
576 // Fill in the literals.
577 bool is_simple = first_spread_index_ < 0;
578 bool is_holey = false;
579 ElementsKind kind = FIRST_FAST_ELEMENTS_KIND;
580 DepthKind depth_acc = kShallow;
581 int array_index = 0;
582 for (; array_index < constants_length; array_index++) {
583 Expression* element = values_->at(array_index);
584 MaterializedLiteral* materialized_literal =
585 element->AsMaterializedLiteral();
586 if (materialized_literal != nullptr) {
587 LiteralBoilerplateBuilder::InitDepthAndFlags(materialized_literal);
588 depth_acc = kNotShallow;
589 }
590
591 if (!element->IsCompileTimeValue()) {
592 is_simple = false;
593
594 // Don't change kind here: non-compile time values resolve to an unknown
595 // elements kind, so we allow them to be considered as any one of them.
596
597 // TODO(leszeks): It would be nice to DCHECK here that GetBoilerplateValue
598 // will return IsUninitialized, but that would require being on the main
599 // thread which we may not be.
600 } else {
601 Literal* literal = element->AsLiteral();
602
603 if (!literal) {
604 // Only arrays and objects are compile-time values but not (primitive)
605 // literals.
606 DCHECK(element->IsObjectLiteral() || element->IsArrayLiteral());
607 kind = PACKED_ELEMENTS;
608 } else {
609 switch (literal->type()) {
610 case Literal::kTheHole:
611 is_holey = true;
612 // The hole is allowed in holey double arrays (and holey Smi
613 // arrays), so ignore it as far as is_all_number is concerned.
614 break;
615 case Literal::kHeapNumber:
616 if (kind == PACKED_SMI_ELEMENTS) kind = PACKED_DOUBLE_ELEMENTS;
617 DCHECK_EQ(kind,
618 GetMoreGeneralElementsKind(kind, PACKED_DOUBLE_ELEMENTS));
619 break;
620 case Literal::kSmi:
621 DCHECK_EQ(kind,
622 GetMoreGeneralElementsKind(kind, PACKED_SMI_ELEMENTS));
623 break;
624 case Literal::kBigInt:
625 case Literal::kString:
626 case Literal::kBoolean:
627 case Literal::kUndefined:
628 case Literal::kNull:
629 kind = PACKED_ELEMENTS;
630 break;
631 }
632 }
633 }
634 }
635
636 if (is_holey) {
637 kind = GetHoleyElementsKind(kind);
638 }
639
640 set_depth(depth_acc);
641 set_is_simple(is_simple);
642 set_boilerplate_descriptor_kind(kind);
643
644 // Array literals always need an initial allocation site to properly track
645 // elements transitions.
646 set_needs_initial_allocation_site(true);
647 }
648
649 template <typename IsolateT>
BuildBoilerplateDescription(IsolateT * isolate)650 void ArrayLiteralBoilerplateBuilder::BuildBoilerplateDescription(
651 IsolateT* isolate) {
652 if (!boilerplate_description_.is_null()) return;
653
654 int constants_length =
655 first_spread_index_ >= 0 ? first_spread_index_ : values_->length();
656 ElementsKind kind = boilerplate_descriptor_kind();
657 bool use_doubles = IsDoubleElementsKind(kind);
658
659 Handle<FixedArrayBase> elements;
660 if (use_doubles) {
661 elements = isolate->factory()->NewFixedDoubleArray(constants_length,
662 AllocationType::kOld);
663 } else {
664 elements = isolate->factory()->NewFixedArrayWithHoles(constants_length,
665 AllocationType::kOld);
666 }
667
668 // Fill in the literals.
669 int array_index = 0;
670 for (; array_index < constants_length; array_index++) {
671 Expression* element = values_->at(array_index);
672 DCHECK(!element->IsSpread());
673 if (use_doubles) {
674 Literal* literal = element->AsLiteral();
675
676 if (literal && literal->type() == Literal::kTheHole) {
677 DCHECK(IsHoleyElementsKind(kind));
678 DCHECK(GetBoilerplateValue(element, isolate)->IsTheHole(isolate));
679 FixedDoubleArray::cast(*elements).set_the_hole(array_index);
680 continue;
681 } else if (literal && literal->IsNumber()) {
682 FixedDoubleArray::cast(*elements).set(array_index, literal->AsNumber());
683 } else {
684 DCHECK(GetBoilerplateValue(element, isolate)->IsUninitialized(isolate));
685 FixedDoubleArray::cast(*elements).set(array_index, 0);
686 }
687
688 } else {
689 MaterializedLiteral* m_literal = element->AsMaterializedLiteral();
690 if (m_literal != nullptr) {
691 BuildConstants(isolate, m_literal);
692 }
693
694 // New handle scope here, needs to be after BuildContants().
695 typename IsolateT::HandleScopeType scope(isolate);
696
697 Object boilerplate_value = *GetBoilerplateValue(element, isolate);
698 // We shouldn't allocate after creating the boilerplate value.
699 DisallowGarbageCollection no_gc;
700
701 if (boilerplate_value.IsTheHole(isolate)) {
702 DCHECK(IsHoleyElementsKind(kind));
703 continue;
704 }
705
706 if (boilerplate_value.IsUninitialized(isolate)) {
707 boilerplate_value = Smi::zero();
708 }
709
710 DCHECK_EQ(kind, GetMoreGeneralElementsKind(
711 kind, boilerplate_value.OptimalElementsKind(
712 GetPtrComprCageBase(*elements))));
713
714 FixedArray::cast(*elements).set(array_index, boilerplate_value);
715 }
716 } // namespace internal
717
718 // Simple and shallow arrays can be lazily copied, we transform the
719 // elements array to a copy-on-write array.
720 if (is_simple() && depth() == kShallow && array_index > 0 &&
721 IsSmiOrObjectElementsKind(kind)) {
722 elements->set_map_safe_transition(
723 ReadOnlyRoots(isolate).fixed_cow_array_map());
724 }
725
726 boilerplate_description_ =
727 isolate->factory()->NewArrayBoilerplateDescription(kind, elements);
728 }
729 template EXPORT_TEMPLATE_DEFINE(
730 V8_BASE_EXPORT) void ArrayLiteralBoilerplateBuilder::
731 BuildBoilerplateDescription(Isolate* isolate);
732 template EXPORT_TEMPLATE_DEFINE(
733 V8_BASE_EXPORT) void ArrayLiteralBoilerplateBuilder::
734 BuildBoilerplateDescription(LocalIsolate*
735
736 isolate);
737
IsFastCloningSupported() const738 bool ArrayLiteralBoilerplateBuilder::IsFastCloningSupported() const {
739 return depth() <= kShallow &&
740 values_->length() <=
741 ConstructorBuiltins::kMaximumClonedShallowArrayElements;
742 }
743
IsSimple() const744 bool MaterializedLiteral::IsSimple() const {
745 if (IsArrayLiteral()) return AsArrayLiteral()->builder()->is_simple();
746 if (IsObjectLiteral()) return AsObjectLiteral()->builder()->is_simple();
747 DCHECK(IsRegExpLiteral());
748 return false;
749 }
750
751 // static
InitDepthAndFlags(MaterializedLiteral * expr)752 void LiteralBoilerplateBuilder::InitDepthAndFlags(MaterializedLiteral* expr) {
753 if (expr->IsArrayLiteral()) {
754 return expr->AsArrayLiteral()->builder()->InitDepthAndFlags();
755 }
756 if (expr->IsObjectLiteral()) {
757 return expr->AsObjectLiteral()->builder()->InitDepthAndFlags();
758 }
759 DCHECK(expr->IsRegExpLiteral());
760 }
761
NeedsInitialAllocationSite()762 bool MaterializedLiteral::NeedsInitialAllocationSite(
763
764 ) {
765 if (IsArrayLiteral()) {
766 return AsArrayLiteral()->builder()->needs_initial_allocation_site();
767 }
768 if (IsObjectLiteral()) {
769 return AsObjectLiteral()->builder()->needs_initial_allocation_site();
770 }
771 DCHECK(IsRegExpLiteral());
772 return false;
773 }
774
775 template <typename IsolateT>
BuildConstants(IsolateT * isolate,MaterializedLiteral * expr)776 void LiteralBoilerplateBuilder::BuildConstants(IsolateT* isolate,
777 MaterializedLiteral* expr) {
778 if (expr->IsArrayLiteral()) {
779 expr->AsArrayLiteral()->builder()->BuildBoilerplateDescription(isolate);
780 return;
781 }
782 if (expr->IsObjectLiteral()) {
783 expr->AsObjectLiteral()->builder()->BuildBoilerplateDescription(isolate);
784 return;
785 }
786 DCHECK(expr->IsRegExpLiteral());
787 }
788 template EXPORT_TEMPLATE_DEFINE(V8_BASE_EXPORT) void LiteralBoilerplateBuilder::
789 BuildConstants(Isolate* isolate, MaterializedLiteral* expr);
790 template EXPORT_TEMPLATE_DEFINE(V8_BASE_EXPORT) void LiteralBoilerplateBuilder::
791 BuildConstants(LocalIsolate* isolate, MaterializedLiteral* expr);
792
793 template <typename IsolateT>
GetOrBuildDescription(IsolateT * isolate)794 Handle<TemplateObjectDescription> GetTemplateObject::GetOrBuildDescription(
795 IsolateT* isolate) {
796 Handle<FixedArray> raw_strings_handle = isolate->factory()->NewFixedArray(
797 this->raw_strings()->length(), AllocationType::kOld);
798 bool raw_and_cooked_match = true;
799 {
800 DisallowGarbageCollection no_gc;
801 FixedArray raw_strings = *raw_strings_handle;
802
803 for (int i = 0; i < raw_strings.length(); ++i) {
804 if (this->raw_strings()->at(i) != this->cooked_strings()->at(i)) {
805 // If the AstRawStrings don't match, then neither should the allocated
806 // Strings, since the AstValueFactory should have deduplicated them
807 // already.
808 DCHECK_IMPLIES(this->cooked_strings()->at(i) != nullptr,
809 *this->cooked_strings()->at(i)->string() !=
810 *this->raw_strings()->at(i)->string());
811
812 raw_and_cooked_match = false;
813 }
814 raw_strings.set(i, *this->raw_strings()->at(i)->string());
815 }
816 }
817 Handle<FixedArray> cooked_strings_handle = raw_strings_handle;
818 if (!raw_and_cooked_match) {
819 cooked_strings_handle = isolate->factory()->NewFixedArray(
820 this->cooked_strings()->length(), AllocationType::kOld);
821 DisallowGarbageCollection no_gc;
822 FixedArray cooked_strings = *cooked_strings_handle;
823 ReadOnlyRoots roots(isolate);
824 for (int i = 0; i < cooked_strings.length(); ++i) {
825 if (this->cooked_strings()->at(i) != nullptr) {
826 cooked_strings.set(i, *this->cooked_strings()->at(i)->string());
827 } else {
828 cooked_strings.set_undefined(roots, i);
829 }
830 }
831 }
832 return isolate->factory()->NewTemplateObjectDescription(
833 raw_strings_handle, cooked_strings_handle);
834 }
835 template EXPORT_TEMPLATE_DEFINE(V8_BASE_EXPORT)
836 Handle<TemplateObjectDescription> GetTemplateObject::GetOrBuildDescription(
837 Isolate* isolate);
838 template EXPORT_TEMPLATE_DEFINE(V8_BASE_EXPORT)
839 Handle<TemplateObjectDescription> GetTemplateObject::GetOrBuildDescription(
840 LocalIsolate* isolate);
841
IsCommutativeOperationWithSmiLiteral(Token::Value op)842 static bool IsCommutativeOperationWithSmiLiteral(Token::Value op) {
843 // Add is not commutative due to potential for string addition.
844 return op == Token::MUL || op == Token::BIT_AND || op == Token::BIT_OR ||
845 op == Token::BIT_XOR;
846 }
847
848 // Check for the pattern: x + 1.
MatchSmiLiteralOperation(Expression * left,Expression * right,Expression ** expr,Smi * literal)849 static bool MatchSmiLiteralOperation(Expression* left, Expression* right,
850 Expression** expr, Smi* literal) {
851 if (right->IsSmiLiteral()) {
852 *expr = left;
853 *literal = right->AsLiteral()->AsSmiLiteral();
854 return true;
855 }
856 return false;
857 }
858
IsSmiLiteralOperation(Expression ** subexpr,Smi * literal)859 bool BinaryOperation::IsSmiLiteralOperation(Expression** subexpr,
860 Smi* literal) {
861 return MatchSmiLiteralOperation(left_, right_, subexpr, literal) ||
862 (IsCommutativeOperationWithSmiLiteral(op()) &&
863 MatchSmiLiteralOperation(right_, left_, subexpr, literal));
864 }
865
IsTypeof(Expression * expr)866 static bool IsTypeof(Expression* expr) {
867 UnaryOperation* maybe_unary = expr->AsUnaryOperation();
868 return maybe_unary != nullptr && maybe_unary->op() == Token::TYPEOF;
869 }
870
871 // Check for the pattern: typeof <expression> equals <string literal>.
MatchLiteralCompareTypeof(Expression * left,Token::Value op,Expression * right,Expression ** expr,Literal ** literal)872 static bool MatchLiteralCompareTypeof(Expression* left, Token::Value op,
873 Expression* right, Expression** expr,
874 Literal** literal) {
875 if (IsTypeof(left) && right->IsStringLiteral() && Token::IsEqualityOp(op)) {
876 *expr = left->AsUnaryOperation()->expression();
877 *literal = right->AsLiteral();
878 return true;
879 }
880 return false;
881 }
882
IsLiteralCompareTypeof(Expression ** expr,Literal ** literal)883 bool CompareOperation::IsLiteralCompareTypeof(Expression** expr,
884 Literal** literal) {
885 return MatchLiteralCompareTypeof(left_, op(), right_, expr, literal) ||
886 MatchLiteralCompareTypeof(right_, op(), left_, expr, literal);
887 }
888
IsVoidOfLiteral(Expression * expr)889 static bool IsVoidOfLiteral(Expression* expr) {
890 UnaryOperation* maybe_unary = expr->AsUnaryOperation();
891 return maybe_unary != nullptr && maybe_unary->op() == Token::VOID &&
892 maybe_unary->expression()->IsLiteral();
893 }
894
895 // Check for the pattern: void <literal> equals <expression> or
896 // undefined equals <expression>
MatchLiteralCompareUndefined(Expression * left,Token::Value op,Expression * right,Expression ** expr)897 static bool MatchLiteralCompareUndefined(Expression* left, Token::Value op,
898 Expression* right, Expression** expr) {
899 if (IsVoidOfLiteral(left) && Token::IsEqualityOp(op)) {
900 *expr = right;
901 return true;
902 }
903 if (left->IsUndefinedLiteral() && Token::IsEqualityOp(op)) {
904 *expr = right;
905 return true;
906 }
907 return false;
908 }
909
IsLiteralCompareUndefined(Expression ** expr)910 bool CompareOperation::IsLiteralCompareUndefined(Expression** expr) {
911 return MatchLiteralCompareUndefined(left_, op(), right_, expr) ||
912 MatchLiteralCompareUndefined(right_, op(), left_, expr);
913 }
914
915 // Check for the pattern: null equals <expression>
MatchLiteralCompareNull(Expression * left,Token::Value op,Expression * right,Expression ** expr)916 static bool MatchLiteralCompareNull(Expression* left, Token::Value op,
917 Expression* right, Expression** expr) {
918 if (left->IsNullLiteral() && Token::IsEqualityOp(op)) {
919 *expr = right;
920 return true;
921 }
922 return false;
923 }
924
IsLiteralCompareNull(Expression ** expr)925 bool CompareOperation::IsLiteralCompareNull(Expression** expr) {
926 return MatchLiteralCompareNull(left_, op(), right_, expr) ||
927 MatchLiteralCompareNull(right_, op(), left_, expr);
928 }
929
ComputeSpreadPosition()930 void CallBase::ComputeSpreadPosition() {
931 int arguments_length = arguments_.length();
932 int first_spread_index = 0;
933 for (; first_spread_index < arguments_length; first_spread_index++) {
934 if (arguments_.at(first_spread_index)->IsSpread()) break;
935 }
936 SpreadPosition position;
937 if (first_spread_index == arguments_length - 1) {
938 position = kHasFinalSpread;
939 } else {
940 DCHECK_LT(first_spread_index, arguments_length - 1);
941 position = kHasNonFinalSpread;
942 }
943 bit_field_ |= SpreadPositionField::encode(position);
944 }
945
GetCallType() const946 Call::CallType Call::GetCallType() const {
947 VariableProxy* proxy = expression()->AsVariableProxy();
948 if (proxy != nullptr) {
949 if (proxy->var()->IsUnallocated()) {
950 return GLOBAL_CALL;
951 } else if (proxy->var()->IsLookupSlot()) {
952 // Calls going through 'with' always use VariableMode::kDynamic rather
953 // than VariableMode::kDynamicLocal or VariableMode::kDynamicGlobal.
954 return proxy->var()->mode() == VariableMode::kDynamic ? WITH_CALL
955 : OTHER_CALL;
956 }
957 }
958
959 if (expression()->IsSuperCallReference()) return SUPER_CALL;
960
961 Property* property = expression()->AsProperty();
962 bool is_optional_chain = false;
963 if (V8_UNLIKELY(property == nullptr && expression()->IsOptionalChain())) {
964 is_optional_chain = true;
965 property = expression()->AsOptionalChain()->expression()->AsProperty();
966 }
967 if (property != nullptr) {
968 if (property->IsPrivateReference()) {
969 if (is_optional_chain) return PRIVATE_OPTIONAL_CHAIN_CALL;
970 return PRIVATE_CALL;
971 }
972 bool is_super = property->IsSuperAccess();
973 // `super?.` is not syntactically valid, so a property load cannot be both
974 // super and an optional chain.
975 DCHECK(!is_super || !is_optional_chain);
976 if (property->key()->IsPropertyName()) {
977 if (is_super) return NAMED_SUPER_PROPERTY_CALL;
978 if (is_optional_chain) return NAMED_OPTIONAL_CHAIN_PROPERTY_CALL;
979 return NAMED_PROPERTY_CALL;
980 } else {
981 if (is_super) return KEYED_SUPER_PROPERTY_CALL;
982 if (is_optional_chain) return KEYED_OPTIONAL_CHAIN_PROPERTY_CALL;
983 return KEYED_PROPERTY_CALL;
984 }
985 }
986
987 return OTHER_CALL;
988 }
989
CaseClause(Zone * zone,Expression * label,const ScopedPtrList<Statement> & statements)990 CaseClause::CaseClause(Zone* zone, Expression* label,
991 const ScopedPtrList<Statement>& statements)
992 : label_(label), statements_(statements.ToConstVector(), zone) {}
993
IsPropertyName() const994 bool Literal::IsPropertyName() const {
995 if (type() != kString) return false;
996 uint32_t index;
997 return !string_->AsArrayIndex(&index);
998 }
999
ToUint32(uint32_t * value) const1000 bool Literal::ToUint32(uint32_t* value) const {
1001 switch (type()) {
1002 case kString:
1003 return string_->AsArrayIndex(value);
1004 case kSmi:
1005 if (smi_ < 0) return false;
1006 *value = static_cast<uint32_t>(smi_);
1007 return true;
1008 case kHeapNumber:
1009 return DoubleToUint32IfEqualToSelf(AsNumber(), value);
1010 default:
1011 return false;
1012 }
1013 }
1014
AsArrayIndex(uint32_t * value) const1015 bool Literal::AsArrayIndex(uint32_t* value) const {
1016 return ToUint32(value) && *value != kMaxUInt32;
1017 }
1018
1019 template <typename IsolateT>
BuildValue(IsolateT * isolate) const1020 Handle<Object> Literal::BuildValue(IsolateT* isolate) const {
1021 switch (type()) {
1022 case kSmi:
1023 return handle(Smi::FromInt(smi_), isolate);
1024 case kHeapNumber:
1025 return isolate->factory()->template NewNumber<AllocationType::kOld>(
1026 number_);
1027 case kString:
1028 return string_->string();
1029 case kBoolean:
1030 return isolate->factory()->ToBoolean(boolean_);
1031 case kNull:
1032 return isolate->factory()->null_value();
1033 case kUndefined:
1034 return isolate->factory()->undefined_value();
1035 case kTheHole:
1036 return isolate->factory()->the_hole_value();
1037 case kBigInt:
1038 // This should never fail: the parser will never create a BigInt
1039 // literal that cannot be allocated.
1040 return BigIntLiteral(isolate, bigint_.c_str()).ToHandleChecked();
1041 }
1042 UNREACHABLE();
1043 }
1044 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
1045 Handle<Object> Literal::BuildValue(Isolate* isolate) const;
1046 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
1047 Handle<Object> Literal::BuildValue(LocalIsolate* isolate) const;
1048
ToBooleanIsTrue() const1049 bool Literal::ToBooleanIsTrue() const {
1050 switch (type()) {
1051 case kSmi:
1052 return smi_ != 0;
1053 case kHeapNumber:
1054 return DoubleToBoolean(number_);
1055 case kString:
1056 return !string_->IsEmpty();
1057 case kNull:
1058 case kUndefined:
1059 return false;
1060 case kBoolean:
1061 return boolean_;
1062 case kBigInt: {
1063 const char* bigint_str = bigint_.c_str();
1064 size_t length = strlen(bigint_str);
1065 DCHECK_GT(length, 0);
1066 if (length == 1 && bigint_str[0] == '0') return false;
1067 // Skip over any radix prefix; BigInts with length > 1 only
1068 // begin with zero if they include a radix.
1069 for (size_t i = (bigint_str[0] == '0') ? 2 : 0; i < length; ++i) {
1070 if (bigint_str[i] != '0') return true;
1071 }
1072 return false;
1073 }
1074 case kTheHole:
1075 UNREACHABLE();
1076 }
1077 UNREACHABLE();
1078 }
1079
Hash()1080 uint32_t Literal::Hash() {
1081 uint32_t index;
1082 if (AsArrayIndex(&index)) {
1083 // Treat array indices as numbers, so that array indices are de-duped
1084 // correctly even if one of them is a string and the other is a number.
1085 return ComputeLongHash(index);
1086 }
1087 return IsString() ? AsRawString()->Hash()
1088 : ComputeLongHash(base::double_to_uint64(AsNumber()));
1089 }
1090
1091 // static
Match(void * a,void * b)1092 bool Literal::Match(void* a, void* b) {
1093 Literal* x = static_cast<Literal*>(a);
1094 Literal* y = static_cast<Literal*>(b);
1095 uint32_t index_x;
1096 uint32_t index_y;
1097 if (x->AsArrayIndex(&index_x)) {
1098 return y->AsArrayIndex(&index_y) && index_x == index_y;
1099 }
1100 return (x->IsString() && y->IsString() &&
1101 x->AsRawString() == y->AsRawString()) ||
1102 (x->IsNumber() && y->IsNumber() && x->AsNumber() == y->AsNumber());
1103 }
1104
NewNumberLiteral(double number,int pos)1105 Literal* AstNodeFactory::NewNumberLiteral(double number, int pos) {
1106 int int_value;
1107 if (DoubleToSmiInteger(number, &int_value)) {
1108 return NewSmiLiteral(int_value, pos);
1109 }
1110 return zone_->New<Literal>(number, pos);
1111 }
1112
debug_name()1113 const char* CallRuntime::debug_name() {
1114 #ifdef DEBUG
1115 return is_jsruntime() ? NameForNativeContextIntrinsicIndex(context_index_)
1116 : function_->name;
1117 #else
1118 return is_jsruntime() ? "(context function)" : function_->name;
1119 #endif // DEBUG
1120 }
1121
1122 } // namespace internal
1123 } // namespace v8
1124