blob: ccfa2b4ecf50a49464d4708573f9958997679e0c [file] [log] [blame]
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001// Copyright 2010 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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 "v8.h"
29
30#include "ast.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000031#include "jump-target-inl.h"
ager@chromium.org3811b432009-10-28 14:53:37 +000032#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000033#include "scopes.h"
ager@chromium.orga74f0da2008-12-03 16:05:52 +000034#include "string-stream.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000035
kasperl@chromium.org71affb52009-05-26 05:44:31 +000036namespace v8 {
37namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038
kasperl@chromium.orga5551262010-12-07 12:49:48 +000039unsigned AstNode::current_id_ = 0;
40unsigned AstNode::count_ = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041VariableProxySentinel VariableProxySentinel::this_proxy_(true);
42VariableProxySentinel VariableProxySentinel::identifier_proxy_(false);
43ValidLeftHandSideSentinel ValidLeftHandSideSentinel::instance_;
44Property Property::this_property_(VariableProxySentinel::this_proxy(), NULL, 0);
ager@chromium.orga74f0da2008-12-03 16:05:52 +000045Call Call::sentinel_(NULL, NULL, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046
47
48// ----------------------------------------------------------------------------
49// All the Accept member functions for each syntax tree node type.
50
kasperl@chromium.orga5551262010-12-07 12:49:48 +000051void Slot::Accept(AstVisitor* v) { v->VisitSlot(this); }
52
lrn@chromium.org25156de2010-04-06 13:10:27 +000053#define DECL_ACCEPT(type) \
54 void type::Accept(AstVisitor* v) { v->Visit##type(this); }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000055AST_NODE_LIST(DECL_ACCEPT)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000056#undef DECL_ACCEPT
57
58
59// ----------------------------------------------------------------------------
60// Implementation of other node functionality.
61
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000062Assignment* ExpressionStatement::StatementAsSimpleAssignment() {
63 return (expression()->AsAssignment() != NULL &&
64 !expression()->AsAssignment()->is_compound())
65 ? expression()->AsAssignment()
66 : NULL;
67}
68
69
70CountOperation* ExpressionStatement::StatementAsCountOperation() {
71 return expression()->AsCountOperation();
72}
73
74
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000075VariableProxy::VariableProxy(Variable* var)
76 : name_(var->name()),
77 var_(NULL), // Will be set by the call to BindTo.
78 is_this_(var->is_this()),
79 inside_with_(false),
80 is_trivial_(false) {
81 BindTo(var);
82}
83
84
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000085VariableProxy::VariableProxy(Handle<String> name,
86 bool is_this,
87 bool inside_with)
88 : name_(name),
89 var_(NULL),
90 is_this_(is_this),
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000091 inside_with_(inside_with),
ricow@chromium.org65fae842010-08-25 15:26:24 +000092 is_trivial_(false) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000093 // names must be canonicalized for fast equality checks
94 ASSERT(name->IsSymbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000095}
96
97
98VariableProxy::VariableProxy(bool is_this)
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +000099 : var_(NULL),
100 is_this_(is_this),
101 inside_with_(false),
102 is_trivial_(false) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103}
104
105
106void VariableProxy::BindTo(Variable* var) {
107 ASSERT(var_ == NULL); // must be bound only once
108 ASSERT(var != NULL); // must bind
109 ASSERT((is_this() && var->is_this()) || name_.is_identical_to(var->name()));
110 // Ideally CONST-ness should match. However, this is very hard to achieve
111 // because we don't know the exact semantics of conflicting (const and
112 // non-const) multiple variable declarations, const vars introduced via
113 // eval() etc. Const-ness and variable declarations are a complete mess
114 // in JS. Sigh...
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000115 var_ = var;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000116 var->set_is_used(true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000117}
118
119
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000120Assignment::Assignment(Token::Value op,
121 Expression* target,
122 Expression* value,
123 int pos)
124 : op_(op),
125 target_(target),
126 value_(value),
127 pos_(pos),
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000128 binary_operation_(NULL),
129 compound_load_id_(kNoNumber),
130 assignment_id_(GetNextId()),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000131 block_start_(false),
132 block_end_(false),
133 is_monomorphic_(false),
134 receiver_types_(NULL) {
135 ASSERT(Token::IsAssignmentOp(op));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000136 if (is_compound()) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000137 binary_operation_ =
138 new BinaryOperation(binary_op(), target, value, pos + 1);
139 compound_load_id_ = GetNextId();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000140 }
141}
142
143
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000144Token::Value Assignment::binary_op() const {
145 switch (op_) {
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();
158 }
159 return Token::ILLEGAL;
160}
161
162
163bool FunctionLiteral::AllowsLazyCompilation() {
164 return scope()->AllowsLazyCompilation();
165}
166
167
168ObjectLiteral::Property::Property(Literal* key, Expression* value) {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000169 emit_store_ = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000170 key_ = key;
171 value_ = value;
172 Object* k = *key->handle();
173 if (k->IsSymbol() && Heap::Proto_symbol()->Equals(String::cast(k))) {
174 kind_ = PROTOTYPE;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000175 } else if (value_->AsMaterializedLiteral() != NULL) {
176 kind_ = MATERIALIZED_LITERAL;
177 } else if (value_->AsLiteral() != NULL) {
178 kind_ = CONSTANT;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000179 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000180 kind_ = COMPUTED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000181 }
182}
183
184
185ObjectLiteral::Property::Property(bool is_getter, FunctionLiteral* value) {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000186 emit_store_ = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000187 key_ = new Literal(value->name());
188 value_ = value;
189 kind_ = is_getter ? GETTER : SETTER;
190}
191
192
ager@chromium.org3811b432009-10-28 14:53:37 +0000193bool ObjectLiteral::Property::IsCompileTimeValue() {
194 return kind_ == CONSTANT ||
195 (kind_ == MATERIALIZED_LITERAL &&
196 CompileTimeValue::IsCompileTimeValue(value_));
197}
198
199
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000200void ObjectLiteral::Property::set_emit_store(bool emit_store) {
201 emit_store_ = emit_store;
202}
203
204
205bool ObjectLiteral::Property::emit_store() {
206 return emit_store_;
207}
208
209
210bool IsEqualString(void* first, void* second) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000211 ASSERT((*reinterpret_cast<String**>(first))->IsString());
212 ASSERT((*reinterpret_cast<String**>(second))->IsString());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000213 Handle<String> h1(reinterpret_cast<String**>(first));
214 Handle<String> h2(reinterpret_cast<String**>(second));
215 return (*h1)->Equals(*h2);
216}
217
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000218
219bool IsEqualNumber(void* first, void* second) {
220 ASSERT((*reinterpret_cast<Object**>(first))->IsNumber());
221 ASSERT((*reinterpret_cast<Object**>(second))->IsNumber());
222
223 Handle<Object> h1(reinterpret_cast<Object**>(first));
224 Handle<Object> h2(reinterpret_cast<Object**>(second));
225 if (h1->IsSmi()) {
226 return h2->IsSmi() && *h1 == *h2;
227 }
228 if (h2->IsSmi()) return false;
229 Handle<HeapNumber> n1 = Handle<HeapNumber>::cast(h1);
230 Handle<HeapNumber> n2 = Handle<HeapNumber>::cast(h2);
231 ASSERT(isfinite(n1->value()));
232 ASSERT(isfinite(n2->value()));
233 return n1->value() == n2->value();
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000234}
235
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000236
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000237void ObjectLiteral::CalculateEmitStore() {
238 HashMap properties(&IsEqualString);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000239 HashMap elements(&IsEqualNumber);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000240 for (int i = this->properties()->length() - 1; i >= 0; i--) {
241 ObjectLiteral::Property* property = this->properties()->at(i);
242 Literal* literal = property->key();
243 Handle<Object> handle = literal->handle();
244
245 if (handle->IsNull()) {
246 continue;
247 }
248
249 uint32_t hash;
250 HashMap* table;
251 void* key;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000252 if (handle->IsSymbol()) {
253 Handle<String> name(String::cast(*handle));
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000254 if (name->AsArrayIndex(&hash)) {
255 Handle<Object> key_handle = Factory::NewNumberFromUint(hash);
256 key = key_handle.location();
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000257 table = &elements;
258 } else {
259 key = name.location();
260 hash = name->Hash();
261 table = &properties;
262 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000263 } else if (handle->ToArrayIndex(&hash)) {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000264 key = handle.location();
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000265 table = &elements;
266 } else {
267 ASSERT(handle->IsNumber());
268 double num = handle->Number();
269 char arr[100];
270 Vector<char> buffer(arr, ARRAY_SIZE(arr));
271 const char* str = DoubleToCString(num, buffer);
272 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
273 key = name.location();
274 hash = name->Hash();
275 table = &properties;
276 }
277 // If the key of a computed property is in the table, do not emit
278 // a store for the property later.
279 if (property->kind() == ObjectLiteral::Property::COMPUTED) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000280 if (table->Lookup(key, hash, false) != NULL) {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000281 property->set_emit_store(false);
282 }
283 }
284 // Add key to the table.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000285 table->Lookup(key, hash, true);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000286 }
287}
288
289
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000290void TargetCollector::AddTarget(BreakTarget* target) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000291 // Add the label to the collector, but discard duplicates.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000292 int length = targets_->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000293 for (int i = 0; i < length; i++) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000294 if (targets_->at(i) == target) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000295 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000296 targets_->Add(target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000297}
298
299
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000300bool Expression::GuaranteedSmiResult() {
301 BinaryOperation* node = AsBinaryOperation();
302 if (node == NULL) return false;
303 Token::Value op = node->op();
304 switch (op) {
305 case Token::COMMA:
306 case Token::OR:
307 case Token::AND:
308 case Token::ADD:
309 case Token::SUB:
310 case Token::MUL:
311 case Token::DIV:
312 case Token::MOD:
313 case Token::BIT_XOR:
314 case Token::SHL:
315 return false;
316 break;
317 case Token::BIT_OR:
318 case Token::BIT_AND: {
319 Literal* left = node->left()->AsLiteral();
320 Literal* right = node->right()->AsLiteral();
321 if (left != NULL && left->handle()->IsSmi()) {
322 int value = Smi::cast(*left->handle())->value();
323 if (op == Token::BIT_OR && ((value & 0xc0000000) == 0xc0000000)) {
324 // Result of bitwise or is always a negative Smi.
325 return true;
326 }
327 if (op == Token::BIT_AND && ((value & 0xc0000000) == 0)) {
328 // Result of bitwise and is always a positive Smi.
329 return true;
330 }
331 }
332 if (right != NULL && right->handle()->IsSmi()) {
333 int value = Smi::cast(*right->handle())->value();
334 if (op == Token::BIT_OR && ((value & 0xc0000000) == 0xc0000000)) {
335 // Result of bitwise or is always a negative Smi.
336 return true;
337 }
338 if (op == Token::BIT_AND && ((value & 0xc0000000) == 0)) {
339 // Result of bitwise and is always a positive Smi.
340 return true;
341 }
342 }
343 return false;
344 break;
345 }
346 case Token::SAR:
347 case Token::SHR: {
348 Literal* right = node->right()->AsLiteral();
349 if (right != NULL && right->handle()->IsSmi()) {
350 int value = Smi::cast(*right->handle())->value();
351 if ((value & 0x1F) > 1 ||
352 (op == Token::SAR && (value & 0x1F) == 1)) {
353 return true;
354 }
355 }
356 return false;
357 break;
358 }
359 default:
360 UNREACHABLE();
361 break;
362 }
363 return false;
364}
365
ricow@chromium.org65fae842010-08-25 15:26:24 +0000366
367void Expression::CopyAnalysisResultsFrom(Expression* other) {
368 bitfields_ = other->bitfields_;
369 type_ = other->type_;
370}
371
372
373bool UnaryOperation::ResultOverwriteAllowed() {
374 switch (op_) {
375 case Token::BIT_NOT:
376 case Token::SUB:
377 return true;
378 default:
379 return false;
380 }
381}
382
383
384bool BinaryOperation::ResultOverwriteAllowed() {
385 switch (op_) {
386 case Token::COMMA:
387 case Token::OR:
388 case Token::AND:
389 return false;
390 case Token::BIT_OR:
391 case Token::BIT_XOR:
392 case Token::BIT_AND:
393 case Token::SHL:
394 case Token::SAR:
395 case Token::SHR:
396 case Token::ADD:
397 case Token::SUB:
398 case Token::MUL:
399 case Token::DIV:
400 case Token::MOD:
401 return true;
402 default:
403 UNREACHABLE();
404 }
405 return false;
406}
407
408
409BinaryOperation::BinaryOperation(Assignment* assignment) {
410 ASSERT(assignment->is_compound());
411 op_ = assignment->binary_op();
412 left_ = assignment->target();
413 right_ = assignment->value();
414 pos_ = assignment->position();
415 CopyAnalysisResultsFrom(assignment);
416}
417
418
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000419// ----------------------------------------------------------------------------
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000420// Inlining support
421
422bool Block::IsInlineable() const {
423 const int count = statements_.length();
424 for (int i = 0; i < count; ++i) {
425 if (!statements_[i]->IsInlineable()) return false;
426 }
427 return true;
428}
429
430
431bool ExpressionStatement::IsInlineable() const {
432 return expression()->IsInlineable();
433}
434
435
436bool IfStatement::IsInlineable() const {
437 return condition()->IsInlineable() && then_statement()->IsInlineable() &&
438 else_statement()->IsInlineable();
439}
440
441
442bool ReturnStatement::IsInlineable() const {
443 return expression()->IsInlineable();
444}
445
446
447bool Conditional::IsInlineable() const {
448 return condition()->IsInlineable() && then_expression()->IsInlineable() &&
449 else_expression()->IsInlineable();
450}
451
452
453bool VariableProxy::IsInlineable() const {
454 return var()->is_global() || var()->IsStackAllocated();
455}
456
457
458bool Assignment::IsInlineable() const {
459 return target()->IsInlineable() && value()->IsInlineable();
460}
461
462
463bool Property::IsInlineable() const {
464 return obj()->IsInlineable() && key()->IsInlineable();
465}
466
467
468bool Call::IsInlineable() const {
469 if (!expression()->IsInlineable()) return false;
470 const int count = arguments()->length();
471 for (int i = 0; i < count; ++i) {
472 if (!arguments()->at(i)->IsInlineable()) return false;
473 }
474 return true;
475}
476
477
478bool CallNew::IsInlineable() const {
479 if (!expression()->IsInlineable()) return false;
480 const int count = arguments()->length();
481 for (int i = 0; i < count; ++i) {
482 if (!arguments()->at(i)->IsInlineable()) return false;
483 }
484 return true;
485}
486
487
488bool CallRuntime::IsInlineable() const {
489 const int count = arguments()->length();
490 for (int i = 0; i < count; ++i) {
491 if (!arguments()->at(i)->IsInlineable()) return false;
492 }
493 return true;
494}
495
496
497bool UnaryOperation::IsInlineable() const {
498 return expression()->IsInlineable();
499}
500
501
502bool BinaryOperation::IsInlineable() const {
503 return left()->IsInlineable() && right()->IsInlineable();
504}
505
506
507bool CompareOperation::IsInlineable() const {
508 return left()->IsInlineable() && right()->IsInlineable();
509}
510
511
512bool CompareToNull::IsInlineable() const {
513 return expression()->IsInlineable();
514}
515
516
517bool CountOperation::IsInlineable() const {
518 return expression()->IsInlineable();
519}
520
521
522// ----------------------------------------------------------------------------
523// Recording of type feedback
524
525void Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
526 // Record type feedback from the oracle in the AST.
527 is_monomorphic_ = oracle->LoadIsMonomorphic(this);
528 if (key()->IsPropertyName()) {
529 if (oracle->LoadIsBuiltin(this, Builtins::LoadIC_ArrayLength)) {
530 is_array_length_ = true;
ager@chromium.org378b34e2011-01-28 08:04:38 +0000531 } else if (oracle->LoadIsBuiltin(this, Builtins::LoadIC_StringLength)) {
532 is_string_length_ = true;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000533 } else if (oracle->LoadIsBuiltin(this,
534 Builtins::LoadIC_FunctionPrototype)) {
535 is_function_prototype_ = true;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000536 } else {
537 Literal* lit_key = key()->AsLiteral();
538 ASSERT(lit_key != NULL && lit_key->handle()->IsString());
539 Handle<String> name = Handle<String>::cast(lit_key->handle());
540 ZoneMapList* types = oracle->LoadReceiverTypes(this, name);
541 receiver_types_ = types;
542 }
543 } else if (is_monomorphic_) {
544 monomorphic_receiver_type_ = oracle->LoadMonomorphicReceiverType(this);
545 }
546}
547
548
549void Assignment::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
550 Property* prop = target()->AsProperty();
551 ASSERT(prop != NULL);
552 is_monomorphic_ = oracle->StoreIsMonomorphic(this);
553 if (prop->key()->IsPropertyName()) {
554 Literal* lit_key = prop->key()->AsLiteral();
555 ASSERT(lit_key != NULL && lit_key->handle()->IsString());
556 Handle<String> name = Handle<String>::cast(lit_key->handle());
557 ZoneMapList* types = oracle->StoreReceiverTypes(this, name);
558 receiver_types_ = types;
559 } else if (is_monomorphic_) {
560 // Record receiver type for monomorphic keyed loads.
561 monomorphic_receiver_type_ = oracle->StoreMonomorphicReceiverType(this);
562 }
563}
564
565
566void CaseClause::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
567 TypeInfo info = oracle->SwitchType(this);
568 if (info.IsSmi()) {
569 compare_type_ = SMI_ONLY;
570 } else if (info.IsNonPrimitive()) {
571 compare_type_ = OBJECT_ONLY;
572 } else {
573 ASSERT(compare_type_ == NONE);
574 }
575}
576
577
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000578static bool CanCallWithoutIC(Handle<JSFunction> target, int arity) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000579 SharedFunctionInfo* info = target->shared();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000580 // If the number of formal parameters of the target function does
581 // not match the number of arguments we're passing, we don't want to
582 // deal with it. Otherwise, we can call it directly.
583 return !target->NeedsArgumentsAdaption() ||
584 info->formal_parameter_count() == arity;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000585}
586
587
588bool Call::ComputeTarget(Handle<Map> type, Handle<String> name) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000589 if (check_type_ == RECEIVER_MAP_CHECK) {
590 // For primitive checks the holder is set up to point to the
591 // corresponding prototype object, i.e. one step of the algorithm
592 // below has been already performed.
593 // For non-primitive checks we clear it to allow computing targets
594 // for polymorphic calls.
595 holder_ = Handle<JSObject>::null();
596 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000597 while (true) {
598 LookupResult lookup;
599 type->LookupInDescriptors(NULL, *name, &lookup);
600 // If the function wasn't found directly in the map, we start
601 // looking upwards through the prototype chain.
602 if (!lookup.IsFound() && type->prototype()->IsJSObject()) {
603 holder_ = Handle<JSObject>(JSObject::cast(type->prototype()));
604 type = Handle<Map>(holder()->map());
605 } else if (lookup.IsProperty() && lookup.type() == CONSTANT_FUNCTION) {
606 target_ = Handle<JSFunction>(lookup.GetConstantFunctionFromMap(*type));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000607 return CanCallWithoutIC(target_, arguments()->length());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000608 } else {
609 return false;
610 }
611 }
612}
613
614
615bool Call::ComputeGlobalTarget(Handle<GlobalObject> global,
616 Handle<String> name) {
617 target_ = Handle<JSFunction>::null();
618 cell_ = Handle<JSGlobalPropertyCell>::null();
619 LookupResult lookup;
620 global->Lookup(*name, &lookup);
621 if (lookup.IsProperty() && lookup.type() == NORMAL) {
622 cell_ = Handle<JSGlobalPropertyCell>(global->GetPropertyCell(&lookup));
623 if (cell_->value()->IsJSFunction()) {
624 Handle<JSFunction> candidate(JSFunction::cast(cell_->value()));
625 // If the function is in new space we assume it's more likely to
626 // change and thus prefer the general IC code.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000627 if (!Heap::InNewSpace(*candidate) &&
628 CanCallWithoutIC(candidate, arguments()->length())) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000629 target_ = candidate;
630 return true;
631 }
632 }
633 }
634 return false;
635}
636
637
638void Call::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
639 Property* property = expression()->AsProperty();
640 ASSERT(property != NULL);
641 // Specialize for the receiver types seen at runtime.
642 Literal* key = property->key()->AsLiteral();
643 ASSERT(key != NULL && key->handle()->IsString());
644 Handle<String> name = Handle<String>::cast(key->handle());
645 receiver_types_ = oracle->CallReceiverTypes(this, name);
646#ifdef DEBUG
647 if (FLAG_enable_slow_asserts) {
648 if (receiver_types_ != NULL) {
649 int length = receiver_types_->length();
650 for (int i = 0; i < length; i++) {
651 Handle<Map> map = receiver_types_->at(i);
652 ASSERT(!map.is_null() && *map != NULL);
653 }
654 }
655 }
656#endif
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000657 is_monomorphic_ = oracle->CallIsMonomorphic(this);
658 check_type_ = oracle->GetCallCheckType(this);
659 if (is_monomorphic_) {
660 Handle<Map> map;
661 if (receiver_types_ != NULL && receiver_types_->length() > 0) {
662 ASSERT(check_type_ == RECEIVER_MAP_CHECK);
663 map = receiver_types_->at(0);
664 } else {
665 ASSERT(check_type_ != RECEIVER_MAP_CHECK);
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000666 holder_ = Handle<JSObject>(
667 oracle->GetPrototypeForPrimitiveCheck(check_type_));
668 map = Handle<Map>(holder_->map());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000669 }
670 is_monomorphic_ = ComputeTarget(map, name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000671 }
672}
673
674
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000675void CompareOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
ager@chromium.org378b34e2011-01-28 08:04:38 +0000676 TypeInfo info = oracle->CompareType(this);
677 if (info.IsSmi()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000678 compare_type_ = SMI_ONLY;
ager@chromium.org378b34e2011-01-28 08:04:38 +0000679 } else if (info.IsNonPrimitive()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000680 compare_type_ = OBJECT_ONLY;
681 } else {
682 ASSERT(compare_type_ == NONE);
683 }
684}
685
686
687// ----------------------------------------------------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000688// Implementation of AstVisitor
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000689
lrn@chromium.org25156de2010-04-06 13:10:27 +0000690bool AstVisitor::CheckStackOverflow() {
691 if (stack_overflow_) return true;
692 StackLimitCheck check;
693 if (!check.HasOverflowed()) return false;
694 return (stack_overflow_ = true);
695}
696
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000697
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000698void AstVisitor::VisitDeclarations(ZoneList<Declaration*>* declarations) {
699 for (int i = 0; i < declarations->length(); i++) {
700 Visit(declarations->at(i));
701 }
702}
703
704
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000705void AstVisitor::VisitStatements(ZoneList<Statement*>* statements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000706 for (int i = 0; i < statements->length(); i++) {
707 Visit(statements->at(i));
708 }
709}
710
711
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000712void AstVisitor::VisitExpressions(ZoneList<Expression*>* expressions) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000713 for (int i = 0; i < expressions->length(); i++) {
714 // The variable statement visiting code may pass NULL expressions
715 // to this code. Maybe this should be handled by introducing an
716 // undefined expression or literal? Revisit this code if this
717 // changes
718 Expression* expression = expressions->at(i);
719 if (expression != NULL) Visit(expression);
720 }
721}
722
723
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000724// ----------------------------------------------------------------------------
725// Regular expressions
726
727#define MAKE_ACCEPT(Name) \
728 void* RegExp##Name::Accept(RegExpVisitor* visitor, void* data) { \
729 return visitor->Visit##Name(this, data); \
730 }
731FOR_EACH_REG_EXP_TREE_TYPE(MAKE_ACCEPT)
732#undef MAKE_ACCEPT
733
734#define MAKE_TYPE_CASE(Name) \
735 RegExp##Name* RegExpTree::As##Name() { \
736 return NULL; \
737 } \
738 bool RegExpTree::Is##Name() { return false; }
739FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE)
740#undef MAKE_TYPE_CASE
741
742#define MAKE_TYPE_CASE(Name) \
743 RegExp##Name* RegExp##Name::As##Name() { \
744 return this; \
745 } \
746 bool RegExp##Name::Is##Name() { return true; }
747FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE)
748#undef MAKE_TYPE_CASE
749
750RegExpEmpty RegExpEmpty::kInstance;
751
752
ager@chromium.org32912102009-01-16 10:38:43 +0000753static Interval ListCaptureRegisters(ZoneList<RegExpTree*>* children) {
754 Interval result = Interval::Empty();
755 for (int i = 0; i < children->length(); i++)
756 result = result.Union(children->at(i)->CaptureRegisters());
757 return result;
758}
759
760
761Interval RegExpAlternative::CaptureRegisters() {
762 return ListCaptureRegisters(nodes());
763}
764
765
766Interval RegExpDisjunction::CaptureRegisters() {
767 return ListCaptureRegisters(alternatives());
768}
769
770
771Interval RegExpLookahead::CaptureRegisters() {
772 return body()->CaptureRegisters();
773}
774
775
776Interval RegExpCapture::CaptureRegisters() {
777 Interval self(StartRegister(index()), EndRegister(index()));
778 return self.Union(body()->CaptureRegisters());
779}
780
781
782Interval RegExpQuantifier::CaptureRegisters() {
783 return body()->CaptureRegisters();
784}
785
786
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000787bool RegExpAssertion::IsAnchoredAtStart() {
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000788 return type() == RegExpAssertion::START_OF_INPUT;
789}
790
791
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000792bool RegExpAssertion::IsAnchoredAtEnd() {
793 return type() == RegExpAssertion::END_OF_INPUT;
794}
795
796
797bool RegExpAlternative::IsAnchoredAtStart() {
iposva@chromium.org245aa852009-02-10 00:49:54 +0000798 ZoneList<RegExpTree*>* nodes = this->nodes();
799 for (int i = 0; i < nodes->length(); i++) {
800 RegExpTree* node = nodes->at(i);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000801 if (node->IsAnchoredAtStart()) { return true; }
iposva@chromium.org245aa852009-02-10 00:49:54 +0000802 if (node->max_match() > 0) { return false; }
803 }
804 return false;
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000805}
806
807
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000808bool RegExpAlternative::IsAnchoredAtEnd() {
809 ZoneList<RegExpTree*>* nodes = this->nodes();
810 for (int i = nodes->length() - 1; i >= 0; i--) {
811 RegExpTree* node = nodes->at(i);
812 if (node->IsAnchoredAtEnd()) { return true; }
813 if (node->max_match() > 0) { return false; }
814 }
815 return false;
816}
817
818
819bool RegExpDisjunction::IsAnchoredAtStart() {
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000820 ZoneList<RegExpTree*>* alternatives = this->alternatives();
821 for (int i = 0; i < alternatives->length(); i++) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000822 if (!alternatives->at(i)->IsAnchoredAtStart())
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000823 return false;
824 }
825 return true;
826}
827
828
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000829bool RegExpDisjunction::IsAnchoredAtEnd() {
830 ZoneList<RegExpTree*>* alternatives = this->alternatives();
831 for (int i = 0; i < alternatives->length(); i++) {
832 if (!alternatives->at(i)->IsAnchoredAtEnd())
833 return false;
834 }
835 return true;
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000836}
837
838
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000839bool RegExpLookahead::IsAnchoredAtStart() {
840 return is_positive() && body()->IsAnchoredAtStart();
841}
842
843
844bool RegExpCapture::IsAnchoredAtStart() {
845 return body()->IsAnchoredAtStart();
846}
847
848
849bool RegExpCapture::IsAnchoredAtEnd() {
850 return body()->IsAnchoredAtEnd();
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000851}
852
853
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000854// Convert regular expression trees to a simple sexp representation.
855// This representation should be different from the input grammar
856// in as many cases as possible, to make it more difficult for incorrect
857// parses to look as correct ones which is likely if the input and
858// output formats are alike.
859class RegExpUnparser: public RegExpVisitor {
860 public:
861 RegExpUnparser();
862 void VisitCharacterRange(CharacterRange that);
863 SmartPointer<const char> ToString() { return stream_.ToCString(); }
864#define MAKE_CASE(Name) virtual void* Visit##Name(RegExp##Name*, void* data);
865 FOR_EACH_REG_EXP_TREE_TYPE(MAKE_CASE)
866#undef MAKE_CASE
867 private:
868 StringStream* stream() { return &stream_; }
869 HeapStringAllocator alloc_;
870 StringStream stream_;
871};
872
873
874RegExpUnparser::RegExpUnparser() : stream_(&alloc_) {
875}
876
877
878void* RegExpUnparser::VisitDisjunction(RegExpDisjunction* that, void* data) {
879 stream()->Add("(|");
880 for (int i = 0; i < that->alternatives()->length(); i++) {
881 stream()->Add(" ");
882 that->alternatives()->at(i)->Accept(this, data);
883 }
884 stream()->Add(")");
885 return NULL;
886}
887
888
889void* RegExpUnparser::VisitAlternative(RegExpAlternative* that, void* data) {
890 stream()->Add("(:");
891 for (int i = 0; i < that->nodes()->length(); i++) {
892 stream()->Add(" ");
893 that->nodes()->at(i)->Accept(this, data);
894 }
895 stream()->Add(")");
896 return NULL;
897}
898
899
900void RegExpUnparser::VisitCharacterRange(CharacterRange that) {
901 stream()->Add("%k", that.from());
902 if (!that.IsSingleton()) {
903 stream()->Add("-%k", that.to());
904 }
905}
906
907
908
909void* RegExpUnparser::VisitCharacterClass(RegExpCharacterClass* that,
910 void* data) {
911 if (that->is_negated())
912 stream()->Add("^");
913 stream()->Add("[");
914 for (int i = 0; i < that->ranges()->length(); i++) {
915 if (i > 0) stream()->Add(" ");
916 VisitCharacterRange(that->ranges()->at(i));
917 }
918 stream()->Add("]");
919 return NULL;
920}
921
922
923void* RegExpUnparser::VisitAssertion(RegExpAssertion* that, void* data) {
924 switch (that->type()) {
925 case RegExpAssertion::START_OF_INPUT:
926 stream()->Add("@^i");
927 break;
928 case RegExpAssertion::END_OF_INPUT:
929 stream()->Add("@$i");
930 break;
931 case RegExpAssertion::START_OF_LINE:
932 stream()->Add("@^l");
933 break;
934 case RegExpAssertion::END_OF_LINE:
935 stream()->Add("@$l");
936 break;
937 case RegExpAssertion::BOUNDARY:
938 stream()->Add("@b");
939 break;
940 case RegExpAssertion::NON_BOUNDARY:
941 stream()->Add("@B");
942 break;
943 }
944 return NULL;
945}
946
947
948void* RegExpUnparser::VisitAtom(RegExpAtom* that, void* data) {
949 stream()->Add("'");
950 Vector<const uc16> chardata = that->data();
951 for (int i = 0; i < chardata.length(); i++) {
952 stream()->Add("%k", chardata[i]);
953 }
954 stream()->Add("'");
955 return NULL;
956}
957
958
959void* RegExpUnparser::VisitText(RegExpText* that, void* data) {
960 if (that->elements()->length() == 1) {
961 that->elements()->at(0).data.u_atom->Accept(this, data);
962 } else {
963 stream()->Add("(!");
964 for (int i = 0; i < that->elements()->length(); i++) {
965 stream()->Add(" ");
966 that->elements()->at(i).data.u_atom->Accept(this, data);
967 }
968 stream()->Add(")");
969 }
970 return NULL;
971}
972
973
974void* RegExpUnparser::VisitQuantifier(RegExpQuantifier* that, void* data) {
975 stream()->Add("(# %i ", that->min());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000976 if (that->max() == RegExpTree::kInfinity) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000977 stream()->Add("- ");
978 } else {
979 stream()->Add("%i ", that->max());
980 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000981 stream()->Add(that->is_greedy() ? "g " : that->is_possessive() ? "p " : "n ");
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000982 that->body()->Accept(this, data);
983 stream()->Add(")");
984 return NULL;
985}
986
987
988void* RegExpUnparser::VisitCapture(RegExpCapture* that, void* data) {
989 stream()->Add("(^ ");
990 that->body()->Accept(this, data);
991 stream()->Add(")");
992 return NULL;
993}
994
995
996void* RegExpUnparser::VisitLookahead(RegExpLookahead* that, void* data) {
997 stream()->Add("(-> ");
998 stream()->Add(that->is_positive() ? "+ " : "- ");
999 that->body()->Accept(this, data);
1000 stream()->Add(")");
1001 return NULL;
1002}
1003
1004
1005void* RegExpUnparser::VisitBackReference(RegExpBackReference* that,
1006 void* data) {
1007 stream()->Add("(<- %i)", that->index());
1008 return NULL;
1009}
1010
1011
1012void* RegExpUnparser::VisitEmpty(RegExpEmpty* that, void* data) {
1013 stream()->Put('%');
1014 return NULL;
1015}
1016
1017
1018SmartPointer<const char> RegExpTree::ToString() {
1019 RegExpUnparser unparser;
1020 Accept(&unparser, NULL);
1021 return unparser.ToString();
1022}
1023
1024
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001025RegExpDisjunction::RegExpDisjunction(ZoneList<RegExpTree*>* alternatives)
1026 : alternatives_(alternatives) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001027 ASSERT(alternatives->length() > 1);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001028 RegExpTree* first_alternative = alternatives->at(0);
1029 min_match_ = first_alternative->min_match();
1030 max_match_ = first_alternative->max_match();
1031 for (int i = 1; i < alternatives->length(); i++) {
1032 RegExpTree* alternative = alternatives->at(i);
1033 min_match_ = Min(min_match_, alternative->min_match());
1034 max_match_ = Max(max_match_, alternative->max_match());
1035 }
1036}
1037
1038
1039RegExpAlternative::RegExpAlternative(ZoneList<RegExpTree*>* nodes)
1040 : nodes_(nodes) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001041 ASSERT(nodes->length() > 1);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001042 min_match_ = 0;
1043 max_match_ = 0;
1044 for (int i = 0; i < nodes->length(); i++) {
1045 RegExpTree* node = nodes->at(i);
1046 min_match_ += node->min_match();
1047 int node_max_match = node->max_match();
1048 if (kInfinity - max_match_ < node_max_match) {
1049 max_match_ = kInfinity;
1050 } else {
1051 max_match_ += node->max_match();
1052 }
1053 }
1054}
1055
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001056
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001057CaseClause::CaseClause(Expression* label,
1058 ZoneList<Statement*>* statements,
1059 int pos)
1060 : label_(label),
1061 statements_(statements),
1062 position_(pos),
1063 compare_type_(NONE) {}
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +00001064
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001065} } // namespace v8::internal