1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <cmath> // For isfinite.
32 #include "code-stubs.h"
34 #include "conversions.h"
37 #include "property-details.h"
40 #include "string-stream.h"
41 #include "type-info.h"
46 // ----------------------------------------------------------------------------
47 // All the Accept member functions for each syntax tree node type.
49 #define DECL_ACCEPT(type) \
50 void type::Accept(AstVisitor* v) { v->Visit##type(this); }
51 AST_NODE_LIST(DECL_ACCEPT)
55 // ----------------------------------------------------------------------------
56 // Implementation of other node functionality.
59 bool Expression::IsSmiLiteral() const {
60 return AsLiteral() != NULL && AsLiteral()->value()->IsSmi();
64 bool Expression::IsStringLiteral() const {
65 return AsLiteral() != NULL && AsLiteral()->value()->IsString();
69 bool Expression::IsNullLiteral() const {
70 return AsLiteral() != NULL && AsLiteral()->value()->IsNull();
74 bool Expression::IsUndefinedLiteral(Isolate* isolate) const {
75 const VariableProxy* var_proxy = AsVariableProxy();
76 if (var_proxy == NULL) return false;
77 Variable* var = var_proxy->var();
78 // The global identifier "undefined" is immutable. Everything
79 // else could be reassigned.
80 return var != NULL && var->location() == Variable::UNALLOCATED &&
81 var_proxy->name()->Equals(isolate->heap()->undefined_string());
85 VariableProxy::VariableProxy(Zone* zone, Variable* var, int position)
86 : Expression(zone, position),
88 var_(NULL), // Will be set by the call to BindTo.
89 is_this_(var->is_this()),
92 interface_(var->interface()) {
97 VariableProxy::VariableProxy(Zone* zone,
100 Interface* interface,
102 : Expression(zone, position),
108 interface_(interface) {
109 // Names must be canonicalized for fast equality checks.
110 ASSERT(name->IsInternalizedString());
114 void VariableProxy::BindTo(Variable* var) {
115 ASSERT(var_ == NULL); // must be bound only once
116 ASSERT(var != NULL); // must bind
117 ASSERT(!FLAG_harmony_modules || interface_->IsUnified(var->interface()));
118 ASSERT((is_this() && var->is_this()) || name_.is_identical_to(var->name()));
119 // Ideally CONST-ness should match. However, this is very hard to achieve
120 // because we don't know the exact semantics of conflicting (const and
121 // non-const) multiple variable declarations, const vars introduced via
122 // eval() etc. Const-ness and variable declarations are a complete mess
125 var->set_is_used(true);
129 Assignment::Assignment(Zone* zone,
134 : Expression(zone, pos),
138 binary_operation_(NULL),
139 assignment_id_(GetNextId(zone)),
140 is_uninitialized_(false),
141 store_mode_(STANDARD_STORE) { }
144 Token::Value Assignment::binary_op() const {
146 case Token::ASSIGN_BIT_OR: return Token::BIT_OR;
147 case Token::ASSIGN_BIT_XOR: return Token::BIT_XOR;
148 case Token::ASSIGN_BIT_AND: return Token::BIT_AND;
149 case Token::ASSIGN_SHL: return Token::SHL;
150 case Token::ASSIGN_SAR: return Token::SAR;
151 case Token::ASSIGN_SHR: return Token::SHR;
152 case Token::ASSIGN_ADD: return Token::ADD;
153 case Token::ASSIGN_SUB: return Token::SUB;
154 case Token::ASSIGN_MUL: return Token::MUL;
155 case Token::ASSIGN_DIV: return Token::DIV;
156 case Token::ASSIGN_MOD: return Token::MOD;
157 default: UNREACHABLE();
159 return Token::ILLEGAL;
163 bool FunctionLiteral::AllowsLazyCompilation() {
164 return scope()->AllowsLazyCompilation();
168 bool FunctionLiteral::AllowsLazyCompilationWithoutContext() {
169 return scope()->AllowsLazyCompilationWithoutContext();
173 int FunctionLiteral::start_position() const {
174 return scope()->start_position();
178 int FunctionLiteral::end_position() const {
179 return scope()->end_position();
183 StrictMode FunctionLiteral::strict_mode() const {
184 return scope()->strict_mode();
188 void FunctionLiteral::InitializeSharedInfo(
189 Handle<Code> unoptimized_code) {
190 for (RelocIterator it(*unoptimized_code); !it.done(); it.next()) {
191 RelocInfo* rinfo = it.rinfo();
192 if (rinfo->rmode() != RelocInfo::EMBEDDED_OBJECT) continue;
193 Object* obj = rinfo->target_object();
194 if (obj->IsSharedFunctionInfo()) {
195 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
196 if (shared->start_position() == start_position()) {
197 shared_info_ = Handle<SharedFunctionInfo>(shared);
205 ObjectLiteralProperty::ObjectLiteralProperty(
206 Zone* zone, Literal* key, Expression* value) {
210 Object* k = *key->value();
211 if (k->IsInternalizedString() &&
212 zone->isolate()->heap()->proto_string()->Equals(String::cast(k))) {
214 } else if (value_->AsMaterializedLiteral() != NULL) {
215 kind_ = MATERIALIZED_LITERAL;
216 } else if (value_->AsLiteral() != NULL) {
224 ObjectLiteralProperty::ObjectLiteralProperty(
225 Zone* zone, bool is_getter, FunctionLiteral* value) {
228 kind_ = is_getter ? GETTER : SETTER;
232 bool ObjectLiteral::Property::IsCompileTimeValue() {
233 return kind_ == CONSTANT ||
234 (kind_ == MATERIALIZED_LITERAL &&
235 CompileTimeValue::IsCompileTimeValue(value_));
239 void ObjectLiteral::Property::set_emit_store(bool emit_store) {
240 emit_store_ = emit_store;
244 bool ObjectLiteral::Property::emit_store() {
249 void ObjectLiteral::CalculateEmitStore(Zone* zone) {
250 ZoneAllocationPolicy allocator(zone);
252 ZoneHashMap table(Literal::Match, ZoneHashMap::kDefaultHashMapCapacity,
254 for (int i = properties()->length() - 1; i >= 0; i--) {
255 ObjectLiteral::Property* property = properties()->at(i);
256 Literal* literal = property->key();
257 if (literal->value()->IsNull()) continue;
258 uint32_t hash = literal->Hash();
259 // If the key of a computed property is in the table, do not emit
260 // a store for the property later.
261 if ((property->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL ||
262 property->kind() == ObjectLiteral::Property::COMPUTED) &&
263 table.Lookup(literal, hash, false, allocator) != NULL) {
264 property->set_emit_store(false);
266 // Add key to the table.
267 table.Lookup(literal, hash, true, allocator);
273 bool ObjectLiteral::IsBoilerplateProperty(ObjectLiteral::Property* property) {
274 return property != NULL &&
275 property->kind() != ObjectLiteral::Property::PROTOTYPE;
279 void ObjectLiteral::BuildConstantProperties(Isolate* isolate) {
280 if (!constant_properties_.is_null()) return;
282 // Allocate a fixed array to hold all the constant properties.
283 Handle<FixedArray> constant_properties = isolate->factory()->NewFixedArray(
284 boilerplate_properties_ * 2, TENURED);
287 // Accumulate the value in local variables and store it at the end.
288 bool is_simple = true;
290 uint32_t max_element_index = 0;
291 uint32_t elements = 0;
292 for (int i = 0; i < properties()->length(); i++) {
293 ObjectLiteral::Property* property = properties()->at(i);
294 if (!IsBoilerplateProperty(property)) {
298 MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral();
299 if (m_literal != NULL) {
300 m_literal->BuildConstants(isolate);
301 if (m_literal->depth() >= depth_acc) depth_acc = m_literal->depth() + 1;
304 // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined
305 // value for COMPUTED properties, the real value is filled in at
306 // runtime. The enumeration order is maintained.
307 Handle<Object> key = property->key()->value();
308 Handle<Object> value = GetBoilerplateValue(property->value(), isolate);
310 // Ensure objects that may, at any point in time, contain fields with double
311 // representation are always treated as nested objects. This is true for
312 // computed fields (value is undefined), and smi and double literals
313 // (value->IsNumber()).
314 // TODO(verwaest): Remove once we can store them inline.
315 if (FLAG_track_double_fields &&
316 (value->IsNumber() || value->IsUninitialized())) {
317 may_store_doubles_ = true;
320 is_simple = is_simple && !value->IsUninitialized();
322 // Keep track of the number of elements in the object literal and
323 // the largest element index. If the largest element index is
324 // much larger than the number of elements, creating an object
325 // literal with fast elements will be a waste of space.
326 uint32_t element_index = 0;
328 && Handle<String>::cast(key)->AsArrayIndex(&element_index)
329 && element_index > max_element_index) {
330 max_element_index = element_index;
332 } else if (key->IsSmi()) {
333 int key_value = Smi::cast(*key)->value();
335 && static_cast<uint32_t>(key_value) > max_element_index) {
336 max_element_index = key_value;
341 // Add name, value pair to the fixed array.
342 constant_properties->set(position++, *key);
343 constant_properties->set(position++, *value);
346 constant_properties_ = constant_properties;
348 (max_element_index <= 32) || ((2 * elements) >= max_element_index);
349 set_is_simple(is_simple);
350 set_depth(depth_acc);
354 void ArrayLiteral::BuildConstantElements(Isolate* isolate) {
355 if (!constant_elements_.is_null()) return;
357 // Allocate a fixed array to hold all the object literals.
358 Handle<JSArray> array =
359 isolate->factory()->NewJSArray(0, FAST_HOLEY_SMI_ELEMENTS);
360 JSArray::Expand(array, values()->length());
362 // Fill in the literals.
363 bool is_simple = true;
365 bool is_holey = false;
366 for (int i = 0, n = values()->length(); i < n; i++) {
367 Expression* element = values()->at(i);
368 MaterializedLiteral* m_literal = element->AsMaterializedLiteral();
369 if (m_literal != NULL) {
370 m_literal->BuildConstants(isolate);
371 if (m_literal->depth() + 1 > depth_acc) {
372 depth_acc = m_literal->depth() + 1;
375 Handle<Object> boilerplate_value = GetBoilerplateValue(element, isolate);
376 if (boilerplate_value->IsTheHole()) {
378 } else if (boilerplate_value->IsUninitialized()) {
380 JSObject::SetOwnElement(
381 array, i, handle(Smi::FromInt(0), isolate), SLOPPY);
383 JSObject::SetOwnElement(array, i, boilerplate_value, SLOPPY);
387 Handle<FixedArrayBase> element_values(array->elements());
389 // Simple and shallow arrays can be lazily copied, we transform the
390 // elements array to a copy-on-write array.
391 if (is_simple && depth_acc == 1 && values()->length() > 0 &&
392 array->HasFastSmiOrObjectElements()) {
393 element_values->set_map(isolate->heap()->fixed_cow_array_map());
396 // Remember both the literal's constant values as well as the ElementsKind
397 // in a 2-element FixedArray.
398 Handle<FixedArray> literals = isolate->factory()->NewFixedArray(2, TENURED);
400 ElementsKind kind = array->GetElementsKind();
401 kind = is_holey ? GetHoleyElementsKind(kind) : GetPackedElementsKind(kind);
403 literals->set(0, Smi::FromInt(kind));
404 literals->set(1, *element_values);
406 constant_elements_ = literals;
407 set_is_simple(is_simple);
408 set_depth(depth_acc);
412 Handle<Object> MaterializedLiteral::GetBoilerplateValue(Expression* expression,
414 if (expression->AsLiteral() != NULL) {
415 return expression->AsLiteral()->value();
417 if (CompileTimeValue::IsCompileTimeValue(expression)) {
418 return CompileTimeValue::GetValue(isolate, expression);
420 return isolate->factory()->uninitialized_value();
424 void MaterializedLiteral::BuildConstants(Isolate* isolate) {
425 if (IsArrayLiteral()) {
426 return AsArrayLiteral()->BuildConstantElements(isolate);
428 if (IsObjectLiteral()) {
429 return AsObjectLiteral()->BuildConstantProperties(isolate);
431 ASSERT(IsRegExpLiteral());
432 ASSERT(depth() >= 1); // Depth should be initialized.
436 void TargetCollector::AddTarget(Label* target, Zone* zone) {
437 // Add the label to the collector, but discard duplicates.
438 int length = targets_.length();
439 for (int i = 0; i < length; i++) {
440 if (targets_[i] == target) return;
442 targets_.Add(target, zone);
446 void UnaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
447 // TODO(olivf) If this Operation is used in a test context, then the
448 // expression has a ToBoolean stub and we want to collect the type
449 // information. However the GraphBuilder expects it to be on the instruction
450 // corresponding to the TestContext, therefore we have to store it here and
451 // not on the operand.
452 set_to_boolean_types(oracle->ToBooleanTypes(expression()->test_id()));
456 void BinaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
457 // TODO(olivf) If this Operation is used in a test context, then the right
458 // hand side has a ToBoolean stub and we want to collect the type information.
459 // However the GraphBuilder expects it to be on the instruction corresponding
460 // to the TestContext, therefore we have to store it here and not on the
461 // right hand operand.
462 set_to_boolean_types(oracle->ToBooleanTypes(right()->test_id()));
466 bool BinaryOperation::ResultOverwriteAllowed() const {
491 static bool IsTypeof(Expression* expr) {
492 UnaryOperation* maybe_unary = expr->AsUnaryOperation();
493 return maybe_unary != NULL && maybe_unary->op() == Token::TYPEOF;
497 // Check for the pattern: typeof <expression> equals <string literal>.
498 static bool MatchLiteralCompareTypeof(Expression* left,
502 Handle<String>* check) {
503 if (IsTypeof(left) && right->IsStringLiteral() && Token::IsEqualityOp(op)) {
504 *expr = left->AsUnaryOperation()->expression();
505 *check = Handle<String>::cast(right->AsLiteral()->value());
512 bool CompareOperation::IsLiteralCompareTypeof(Expression** expr,
513 Handle<String>* check) {
514 return MatchLiteralCompareTypeof(left_, op_, right_, expr, check) ||
515 MatchLiteralCompareTypeof(right_, op_, left_, expr, check);
519 static bool IsVoidOfLiteral(Expression* expr) {
520 UnaryOperation* maybe_unary = expr->AsUnaryOperation();
521 return maybe_unary != NULL &&
522 maybe_unary->op() == Token::VOID &&
523 maybe_unary->expression()->AsLiteral() != NULL;
527 // Check for the pattern: void <literal> equals <expression> or
528 // undefined equals <expression>
529 static bool MatchLiteralCompareUndefined(Expression* left,
534 if (IsVoidOfLiteral(left) && Token::IsEqualityOp(op)) {
538 if (left->IsUndefinedLiteral(isolate) && Token::IsEqualityOp(op)) {
546 bool CompareOperation::IsLiteralCompareUndefined(
547 Expression** expr, Isolate* isolate) {
548 return MatchLiteralCompareUndefined(left_, op_, right_, expr, isolate) ||
549 MatchLiteralCompareUndefined(right_, op_, left_, expr, isolate);
553 // Check for the pattern: null equals <expression>
554 static bool MatchLiteralCompareNull(Expression* left,
558 if (left->IsNullLiteral() && Token::IsEqualityOp(op)) {
566 bool CompareOperation::IsLiteralCompareNull(Expression** expr) {
567 return MatchLiteralCompareNull(left_, op_, right_, expr) ||
568 MatchLiteralCompareNull(right_, op_, left_, expr);
572 // ----------------------------------------------------------------------------
575 bool Declaration::IsInlineable() const {
576 return proxy()->var()->IsStackAllocated();
579 bool FunctionDeclaration::IsInlineable() const {
584 // ----------------------------------------------------------------------------
585 // Recording of type feedback
587 // TODO(rossberg): all RecordTypeFeedback functions should disappear
588 // once we use the common type field in the AST consistently.
590 void Expression::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
591 to_boolean_types_ = oracle->ToBooleanTypes(test_id());
595 int Call::ComputeFeedbackSlotCount(Isolate* isolate) {
596 CallType call_type = GetCallType(isolate);
597 if (call_type == LOOKUP_SLOT_CALL || call_type == OTHER_CALL) {
598 // Call only uses a slot in some cases.
606 Call::CallType Call::GetCallType(Isolate* isolate) const {
607 VariableProxy* proxy = expression()->AsVariableProxy();
609 if (proxy->var()->is_possibly_eval(isolate)) {
610 return POSSIBLY_EVAL_CALL;
611 } else if (proxy->var()->IsUnallocated()) {
613 } else if (proxy->var()->IsLookupSlot()) {
614 return LOOKUP_SLOT_CALL;
618 Property* property = expression()->AsProperty();
619 return property != NULL ? PROPERTY_CALL : OTHER_CALL;
623 bool Call::ComputeGlobalTarget(Handle<GlobalObject> global,
624 LookupResult* lookup) {
625 target_ = Handle<JSFunction>::null();
626 cell_ = Handle<Cell>::null();
627 ASSERT(lookup->IsFound() &&
628 lookup->type() == NORMAL &&
629 lookup->holder() == *global);
630 cell_ = Handle<Cell>(global->GetPropertyCell(lookup));
631 if (cell_->value()->IsJSFunction()) {
632 Handle<JSFunction> candidate(JSFunction::cast(cell_->value()));
633 // If the function is in new space we assume it's more likely to
634 // change and thus prefer the general IC code.
635 if (!lookup->isolate()->heap()->InNewSpace(*candidate)) {
644 void CallNew::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
645 int allocation_site_feedback_slot = FLAG_pretenuring_call_new
646 ? AllocationSiteFeedbackSlot()
647 : CallNewFeedbackSlot();
649 oracle->GetCallNewAllocationSite(allocation_site_feedback_slot);
650 is_monomorphic_ = oracle->CallNewIsMonomorphic(CallNewFeedbackSlot());
651 if (is_monomorphic_) {
652 target_ = oracle->GetCallNewTarget(CallNewFeedbackSlot());
653 if (!allocation_site_.is_null()) {
654 elements_kind_ = allocation_site_->GetElementsKind();
660 void ObjectLiteral::Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
661 TypeFeedbackId id = key()->LiteralFeedbackId();
663 oracle->CollectReceiverTypes(id, &maps);
664 receiver_type_ = maps.length() == 1 ? maps.at(0)
665 : Handle<Map>::null();
669 // ----------------------------------------------------------------------------
670 // Implementation of AstVisitor
672 void AstVisitor::VisitDeclarations(ZoneList<Declaration*>* declarations) {
673 for (int i = 0; i < declarations->length(); i++) {
674 Visit(declarations->at(i));
679 void AstVisitor::VisitStatements(ZoneList<Statement*>* statements) {
680 for (int i = 0; i < statements->length(); i++) {
681 Statement* stmt = statements->at(i);
683 if (stmt->IsJump()) break;
688 void AstVisitor::VisitExpressions(ZoneList<Expression*>* expressions) {
689 for (int i = 0; i < expressions->length(); i++) {
690 // The variable statement visiting code may pass NULL expressions
691 // to this code. Maybe this should be handled by introducing an
692 // undefined expression or literal? Revisit this code if this
694 Expression* expression = expressions->at(i);
695 if (expression != NULL) Visit(expression);
700 // ----------------------------------------------------------------------------
701 // Regular expressions
703 #define MAKE_ACCEPT(Name) \
704 void* RegExp##Name::Accept(RegExpVisitor* visitor, void* data) { \
705 return visitor->Visit##Name(this, data); \
707 FOR_EACH_REG_EXP_TREE_TYPE(MAKE_ACCEPT)
710 #define MAKE_TYPE_CASE(Name) \
711 RegExp##Name* RegExpTree::As##Name() { \
714 bool RegExpTree::Is##Name() { return false; }
715 FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE)
716 #undef MAKE_TYPE_CASE
718 #define MAKE_TYPE_CASE(Name) \
719 RegExp##Name* RegExp##Name::As##Name() { \
722 bool RegExp##Name::Is##Name() { return true; }
723 FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE)
724 #undef MAKE_TYPE_CASE
727 static Interval ListCaptureRegisters(ZoneList<RegExpTree*>* children) {
728 Interval result = Interval::Empty();
729 for (int i = 0; i < children->length(); i++)
730 result = result.Union(children->at(i)->CaptureRegisters());
735 Interval RegExpAlternative::CaptureRegisters() {
736 return ListCaptureRegisters(nodes());
740 Interval RegExpDisjunction::CaptureRegisters() {
741 return ListCaptureRegisters(alternatives());
745 Interval RegExpLookahead::CaptureRegisters() {
746 return body()->CaptureRegisters();
750 Interval RegExpCapture::CaptureRegisters() {
751 Interval self(StartRegister(index()), EndRegister(index()));
752 return self.Union(body()->CaptureRegisters());
756 Interval RegExpQuantifier::CaptureRegisters() {
757 return body()->CaptureRegisters();
761 bool RegExpAssertion::IsAnchoredAtStart() {
762 return assertion_type() == RegExpAssertion::START_OF_INPUT;
766 bool RegExpAssertion::IsAnchoredAtEnd() {
767 return assertion_type() == RegExpAssertion::END_OF_INPUT;
771 bool RegExpAlternative::IsAnchoredAtStart() {
772 ZoneList<RegExpTree*>* nodes = this->nodes();
773 for (int i = 0; i < nodes->length(); i++) {
774 RegExpTree* node = nodes->at(i);
775 if (node->IsAnchoredAtStart()) { return true; }
776 if (node->max_match() > 0) { return false; }
782 bool RegExpAlternative::IsAnchoredAtEnd() {
783 ZoneList<RegExpTree*>* nodes = this->nodes();
784 for (int i = nodes->length() - 1; i >= 0; i--) {
785 RegExpTree* node = nodes->at(i);
786 if (node->IsAnchoredAtEnd()) { return true; }
787 if (node->max_match() > 0) { return false; }
793 bool RegExpDisjunction::IsAnchoredAtStart() {
794 ZoneList<RegExpTree*>* alternatives = this->alternatives();
795 for (int i = 0; i < alternatives->length(); i++) {
796 if (!alternatives->at(i)->IsAnchoredAtStart())
803 bool RegExpDisjunction::IsAnchoredAtEnd() {
804 ZoneList<RegExpTree*>* alternatives = this->alternatives();
805 for (int i = 0; i < alternatives->length(); i++) {
806 if (!alternatives->at(i)->IsAnchoredAtEnd())
813 bool RegExpLookahead::IsAnchoredAtStart() {
814 return is_positive() && body()->IsAnchoredAtStart();
818 bool RegExpCapture::IsAnchoredAtStart() {
819 return body()->IsAnchoredAtStart();
823 bool RegExpCapture::IsAnchoredAtEnd() {
824 return body()->IsAnchoredAtEnd();
828 // Convert regular expression trees to a simple sexp representation.
829 // This representation should be different from the input grammar
830 // in as many cases as possible, to make it more difficult for incorrect
831 // parses to look as correct ones which is likely if the input and
832 // output formats are alike.
833 class RegExpUnparser V8_FINAL : public RegExpVisitor {
835 explicit RegExpUnparser(Zone* zone);
836 void VisitCharacterRange(CharacterRange that);
837 SmartArrayPointer<const char> ToString() { return stream_.ToCString(); }
838 #define MAKE_CASE(Name) virtual void* Visit##Name(RegExp##Name*, \
839 void* data) V8_OVERRIDE;
840 FOR_EACH_REG_EXP_TREE_TYPE(MAKE_CASE)
843 StringStream* stream() { return &stream_; }
844 HeapStringAllocator alloc_;
845 StringStream stream_;
850 RegExpUnparser::RegExpUnparser(Zone* zone) : stream_(&alloc_), zone_(zone) {
854 void* RegExpUnparser::VisitDisjunction(RegExpDisjunction* that, void* data) {
856 for (int i = 0; i < that->alternatives()->length(); i++) {
858 that->alternatives()->at(i)->Accept(this, data);
865 void* RegExpUnparser::VisitAlternative(RegExpAlternative* that, void* data) {
867 for (int i = 0; i < that->nodes()->length(); i++) {
869 that->nodes()->at(i)->Accept(this, data);
876 void RegExpUnparser::VisitCharacterRange(CharacterRange that) {
877 stream()->Add("%k", that.from());
878 if (!that.IsSingleton()) {
879 stream()->Add("-%k", that.to());
885 void* RegExpUnparser::VisitCharacterClass(RegExpCharacterClass* that,
887 if (that->is_negated())
890 for (int i = 0; i < that->ranges(zone_)->length(); i++) {
891 if (i > 0) stream()->Add(" ");
892 VisitCharacterRange(that->ranges(zone_)->at(i));
899 void* RegExpUnparser::VisitAssertion(RegExpAssertion* that, void* data) {
900 switch (that->assertion_type()) {
901 case RegExpAssertion::START_OF_INPUT:
902 stream()->Add("@^i");
904 case RegExpAssertion::END_OF_INPUT:
905 stream()->Add("@$i");
907 case RegExpAssertion::START_OF_LINE:
908 stream()->Add("@^l");
910 case RegExpAssertion::END_OF_LINE:
911 stream()->Add("@$l");
913 case RegExpAssertion::BOUNDARY:
916 case RegExpAssertion::NON_BOUNDARY:
924 void* RegExpUnparser::VisitAtom(RegExpAtom* that, void* data) {
926 Vector<const uc16> chardata = that->data();
927 for (int i = 0; i < chardata.length(); i++) {
928 stream()->Add("%k", chardata[i]);
935 void* RegExpUnparser::VisitText(RegExpText* that, void* data) {
936 if (that->elements()->length() == 1) {
937 that->elements()->at(0).tree()->Accept(this, data);
940 for (int i = 0; i < that->elements()->length(); i++) {
942 that->elements()->at(i).tree()->Accept(this, data);
950 void* RegExpUnparser::VisitQuantifier(RegExpQuantifier* that, void* data) {
951 stream()->Add("(# %i ", that->min());
952 if (that->max() == RegExpTree::kInfinity) {
955 stream()->Add("%i ", that->max());
957 stream()->Add(that->is_greedy() ? "g " : that->is_possessive() ? "p " : "n ");
958 that->body()->Accept(this, data);
964 void* RegExpUnparser::VisitCapture(RegExpCapture* that, void* data) {
965 stream()->Add("(^ ");
966 that->body()->Accept(this, data);
972 void* RegExpUnparser::VisitLookahead(RegExpLookahead* that, void* data) {
973 stream()->Add("(-> ");
974 stream()->Add(that->is_positive() ? "+ " : "- ");
975 that->body()->Accept(this, data);
981 void* RegExpUnparser::VisitBackReference(RegExpBackReference* that,
983 stream()->Add("(<- %i)", that->index());
988 void* RegExpUnparser::VisitEmpty(RegExpEmpty* that, void* data) {
994 SmartArrayPointer<const char> RegExpTree::ToString(Zone* zone) {
995 RegExpUnparser unparser(zone);
996 Accept(&unparser, NULL);
997 return unparser.ToString();
1001 RegExpDisjunction::RegExpDisjunction(ZoneList<RegExpTree*>* alternatives)
1002 : alternatives_(alternatives) {
1003 ASSERT(alternatives->length() > 1);
1004 RegExpTree* first_alternative = alternatives->at(0);
1005 min_match_ = first_alternative->min_match();
1006 max_match_ = first_alternative->max_match();
1007 for (int i = 1; i < alternatives->length(); i++) {
1008 RegExpTree* alternative = alternatives->at(i);
1009 min_match_ = Min(min_match_, alternative->min_match());
1010 max_match_ = Max(max_match_, alternative->max_match());
1015 static int IncreaseBy(int previous, int increase) {
1016 if (RegExpTree::kInfinity - previous < increase) {
1017 return RegExpTree::kInfinity;
1019 return previous + increase;
1023 RegExpAlternative::RegExpAlternative(ZoneList<RegExpTree*>* nodes)
1025 ASSERT(nodes->length() > 1);
1028 for (int i = 0; i < nodes->length(); i++) {
1029 RegExpTree* node = nodes->at(i);
1030 int node_min_match = node->min_match();
1031 min_match_ = IncreaseBy(min_match_, node_min_match);
1032 int node_max_match = node->max_match();
1033 max_match_ = IncreaseBy(max_match_, node_max_match);
1038 CaseClause::CaseClause(Zone* zone,
1040 ZoneList<Statement*>* statements,
1042 : Expression(zone, pos),
1044 statements_(statements),
1045 compare_type_(Type::None(zone)),
1046 compare_id_(AstNode::GetNextId(zone)),
1047 entry_id_(AstNode::GetNextId(zone)) {
1051 #define REGULAR_NODE(NodeType) \
1052 void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
1053 increase_node_count(); \
1055 #define REGULAR_NODE_WITH_FEEDBACK_SLOTS(NodeType) \
1056 void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
1057 increase_node_count(); \
1058 add_slot_node(node); \
1060 #define DONT_OPTIMIZE_NODE(NodeType) \
1061 void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
1062 increase_node_count(); \
1063 set_dont_optimize_reason(k##NodeType); \
1064 add_flag(kDontInline); \
1065 add_flag(kDontSelfOptimize); \
1067 #define DONT_SELFOPTIMIZE_NODE(NodeType) \
1068 void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
1069 increase_node_count(); \
1070 add_flag(kDontSelfOptimize); \
1072 #define DONT_SELFOPTIMIZE_NODE_WITH_FEEDBACK_SLOTS(NodeType) \
1073 void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
1074 increase_node_count(); \
1075 add_slot_node(node); \
1076 add_flag(kDontSelfOptimize); \
1078 #define DONT_CACHE_NODE(NodeType) \
1079 void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
1080 increase_node_count(); \
1081 set_dont_optimize_reason(k##NodeType); \
1082 add_flag(kDontInline); \
1083 add_flag(kDontSelfOptimize); \
1084 add_flag(kDontCache); \
1087 REGULAR_NODE(VariableDeclaration)
1088 REGULAR_NODE(FunctionDeclaration)
1090 REGULAR_NODE(ExpressionStatement)
1091 REGULAR_NODE(EmptyStatement)
1092 REGULAR_NODE(IfStatement)
1093 REGULAR_NODE(ContinueStatement)
1094 REGULAR_NODE(BreakStatement)
1095 REGULAR_NODE(ReturnStatement)
1096 REGULAR_NODE(SwitchStatement)
1097 REGULAR_NODE(CaseClause)
1098 REGULAR_NODE(Conditional)
1099 REGULAR_NODE(Literal)
1100 REGULAR_NODE(ArrayLiteral)
1101 REGULAR_NODE(ObjectLiteral)
1102 REGULAR_NODE(RegExpLiteral)
1103 REGULAR_NODE(FunctionLiteral)
1104 REGULAR_NODE(Assignment)
1106 REGULAR_NODE(Property)
1107 REGULAR_NODE(UnaryOperation)
1108 REGULAR_NODE(CountOperation)
1109 REGULAR_NODE(BinaryOperation)
1110 REGULAR_NODE(CompareOperation)
1111 REGULAR_NODE(ThisFunction)
1112 REGULAR_NODE_WITH_FEEDBACK_SLOTS(Call)
1113 REGULAR_NODE_WITH_FEEDBACK_SLOTS(CallNew)
1114 // In theory, for VariableProxy we'd have to add:
1115 // if (node->var()->IsLookupSlot()) add_flag(kDontInline);
1116 // But node->var() is usually not bound yet at VariableProxy creation time, and
1117 // LOOKUP variables only result from constructs that cannot be inlined anyway.
1118 REGULAR_NODE(VariableProxy)
1120 // We currently do not optimize any modules.
1121 DONT_OPTIMIZE_NODE(ModuleDeclaration)
1122 DONT_OPTIMIZE_NODE(ImportDeclaration)
1123 DONT_OPTIMIZE_NODE(ExportDeclaration)
1124 DONT_OPTIMIZE_NODE(ModuleVariable)
1125 DONT_OPTIMIZE_NODE(ModulePath)
1126 DONT_OPTIMIZE_NODE(ModuleUrl)
1127 DONT_OPTIMIZE_NODE(ModuleStatement)
1128 DONT_OPTIMIZE_NODE(Yield)
1129 DONT_OPTIMIZE_NODE(WithStatement)
1130 DONT_OPTIMIZE_NODE(TryCatchStatement)
1131 DONT_OPTIMIZE_NODE(TryFinallyStatement)
1132 DONT_OPTIMIZE_NODE(DebuggerStatement)
1133 DONT_OPTIMIZE_NODE(NativeFunctionLiteral)
1135 DONT_SELFOPTIMIZE_NODE(DoWhileStatement)
1136 DONT_SELFOPTIMIZE_NODE(WhileStatement)
1137 DONT_SELFOPTIMIZE_NODE(ForStatement)
1138 DONT_SELFOPTIMIZE_NODE_WITH_FEEDBACK_SLOTS(ForInStatement)
1139 DONT_SELFOPTIMIZE_NODE(ForOfStatement)
1141 DONT_CACHE_NODE(ModuleLiteral)
1144 void AstConstructionVisitor::VisitCallRuntime(CallRuntime* node) {
1145 increase_node_count();
1146 if (node->is_jsruntime()) {
1147 // Don't try to inline JS runtime calls because we don't (currently) even
1149 add_flag(kDontInline);
1150 } else if (node->function()->intrinsic_type == Runtime::INLINE &&
1151 (node->name()->IsOneByteEqualTo(
1152 STATIC_ASCII_VECTOR("_ArgumentsLength")) ||
1153 node->name()->IsOneByteEqualTo(STATIC_ASCII_VECTOR("_Arguments")))) {
1154 // Don't inline the %_ArgumentsLength or %_Arguments because their
1155 // implementation will not work. There is no stack frame to get them
1157 add_flag(kDontInline);
1162 #undef DONT_OPTIMIZE_NODE
1163 #undef DONT_SELFOPTIMIZE_NODE
1164 #undef DONT_CACHE_NODE
1167 Handle<String> Literal::ToString() {
1168 if (value_->IsString()) return Handle<String>::cast(value_);
1169 ASSERT(value_->IsNumber());
1171 Vector<char> buffer(arr, ARRAY_SIZE(arr));
1173 if (value_->IsSmi()) {
1174 // Optimization only, the heap number case would subsume this.
1175 OS::SNPrintF(buffer, "%d", Smi::cast(*value_)->value());
1178 str = DoubleToCString(value_->Number(), buffer);
1180 return isolate_->factory()->NewStringFromAscii(CStrVector(str));
1184 } } // namespace v8::internal