#include "bootstrapper.h"
#include "codegen-inl.h"
#include "debug.h"
-#include "prettyprinter.h"
-#include "scopeinfo.h"
#include "scopes.h"
#include "runtime.h"
namespace v8 { namespace internal {
-class ArmCodeGenerator;
-
-
-// -----------------------------------------------------------------------------
-// Reference support
-
-// A reference is a C++ stack-allocated object that keeps an ECMA
-// reference on the execution stack while in scope. For variables
-// the reference is empty, indicating that it isn't necessary to
-// store state on the stack for keeping track of references to those.
-// For properties, we keep either one (named) or two (indexed) values
-// on the execution stack to represent the reference.
-
-enum InitState { CONST_INIT, NOT_CONST_INIT };
-enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
-
-class Reference BASE_EMBEDDED {
- public:
- // The values of the types is important, see size().
- enum Type { ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 };
- Reference(ArmCodeGenerator* cgen, Expression* expression);
- ~Reference();
-
- Expression* expression() const { return expression_; }
- Type type() const { return type_; }
- void set_type(Type value) {
- ASSERT(type_ == ILLEGAL);
- type_ = value;
- }
- // The size of the reference or -1 if the reference is illegal.
- int size() const { return type_; }
-
- bool is_illegal() const { return type_ == ILLEGAL; }
- bool is_slot() const { return type_ == SLOT; }
- bool is_property() const { return type_ == NAMED || type_ == KEYED; }
-
- // Return the name. Only valid for named property references.
- Handle<String> GetName();
-
- // Generate code to push the value of the reference on top of the
- // expression stack. The reference is expected to be already on top of
- // the expression stack, and it is left in place with its value above it.
- void GetValue(TypeofState typeof_state);
-
- // Generate code to store the value on top of the expression stack in the
- // reference. The reference is expected to be immediately below the value
- // on the expression stack. The stored value is left in place (with the
- // reference intact below it) to support chained assignments.
- void SetValue(InitState init_state);
-
- private:
- ArmCodeGenerator* cgen_;
- Expression* expression_;
- Type type_;
-};
-
-
-// -------------------------------------------------------------------------
-// Code generation state
-
-// The state is passed down the AST by the code generator (and back up, in
-// the form of the state of the label pair). It is threaded through the
-// call stack. Constructing a state implicitly pushes it on the owning code
-// generator's stack of states, and destroying one implicitly pops it.
-
-class CodeGenState BASE_EMBEDDED {
- public:
- // Create an initial code generator state. Destroying the initial state
- // leaves the code generator with a NULL state.
- explicit CodeGenState(ArmCodeGenerator* owner);
-
- // Create a code generator state based on a code generator's current
- // state. The new state has its own typeof state and pair of branch
- // labels.
- CodeGenState(ArmCodeGenerator* owner,
- TypeofState typeof_state,
- Label* true_target,
- Label* false_target);
-
- // Destroy a code generator state and restore the owning code generator's
- // previous state.
- ~CodeGenState();
-
- TypeofState typeof_state() const { return typeof_state_; }
- Label* true_target() const { return true_target_; }
- Label* false_target() const { return false_target_; }
-
- private:
- ArmCodeGenerator* owner_;
- TypeofState typeof_state_;
- Label* true_target_;
- Label* false_target_;
- CodeGenState* previous_;
-};
-
-
-// -----------------------------------------------------------------------------
-// ArmCodeGenerator
-
-class ArmCodeGenerator: public CodeGenerator {
- public:
- static Handle<Code> MakeCode(FunctionLiteral* fun,
- Handle<Script> script,
- bool is_eval);
-
- MacroAssembler* masm() { return masm_; }
-
- Scope* scope() const { return scope_; }
-
- CodeGenState* state() { return state_; }
- void set_state(CodeGenState* state) { state_ = state; }
-
- private:
- // Assembler
- MacroAssembler* masm_; // to generate code
-
- // Code generation state
- Scope* scope_;
- Condition cc_reg_;
- CodeGenState* state_;
- int break_stack_height_;
-
- // Labels
- Label function_return_;
-
- // Construction/destruction
- ArmCodeGenerator(int buffer_size,
- Handle<Script> script,
- bool is_eval);
-
- virtual ~ArmCodeGenerator() { delete masm_; }
-
- // Main code generation function
- void GenCode(FunctionLiteral* fun);
-
- // The following are used by class Reference.
- void LoadReference(Reference* ref);
- void UnloadReference(Reference* ref);
-
- // State
- bool has_cc() const { return cc_reg_ != al; }
- TypeofState typeof_state() const { return state_->typeof_state(); }
- Label* true_target() const { return state_->true_target(); }
- Label* false_target() const { return state_->false_target(); }
-
-
- // Expressions
- MemOperand GlobalObject() const {
- return ContextOperand(cp, Context::GLOBAL_INDEX);
- }
-
- MemOperand ContextOperand(Register context, int index) const {
- return MemOperand(context, Context::SlotOffset(index));
- }
-
- MemOperand ParameterOperand(int index) const {
- int num_parameters = scope()->num_parameters();
- // index -2 corresponds to the activated closure, -1 corresponds
- // to the receiver
- ASSERT(-2 <= index && index < num_parameters);
- int offset = (1 + num_parameters - index) * kPointerSize;
- return MemOperand(fp, offset);
- }
-
- MemOperand FunctionOperand() const {
- return MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset);
- }
-
- MemOperand SlotOperand(Slot* slot, Register tmp);
-
- void LoadCondition(Expression* x,
- TypeofState typeof_state,
- Label* true_target,
- Label* false_target,
- bool force_cc);
- void Load(Expression* x, TypeofState typeof_state = NOT_INSIDE_TYPEOF);
- void LoadGlobal();
-
- // Read a value from a slot and leave it on top of the expression stack.
- void LoadFromSlot(Slot* slot, TypeofState typeof_state);
-
- // Special code for typeof expressions: Unfortunately, we must
- // be careful when loading the expression in 'typeof'
- // expressions. We are not allowed to throw reference errors for
- // non-existing properties of the global object, so we must make it
- // look like an explicit property access, instead of an access
- // through the context chain.
- void LoadTypeofExpression(Expression* x);
-
- void ToBoolean(Label* true_target, Label* false_target);
-
- void GenericBinaryOperation(Token::Value op);
- void Comparison(Condition cc, bool strict = false);
-
- void SmiOperation(Token::Value op, Handle<Object> value, bool reversed);
-
- void CallWithArguments(ZoneList<Expression*>* arguments, int position);
-
- // Declare global variables and functions in the given array of
- // name/value pairs.
- virtual void DeclareGlobals(Handle<FixedArray> pairs);
-
- // Instantiate the function boilerplate.
- void InstantiateBoilerplate(Handle<JSFunction> boilerplate);
-
- // Control flow
- void Branch(bool if_true, Label* L);
- void CheckStack();
- void CleanStack(int num_bytes);
-
- // Node visitors
-#define DEF_VISIT(type) \
- virtual void Visit##type(type* node);
- NODE_LIST(DEF_VISIT)
-#undef DEF_VISIT
-
- // Fast-case switch
- static const int kFastCaseSwitchMaxOverheadFactor = 10;
- static const int kFastCaseSwitchMinCaseCount = 5;
- virtual int FastCaseSwitchMaxOverheadFactor();
- virtual int FastCaseSwitchMinCaseCount();
- virtual void GenerateFastCaseSwitchJumpTable(
- SwitchStatement* node, int min_index, int range, Label *fail_label,
- SmartPointer<Label*> &case_targets, SmartPointer<Label> &case_labels);
-
- void RecordStatementPosition(Node* node);
-
- // Activation frames
- void EnterJSFrame();
- void ExitJSFrame();
-
- virtual void GenerateIsSmi(ZoneList<Expression*>* args);
- virtual void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
- virtual void GenerateIsArray(ZoneList<Expression*>* args);
-
- virtual void GenerateArgumentsLength(ZoneList<Expression*>* args);
- virtual void GenerateArgumentsAccess(ZoneList<Expression*>* args);
-
- virtual void GenerateValueOf(ZoneList<Expression*>* args);
- virtual void GenerateSetValueOf(ZoneList<Expression*>* args);
-
- virtual void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
-
- virtual void GenerateObjectEquals(ZoneList<Expression*>* args);
-
- friend class Reference;
- friend class Property;
- friend class VariableProxy;
- friend class Slot;
-};
-
-
// -------------------------------------------------------------------------
// CodeGenState implementation.
-CodeGenState::CodeGenState(ArmCodeGenerator* owner)
+CodeGenState::CodeGenState(CodeGenerator* owner)
: owner_(owner),
typeof_state_(NOT_INSIDE_TYPEOF),
true_target_(NULL),
}
-CodeGenState::CodeGenState(ArmCodeGenerator* owner,
+CodeGenState::CodeGenState(CodeGenerator* owner,
TypeofState typeof_state,
Label* true_target,
Label* false_target)
// -----------------------------------------------------------------------------
-// ArmCodeGenerator implementation
+// CodeGenerator implementation
#define __ masm_->
-Handle<Code> ArmCodeGenerator::MakeCode(FunctionLiteral* flit,
- Handle<Script> script,
- bool is_eval) {
-#ifdef ENABLE_DISASSEMBLER
- bool print_code = FLAG_print_code && !Bootstrapper::IsActive();
-#endif // ENABLE_DISASSEMBLER
-
-#ifdef DEBUG
- bool print_source = false;
- bool print_ast = false;
- const char* ftype;
-
- if (Bootstrapper::IsActive()) {
- print_source = FLAG_print_builtin_source;
- print_ast = FLAG_print_builtin_ast;
- print_code = FLAG_print_builtin_code;
- ftype = "builtin";
- } else {
- print_source = FLAG_print_source;
- print_ast = FLAG_print_ast;
- ftype = "user-defined";
- }
-
- if (FLAG_trace_codegen || print_source || print_ast) {
- PrintF("*** Generate code for %s function: ", ftype);
- flit->name()->ShortPrint();
- PrintF(" ***\n");
- }
-
- if (print_source) {
- PrintF("--- Source from AST ---\n%s\n", PrettyPrinter().PrintProgram(flit));
- }
-
- if (print_ast) {
- PrintF("--- AST ---\n%s\n", AstPrinter().PrintProgram(flit));
- }
-#endif // DEBUG
-
- // Generate code.
- const int initial_buffer_size = 4 * KB;
- ArmCodeGenerator cgen(initial_buffer_size, script, is_eval);
- cgen.GenCode(flit);
- if (cgen.HasStackOverflow()) {
- ASSERT(!Top::has_pending_exception());
- return Handle<Code>::null();
- }
-
- // Process any deferred code.
- cgen.ProcessDeferred();
-
- // Allocate and install the code.
- CodeDesc desc;
- cgen.masm()->GetCode(&desc);
- ScopeInfo<> sinfo(flit->scope());
- Code::Flags flags = Code::ComputeFlags(Code::FUNCTION);
- Handle<Code> code = Factory::NewCode(desc, &sinfo, flags);
-
- // Add unresolved entries in the code to the fixup list.
- Bootstrapper::AddFixup(*code, cgen.masm());
-
-#ifdef ENABLE_DISASSEMBLER
- if (print_code) {
- // Print the source code if available.
- if (!script->IsUndefined() && !script->source()->IsUndefined()) {
- PrintF("--- Raw source ---\n");
- StringInputBuffer stream(String::cast(script->source()));
- stream.Seek(flit->start_position());
- // flit->end_position() points to the last character in the stream. We
- // need to compensate by adding one to calculate the length.
- int source_len = flit->end_position() - flit->start_position() + 1;
- for (int i = 0; i < source_len; i++) {
- if (stream.has_more()) PrintF("%c", stream.GetNext());
- }
- PrintF("\n\n");
- }
- PrintF("--- Code ---\n");
- code->Disassemble();
- }
-#endif // ENABLE_DISASSEMBLER
-
- return code;
-}
-
-
-ArmCodeGenerator::ArmCodeGenerator(int buffer_size,
- Handle<Script> script,
- bool is_eval)
- : CodeGenerator(is_eval, script),
+CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script,
+ bool is_eval)
+ : is_eval_(is_eval),
+ script_(script),
+ deferred_(8),
masm_(new MacroAssembler(NULL, buffer_size)),
scope_(NULL),
cc_reg_(al),
// pp: caller's parameter pointer
// cp: callee's context
-void ArmCodeGenerator::GenCode(FunctionLiteral* fun) {
+void CodeGenerator::GenCode(FunctionLiteral* fun) {
Scope* scope = fun->scope();
ZoneList<Statement*>* body = fun->body();
}
-MemOperand ArmCodeGenerator::SlotOperand(Slot* slot, Register tmp) {
+MemOperand CodeGenerator::SlotOperand(Slot* slot, Register tmp) {
// Currently, this assertion will fail if we try to assign to
// a constant variable that is constant because it is read-only
// (such as the variable referring to a named function expression).
// code register. If force_cc is set, the value is forced to set the condition
// code register and no value is pushed. If the condition code register was set,
// has_cc() is true and cc_reg_ contains the condition to test for 'true'.
-void ArmCodeGenerator::LoadCondition(Expression* x,
+void CodeGenerator::LoadCondition(Expression* x,
TypeofState typeof_state,
Label* true_target,
Label* false_target,
}
-void ArmCodeGenerator::Load(Expression* x, TypeofState typeof_state) {
+void CodeGenerator::Load(Expression* x, TypeofState typeof_state) {
Label true_target;
Label false_target;
LoadCondition(x, typeof_state, &true_target, &false_target, false);
}
-void ArmCodeGenerator::LoadGlobal() {
+void CodeGenerator::LoadGlobal() {
__ ldr(r0, GlobalObject());
__ push(r0);
}
// TODO(1241834): Get rid of this function in favor of just using Load, now
// that we have the INSIDE_TYPEOF typeof state. => Need to handle global
// variables w/o reference errors elsewhere.
-void ArmCodeGenerator::LoadTypeofExpression(Expression* x) {
+void CodeGenerator::LoadTypeofExpression(Expression* x) {
Variable* variable = x->AsVariableProxy()->AsVariable();
if (variable != NULL && !variable->is_this() && variable->is_global()) {
// NOTE: This is somewhat nasty. We force the compiler to load
}
-Reference::Reference(ArmCodeGenerator* cgen, Expression* expression)
+Reference::Reference(CodeGenerator* cgen, Expression* expression)
: cgen_(cgen), expression_(expression), type_(ILLEGAL) {
cgen->LoadReference(this);
}
}
-void ArmCodeGenerator::LoadReference(Reference* ref) {
+void CodeGenerator::LoadReference(Reference* ref) {
Comment cmnt(masm_, "[ LoadReference");
+
Expression* e = ref->expression();
Property* property = e->AsProperty();
Variable* var = e->AsVariableProxy()->AsVariable();
}
-void ArmCodeGenerator::UnloadReference(Reference* ref) {
+void CodeGenerator::UnloadReference(Reference* ref) {
Comment cmnt(masm_, "[ UnloadReference");
+
int size = ref->size();
if (size <= 0) {
// Do nothing. No popping is necessary.
// ECMA-262, section 9.2, page 30: ToBoolean(). Convert the given
// register to a boolean in the condition code register. The code
// may jump to 'false_target' in case the register converts to 'false'.
-void ArmCodeGenerator::ToBoolean(Label* true_target,
+void CodeGenerator::ToBoolean(Label* true_target,
Label* false_target) {
// Note: The generated code snippet does not change stack variables.
// Only the condition code should be set.
};
-void ArmCodeGenerator::GenericBinaryOperation(Token::Value op) {
+void CodeGenerator::GenericBinaryOperation(Token::Value op) {
// sp[0] : y
// sp[1] : x
// result : r0
};
-void ArmCodeGenerator::SmiOperation(Token::Value op,
+void CodeGenerator::SmiOperation(Token::Value op,
Handle<Object> value,
bool reversed) {
// NOTE: This is an attempt to inline (a bit) more of the code for
}
-void ArmCodeGenerator::Comparison(Condition cc, bool strict) {
+void CodeGenerator::Comparison(Condition cc, bool strict) {
// sp[0] : y
// sp[1] : x
// result : cc register
// Call the function on the stack with the given arguments.
-void ArmCodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
+void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
int position) {
// Push the arguments ("left-to-right") on the stack.
for (int i = 0; i < args->length(); i++) {
}
-void ArmCodeGenerator::Branch(bool if_true, Label* L) {
+void CodeGenerator::Branch(bool if_true, Label* L) {
ASSERT(has_cc());
Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_);
__ b(cc, L);
}
-void ArmCodeGenerator::CheckStack() {
+void CodeGenerator::CheckStack() {
if (FLAG_check_stack) {
Comment cmnt(masm_, "[ check stack");
StackCheckStub stub;
}
-void ArmCodeGenerator::VisitBlock(Block* node) {
+void CodeGenerator::VisitBlock(Block* node) {
Comment cmnt(masm_, "[ Block");
if (FLAG_debug_info) RecordStatementPosition(node);
node->set_break_stack_height(break_stack_height_);
}
-void ArmCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
+void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
__ mov(r0, Operand(pairs));
__ push(r0);
__ push(cp);
}
-void ArmCodeGenerator::VisitDeclaration(Declaration* node) {
+void CodeGenerator::VisitDeclaration(Declaration* node) {
Comment cmnt(masm_, "[ Declaration");
Variable* var = node->proxy()->var();
ASSERT(var != NULL); // must have been resolved
}
-void ArmCodeGenerator::VisitExpressionStatement(ExpressionStatement* node) {
+void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) {
Comment cmnt(masm_, "[ ExpressionStatement");
if (FLAG_debug_info) RecordStatementPosition(node);
Expression* expression = node->expression();
}
-void ArmCodeGenerator::VisitEmptyStatement(EmptyStatement* node) {
+void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) {
Comment cmnt(masm_, "// EmptyStatement");
// nothing to do
}
-void ArmCodeGenerator::VisitIfStatement(IfStatement* node) {
+void CodeGenerator::VisitIfStatement(IfStatement* node) {
Comment cmnt(masm_, "[ IfStatement");
// Generate different code depending on which
// parts of the if statement are present or not.
}
-void ArmCodeGenerator::CleanStack(int num_bytes) {
+void CodeGenerator::CleanStack(int num_bytes) {
ASSERT(num_bytes >= 0);
if (num_bytes > 0) {
__ add(sp, sp, Operand(num_bytes));
}
-void ArmCodeGenerator::VisitContinueStatement(ContinueStatement* node) {
+void CodeGenerator::VisitContinueStatement(ContinueStatement* node) {
Comment cmnt(masm_, "[ ContinueStatement");
if (FLAG_debug_info) RecordStatementPosition(node);
CleanStack(break_stack_height_ - node->target()->break_stack_height());
}
-void ArmCodeGenerator::VisitBreakStatement(BreakStatement* node) {
+void CodeGenerator::VisitBreakStatement(BreakStatement* node) {
Comment cmnt(masm_, "[ BreakStatement");
if (FLAG_debug_info) RecordStatementPosition(node);
CleanStack(break_stack_height_ - node->target()->break_stack_height());
}
-void ArmCodeGenerator::VisitReturnStatement(ReturnStatement* node) {
+void CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
Comment cmnt(masm_, "[ ReturnStatement");
if (FLAG_debug_info) RecordStatementPosition(node);
Load(node->expression());
}
-void ArmCodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) {
+void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) {
Comment cmnt(masm_, "[ WithEnterStatement");
if (FLAG_debug_info) RecordStatementPosition(node);
Load(node->expression());
}
-void ArmCodeGenerator::VisitWithExitStatement(WithExitStatement* node) {
+void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) {
Comment cmnt(masm_, "[ WithExitStatement");
// Pop context.
__ ldr(cp, ContextOperand(cp, Context::PREVIOUS_INDEX));
}
-int ArmCodeGenerator::FastCaseSwitchMaxOverheadFactor() {
- return kFastCaseSwitchMaxOverheadFactor;
+int CodeGenerator::FastCaseSwitchMaxOverheadFactor() {
+ return kFastSwitchMaxOverheadFactor;
}
-int ArmCodeGenerator::FastCaseSwitchMinCaseCount() {
- return kFastCaseSwitchMinCaseCount;
+int CodeGenerator::FastCaseSwitchMinCaseCount() {
+ return kFastSwitchMinCaseCount;
}
-void ArmCodeGenerator::GenerateFastCaseSwitchJumpTable(
+void CodeGenerator::GenerateFastCaseSwitchJumpTable(
SwitchStatement* node, int min_index, int range, Label *fail_label,
SmartPointer<Label*> &case_targets, SmartPointer<Label> &case_labels) {
}
-void ArmCodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
+void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
Comment cmnt(masm_, "[ SwitchStatement");
if (FLAG_debug_info) RecordStatementPosition(node);
node->set_break_stack_height(break_stack_height_);
}
-void ArmCodeGenerator::VisitLoopStatement(LoopStatement* node) {
+void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
Comment cmnt(masm_, "[ LoopStatement");
if (FLAG_debug_info) RecordStatementPosition(node);
node->set_break_stack_height(break_stack_height_);
}
-void ArmCodeGenerator::VisitForInStatement(ForInStatement* node) {
+void CodeGenerator::VisitForInStatement(ForInStatement* node) {
Comment cmnt(masm_, "[ ForInStatement");
if (FLAG_debug_info) RecordStatementPosition(node);
}
-void ArmCodeGenerator::VisitTryCatch(TryCatch* node) {
+void CodeGenerator::VisitTryCatch(TryCatch* node) {
Comment cmnt(masm_, "[ TryCatch");
Label try_block, exit;
}
-void ArmCodeGenerator::VisitTryFinally(TryFinally* node) {
+void CodeGenerator::VisitTryFinally(TryFinally* node) {
Comment cmnt(masm_, "[ TryFinally");
// State: Used to keep track of reason for entering the finally
}
-void ArmCodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
+void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
Comment cmnt(masm_, "[ DebuggerStatament");
if (FLAG_debug_info) RecordStatementPosition(node);
__ CallRuntime(Runtime::kDebugBreak, 1);
}
-void ArmCodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) {
+void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) {
ASSERT(boilerplate->IsBoilerplate());
// Push the boilerplate on the stack.
}
-void ArmCodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
+void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
Comment cmnt(masm_, "[ FunctionLiteral");
// Build the function boilerplate and instantiate it.
}
-void ArmCodeGenerator::VisitFunctionBoilerplateLiteral(
+void CodeGenerator::VisitFunctionBoilerplateLiteral(
FunctionBoilerplateLiteral* node) {
Comment cmnt(masm_, "[ FunctionBoilerplateLiteral");
InstantiateBoilerplate(node->boilerplate());
}
-void ArmCodeGenerator::VisitConditional(Conditional* node) {
+void CodeGenerator::VisitConditional(Conditional* node) {
Comment cmnt(masm_, "[ Conditional");
Label then, else_, exit;
LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
}
-void ArmCodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
+void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
if (slot->type() == Slot::LOOKUP) {
ASSERT(slot->var()->mode() == Variable::DYNAMIC);
}
-void ArmCodeGenerator::VisitSlot(Slot* node) {
+void CodeGenerator::VisitSlot(Slot* node) {
Comment cmnt(masm_, "[ Slot");
LoadFromSlot(node, typeof_state());
}
-void ArmCodeGenerator::VisitVariableProxy(VariableProxy* node) {
+void CodeGenerator::VisitVariableProxy(VariableProxy* node) {
Comment cmnt(masm_, "[ VariableProxy");
+
Variable* var = node->var();
Expression* expr = var->rewrite();
if (expr != NULL) {
}
-void ArmCodeGenerator::VisitLiteral(Literal* node) {
+void CodeGenerator::VisitLiteral(Literal* node) {
Comment cmnt(masm_, "[ Literal");
__ mov(r0, Operand(node->handle()));
__ push(r0);
}
-void ArmCodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) {
+void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) {
Comment cmnt(masm_, "[ RexExp Literal");
// Retrieve the literal array and check the allocated entry.
}
-void ArmCodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
+void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
Comment cmnt(masm_, "[ ObjectLiteral");
ObjectLiteralDeferred* deferred = new ObjectLiteralDeferred(this, node);
}
-void ArmCodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
+void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
Comment cmnt(masm_, "[ ArrayLiteral");
// Call runtime to create the array literal.
}
-void ArmCodeGenerator::VisitAssignment(Assignment* node) {
+void CodeGenerator::VisitAssignment(Assignment* node) {
Comment cmnt(masm_, "[ Assignment");
if (FLAG_debug_info) RecordStatementPosition(node);
}
-void ArmCodeGenerator::VisitThrow(Throw* node) {
+void CodeGenerator::VisitThrow(Throw* node) {
Comment cmnt(masm_, "[ Throw");
Load(node->exception());
}
-void ArmCodeGenerator::VisitProperty(Property* node) {
+void CodeGenerator::VisitProperty(Property* node) {
Comment cmnt(masm_, "[ Property");
+
Reference property(this, node);
property.GetValue(typeof_state());
}
-void ArmCodeGenerator::VisitCall(Call* node) {
+void CodeGenerator::VisitCall(Call* node) {
Comment cmnt(masm_, "[ Call");
ZoneList<Expression*>* args = node->arguments();
}
-void ArmCodeGenerator::VisitCallNew(CallNew* node) {
+void CodeGenerator::VisitCallNew(CallNew* node) {
Comment cmnt(masm_, "[ CallNew");
// According to ECMA-262, section 11.2.2, page 44, the function
}
-void ArmCodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Label leave;
Load(args->at(0));
}
-void ArmCodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) {
ASSERT(args->length() == 2);
Label leave;
Load(args->at(0)); // Load the object.
}
-void ArmCodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));
__ pop(r0);
}
-void ArmCodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));
__ pop(r0);
// This should generate code that performs a charCodeAt() call or returns
// undefined in order to trigger the slow case, Runtime_StringCharCodeAt.
// It is not yet implemented on ARM, so it always goes to the slow case.
-void ArmCodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
ASSERT(args->length() == 2);
__ mov(r0, Operand(Factory::undefined_value()));
__ push(r0);
}
-void ArmCodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));
Label answer;
}
-void ArmCodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
ASSERT(args->length() == 0);
// Seed the result with the formal parameters count, which will be used
}
-void ArmCodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
// Satisfy contract with ArgumentsAccessStub:
}
-void ArmCodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) {
ASSERT(args->length() == 2);
// Load the two objects into registers and perform the comparison.
}
-void ArmCodeGenerator::VisitCallRuntime(CallRuntime* node) {
+void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
if (CheckForInlineRuntimeCall(node)) return;
ZoneList<Expression*>* args = node->arguments();
}
-void ArmCodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
+void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
Comment cmnt(masm_, "[ UnaryOperation");
Token::Value op = node->op();
}
-void ArmCodeGenerator::VisitCountOperation(CountOperation* node) {
+void CodeGenerator::VisitCountOperation(CountOperation* node) {
Comment cmnt(masm_, "[ CountOperation");
bool is_postfix = node->is_postfix();
}
-void ArmCodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
+void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
Comment cmnt(masm_, "[ BinaryOperation");
Token::Value op = node->op();
}
-void ArmCodeGenerator::VisitThisFunction(ThisFunction* node) {
+void CodeGenerator::VisitThisFunction(ThisFunction* node) {
__ ldr(r0, FunctionOperand());
__ push(r0);
}
-void ArmCodeGenerator::VisitCompareOperation(CompareOperation* node) {
+void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
Comment cmnt(masm_, "[ CompareOperation");
// Get the expressions from the node.
}
-void ArmCodeGenerator::RecordStatementPosition(Node* node) {
+void CodeGenerator::RecordStatementPosition(Node* node) {
if (FLAG_debug_info) {
int statement_pos = node->statement_pos();
if (statement_pos == RelocInfo::kNoPosition) return;
}
-void ArmCodeGenerator::EnterJSFrame() {
+void CodeGenerator::EnterJSFrame() {
#if defined(DEBUG)
{ Label done, fail;
__ tst(r1, Operand(kSmiTagMask));
__ cmp(r2, Operand(JS_FUNCTION_TYPE));
__ b(eq, &done);
__ bind(&fail);
- __ stop("ArmCodeGenerator::EnterJSFrame - r1 not a function");
+ __ stop("CodeGenerator::EnterJSFrame - r1 not a function");
__ bind(&done);
}
#endif // DEBUG
}
-void ArmCodeGenerator::ExitJSFrame() {
+void CodeGenerator::ExitJSFrame() {
// Drop the execution stack down to the frame pointer and restore the caller
// frame pointer and return address.
__ mov(sp, fp);
#undef __
-// -----------------------------------------------------------------------------
-// CodeGenerator interface
-
-// MakeCode() is just a wrapper for CodeGenerator::MakeCode()
-// so we don't have to expose the entire CodeGenerator class in
-// the .h file.
-Handle<Code> CodeGenerator::MakeCode(FunctionLiteral* fun,
- Handle<Script> script,
- bool is_eval) {
- Handle<Code> code = ArmCodeGenerator::MakeCode(fun, script, is_eval);
- if (!code.is_null()) {
- Counters::total_compiled_code_size.Increment(code->instruction_size());
- }
- return code;
-}
-
-
} } // namespace v8::internal
--- /dev/null
+// Copyright 2006-2008 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:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_CODEGEN_ARM_H_
+#define V8_CODEGEN_ARM_H_
+
+#include "scopes.h"
+
+namespace v8 { namespace internal {
+
+// Forward declarations
+class DeferredCode;
+
+// Mode to overwrite BinaryExpression values.
+enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
+
+
+// -----------------------------------------------------------------------------
+// Reference support
+
+// A reference is a C++ stack-allocated object that keeps an ECMA
+// reference on the execution stack while in scope. For variables
+// the reference is empty, indicating that it isn't necessary to
+// store state on the stack for keeping track of references to those.
+// For properties, we keep either one (named) or two (indexed) values
+// on the execution stack to represent the reference.
+
+enum InitState { CONST_INIT, NOT_CONST_INIT };
+enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
+
+class Reference BASE_EMBEDDED {
+ public:
+ // The values of the types is important, see size().
+ enum Type { ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 };
+ Reference(CodeGenerator* cgen, Expression* expression);
+ ~Reference();
+
+ Expression* expression() const { return expression_; }
+ Type type() const { return type_; }
+ void set_type(Type value) {
+ ASSERT(type_ == ILLEGAL);
+ type_ = value;
+ }
+
+ // The size of the reference or -1 if the reference is illegal.
+ int size() const { return type_; }
+
+ bool is_illegal() const { return type_ == ILLEGAL; }
+ bool is_slot() const { return type_ == SLOT; }
+ bool is_property() const { return type_ == NAMED || type_ == KEYED; }
+
+ // Return the name. Only valid for named property references.
+ Handle<String> GetName();
+
+ // Generate code to push the value of the reference on top of the
+ // expression stack. The reference is expected to be already on top of
+ // the expression stack, and it is left in place with its value above it.
+ void GetValue(TypeofState typeof_state);
+
+ // Generate code to store the value on top of the expression stack in the
+ // reference. The reference is expected to be immediately below the value
+ // on the expression stack. The stored value is left in place (with the
+ // reference intact below it) to support chained assignments.
+ void SetValue(InitState init_state);
+
+ private:
+ CodeGenerator* cgen_;
+ Expression* expression_;
+ Type type_;
+};
+
+
+// -------------------------------------------------------------------------
+// Code generation state
+
+// The state is passed down the AST by the code generator (and back up, in
+// the form of the state of the label pair). It is threaded through the
+// call stack. Constructing a state implicitly pushes it on the owning code
+// generator's stack of states, and destroying one implicitly pops it.
+
+class CodeGenState BASE_EMBEDDED {
+ public:
+ // Create an initial code generator state. Destroying the initial state
+ // leaves the code generator with a NULL state.
+ explicit CodeGenState(CodeGenerator* owner);
+
+ // Create a code generator state based on a code generator's current
+ // state. The new state has its own typeof state and pair of branch
+ // labels.
+ CodeGenState(CodeGenerator* owner,
+ TypeofState typeof_state,
+ Label* true_target,
+ Label* false_target);
+
+ // Destroy a code generator state and restore the owning code generator's
+ // previous state.
+ ~CodeGenState();
+
+ TypeofState typeof_state() const { return typeof_state_; }
+ Label* true_target() const { return true_target_; }
+ Label* false_target() const { return false_target_; }
+
+ private:
+ CodeGenerator* owner_;
+ TypeofState typeof_state_;
+ Label* true_target_;
+ Label* false_target_;
+ CodeGenState* previous_;
+};
+
+
+// -----------------------------------------------------------------------------
+// CodeGenerator
+
+class CodeGenerator: public Visitor {
+ public:
+ // Takes a function literal, generates code for it. This function should only
+ // be called by compiler.cc.
+ static Handle<Code> MakeCode(FunctionLiteral* fun,
+ Handle<Script> script,
+ bool is_eval);
+
+ static void SetFunctionInfo(Handle<JSFunction> fun,
+ int length,
+ int function_token_position,
+ int start_position,
+ int end_position,
+ bool is_expression,
+ bool is_toplevel,
+ Handle<Script> script);
+
+ // Accessors
+ MacroAssembler* masm() { return masm_; }
+
+ CodeGenState* state() { return state_; }
+ void set_state(CodeGenState* state) { state_ = state; }
+
+ void AddDeferred(DeferredCode* code) { deferred_.Add(code); }
+
+ private:
+ // Construction/Destruction
+ CodeGenerator(int buffer_size, Handle<Script> script, bool is_eval);
+ virtual ~CodeGenerator() { delete masm_; }
+
+ // Accessors
+ Scope* scope() const { return scope_; }
+
+ void ProcessDeferred();
+
+ bool is_eval() { return is_eval_; }
+
+ // State
+ bool has_cc() const { return cc_reg_ != al; }
+ TypeofState typeof_state() const { return state_->typeof_state(); }
+ Label* true_target() const { return state_->true_target(); }
+ Label* false_target() const { return state_->false_target(); }
+
+
+ // Node visitors.
+#define DEF_VISIT(type) \
+ void Visit##type(type* node);
+ NODE_LIST(DEF_VISIT)
+#undef DEF_VISIT
+
+ // Main code generation function
+ void GenCode(FunctionLiteral* fun);
+
+ // The following are used by class Reference.
+ void LoadReference(Reference* ref);
+ void UnloadReference(Reference* ref);
+
+ // Support functions for accessing parameters and other operands.
+ MemOperand ParameterOperand(int index) const {
+ int num_parameters = scope()->num_parameters();
+ // index -2 corresponds to the activated closure, -1 corresponds
+ // to the receiver
+ ASSERT(-2 <= index && index < num_parameters);
+ int offset = (1 + num_parameters - index) * kPointerSize;
+ return MemOperand(fp, offset);
+ }
+
+ MemOperand FunctionOperand() const {
+ return MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset);
+ }
+
+ MemOperand ContextOperand(Register context, int index) const {
+ return MemOperand(context, Context::SlotOffset(index));
+ }
+
+ MemOperand SlotOperand(Slot* slot, Register tmp);
+
+ // Expressions
+ MemOperand GlobalObject() const {
+ return ContextOperand(cp, Context::GLOBAL_INDEX);
+ }
+
+ void LoadCondition(Expression* x,
+ TypeofState typeof_state,
+ Label* true_target,
+ Label* false_target,
+ bool force_cc);
+ void Load(Expression* x, TypeofState typeof_state = NOT_INSIDE_TYPEOF);
+ void LoadGlobal();
+
+ // Read a value from a slot and leave it on top of the expression stack.
+ void LoadFromSlot(Slot* slot, TypeofState typeof_state);
+
+ // Special code for typeof expressions: Unfortunately, we must
+ // be careful when loading the expression in 'typeof'
+ // expressions. We are not allowed to throw reference errors for
+ // non-existing properties of the global object, so we must make it
+ // look like an explicit property access, instead of an access
+ // through the context chain.
+ void LoadTypeofExpression(Expression* x);
+
+ void ToBoolean(Label* true_target, Label* false_target);
+
+ void GenericBinaryOperation(Token::Value op);
+ void Comparison(Condition cc, bool strict = false);
+
+ void SmiOperation(Token::Value op, Handle<Object> value, bool reversed);
+
+ void CallWithArguments(ZoneList<Expression*>* arguments, int position);
+
+ // Control flow
+ void Branch(bool if_true, Label* L);
+ void CheckStack();
+ void CleanStack(int num_bytes);
+
+ bool CheckForInlineRuntimeCall(CallRuntime* node);
+ Handle<JSFunction> BuildBoilerplate(FunctionLiteral* node);
+ void ProcessDeclarations(ZoneList<Declaration*>* declarations);
+
+ Handle<Code> ComputeCallInitialize(int argc);
+
+ // Declare global variables and functions in the given array of
+ // name/value pairs.
+ void DeclareGlobals(Handle<FixedArray> pairs);
+
+ // Instantiate the function boilerplate.
+ void InstantiateBoilerplate(Handle<JSFunction> boilerplate);
+
+ // Support for type checks.
+ void GenerateIsSmi(ZoneList<Expression*>* args);
+ void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
+ void GenerateIsArray(ZoneList<Expression*>* args);
+
+ // Support for arguments.length and arguments[?].
+ void GenerateArgumentsLength(ZoneList<Expression*>* args);
+ void GenerateArgumentsAccess(ZoneList<Expression*>* args);
+
+ // Support for accessing the value field of an object (used by Date).
+ void GenerateValueOf(ZoneList<Expression*>* args);
+ void GenerateSetValueOf(ZoneList<Expression*>* args);
+
+ // Fast support for charCodeAt(n).
+ void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
+
+ // Fast support for object equality testing.
+ void GenerateObjectEquals(ZoneList<Expression*>* args);
+
+ // Methods and constants for fast case switch statement support.
+ //
+ // Only allow fast-case switch if the range of labels is at most
+ // this factor times the number of case labels.
+ // Value is derived from comparing the size of code generated by the normal
+ // switch code for Smi-labels to the size of a single pointer. If code
+ // quality increases this number should be decreased to match.
+ static const int kFastSwitchMaxOverheadFactor = 10;
+
+ // Minimal number of switch cases required before we allow jump-table
+ // optimization.
+ static const int kFastSwitchMinCaseCount = 5;
+
+ // The limit of the range of a fast-case switch, as a factor of the number
+ // of cases of the switch. Each platform should return a value that
+ // is optimal compared to the default code generated for a switch statement
+ // on that platform.
+ int FastCaseSwitchMaxOverheadFactor();
+
+ // The minimal number of cases in a switch before the fast-case switch
+ // optimization is enabled. Each platform should return a value that
+ // is optimal compared to the default code generated for a switch statement
+ // on that platform.
+ int FastCaseSwitchMinCaseCount();
+
+ // Allocate a jump table and create code to jump through it.
+ // Should call GenerateFastCaseSwitchCases to generate the code for
+ // all the cases at the appropriate point.
+ void GenerateFastCaseSwitchJumpTable(SwitchStatement* node, int min_index,
+ int range, Label *fail_label,
+ SmartPointer<Label*> &case_targets,
+ SmartPointer<Label>& case_labels);
+
+ // Generate the code for cases for the fast case switch.
+ // Called by GenerateFastCaseSwitchJumpTable.
+ void GenerateFastCaseSwitchCases(SwitchStatement* node,
+ SmartPointer<Label> &case_labels);
+
+ // Fast support for constant-Smi switches.
+ void GenerateFastCaseSwitchStatement(SwitchStatement *node, int min_index,
+ int range, int default_index);
+
+ // Fast support for constant-Smi switches. Tests whether switch statement
+ // permits optimization and calls GenerateFastCaseSwitch if it does.
+ // Returns true if the fast-case switch was generated, and false if not.
+ bool TryGenerateFastCaseSwitchStatement(SwitchStatement *node);
+
+
+ // Bottle-neck interface to call the Assembler to generate the statement
+ // position. This allows us to easily control whether statement positions
+ // should be generated or not.
+ void RecordStatementPosition(Node* node);
+
+ // Activation frames.
+ void EnterJSFrame();
+ void ExitJSFrame();
+
+
+ bool is_eval_; // Tells whether code is generated for eval.
+ Handle<Script> script_;
+ List<DeferredCode*> deferred_;
+
+ // Assembler
+ MacroAssembler* masm_; // to generate code
+
+ // Code generation state
+ Scope* scope_;
+ Condition cc_reg_;
+ CodeGenState* state_;
+ bool is_inside_try_;
+ int break_stack_height_;
+
+ // Labels
+ Label function_return_;
+
+ friend class Reference;
+ friend class Property;
+ friend class VariableProxy;
+ friend class Slot;
+
+ DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
+};
+
+} } // namespace v8::internal
+
+#endif // V8_CODEGEN_ARM_H_
#include "bootstrapper.h"
#include "codegen-inl.h"
#include "debug.h"
-#include "prettyprinter.h"
-#include "scopeinfo.h"
#include "scopes.h"
#include "runtime.h"
#define TOS (Operand(esp, 0))
-class Ia32CodeGenerator;
-
-// Mode to overwrite BinaryExpression values.
-enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
-
-
-// -----------------------------------------------------------------------------
-// Reference support
-
-// A reference is a C++ stack-allocated object that keeps an ECMA
-// reference on the execution stack while in scope. For variables
-// the reference is empty, indicating that it isn't necessary to
-// store state on the stack for keeping track of references to those.
-// For properties, we keep either one (named) or two (indexed) values
-// on the execution stack to represent the reference.
-
-enum InitState { CONST_INIT, NOT_CONST_INIT };
-enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
-
-class Reference BASE_EMBEDDED {
- public:
- // The values of the types is important, see size().
- enum Type { ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 };
- Reference(Ia32CodeGenerator* cgen, Expression* expression);
- ~Reference();
-
- Expression* expression() const { return expression_; }
- Type type() const { return type_; }
- void set_type(Type value) {
- ASSERT(type_ == ILLEGAL);
- type_ = value;
- }
-
- // The size of the reference or -1 if the reference is illegal.
- int size() const { return type_; }
-
- bool is_illegal() const { return type_ == ILLEGAL; }
- bool is_slot() const { return type_ == SLOT; }
- bool is_property() const { return type_ == NAMED || type_ == KEYED; }
-
- // Return the name. Only valid for named property references.
- Handle<String> GetName();
-
- // Generate code to push the value of the reference on top of the
- // expression stack. The reference is expected to be already on top of
- // the expression stack, and it is left in place with its value above it.
- void GetValue(TypeofState typeof_state);
-
- // Generate code to store the value on top of the expression stack in the
- // reference. The reference is expected to be immediately below the value
- // on the expression stack. The stored value is left in place (with the
- // reference intact below it) to support chained assignments.
- void SetValue(InitState init_state);
-
- private:
- Ia32CodeGenerator* cgen_;
- Expression* expression_;
- Type type_;
-};
-
-
-// -------------------------------------------------------------------------
-// Code generation state
-
-// The state is passed down the AST by the code generator (and back up, in
-// the form of the state of the label pair). It is threaded through the
-// call stack. Constructing a state implicitly pushes it on the owning code
-// generator's stack of states, and destroying one implicitly pops it.
-
-class CodeGenState BASE_EMBEDDED {
- public:
- // Create an initial code generator state. Destroying the initial state
- // leaves the code generator with a NULL state.
- explicit CodeGenState(Ia32CodeGenerator* owner);
-
- // Create a code generator state based on a code generator's current
- // state. The new state has its own typeof state and pair of branch
- // labels.
- CodeGenState(Ia32CodeGenerator* owner,
- TypeofState typeof_state,
- Label* true_target,
- Label* false_target);
-
- // Destroy a code generator state and restore the owning code generator's
- // previous state.
- ~CodeGenState();
-
- TypeofState typeof_state() const { return typeof_state_; }
- Label* true_target() const { return true_target_; }
- Label* false_target() const { return false_target_; }
-
- private:
- Ia32CodeGenerator* owner_;
- TypeofState typeof_state_;
- Label* true_target_;
- Label* false_target_;
- CodeGenState* previous_;
-};
-
-
-// -----------------------------------------------------------------------------
-// Ia32CodeGenerator
-
-class Ia32CodeGenerator: public CodeGenerator {
- public:
- static Handle<Code> MakeCode(FunctionLiteral* fun,
- Handle<Script> script,
- bool is_eval);
-
- MacroAssembler* masm() { return masm_; }
-
- Scope* scope() const { return scope_; }
-
- CodeGenState* state() { return state_; }
- void set_state(CodeGenState* state) { state_ = state; }
-
- private:
- // Assembler
- MacroAssembler* masm_; // to generate code
-
- // Code generation state
- Scope* scope_;
- Condition cc_reg_;
- CodeGenState* state_;
- bool is_inside_try_;
- int break_stack_height_;
-
- // Labels
- Label function_return_;
-
- // Construction/destruction
- Ia32CodeGenerator(int buffer_size,
- Handle<Script> script,
- bool is_eval);
- virtual ~Ia32CodeGenerator() { delete masm_; }
-
- // Main code generation function
- void GenCode(FunctionLiteral* fun);
-
- // The following are used by class Reference.
- void LoadReference(Reference* ref);
- void UnloadReference(Reference* ref);
-
- // State
- bool has_cc() const { return cc_reg_ >= 0; }
- TypeofState typeof_state() const { return state_->typeof_state(); }
- Label* true_target() const { return state_->true_target(); }
- Label* false_target() const { return state_->false_target(); }
-
- // Expressions
- Operand GlobalObject() const {
- return ContextOperand(esi, Context::GLOBAL_INDEX);
- }
-
- // Support functions for accessing parameters.
- Operand ParameterOperand(int index) const {
- int num_parameters = scope()->num_parameters();
- ASSERT(-2 <= index && index < num_parameters);
- return Operand(ebp, (1 + num_parameters - index) * kPointerSize);
- }
-
- Operand ReceiverOperand() const { return ParameterOperand(-1); }
-
- Operand FunctionOperand() const {
- return Operand(ebp, JavaScriptFrameConstants::kFunctionOffset);
- }
-
- Operand ContextOperand(Register context, int index) const {
- return Operand(context, Context::SlotOffset(index));
- }
-
- Operand SlotOperand(Slot* slot, Register tmp);
-
- void LoadCondition(Expression* x,
- TypeofState typeof_state,
- Label* true_target,
- Label* false_target,
- bool force_cc);
- void Load(Expression* x, TypeofState typeof_state = NOT_INSIDE_TYPEOF);
- void LoadGlobal();
-
- // Read a value from a slot and leave it on top of the expression stack.
- void LoadFromSlot(Slot* slot, TypeofState typeof_state);
-
- // Special code for typeof expressions: Unfortunately, we must
- // be careful when loading the expression in 'typeof'
- // expressions. We are not allowed to throw reference errors for
- // non-existing properties of the global object, so we must make it
- // look like an explicit property access, instead of an access
- // through the context chain.
- void LoadTypeofExpression(Expression* x);
-
- void ToBoolean(Label* true_target, Label* false_target);
-
- void GenericBinaryOperation(
- Token::Value op,
- const OverwriteMode overwrite_mode = NO_OVERWRITE);
- void Comparison(Condition cc, bool strict = false);
-
- // Inline small integer literals. To prevent long attacker-controlled byte
- // sequences, we only inline small Smi:s.
- static const int kMaxSmiInlinedBits = 16;
- bool IsInlineSmi(Literal* literal);
- void SmiComparison(Condition cc, Handle<Object> value, bool strict = false);
- void SmiOperation(Token::Value op,
- Handle<Object> value,
- bool reversed,
- OverwriteMode overwrite_mode);
-
- void CallWithArguments(ZoneList<Expression*>* arguments, int position);
-
- // Declare global variables and functions in the given array of
- // name/value pairs.
- virtual void DeclareGlobals(Handle<FixedArray> pairs);
-
- // Instantiate the function boilerplate.
- void InstantiateBoilerplate(Handle<JSFunction> boilerplate);
-
- // Control flow
- void Branch(bool if_true, Label* L);
- void CheckStack();
- void CleanStack(int num_bytes);
-
- // Node visitors
-#define DEF_VISIT(type) \
- virtual void Visit##type(type* node);
- NODE_LIST(DEF_VISIT)
-#undef DEF_VISIT
-
- // Only allow fast-case switch if the range of labels is at most
- // this factor times the number of case labels.
- // Value is derived from comparing the size of code generated by the normal
- // switch code for Smi-labels to the size of a single pointer. If code
- // quality increases this number should be decreased to match.
- static const int kFastSwitchMaxOverheadFactor = 5;
-
- // Minimal number of switch cases required before we allow jump-table
- // optimization.
- static const int kFastSwitchMinCaseCount = 5;
-
- virtual int FastCaseSwitchMaxOverheadFactor();
- virtual int FastCaseSwitchMinCaseCount();
-
- // Generate a computed jump with an empty jump table.
- // Binds a label to the start of the jump table. This table must
- // be populated later when the addresses of the targets are known.
- // Used by GenerateFastCaseSwitchStatement.
- virtual void GenerateFastCaseSwitchJumpTable(
- SwitchStatement* node, int min_index, int range, Label *fail_label,
- SmartPointer<Label*> &case_targets, SmartPointer<Label> &case_labels);
-
- void RecordStatementPosition(Node* node);
-
- // Activation frames.
- void EnterJSFrame();
- void ExitJSFrame();
-
- virtual void GenerateIsSmi(ZoneList<Expression*>* args);
- virtual void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
- virtual void GenerateIsArray(ZoneList<Expression*>* args);
-
- virtual void GenerateArgumentsLength(ZoneList<Expression*>* args);
- virtual void GenerateArgumentsAccess(ZoneList<Expression*>* args);
-
- virtual void GenerateValueOf(ZoneList<Expression*>* args);
- virtual void GenerateSetValueOf(ZoneList<Expression*>* args);
-
- virtual void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
-
- virtual void GenerateObjectEquals(ZoneList<Expression*>* args);
-
- friend class Reference;
- friend class Property;
- friend class VariableProxy;
- friend class Slot;
-};
-
-
// -------------------------------------------------------------------------
// CodeGenState implementation.
-CodeGenState::CodeGenState(Ia32CodeGenerator* owner)
+CodeGenState::CodeGenState(CodeGenerator* owner)
: owner_(owner),
typeof_state_(NOT_INSIDE_TYPEOF),
true_target_(NULL),
}
-CodeGenState::CodeGenState(Ia32CodeGenerator* owner,
+CodeGenState::CodeGenState(CodeGenerator* owner,
TypeofState typeof_state,
Label* true_target,
Label* false_target)
// -----------------------------------------------------------------------------
-// Ia32CodeGenerator implementation
+// CodeGenerator implementation
#define __ masm_->
-Handle<Code> Ia32CodeGenerator::MakeCode(FunctionLiteral* flit,
- Handle<Script> script,
- bool is_eval) {
-#ifdef ENABLE_DISASSEMBLER
- bool print_code = FLAG_print_code && !Bootstrapper::IsActive();
-#endif
-
-#ifdef DEBUG
- bool print_source = false;
- bool print_ast = false;
- const char* ftype;
-
- if (Bootstrapper::IsActive()) {
- print_source = FLAG_print_builtin_source;
- print_ast = FLAG_print_builtin_ast;
- print_code = FLAG_print_builtin_code;
- ftype = "builtin";
- } else {
- print_source = FLAG_print_source;
- print_ast = FLAG_print_ast;
- ftype = "user-defined";
- }
-
- if (FLAG_trace_codegen || print_source || print_ast) {
- PrintF("*** Generate code for %s function: ", ftype);
- flit->name()->ShortPrint();
- PrintF(" ***\n");
- }
-
- if (print_source) {
- PrintF("--- Source from AST ---\n%s\n", PrettyPrinter().PrintProgram(flit));
- }
-
- if (print_ast) {
- PrintF("--- AST ---\n%s\n", AstPrinter().PrintProgram(flit));
- }
-#endif // DEBUG
-
- // Generate code.
- const int initial_buffer_size = 4 * KB;
- Ia32CodeGenerator cgen(initial_buffer_size, script, is_eval);
- cgen.GenCode(flit);
- if (cgen.HasStackOverflow()) {
- ASSERT(!Top::has_pending_exception());
- return Handle<Code>::null();
- }
-
- // Process any deferred code.
- cgen.ProcessDeferred();
-
- // Allocate and install the code.
- CodeDesc desc;
- cgen.masm()->GetCode(&desc);
- ScopeInfo<> sinfo(flit->scope());
- Code::Flags flags = Code::ComputeFlags(Code::FUNCTION);
- Handle<Code> code = Factory::NewCode(desc, &sinfo, flags);
-
- // Add unresolved entries in the code to the fixup list.
- Bootstrapper::AddFixup(*code, cgen.masm());
-
-#ifdef ENABLE_DISASSEMBLER
- if (print_code) {
- // Print the source code if available.
- if (!script->IsUndefined() && !script->source()->IsUndefined()) {
- PrintF("--- Raw source ---\n");
- StringInputBuffer stream(String::cast(script->source()));
- stream.Seek(flit->start_position());
- // flit->end_position() points to the last character in the stream. We
- // need to compensate by adding one to calculate the length.
- int source_len = flit->end_position() - flit->start_position() + 1;
- for (int i = 0; i < source_len; i++) {
- if (stream.has_more()) PrintF("%c", stream.GetNext());
- }
- PrintF("\n\n");
- }
- PrintF("--- Code ---\n");
- code->Disassemble();
- }
-#endif // ENABLE_DISASSEMBLER
-
- return code;
-}
-
-
-Ia32CodeGenerator::Ia32CodeGenerator(int buffer_size,
- Handle<Script> script,
- bool is_eval)
- : CodeGenerator(is_eval, script),
+CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script,
+ bool is_eval)
+ : is_eval_(is_eval),
+ script_(script),
+ deferred_(8),
masm_(new MacroAssembler(NULL, buffer_size)),
scope_(NULL),
cc_reg_(no_condition),
// edi: caller's parameter pointer
// esi: callee's context
-void Ia32CodeGenerator::GenCode(FunctionLiteral* fun) {
+void CodeGenerator::GenCode(FunctionLiteral* fun) {
// Record the position for debugging purposes.
__ RecordPosition(fun->start_position());
}
-Operand Ia32CodeGenerator::SlotOperand(Slot* slot, Register tmp) {
+Operand CodeGenerator::SlotOperand(Slot* slot, Register tmp) {
// Currently, this assertion will fail if we try to assign to
// a constant variable that is constant because it is read-only
// (such as the variable referring to a named function expression).
// register. If force_cc is set, the value is forced to set the condition code
// register and no value is pushed. If the condition code register was set,
// has_cc() is true and cc_reg_ contains the condition to test for 'true'.
-void Ia32CodeGenerator::LoadCondition(Expression* x,
- TypeofState typeof_state,
- Label* true_target,
- Label* false_target,
- bool force_cc) {
+void CodeGenerator::LoadCondition(Expression* x,
+ TypeofState typeof_state,
+ Label* true_target,
+ Label* false_target,
+ bool force_cc) {
ASSERT(!has_cc());
{ CodeGenState new_state(this, typeof_state, true_target, false_target);
}
-void Ia32CodeGenerator::Load(Expression* x, TypeofState typeof_state) {
+void CodeGenerator::Load(Expression* x, TypeofState typeof_state) {
Label true_target;
Label false_target;
LoadCondition(x, typeof_state, &true_target, &false_target, false);
}
-void Ia32CodeGenerator::LoadGlobal() {
+void CodeGenerator::LoadGlobal() {
__ push(GlobalObject());
}
// TODO(1241834): Get rid of this function in favor of just using Load, now
// that we have the INSIDE_TYPEOF typeof state. => Need to handle global
// variables w/o reference errors elsewhere.
-void Ia32CodeGenerator::LoadTypeofExpression(Expression* x) {
+void CodeGenerator::LoadTypeofExpression(Expression* x) {
Variable* variable = x->AsVariableProxy()->AsVariable();
if (variable != NULL && !variable->is_this() && variable->is_global()) {
// NOTE: This is somewhat nasty. We force the compiler to load
}
-Reference::Reference(Ia32CodeGenerator* cgen, Expression* expression)
+Reference::Reference(CodeGenerator* cgen, Expression* expression)
: cgen_(cgen), expression_(expression), type_(ILLEGAL) {
cgen->LoadReference(this);
}
}
-void Ia32CodeGenerator::LoadReference(Reference* ref) {
+void CodeGenerator::LoadReference(Reference* ref) {
Comment cmnt(masm_, "[ LoadReference");
Expression* e = ref->expression();
Property* property = e->AsProperty();
}
-void Ia32CodeGenerator::UnloadReference(Reference* ref) {
+void CodeGenerator::UnloadReference(Reference* ref) {
// Pop a reference from the stack while preserving TOS.
Comment cmnt(masm_, "[ UnloadReference");
int size = ref->size();
// ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and
// convert it to a boolean in the condition code register or jump to
// 'false_target'/'true_target' as appropriate.
-void Ia32CodeGenerator::ToBoolean(Label* true_target, Label* false_target) {
+void CodeGenerator::ToBoolean(Label* true_target, Label* false_target) {
Comment cmnt(masm_, "[ ToBoolean");
// The value to convert should be popped from the stack.
}
-void Ia32CodeGenerator::GenericBinaryOperation(Token::Value op,
+void CodeGenerator::GenericBinaryOperation(Token::Value op,
OverwriteMode overwrite_mode) {
Comment cmnt(masm_, "[ BinaryOperation");
Comment cmnt_token(masm_, Token::String(op));
};
-void Ia32CodeGenerator::SmiOperation(Token::Value op,
+void CodeGenerator::SmiOperation(Token::Value op,
Handle<Object> value,
bool reversed,
OverwriteMode overwrite_mode) {
};
-void Ia32CodeGenerator::Comparison(Condition cc, bool strict) {
+void CodeGenerator::Comparison(Condition cc, bool strict) {
// Strict only makes sense for equality comparisons.
ASSERT(!strict || cc == equal);
}
-void Ia32CodeGenerator::SmiComparison(Condition cc,
+void CodeGenerator::SmiComparison(Condition cc,
Handle<Object> value,
bool strict) {
// Strict only makes sense for equality comparisons.
// Call the function just below TOS on the stack with the given
// arguments. The receiver is the TOS.
-void Ia32CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
+void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
int position) {
// Push the arguments ("left-to-right") on the stack.
for (int i = 0; i < args->length(); i++) {
}
-void Ia32CodeGenerator::Branch(bool if_true, Label* L) {
+void CodeGenerator::Branch(bool if_true, Label* L) {
ASSERT(has_cc());
Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_);
__ j(cc, L);
}
-void Ia32CodeGenerator::CheckStack() {
+void CodeGenerator::CheckStack() {
if (FLAG_check_stack) {
Label stack_is_ok;
StackCheckStub stub;
}
-void Ia32CodeGenerator::VisitBlock(Block* node) {
+void CodeGenerator::VisitBlock(Block* node) {
Comment cmnt(masm_, "[ Block");
RecordStatementPosition(node);
node->set_break_stack_height(break_stack_height_);
}
-void Ia32CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
+void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
__ push(Immediate(pairs));
__ push(Operand(esi));
__ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0)));
}
-void Ia32CodeGenerator::VisitDeclaration(Declaration* node) {
+void CodeGenerator::VisitDeclaration(Declaration* node) {
Comment cmnt(masm_, "[ Declaration");
Variable* var = node->proxy()->var();
ASSERT(var != NULL); // must have been resolved
}
-void Ia32CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) {
+void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) {
Comment cmnt(masm_, "[ ExpressionStatement");
RecordStatementPosition(node);
Expression* expression = node->expression();
}
-void Ia32CodeGenerator::VisitEmptyStatement(EmptyStatement* node) {
+void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) {
Comment cmnt(masm_, "// EmptyStatement");
// nothing to do
}
-void Ia32CodeGenerator::VisitIfStatement(IfStatement* node) {
+void CodeGenerator::VisitIfStatement(IfStatement* node) {
Comment cmnt(masm_, "[ IfStatement");
// Generate different code depending on which
// parts of the if statement are present or not.
}
-void Ia32CodeGenerator::CleanStack(int num_bytes) {
+void CodeGenerator::CleanStack(int num_bytes) {
ASSERT(num_bytes >= 0);
if (num_bytes > 0) {
__ add(Operand(esp), Immediate(num_bytes));
}
-void Ia32CodeGenerator::VisitContinueStatement(ContinueStatement* node) {
+void CodeGenerator::VisitContinueStatement(ContinueStatement* node) {
Comment cmnt(masm_, "[ ContinueStatement");
RecordStatementPosition(node);
CleanStack(break_stack_height_ - node->target()->break_stack_height());
}
-void Ia32CodeGenerator::VisitBreakStatement(BreakStatement* node) {
+void CodeGenerator::VisitBreakStatement(BreakStatement* node) {
Comment cmnt(masm_, "[ BreakStatement");
RecordStatementPosition(node);
CleanStack(break_stack_height_ - node->target()->break_stack_height());
}
-void Ia32CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
+void CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
Comment cmnt(masm_, "[ ReturnStatement");
RecordStatementPosition(node);
Load(node->expression());
}
-void Ia32CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) {
+void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) {
Comment cmnt(masm_, "[ WithEnterStatement");
RecordStatementPosition(node);
Load(node->expression());
}
-void Ia32CodeGenerator::VisitWithExitStatement(WithExitStatement* node) {
+void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) {
Comment cmnt(masm_, "[ WithExitStatement");
// Pop context.
__ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX));
__ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
}
-int Ia32CodeGenerator::FastCaseSwitchMaxOverheadFactor() {
+int CodeGenerator::FastCaseSwitchMaxOverheadFactor() {
return kFastSwitchMaxOverheadFactor;
}
-int Ia32CodeGenerator::FastCaseSwitchMinCaseCount() {
+int CodeGenerator::FastCaseSwitchMinCaseCount() {
return kFastSwitchMinCaseCount;
}
// Generate a computed jump to a switch case.
-void Ia32CodeGenerator::GenerateFastCaseSwitchJumpTable(
+void CodeGenerator::GenerateFastCaseSwitchJumpTable(
SwitchStatement* node, int min_index, int range, Label *fail_label,
SmartPointer<Label*> &case_targets, SmartPointer<Label> &case_labels) {
// Notice: Internal references, used by both the jmp instruction and
}
-void Ia32CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
+void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
Comment cmnt(masm_, "[ SwitchStatement");
RecordStatementPosition(node);
node->set_break_stack_height(break_stack_height_);
}
-void Ia32CodeGenerator::VisitLoopStatement(LoopStatement* node) {
+void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
Comment cmnt(masm_, "[ LoopStatement");
RecordStatementPosition(node);
node->set_break_stack_height(break_stack_height_);
}
-void Ia32CodeGenerator::VisitForInStatement(ForInStatement* node) {
+void CodeGenerator::VisitForInStatement(ForInStatement* node) {
Comment cmnt(masm_, "[ ForInStatement");
RecordStatementPosition(node);
}
-void Ia32CodeGenerator::VisitTryCatch(TryCatch* node) {
+void CodeGenerator::VisitTryCatch(TryCatch* node) {
Comment cmnt(masm_, "[ TryCatch");
Label try_block, exit;
}
-void Ia32CodeGenerator::VisitTryFinally(TryFinally* node) {
+void CodeGenerator::VisitTryFinally(TryFinally* node) {
Comment cmnt(masm_, "[ TryFinally");
// State: Used to keep track of reason for entering the finally
}
-void Ia32CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
+void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
Comment cmnt(masm_, "[ DebuggerStatement");
RecordStatementPosition(node);
__ CallRuntime(Runtime::kDebugBreak, 1);
}
-void Ia32CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) {
+void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) {
ASSERT(boilerplate->IsBoilerplate());
// Push the boilerplate on the stack.
}
-void Ia32CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
+void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
Comment cmnt(masm_, "[ FunctionLiteral");
// Build the function boilerplate and instantiate it.
}
-void Ia32CodeGenerator::VisitFunctionBoilerplateLiteral(
+void CodeGenerator::VisitFunctionBoilerplateLiteral(
FunctionBoilerplateLiteral* node) {
Comment cmnt(masm_, "[ FunctionBoilerplateLiteral");
InstantiateBoilerplate(node->boilerplate());
}
-void Ia32CodeGenerator::VisitConditional(Conditional* node) {
+void CodeGenerator::VisitConditional(Conditional* node) {
Comment cmnt(masm_, "[ Conditional");
Label then, else_, exit;
LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
}
-void Ia32CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
+void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
if (slot->type() == Slot::LOOKUP) {
ASSERT(slot->var()->mode() == Variable::DYNAMIC);
}
-void Ia32CodeGenerator::VisitSlot(Slot* node) {
+void CodeGenerator::VisitSlot(Slot* node) {
Comment cmnt(masm_, "[ Slot");
LoadFromSlot(node, typeof_state());
}
-void Ia32CodeGenerator::VisitVariableProxy(VariableProxy* node) {
+void CodeGenerator::VisitVariableProxy(VariableProxy* node) {
Comment cmnt(masm_, "[ VariableProxy");
Variable* var = node->var();
Expression* expr = var->rewrite();
}
-void Ia32CodeGenerator::VisitLiteral(Literal* node) {
+void CodeGenerator::VisitLiteral(Literal* node) {
Comment cmnt(masm_, "[ Literal");
if (node->handle()->IsSmi() && !IsInlineSmi(node)) {
// To prevent long attacker-controlled byte sequences in code, larger
}
-void Ia32CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) {
+void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) {
Comment cmnt(masm_, "[ RegExp Literal");
RegExpDeferred* deferred = new RegExpDeferred(this, node);
}
-void Ia32CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
+void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
Comment cmnt(masm_, "[ ObjectLiteral");
ObjectLiteralDeferred* deferred = new ObjectLiteralDeferred(this, node);
}
-void Ia32CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
+void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
Comment cmnt(masm_, "[ ArrayLiteral");
// Call runtime to create the array literal.
}
-bool Ia32CodeGenerator::IsInlineSmi(Literal* literal) {
+bool CodeGenerator::IsInlineSmi(Literal* literal) {
if (literal == NULL || !literal->handle()->IsSmi()) return false;
int int_value = Smi::cast(*literal->handle())->value();
return is_intn(int_value, kMaxSmiInlinedBits);
}
-void Ia32CodeGenerator::VisitAssignment(Assignment* node) {
+void CodeGenerator::VisitAssignment(Assignment* node) {
Comment cmnt(masm_, "[ Assignment");
RecordStatementPosition(node);
}
-void Ia32CodeGenerator::VisitThrow(Throw* node) {
+void CodeGenerator::VisitThrow(Throw* node) {
Comment cmnt(masm_, "[ Throw");
Load(node->exception());
}
-void Ia32CodeGenerator::VisitProperty(Property* node) {
+void CodeGenerator::VisitProperty(Property* node) {
Comment cmnt(masm_, "[ Property");
+
Reference property(this, node);
property.GetValue(typeof_state());
}
-void Ia32CodeGenerator::VisitCall(Call* node) {
+void CodeGenerator::VisitCall(Call* node) {
Comment cmnt(masm_, "[ Call");
ZoneList<Expression*>* args = node->arguments();
}
-void Ia32CodeGenerator::VisitCallNew(CallNew* node) {
+void CodeGenerator::VisitCallNew(CallNew* node) {
Comment cmnt(masm_, "[ CallNew");
// According to ECMA-262, section 11.2.2, page 44, the function
}
-void Ia32CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));
__ pop(eax);
}
-void Ia32CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));
__ pop(eax);
// cons strings where the answer is found in the left hand branch of the
// cons. The slow case will flatten the string, which will ensure that
// the answer is in the left hand side the next time around.
-void Ia32CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
ASSERT(args->length() == 2);
Label slow_case;
}
-void Ia32CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));
Label answer;
}
-void Ia32CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
ASSERT(args->length() == 0);
// Seed the result with the formal parameters count, which will be
}
-void Ia32CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Label leave;
Load(args->at(0)); // Load the object.
}
-void Ia32CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) {
ASSERT(args->length() == 2);
Label leave;
Load(args->at(0)); // Load the object.
}
-void Ia32CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
// Load the key onto the stack and set register eax to the formal
}
-void Ia32CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) {
ASSERT(args->length() == 2);
// Load the two objects into registers and perform the comparison.
}
-void Ia32CodeGenerator::VisitCallRuntime(CallRuntime* node) {
+void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
if (CheckForInlineRuntimeCall(node)) return;
ZoneList<Expression*>* args = node->arguments();
}
-void Ia32CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
+void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
Comment cmnt(masm_, "[ UnaryOperation");
Token::Value op = node->op();
}
-void Ia32CodeGenerator::VisitCountOperation(CountOperation* node) {
+void CodeGenerator::VisitCountOperation(CountOperation* node) {
Comment cmnt(masm_, "[ CountOperation");
bool is_postfix = node->is_postfix();
}
-void Ia32CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
+void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
Comment cmnt(masm_, "[ BinaryOperation");
Token::Value op = node->op();
}
-void Ia32CodeGenerator::VisitThisFunction(ThisFunction* node) {
+void CodeGenerator::VisitThisFunction(ThisFunction* node) {
__ push(FunctionOperand());
}
};
-void Ia32CodeGenerator::VisitCompareOperation(CompareOperation* node) {
+void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
Comment cmnt(masm_, "[ CompareOperation");
// Get the expressions from the node.
}
-void Ia32CodeGenerator::RecordStatementPosition(Node* node) {
+void CodeGenerator::RecordStatementPosition(Node* node) {
if (FLAG_debug_info) {
int pos = node->statement_pos();
if (pos != RelocInfo::kNoPosition) {
}
-void Ia32CodeGenerator::EnterJSFrame() {
+void CodeGenerator::EnterJSFrame() {
__ push(ebp);
__ mov(ebp, Operand(esp));
}
-void Ia32CodeGenerator::ExitJSFrame() {
+void CodeGenerator::ExitJSFrame() {
// Record the location of the JS exit code for patching when setting
// break point.
__ RecordJSReturn();
#undef __
-// -----------------------------------------------------------------------------
-// CodeGenerator interfaces
-
-// MakeCode() is just a wrapper for CodeGenerator::MakeCode()
-// so we don't have to expose the entire CodeGenerator class in
-// the .h file.
-Handle<Code> CodeGenerator::MakeCode(FunctionLiteral* fun,
- Handle<Script> script,
- bool is_eval) {
- Handle<Code> code = Ia32CodeGenerator::MakeCode(fun, script, is_eval);
- if (!code.is_null()) {
- Counters::total_compiled_code_size.Increment(code->instruction_size());
- }
- return code;
-}
-
-
} } // namespace v8::internal
--- /dev/null
+// Copyright 2006-2008 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:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_CODEGEN_IA32_H_
+#define V8_CODEGEN_IA32_H_
+
+#include "scopes.h"
+
+namespace v8 { namespace internal {
+
+// Forward declarations
+class DeferredCode;
+
+// Mode to overwrite BinaryExpression values.
+enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
+
+
+// -----------------------------------------------------------------------------
+// Reference support
+
+// A reference is a C++ stack-allocated object that keeps an ECMA
+// reference on the execution stack while in scope. For variables
+// the reference is empty, indicating that it isn't necessary to
+// store state on the stack for keeping track of references to those.
+// For properties, we keep either one (named) or two (indexed) values
+// on the execution stack to represent the reference.
+
+enum InitState { CONST_INIT, NOT_CONST_INIT };
+enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
+
+class Reference BASE_EMBEDDED {
+ public:
+ // The values of the types is important, see size().
+ enum Type { ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 };
+ Reference(CodeGenerator* cgen, Expression* expression);
+ ~Reference();
+
+ Expression* expression() const { return expression_; }
+ Type type() const { return type_; }
+ void set_type(Type value) {
+ ASSERT(type_ == ILLEGAL);
+ type_ = value;
+ }
+
+ // The size of the reference or -1 if the reference is illegal.
+ int size() const { return type_; }
+
+ bool is_illegal() const { return type_ == ILLEGAL; }
+ bool is_slot() const { return type_ == SLOT; }
+ bool is_property() const { return type_ == NAMED || type_ == KEYED; }
+
+ // Return the name. Only valid for named property references.
+ Handle<String> GetName();
+
+ // Generate code to push the value of the reference on top of the
+ // expression stack. The reference is expected to be already on top of
+ // the expression stack, and it is left in place with its value above it.
+ void GetValue(TypeofState typeof_state);
+
+ // Generate code to store the value on top of the expression stack in the
+ // reference. The reference is expected to be immediately below the value
+ // on the expression stack. The stored value is left in place (with the
+ // reference intact below it) to support chained assignments.
+ void SetValue(InitState init_state);
+
+ private:
+ CodeGenerator* cgen_;
+ Expression* expression_;
+ Type type_;
+};
+
+
+// -------------------------------------------------------------------------
+// Code generation state
+
+// The state is passed down the AST by the code generator (and back up, in
+// the form of the state of the label pair). It is threaded through the
+// call stack. Constructing a state implicitly pushes it on the owning code
+// generator's stack of states, and destroying one implicitly pops it.
+
+class CodeGenState BASE_EMBEDDED {
+ public:
+ // Create an initial code generator state. Destroying the initial state
+ // leaves the code generator with a NULL state.
+ explicit CodeGenState(CodeGenerator* owner);
+
+ // Create a code generator state based on a code generator's current
+ // state. The new state has its own access type and pair of branch
+ // labels, and no reference.
+ CodeGenState(CodeGenerator* owner,
+ TypeofState typeof_state,
+ Label* true_target,
+ Label* false_target);
+
+ // Destroy a code generator state and restore the owning code generator's
+ // previous state.
+ ~CodeGenState();
+
+ TypeofState typeof_state() const { return typeof_state_; }
+ Label* true_target() const { return true_target_; }
+ Label* false_target() const { return false_target_; }
+
+ private:
+ CodeGenerator* owner_;
+ TypeofState typeof_state_;
+ Label* true_target_;
+ Label* false_target_;
+ CodeGenState* previous_;
+};
+
+
+
+
+// -----------------------------------------------------------------------------
+// CodeGenerator
+
+//
+class CodeGenerator: public Visitor {
+ public:
+ // Takes a function literal, generates code for it. This function should only
+ // be called by compiler.cc.
+ static Handle<Code> MakeCode(FunctionLiteral* fun,
+ Handle<Script> script,
+ bool is_eval);
+
+ static void SetFunctionInfo(Handle<JSFunction> fun,
+ int length,
+ int function_token_position,
+ int start_position,
+ int end_position,
+ bool is_expression,
+ bool is_toplevel,
+ Handle<Script> script);
+
+ // Accessors
+ MacroAssembler* masm() { return masm_; }
+
+ CodeGenState* state() { return state_; }
+ void set_state(CodeGenState* state) { state_ = state; }
+
+ void AddDeferred(DeferredCode* code) { deferred_.Add(code); }
+
+ private:
+ // Construction/Destruction
+ CodeGenerator(int buffer_size, Handle<Script> script, bool is_eval);
+ virtual ~CodeGenerator() { delete masm_; }
+
+ // Accessors
+ Scope* scope() const { return scope_; }
+
+ void ProcessDeferred();
+
+ bool is_eval() { return is_eval_; }
+
+ // State
+ bool has_cc() const { return cc_reg_ >= 0; }
+ TypeofState typeof_state() const { return state_->typeof_state(); }
+ Label* true_target() const { return state_->true_target(); }
+ Label* false_target() const { return state_->false_target(); }
+
+
+ // Node visitors.
+#define DEF_VISIT(type) \
+ void Visit##type(type* node);
+ NODE_LIST(DEF_VISIT)
+#undef DEF_VISIT
+
+ // Main code generation function
+ void GenCode(FunctionLiteral* fun);
+
+ // The following are used by class Reference.
+ void LoadReference(Reference* ref);
+ void UnloadReference(Reference* ref);
+
+ // Support functions for accessing parameters and other operands.
+ Operand ParameterOperand(int index) const {
+ int num_parameters = scope()->num_parameters();
+ ASSERT(-2 <= index && index < num_parameters);
+ return Operand(ebp, (1 + num_parameters - index) * kPointerSize);
+ }
+
+ Operand ReceiverOperand() const { return ParameterOperand(-1); }
+
+ Operand FunctionOperand() const {
+ return Operand(ebp, JavaScriptFrameConstants::kFunctionOffset);
+ }
+
+ Operand ContextOperand(Register context, int index) const {
+ return Operand(context, Context::SlotOffset(index));
+ }
+
+ Operand SlotOperand(Slot* slot, Register tmp);
+
+
+ // Expressions
+ Operand GlobalObject() const {
+ return ContextOperand(esi, Context::GLOBAL_INDEX);
+ }
+
+ void LoadCondition(Expression* x,
+ TypeofState typeof_state,
+ Label* true_target,
+ Label* false_target,
+ bool force_cc);
+ void Load(Expression* x, TypeofState typeof_state = NOT_INSIDE_TYPEOF);
+ void LoadGlobal();
+
+ // Read a value from a slot and leave it on top of the expression stack.
+ void LoadFromSlot(Slot* slot, TypeofState typeof_state);
+
+ // Special code for typeof expressions: Unfortunately, we must
+ // be careful when loading the expression in 'typeof'
+ // expressions. We are not allowed to throw reference errors for
+ // non-existing properties of the global object, so we must make it
+ // look like an explicit property access, instead of an access
+ // through the context chain.
+ void LoadTypeofExpression(Expression* x);
+
+ void ToBoolean(Label* true_target, Label* false_target);
+
+ void GenericBinaryOperation(Token::Value op,
+ const OverwriteMode overwrite_mode = NO_OVERWRITE);
+ void Comparison(Condition cc, bool strict = false);
+
+ // Inline small integer literals. To prevent long attacker-controlled byte
+ // sequences, we only inline small Smi:s.
+ static const int kMaxSmiInlinedBits = 16;
+ bool IsInlineSmi(Literal* literal);
+ void SmiComparison(Condition cc, Handle<Object> value, bool strict = false);
+ void SmiOperation(Token::Value op,
+ Handle<Object> value,
+ bool reversed,
+ OverwriteMode overwrite_mode);
+
+ void CallWithArguments(ZoneList<Expression*>* arguments, int position);
+
+ // Control flow
+ void Branch(bool if_true, Label* L);
+ void CheckStack();
+ void CleanStack(int num_bytes);
+
+ bool CheckForInlineRuntimeCall(CallRuntime* node);
+ Handle<JSFunction> BuildBoilerplate(FunctionLiteral* node);
+ void ProcessDeclarations(ZoneList<Declaration*>* declarations);
+
+ Handle<Code> ComputeCallInitialize(int argc);
+
+ // Declare global variables and functions in the given array of
+ // name/value pairs.
+ void DeclareGlobals(Handle<FixedArray> pairs);
+
+ // Instantiate the function boilerplate.
+ void InstantiateBoilerplate(Handle<JSFunction> boilerplate);
+
+ // Support for type checks.
+ void GenerateIsSmi(ZoneList<Expression*>* args);
+ void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
+ void GenerateIsArray(ZoneList<Expression*>* args);
+
+ // Support for arguments.length and arguments[?].
+ void GenerateArgumentsLength(ZoneList<Expression*>* args);
+ void GenerateArgumentsAccess(ZoneList<Expression*>* args);
+
+ // Support for accessing the value field of an object (used by Date).
+ void GenerateValueOf(ZoneList<Expression*>* args);
+ void GenerateSetValueOf(ZoneList<Expression*>* args);
+
+ // Fast support for charCodeAt(n).
+ void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
+
+ // Fast support for object equality testing.
+ void GenerateObjectEquals(ZoneList<Expression*>* args);
+
+
+ // Methods and constants for fast case switch statement support.
+ //
+ // Only allow fast-case switch if the range of labels is at most
+ // this factor times the number of case labels.
+ // Value is derived from comparing the size of code generated by the normal
+ // switch code for Smi-labels to the size of a single pointer. If code
+ // quality increases this number should be decreased to match.
+ static const int kFastSwitchMaxOverheadFactor = 5;
+
+ // Minimal number of switch cases required before we allow jump-table
+ // optimization.
+ static const int kFastSwitchMinCaseCount = 5;
+
+ // The limit of the range of a fast-case switch, as a factor of the number
+ // of cases of the switch. Each platform should return a value that
+ // is optimal compared to the default code generated for a switch statement
+ // on that platform.
+ int FastCaseSwitchMaxOverheadFactor();
+
+ // The minimal number of cases in a switch before the fast-case switch
+ // optimization is enabled. Each platform should return a value that
+ // is optimal compared to the default code generated for a switch statement
+ // on that platform.
+ int FastCaseSwitchMinCaseCount();
+
+ // Allocate a jump table and create code to jump through it.
+ // Should call GenerateFastCaseSwitchCases to generate the code for
+ // all the cases at the appropriate point.
+ void GenerateFastCaseSwitchJumpTable(SwitchStatement* node, int min_index,
+ int range, Label *fail_label,
+ SmartPointer<Label*> &case_targets,
+ SmartPointer<Label>& case_labels);
+
+ // Generate the code for cases for the fast case switch.
+ // Called by GenerateFastCaseSwitchJumpTable.
+ void GenerateFastCaseSwitchCases(SwitchStatement* node,
+ SmartPointer<Label> &case_labels);
+
+ // Fast support for constant-Smi switches.
+ void GenerateFastCaseSwitchStatement(SwitchStatement *node, int min_index,
+ int range, int default_index);
+
+ // Fast support for constant-Smi switches. Tests whether switch statement
+ // permits optimization and calls GenerateFastCaseSwitch if it does.
+ // Returns true if the fast-case switch was generated, and false if not.
+ bool TryGenerateFastCaseSwitchStatement(SwitchStatement *node);
+
+
+ // Bottle-neck interface to call the Assembler to generate the statement
+ // position. This allows us to easily control whether statement positions
+ // should be generated or not.
+ void RecordStatementPosition(Node* node);
+
+ // Activation frames.
+ void EnterJSFrame();
+ void ExitJSFrame();
+
+
+ bool is_eval_; // Tells whether code is generated for eval.
+ Handle<Script> script_;
+ List<DeferredCode*> deferred_;
+
+ // Assembler
+ MacroAssembler* masm_; // to generate code
+
+ // Code generation state
+ Scope* scope_;
+ Condition cc_reg_;
+ CodeGenState* state_;
+ bool is_inside_try_;
+ int break_stack_height_;
+
+ // Labels
+ Label function_return_;
+
+ friend class Reference;
+ friend class Property;
+ friend class VariableProxy;
+ friend class Slot;
+
+ DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
+};
+
+
+} } // namespace v8::internal
+
+#endif // V8_CODEGEN_IA32_H_
#include "v8.h"
+#include "bootstrapper.h"
#include "codegen-inl.h"
#include "debug.h"
+#include "prettyprinter.h"
+#include "scopeinfo.h"
#include "runtime.h"
#include "stub-cache.h"
}
+// Generate the code. Takes a function literal, generates code for it, assemble
+// all the pieces into a Code object. This function is only to be called by
+// the compiler.cc code.
+Handle<Code> CodeGenerator::MakeCode(FunctionLiteral* flit,
+ Handle<Script> script,
+ bool is_eval) {
+#ifdef ENABLE_DISASSEMBLER
+ bool print_code = FLAG_print_code && !Bootstrapper::IsActive();
+#endif
+
+#ifdef DEBUG
+ bool print_source = false;
+ bool print_ast = false;
+ const char* ftype;
+
+ if (Bootstrapper::IsActive()) {
+ print_source = FLAG_print_builtin_source;
+ print_ast = FLAG_print_builtin_ast;
+ print_code = FLAG_print_builtin_code;
+ ftype = "builtin";
+ } else {
+ print_source = FLAG_print_source;
+ print_ast = FLAG_print_ast;
+ ftype = "user-defined";
+ }
+
+ if (FLAG_trace_codegen || print_source || print_ast) {
+ PrintF("*** Generate code for %s function: ", ftype);
+ flit->name()->ShortPrint();
+ PrintF(" ***\n");
+ }
+
+ if (print_source) {
+ PrintF("--- Source from AST ---\n%s\n", PrettyPrinter().PrintProgram(flit));
+ }
+
+ if (print_ast) {
+ PrintF("--- AST ---\n%s\n", AstPrinter().PrintProgram(flit));
+ }
+#endif // DEBUG
+
+ // Generate code.
+ const int initial_buffer_size = 4 * KB;
+ CodeGenerator cgen(initial_buffer_size, script, is_eval);
+ cgen.GenCode(flit);
+ if (cgen.HasStackOverflow()) {
+ ASSERT(!Top::has_pending_exception());
+ return Handle<Code>::null();
+ }
+
+ // Process any deferred code.
+ cgen.ProcessDeferred();
+
+ // Allocate and install the code.
+ CodeDesc desc;
+ cgen.masm()->GetCode(&desc);
+ ScopeInfo<> sinfo(flit->scope());
+ Code::Flags flags = Code::ComputeFlags(Code::FUNCTION);
+ Handle<Code> code = Factory::NewCode(desc, &sinfo, flags);
+
+ // Add unresolved entries in the code to the fixup list.
+ Bootstrapper::AddFixup(*code, cgen.masm());
+
+#ifdef ENABLE_DISASSEMBLER
+ if (print_code) {
+ // Print the source code if available.
+ if (!script->IsUndefined() && !script->source()->IsUndefined()) {
+ PrintF("--- Raw source ---\n");
+ StringInputBuffer stream(String::cast(script->source()));
+ stream.Seek(flit->start_position());
+ // flit->end_position() points to the last character in the stream. We
+ // need to compensate by adding one to calculate the length.
+ int source_len = flit->end_position() - flit->start_position() + 1;
+ for (int i = 0; i < source_len; i++) {
+ if (stream.has_more()) PrintF("%c", stream.GetNext());
+ }
+ PrintF("\n\n");
+ }
+ PrintF("--- Code ---\n");
+ code->Disassemble();
+ }
+#endif // ENABLE_DISASSEMBLER
+
+ if (!code.is_null()) {
+ Counters::total_compiled_code_size.Increment(code->instruction_size());
+ }
+
+ return code;
+}
+
+
// Sets the function info on a function.
// The start_position points to the first '(' character after the function name
// in the full script source. When counting characters in the script source the
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef V8_CODEGEN_H_
+#define V8_CODEGEN_H_
#include "ast.h"
#include "code-stubs.h"
#include "runtime.h"
-#define V8_CODEGEN_H_
+// Include the declaration of the architecture defined class CodeGenerator.
+// The contract to the shared code is that the the CodeGenerator is a subclass
+// of Visitor and that the following methods are available publicly:
+// CodeGenerator::MakeCode
+// CodeGenerator::SetFunctionInfo
+// CodeGenerator::AddDeferred
+// CodeGenerator::masm
+//
+// These methods are either used privately by the shared code or implemented as
+// shared code:
+// CodeGenerator::CodeGenerator
+// CodeGenerator::~CodeGenerator
+// CodeGenerator::ProcessDeferred
+// CodeGenerator::GenCode
+// CodeGenerator::BuildBoilerplate
+// CodeGenerator::ComputeCallInitialize
+// CodeGenerator::ProcessDeclarations
+// CodeGenerator::DeclareGlobals
+// CodeGenerator::CheckForInlineRuntimeCall
+// CodeGenerator::GenerateFastCaseSwitchStatement
+// CodeGenerator::GenerateFastCaseSwitchCases
+// CodeGenerator::TryGenerateFastCaseSwitchStatement
+// CodeGenerator::GenerateFastCaseSwitchJumpTable
+// CodeGenerator::FastCaseSwitchMinCaseCount
+// CodeGenerator::FastCaseSwitchMaxOverheadFactor
+
+#if defined(ARM)
+#include "codegen-arm.h"
+#else
+#include "codegen-ia32.h"
+#endif
namespace v8 { namespace internal {
// and we can only run the tests with --nolazy.
-// Forward declaration.
-class CodeGenerator;
-
-
// Deferred code objects are small pieces of code that are compiled
// out of line. They are used to defer the compilation of uncommon
// paths thereby avoiding expensive jumps around uncommon code parts.
};
-// A superclass for code generators. The implementations of methods
-// declared in this class are partially in codegen.c and partially in
-// codegen_<arch>.c.
-class CodeGenerator: public Visitor {
- public:
- CodeGenerator(bool is_eval,
- Handle<Script> script)
- : is_eval_(is_eval),
- script_(script),
- deferred_(8) { }
-
-
- // The code generator: Takes a function literal, generates code for it,
- // and assembles it all into a Code* object. This function should only
- // be called by compiler.cc.
- static Handle<Code> MakeCode(FunctionLiteral* fun,
- Handle<Script> script,
- bool is_eval);
-
- static void SetFunctionInfo(Handle<JSFunction> fun,
- int length,
- int function_token_position,
- int start_position,
- int end_position,
- bool is_expression,
- bool is_toplevel,
- Handle<Script> script);
-
- virtual MacroAssembler* masm() = 0;
-
- virtual Scope* scope() const = 0;
-
- void AddDeferred(DeferredCode* code) { deferred_.Add(code); }
- void ProcessDeferred();
-
- // Accessors for is_eval.
- bool is_eval() { return is_eval_; }
-
- // Abstract node visitors.
-#define DEF_VISIT(type) \
- virtual void Visit##type(type* node) = 0;
- NODE_LIST(DEF_VISIT)
-#undef DEF_VISIT
-
- protected:
- bool CheckForInlineRuntimeCall(CallRuntime* node);
- Handle<JSFunction> BuildBoilerplate(FunctionLiteral* node);
- void ProcessDeclarations(ZoneList<Declaration*>* declarations);
-
- Handle<Code> ComputeCallInitialize(int argc);
-
- // Declare global variables and functions in the given array of
- // name/value pairs.
- virtual void DeclareGlobals(Handle<FixedArray> pairs) = 0;
-
- // Support for type checks.
- virtual void GenerateIsSmi(ZoneList<Expression*>* args) = 0;
- virtual void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) = 0;
- virtual void GenerateIsArray(ZoneList<Expression*>* args) = 0;
-
- // Support for arguments.length and arguments[?].
- virtual void GenerateArgumentsLength(ZoneList<Expression*>* args) = 0;
- virtual void GenerateArgumentsAccess(ZoneList<Expression*>* args) = 0;
-
- // Support for accessing the value field of an object (used by Date).
- virtual void GenerateValueOf(ZoneList<Expression*>* args) = 0;
- virtual void GenerateSetValueOf(ZoneList<Expression*>* args) = 0;
-
- // Fast support for charCodeAt(n).
- virtual void GenerateFastCharCodeAt(ZoneList<Expression*>* args) = 0;
-
- // Fast support for object equality testing.
- virtual void GenerateObjectEquals(ZoneList<Expression*>* args) = 0;
-
-
- // Multiple methods for fast case switch statement support.
-
- // The limit of the range of a fast-case switch, as a factor of the number
- // of cases of the switch. Each platform should return a value that
- // is optimal compared to the default code generated for a switch statement
- // on that platform.
- virtual int FastCaseSwitchMaxOverheadFactor() = 0;
-
- // The minimal number of cases in a switch before the fast-case switch
- // optimization is enabled. Each platform should return a value that
- // is optimal compared to the default code generated for a switch statement
- // on that platform.
- virtual int FastCaseSwitchMinCaseCount() = 0;
-
- // Allocate a jump table and create code to jump through it.
- // Should call GenerateFastCaseSwitchCases to generate the code for
- // all the cases at the appropriate point.
- virtual void GenerateFastCaseSwitchJumpTable(
- SwitchStatement* node, int min_index, int range, Label *fail_label,
- SmartPointer<Label*> &case_targets, SmartPointer<Label>& case_labels) = 0;
-
- // Generate the code for cases for the fast case switch.
- // Called by GenerateFastCaseSwitchJumpTable.
- virtual void GenerateFastCaseSwitchCases(
- SwitchStatement* node, SmartPointer<Label> &case_labels);
-
- // Fast support for constant-Smi switches.
- virtual void GenerateFastCaseSwitchStatement(
- SwitchStatement *node, int min_index, int range, int default_index);
-
- // Fast support for constant-Smi switches. Tests whether switch statement
- // permits optimization and calls GenerateFastCaseSwitch if it does.
- // Returns true if the fast-case switch was generated, and false if not.
- virtual bool TryGenerateFastCaseSwitchStatement(SwitchStatement *node);
-
-
- private:
- bool is_eval_; // Tells whether code is generated for eval.
- Handle<Script> script_;
- List<DeferredCode*> deferred_;
-};
-
-
// RuntimeStub models code stubs calling entry points in the Runtime class.
class RuntimeStub : public CodeStub {
public:
8900116B0E71CA2300F91F35 /* libraries.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = libraries.cc; sourceTree = "<group>"; };
89495E460E79FC23001F68C3 /* compilation-cache.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "compilation-cache.cc"; sourceTree = "<group>"; };
89495E470E79FC23001F68C3 /* compilation-cache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "compilation-cache.h"; sourceTree = "<group>"; };
+ 8964482B0E9C00F700E7C516 /* codegen-ia32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "codegen-ia32.h"; sourceTree = "<group>"; };
+ 896448BC0E9D530500E7C516 /* codegen-arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "codegen-arm.h"; sourceTree = "<group>"; };
8970F2F00E719FB2006AE7B5 /* libv8.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libv8.a; sourceTree = BUILT_PRODUCTS_DIR; };
897F767A0E71B4CC007ACF34 /* v8_shell */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = v8_shell; sourceTree = BUILT_PRODUCTS_DIR; };
897FF0D40E719A8500D62E90 /* v8-debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "v8-debug.h"; sourceTree = "<group>"; };
897FF1B50E719C0900D62E90 /* shell.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = shell.cc; sourceTree = "<group>"; };
897FF1B60E719C2300D62E90 /* js2c.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = js2c.py; sourceTree = "<group>"; };
897FF1B70E719C2E00D62E90 /* macros.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; name = macros.py; path = ../src/macros.py; sourceTree = "<group>"; };
- 89B12E8D0E7FF2A40080BA62 /* presubmit.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = presubmit.py; sourceTree = "<group>"; };
897FF1BF0E719CB600D62E90 /* libjscre.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjscre.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 89B12E8D0E7FF2A40080BA62 /* presubmit.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = presubmit.py; sourceTree = "<group>"; };
89F23C870E78D5B2006B2466 /* libv8-arm.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libv8-arm.a"; sourceTree = BUILT_PRODUCTS_DIR; };
89F23C950E78D5B6006B2466 /* v8_shell-arm */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "v8_shell-arm"; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
897FF1120E719B8F00D62E90 /* code-stubs.h */,
897FF1130E719B8F00D62E90 /* code.h */,
897FF1140E719B8F00D62E90 /* codegen-arm.cc */,
+ 896448BC0E9D530500E7C516 /* codegen-arm.h */,
897FF1150E719B8F00D62E90 /* codegen-ia32.cc */,
+ 8964482B0E9C00F700E7C516 /* codegen-ia32.h */,
897FF1160E719B8F00D62E90 /* codegen-inl.h */,
897FF1170E719B8F00D62E90 /* codegen.cc */,
897FF1180E719B8F00D62E90 /* codegen.h */,