summaryrefslogtreecommitdiff
path: root/deps/v8/src/fast-codegen.cc
diff options
context:
space:
mode:
authorRyan Dahl <ry@tinyclouds.org>2010-02-03 09:06:03 -0800
committerRyan Dahl <ry@tinyclouds.org>2010-02-03 09:07:02 -0800
commitc7cb4daa25966e4f9af3c6d5499d762736454da9 (patch)
tree27c6541f5a1207eb74797ed63a43126c9bf2ba81 /deps/v8/src/fast-codegen.cc
parentc723acc72192334a62bea6ff4baa33aab0da50ad (diff)
downloadnode-c7cb4daa25966e4f9af3c6d5499d762736454da9.tar.gz
Upgrade V8 to 2.1.0
Diffstat (limited to 'deps/v8/src/fast-codegen.cc')
-rw-r--r--deps/v8/src/fast-codegen.cc947
1 files changed, 391 insertions, 556 deletions
diff --git a/deps/v8/src/fast-codegen.cc b/deps/v8/src/fast-codegen.cc
index 455dd5fab..4e6f259c6 100644
--- a/deps/v8/src/fast-codegen.cc
+++ b/deps/v8/src/fast-codegen.cc
@@ -1,4 +1,4 @@
-// Copyright 2009 the V8 project authors. All rights reserved.
+// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -28,431 +28,410 @@
#include "v8.h"
#include "codegen-inl.h"
-#include "compiler.h"
+#include "data-flow.h"
#include "fast-codegen.h"
-#include "stub-cache.h"
-#include "debug.h"
+#include "scopes.h"
namespace v8 {
namespace internal {
-#define __ ACCESS_MASM(masm())
-
-Handle<Code> FastCodeGenerator::MakeCode(FunctionLiteral* fun,
- Handle<Script> script,
- bool is_eval) {
- CodeGenerator::MakeCodePrologue(fun);
- const int kInitialBufferSize = 4 * KB;
- MacroAssembler masm(NULL, kInitialBufferSize);
- FastCodeGenerator cgen(&masm, script, is_eval);
- cgen.Generate(fun);
- if (cgen.HasStackOverflow()) {
- ASSERT(!Top::has_pending_exception());
- return Handle<Code>::null();
+#define BAILOUT(reason) \
+ do { \
+ if (FLAG_trace_bailout) { \
+ PrintF("%s\n", reason); \
+ } \
+ has_supported_syntax_ = false; \
+ return; \
+ } while (false)
+
+
+#define CHECK_BAILOUT \
+ do { \
+ if (!has_supported_syntax_) return; \
+ } while (false)
+
+
+void FastCodeGenSyntaxChecker::Check(FunctionLiteral* fun,
+ CompilationInfo* info) {
+ info_ = info;
+
+ // We do not specialize if we do not have a receiver or if it is not a
+ // JS object with fast mode properties.
+ if (!info->has_receiver()) BAILOUT("No receiver");
+ if (!info->receiver()->IsJSObject()) BAILOUT("Receiver is not an object");
+ Handle<JSObject> object = Handle<JSObject>::cast(info->receiver());
+ if (!object->HasFastProperties()) BAILOUT("Receiver is in dictionary mode");
+
+ // We do not support stack or heap slots (both of which require
+ // allocation).
+ Scope* scope = fun->scope();
+ if (scope->num_stack_slots() > 0) {
+ BAILOUT("Function has stack-allocated locals");
}
- Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, NOT_IN_LOOP);
- return CodeGenerator::MakeCodeEpilogue(fun, &masm, flags, script);
+ if (scope->num_heap_slots() > 0) {
+ BAILOUT("Function has context-allocated locals");
+ }
+
+ VisitDeclarations(scope->declarations());
+ CHECK_BAILOUT;
+
+ // We do not support empty function bodies.
+ if (fun->body()->is_empty()) BAILOUT("Function has an empty body");
+ VisitStatements(fun->body());
}
-int FastCodeGenerator::SlotOffset(Slot* slot) {
- ASSERT(slot != NULL);
- // Offset is negative because higher indexes are at lower addresses.
- int offset = -slot->index() * kPointerSize;
- // Adjust by a (parameter or local) base offset.
- switch (slot->type()) {
- case Slot::PARAMETER:
- offset += (function_->scope()->num_parameters() + 1) * kPointerSize;
- break;
- case Slot::LOCAL:
- offset += JavaScriptFrameConstants::kLocal0Offset;
- break;
- case Slot::CONTEXT:
- case Slot::LOOKUP:
- UNREACHABLE();
- }
- return offset;
-}
-
-
-void FastCodeGenerator::Apply(Expression::Context context, Register reg) {
- switch (context) {
- case Expression::kUninitialized:
- UNREACHABLE();
- case Expression::kEffect:
- break;
- case Expression::kValue:
- __ push(reg);
- break;
- case Expression::kTest:
- TestAndBranch(reg, true_label_, false_label_);
- break;
- case Expression::kValueTest: {
- Label discard;
- __ push(reg);
- TestAndBranch(reg, true_label_, &discard);
- __ bind(&discard);
- __ Drop(1);
- __ jmp(false_label_);
- break;
- }
- case Expression::kTestValue: {
- Label discard;
- __ push(reg);
- TestAndBranch(reg, &discard, false_label_);
- __ bind(&discard);
- __ Drop(1);
- __ jmp(true_label_);
- }
- }
+void FastCodeGenSyntaxChecker::VisitDeclarations(
+ ZoneList<Declaration*>* decls) {
+ if (!decls->is_empty()) BAILOUT("Function has declarations");
}
-void FastCodeGenerator::VisitDeclarations(
- ZoneList<Declaration*>* declarations) {
- int length = declarations->length();
- int globals = 0;
- for (int i = 0; i < length; i++) {
- Declaration* decl = declarations->at(i);
- Variable* var = decl->proxy()->var();
- Slot* slot = var->slot();
-
- // If it was not possible to allocate the variable at compile
- // time, we need to "declare" it at runtime to make sure it
- // actually exists in the local context.
- if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
- VisitDeclaration(decl);
- } else {
- // Count global variables and functions for later processing
- globals++;
- }
+void FastCodeGenSyntaxChecker::VisitStatements(ZoneList<Statement*>* stmts) {
+ for (int i = 0, len = stmts->length(); i < len; i++) {
+ Visit(stmts->at(i));
+ CHECK_BAILOUT;
}
+}
- // Compute array of global variable and function declarations.
- // Do nothing in case of no declared global functions or variables.
- if (globals > 0) {
- Handle<FixedArray> array = Factory::NewFixedArray(2 * globals, TENURED);
- for (int j = 0, i = 0; i < length; i++) {
- Declaration* decl = declarations->at(i);
- Variable* var = decl->proxy()->var();
- Slot* slot = var->slot();
-
- if ((slot == NULL || slot->type() != Slot::LOOKUP) && var->is_global()) {
- array->set(j++, *(var->name()));
- if (decl->fun() == NULL) {
- if (var->mode() == Variable::CONST) {
- // In case this is const property use the hole.
- array->set_the_hole(j++);
- } else {
- array->set_undefined(j++);
- }
- } else {
- Handle<JSFunction> function =
- Compiler::BuildBoilerplate(decl->fun(), script_, this);
- // Check for stack-overflow exception.
- if (HasStackOverflow()) return;
- array->set(j++, *function);
- }
- }
- }
- // Invoke the platform-dependent code generator to do the actual
- // declaration the global variables and functions.
- DeclareGlobals(array);
- }
+
+void FastCodeGenSyntaxChecker::VisitDeclaration(Declaration* decl) {
+ UNREACHABLE();
}
-void FastCodeGenerator::SetFunctionPosition(FunctionLiteral* fun) {
- if (FLAG_debug_info) {
- CodeGenerator::RecordPositions(masm_, fun->start_position());
- }
+void FastCodeGenSyntaxChecker::VisitBlock(Block* stmt) {
+ VisitStatements(stmt->statements());
}
-void FastCodeGenerator::SetReturnPosition(FunctionLiteral* fun) {
- if (FLAG_debug_info) {
- CodeGenerator::RecordPositions(masm_, fun->end_position());
- }
+void FastCodeGenSyntaxChecker::VisitExpressionStatement(
+ ExpressionStatement* stmt) {
+ Visit(stmt->expression());
}
-void FastCodeGenerator::SetStatementPosition(Statement* stmt) {
- if (FLAG_debug_info) {
- CodeGenerator::RecordPositions(masm_, stmt->statement_pos());
- }
+void FastCodeGenSyntaxChecker::VisitEmptyStatement(EmptyStatement* stmt) {
+ // Supported.
}
-void FastCodeGenerator::SetSourcePosition(int pos) {
- if (FLAG_debug_info && pos != RelocInfo::kNoPosition) {
- masm_->RecordPosition(pos);
- }
+void FastCodeGenSyntaxChecker::VisitIfStatement(IfStatement* stmt) {
+ BAILOUT("IfStatement");
}
-void FastCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
-#ifdef DEBUG
- Expression::Context expected = Expression::kUninitialized;
- switch (expr->context()) {
- case Expression::kUninitialized:
- UNREACHABLE();
- case Expression::kEffect:
- case Expression::kTest:
- // The value of the left subexpression is not needed.
- expected = Expression::kTest;
- break;
- case Expression::kValue:
- // The value of the left subexpression is needed and its specific
- // context depends on the operator.
- expected = (expr->op() == Token::OR)
- ? Expression::kValueTest
- : Expression::kTestValue;
- break;
- case Expression::kValueTest:
- // The value of the left subexpression is needed for OR.
- expected = (expr->op() == Token::OR)
- ? Expression::kValueTest
- : Expression::kTest;
- break;
- case Expression::kTestValue:
- // The value of the left subexpression is needed for AND.
- expected = (expr->op() == Token::OR)
- ? Expression::kTest
- : Expression::kTestValue;
- break;
- }
- ASSERT_EQ(expected, expr->left()->context());
- ASSERT_EQ(expr->context(), expr->right()->context());
-#endif
-
- Label eval_right, done;
-
- // Set up the appropriate context for the left subexpression based
- // on the operation and our own context. Initially assume we can
- // inherit both true and false labels from our context.
- Label* if_true = true_label_;
- Label* if_false = false_label_;
- if (expr->op() == Token::OR) {
- // If we are not in some kind of a test context, we did not inherit a
- // true label from our context. Use the end of the expression.
- if (expr->context() == Expression::kEffect ||
- expr->context() == Expression::kValue) {
- if_true = &done;
- }
- // The false label is the label of the right subexpression.
- if_false = &eval_right;
- } else {
- ASSERT_EQ(Token::AND, expr->op());
- // The true label is the label of the right subexpression.
- if_true = &eval_right;
- // If we are not in some kind of a test context, we did not inherit a
- // false label from our context. Use the end of the expression.
- if (expr->context() == Expression::kEffect ||
- expr->context() == Expression::kValue) {
- if_false = &done;
- }
- }
- VisitForControl(expr->left(), if_true, if_false);
+void FastCodeGenSyntaxChecker::VisitContinueStatement(ContinueStatement* stmt) {
+ BAILOUT("Continuestatement");
+}
- __ bind(&eval_right);
- Visit(expr->right());
- __ bind(&done);
+void FastCodeGenSyntaxChecker::VisitBreakStatement(BreakStatement* stmt) {
+ BAILOUT("BreakStatement");
}
-void FastCodeGenerator::VisitBlock(Block* stmt) {
- Comment cmnt(masm_, "[ Block");
- Breakable nested_statement(this, stmt);
- SetStatementPosition(stmt);
- VisitStatements(stmt->statements());
- __ bind(nested_statement.break_target());
+void FastCodeGenSyntaxChecker::VisitReturnStatement(ReturnStatement* stmt) {
+ BAILOUT("ReturnStatement");
}
-void FastCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
- Comment cmnt(masm_, "[ ExpressionStatement");
- SetStatementPosition(stmt);
- Visit(stmt->expression());
+void FastCodeGenSyntaxChecker::VisitWithEnterStatement(
+ WithEnterStatement* stmt) {
+ BAILOUT("WithEnterStatement");
}
-void FastCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
- Comment cmnt(masm_, "[ EmptyStatement");
- SetStatementPosition(stmt);
+void FastCodeGenSyntaxChecker::VisitWithExitStatement(WithExitStatement* stmt) {
+ BAILOUT("WithExitStatement");
}
-void FastCodeGenerator::VisitIfStatement(IfStatement* stmt) {
- Comment cmnt(masm_, "[ IfStatement");
- SetStatementPosition(stmt);
- Label then_part, else_part, done;
+void FastCodeGenSyntaxChecker::VisitSwitchStatement(SwitchStatement* stmt) {
+ BAILOUT("SwitchStatement");
+}
- // Do not worry about optimizing for empty then or else bodies.
- VisitForControl(stmt->condition(), &then_part, &else_part);
- __ bind(&then_part);
- Visit(stmt->then_statement());
- __ jmp(&done);
+void FastCodeGenSyntaxChecker::VisitDoWhileStatement(DoWhileStatement* stmt) {
+ BAILOUT("DoWhileStatement");
+}
- __ bind(&else_part);
- Visit(stmt->else_statement());
- __ bind(&done);
+void FastCodeGenSyntaxChecker::VisitWhileStatement(WhileStatement* stmt) {
+ BAILOUT("WhileStatement");
}
-void FastCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
- Comment cmnt(masm_, "[ ContinueStatement");
- SetStatementPosition(stmt);
- NestedStatement* current = nesting_stack_;
- int stack_depth = 0;
- while (!current->IsContinueTarget(stmt->target())) {
- stack_depth = current->Exit(stack_depth);
- current = current->outer();
- }
- __ Drop(stack_depth);
+void FastCodeGenSyntaxChecker::VisitForStatement(ForStatement* stmt) {
+ BAILOUT("ForStatement");
+}
+
- Iteration* loop = current->AsIteration();
- __ jmp(loop->continue_target());
+void FastCodeGenSyntaxChecker::VisitForInStatement(ForInStatement* stmt) {
+ BAILOUT("ForInStatement");
}
-void FastCodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
- Comment cmnt(masm_, "[ BreakStatement");
- SetStatementPosition(stmt);
- NestedStatement* current = nesting_stack_;
- int stack_depth = 0;
- while (!current->IsBreakTarget(stmt->target())) {
- stack_depth = current->Exit(stack_depth);
- current = current->outer();
- }
- __ Drop(stack_depth);
+void FastCodeGenSyntaxChecker::VisitTryCatchStatement(TryCatchStatement* stmt) {
+ BAILOUT("TryCatchStatement");
+}
+
- Breakable* target = current->AsBreakable();
- __ jmp(target->break_target());
+void FastCodeGenSyntaxChecker::VisitTryFinallyStatement(
+ TryFinallyStatement* stmt) {
+ BAILOUT("TryFinallyStatement");
}
-void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
- Comment cmnt(masm_, "[ ReturnStatement");
- SetStatementPosition(stmt);
- Expression* expr = stmt->expression();
- // Complete the statement based on the type of the subexpression.
- if (expr->AsLiteral() != NULL) {
- __ Move(result_register(), expr->AsLiteral()->handle());
- } else {
- ASSERT_EQ(Expression::kValue, expr->context());
- Visit(expr);
- __ pop(result_register());
- }
+void FastCodeGenSyntaxChecker::VisitDebuggerStatement(
+ DebuggerStatement* stmt) {
+ BAILOUT("DebuggerStatement");
+}
- // Exit all nested statements.
- NestedStatement* current = nesting_stack_;
- int stack_depth = 0;
- while (current != NULL) {
- stack_depth = current->Exit(stack_depth);
- current = current->outer();
- }
- __ Drop(stack_depth);
- EmitReturnSequence(stmt->statement_pos());
+void FastCodeGenSyntaxChecker::VisitFunctionLiteral(FunctionLiteral* expr) {
+ BAILOUT("FunctionLiteral");
}
+void FastCodeGenSyntaxChecker::VisitFunctionBoilerplateLiteral(
+ FunctionBoilerplateLiteral* expr) {
+ BAILOUT("FunctionBoilerplateLiteral");
+}
-void FastCodeGenerator::VisitWithEnterStatement(WithEnterStatement* stmt) {
- Comment cmnt(masm_, "[ WithEnterStatement");
- SetStatementPosition(stmt);
+void FastCodeGenSyntaxChecker::VisitConditional(Conditional* expr) {
+ BAILOUT("Conditional");
+}
- Visit(stmt->expression());
- if (stmt->is_catch_block()) {
- __ CallRuntime(Runtime::kPushCatchContext, 1);
+
+void FastCodeGenSyntaxChecker::VisitSlot(Slot* expr) {
+ UNREACHABLE();
+}
+
+
+void FastCodeGenSyntaxChecker::VisitVariableProxy(VariableProxy* expr) {
+ // Only global variable references are supported.
+ Variable* var = expr->var();
+ if (!var->is_global()) BAILOUT("Non-global variable");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitLiteral(Literal* expr) {
+ BAILOUT("Literal");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitRegExpLiteral(RegExpLiteral* expr) {
+ BAILOUT("RegExpLiteral");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitObjectLiteral(ObjectLiteral* expr) {
+ BAILOUT("ObjectLiteral");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitArrayLiteral(ArrayLiteral* expr) {
+ BAILOUT("ArrayLiteral");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitCatchExtensionObject(
+ CatchExtensionObject* expr) {
+ BAILOUT("CatchExtensionObject");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitAssignment(Assignment* expr) {
+ // Simple assignments to (named) this properties are supported.
+ if (expr->op() != Token::ASSIGN) BAILOUT("Non-simple assignment");
+
+ Property* prop = expr->target()->AsProperty();
+ if (prop == NULL) BAILOUT("Non-property assignment");
+ VariableProxy* proxy = prop->obj()->AsVariableProxy();
+ if (proxy == NULL || !proxy->var()->is_this()) {
+ BAILOUT("Non-this-property assignment");
+ }
+ if (!prop->key()->IsPropertyName()) {
+ BAILOUT("Non-named-property assignment");
+ }
+
+ // We will only specialize for fields on the object itself.
+ // Expression::IsPropertyName implies that the name is a literal
+ // symbol but we do not assume that.
+ Literal* key = prop->key()->AsLiteral();
+ if (key != NULL && key->handle()->IsString()) {
+ Handle<Object> receiver = info()->receiver();
+ Handle<String> name = Handle<String>::cast(key->handle());
+ LookupResult lookup;
+ receiver->Lookup(*name, &lookup);
+ if (lookup.holder() != *receiver) BAILOUT("Non-own property assignment");
+ if (!lookup.type() == FIELD) BAILOUT("Non-field property assignment");
} else {
- __ CallRuntime(Runtime::kPushContext, 1);
+ UNREACHABLE();
+ BAILOUT("Unexpected non-string-literal property key");
}
- // Both runtime calls return the new context in both the context and the
- // result registers.
- // Update local stack frame context field.
- StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
+ Visit(expr->value());
}
-void FastCodeGenerator::VisitWithExitStatement(WithExitStatement* stmt) {
- Comment cmnt(masm_, "[ WithExitStatement");
- SetStatementPosition(stmt);
+void FastCodeGenSyntaxChecker::VisitThrow(Throw* expr) {
+ BAILOUT("Throw");
+}
- // Pop context.
- LoadContextField(context_register(), Context::PREVIOUS_INDEX);
- // Update local stack frame context field.
- StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
+
+void FastCodeGenSyntaxChecker::VisitProperty(Property* expr) {
+ BAILOUT("Property");
}
-void FastCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
+void FastCodeGenSyntaxChecker::VisitCall(Call* expr) {
+ BAILOUT("Call");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitCallNew(CallNew* expr) {
+ BAILOUT("CallNew");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitCallRuntime(CallRuntime* expr) {
+ BAILOUT("CallRuntime");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitUnaryOperation(UnaryOperation* expr) {
+ BAILOUT("UnaryOperation");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitCountOperation(CountOperation* expr) {
+ BAILOUT("CountOperation");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitBinaryOperation(BinaryOperation* expr) {
+ BAILOUT("BinaryOperation");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitCompareOperation(CompareOperation* expr) {
+ BAILOUT("CompareOperation");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitThisFunction(ThisFunction* expr) {
+ BAILOUT("ThisFunction");
+}
+
+#undef BAILOUT
+#undef CHECK_BAILOUT
+
+
+#define __ ACCESS_MASM(masm())
+
+Handle<Code> FastCodeGenerator::MakeCode(FunctionLiteral* fun,
+ Handle<Script> script,
+ bool is_eval,
+ CompilationInfo* info) {
+ // Label the AST before calling MakeCodePrologue, so AST node numbers are
+ // printed with the AST.
+ AstLabeler labeler;
+ labeler.Label(fun);
+ info->set_has_this_properties(labeler.has_this_properties());
+
+ CodeGenerator::MakeCodePrologue(fun);
+
+ const int kInitialBufferSize = 4 * KB;
+ MacroAssembler masm(NULL, kInitialBufferSize);
+
+ // Generate the fast-path code.
+ FastCodeGenerator fast_cgen(&masm, script, is_eval);
+ fast_cgen.Generate(fun, info);
+ if (fast_cgen.HasStackOverflow()) {
+ ASSERT(!Top::has_pending_exception());
+ return Handle<Code>::null();
+ }
+
+ // Generate the full code for the function in bailout mode, using the same
+ // macro assembler.
+ CodeGenerator cgen(&masm, script, is_eval);
+ CodeGeneratorScope scope(&cgen);
+ cgen.Generate(fun, CodeGenerator::SECONDARY, info);
+ if (cgen.HasStackOverflow()) {
+ ASSERT(!Top::has_pending_exception());
+ return Handle<Code>::null();
+ }
+
+ Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, NOT_IN_LOOP);
+ return CodeGenerator::MakeCodeEpilogue(fun, &masm, flags, script);
+}
+
+
+void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
UNREACHABLE();
}
-void FastCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
- Comment cmnt(masm_, "[ DoWhileStatement");
- SetStatementPosition(stmt);
- Label body, stack_limit_hit, stack_check_success;
+void FastCodeGenerator::VisitBlock(Block* stmt) {
+ VisitStatements(stmt->statements());
+}
- Iteration loop_statement(this, stmt);
- increment_loop_depth();
- __ bind(&body);
- Visit(stmt->body());
+void FastCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
+ Visit(stmt->expression());
+}
- // Check stack before looping.
- __ StackLimitCheck(&stack_limit_hit);
- __ bind(&stack_check_success);
- __ bind(loop_statement.continue_target());
- VisitForControl(stmt->cond(), &body, loop_statement.break_target());
+void FastCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
+ // Nothing to do.
+}
- __ bind(&stack_limit_hit);
- StackCheckStub stack_stub;
- __ CallStub(&stack_stub);
- __ jmp(&stack_check_success);
- __ bind(loop_statement.break_target());
+void FastCodeGenerator::VisitIfStatement(IfStatement* stmt) {
+ UNREACHABLE();
+}
+
- decrement_loop_depth();
+void FastCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
+ UNREACHABLE();
}
-void FastCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
- Comment cmnt(masm_, "[ WhileStatement");
- SetStatementPosition(stmt);
- Label body, stack_limit_hit, stack_check_success;
+void FastCodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
+ UNREACHABLE();
+}
+
- Iteration loop_statement(this, stmt);
- increment_loop_depth();
+void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
+ UNREACHABLE();
+}
- // Emit the test at the bottom of the loop.
- __ jmp(loop_statement.continue_target());
- __ bind(&body);
- Visit(stmt->body());
+void FastCodeGenerator::VisitWithEnterStatement(WithEnterStatement* stmt) {
+ UNREACHABLE();
+}
- __ bind(loop_statement.continue_target());
- // Check stack before looping.
- __ StackLimitCheck(&stack_limit_hit);
- __ bind(&stack_check_success);
- VisitForControl(stmt->cond(), &body, loop_statement.break_target());
+void FastCodeGenerator::VisitWithExitStatement(WithExitStatement* stmt) {
+ UNREACHABLE();
+}
- __ bind(&stack_limit_hit);
- StackCheckStub stack_stub;
- __ CallStub(&stack_stub);
- __ jmp(&stack_check_success);
- __ bind(loop_statement.break_target());
- decrement_loop_depth();
+void FastCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
+ UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
+ UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
+ UNREACHABLE();
}
@@ -467,120 +446,22 @@ void FastCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
void FastCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
- Comment cmnt(masm_, "[ TryCatchStatement");
- SetStatementPosition(stmt);
- // The try block adds a handler to the exception handler chain
- // before entering, and removes it again when exiting normally.
- // If an exception is thrown during execution of the try block,
- // control is passed to the handler, which also consumes the handler.
- // At this point, the exception is in a register, and store it in
- // the temporary local variable (prints as ".catch-var") before
- // executing the catch block. The catch block has been rewritten
- // to introduce a new scope to bind the catch variable and to remove
- // that scope again afterwards.
-
- Label try_handler_setup, catch_entry, done;
-
- __ Call(&try_handler_setup);
- // Try handler code, exception in result register.
-
- // Store exception in local .catch variable before executing catch block.
- {
- // The catch variable is *always* a variable proxy for a local variable.
- Variable* catch_var = stmt->catch_var()->AsVariableProxy()->AsVariable();
- ASSERT_NOT_NULL(catch_var);
- Slot* variable_slot = catch_var->slot();
- ASSERT_NOT_NULL(variable_slot);
- ASSERT_EQ(Slot::LOCAL, variable_slot->type());
- StoreToFrameField(SlotOffset(variable_slot), result_register());
- }
-
- Visit(stmt->catch_block());
- __ jmp(&done);
-
- // Try block code. Sets up the exception handler chain.
- __ bind(&try_handler_setup);
- {
- TryCatch try_block(this, &catch_entry);
- __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER);
- Visit(stmt->try_block());
- __ PopTryHandler();
- }
- __ bind(&done);
+ UNREACHABLE();
}
void FastCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
- Comment cmnt(masm_, "[ TryFinallyStatement");
- SetStatementPosition(stmt);
- // Try finally is compiled by setting up a try-handler on the stack while
- // executing the try body, and removing it again afterwards.
- //
- // The try-finally construct can enter the finally block in three ways:
- // 1. By exiting the try-block normally. This removes the try-handler and
- // calls the finally block code before continuing.
- // 2. By exiting the try-block with a function-local control flow transfer
- // (break/continue/return). The site of the, e.g., break removes the
- // try handler and calls the finally block code before continuing
- // its outward control transfer.
- // 3. by exiting the try-block with a thrown exception.
- // This can happen in nested function calls. It traverses the try-handler
- // chain and consumes the try-handler entry before jumping to the
- // handler code. The handler code then calls the finally-block before
- // rethrowing the exception.
- //
- // The finally block must assume a return address on top of the stack
- // (or in the link register on ARM chips) and a value (return value or
- // exception) in the result register (rax/eax/r0), both of which must
- // be preserved. The return address isn't GC-safe, so it should be
- // cooked before GC.
- Label finally_entry;
- Label try_handler_setup;
-
- // Setup the try-handler chain. Use a call to
- // Jump to try-handler setup and try-block code. Use call to put try-handler
- // address on stack.
- __ Call(&try_handler_setup);
- // Try handler code. Return address of call is pushed on handler stack.
- {
- // This code is only executed during stack-handler traversal when an
- // exception is thrown. The execption is in the result register, which
- // is retained by the finally block.
- // Call the finally block and then rethrow the exception.
- __ Call(&finally_entry);
- __ push(result_register());
- __ CallRuntime(Runtime::kReThrow, 1);
- }
+ UNREACHABLE();
+}
- __ bind(&finally_entry);
- {
- // Finally block implementation.
- Finally finally_block(this);
- EnterFinallyBlock();
- Visit(stmt->finally_block());
- ExitFinallyBlock(); // Return to the calling code.
- }
- __ bind(&try_handler_setup);
- {
- // Setup try handler (stack pointer registers).
- TryFinally try_block(this, &finally_entry);
- __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER);
- Visit(stmt->try_block());
- __ PopTryHandler();
- }
- // Execute the finally block on the way out.
- __ Call(&finally_entry);
+void FastCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
+ UNREACHABLE();
}
-void FastCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
-#ifdef ENABLE_DEBUGGER_SUPPORT
- Comment cmnt(masm_, "[ DebuggerStatement");
- SetStatementPosition(stmt);
- __ CallRuntime(Runtime::kDebugBreak, 0);
- // Ignore the return value.
-#endif
+void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
+ UNREACHABLE();
}
@@ -591,169 +472,123 @@ void FastCodeGenerator::VisitFunctionBoilerplateLiteral(
void FastCodeGenerator::VisitConditional(Conditional* expr) {
- Comment cmnt(masm_, "[ Conditional");
- ASSERT_EQ(Expression::kTest, expr->condition()->context());
- ASSERT_EQ(expr->context(), expr->then_expression()->context());
- ASSERT_EQ(expr->context(), expr->else_expression()->context());
+ UNREACHABLE();
+}
- Label true_case, false_case, done;
- VisitForControl(expr->condition(), &true_case, &false_case);
+void FastCodeGenerator::VisitSlot(Slot* expr) {
+ UNREACHABLE();
+}
- __ bind(&true_case);
- Visit(expr->then_expression());
- // If control flow falls through Visit, jump to done.
- if (expr->context() == Expression::kEffect ||
- expr->context() == Expression::kValue) {
- __ jmp(&done);
- }
- __ bind(&false_case);
- Visit(expr->else_expression());
- // If control flow falls through Visit, merge it with true case here.
- if (expr->context() == Expression::kEffect ||
- expr->context() == Expression::kValue) {
- __ bind(&done);
+void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
+ ASSERT(expr->var()->is_global() && !expr->var()->is_this());
+ Comment cmnt(masm(), ";; Global");
+ if (FLAG_print_ir) {
+ SmartPointer<char> name = expr->name()->ToCString();
+ PrintF("%d: t%d = Global(%s)\n", expr->num(), expr->num(), *name);
}
+ EmitGlobalVariableLoad(expr->name());
}
-void FastCodeGenerator::VisitSlot(Slot* expr) {
- // Slots do not appear directly in the AST.
+void FastCodeGenerator::VisitLiteral(Literal* expr) {
UNREACHABLE();
}
-void FastCodeGenerator::VisitLiteral(Literal* expr) {
- Comment cmnt(masm_, "[ Literal");
- Apply(expr->context(), expr);
+void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
+ UNREACHABLE();
}
-void FastCodeGenerator::VisitAssignment(Assignment* expr) {
- Comment cmnt(masm_, "[ Assignment");
+void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
+ UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
+ UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) {
+ UNREACHABLE();
+}
+
- // Record source code position of the (possible) IC call.
- SetSourcePosition(expr->position());
+void FastCodeGenerator::VisitAssignment(Assignment* expr) {
+ // Known to be a simple this property assignment.
+ Visit(expr->value());
- // Left-hand side can only be a property, a global or a (parameter or local)
- // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
- enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
- LhsKind assign_type = VARIABLE;
Property* prop = expr->target()->AsProperty();
- // In case of a property we use the uninitialized expression context
- // of the key to detect a named property.
- if (prop != NULL) {
- assign_type = (prop->key()->context() == Expression::kUninitialized)
- ? NAMED_PROPERTY
- : KEYED_PROPERTY;
+ ASSERT_NOT_NULL(prop);
+ ASSERT_NOT_NULL(prop->obj()->AsVariableProxy());
+ ASSERT(prop->obj()->AsVariableProxy()->var()->is_this());
+ ASSERT(prop->key()->IsPropertyName());
+ Handle<String> name =
+ Handle<String>::cast(prop->key()->AsLiteral()->handle());
+
+ Comment cmnt(masm(), ";; Store(this)");
+ if (FLAG_print_ir) {
+ SmartPointer<char> name_string = name->ToCString();
+ PrintF("%d: t%d = Store(this, \"%s\", t%d)\n",
+ expr->num(), expr->num(), *name_string, expr->value()->num());
}
- // Evaluate LHS expression.
- switch (assign_type) {
- case VARIABLE:
- // Nothing to do here.
- break;
- case NAMED_PROPERTY:
- Visit(prop->obj());
- ASSERT_EQ(Expression::kValue, prop->obj()->context());
- break;
- case KEYED_PROPERTY:
- Visit(prop->obj());
- ASSERT_EQ(Expression::kValue, prop->obj()->context());
- Visit(prop->key());
- ASSERT_EQ(Expression::kValue, prop->key()->context());
- break;
- }
+ EmitThisPropertyStore(name);
+}
- // If we have a compound assignment: Get value of LHS expression and
- // store in on top of the stack.
- // Note: Relies on kValue context being 'stack'.
- if (expr->is_compound()) {
- switch (assign_type) {
- case VARIABLE:
- EmitVariableLoad(expr->target()->AsVariableProxy()->var(),
- Expression::kValue);
- break;
- case NAMED_PROPERTY:
- EmitNamedPropertyLoad(prop, Expression::kValue);
- break;
- case KEYED_PROPERTY:
- EmitKeyedPropertyLoad(prop, Expression::kValue);
- break;
- }
- }
- // Evaluate RHS expression.
- Expression* rhs = expr->value();
- ASSERT_EQ(Expression::kValue, rhs->context());
- Visit(rhs);
+void FastCodeGenerator::VisitThrow(Throw* expr) {
+ UNREACHABLE();
+}
- // If we have a compount assignment: Apply operator.
- if (expr->is_compound()) {
- EmitCompoundAssignmentOp(expr->binary_op(), Expression::kValue);
- }
- // Store the value.
- switch (assign_type) {
- case VARIABLE:
- EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
- expr->context());
- break;
- case NAMED_PROPERTY:
- EmitNamedPropertyAssignment(expr);
- break;
- case KEYED_PROPERTY:
- EmitKeyedPropertyAssignment(expr);
- break;
- }
+void FastCodeGenerator::VisitProperty(Property* expr) {
+ UNREACHABLE();
}
-void FastCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) {
- // Call runtime routine to allocate the catch extension object and
- // assign the exception value to the catch variable.
- Comment cmnt(masm_, "[ CatchExtensionObject");
-
- // Push key string.
- ASSERT_EQ(Expression::kValue, expr->key()->context());
- Visit(expr->key());
- ASSERT_EQ(Expression::kValue, expr->value()->context());
- Visit(expr->value());
+void FastCodeGenerator::VisitCall(Call* expr) {
+ UNREACHABLE();
+}
- // Create catch extension object.
- __ CallRuntime(Runtime::kCreateCatchExtensionObject, 2);
- __ push(result_register());
+void FastCodeGenerator::VisitCallNew(CallNew* expr) {
+ UNREACHABLE();
}
-void FastCodeGenerator::VisitThrow(Throw* expr) {
- Comment cmnt(masm_, "[ Throw");
- Visit(expr->exception());
- // Exception is on stack.
- __ CallRuntime(Runtime::kThrow, 1);
- // Never returns here.
+void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
+ UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
+ UNREACHABLE();
}
-int FastCodeGenerator::TryFinally::Exit(int stack_depth) {
- // The macros used here must preserve the result register.
- __ Drop(stack_depth);
- __ PopTryHandler();
- __ Call(finally_entry_);
- return 0;
+void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
+ UNREACHABLE();
}
-int FastCodeGenerator::TryCatch::Exit(int stack_depth) {
- // The macros used here must preserve the result register.
- __ Drop(stack_depth);
- __ PopTryHandler();
- return 0;
+void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
+ UNREACHABLE();
}
+void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
+ UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) {
+ UNREACHABLE();
+}
+
#undef __