blob: e8b3e034509c4cba20f40d360cbf0f07f3b2996e [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
218bool IsEqualSmi(void* first, void* second) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000219 ASSERT((*reinterpret_cast<Smi**>(first))->IsSmi());
220 ASSERT((*reinterpret_cast<Smi**>(second))->IsSmi());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000221 Handle<Smi> h1(reinterpret_cast<Smi**>(first));
222 Handle<Smi> h2(reinterpret_cast<Smi**>(second));
223 return (*h1)->value() == (*h2)->value();
224}
225
226void ObjectLiteral::CalculateEmitStore() {
227 HashMap properties(&IsEqualString);
228 HashMap elements(&IsEqualSmi);
229 for (int i = this->properties()->length() - 1; i >= 0; i--) {
230 ObjectLiteral::Property* property = this->properties()->at(i);
231 Literal* literal = property->key();
232 Handle<Object> handle = literal->handle();
233
234 if (handle->IsNull()) {
235 continue;
236 }
237
238 uint32_t hash;
239 HashMap* table;
240 void* key;
241 uint32_t index;
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000242 Smi* smi_key_location;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000243 if (handle->IsSymbol()) {
244 Handle<String> name(String::cast(*handle));
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000245 if (name->AsArrayIndex(&index)) {
246 smi_key_location = Smi::FromInt(index);
247 key = &smi_key_location;
248 hash = index;
249 table = &elements;
250 } else {
251 key = name.location();
252 hash = name->Hash();
253 table = &properties;
254 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000255 } else if (handle->ToArrayIndex(&index)) {
256 key = handle.location();
257 hash = index;
258 table = &elements;
259 } else {
260 ASSERT(handle->IsNumber());
261 double num = handle->Number();
262 char arr[100];
263 Vector<char> buffer(arr, ARRAY_SIZE(arr));
264 const char* str = DoubleToCString(num, buffer);
265 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
266 key = name.location();
267 hash = name->Hash();
268 table = &properties;
269 }
270 // If the key of a computed property is in the table, do not emit
271 // a store for the property later.
272 if (property->kind() == ObjectLiteral::Property::COMPUTED) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000273 if (table->Lookup(key, hash, false) != NULL) {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000274 property->set_emit_store(false);
275 }
276 }
277 // Add key to the table.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000278 table->Lookup(key, hash, true);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000279 }
280}
281
282
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000283void TargetCollector::AddTarget(BreakTarget* target) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000284 // Add the label to the collector, but discard duplicates.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000285 int length = targets_->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000286 for (int i = 0; i < length; i++) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000287 if (targets_->at(i) == target) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000288 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000289 targets_->Add(target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000290}
291
292
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000293bool Expression::GuaranteedSmiResult() {
294 BinaryOperation* node = AsBinaryOperation();
295 if (node == NULL) return false;
296 Token::Value op = node->op();
297 switch (op) {
298 case Token::COMMA:
299 case Token::OR:
300 case Token::AND:
301 case Token::ADD:
302 case Token::SUB:
303 case Token::MUL:
304 case Token::DIV:
305 case Token::MOD:
306 case Token::BIT_XOR:
307 case Token::SHL:
308 return false;
309 break;
310 case Token::BIT_OR:
311 case Token::BIT_AND: {
312 Literal* left = node->left()->AsLiteral();
313 Literal* right = node->right()->AsLiteral();
314 if (left != NULL && left->handle()->IsSmi()) {
315 int value = Smi::cast(*left->handle())->value();
316 if (op == Token::BIT_OR && ((value & 0xc0000000) == 0xc0000000)) {
317 // Result of bitwise or is always a negative Smi.
318 return true;
319 }
320 if (op == Token::BIT_AND && ((value & 0xc0000000) == 0)) {
321 // Result of bitwise and is always a positive Smi.
322 return true;
323 }
324 }
325 if (right != NULL && right->handle()->IsSmi()) {
326 int value = Smi::cast(*right->handle())->value();
327 if (op == Token::BIT_OR && ((value & 0xc0000000) == 0xc0000000)) {
328 // Result of bitwise or is always a negative Smi.
329 return true;
330 }
331 if (op == Token::BIT_AND && ((value & 0xc0000000) == 0)) {
332 // Result of bitwise and is always a positive Smi.
333 return true;
334 }
335 }
336 return false;
337 break;
338 }
339 case Token::SAR:
340 case Token::SHR: {
341 Literal* right = node->right()->AsLiteral();
342 if (right != NULL && right->handle()->IsSmi()) {
343 int value = Smi::cast(*right->handle())->value();
344 if ((value & 0x1F) > 1 ||
345 (op == Token::SAR && (value & 0x1F) == 1)) {
346 return true;
347 }
348 }
349 return false;
350 break;
351 }
352 default:
353 UNREACHABLE();
354 break;
355 }
356 return false;
357}
358
ricow@chromium.org65fae842010-08-25 15:26:24 +0000359
360void Expression::CopyAnalysisResultsFrom(Expression* other) {
361 bitfields_ = other->bitfields_;
362 type_ = other->type_;
363}
364
365
366bool UnaryOperation::ResultOverwriteAllowed() {
367 switch (op_) {
368 case Token::BIT_NOT:
369 case Token::SUB:
370 return true;
371 default:
372 return false;
373 }
374}
375
376
377bool BinaryOperation::ResultOverwriteAllowed() {
378 switch (op_) {
379 case Token::COMMA:
380 case Token::OR:
381 case Token::AND:
382 return false;
383 case Token::BIT_OR:
384 case Token::BIT_XOR:
385 case Token::BIT_AND:
386 case Token::SHL:
387 case Token::SAR:
388 case Token::SHR:
389 case Token::ADD:
390 case Token::SUB:
391 case Token::MUL:
392 case Token::DIV:
393 case Token::MOD:
394 return true;
395 default:
396 UNREACHABLE();
397 }
398 return false;
399}
400
401
402BinaryOperation::BinaryOperation(Assignment* assignment) {
403 ASSERT(assignment->is_compound());
404 op_ = assignment->binary_op();
405 left_ = assignment->target();
406 right_ = assignment->value();
407 pos_ = assignment->position();
408 CopyAnalysisResultsFrom(assignment);
409}
410
411
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000412// ----------------------------------------------------------------------------
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000413// Inlining support
414
415bool Block::IsInlineable() const {
416 const int count = statements_.length();
417 for (int i = 0; i < count; ++i) {
418 if (!statements_[i]->IsInlineable()) return false;
419 }
420 return true;
421}
422
423
424bool ExpressionStatement::IsInlineable() const {
425 return expression()->IsInlineable();
426}
427
428
429bool IfStatement::IsInlineable() const {
430 return condition()->IsInlineable() && then_statement()->IsInlineable() &&
431 else_statement()->IsInlineable();
432}
433
434
435bool ReturnStatement::IsInlineable() const {
436 return expression()->IsInlineable();
437}
438
439
440bool Conditional::IsInlineable() const {
441 return condition()->IsInlineable() && then_expression()->IsInlineable() &&
442 else_expression()->IsInlineable();
443}
444
445
446bool VariableProxy::IsInlineable() const {
447 return var()->is_global() || var()->IsStackAllocated();
448}
449
450
451bool Assignment::IsInlineable() const {
452 return target()->IsInlineable() && value()->IsInlineable();
453}
454
455
456bool Property::IsInlineable() const {
457 return obj()->IsInlineable() && key()->IsInlineable();
458}
459
460
461bool Call::IsInlineable() const {
462 if (!expression()->IsInlineable()) return false;
463 const int count = arguments()->length();
464 for (int i = 0; i < count; ++i) {
465 if (!arguments()->at(i)->IsInlineable()) return false;
466 }
467 return true;
468}
469
470
471bool CallNew::IsInlineable() const {
472 if (!expression()->IsInlineable()) return false;
473 const int count = arguments()->length();
474 for (int i = 0; i < count; ++i) {
475 if (!arguments()->at(i)->IsInlineable()) return false;
476 }
477 return true;
478}
479
480
481bool CallRuntime::IsInlineable() const {
482 const int count = arguments()->length();
483 for (int i = 0; i < count; ++i) {
484 if (!arguments()->at(i)->IsInlineable()) return false;
485 }
486 return true;
487}
488
489
490bool UnaryOperation::IsInlineable() const {
491 return expression()->IsInlineable();
492}
493
494
495bool BinaryOperation::IsInlineable() const {
496 return left()->IsInlineable() && right()->IsInlineable();
497}
498
499
500bool CompareOperation::IsInlineable() const {
501 return left()->IsInlineable() && right()->IsInlineable();
502}
503
504
505bool CompareToNull::IsInlineable() const {
506 return expression()->IsInlineable();
507}
508
509
510bool CountOperation::IsInlineable() const {
511 return expression()->IsInlineable();
512}
513
514
515// ----------------------------------------------------------------------------
516// Recording of type feedback
517
518void Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
519 // Record type feedback from the oracle in the AST.
520 is_monomorphic_ = oracle->LoadIsMonomorphic(this);
521 if (key()->IsPropertyName()) {
522 if (oracle->LoadIsBuiltin(this, Builtins::LoadIC_ArrayLength)) {
523 is_array_length_ = true;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000524 } else if (oracle->LoadIsBuiltin(this,
525 Builtins::LoadIC_FunctionPrototype)) {
526 is_function_prototype_ = true;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000527 } else {
528 Literal* lit_key = key()->AsLiteral();
529 ASSERT(lit_key != NULL && lit_key->handle()->IsString());
530 Handle<String> name = Handle<String>::cast(lit_key->handle());
531 ZoneMapList* types = oracle->LoadReceiverTypes(this, name);
532 receiver_types_ = types;
533 }
534 } else if (is_monomorphic_) {
535 monomorphic_receiver_type_ = oracle->LoadMonomorphicReceiverType(this);
536 }
537}
538
539
540void Assignment::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
541 Property* prop = target()->AsProperty();
542 ASSERT(prop != NULL);
543 is_monomorphic_ = oracle->StoreIsMonomorphic(this);
544 if (prop->key()->IsPropertyName()) {
545 Literal* lit_key = prop->key()->AsLiteral();
546 ASSERT(lit_key != NULL && lit_key->handle()->IsString());
547 Handle<String> name = Handle<String>::cast(lit_key->handle());
548 ZoneMapList* types = oracle->StoreReceiverTypes(this, name);
549 receiver_types_ = types;
550 } else if (is_monomorphic_) {
551 // Record receiver type for monomorphic keyed loads.
552 monomorphic_receiver_type_ = oracle->StoreMonomorphicReceiverType(this);
553 }
554}
555
556
557void CaseClause::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
558 TypeInfo info = oracle->SwitchType(this);
559 if (info.IsSmi()) {
560 compare_type_ = SMI_ONLY;
561 } else if (info.IsNonPrimitive()) {
562 compare_type_ = OBJECT_ONLY;
563 } else {
564 ASSERT(compare_type_ == NONE);
565 }
566}
567
568
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000569static bool CanCallWithoutIC(Handle<JSFunction> target, int arity) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000570 SharedFunctionInfo* info = target->shared();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000571 // If the number of formal parameters of the target function does
572 // not match the number of arguments we're passing, we don't want to
573 // deal with it. Otherwise, we can call it directly.
574 return !target->NeedsArgumentsAdaption() ||
575 info->formal_parameter_count() == arity;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000576}
577
578
579bool Call::ComputeTarget(Handle<Map> type, Handle<String> name) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000580 if (check_type_ == RECEIVER_MAP_CHECK) {
581 // For primitive checks the holder is set up to point to the
582 // corresponding prototype object, i.e. one step of the algorithm
583 // below has been already performed.
584 // For non-primitive checks we clear it to allow computing targets
585 // for polymorphic calls.
586 holder_ = Handle<JSObject>::null();
587 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000588 while (true) {
589 LookupResult lookup;
590 type->LookupInDescriptors(NULL, *name, &lookup);
591 // If the function wasn't found directly in the map, we start
592 // looking upwards through the prototype chain.
593 if (!lookup.IsFound() && type->prototype()->IsJSObject()) {
594 holder_ = Handle<JSObject>(JSObject::cast(type->prototype()));
595 type = Handle<Map>(holder()->map());
596 } else if (lookup.IsProperty() && lookup.type() == CONSTANT_FUNCTION) {
597 target_ = Handle<JSFunction>(lookup.GetConstantFunctionFromMap(*type));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000598 return CanCallWithoutIC(target_, arguments()->length());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000599 } else {
600 return false;
601 }
602 }
603}
604
605
606bool Call::ComputeGlobalTarget(Handle<GlobalObject> global,
607 Handle<String> name) {
608 target_ = Handle<JSFunction>::null();
609 cell_ = Handle<JSGlobalPropertyCell>::null();
610 LookupResult lookup;
611 global->Lookup(*name, &lookup);
612 if (lookup.IsProperty() && lookup.type() == NORMAL) {
613 cell_ = Handle<JSGlobalPropertyCell>(global->GetPropertyCell(&lookup));
614 if (cell_->value()->IsJSFunction()) {
615 Handle<JSFunction> candidate(JSFunction::cast(cell_->value()));
616 // If the function is in new space we assume it's more likely to
617 // change and thus prefer the general IC code.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000618 if (!Heap::InNewSpace(*candidate) &&
619 CanCallWithoutIC(candidate, arguments()->length())) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000620 target_ = candidate;
621 return true;
622 }
623 }
624 }
625 return false;
626}
627
628
629void Call::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
630 Property* property = expression()->AsProperty();
631 ASSERT(property != NULL);
632 // Specialize for the receiver types seen at runtime.
633 Literal* key = property->key()->AsLiteral();
634 ASSERT(key != NULL && key->handle()->IsString());
635 Handle<String> name = Handle<String>::cast(key->handle());
636 receiver_types_ = oracle->CallReceiverTypes(this, name);
637#ifdef DEBUG
638 if (FLAG_enable_slow_asserts) {
639 if (receiver_types_ != NULL) {
640 int length = receiver_types_->length();
641 for (int i = 0; i < length; i++) {
642 Handle<Map> map = receiver_types_->at(i);
643 ASSERT(!map.is_null() && *map != NULL);
644 }
645 }
646 }
647#endif
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000648 is_monomorphic_ = oracle->CallIsMonomorphic(this);
649 check_type_ = oracle->GetCallCheckType(this);
650 if (is_monomorphic_) {
651 Handle<Map> map;
652 if (receiver_types_ != NULL && receiver_types_->length() > 0) {
653 ASSERT(check_type_ == RECEIVER_MAP_CHECK);
654 map = receiver_types_->at(0);
655 } else {
656 ASSERT(check_type_ != RECEIVER_MAP_CHECK);
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000657 holder_ = Handle<JSObject>(
658 oracle->GetPrototypeForPrimitiveCheck(check_type_));
659 map = Handle<Map>(holder_->map());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000660 }
661 is_monomorphic_ = ComputeTarget(map, name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000662 }
663}
664
665
666void BinaryOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
667 TypeInfo left = oracle->BinaryType(this, TypeFeedbackOracle::LEFT);
668 TypeInfo right = oracle->BinaryType(this, TypeFeedbackOracle::RIGHT);
669 is_smi_only_ = left.IsSmi() && right.IsSmi();
670}
671
672
673void CompareOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
674 TypeInfo left = oracle->CompareType(this, TypeFeedbackOracle::LEFT);
675 TypeInfo right = oracle->CompareType(this, TypeFeedbackOracle::RIGHT);
676 if (left.IsSmi() && right.IsSmi()) {
677 compare_type_ = SMI_ONLY;
678 } else if (left.IsNonPrimitive() && right.IsNonPrimitive()) {
679 compare_type_ = OBJECT_ONLY;
680 } else {
681 ASSERT(compare_type_ == NONE);
682 }
683}
684
685
686// ----------------------------------------------------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000687// Implementation of AstVisitor
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000688
lrn@chromium.org25156de2010-04-06 13:10:27 +0000689bool AstVisitor::CheckStackOverflow() {
690 if (stack_overflow_) return true;
691 StackLimitCheck check;
692 if (!check.HasOverflowed()) return false;
693 return (stack_overflow_ = true);
694}
695
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000696
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000697void AstVisitor::VisitDeclarations(ZoneList<Declaration*>* declarations) {
698 for (int i = 0; i < declarations->length(); i++) {
699 Visit(declarations->at(i));
700 }
701}
702
703
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000704void AstVisitor::VisitStatements(ZoneList<Statement*>* statements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000705 for (int i = 0; i < statements->length(); i++) {
706 Visit(statements->at(i));
707 }
708}
709
710
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000711void AstVisitor::VisitExpressions(ZoneList<Expression*>* expressions) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000712 for (int i = 0; i < expressions->length(); i++) {
713 // The variable statement visiting code may pass NULL expressions
714 // to this code. Maybe this should be handled by introducing an
715 // undefined expression or literal? Revisit this code if this
716 // changes
717 Expression* expression = expressions->at(i);
718 if (expression != NULL) Visit(expression);
719 }
720}
721
722
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000723// ----------------------------------------------------------------------------
724// Regular expressions
725
726#define MAKE_ACCEPT(Name) \
727 void* RegExp##Name::Accept(RegExpVisitor* visitor, void* data) { \
728 return visitor->Visit##Name(this, data); \
729 }
730FOR_EACH_REG_EXP_TREE_TYPE(MAKE_ACCEPT)
731#undef MAKE_ACCEPT
732
733#define MAKE_TYPE_CASE(Name) \
734 RegExp##Name* RegExpTree::As##Name() { \
735 return NULL; \
736 } \
737 bool RegExpTree::Is##Name() { return false; }
738FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE)
739#undef MAKE_TYPE_CASE
740
741#define MAKE_TYPE_CASE(Name) \
742 RegExp##Name* RegExp##Name::As##Name() { \
743 return this; \
744 } \
745 bool RegExp##Name::Is##Name() { return true; }
746FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE)
747#undef MAKE_TYPE_CASE
748
749RegExpEmpty RegExpEmpty::kInstance;
750
751
ager@chromium.org32912102009-01-16 10:38:43 +0000752static Interval ListCaptureRegisters(ZoneList<RegExpTree*>* children) {
753 Interval result = Interval::Empty();
754 for (int i = 0; i < children->length(); i++)
755 result = result.Union(children->at(i)->CaptureRegisters());
756 return result;
757}
758
759
760Interval RegExpAlternative::CaptureRegisters() {
761 return ListCaptureRegisters(nodes());
762}
763
764
765Interval RegExpDisjunction::CaptureRegisters() {
766 return ListCaptureRegisters(alternatives());
767}
768
769
770Interval RegExpLookahead::CaptureRegisters() {
771 return body()->CaptureRegisters();
772}
773
774
775Interval RegExpCapture::CaptureRegisters() {
776 Interval self(StartRegister(index()), EndRegister(index()));
777 return self.Union(body()->CaptureRegisters());
778}
779
780
781Interval RegExpQuantifier::CaptureRegisters() {
782 return body()->CaptureRegisters();
783}
784
785
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000786bool RegExpAssertion::IsAnchoredAtStart() {
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000787 return type() == RegExpAssertion::START_OF_INPUT;
788}
789
790
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000791bool RegExpAssertion::IsAnchoredAtEnd() {
792 return type() == RegExpAssertion::END_OF_INPUT;
793}
794
795
796bool RegExpAlternative::IsAnchoredAtStart() {
iposva@chromium.org245aa852009-02-10 00:49:54 +0000797 ZoneList<RegExpTree*>* nodes = this->nodes();
798 for (int i = 0; i < nodes->length(); i++) {
799 RegExpTree* node = nodes->at(i);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000800 if (node->IsAnchoredAtStart()) { return true; }
iposva@chromium.org245aa852009-02-10 00:49:54 +0000801 if (node->max_match() > 0) { return false; }
802 }
803 return false;
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000804}
805
806
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000807bool RegExpAlternative::IsAnchoredAtEnd() {
808 ZoneList<RegExpTree*>* nodes = this->nodes();
809 for (int i = nodes->length() - 1; i >= 0; i--) {
810 RegExpTree* node = nodes->at(i);
811 if (node->IsAnchoredAtEnd()) { return true; }
812 if (node->max_match() > 0) { return false; }
813 }
814 return false;
815}
816
817
818bool RegExpDisjunction::IsAnchoredAtStart() {
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000819 ZoneList<RegExpTree*>* alternatives = this->alternatives();
820 for (int i = 0; i < alternatives->length(); i++) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000821 if (!alternatives->at(i)->IsAnchoredAtStart())
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000822 return false;
823 }
824 return true;
825}
826
827
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000828bool RegExpDisjunction::IsAnchoredAtEnd() {
829 ZoneList<RegExpTree*>* alternatives = this->alternatives();
830 for (int i = 0; i < alternatives->length(); i++) {
831 if (!alternatives->at(i)->IsAnchoredAtEnd())
832 return false;
833 }
834 return true;
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000835}
836
837
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000838bool RegExpLookahead::IsAnchoredAtStart() {
839 return is_positive() && body()->IsAnchoredAtStart();
840}
841
842
843bool RegExpCapture::IsAnchoredAtStart() {
844 return body()->IsAnchoredAtStart();
845}
846
847
848bool RegExpCapture::IsAnchoredAtEnd() {
849 return body()->IsAnchoredAtEnd();
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000850}
851
852
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000853// Convert regular expression trees to a simple sexp representation.
854// This representation should be different from the input grammar
855// in as many cases as possible, to make it more difficult for incorrect
856// parses to look as correct ones which is likely if the input and
857// output formats are alike.
858class RegExpUnparser: public RegExpVisitor {
859 public:
860 RegExpUnparser();
861 void VisitCharacterRange(CharacterRange that);
862 SmartPointer<const char> ToString() { return stream_.ToCString(); }
863#define MAKE_CASE(Name) virtual void* Visit##Name(RegExp##Name*, void* data);
864 FOR_EACH_REG_EXP_TREE_TYPE(MAKE_CASE)
865#undef MAKE_CASE
866 private:
867 StringStream* stream() { return &stream_; }
868 HeapStringAllocator alloc_;
869 StringStream stream_;
870};
871
872
873RegExpUnparser::RegExpUnparser() : stream_(&alloc_) {
874}
875
876
877void* RegExpUnparser::VisitDisjunction(RegExpDisjunction* that, void* data) {
878 stream()->Add("(|");
879 for (int i = 0; i < that->alternatives()->length(); i++) {
880 stream()->Add(" ");
881 that->alternatives()->at(i)->Accept(this, data);
882 }
883 stream()->Add(")");
884 return NULL;
885}
886
887
888void* RegExpUnparser::VisitAlternative(RegExpAlternative* that, void* data) {
889 stream()->Add("(:");
890 for (int i = 0; i < that->nodes()->length(); i++) {
891 stream()->Add(" ");
892 that->nodes()->at(i)->Accept(this, data);
893 }
894 stream()->Add(")");
895 return NULL;
896}
897
898
899void RegExpUnparser::VisitCharacterRange(CharacterRange that) {
900 stream()->Add("%k", that.from());
901 if (!that.IsSingleton()) {
902 stream()->Add("-%k", that.to());
903 }
904}
905
906
907
908void* RegExpUnparser::VisitCharacterClass(RegExpCharacterClass* that,
909 void* data) {
910 if (that->is_negated())
911 stream()->Add("^");
912 stream()->Add("[");
913 for (int i = 0; i < that->ranges()->length(); i++) {
914 if (i > 0) stream()->Add(" ");
915 VisitCharacterRange(that->ranges()->at(i));
916 }
917 stream()->Add("]");
918 return NULL;
919}
920
921
922void* RegExpUnparser::VisitAssertion(RegExpAssertion* that, void* data) {
923 switch (that->type()) {
924 case RegExpAssertion::START_OF_INPUT:
925 stream()->Add("@^i");
926 break;
927 case RegExpAssertion::END_OF_INPUT:
928 stream()->Add("@$i");
929 break;
930 case RegExpAssertion::START_OF_LINE:
931 stream()->Add("@^l");
932 break;
933 case RegExpAssertion::END_OF_LINE:
934 stream()->Add("@$l");
935 break;
936 case RegExpAssertion::BOUNDARY:
937 stream()->Add("@b");
938 break;
939 case RegExpAssertion::NON_BOUNDARY:
940 stream()->Add("@B");
941 break;
942 }
943 return NULL;
944}
945
946
947void* RegExpUnparser::VisitAtom(RegExpAtom* that, void* data) {
948 stream()->Add("'");
949 Vector<const uc16> chardata = that->data();
950 for (int i = 0; i < chardata.length(); i++) {
951 stream()->Add("%k", chardata[i]);
952 }
953 stream()->Add("'");
954 return NULL;
955}
956
957
958void* RegExpUnparser::VisitText(RegExpText* that, void* data) {
959 if (that->elements()->length() == 1) {
960 that->elements()->at(0).data.u_atom->Accept(this, data);
961 } else {
962 stream()->Add("(!");
963 for (int i = 0; i < that->elements()->length(); i++) {
964 stream()->Add(" ");
965 that->elements()->at(i).data.u_atom->Accept(this, data);
966 }
967 stream()->Add(")");
968 }
969 return NULL;
970}
971
972
973void* RegExpUnparser::VisitQuantifier(RegExpQuantifier* that, void* data) {
974 stream()->Add("(# %i ", that->min());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000975 if (that->max() == RegExpTree::kInfinity) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000976 stream()->Add("- ");
977 } else {
978 stream()->Add("%i ", that->max());
979 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000980 stream()->Add(that->is_greedy() ? "g " : that->is_possessive() ? "p " : "n ");
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000981 that->body()->Accept(this, data);
982 stream()->Add(")");
983 return NULL;
984}
985
986
987void* RegExpUnparser::VisitCapture(RegExpCapture* that, void* data) {
988 stream()->Add("(^ ");
989 that->body()->Accept(this, data);
990 stream()->Add(")");
991 return NULL;
992}
993
994
995void* RegExpUnparser::VisitLookahead(RegExpLookahead* that, void* data) {
996 stream()->Add("(-> ");
997 stream()->Add(that->is_positive() ? "+ " : "- ");
998 that->body()->Accept(this, data);
999 stream()->Add(")");
1000 return NULL;
1001}
1002
1003
1004void* RegExpUnparser::VisitBackReference(RegExpBackReference* that,
1005 void* data) {
1006 stream()->Add("(<- %i)", that->index());
1007 return NULL;
1008}
1009
1010
1011void* RegExpUnparser::VisitEmpty(RegExpEmpty* that, void* data) {
1012 stream()->Put('%');
1013 return NULL;
1014}
1015
1016
1017SmartPointer<const char> RegExpTree::ToString() {
1018 RegExpUnparser unparser;
1019 Accept(&unparser, NULL);
1020 return unparser.ToString();
1021}
1022
1023
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001024RegExpDisjunction::RegExpDisjunction(ZoneList<RegExpTree*>* alternatives)
1025 : alternatives_(alternatives) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001026 ASSERT(alternatives->length() > 1);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001027 RegExpTree* first_alternative = alternatives->at(0);
1028 min_match_ = first_alternative->min_match();
1029 max_match_ = first_alternative->max_match();
1030 for (int i = 1; i < alternatives->length(); i++) {
1031 RegExpTree* alternative = alternatives->at(i);
1032 min_match_ = Min(min_match_, alternative->min_match());
1033 max_match_ = Max(max_match_, alternative->max_match());
1034 }
1035}
1036
1037
1038RegExpAlternative::RegExpAlternative(ZoneList<RegExpTree*>* nodes)
1039 : nodes_(nodes) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001040 ASSERT(nodes->length() > 1);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001041 min_match_ = 0;
1042 max_match_ = 0;
1043 for (int i = 0; i < nodes->length(); i++) {
1044 RegExpTree* node = nodes->at(i);
1045 min_match_ += node->min_match();
1046 int node_max_match = node->max_match();
1047 if (kInfinity - max_match_ < node_max_match) {
1048 max_match_ = kInfinity;
1049 } else {
1050 max_match_ += node->max_match();
1051 }
1052 }
1053}
1054
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001055
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001056CaseClause::CaseClause(Expression* label,
1057 ZoneList<Statement*>* statements,
1058 int pos)
1059 : label_(label),
1060 statements_(statements),
1061 position_(pos),
1062 compare_type_(NONE) {}
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +00001063
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001064} } // namespace v8::internal