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.h" 6 7 #include <cmath> // For isfinite. 8 #include "src/builtins.h" 9 #include "src/code-stubs.h" 10 #include "src/contexts.h" 11 #include "src/conversions.h" 12 #include "src/hashmap.h" 13 #include "src/parser.h" 14 #include "src/property.h" 15 #include "src/property-details.h" 16 #include "src/scopes.h" 17 #include "src/string-stream.h" 18 #include "src/type-info.h" 19 20 namespace v8 { 21 namespace internal { 22 23 // ---------------------------------------------------------------------------- 24 // All the Accept member functions for each syntax tree node type. 25 26 #define DECL_ACCEPT(type) \ 27 void type::Accept(AstVisitor* v) { v->Visit##type(this); } 28 AST_NODE_LIST(DECL_ACCEPT) 29 #undef DECL_ACCEPT 30 31 32 // ---------------------------------------------------------------------------- 33 // Implementation of other node functionality. 34 35 36 bool Expression::IsSmiLiteral() const { 37 return IsLiteral() && AsLiteral()->value()->IsSmi(); 38 } 39 40 41 bool Expression::IsStringLiteral() const { 42 return IsLiteral() && AsLiteral()->value()->IsString(); 43 } 44 45 46 bool Expression::IsNullLiteral() const { 47 return IsLiteral() && AsLiteral()->value()->IsNull(); 48 } 49 50 51 bool Expression::IsUndefinedLiteral(Isolate* isolate) const { 52 const VariableProxy* var_proxy = AsVariableProxy(); 53 if (var_proxy == NULL) return false; 54 Variable* var = var_proxy->var(); 55 // The global identifier "undefined" is immutable. Everything 56 // else could be reassigned. 57 return var != NULL && var->location() == Variable::UNALLOCATED && 58 var_proxy->raw_name()->IsOneByteEqualTo("undefined"); 59 } 60 61 62 VariableProxy::VariableProxy(Zone* zone, Variable* var, int position, 63 IdGen* id_gen) 64 : Expression(zone, position, id_gen), 65 name_(var->raw_name()), 66 var_(NULL), // Will be set by the call to BindTo. 67 is_this_(var->is_this()), 68 is_assigned_(false), 69 interface_(var->interface()), 70 variable_feedback_slot_(kInvalidFeedbackSlot) { 71 BindTo(var); 72 } 73 74 75 VariableProxy::VariableProxy(Zone* zone, const AstRawString* name, bool is_this, 76 Interface* interface, int position, IdGen* id_gen) 77 : Expression(zone, position, id_gen), 78 name_(name), 79 var_(NULL), 80 is_this_(is_this), 81 is_assigned_(false), 82 interface_(interface), 83 variable_feedback_slot_(kInvalidFeedbackSlot) {} 84 85 86 void VariableProxy::BindTo(Variable* var) { 87 DCHECK(var_ == NULL); // must be bound only once 88 DCHECK(var != NULL); // must bind 89 DCHECK(!FLAG_harmony_modules || interface_->IsUnified(var->interface())); 90 DCHECK((is_this() && var->is_this()) || name_ == var->raw_name()); 91 // Ideally CONST-ness should match. However, this is very hard to achieve 92 // because we don't know the exact semantics of conflicting (const and 93 // non-const) multiple variable declarations, const vars introduced via 94 // eval() etc. Const-ness and variable declarations are a complete mess 95 // in JS. Sigh... 96 var_ = var; 97 var->set_is_used(); 98 } 99 100 101 Assignment::Assignment(Zone* zone, Token::Value op, Expression* target, 102 Expression* value, int pos, IdGen* id_gen) 103 : Expression(zone, pos, id_gen), 104 op_(op), 105 target_(target), 106 value_(value), 107 binary_operation_(NULL), 108 assignment_id_(id_gen->GetNextId()), 109 is_uninitialized_(false), 110 store_mode_(STANDARD_STORE) {} 111 112 113 Token::Value Assignment::binary_op() const { 114 switch (op_) { 115 case Token::ASSIGN_BIT_OR: return Token::BIT_OR; 116 case Token::ASSIGN_BIT_XOR: return Token::BIT_XOR; 117 case Token::ASSIGN_BIT_AND: return Token::BIT_AND; 118 case Token::ASSIGN_SHL: return Token::SHL; 119 case Token::ASSIGN_SAR: return Token::SAR; 120 case Token::ASSIGN_SHR: return Token::SHR; 121 case Token::ASSIGN_ADD: return Token::ADD; 122 case Token::ASSIGN_SUB: return Token::SUB; 123 case Token::ASSIGN_MUL: return Token::MUL; 124 case Token::ASSIGN_DIV: return Token::DIV; 125 case Token::ASSIGN_MOD: return Token::MOD; 126 default: UNREACHABLE(); 127 } 128 return Token::ILLEGAL; 129 } 130 131 132 bool FunctionLiteral::AllowsLazyCompilation() { 133 return scope()->AllowsLazyCompilation(); 134 } 135 136 137 bool FunctionLiteral::AllowsLazyCompilationWithoutContext() { 138 return scope()->AllowsLazyCompilationWithoutContext(); 139 } 140 141 142 int FunctionLiteral::start_position() const { 143 return scope()->start_position(); 144 } 145 146 147 int FunctionLiteral::end_position() const { 148 return scope()->end_position(); 149 } 150 151 152 StrictMode FunctionLiteral::strict_mode() const { 153 return scope()->strict_mode(); 154 } 155 156 157 void FunctionLiteral::InitializeSharedInfo( 158 Handle<Code> unoptimized_code) { 159 for (RelocIterator it(*unoptimized_code); !it.done(); it.next()) { 160 RelocInfo* rinfo = it.rinfo(); 161 if (rinfo->rmode() != RelocInfo::EMBEDDED_OBJECT) continue; 162 Object* obj = rinfo->target_object(); 163 if (obj->IsSharedFunctionInfo()) { 164 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj); 165 if (shared->start_position() == start_position()) { 166 shared_info_ = Handle<SharedFunctionInfo>(shared); 167 break; 168 } 169 } 170 } 171 } 172 173 174 ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone, 175 AstValueFactory* ast_value_factory, 176 Literal* key, Expression* value, 177 bool is_static) { 178 emit_store_ = true; 179 key_ = key; 180 value_ = value; 181 is_static_ = is_static; 182 if (key->raw_value()->EqualsString(ast_value_factory->proto_string())) { 183 kind_ = PROTOTYPE; 184 } else if (value_->AsMaterializedLiteral() != NULL) { 185 kind_ = MATERIALIZED_LITERAL; 186 } else if (value_->IsLiteral()) { 187 kind_ = CONSTANT; 188 } else { 189 kind_ = COMPUTED; 190 } 191 } 192 193 194 ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone, bool is_getter, 195 FunctionLiteral* value, 196 bool is_static) { 197 emit_store_ = true; 198 value_ = value; 199 kind_ = is_getter ? GETTER : SETTER; 200 is_static_ = is_static; 201 } 202 203 204 bool ObjectLiteral::Property::IsCompileTimeValue() { 205 return kind_ == CONSTANT || 206 (kind_ == MATERIALIZED_LITERAL && 207 CompileTimeValue::IsCompileTimeValue(value_)); 208 } 209 210 211 void ObjectLiteral::Property::set_emit_store(bool emit_store) { 212 emit_store_ = emit_store; 213 } 214 215 216 bool ObjectLiteral::Property::emit_store() { 217 return emit_store_; 218 } 219 220 221 void ObjectLiteral::CalculateEmitStore(Zone* zone) { 222 ZoneAllocationPolicy allocator(zone); 223 224 ZoneHashMap table(Literal::Match, ZoneHashMap::kDefaultHashMapCapacity, 225 allocator); 226 for (int i = properties()->length() - 1; i >= 0; i--) { 227 ObjectLiteral::Property* property = properties()->at(i); 228 Literal* literal = property->key(); 229 if (literal->value()->IsNull()) continue; 230 uint32_t hash = literal->Hash(); 231 // If the key of a computed property is in the table, do not emit 232 // a store for the property later. 233 if ((property->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL || 234 property->kind() == ObjectLiteral::Property::COMPUTED) && 235 table.Lookup(literal, hash, false, allocator) != NULL) { 236 property->set_emit_store(false); 237 } else { 238 // Add key to the table. 239 table.Lookup(literal, hash, true, allocator); 240 } 241 } 242 } 243 244 245 bool ObjectLiteral::IsBoilerplateProperty(ObjectLiteral::Property* property) { 246 return property != NULL && 247 property->kind() != ObjectLiteral::Property::PROTOTYPE; 248 } 249 250 251 void ObjectLiteral::BuildConstantProperties(Isolate* isolate) { 252 if (!constant_properties_.is_null()) return; 253 254 // Allocate a fixed array to hold all the constant properties. 255 Handle<FixedArray> constant_properties = isolate->factory()->NewFixedArray( 256 boilerplate_properties_ * 2, TENURED); 257 258 int position = 0; 259 // Accumulate the value in local variables and store it at the end. 260 bool is_simple = true; 261 int depth_acc = 1; 262 uint32_t max_element_index = 0; 263 uint32_t elements = 0; 264 for (int i = 0; i < properties()->length(); i++) { 265 ObjectLiteral::Property* property = properties()->at(i); 266 if (!IsBoilerplateProperty(property)) { 267 is_simple = false; 268 continue; 269 } 270 MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral(); 271 if (m_literal != NULL) { 272 m_literal->BuildConstants(isolate); 273 if (m_literal->depth() >= depth_acc) depth_acc = m_literal->depth() + 1; 274 } 275 276 // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined 277 // value for COMPUTED properties, the real value is filled in at 278 // runtime. The enumeration order is maintained. 279 Handle<Object> key = property->key()->value(); 280 Handle<Object> value = GetBoilerplateValue(property->value(), isolate); 281 282 // Ensure objects that may, at any point in time, contain fields with double 283 // representation are always treated as nested objects. This is true for 284 // computed fields (value is undefined), and smi and double literals 285 // (value->IsNumber()). 286 // TODO(verwaest): Remove once we can store them inline. 287 if (FLAG_track_double_fields && 288 (value->IsNumber() || value->IsUninitialized())) { 289 may_store_doubles_ = true; 290 } 291 292 is_simple = is_simple && !value->IsUninitialized(); 293 294 // Keep track of the number of elements in the object literal and 295 // the largest element index. If the largest element index is 296 // much larger than the number of elements, creating an object 297 // literal with fast elements will be a waste of space. 298 uint32_t element_index = 0; 299 if (key->IsString() 300 && Handle<String>::cast(key)->AsArrayIndex(&element_index) 301 && element_index > max_element_index) { 302 max_element_index = element_index; 303 elements++; 304 } else if (key->IsSmi()) { 305 int key_value = Smi::cast(*key)->value(); 306 if (key_value > 0 307 && static_cast<uint32_t>(key_value) > max_element_index) { 308 max_element_index = key_value; 309 } 310 elements++; 311 } 312 313 // Add name, value pair to the fixed array. 314 constant_properties->set(position++, *key); 315 constant_properties->set(position++, *value); 316 } 317 318 constant_properties_ = constant_properties; 319 fast_elements_ = 320 (max_element_index <= 32) || ((2 * elements) >= max_element_index); 321 set_is_simple(is_simple); 322 set_depth(depth_acc); 323 } 324 325 326 void ArrayLiteral::BuildConstantElements(Isolate* isolate) { 327 if (!constant_elements_.is_null()) return; 328 329 // Allocate a fixed array to hold all the object literals. 330 Handle<JSArray> array = 331 isolate->factory()->NewJSArray(0, FAST_HOLEY_SMI_ELEMENTS); 332 JSArray::Expand(array, values()->length()); 333 334 // Fill in the literals. 335 bool is_simple = true; 336 int depth_acc = 1; 337 bool is_holey = false; 338 for (int i = 0, n = values()->length(); i < n; i++) { 339 Expression* element = values()->at(i); 340 MaterializedLiteral* m_literal = element->AsMaterializedLiteral(); 341 if (m_literal != NULL) { 342 m_literal->BuildConstants(isolate); 343 if (m_literal->depth() + 1 > depth_acc) { 344 depth_acc = m_literal->depth() + 1; 345 } 346 } 347 Handle<Object> boilerplate_value = GetBoilerplateValue(element, isolate); 348 if (boilerplate_value->IsTheHole()) { 349 is_holey = true; 350 } else if (boilerplate_value->IsUninitialized()) { 351 is_simple = false; 352 JSObject::SetOwnElement( 353 array, i, handle(Smi::FromInt(0), isolate), SLOPPY).Assert(); 354 } else { 355 JSObject::SetOwnElement(array, i, boilerplate_value, SLOPPY).Assert(); 356 } 357 } 358 359 Handle<FixedArrayBase> element_values(array->elements()); 360 361 // Simple and shallow arrays can be lazily copied, we transform the 362 // elements array to a copy-on-write array. 363 if (is_simple && depth_acc == 1 && values()->length() > 0 && 364 array->HasFastSmiOrObjectElements()) { 365 element_values->set_map(isolate->heap()->fixed_cow_array_map()); 366 } 367 368 // Remember both the literal's constant values as well as the ElementsKind 369 // in a 2-element FixedArray. 370 Handle<FixedArray> literals = isolate->factory()->NewFixedArray(2, TENURED); 371 372 ElementsKind kind = array->GetElementsKind(); 373 kind = is_holey ? GetHoleyElementsKind(kind) : GetPackedElementsKind(kind); 374 375 literals->set(0, Smi::FromInt(kind)); 376 literals->set(1, *element_values); 377 378 constant_elements_ = literals; 379 set_is_simple(is_simple); 380 set_depth(depth_acc); 381 } 382 383 384 Handle<Object> MaterializedLiteral::GetBoilerplateValue(Expression* expression, 385 Isolate* isolate) { 386 if (expression->IsLiteral()) { 387 return expression->AsLiteral()->value(); 388 } 389 if (CompileTimeValue::IsCompileTimeValue(expression)) { 390 return CompileTimeValue::GetValue(isolate, expression); 391 } 392 return isolate->factory()->uninitialized_value(); 393 } 394 395 396 void MaterializedLiteral::BuildConstants(Isolate* isolate) { 397 if (IsArrayLiteral()) { 398 return AsArrayLiteral()->BuildConstantElements(isolate); 399 } 400 if (IsObjectLiteral()) { 401 return AsObjectLiteral()->BuildConstantProperties(isolate); 402 } 403 DCHECK(IsRegExpLiteral()); 404 DCHECK(depth() >= 1); // Depth should be initialized. 405 } 406 407 408 void TargetCollector::AddTarget(Label* target, Zone* zone) { 409 // Add the label to the collector, but discard duplicates. 410 int length = targets_.length(); 411 for (int i = 0; i < length; i++) { 412 if (targets_[i] == target) return; 413 } 414 targets_.Add(target, zone); 415 } 416 417 418 void UnaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) { 419 // TODO(olivf) If this Operation is used in a test context, then the 420 // expression has a ToBoolean stub and we want to collect the type 421 // information. However the GraphBuilder expects it to be on the instruction 422 // corresponding to the TestContext, therefore we have to store it here and 423 // not on the operand. 424 set_to_boolean_types(oracle->ToBooleanTypes(expression()->test_id())); 425 } 426 427 428 void BinaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) { 429 // TODO(olivf) If this Operation is used in a test context, then the right 430 // hand side has a ToBoolean stub and we want to collect the type information. 431 // However the GraphBuilder expects it to be on the instruction corresponding 432 // to the TestContext, therefore we have to store it here and not on the 433 // right hand operand. 434 set_to_boolean_types(oracle->ToBooleanTypes(right()->test_id())); 435 } 436 437 438 bool BinaryOperation::ResultOverwriteAllowed() const { 439 switch (op_) { 440 case Token::COMMA: 441 case Token::OR: 442 case Token::AND: 443 return false; 444 case Token::BIT_OR: 445 case Token::BIT_XOR: 446 case Token::BIT_AND: 447 case Token::SHL: 448 case Token::SAR: 449 case Token::SHR: 450 case Token::ADD: 451 case Token::SUB: 452 case Token::MUL: 453 case Token::DIV: 454 case Token::MOD: 455 return true; 456 default: 457 UNREACHABLE(); 458 } 459 return false; 460 } 461 462 463 static bool IsTypeof(Expression* expr) { 464 UnaryOperation* maybe_unary = expr->AsUnaryOperation(); 465 return maybe_unary != NULL && maybe_unary->op() == Token::TYPEOF; 466 } 467 468 469 // Check for the pattern: typeof <expression> equals <string literal>. 470 static bool MatchLiteralCompareTypeof(Expression* left, 471 Token::Value op, 472 Expression* right, 473 Expression** expr, 474 Handle<String>* check) { 475 if (IsTypeof(left) && right->IsStringLiteral() && Token::IsEqualityOp(op)) { 476 *expr = left->AsUnaryOperation()->expression(); 477 *check = Handle<String>::cast(right->AsLiteral()->value()); 478 return true; 479 } 480 return false; 481 } 482 483 484 bool CompareOperation::IsLiteralCompareTypeof(Expression** expr, 485 Handle<String>* check) { 486 return MatchLiteralCompareTypeof(left_, op_, right_, expr, check) || 487 MatchLiteralCompareTypeof(right_, op_, left_, expr, check); 488 } 489 490 491 static bool IsVoidOfLiteral(Expression* expr) { 492 UnaryOperation* maybe_unary = expr->AsUnaryOperation(); 493 return maybe_unary != NULL && 494 maybe_unary->op() == Token::VOID && 495 maybe_unary->expression()->IsLiteral(); 496 } 497 498 499 // Check for the pattern: void <literal> equals <expression> or 500 // undefined equals <expression> 501 static bool MatchLiteralCompareUndefined(Expression* left, 502 Token::Value op, 503 Expression* right, 504 Expression** expr, 505 Isolate* isolate) { 506 if (IsVoidOfLiteral(left) && Token::IsEqualityOp(op)) { 507 *expr = right; 508 return true; 509 } 510 if (left->IsUndefinedLiteral(isolate) && Token::IsEqualityOp(op)) { 511 *expr = right; 512 return true; 513 } 514 return false; 515 } 516 517 518 bool CompareOperation::IsLiteralCompareUndefined( 519 Expression** expr, Isolate* isolate) { 520 return MatchLiteralCompareUndefined(left_, op_, right_, expr, isolate) || 521 MatchLiteralCompareUndefined(right_, op_, left_, expr, isolate); 522 } 523 524 525 // Check for the pattern: null equals <expression> 526 static bool MatchLiteralCompareNull(Expression* left, 527 Token::Value op, 528 Expression* right, 529 Expression** expr) { 530 if (left->IsNullLiteral() && Token::IsEqualityOp(op)) { 531 *expr = right; 532 return true; 533 } 534 return false; 535 } 536 537 538 bool CompareOperation::IsLiteralCompareNull(Expression** expr) { 539 return MatchLiteralCompareNull(left_, op_, right_, expr) || 540 MatchLiteralCompareNull(right_, op_, left_, expr); 541 } 542 543 544 // ---------------------------------------------------------------------------- 545 // Inlining support 546 547 bool Declaration::IsInlineable() const { 548 return proxy()->var()->IsStackAllocated(); 549 } 550 551 bool FunctionDeclaration::IsInlineable() const { 552 return false; 553 } 554 555 556 // ---------------------------------------------------------------------------- 557 // Recording of type feedback 558 559 // TODO(rossberg): all RecordTypeFeedback functions should disappear 560 // once we use the common type field in the AST consistently. 561 562 void Expression::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) { 563 to_boolean_types_ = oracle->ToBooleanTypes(test_id()); 564 } 565 566 567 bool Call::IsUsingCallFeedbackSlot(Isolate* isolate) const { 568 CallType call_type = GetCallType(isolate); 569 return (call_type != POSSIBLY_EVAL_CALL); 570 } 571 572 573 Call::CallType Call::GetCallType(Isolate* isolate) const { 574 VariableProxy* proxy = expression()->AsVariableProxy(); 575 if (proxy != NULL) { 576 if (proxy->var()->is_possibly_eval(isolate)) { 577 return POSSIBLY_EVAL_CALL; 578 } else if (proxy->var()->IsUnallocated()) { 579 return GLOBAL_CALL; 580 } else if (proxy->var()->IsLookupSlot()) { 581 return LOOKUP_SLOT_CALL; 582 } 583 } 584 585 Property* property = expression()->AsProperty(); 586 return property != NULL ? PROPERTY_CALL : OTHER_CALL; 587 } 588 589 590 bool Call::ComputeGlobalTarget(Handle<GlobalObject> global, 591 LookupIterator* it) { 592 target_ = Handle<JSFunction>::null(); 593 cell_ = Handle<Cell>::null(); 594 DCHECK(it->IsFound() && it->GetHolder<JSObject>().is_identical_to(global)); 595 cell_ = it->GetPropertyCell(); 596 if (cell_->value()->IsJSFunction()) { 597 Handle<JSFunction> candidate(JSFunction::cast(cell_->value())); 598 // If the function is in new space we assume it's more likely to 599 // change and thus prefer the general IC code. 600 if (!it->isolate()->heap()->InNewSpace(*candidate)) { 601 target_ = candidate; 602 return true; 603 } 604 } 605 return false; 606 } 607 608 609 void CallNew::RecordTypeFeedback(TypeFeedbackOracle* oracle) { 610 int allocation_site_feedback_slot = FLAG_pretenuring_call_new 611 ? AllocationSiteFeedbackSlot() 612 : CallNewFeedbackSlot(); 613 allocation_site_ = 614 oracle->GetCallNewAllocationSite(allocation_site_feedback_slot); 615 is_monomorphic_ = oracle->CallNewIsMonomorphic(CallNewFeedbackSlot()); 616 if (is_monomorphic_) { 617 target_ = oracle->GetCallNewTarget(CallNewFeedbackSlot()); 618 if (!allocation_site_.is_null()) { 619 elements_kind_ = allocation_site_->GetElementsKind(); 620 } 621 } 622 } 623 624 625 void ObjectLiteral::Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) { 626 TypeFeedbackId id = key()->LiteralFeedbackId(); 627 SmallMapList maps; 628 oracle->CollectReceiverTypes(id, &maps); 629 receiver_type_ = maps.length() == 1 ? maps.at(0) 630 : Handle<Map>::null(); 631 } 632 633 634 // ---------------------------------------------------------------------------- 635 // Implementation of AstVisitor 636 637 void AstVisitor::VisitDeclarations(ZoneList<Declaration*>* declarations) { 638 for (int i = 0; i < declarations->length(); i++) { 639 Visit(declarations->at(i)); 640 } 641 } 642 643 644 void AstVisitor::VisitStatements(ZoneList<Statement*>* statements) { 645 for (int i = 0; i < statements->length(); i++) { 646 Statement* stmt = statements->at(i); 647 Visit(stmt); 648 if (stmt->IsJump()) break; 649 } 650 } 651 652 653 void AstVisitor::VisitExpressions(ZoneList<Expression*>* expressions) { 654 for (int i = 0; i < expressions->length(); i++) { 655 // The variable statement visiting code may pass NULL expressions 656 // to this code. Maybe this should be handled by introducing an 657 // undefined expression or literal? Revisit this code if this 658 // changes 659 Expression* expression = expressions->at(i); 660 if (expression != NULL) Visit(expression); 661 } 662 } 663 664 665 // ---------------------------------------------------------------------------- 666 // Regular expressions 667 668 #define MAKE_ACCEPT(Name) \ 669 void* RegExp##Name::Accept(RegExpVisitor* visitor, void* data) { \ 670 return visitor->Visit##Name(this, data); \ 671 } 672 FOR_EACH_REG_EXP_TREE_TYPE(MAKE_ACCEPT) 673 #undef MAKE_ACCEPT 674 675 #define MAKE_TYPE_CASE(Name) \ 676 RegExp##Name* RegExpTree::As##Name() { \ 677 return NULL; \ 678 } \ 679 bool RegExpTree::Is##Name() { return false; } 680 FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE) 681 #undef MAKE_TYPE_CASE 682 683 #define MAKE_TYPE_CASE(Name) \ 684 RegExp##Name* RegExp##Name::As##Name() { \ 685 return this; \ 686 } \ 687 bool RegExp##Name::Is##Name() { return true; } 688 FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE) 689 #undef MAKE_TYPE_CASE 690 691 692 static Interval ListCaptureRegisters(ZoneList<RegExpTree*>* children) { 693 Interval result = Interval::Empty(); 694 for (int i = 0; i < children->length(); i++) 695 result = result.Union(children->at(i)->CaptureRegisters()); 696 return result; 697 } 698 699 700 Interval RegExpAlternative::CaptureRegisters() { 701 return ListCaptureRegisters(nodes()); 702 } 703 704 705 Interval RegExpDisjunction::CaptureRegisters() { 706 return ListCaptureRegisters(alternatives()); 707 } 708 709 710 Interval RegExpLookahead::CaptureRegisters() { 711 return body()->CaptureRegisters(); 712 } 713 714 715 Interval RegExpCapture::CaptureRegisters() { 716 Interval self(StartRegister(index()), EndRegister(index())); 717 return self.Union(body()->CaptureRegisters()); 718 } 719 720 721 Interval RegExpQuantifier::CaptureRegisters() { 722 return body()->CaptureRegisters(); 723 } 724 725 726 bool RegExpAssertion::IsAnchoredAtStart() { 727 return assertion_type() == RegExpAssertion::START_OF_INPUT; 728 } 729 730 731 bool RegExpAssertion::IsAnchoredAtEnd() { 732 return assertion_type() == RegExpAssertion::END_OF_INPUT; 733 } 734 735 736 bool RegExpAlternative::IsAnchoredAtStart() { 737 ZoneList<RegExpTree*>* nodes = this->nodes(); 738 for (int i = 0; i < nodes->length(); i++) { 739 RegExpTree* node = nodes->at(i); 740 if (node->IsAnchoredAtStart()) { return true; } 741 if (node->max_match() > 0) { return false; } 742 } 743 return false; 744 } 745 746 747 bool RegExpAlternative::IsAnchoredAtEnd() { 748 ZoneList<RegExpTree*>* nodes = this->nodes(); 749 for (int i = nodes->length() - 1; i >= 0; i--) { 750 RegExpTree* node = nodes->at(i); 751 if (node->IsAnchoredAtEnd()) { return true; } 752 if (node->max_match() > 0) { return false; } 753 } 754 return false; 755 } 756 757 758 bool RegExpDisjunction::IsAnchoredAtStart() { 759 ZoneList<RegExpTree*>* alternatives = this->alternatives(); 760 for (int i = 0; i < alternatives->length(); i++) { 761 if (!alternatives->at(i)->IsAnchoredAtStart()) 762 return false; 763 } 764 return true; 765 } 766 767 768 bool RegExpDisjunction::IsAnchoredAtEnd() { 769 ZoneList<RegExpTree*>* alternatives = this->alternatives(); 770 for (int i = 0; i < alternatives->length(); i++) { 771 if (!alternatives->at(i)->IsAnchoredAtEnd()) 772 return false; 773 } 774 return true; 775 } 776 777 778 bool RegExpLookahead::IsAnchoredAtStart() { 779 return is_positive() && body()->IsAnchoredAtStart(); 780 } 781 782 783 bool RegExpCapture::IsAnchoredAtStart() { 784 return body()->IsAnchoredAtStart(); 785 } 786 787 788 bool RegExpCapture::IsAnchoredAtEnd() { 789 return body()->IsAnchoredAtEnd(); 790 } 791 792 793 // Convert regular expression trees to a simple sexp representation. 794 // This representation should be different from the input grammar 795 // in as many cases as possible, to make it more difficult for incorrect 796 // parses to look as correct ones which is likely if the input and 797 // output formats are alike. 798 class RegExpUnparser FINAL : public RegExpVisitor { 799 public: 800 RegExpUnparser(OStream& os, Zone* zone) : os_(os), zone_(zone) {} 801 void VisitCharacterRange(CharacterRange that); 802 #define MAKE_CASE(Name) virtual void* Visit##Name(RegExp##Name*, \ 803 void* data) OVERRIDE; 804 FOR_EACH_REG_EXP_TREE_TYPE(MAKE_CASE) 805 #undef MAKE_CASE 806 private: 807 OStream& os_; 808 Zone* zone_; 809 }; 810 811 812 void* RegExpUnparser::VisitDisjunction(RegExpDisjunction* that, void* data) { 813 os_ << "(|"; 814 for (int i = 0; i < that->alternatives()->length(); i++) { 815 os_ << " "; 816 that->alternatives()->at(i)->Accept(this, data); 817 } 818 os_ << ")"; 819 return NULL; 820 } 821 822 823 void* RegExpUnparser::VisitAlternative(RegExpAlternative* that, void* data) { 824 os_ << "(:"; 825 for (int i = 0; i < that->nodes()->length(); i++) { 826 os_ << " "; 827 that->nodes()->at(i)->Accept(this, data); 828 } 829 os_ << ")"; 830 return NULL; 831 } 832 833 834 void RegExpUnparser::VisitCharacterRange(CharacterRange that) { 835 os_ << AsUC16(that.from()); 836 if (!that.IsSingleton()) { 837 os_ << "-" << AsUC16(that.to()); 838 } 839 } 840 841 842 843 void* RegExpUnparser::VisitCharacterClass(RegExpCharacterClass* that, 844 void* data) { 845 if (that->is_negated()) os_ << "^"; 846 os_ << "["; 847 for (int i = 0; i < that->ranges(zone_)->length(); i++) { 848 if (i > 0) os_ << " "; 849 VisitCharacterRange(that->ranges(zone_)->at(i)); 850 } 851 os_ << "]"; 852 return NULL; 853 } 854 855 856 void* RegExpUnparser::VisitAssertion(RegExpAssertion* that, void* data) { 857 switch (that->assertion_type()) { 858 case RegExpAssertion::START_OF_INPUT: 859 os_ << "@^i"; 860 break; 861 case RegExpAssertion::END_OF_INPUT: 862 os_ << "@$i"; 863 break; 864 case RegExpAssertion::START_OF_LINE: 865 os_ << "@^l"; 866 break; 867 case RegExpAssertion::END_OF_LINE: 868 os_ << "@$l"; 869 break; 870 case RegExpAssertion::BOUNDARY: 871 os_ << "@b"; 872 break; 873 case RegExpAssertion::NON_BOUNDARY: 874 os_ << "@B"; 875 break; 876 } 877 return NULL; 878 } 879 880 881 void* RegExpUnparser::VisitAtom(RegExpAtom* that, void* data) { 882 os_ << "'"; 883 Vector<const uc16> chardata = that->data(); 884 for (int i = 0; i < chardata.length(); i++) { 885 os_ << AsUC16(chardata[i]); 886 } 887 os_ << "'"; 888 return NULL; 889 } 890 891 892 void* RegExpUnparser::VisitText(RegExpText* that, void* data) { 893 if (that->elements()->length() == 1) { 894 that->elements()->at(0).tree()->Accept(this, data); 895 } else { 896 os_ << "(!"; 897 for (int i = 0; i < that->elements()->length(); i++) { 898 os_ << " "; 899 that->elements()->at(i).tree()->Accept(this, data); 900 } 901 os_ << ")"; 902 } 903 return NULL; 904 } 905 906 907 void* RegExpUnparser::VisitQuantifier(RegExpQuantifier* that, void* data) { 908 os_ << "(# " << that->min() << " "; 909 if (that->max() == RegExpTree::kInfinity) { 910 os_ << "- "; 911 } else { 912 os_ << that->max() << " "; 913 } 914 os_ << (that->is_greedy() ? "g " : that->is_possessive() ? "p " : "n "); 915 that->body()->Accept(this, data); 916 os_ << ")"; 917 return NULL; 918 } 919 920 921 void* RegExpUnparser::VisitCapture(RegExpCapture* that, void* data) { 922 os_ << "(^ "; 923 that->body()->Accept(this, data); 924 os_ << ")"; 925 return NULL; 926 } 927 928 929 void* RegExpUnparser::VisitLookahead(RegExpLookahead* that, void* data) { 930 os_ << "(-> " << (that->is_positive() ? "+ " : "- "); 931 that->body()->Accept(this, data); 932 os_ << ")"; 933 return NULL; 934 } 935 936 937 void* RegExpUnparser::VisitBackReference(RegExpBackReference* that, 938 void* data) { 939 os_ << "(<- " << that->index() << ")"; 940 return NULL; 941 } 942 943 944 void* RegExpUnparser::VisitEmpty(RegExpEmpty* that, void* data) { 945 os_ << '%'; 946 return NULL; 947 } 948 949 950 OStream& RegExpTree::Print(OStream& os, Zone* zone) { // NOLINT 951 RegExpUnparser unparser(os, zone); 952 Accept(&unparser, NULL); 953 return os; 954 } 955 956 957 RegExpDisjunction::RegExpDisjunction(ZoneList<RegExpTree*>* alternatives) 958 : alternatives_(alternatives) { 959 DCHECK(alternatives->length() > 1); 960 RegExpTree* first_alternative = alternatives->at(0); 961 min_match_ = first_alternative->min_match(); 962 max_match_ = first_alternative->max_match(); 963 for (int i = 1; i < alternatives->length(); i++) { 964 RegExpTree* alternative = alternatives->at(i); 965 min_match_ = Min(min_match_, alternative->min_match()); 966 max_match_ = Max(max_match_, alternative->max_match()); 967 } 968 } 969 970 971 static int IncreaseBy(int previous, int increase) { 972 if (RegExpTree::kInfinity - previous < increase) { 973 return RegExpTree::kInfinity; 974 } else { 975 return previous + increase; 976 } 977 } 978 979 RegExpAlternative::RegExpAlternative(ZoneList<RegExpTree*>* nodes) 980 : nodes_(nodes) { 981 DCHECK(nodes->length() > 1); 982 min_match_ = 0; 983 max_match_ = 0; 984 for (int i = 0; i < nodes->length(); i++) { 985 RegExpTree* node = nodes->at(i); 986 int node_min_match = node->min_match(); 987 min_match_ = IncreaseBy(min_match_, node_min_match); 988 int node_max_match = node->max_match(); 989 max_match_ = IncreaseBy(max_match_, node_max_match); 990 } 991 } 992 993 994 CaseClause::CaseClause(Zone* zone, Expression* label, 995 ZoneList<Statement*>* statements, int pos, IdGen* id_gen) 996 : Expression(zone, pos, id_gen), 997 label_(label), 998 statements_(statements), 999 compare_type_(Type::None(zone)), 1000 compare_id_(id_gen->GetNextId()), 1001 entry_id_(id_gen->GetNextId()) {} 1002 1003 1004 #define REGULAR_NODE(NodeType) \ 1005 void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \ 1006 increase_node_count(); \ 1007 } 1008 #define REGULAR_NODE_WITH_FEEDBACK_SLOTS(NodeType) \ 1009 void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \ 1010 increase_node_count(); \ 1011 add_slot_node(node); \ 1012 } 1013 #define DONT_OPTIMIZE_NODE(NodeType) \ 1014 void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \ 1015 increase_node_count(); \ 1016 set_dont_crankshaft_reason(k##NodeType); \ 1017 add_flag(kDontSelfOptimize); \ 1018 } 1019 #define DONT_OPTIMIZE_NODE_WITH_FEEDBACK_SLOTS(NodeType) \ 1020 void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \ 1021 increase_node_count(); \ 1022 add_slot_node(node); \ 1023 set_dont_crankshaft_reason(k##NodeType); \ 1024 add_flag(kDontSelfOptimize); \ 1025 } 1026 #define DONT_TURBOFAN_NODE(NodeType) \ 1027 void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \ 1028 increase_node_count(); \ 1029 set_dont_crankshaft_reason(k##NodeType); \ 1030 set_dont_turbofan_reason(k##NodeType); \ 1031 add_flag(kDontSelfOptimize); \ 1032 } 1033 #define DONT_SELFOPTIMIZE_NODE(NodeType) \ 1034 void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \ 1035 increase_node_count(); \ 1036 add_flag(kDontSelfOptimize); \ 1037 } 1038 #define DONT_SELFOPTIMIZE_NODE_WITH_FEEDBACK_SLOTS(NodeType) \ 1039 void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \ 1040 increase_node_count(); \ 1041 add_slot_node(node); \ 1042 add_flag(kDontSelfOptimize); \ 1043 } 1044 #define DONT_CACHE_NODE(NodeType) \ 1045 void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \ 1046 increase_node_count(); \ 1047 set_dont_crankshaft_reason(k##NodeType); \ 1048 add_flag(kDontSelfOptimize); \ 1049 add_flag(kDontCache); \ 1050 } 1051 1052 REGULAR_NODE(VariableDeclaration) 1053 REGULAR_NODE(FunctionDeclaration) 1054 REGULAR_NODE(Block) 1055 REGULAR_NODE(ExpressionStatement) 1056 REGULAR_NODE(EmptyStatement) 1057 REGULAR_NODE(IfStatement) 1058 REGULAR_NODE(ContinueStatement) 1059 REGULAR_NODE(BreakStatement) 1060 REGULAR_NODE(ReturnStatement) 1061 REGULAR_NODE(SwitchStatement) 1062 REGULAR_NODE(CaseClause) 1063 REGULAR_NODE(Conditional) 1064 REGULAR_NODE(Literal) 1065 REGULAR_NODE(ArrayLiteral) 1066 REGULAR_NODE(ObjectLiteral) 1067 REGULAR_NODE(RegExpLiteral) 1068 REGULAR_NODE(FunctionLiteral) 1069 REGULAR_NODE(Assignment) 1070 REGULAR_NODE(Throw) 1071 REGULAR_NODE(UnaryOperation) 1072 REGULAR_NODE(CountOperation) 1073 REGULAR_NODE(BinaryOperation) 1074 REGULAR_NODE(CompareOperation) 1075 REGULAR_NODE(ThisFunction) 1076 1077 REGULAR_NODE_WITH_FEEDBACK_SLOTS(Call) 1078 REGULAR_NODE_WITH_FEEDBACK_SLOTS(CallNew) 1079 REGULAR_NODE_WITH_FEEDBACK_SLOTS(Property) 1080 // In theory, for VariableProxy we'd have to add: 1081 // if (node->var()->IsLookupSlot()) 1082 // set_dont_optimize_reason(kReferenceToAVariableWhichRequiresDynamicLookup); 1083 // But node->var() is usually not bound yet at VariableProxy creation time, and 1084 // LOOKUP variables only result from constructs that cannot be inlined anyway. 1085 REGULAR_NODE_WITH_FEEDBACK_SLOTS(VariableProxy) 1086 1087 // We currently do not optimize any modules. 1088 DONT_OPTIMIZE_NODE(ModuleDeclaration) 1089 DONT_OPTIMIZE_NODE(ImportDeclaration) 1090 DONT_OPTIMIZE_NODE(ExportDeclaration) 1091 DONT_OPTIMIZE_NODE(ModuleVariable) 1092 DONT_OPTIMIZE_NODE(ModulePath) 1093 DONT_OPTIMIZE_NODE(ModuleUrl) 1094 DONT_OPTIMIZE_NODE(ModuleStatement) 1095 DONT_OPTIMIZE_NODE(WithStatement) 1096 DONT_OPTIMIZE_NODE(DebuggerStatement) 1097 DONT_OPTIMIZE_NODE(ClassLiteral) 1098 DONT_OPTIMIZE_NODE(NativeFunctionLiteral) 1099 DONT_OPTIMIZE_NODE(SuperReference) 1100 1101 DONT_OPTIMIZE_NODE_WITH_FEEDBACK_SLOTS(Yield) 1102 1103 // TODO(turbofan): Remove the dont_turbofan_reason once this list is empty. 1104 DONT_TURBOFAN_NODE(ForOfStatement) 1105 DONT_TURBOFAN_NODE(TryCatchStatement) 1106 DONT_TURBOFAN_NODE(TryFinallyStatement) 1107 1108 DONT_SELFOPTIMIZE_NODE(DoWhileStatement) 1109 DONT_SELFOPTIMIZE_NODE(WhileStatement) 1110 DONT_SELFOPTIMIZE_NODE(ForStatement) 1111 1112 DONT_SELFOPTIMIZE_NODE_WITH_FEEDBACK_SLOTS(ForInStatement) 1113 1114 DONT_CACHE_NODE(ModuleLiteral) 1115 1116 1117 void AstConstructionVisitor::VisitCallRuntime(CallRuntime* node) { 1118 increase_node_count(); 1119 add_slot_node(node); 1120 if (node->is_jsruntime()) { 1121 // Don't try to optimize JS runtime calls because we bailout on them. 1122 set_dont_crankshaft_reason(kCallToAJavaScriptRuntimeFunction); 1123 } 1124 } 1125 1126 #undef REGULAR_NODE 1127 #undef DONT_OPTIMIZE_NODE 1128 #undef DONT_SELFOPTIMIZE_NODE 1129 #undef DONT_CACHE_NODE 1130 1131 1132 Handle<String> Literal::ToString() { 1133 if (value_->IsString()) return value_->AsString()->string(); 1134 DCHECK(value_->IsNumber()); 1135 char arr[100]; 1136 Vector<char> buffer(arr, arraysize(arr)); 1137 const char* str; 1138 if (value()->IsSmi()) { 1139 // Optimization only, the heap number case would subsume this. 1140 SNPrintF(buffer, "%d", Smi::cast(*value())->value()); 1141 str = arr; 1142 } else { 1143 str = DoubleToCString(value()->Number(), buffer); 1144 } 1145 return isolate_->factory()->NewStringFromAsciiChecked(str); 1146 } 1147 1148 1149 } } // namespace v8::internal 1150