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