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
4 // met:
5 //
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.
15 //
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.
27
28 #include "ast.h"
29
30 #include <math.h> // For isfinite.
31 #include "builtins.h"
32 #include "conversions.h"
33 #include "hashmap.h"
34 #include "parser.h"
35 #include "property-details.h"
36 #include "property.h"
37 #include "scopes.h"
38 #include "string-stream.h"
39 #include "type-info.h"
40
41 namespace v8 {
42 namespace internal {
43
44 // ----------------------------------------------------------------------------
45 // All the Accept member functions for each syntax tree node type.
46
47 #define DECL_ACCEPT(type) \
48 void type::Accept(AstVisitor* v) { v->Visit##type(this); }
AST_NODE_LIST(DECL_ACCEPT)49 AST_NODE_LIST(DECL_ACCEPT)
50 #undef DECL_ACCEPT
51
52
53 // ----------------------------------------------------------------------------
54 // Implementation of other node functionality.
55
56
57 bool Expression::IsSmiLiteral() {
58 return AsLiteral() != NULL && AsLiteral()->handle()->IsSmi();
59 }
60
61
IsStringLiteral()62 bool Expression::IsStringLiteral() {
63 return AsLiteral() != NULL && AsLiteral()->handle()->IsString();
64 }
65
66
IsNullLiteral()67 bool Expression::IsNullLiteral() {
68 return AsLiteral() != NULL && AsLiteral()->handle()->IsNull();
69 }
70
71
VariableProxy(Isolate * isolate,Variable * var)72 VariableProxy::VariableProxy(Isolate* isolate, Variable* var)
73 : Expression(isolate),
74 name_(var->name()),
75 var_(NULL), // Will be set by the call to BindTo.
76 is_this_(var->is_this()),
77 is_trivial_(false),
78 is_lvalue_(false),
79 position_(RelocInfo::kNoPosition),
80 interface_(var->interface()) {
81 BindTo(var);
82 }
83
84
VariableProxy(Isolate * isolate,Handle<String> name,bool is_this,int position,Interface * interface)85 VariableProxy::VariableProxy(Isolate* isolate,
86 Handle<String> name,
87 bool is_this,
88 int position,
89 Interface* interface)
90 : Expression(isolate),
91 name_(name),
92 var_(NULL),
93 is_this_(is_this),
94 is_trivial_(false),
95 is_lvalue_(false),
96 position_(position),
97 interface_(interface) {
98 // Names must be canonicalized for fast equality checks.
99 ASSERT(name->IsSymbol());
100 }
101
102
BindTo(Variable * var)103 void VariableProxy::BindTo(Variable* var) {
104 ASSERT(var_ == NULL); // must be bound only once
105 ASSERT(var != NULL); // must bind
106 ASSERT((is_this() && var->is_this()) || name_.is_identical_to(var->name()));
107 // Ideally CONST-ness should match. However, this is very hard to achieve
108 // because we don't know the exact semantics of conflicting (const and
109 // non-const) multiple variable declarations, const vars introduced via
110 // eval() etc. Const-ness and variable declarations are a complete mess
111 // in JS. Sigh...
112 var_ = var;
113 var->set_is_used(true);
114 }
115
116
Assignment(Isolate * isolate,Token::Value op,Expression * target,Expression * value,int pos)117 Assignment::Assignment(Isolate* isolate,
118 Token::Value op,
119 Expression* target,
120 Expression* value,
121 int pos)
122 : Expression(isolate),
123 op_(op),
124 target_(target),
125 value_(value),
126 pos_(pos),
127 binary_operation_(NULL),
128 compound_load_id_(kNoNumber),
129 assignment_id_(GetNextId(isolate)),
130 block_start_(false),
131 block_end_(false),
132 is_monomorphic_(false) { }
133
134
binary_op() const135 Token::Value Assignment::binary_op() const {
136 switch (op_) {
137 case Token::ASSIGN_BIT_OR: return Token::BIT_OR;
138 case Token::ASSIGN_BIT_XOR: return Token::BIT_XOR;
139 case Token::ASSIGN_BIT_AND: return Token::BIT_AND;
140 case Token::ASSIGN_SHL: return Token::SHL;
141 case Token::ASSIGN_SAR: return Token::SAR;
142 case Token::ASSIGN_SHR: return Token::SHR;
143 case Token::ASSIGN_ADD: return Token::ADD;
144 case Token::ASSIGN_SUB: return Token::SUB;
145 case Token::ASSIGN_MUL: return Token::MUL;
146 case Token::ASSIGN_DIV: return Token::DIV;
147 case Token::ASSIGN_MOD: return Token::MOD;
148 default: UNREACHABLE();
149 }
150 return Token::ILLEGAL;
151 }
152
153
AllowsLazyCompilation()154 bool FunctionLiteral::AllowsLazyCompilation() {
155 return scope()->AllowsLazyCompilation();
156 }
157
158
start_position() const159 int FunctionLiteral::start_position() const {
160 return scope()->start_position();
161 }
162
163
end_position() const164 int FunctionLiteral::end_position() const {
165 return scope()->end_position();
166 }
167
168
language_mode() const169 LanguageMode FunctionLiteral::language_mode() const {
170 return scope()->language_mode();
171 }
172
173
Property(Literal * key,Expression * value,Isolate * isolate)174 ObjectLiteral::Property::Property(Literal* key,
175 Expression* value,
176 Isolate* isolate) {
177 emit_store_ = true;
178 key_ = key;
179 value_ = value;
180 Object* k = *key->handle();
181 if (k->IsSymbol() &&
182 isolate->heap()->Proto_symbol()->Equals(String::cast(k))) {
183 kind_ = PROTOTYPE;
184 } else if (value_->AsMaterializedLiteral() != NULL) {
185 kind_ = MATERIALIZED_LITERAL;
186 } else if (value_->AsLiteral() != NULL) {
187 kind_ = CONSTANT;
188 } else {
189 kind_ = COMPUTED;
190 }
191 }
192
193
Property(bool is_getter,FunctionLiteral * value)194 ObjectLiteral::Property::Property(bool is_getter, FunctionLiteral* value) {
195 emit_store_ = true;
196 value_ = value;
197 kind_ = is_getter ? GETTER : SETTER;
198 }
199
200
IsCompileTimeValue()201 bool ObjectLiteral::Property::IsCompileTimeValue() {
202 return kind_ == CONSTANT ||
203 (kind_ == MATERIALIZED_LITERAL &&
204 CompileTimeValue::IsCompileTimeValue(value_));
205 }
206
207
set_emit_store(bool emit_store)208 void ObjectLiteral::Property::set_emit_store(bool emit_store) {
209 emit_store_ = emit_store;
210 }
211
212
emit_store()213 bool ObjectLiteral::Property::emit_store() {
214 return emit_store_;
215 }
216
217
IsEqualString(void * first,void * second)218 bool IsEqualString(void* first, void* second) {
219 ASSERT((*reinterpret_cast<String**>(first))->IsString());
220 ASSERT((*reinterpret_cast<String**>(second))->IsString());
221 Handle<String> h1(reinterpret_cast<String**>(first));
222 Handle<String> h2(reinterpret_cast<String**>(second));
223 return (*h1)->Equals(*h2);
224 }
225
226
IsEqualNumber(void * first,void * second)227 bool IsEqualNumber(void* first, void* second) {
228 ASSERT((*reinterpret_cast<Object**>(first))->IsNumber());
229 ASSERT((*reinterpret_cast<Object**>(second))->IsNumber());
230
231 Handle<Object> h1(reinterpret_cast<Object**>(first));
232 Handle<Object> h2(reinterpret_cast<Object**>(second));
233 if (h1->IsSmi()) {
234 return h2->IsSmi() && *h1 == *h2;
235 }
236 if (h2->IsSmi()) return false;
237 Handle<HeapNumber> n1 = Handle<HeapNumber>::cast(h1);
238 Handle<HeapNumber> n2 = Handle<HeapNumber>::cast(h2);
239 ASSERT(isfinite(n1->value()));
240 ASSERT(isfinite(n2->value()));
241 return n1->value() == n2->value();
242 }
243
244
CalculateEmitStore()245 void ObjectLiteral::CalculateEmitStore() {
246 ZoneHashMap table(Literal::Match);
247 for (int i = properties()->length() - 1; i >= 0; i--) {
248 ObjectLiteral::Property* property = properties()->at(i);
249 Literal* literal = property->key();
250 if (literal->handle()->IsNull()) continue;
251 uint32_t hash = literal->Hash();
252 // If the key of a computed property is in the table, do not emit
253 // a store for the property later.
254 if (property->kind() == ObjectLiteral::Property::COMPUTED &&
255 table.Lookup(literal, hash, false) != NULL) {
256 property->set_emit_store(false);
257 } else {
258 // Add key to the table.
259 table.Lookup(literal, hash, true);
260 }
261 }
262 }
263
264
AddTarget(Label * target)265 void TargetCollector::AddTarget(Label* target) {
266 // Add the label to the collector, but discard duplicates.
267 int length = targets_.length();
268 for (int i = 0; i < length; i++) {
269 if (targets_[i] == target) return;
270 }
271 targets_.Add(target);
272 }
273
274
ResultOverwriteAllowed()275 bool UnaryOperation::ResultOverwriteAllowed() {
276 switch (op_) {
277 case Token::BIT_NOT:
278 case Token::SUB:
279 return true;
280 default:
281 return false;
282 }
283 }
284
285
ResultOverwriteAllowed()286 bool BinaryOperation::ResultOverwriteAllowed() {
287 switch (op_) {
288 case Token::COMMA:
289 case Token::OR:
290 case Token::AND:
291 return false;
292 case Token::BIT_OR:
293 case Token::BIT_XOR:
294 case Token::BIT_AND:
295 case Token::SHL:
296 case Token::SAR:
297 case Token::SHR:
298 case Token::ADD:
299 case Token::SUB:
300 case Token::MUL:
301 case Token::DIV:
302 case Token::MOD:
303 return true;
304 default:
305 UNREACHABLE();
306 }
307 return false;
308 }
309
310
IsTypeof(Expression * expr)311 static bool IsTypeof(Expression* expr) {
312 UnaryOperation* maybe_unary = expr->AsUnaryOperation();
313 return maybe_unary != NULL && maybe_unary->op() == Token::TYPEOF;
314 }
315
316
317 // Check for the pattern: typeof <expression> equals <string literal>.
MatchLiteralCompareTypeof(Expression * left,Token::Value op,Expression * right,Expression ** expr,Handle<String> * check)318 static bool MatchLiteralCompareTypeof(Expression* left,
319 Token::Value op,
320 Expression* right,
321 Expression** expr,
322 Handle<String>* check) {
323 if (IsTypeof(left) && right->IsStringLiteral() && Token::IsEqualityOp(op)) {
324 *expr = left->AsUnaryOperation()->expression();
325 *check = Handle<String>::cast(right->AsLiteral()->handle());
326 return true;
327 }
328 return false;
329 }
330
331
IsLiteralCompareTypeof(Expression ** expr,Handle<String> * check)332 bool CompareOperation::IsLiteralCompareTypeof(Expression** expr,
333 Handle<String>* check) {
334 return MatchLiteralCompareTypeof(left_, op_, right_, expr, check) ||
335 MatchLiteralCompareTypeof(right_, op_, left_, expr, check);
336 }
337
338
IsVoidOfLiteral(Expression * expr)339 static bool IsVoidOfLiteral(Expression* expr) {
340 UnaryOperation* maybe_unary = expr->AsUnaryOperation();
341 return maybe_unary != NULL &&
342 maybe_unary->op() == Token::VOID &&
343 maybe_unary->expression()->AsLiteral() != NULL;
344 }
345
346
347 // Check for the pattern: void <literal> equals <expression>
MatchLiteralCompareUndefined(Expression * left,Token::Value op,Expression * right,Expression ** expr)348 static bool MatchLiteralCompareUndefined(Expression* left,
349 Token::Value op,
350 Expression* right,
351 Expression** expr) {
352 if (IsVoidOfLiteral(left) && Token::IsEqualityOp(op)) {
353 *expr = right;
354 return true;
355 }
356 return false;
357 }
358
359
IsLiteralCompareUndefined(Expression ** expr)360 bool CompareOperation::IsLiteralCompareUndefined(Expression** expr) {
361 return MatchLiteralCompareUndefined(left_, op_, right_, expr) ||
362 MatchLiteralCompareUndefined(right_, op_, left_, expr);
363 }
364
365
366 // Check for the pattern: null equals <expression>
MatchLiteralCompareNull(Expression * left,Token::Value op,Expression * right,Expression ** expr)367 static bool MatchLiteralCompareNull(Expression* left,
368 Token::Value op,
369 Expression* right,
370 Expression** expr) {
371 if (left->IsNullLiteral() && Token::IsEqualityOp(op)) {
372 *expr = right;
373 return true;
374 }
375 return false;
376 }
377
378
IsLiteralCompareNull(Expression ** expr)379 bool CompareOperation::IsLiteralCompareNull(Expression** expr) {
380 return MatchLiteralCompareNull(left_, op_, right_, expr) ||
381 MatchLiteralCompareNull(right_, op_, left_, expr);
382 }
383
384
385 // ----------------------------------------------------------------------------
386 // Inlining support
387
IsInlineable() const388 bool Declaration::IsInlineable() const {
389 return proxy()->var()->IsStackAllocated();
390 }
391
IsInlineable() const392 bool FunctionDeclaration::IsInlineable() const {
393 return false;
394 }
395
396
397 // ----------------------------------------------------------------------------
398 // Recording of type feedback
399
RecordTypeFeedback(TypeFeedbackOracle * oracle)400 void Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
401 // Record type feedback from the oracle in the AST.
402 is_uninitialized_ = oracle->LoadIsUninitialized(this);
403 if (is_uninitialized_) return;
404
405 is_monomorphic_ = oracle->LoadIsMonomorphicNormal(this);
406 receiver_types_.Clear();
407 if (key()->IsPropertyName()) {
408 if (oracle->LoadIsBuiltin(this, Builtins::kLoadIC_ArrayLength)) {
409 is_array_length_ = true;
410 } else if (oracle->LoadIsBuiltin(this, Builtins::kLoadIC_StringLength)) {
411 is_string_length_ = true;
412 } else if (oracle->LoadIsBuiltin(this,
413 Builtins::kLoadIC_FunctionPrototype)) {
414 is_function_prototype_ = true;
415 } else {
416 Literal* lit_key = key()->AsLiteral();
417 ASSERT(lit_key != NULL && lit_key->handle()->IsString());
418 Handle<String> name = Handle<String>::cast(lit_key->handle());
419 oracle->LoadReceiverTypes(this, name, &receiver_types_);
420 }
421 } else if (oracle->LoadIsBuiltin(this, Builtins::kKeyedLoadIC_String)) {
422 is_string_access_ = true;
423 } else if (is_monomorphic_) {
424 receiver_types_.Add(oracle->LoadMonomorphicReceiverType(this));
425 } else if (oracle->LoadIsMegamorphicWithTypeInfo(this)) {
426 receiver_types_.Reserve(kMaxKeyedPolymorphism);
427 oracle->CollectKeyedReceiverTypes(this->id(), &receiver_types_);
428 }
429 }
430
431
RecordTypeFeedback(TypeFeedbackOracle * oracle)432 void Assignment::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
433 Property* prop = target()->AsProperty();
434 ASSERT(prop != NULL);
435 is_monomorphic_ = oracle->StoreIsMonomorphicNormal(this);
436 receiver_types_.Clear();
437 if (prop->key()->IsPropertyName()) {
438 Literal* lit_key = prop->key()->AsLiteral();
439 ASSERT(lit_key != NULL && lit_key->handle()->IsString());
440 Handle<String> name = Handle<String>::cast(lit_key->handle());
441 oracle->StoreReceiverTypes(this, name, &receiver_types_);
442 } else if (is_monomorphic_) {
443 // Record receiver type for monomorphic keyed stores.
444 receiver_types_.Add(oracle->StoreMonomorphicReceiverType(this));
445 } else if (oracle->StoreIsMegamorphicWithTypeInfo(this)) {
446 receiver_types_.Reserve(kMaxKeyedPolymorphism);
447 oracle->CollectKeyedReceiverTypes(this->id(), &receiver_types_);
448 }
449 }
450
451
RecordTypeFeedback(TypeFeedbackOracle * oracle)452 void CountOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
453 is_monomorphic_ = oracle->StoreIsMonomorphicNormal(this);
454 receiver_types_.Clear();
455 if (is_monomorphic_) {
456 // Record receiver type for monomorphic keyed stores.
457 receiver_types_.Add(oracle->StoreMonomorphicReceiverType(this));
458 } else if (oracle->StoreIsMegamorphicWithTypeInfo(this)) {
459 receiver_types_.Reserve(kMaxKeyedPolymorphism);
460 oracle->CollectKeyedReceiverTypes(this->id(), &receiver_types_);
461 }
462 }
463
464
RecordTypeFeedback(TypeFeedbackOracle * oracle)465 void CaseClause::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
466 TypeInfo info = oracle->SwitchType(this);
467 if (info.IsSmi()) {
468 compare_type_ = SMI_ONLY;
469 } else if (info.IsSymbol()) {
470 compare_type_ = SYMBOL_ONLY;
471 } else if (info.IsNonSymbol()) {
472 compare_type_ = STRING_ONLY;
473 } else if (info.IsNonPrimitive()) {
474 compare_type_ = OBJECT_ONLY;
475 } else {
476 ASSERT(compare_type_ == NONE);
477 }
478 }
479
480
ComputeTarget(Handle<Map> type,Handle<String> name)481 bool Call::ComputeTarget(Handle<Map> type, Handle<String> name) {
482 // If there is an interceptor, we can't compute the target for a direct call.
483 if (type->has_named_interceptor()) return false;
484
485 if (check_type_ == RECEIVER_MAP_CHECK) {
486 // For primitive checks the holder is set up to point to the corresponding
487 // prototype object, i.e. one step of the algorithm below has been already
488 // performed. For non-primitive checks we clear it to allow computing
489 // targets for polymorphic calls.
490 holder_ = Handle<JSObject>::null();
491 }
492 LookupResult lookup(type->GetIsolate());
493 while (true) {
494 type->LookupInDescriptors(NULL, *name, &lookup);
495 if (lookup.IsFound()) {
496 switch (lookup.type()) {
497 case CONSTANT_FUNCTION:
498 // We surely know the target for a constant function.
499 target_ =
500 Handle<JSFunction>(lookup.GetConstantFunctionFromMap(*type));
501 return true;
502 case NORMAL:
503 case FIELD:
504 case CALLBACKS:
505 case HANDLER:
506 case INTERCEPTOR:
507 // We don't know the target.
508 return false;
509 case MAP_TRANSITION:
510 case ELEMENTS_TRANSITION:
511 case CONSTANT_TRANSITION:
512 case NULL_DESCRIPTOR:
513 // Perhaps something interesting is up in the prototype chain...
514 break;
515 }
516 }
517 // If we reach the end of the prototype chain, we don't know the target.
518 if (!type->prototype()->IsJSObject()) return false;
519 // Go up the prototype chain, recording where we are currently.
520 holder_ = Handle<JSObject>(JSObject::cast(type->prototype()));
521 type = Handle<Map>(holder()->map());
522 }
523 }
524
525
ComputeGlobalTarget(Handle<GlobalObject> global,LookupResult * lookup)526 bool Call::ComputeGlobalTarget(Handle<GlobalObject> global,
527 LookupResult* lookup) {
528 target_ = Handle<JSFunction>::null();
529 cell_ = Handle<JSGlobalPropertyCell>::null();
530 ASSERT(lookup->IsFound() &&
531 lookup->type() == NORMAL &&
532 lookup->holder() == *global);
533 cell_ = Handle<JSGlobalPropertyCell>(global->GetPropertyCell(lookup));
534 if (cell_->value()->IsJSFunction()) {
535 Handle<JSFunction> candidate(JSFunction::cast(cell_->value()));
536 // If the function is in new space we assume it's more likely to
537 // change and thus prefer the general IC code.
538 if (!HEAP->InNewSpace(*candidate)) {
539 target_ = candidate;
540 return true;
541 }
542 }
543 return false;
544 }
545
546
RecordTypeFeedback(TypeFeedbackOracle * oracle,CallKind call_kind)547 void Call::RecordTypeFeedback(TypeFeedbackOracle* oracle,
548 CallKind call_kind) {
549 is_monomorphic_ = oracle->CallIsMonomorphic(this);
550 Property* property = expression()->AsProperty();
551 if (property == NULL) {
552 // Function call. Specialize for monomorphic calls.
553 if (is_monomorphic_) target_ = oracle->GetCallTarget(this);
554 } else {
555 // Method call. Specialize for the receiver types seen at runtime.
556 Literal* key = property->key()->AsLiteral();
557 ASSERT(key != NULL && key->handle()->IsString());
558 Handle<String> name = Handle<String>::cast(key->handle());
559 receiver_types_.Clear();
560 oracle->CallReceiverTypes(this, name, call_kind, &receiver_types_);
561 #ifdef DEBUG
562 if (FLAG_enable_slow_asserts) {
563 int length = receiver_types_.length();
564 for (int i = 0; i < length; i++) {
565 Handle<Map> map = receiver_types_.at(i);
566 ASSERT(!map.is_null() && *map != NULL);
567 }
568 }
569 #endif
570 check_type_ = oracle->GetCallCheckType(this);
571 if (is_monomorphic_) {
572 Handle<Map> map;
573 if (receiver_types_.length() > 0) {
574 ASSERT(check_type_ == RECEIVER_MAP_CHECK);
575 map = receiver_types_.at(0);
576 } else {
577 ASSERT(check_type_ != RECEIVER_MAP_CHECK);
578 holder_ = Handle<JSObject>(
579 oracle->GetPrototypeForPrimitiveCheck(check_type_));
580 map = Handle<Map>(holder_->map());
581 }
582 is_monomorphic_ = ComputeTarget(map, name);
583 }
584 }
585 }
586
587
RecordTypeFeedback(TypeFeedbackOracle * oracle)588 void CallNew::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
589 is_monomorphic_ = oracle->CallNewIsMonomorphic(this);
590 if (is_monomorphic_) {
591 target_ = oracle->GetCallNewTarget(this);
592 }
593 }
594
595
RecordTypeFeedback(TypeFeedbackOracle * oracle)596 void CompareOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
597 TypeInfo info = oracle->CompareType(this);
598 if (info.IsSmi()) {
599 compare_type_ = SMI_ONLY;
600 } else if (info.IsNonPrimitive()) {
601 compare_type_ = OBJECT_ONLY;
602 } else {
603 ASSERT(compare_type_ == NONE);
604 }
605 }
606
607
RecordTypeFeedback(TypeFeedbackOracle * oracle)608 void ObjectLiteral::Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
609 receiver_type_ = oracle->ObjectLiteralStoreIsMonomorphic(this)
610 ? oracle->GetObjectLiteralStoreMap(this)
611 : Handle<Map>::null();
612 }
613
614
615 // ----------------------------------------------------------------------------
616 // Implementation of AstVisitor
617
CheckStackOverflow()618 bool AstVisitor::CheckStackOverflow() {
619 if (stack_overflow_) return true;
620 StackLimitCheck check(isolate_);
621 if (!check.HasOverflowed()) return false;
622 return (stack_overflow_ = true);
623 }
624
625
VisitDeclarations(ZoneList<Declaration * > * declarations)626 void AstVisitor::VisitDeclarations(ZoneList<Declaration*>* declarations) {
627 for (int i = 0; i < declarations->length(); i++) {
628 Visit(declarations->at(i));
629 }
630 }
631
632
VisitStatements(ZoneList<Statement * > * statements)633 void AstVisitor::VisitStatements(ZoneList<Statement*>* statements) {
634 for (int i = 0; i < statements->length(); i++) {
635 Visit(statements->at(i));
636 }
637 }
638
639
VisitExpressions(ZoneList<Expression * > * expressions)640 void AstVisitor::VisitExpressions(ZoneList<Expression*>* expressions) {
641 for (int i = 0; i < expressions->length(); i++) {
642 // The variable statement visiting code may pass NULL expressions
643 // to this code. Maybe this should be handled by introducing an
644 // undefined expression or literal? Revisit this code if this
645 // changes
646 Expression* expression = expressions->at(i);
647 if (expression != NULL) Visit(expression);
648 }
649 }
650
651
652 // ----------------------------------------------------------------------------
653 // Regular expressions
654
655 #define MAKE_ACCEPT(Name) \
656 void* RegExp##Name::Accept(RegExpVisitor* visitor, void* data) { \
657 return visitor->Visit##Name(this, data); \
658 }
659 FOR_EACH_REG_EXP_TREE_TYPE(MAKE_ACCEPT)
660 #undef MAKE_ACCEPT
661
662 #define MAKE_TYPE_CASE(Name) \
663 RegExp##Name* RegExpTree::As##Name() { \
664 return NULL; \
665 } \
666 bool RegExpTree::Is##Name() { return false; }
FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE)667 FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE)
668 #undef MAKE_TYPE_CASE
669
670 #define MAKE_TYPE_CASE(Name) \
671 RegExp##Name* RegExp##Name::As##Name() { \
672 return this; \
673 } \
674 bool RegExp##Name::Is##Name() { return true; }
675 FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE)
676 #undef MAKE_TYPE_CASE
677
678
679 static Interval ListCaptureRegisters(ZoneList<RegExpTree*>* children) {
680 Interval result = Interval::Empty();
681 for (int i = 0; i < children->length(); i++)
682 result = result.Union(children->at(i)->CaptureRegisters());
683 return result;
684 }
685
686
CaptureRegisters()687 Interval RegExpAlternative::CaptureRegisters() {
688 return ListCaptureRegisters(nodes());
689 }
690
691
CaptureRegisters()692 Interval RegExpDisjunction::CaptureRegisters() {
693 return ListCaptureRegisters(alternatives());
694 }
695
696
CaptureRegisters()697 Interval RegExpLookahead::CaptureRegisters() {
698 return body()->CaptureRegisters();
699 }
700
701
CaptureRegisters()702 Interval RegExpCapture::CaptureRegisters() {
703 Interval self(StartRegister(index()), EndRegister(index()));
704 return self.Union(body()->CaptureRegisters());
705 }
706
707
CaptureRegisters()708 Interval RegExpQuantifier::CaptureRegisters() {
709 return body()->CaptureRegisters();
710 }
711
712
IsAnchoredAtStart()713 bool RegExpAssertion::IsAnchoredAtStart() {
714 return type() == RegExpAssertion::START_OF_INPUT;
715 }
716
717
IsAnchoredAtEnd()718 bool RegExpAssertion::IsAnchoredAtEnd() {
719 return type() == RegExpAssertion::END_OF_INPUT;
720 }
721
722
IsAnchoredAtStart()723 bool RegExpAlternative::IsAnchoredAtStart() {
724 ZoneList<RegExpTree*>* nodes = this->nodes();
725 for (int i = 0; i < nodes->length(); i++) {
726 RegExpTree* node = nodes->at(i);
727 if (node->IsAnchoredAtStart()) { return true; }
728 if (node->max_match() > 0) { return false; }
729 }
730 return false;
731 }
732
733
IsAnchoredAtEnd()734 bool RegExpAlternative::IsAnchoredAtEnd() {
735 ZoneList<RegExpTree*>* nodes = this->nodes();
736 for (int i = nodes->length() - 1; i >= 0; i--) {
737 RegExpTree* node = nodes->at(i);
738 if (node->IsAnchoredAtEnd()) { return true; }
739 if (node->max_match() > 0) { return false; }
740 }
741 return false;
742 }
743
744
IsAnchoredAtStart()745 bool RegExpDisjunction::IsAnchoredAtStart() {
746 ZoneList<RegExpTree*>* alternatives = this->alternatives();
747 for (int i = 0; i < alternatives->length(); i++) {
748 if (!alternatives->at(i)->IsAnchoredAtStart())
749 return false;
750 }
751 return true;
752 }
753
754
IsAnchoredAtEnd()755 bool RegExpDisjunction::IsAnchoredAtEnd() {
756 ZoneList<RegExpTree*>* alternatives = this->alternatives();
757 for (int i = 0; i < alternatives->length(); i++) {
758 if (!alternatives->at(i)->IsAnchoredAtEnd())
759 return false;
760 }
761 return true;
762 }
763
764
IsAnchoredAtStart()765 bool RegExpLookahead::IsAnchoredAtStart() {
766 return is_positive() && body()->IsAnchoredAtStart();
767 }
768
769
IsAnchoredAtStart()770 bool RegExpCapture::IsAnchoredAtStart() {
771 return body()->IsAnchoredAtStart();
772 }
773
774
IsAnchoredAtEnd()775 bool RegExpCapture::IsAnchoredAtEnd() {
776 return body()->IsAnchoredAtEnd();
777 }
778
779
780 // Convert regular expression trees to a simple sexp representation.
781 // This representation should be different from the input grammar
782 // in as many cases as possible, to make it more difficult for incorrect
783 // parses to look as correct ones which is likely if the input and
784 // output formats are alike.
785 class RegExpUnparser: public RegExpVisitor {
786 public:
787 RegExpUnparser();
788 void VisitCharacterRange(CharacterRange that);
ToString()789 SmartArrayPointer<const char> ToString() { return stream_.ToCString(); }
790 #define MAKE_CASE(Name) virtual void* Visit##Name(RegExp##Name*, void* data);
791 FOR_EACH_REG_EXP_TREE_TYPE(MAKE_CASE)
792 #undef MAKE_CASE
793 private:
stream()794 StringStream* stream() { return &stream_; }
795 HeapStringAllocator alloc_;
796 StringStream stream_;
797 };
798
799
RegExpUnparser()800 RegExpUnparser::RegExpUnparser() : stream_(&alloc_) {
801 }
802
803
VisitDisjunction(RegExpDisjunction * that,void * data)804 void* RegExpUnparser::VisitDisjunction(RegExpDisjunction* that, void* data) {
805 stream()->Add("(|");
806 for (int i = 0; i < that->alternatives()->length(); i++) {
807 stream()->Add(" ");
808 that->alternatives()->at(i)->Accept(this, data);
809 }
810 stream()->Add(")");
811 return NULL;
812 }
813
814
VisitAlternative(RegExpAlternative * that,void * data)815 void* RegExpUnparser::VisitAlternative(RegExpAlternative* that, void* data) {
816 stream()->Add("(:");
817 for (int i = 0; i < that->nodes()->length(); i++) {
818 stream()->Add(" ");
819 that->nodes()->at(i)->Accept(this, data);
820 }
821 stream()->Add(")");
822 return NULL;
823 }
824
825
VisitCharacterRange(CharacterRange that)826 void RegExpUnparser::VisitCharacterRange(CharacterRange that) {
827 stream()->Add("%k", that.from());
828 if (!that.IsSingleton()) {
829 stream()->Add("-%k", that.to());
830 }
831 }
832
833
834
VisitCharacterClass(RegExpCharacterClass * that,void * data)835 void* RegExpUnparser::VisitCharacterClass(RegExpCharacterClass* that,
836 void* data) {
837 if (that->is_negated())
838 stream()->Add("^");
839 stream()->Add("[");
840 for (int i = 0; i < that->ranges()->length(); i++) {
841 if (i > 0) stream()->Add(" ");
842 VisitCharacterRange(that->ranges()->at(i));
843 }
844 stream()->Add("]");
845 return NULL;
846 }
847
848
VisitAssertion(RegExpAssertion * that,void * data)849 void* RegExpUnparser::VisitAssertion(RegExpAssertion* that, void* data) {
850 switch (that->type()) {
851 case RegExpAssertion::START_OF_INPUT:
852 stream()->Add("@^i");
853 break;
854 case RegExpAssertion::END_OF_INPUT:
855 stream()->Add("@$i");
856 break;
857 case RegExpAssertion::START_OF_LINE:
858 stream()->Add("@^l");
859 break;
860 case RegExpAssertion::END_OF_LINE:
861 stream()->Add("@$l");
862 break;
863 case RegExpAssertion::BOUNDARY:
864 stream()->Add("@b");
865 break;
866 case RegExpAssertion::NON_BOUNDARY:
867 stream()->Add("@B");
868 break;
869 }
870 return NULL;
871 }
872
873
VisitAtom(RegExpAtom * that,void * data)874 void* RegExpUnparser::VisitAtom(RegExpAtom* that, void* data) {
875 stream()->Add("'");
876 Vector<const uc16> chardata = that->data();
877 for (int i = 0; i < chardata.length(); i++) {
878 stream()->Add("%k", chardata[i]);
879 }
880 stream()->Add("'");
881 return NULL;
882 }
883
884
VisitText(RegExpText * that,void * data)885 void* RegExpUnparser::VisitText(RegExpText* that, void* data) {
886 if (that->elements()->length() == 1) {
887 that->elements()->at(0).data.u_atom->Accept(this, data);
888 } else {
889 stream()->Add("(!");
890 for (int i = 0; i < that->elements()->length(); i++) {
891 stream()->Add(" ");
892 that->elements()->at(i).data.u_atom->Accept(this, data);
893 }
894 stream()->Add(")");
895 }
896 return NULL;
897 }
898
899
VisitQuantifier(RegExpQuantifier * that,void * data)900 void* RegExpUnparser::VisitQuantifier(RegExpQuantifier* that, void* data) {
901 stream()->Add("(# %i ", that->min());
902 if (that->max() == RegExpTree::kInfinity) {
903 stream()->Add("- ");
904 } else {
905 stream()->Add("%i ", that->max());
906 }
907 stream()->Add(that->is_greedy() ? "g " : that->is_possessive() ? "p " : "n ");
908 that->body()->Accept(this, data);
909 stream()->Add(")");
910 return NULL;
911 }
912
913
VisitCapture(RegExpCapture * that,void * data)914 void* RegExpUnparser::VisitCapture(RegExpCapture* that, void* data) {
915 stream()->Add("(^ ");
916 that->body()->Accept(this, data);
917 stream()->Add(")");
918 return NULL;
919 }
920
921
VisitLookahead(RegExpLookahead * that,void * data)922 void* RegExpUnparser::VisitLookahead(RegExpLookahead* that, void* data) {
923 stream()->Add("(-> ");
924 stream()->Add(that->is_positive() ? "+ " : "- ");
925 that->body()->Accept(this, data);
926 stream()->Add(")");
927 return NULL;
928 }
929
930
VisitBackReference(RegExpBackReference * that,void * data)931 void* RegExpUnparser::VisitBackReference(RegExpBackReference* that,
932 void* data) {
933 stream()->Add("(<- %i)", that->index());
934 return NULL;
935 }
936
937
VisitEmpty(RegExpEmpty * that,void * data)938 void* RegExpUnparser::VisitEmpty(RegExpEmpty* that, void* data) {
939 stream()->Put('%');
940 return NULL;
941 }
942
943
ToString()944 SmartArrayPointer<const char> RegExpTree::ToString() {
945 RegExpUnparser unparser;
946 Accept(&unparser, NULL);
947 return unparser.ToString();
948 }
949
950
RegExpDisjunction(ZoneList<RegExpTree * > * alternatives)951 RegExpDisjunction::RegExpDisjunction(ZoneList<RegExpTree*>* alternatives)
952 : alternatives_(alternatives) {
953 ASSERT(alternatives->length() > 1);
954 RegExpTree* first_alternative = alternatives->at(0);
955 min_match_ = first_alternative->min_match();
956 max_match_ = first_alternative->max_match();
957 for (int i = 1; i < alternatives->length(); i++) {
958 RegExpTree* alternative = alternatives->at(i);
959 min_match_ = Min(min_match_, alternative->min_match());
960 max_match_ = Max(max_match_, alternative->max_match());
961 }
962 }
963
964
RegExpAlternative(ZoneList<RegExpTree * > * nodes)965 RegExpAlternative::RegExpAlternative(ZoneList<RegExpTree*>* nodes)
966 : nodes_(nodes) {
967 ASSERT(nodes->length() > 1);
968 min_match_ = 0;
969 max_match_ = 0;
970 for (int i = 0; i < nodes->length(); i++) {
971 RegExpTree* node = nodes->at(i);
972 min_match_ += node->min_match();
973 int node_max_match = node->max_match();
974 if (kInfinity - max_match_ < node_max_match) {
975 max_match_ = kInfinity;
976 } else {
977 max_match_ += node->max_match();
978 }
979 }
980 }
981
982
CaseClause(Isolate * isolate,Expression * label,ZoneList<Statement * > * statements,int pos)983 CaseClause::CaseClause(Isolate* isolate,
984 Expression* label,
985 ZoneList<Statement*>* statements,
986 int pos)
987 : label_(label),
988 statements_(statements),
989 position_(pos),
990 compare_type_(NONE),
991 compare_id_(AstNode::GetNextId(isolate)),
992 entry_id_(AstNode::GetNextId(isolate)) {
993 }
994
995
996 #define INCREASE_NODE_COUNT(NodeType) \
997 void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
998 increase_node_count(); \
999 }
1000
1001 INCREASE_NODE_COUNT(VariableDeclaration)
INCREASE_NODE_COUNT(FunctionDeclaration)1002 INCREASE_NODE_COUNT(FunctionDeclaration)
1003 INCREASE_NODE_COUNT(ModuleDeclaration)
1004 INCREASE_NODE_COUNT(ImportDeclaration)
1005 INCREASE_NODE_COUNT(ExportDeclaration)
1006 INCREASE_NODE_COUNT(ModuleLiteral)
1007 INCREASE_NODE_COUNT(ModuleVariable)
1008 INCREASE_NODE_COUNT(ModulePath)
1009 INCREASE_NODE_COUNT(ModuleUrl)
1010 INCREASE_NODE_COUNT(Block)
1011 INCREASE_NODE_COUNT(ExpressionStatement)
1012 INCREASE_NODE_COUNT(EmptyStatement)
1013 INCREASE_NODE_COUNT(IfStatement)
1014 INCREASE_NODE_COUNT(ContinueStatement)
1015 INCREASE_NODE_COUNT(BreakStatement)
1016 INCREASE_NODE_COUNT(ReturnStatement)
1017 INCREASE_NODE_COUNT(Conditional)
1018 INCREASE_NODE_COUNT(Literal)
1019 INCREASE_NODE_COUNT(ObjectLiteral)
1020 INCREASE_NODE_COUNT(Assignment)
1021 INCREASE_NODE_COUNT(Throw)
1022 INCREASE_NODE_COUNT(Property)
1023 INCREASE_NODE_COUNT(UnaryOperation)
1024 INCREASE_NODE_COUNT(CountOperation)
1025 INCREASE_NODE_COUNT(BinaryOperation)
1026 INCREASE_NODE_COUNT(CompareOperation)
1027 INCREASE_NODE_COUNT(ThisFunction)
1028 INCREASE_NODE_COUNT(Call)
1029 INCREASE_NODE_COUNT(CallNew)
1030
1031 #undef INCREASE_NODE_COUNT
1032
1033
1034 void AstConstructionVisitor::VisitWithStatement(WithStatement* node) {
1035 increase_node_count();
1036 add_flag(kDontOptimize);
1037 add_flag(kDontInline);
1038 }
1039
1040
VisitSwitchStatement(SwitchStatement * node)1041 void AstConstructionVisitor::VisitSwitchStatement(SwitchStatement* node) {
1042 increase_node_count();
1043 add_flag(kDontInline);
1044 }
1045
1046
VisitDoWhileStatement(DoWhileStatement * node)1047 void AstConstructionVisitor::VisitDoWhileStatement(DoWhileStatement* node) {
1048 increase_node_count();
1049 add_flag(kDontSelfOptimize);
1050 }
1051
1052
VisitWhileStatement(WhileStatement * node)1053 void AstConstructionVisitor::VisitWhileStatement(WhileStatement* node) {
1054 increase_node_count();
1055 add_flag(kDontSelfOptimize);
1056 }
1057
1058
VisitForStatement(ForStatement * node)1059 void AstConstructionVisitor::VisitForStatement(ForStatement* node) {
1060 increase_node_count();
1061 add_flag(kDontSelfOptimize);
1062 }
1063
1064
VisitForInStatement(ForInStatement * node)1065 void AstConstructionVisitor::VisitForInStatement(ForInStatement* node) {
1066 increase_node_count();
1067 add_flag(kDontSelfOptimize);
1068 }
1069
1070
VisitTryCatchStatement(TryCatchStatement * node)1071 void AstConstructionVisitor::VisitTryCatchStatement(TryCatchStatement* node) {
1072 increase_node_count();
1073 add_flag(kDontOptimize);
1074 add_flag(kDontInline);
1075 }
1076
1077
VisitTryFinallyStatement(TryFinallyStatement * node)1078 void AstConstructionVisitor::VisitTryFinallyStatement(
1079 TryFinallyStatement* node) {
1080 increase_node_count();
1081 add_flag(kDontOptimize);
1082 add_flag(kDontInline);
1083 }
1084
1085
VisitDebuggerStatement(DebuggerStatement * node)1086 void AstConstructionVisitor::VisitDebuggerStatement(DebuggerStatement* node) {
1087 increase_node_count();
1088 add_flag(kDontOptimize);
1089 add_flag(kDontInline);
1090 }
1091
1092
VisitFunctionLiteral(FunctionLiteral * node)1093 void AstConstructionVisitor::VisitFunctionLiteral(FunctionLiteral* node) {
1094 increase_node_count();
1095 add_flag(kDontInline);
1096 }
1097
1098
VisitSharedFunctionInfoLiteral(SharedFunctionInfoLiteral * node)1099 void AstConstructionVisitor::VisitSharedFunctionInfoLiteral(
1100 SharedFunctionInfoLiteral* node) {
1101 increase_node_count();
1102 add_flag(kDontOptimize);
1103 add_flag(kDontInline);
1104 }
1105
1106
VisitVariableProxy(VariableProxy * node)1107 void AstConstructionVisitor::VisitVariableProxy(VariableProxy* node) {
1108 increase_node_count();
1109 // In theory, we'd have to add:
1110 // if(node->var()->IsLookupSlot()) { add_flag(kDontInline); }
1111 // However, node->var() is usually not bound yet at VariableProxy creation
1112 // time, and LOOKUP variables only result from constructs that cannot
1113 // be inlined anyway.
1114 }
1115
1116
VisitRegExpLiteral(RegExpLiteral * node)1117 void AstConstructionVisitor::VisitRegExpLiteral(RegExpLiteral* node) {
1118 increase_node_count();
1119 add_flag(kDontInline); // TODO(1322): Allow materialized literals.
1120 }
1121
1122
VisitArrayLiteral(ArrayLiteral * node)1123 void AstConstructionVisitor::VisitArrayLiteral(ArrayLiteral* node) {
1124 increase_node_count();
1125 add_flag(kDontInline); // TODO(1322): Allow materialized literals.
1126 }
1127
1128
VisitCallRuntime(CallRuntime * node)1129 void AstConstructionVisitor::VisitCallRuntime(CallRuntime* node) {
1130 increase_node_count();
1131 if (node->is_jsruntime()) {
1132 // Don't try to inline JS runtime calls because we don't (currently) even
1133 // optimize them.
1134 add_flag(kDontInline);
1135 } else if (node->function()->intrinsic_type == Runtime::INLINE &&
1136 (node->name()->IsEqualTo(CStrVector("_ArgumentsLength")) ||
1137 node->name()->IsEqualTo(CStrVector("_Arguments")))) {
1138 // Don't inline the %_ArgumentsLength or %_Arguments because their
1139 // implementation will not work. There is no stack frame to get them
1140 // from.
1141 add_flag(kDontInline);
1142 }
1143 }
1144
1145
ToString()1146 Handle<String> Literal::ToString() {
1147 if (handle_->IsString()) return Handle<String>::cast(handle_);
1148 ASSERT(handle_->IsNumber());
1149 char arr[100];
1150 Vector<char> buffer(arr, ARRAY_SIZE(arr));
1151 const char* str;
1152 if (handle_->IsSmi()) {
1153 // Optimization only, the heap number case would subsume this.
1154 OS::SNPrintF(buffer, "%d", Smi::cast(*handle_)->value());
1155 str = arr;
1156 } else {
1157 str = DoubleToCString(handle_->Number(), buffer);
1158 }
1159 return FACTORY->NewStringFromAscii(CStrVector(str));
1160 }
1161
1162
1163 } } // namespace v8::internal
1164