Implement simple fast-path code for functions containing this property stores and global variables.

Code is specialized to the initial receiver.

Review URL: http://codereview.chromium.org/553149

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3760 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 6c605d1f
...@@ -114,6 +114,7 @@ SOURCES = { ...@@ -114,6 +114,7 @@ SOURCES = {
arm/cpu-arm.cc arm/cpu-arm.cc
arm/debug-arm.cc arm/debug-arm.cc
arm/disasm-arm.cc arm/disasm-arm.cc
arm/fast-codegen-arm.cc
arm/frames-arm.cc arm/frames-arm.cc
arm/full-codegen-arm.cc arm/full-codegen-arm.cc
arm/ic-arm.cc arm/ic-arm.cc
...@@ -137,6 +138,7 @@ SOURCES = { ...@@ -137,6 +138,7 @@ SOURCES = {
ia32/cpu-ia32.cc ia32/cpu-ia32.cc
ia32/debug-ia32.cc ia32/debug-ia32.cc
ia32/disasm-ia32.cc ia32/disasm-ia32.cc
ia32/fast-codegen-ia32.cc
ia32/frames-ia32.cc ia32/frames-ia32.cc
ia32/full-codegen-ia32.cc ia32/full-codegen-ia32.cc
ia32/ic-ia32.cc ia32/ic-ia32.cc
...@@ -154,6 +156,7 @@ SOURCES = { ...@@ -154,6 +156,7 @@ SOURCES = {
x64/cpu-x64.cc x64/cpu-x64.cc
x64/debug-x64.cc x64/debug-x64.cc
x64/disasm-x64.cc x64/disasm-x64.cc
x64/fast-codegen-x64.cc
x64/frames-x64.cc x64/frames-x64.cc
x64/full-codegen-x64.cc x64/full-codegen-x64.cc
x64/ic-x64.cc x64/ic-x64.cc
......
...@@ -444,6 +444,7 @@ class CodeGenerator: public AstVisitor { ...@@ -444,6 +444,7 @@ class CodeGenerator: public AstVisitor {
friend class VirtualFrame; friend class VirtualFrame;
friend class JumpTarget; friend class JumpTarget;
friend class Reference; friend class Reference;
friend class FastCodeGenerator;
friend class FullCodeGenerator; friend class FullCodeGenerator;
friend class FullCodeGenSyntaxChecker; friend class FullCodeGenSyntaxChecker;
......
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * 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.
#include "v8.h"
#include "codegen-inl.h"
#include "fast-codegen.h"
namespace v8 {
namespace internal {
#define __ ACCESS_MASM(masm())
void FastCodeGenerator::EmitLoadReceiver(Register reg) {
// Offset 2 is due to return address and saved frame pointer.
int index = 2 + function()->scope()->num_parameters();
__ ldr(reg, MemOperand(sp, index * kPointerSize));
}
void FastCodeGenerator::EmitReceiverMapCheck() {
Comment cmnt(masm(), ";; MapCheck(this)");
if (FLAG_print_ir) {
PrintF("MapCheck(this)\n");
}
EmitLoadReceiver(r1);
__ BranchOnSmi(r1, bailout());
ASSERT(has_receiver() && receiver()->IsHeapObject());
Handle<HeapObject> object = Handle<HeapObject>::cast(receiver());
Handle<Map> map(object->map());
__ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
__ mov(ip, Operand(map));
__ cmp(r3, ip);
__ b(ne, bailout());
}
void FastCodeGenerator::EmitGlobalVariableLoad(Handle<String> name) {
// Compile global variable accesses as load IC calls. The only live
// registers are cp (context) and possibly r1 (this). Both are also saved
// in the stack and cp is preserved by the call.
__ ldr(ip, CodeGenerator::GlobalObject());
__ push(ip);
__ mov(r2, Operand(name));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
if (has_this_properties()) {
// Restore this.
EmitLoadReceiver(r1);
}
}
void FastCodeGenerator::EmitThisPropertyStore(Handle<String> name) {
LookupResult lookup;
receiver()->Lookup(*name, &lookup);
ASSERT(lookup.holder() == *receiver());
ASSERT(lookup.type() == FIELD);
Handle<Map> map(Handle<HeapObject>::cast(receiver())->map());
int index = lookup.GetFieldIndex() - map->inobject_properties();
int offset = index * kPointerSize;
// Negative offsets are inobject properties.
if (offset < 0) {
offset += map->instance_size();
__ mov(r2, r1); // Copy receiver for write barrier.
} else {
offset += FixedArray::kHeaderSize;
__ ldr(r2, FieldMemOperand(r1, JSObject::kPropertiesOffset));
}
// Perform the store.
__ str(r0, FieldMemOperand(r2, offset));
__ mov(r3, Operand(offset));
__ RecordWrite(r2, r3, ip);
}
void FastCodeGenerator::Generate(FunctionLiteral* fun, CompilationInfo* info) {
ASSERT(function_ == NULL);
ASSERT(info_ == NULL);
function_ = fun;
info_ = info;
// Save the caller's frame pointer and set up our own.
Comment prologue_cmnt(masm(), ";; Prologue");
__ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
// Note that we keep a live register reference to cp (context) at
// this point.
// Receiver (this) is allocated to r1 if there are this properties.
if (has_this_properties()) EmitReceiverMapCheck();
VisitStatements(fun->body());
Comment return_cmnt(masm(), ";; Return(<undefined>)");
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
Comment epilogue_cmnt(masm(), ";; Epilogue");
__ mov(sp, fp);
__ ldm(ia_w, sp, fp.bit() | lr.bit());
int32_t sp_delta = (fun->scope()->num_parameters() + 1) * kPointerSize;
__ add(sp, sp, Operand(sp_delta));
__ Jump(lr);
__ bind(&bailout_);
}
#undef __
} } // namespace v8::internal
...@@ -52,80 +52,84 @@ namespace internal { ...@@ -52,80 +52,84 @@ namespace internal {
// //
// The function builds a JS frame. Please see JavaScriptFrameConstants in // The function builds a JS frame. Please see JavaScriptFrameConstants in
// frames-arm.h for its layout. // frames-arm.h for its layout.
void FullCodeGenerator::Generate(FunctionLiteral* fun) { void FullCodeGenerator::Generate(FunctionLiteral* fun, Mode mode) {
function_ = fun; function_ = fun;
SetFunctionPosition(fun); SetFunctionPosition(fun);
int locals_count = fun->scope()->num_stack_slots();
__ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); if (mode == PRIMARY) {
if (locals_count > 0) { int locals_count = fun->scope()->num_stack_slots();
// Load undefined value here, so the value is ready for the loop below.
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
}
// Adjust fp to point to caller's fp.
__ add(fp, sp, Operand(2 * kPointerSize));
{ Comment cmnt(masm_, "[ Allocate locals"); __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
for (int i = 0; i < locals_count; i++) { if (locals_count > 0) {
__ push(ip); // Load undefined value here, so the value is ready for the loop
// below.
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
} }
} // Adjust fp to point to caller's fp.
__ add(fp, sp, Operand(2 * kPointerSize));
bool function_in_register = true; { Comment cmnt(masm_, "[ Allocate locals");
for (int i = 0; i < locals_count; i++) {
__ push(ip);
}
}
// Possibly allocate a local context. bool function_in_register = true;
if (fun->scope()->num_heap_slots() > 0) {
Comment cmnt(masm_, "[ Allocate local context"); // Possibly allocate a local context.
// Argument to NewContext is the function, which is in r1. if (fun->scope()->num_heap_slots() > 0) {
__ push(r1); Comment cmnt(masm_, "[ Allocate local context");
__ CallRuntime(Runtime::kNewContext, 1); // Argument to NewContext is the function, which is in r1.
function_in_register = false; __ push(r1);
// Context is returned in both r0 and cp. It replaces the context __ CallRuntime(Runtime::kNewContext, 1);
// passed to us. It's saved in the stack and kept live in cp. function_in_register = false;
__ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); // Context is returned in both r0 and cp. It replaces the context
// Copy any necessary parameters into the context. // passed to us. It's saved in the stack and kept live in cp.
int num_parameters = fun->scope()->num_parameters(); __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
for (int i = 0; i < num_parameters; i++) { // Copy any necessary parameters into the context.
Slot* slot = fun->scope()->parameter(i)->slot(); int num_parameters = fun->scope()->num_parameters();
if (slot != NULL && slot->type() == Slot::CONTEXT) { for (int i = 0; i < num_parameters; i++) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset + Slot* slot = fun->scope()->parameter(i)->slot();
(num_parameters - 1 - i) * kPointerSize; if (slot != NULL && slot->type() == Slot::CONTEXT) {
// Load parameter from stack. int parameter_offset = StandardFrameConstants::kCallerSPOffset +
__ ldr(r0, MemOperand(fp, parameter_offset)); (num_parameters - 1 - i) * kPointerSize;
// Store it in the context // Load parameter from stack.
__ str(r0, MemOperand(cp, Context::SlotOffset(slot->index()))); __ ldr(r0, MemOperand(fp, parameter_offset));
// Store it in the context
__ str(r0, MemOperand(cp, Context::SlotOffset(slot->index())));
}
} }
} }
}
Variable* arguments = fun->scope()->arguments()->AsVariable(); Variable* arguments = fun->scope()->arguments()->AsVariable();
if (arguments != NULL) { if (arguments != NULL) {
// Function uses arguments object. // Function uses arguments object.
Comment cmnt(masm_, "[ Allocate arguments object"); Comment cmnt(masm_, "[ Allocate arguments object");
if (!function_in_register) { if (!function_in_register) {
// Load this again, if it's used by the local context below. // Load this again, if it's used by the local context below.
__ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
} else { } else {
__ mov(r3, r1); __ mov(r3, r1);
}
// Receiver is just before the parameters on the caller's stack.
__ add(r2, fp, Operand(StandardFrameConstants::kCallerSPOffset +
fun->num_parameters() * kPointerSize));
__ mov(r1, Operand(Smi::FromInt(fun->num_parameters())));
__ stm(db_w, sp, r3.bit() | r2.bit() | r1.bit());
// Arguments to ArgumentsAccessStub:
// function, receiver address, parameter count.
// The stub will rewrite receiever and parameter count if the previous
// stack frame was an arguments adapter frame.
ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
__ CallStub(&stub);
// Duplicate the value; move-to-slot operation might clobber registers.
__ mov(r3, r0);
Move(arguments->slot(), r0, r1, r2);
Slot* dot_arguments_slot =
fun->scope()->arguments_shadow()->AsVariable()->slot();
Move(dot_arguments_slot, r3, r1, r2);
} }
// Receiver is just before the parameters on the caller's stack.
__ add(r2, fp, Operand(StandardFrameConstants::kCallerSPOffset +
fun->num_parameters() * kPointerSize));
__ mov(r1, Operand(Smi::FromInt(fun->num_parameters())));
__ stm(db_w, sp, r3.bit() | r2.bit() | r1.bit());
// Arguments to ArgumentsAccessStub:
// function, receiver address, parameter count.
// The stub will rewrite receiever and parameter count if the previous
// stack frame was an arguments adapter frame.
ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
__ CallStub(&stub);
// Duplicate the value; move-to-slot operation might clobber registers.
__ mov(r3, r0);
Move(arguments->slot(), r0, r1, r2);
Slot* dot_arguments_slot =
fun->scope()->arguments_shadow()->AsVariable()->slot();
Move(dot_arguments_slot, r3, r1, r2);
} }
// Check the stack for overflow or break request. // Check the stack for overflow or break request.
...@@ -133,15 +137,15 @@ void FullCodeGenerator::Generate(FunctionLiteral* fun) { ...@@ -133,15 +137,15 @@ void FullCodeGenerator::Generate(FunctionLiteral* fun) {
// added to the implicit 8 byte offset that always applies to operations // added to the implicit 8 byte offset that always applies to operations
// with pc and gives a return address 12 bytes down. // with pc and gives a return address 12 bytes down.
{ Comment cmnt(masm_, "[ Stack check"); { Comment cmnt(masm_, "[ Stack check");
__ LoadRoot(r2, Heap::kStackLimitRootIndex); __ LoadRoot(r2, Heap::kStackLimitRootIndex);
__ add(lr, pc, Operand(Assembler::kInstrSize)); __ add(lr, pc, Operand(Assembler::kInstrSize));
__ cmp(sp, Operand(r2)); __ cmp(sp, Operand(r2));
StackCheckStub stub; StackCheckStub stub;
__ mov(pc, __ mov(pc,
Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()), Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()),
RelocInfo::CODE_TARGET), RelocInfo::CODE_TARGET),
LeaveCC, LeaveCC,
lo); lo);
} }
{ Comment cmnt(masm_, "[ Declarations"); { Comment cmnt(masm_, "[ Declarations");
......
...@@ -112,8 +112,7 @@ static Handle<Code> MakeCode(FunctionLiteral* literal, ...@@ -112,8 +112,7 @@ static Handle<Code> MakeCode(FunctionLiteral* literal,
FastCodeGenSyntaxChecker checker; FastCodeGenSyntaxChecker checker;
checker.Check(literal, info); checker.Check(literal, info);
if (checker.has_supported_syntax()) { if (checker.has_supported_syntax()) {
// Does not yet generate code. return FastCodeGenerator::MakeCode(literal, script, is_eval, info);
FastCodeGenerator::MakeCode(literal, script, is_eval, info);
} }
} }
...@@ -490,8 +489,8 @@ Handle<JSFunction> Compiler::BuildBoilerplate(FunctionLiteral* literal, ...@@ -490,8 +489,8 @@ Handle<JSFunction> Compiler::BuildBoilerplate(FunctionLiteral* literal,
FastCodeGenSyntaxChecker checker; FastCodeGenSyntaxChecker checker;
checker.Check(literal, &info); checker.Check(literal, &info);
if (checker.has_supported_syntax()) { if (checker.has_supported_syntax()) {
// Does not yet generate code. code = FastCodeGenerator::MakeCode(literal, script, false, &info);
FastCodeGenerator::MakeCode(literal, script, false, &info); is_compiled = true;
} }
} }
......
...@@ -43,7 +43,9 @@ class CompilationInfo BASE_EMBEDDED { ...@@ -43,7 +43,9 @@ class CompilationInfo BASE_EMBEDDED {
int loop_nesting) int loop_nesting)
: shared_info_(shared_info), : shared_info_(shared_info),
receiver_(receiver), receiver_(receiver),
loop_nesting_(loop_nesting) { loop_nesting_(loop_nesting),
has_this_properties_(false),
has_globals_(false) {
} }
Handle<SharedFunctionInfo> shared_info() { return shared_info_; } Handle<SharedFunctionInfo> shared_info() { return shared_info_; }
...@@ -53,10 +55,18 @@ class CompilationInfo BASE_EMBEDDED { ...@@ -53,10 +55,18 @@ class CompilationInfo BASE_EMBEDDED {
int loop_nesting() { return loop_nesting_; } int loop_nesting() { return loop_nesting_; }
bool has_this_properties() { return has_this_properties_; }
void set_has_this_properties(bool flag) { has_this_properties_ = flag; }
bool has_globals() { return has_globals_; }
void set_has_globals(bool flag) { has_globals_ = flag; }
private: private:
Handle<SharedFunctionInfo> shared_info_; Handle<SharedFunctionInfo> shared_info_;
Handle<Object> receiver_; Handle<Object> receiver_;
int loop_nesting_; int loop_nesting_;
bool has_this_properties_;
bool has_globals_;
}; };
......
...@@ -196,9 +196,12 @@ void AstLabeler::VisitAssignment(Assignment* expr) { ...@@ -196,9 +196,12 @@ void AstLabeler::VisitAssignment(Assignment* expr) {
ASSERT(prop != NULL); ASSERT(prop != NULL);
if (prop != NULL) { if (prop != NULL) {
ASSERT(prop->key()->IsPropertyName()); ASSERT(prop->key()->IsPropertyName());
if (prop->obj()->AsVariableProxy() == NULL || VariableProxy* proxy = prop->obj()->AsVariableProxy();
!prop->obj()->AsVariableProxy()->var()->is_this()) if (proxy != NULL && proxy->var()->is_this()) {
has_this_properties_ = true;
} else {
Visit(prop->obj()); Visit(prop->obj());
}
} }
Visit(expr->value()); Visit(expr->value());
expr->set_num(next_number_++); expr->set_num(next_number_++);
......
...@@ -38,10 +38,12 @@ namespace internal { ...@@ -38,10 +38,12 @@ namespace internal {
// their evaluation order (post-order left-to-right traversal). // their evaluation order (post-order left-to-right traversal).
class AstLabeler: public AstVisitor { class AstLabeler: public AstVisitor {
public: public:
AstLabeler() : next_number_(0) {} AstLabeler() : next_number_(0), has_this_properties_(false) {}
void Label(FunctionLiteral* fun); void Label(FunctionLiteral* fun);
bool has_this_properties() { return has_this_properties_; }
private: private:
void VisitDeclarations(ZoneList<Declaration*>* decls); void VisitDeclarations(ZoneList<Declaration*>* decls);
void VisitStatements(ZoneList<Statement*>* stmts); void VisitStatements(ZoneList<Statement*>* stmts);
...@@ -54,6 +56,8 @@ class AstLabeler: public AstVisitor { ...@@ -54,6 +56,8 @@ class AstLabeler: public AstVisitor {
// Traversal number for labelling AST nodes. // Traversal number for labelling AST nodes.
int next_number_; int next_number_;
bool has_this_properties_;
DISALLOW_COPY_AND_ASSIGN(AstLabeler); DISALLOW_COPY_AND_ASSIGN(AstLabeler);
}; };
......
...@@ -27,8 +27,10 @@ ...@@ -27,8 +27,10 @@
#include "v8.h" #include "v8.h"
#include "codegen-inl.h"
#include "data-flow.h" #include "data-flow.h"
#include "fast-codegen.h" #include "fast-codegen.h"
#include "full-codegen.h"
#include "scopes.h" #include "scopes.h"
namespace v8 { namespace v8 {
...@@ -54,8 +56,12 @@ void FastCodeGenSyntaxChecker::Check(FunctionLiteral* fun, ...@@ -54,8 +56,12 @@ void FastCodeGenSyntaxChecker::Check(FunctionLiteral* fun,
CompilationInfo* info) { CompilationInfo* info) {
info_ = info; info_ = info;
// We do not specialize if we do not have a receiver. // We do not specialize if we do not have a receiver or if it is not a
// JS object with fast mode properties.
if (!info->has_receiver()) BAILOUT("No receiver"); if (!info->has_receiver()) BAILOUT("No receiver");
if (!info->receiver()->IsJSObject()) BAILOUT("Receiver is not an object");
Handle<JSObject> object = Handle<JSObject>::cast(info->receiver());
if (!object->HasFastProperties()) BAILOUT("Receiver is in dictionary mode");
// We do not support stack or heap slots (both of which require // We do not support stack or heap slots (both of which require
// allocation). // allocation).
...@@ -325,25 +331,42 @@ void FastCodeGenSyntaxChecker::VisitThisFunction(ThisFunction* expr) { ...@@ -325,25 +331,42 @@ void FastCodeGenSyntaxChecker::VisitThisFunction(ThisFunction* expr) {
#undef CHECK_BAILOUT #undef CHECK_BAILOUT
void FastCodeGenerator::MakeCode(FunctionLiteral* fun, #define __ ACCESS_MASM(masm())
Handle<Script> script,
bool is_eval, Handle<Code> FastCodeGenerator::MakeCode(FunctionLiteral* fun,
CompilationInfo* info) { Handle<Script> script,
bool is_eval,
CompilationInfo* info) {
// Label the AST before calling MakeCodePrologue, so AST node numbers are
// printed with the AST.
AstLabeler labeler; AstLabeler labeler;
FastCodeGenerator cgen(script, is_eval);
labeler.Label(fun); labeler.Label(fun);
cgen.Generate(fun, info); info->set_has_this_properties(labeler.has_this_properties());
}
CodeGenerator::MakeCodePrologue(fun);
void FastCodeGenerator::Generate(FunctionLiteral* fun, CompilationInfo* info) { const int kInitialBufferSize = 4 * KB;
ASSERT(function_ == NULL); MacroAssembler masm(NULL, kInitialBufferSize);
ASSERT(info_ == NULL);
function_ = fun; // Generate the fast-path code.
info_ = info; FastCodeGenerator fast_cgen(&masm, script, is_eval);
VisitStatements(fun->body()); fast_cgen.Generate(fun, info);
function_ = NULL; if (fast_cgen.HasStackOverflow()) {
info_ = NULL; ASSERT(!Top::has_pending_exception());
return Handle<Code>::null();
}
// Generate the full code for the function in bailout mode, using the same
// macro assembler.
FullCodeGenerator full_cgen(&masm, script, is_eval);
full_cgen.Generate(fun, FullCodeGenerator::SECONDARY);
if (full_cgen.HasStackOverflow()) {
ASSERT(!Top::has_pending_exception());
return Handle<Code>::null();
}
Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, NOT_IN_LOOP);
return CodeGenerator::MakeCodeEpilogue(fun, &masm, flags, script);
} }
...@@ -459,11 +482,13 @@ void FastCodeGenerator::VisitSlot(Slot* expr) { ...@@ -459,11 +482,13 @@ void FastCodeGenerator::VisitSlot(Slot* expr) {
void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
ASSERT(expr->var()->is_global() && !expr->var()->is_this());
Comment cmnt(masm(), ";; Global");
if (FLAG_print_ir) { if (FLAG_print_ir) {
ASSERT(expr->var()->is_global() && !expr->var()->is_this());
SmartPointer<char> name = expr->name()->ToCString(); SmartPointer<char> name = expr->name()->ToCString();
PrintF("%d: t%d = Global(%s)\n", expr->num(), expr->num(), *name); PrintF("%d: t%d = Global(%s)\n", expr->num(), expr->num(), *name);
} }
EmitGlobalVariableLoad(expr->name());
} }
...@@ -496,18 +521,22 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) { ...@@ -496,18 +521,22 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
// Known to be a simple this property assignment. // Known to be a simple this property assignment.
Visit(expr->value()); Visit(expr->value());
Property* prop = expr->target()->AsProperty();
ASSERT_NOT_NULL(prop);
ASSERT_NOT_NULL(prop->obj()->AsVariableProxy());
ASSERT(prop->obj()->AsVariableProxy()->var()->is_this());
ASSERT(prop->key()->IsPropertyName());
Handle<String> name =
Handle<String>::cast(prop->key()->AsLiteral()->handle());
Comment cmnt(masm(), ";; Store(this)");
if (FLAG_print_ir) { if (FLAG_print_ir) {
Property* prop = expr->target()->AsProperty(); SmartPointer<char> name_string = name->ToCString();
ASSERT_NOT_NULL(prop);
ASSERT_NOT_NULL(prop->obj()->AsVariableProxy());
ASSERT(prop->obj()->AsVariableProxy()->var()->is_this());
ASSERT(prop->key()->IsPropertyName());
Handle<String> key =
Handle<String>::cast(prop->key()->AsLiteral()->handle());
SmartPointer<char> name = key->ToCString();
PrintF("%d: t%d = Store(this, \"%s\", t%d)\n", PrintF("%d: t%d = Store(this, \"%s\", t%d)\n",
expr->num(), expr->num(), *name, expr->value()->num()); expr->num(), expr->num(), *name_string, expr->value()->num());
} }
EmitThisPropertyStore(name);
} }
...@@ -560,4 +589,7 @@ void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) { ...@@ -560,4 +589,7 @@ void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) {
UNREACHABLE(); UNREACHABLE();
} }
#undef __
} } // namespace v8::internal } } // namespace v8::internal
...@@ -65,27 +65,54 @@ class FastCodeGenSyntaxChecker: public AstVisitor { ...@@ -65,27 +65,54 @@ class FastCodeGenSyntaxChecker: public AstVisitor {
class FastCodeGenerator: public AstVisitor { class FastCodeGenerator: public AstVisitor {
public: public:
FastCodeGenerator(Handle<Script> script, bool is_eval) FastCodeGenerator(MacroAssembler* masm, Handle<Script> script, bool is_eval)
: masm_(NULL), : masm_(masm),
script_(script), script_(script),
is_eval_(is_eval), is_eval_(is_eval),
function_(NULL), function_(NULL),
info_(NULL) { info_(NULL) {
} }
static void MakeCode(FunctionLiteral* fun, static Handle<Code> MakeCode(FunctionLiteral* fun,
Handle<Script> script, Handle<Script> script,
bool is_eval, bool is_eval,
CompilationInfo* info); CompilationInfo* info);
void Generate(FunctionLiteral* fun, CompilationInfo* info); void Generate(FunctionLiteral* fun, CompilationInfo* info);
private: private:
MacroAssembler* masm() { return masm_; }
FunctionLiteral* function() { return function_; }
Label* bailout() { return &bailout_; }
bool has_receiver() { return !info_->receiver().is_null(); }
Handle<Object> receiver() { return info_->receiver(); }
bool has_this_properties() { return info_->has_this_properties(); }
// AST node visit functions. // AST node visit functions.
#define DECLARE_VISIT(type) virtual void Visit##type(type* node); #define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT) AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT #undef DECLARE_VISIT
// Emit code to load the receiver from the stack into a given register.
void EmitLoadReceiver(Register reg);
// Emit code to check that the receiver has the same map as the
// compile-time receiver. Receiver is expected in {ia32-edx, x64-rdx,
// arm-r1}. Emit a branch to the (single) bailout label if check fails.
void EmitReceiverMapCheck();
// Emit code to load a global variable value into {is32-eax, x64-rax,
// arm-r0}. Register {ia32-edx, x64-rdx, arm-r1} is preserved if it is
// holding the receiver and {is32-ecx, x64-rcx, arm-r2} is always
// clobbered.
void EmitGlobalVariableLoad(Handle<String> name);
// Emit a store to an own property of this. The stored value is expected
// in {ia32-eax, x64-rax, arm-r0} and the receiver in {is32-edx, x64-rdx,
// arm-r1}. Both are preserve.
void EmitThisPropertyStore(Handle<String> name);
MacroAssembler* masm_; MacroAssembler* masm_;
Handle<Script> script_; Handle<Script> script_;
bool is_eval_; bool is_eval_;
...@@ -93,6 +120,8 @@ class FastCodeGenerator: public AstVisitor { ...@@ -93,6 +120,8 @@ class FastCodeGenerator: public AstVisitor {
FunctionLiteral* function_; FunctionLiteral* function_;
CompilationInfo* info_; CompilationInfo* info_;
Label bailout_;
DISALLOW_COPY_AND_ASSIGN(FastCodeGenerator); DISALLOW_COPY_AND_ASSIGN(FastCodeGenerator);
}; };
......
...@@ -462,7 +462,7 @@ Handle<Code> FullCodeGenerator::MakeCode(FunctionLiteral* fun, ...@@ -462,7 +462,7 @@ Handle<Code> FullCodeGenerator::MakeCode(FunctionLiteral* fun,
const int kInitialBufferSize = 4 * KB; const int kInitialBufferSize = 4 * KB;
MacroAssembler masm(NULL, kInitialBufferSize); MacroAssembler masm(NULL, kInitialBufferSize);
FullCodeGenerator cgen(&masm, script, is_eval); FullCodeGenerator cgen(&masm, script, is_eval);
cgen.Generate(fun); cgen.Generate(fun, PRIMARY);
if (cgen.HasStackOverflow()) { if (cgen.HasStackOverflow()) {
ASSERT(!Top::has_pending_exception()); ASSERT(!Top::has_pending_exception());
return Handle<Code>::null(); return Handle<Code>::null();
...@@ -1161,7 +1161,6 @@ int FullCodeGenerator::TryCatch::Exit(int stack_depth) { ...@@ -1161,7 +1161,6 @@ int FullCodeGenerator::TryCatch::Exit(int stack_depth) {
return 0; return 0;
} }
#undef __ #undef __
......
...@@ -63,11 +63,16 @@ class FullCodeGenSyntaxChecker: public AstVisitor { ...@@ -63,11 +63,16 @@ class FullCodeGenSyntaxChecker: public AstVisitor {
class FullCodeGenerator: public AstVisitor { class FullCodeGenerator: public AstVisitor {
public: public:
enum Mode {
PRIMARY,
SECONDARY
};
FullCodeGenerator(MacroAssembler* masm, Handle<Script> script, bool is_eval) FullCodeGenerator(MacroAssembler* masm, Handle<Script> script, bool is_eval)
: masm_(masm), : masm_(masm),
function_(NULL),
script_(script), script_(script),
is_eval_(is_eval), is_eval_(is_eval),
function_(NULL),
nesting_stack_(NULL), nesting_stack_(NULL),
loop_depth_(0), loop_depth_(0),
location_(kStack), location_(kStack),
...@@ -79,7 +84,7 @@ class FullCodeGenerator: public AstVisitor { ...@@ -79,7 +84,7 @@ class FullCodeGenerator: public AstVisitor {
Handle<Script> script, Handle<Script> script,
bool is_eval); bool is_eval);
void Generate(FunctionLiteral* fun); void Generate(FunctionLiteral* fun, Mode mode);
private: private:
class Breakable; class Breakable;
...@@ -422,9 +427,11 @@ class FullCodeGenerator: public AstVisitor { ...@@ -422,9 +427,11 @@ class FullCodeGenerator: public AstVisitor {
void EmitLogicalOperation(BinaryOperation* expr); void EmitLogicalOperation(BinaryOperation* expr);
MacroAssembler* masm_; MacroAssembler* masm_;
FunctionLiteral* function_;
Handle<Script> script_; Handle<Script> script_;
bool is_eval_; bool is_eval_;
FunctionLiteral* function_;
Label return_label_; Label return_label_;
NestedStatement* nesting_stack_; NestedStatement* nesting_stack_;
int loop_depth_; int loop_depth_;
......
...@@ -633,6 +633,7 @@ class CodeGenerator: public AstVisitor { ...@@ -633,6 +633,7 @@ class CodeGenerator: public AstVisitor {
friend class JumpTarget; friend class JumpTarget;
friend class Reference; friend class Reference;
friend class Result; friend class Result;
friend class FastCodeGenerator;
friend class FullCodeGenerator; friend class FullCodeGenerator;
friend class FullCodeGenSyntaxChecker; friend class FullCodeGenSyntaxChecker;
......
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * 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.
#include "v8.h"
#include "codegen-inl.h"
#include "fast-codegen.h"
namespace v8 {
namespace internal {
#define __ ACCESS_MASM(masm())
void FastCodeGenerator::EmitLoadReceiver(Register reg) {
// Offset 2 is due to return address and saved frame pointer.
int index = 2 + function()->scope()->num_parameters();
__ mov(reg, Operand(ebp, index * kPointerSize));
}
void FastCodeGenerator::EmitReceiverMapCheck() {
Comment cmnt(masm(), ";; MapCheck(this)");
if (FLAG_print_ir) {
PrintF("MapCheck(this)\n");
}
EmitLoadReceiver(edx);
__ test(edx, Immediate(kSmiTagMask));
__ j(zero, bailout());
ASSERT(has_receiver() && receiver()->IsHeapObject());
Handle<HeapObject> object = Handle<HeapObject>::cast(receiver());
Handle<Map> map(object->map());
__ cmp(FieldOperand(edx, HeapObject::kMapOffset), Immediate(map));
__ j(not_equal, bailout());
}
void FastCodeGenerator::EmitGlobalVariableLoad(Handle<String> name) {
// Compile global variable accesses as load IC calls. The only live
// registers are esi (context) and possibly edx (this). Both are also
// saved in the stack and esi is preserved by the call.
__ push(CodeGenerator::GlobalObject());
__ mov(ecx, name);
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
if (has_this_properties()) {
// Restore this.
EmitLoadReceiver(edx);
} else {
__ nop(); // Not test eax, indicates IC has no inlined code at call site.
}
}
void FastCodeGenerator::EmitThisPropertyStore(Handle<String> name) {
LookupResult lookup;
receiver()->Lookup(*name, &lookup);
ASSERT(lookup.holder() == *receiver());
ASSERT(lookup.type() == FIELD);
Handle<Map> map(Handle<HeapObject>::cast(receiver())->map());
int index = lookup.GetFieldIndex() - map->inobject_properties();
int offset = index * kPointerSize;
// Negative offsets are inobject properties.
if (offset < 0) {
offset += map->instance_size();
__ mov(ecx, edx); // Copy receiver for write barrier.
} else {
offset += FixedArray::kHeaderSize;
__ mov(ecx, FieldOperand(edx, JSObject::kPropertiesOffset));
}
// Perform the store.
__ mov(FieldOperand(ecx, offset), eax);
// Preserve value from write barrier in case it's needed.
__ mov(ebx, eax);
__ RecordWrite(ecx, offset, ebx, edi);
}
void FastCodeGenerator::Generate(FunctionLiteral* fun, CompilationInfo* info) {
ASSERT(function_ == NULL);
ASSERT(info_ == NULL);
function_ = fun;
info_ = info;
// Save the caller's frame pointer and set up our own.
Comment prologue_cmnt(masm(), ";; Prologue");
__ push(ebp);
__ mov(ebp, esp);
__ push(esi); // Context.
__ push(edi); // Closure.
// Note that we keep a live register reference to esi (context) at this
// point.
// Receiver (this) is allocated to edx if there are this properties.
if (has_this_properties()) EmitReceiverMapCheck();
VisitStatements(fun->body());
Comment return_cmnt(masm(), ";; Return(<undefined>)");
__ mov(eax, Factory::undefined_value());
Comment epilogue_cmnt(masm(), ";; Epilogue");
__ mov(esp, ebp);
__ pop(ebp);
__ ret((fun->scope()->num_parameters() + 1) * kPointerSize);
__ bind(&bailout_);
}
#undef __
} } // namespace v8::internal
...@@ -51,80 +51,82 @@ namespace internal { ...@@ -51,80 +51,82 @@ namespace internal {
// //
// The function builds a JS frame. Please see JavaScriptFrameConstants in // The function builds a JS frame. Please see JavaScriptFrameConstants in
// frames-ia32.h for its layout. // frames-ia32.h for its layout.
void FullCodeGenerator::Generate(FunctionLiteral* fun) { void FullCodeGenerator::Generate(FunctionLiteral* fun, Mode mode) {
function_ = fun; function_ = fun;
SetFunctionPosition(fun); SetFunctionPosition(fun);
__ push(ebp); // Caller's frame pointer. if (mode == PRIMARY) {
__ mov(ebp, esp); __ push(ebp); // Caller's frame pointer.
__ push(esi); // Callee's context. __ mov(ebp, esp);
__ push(edi); // Callee's JS Function. __ push(esi); // Callee's context.
__ push(edi); // Callee's JS Function.
{ Comment cmnt(masm_, "[ Allocate locals");
int locals_count = fun->scope()->num_stack_slots(); { Comment cmnt(masm_, "[ Allocate locals");
if (locals_count == 1) { int locals_count = fun->scope()->num_stack_slots();
__ push(Immediate(Factory::undefined_value())); if (locals_count == 1) {
} else if (locals_count > 1) { __ push(Immediate(Factory::undefined_value()));
__ mov(eax, Immediate(Factory::undefined_value())); } else if (locals_count > 1) {
for (int i = 0; i < locals_count; i++) { __ mov(eax, Immediate(Factory::undefined_value()));
__ push(eax); for (int i = 0; i < locals_count; i++) {
__ push(eax);
}
} }
} }
}
bool function_in_register = true; bool function_in_register = true;
// Possibly allocate a local context. // Possibly allocate a local context.
if (fun->scope()->num_heap_slots() > 0) { if (fun->scope()->num_heap_slots() > 0) {
Comment cmnt(masm_, "[ Allocate local context"); Comment cmnt(masm_, "[ Allocate local context");
// Argument to NewContext is the function, which is still in edi. // Argument to NewContext is the function, which is still in edi.
__ push(edi); __ push(edi);
__ CallRuntime(Runtime::kNewContext, 1); __ CallRuntime(Runtime::kNewContext, 1);
function_in_register = false; function_in_register = false;
// Context is returned in both eax and esi. It replaces the context // Context is returned in both eax and esi. It replaces the context
// passed to us. It's saved in the stack and kept live in esi. // passed to us. It's saved in the stack and kept live in esi.
__ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
// Copy parameters into context if necessary. // Copy parameters into context if necessary.
int num_parameters = fun->scope()->num_parameters(); int num_parameters = fun->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) { for (int i = 0; i < num_parameters; i++) {
Slot* slot = fun->scope()->parameter(i)->slot(); Slot* slot = fun->scope()->parameter(i)->slot();
if (slot != NULL && slot->type() == Slot::CONTEXT) { if (slot != NULL && slot->type() == Slot::CONTEXT) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset + int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize; (num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack. // Load parameter from stack.
__ mov(eax, Operand(ebp, parameter_offset)); __ mov(eax, Operand(ebp, parameter_offset));
// Store it in the context // Store it in the context
__ mov(Operand(esi, Context::SlotOffset(slot->index())), eax); __ mov(Operand(esi, Context::SlotOffset(slot->index())), eax);
}
} }
} }
}
Variable* arguments = fun->scope()->arguments()->AsVariable(); Variable* arguments = fun->scope()->arguments()->AsVariable();
if (arguments != NULL) { if (arguments != NULL) {
// Function uses arguments object. // Function uses arguments object.
Comment cmnt(masm_, "[ Allocate arguments object"); Comment cmnt(masm_, "[ Allocate arguments object");
if (function_in_register) { if (function_in_register) {
__ push(edi); __ push(edi);
} else { } else {
__ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
}
// Receiver is just before the parameters on the caller's stack.
__ lea(edx, Operand(ebp, StandardFrameConstants::kCallerSPOffset +
fun->num_parameters() * kPointerSize));
__ push(edx);
__ push(Immediate(Smi::FromInt(fun->num_parameters())));
// Arguments to ArgumentsAccessStub:
// function, receiver address, parameter count.
// The stub will rewrite receiver and parameter count if the previous
// stack frame was an arguments adapter frame.
ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
__ CallStub(&stub);
__ mov(ecx, eax); // Duplicate result.
Move(arguments->slot(), eax, ebx, edx);
Slot* dot_arguments_slot =
fun->scope()->arguments_shadow()->AsVariable()->slot();
Move(dot_arguments_slot, ecx, ebx, edx);
} }
// Receiver is just before the parameters on the caller's stack.
__ lea(edx, Operand(ebp, StandardFrameConstants::kCallerSPOffset +
fun->num_parameters() * kPointerSize));
__ push(edx);
__ push(Immediate(Smi::FromInt(fun->num_parameters())));
// Arguments to ArgumentsAccessStub:
// function, receiver address, parameter count.
// The stub will rewrite receiver and parameter count if the previous
// stack frame was an arguments adapter frame.
ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
__ CallStub(&stub);
__ mov(ecx, eax); // Duplicate result.
Move(arguments->slot(), eax, ebx, edx);
Slot* dot_arguments_slot =
fun->scope()->arguments_shadow()->AsVariable()->slot();
Move(dot_arguments_slot, ecx, ebx, edx);
} }
{ Comment cmnt(masm_, "[ Declarations"); { Comment cmnt(masm_, "[ Declarations");
......
...@@ -630,6 +630,7 @@ class CodeGenerator: public AstVisitor { ...@@ -630,6 +630,7 @@ class CodeGenerator: public AstVisitor {
friend class JumpTarget; friend class JumpTarget;
friend class Reference; friend class Reference;
friend class Result; friend class Result;
friend class FastCodeGenerator;
friend class FullCodeGenerator; friend class FullCodeGenerator;
friend class FullCodeGenSyntaxChecker; friend class FullCodeGenSyntaxChecker;
......
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * 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.
#include "v8.h"
#include "codegen-inl.h"
#include "fast-codegen.h"
namespace v8 {
namespace internal {
#define __ ACCESS_MASM(masm())
void FastCodeGenerator::EmitLoadReceiver(Register reg) {
// Offset 2 is due to return address and saved frame pointer.
int index = 2 + function()->scope()->num_parameters();
__ movq(reg, Operand(rbp, index * kPointerSize));
}
void FastCodeGenerator::EmitReceiverMapCheck() {
Comment cmnt(masm(), ";; MapCheck(this)");
if (FLAG_print_ir) {
PrintF("MapCheck(this)\n");
}
EmitLoadReceiver(rdx);
__ JumpIfSmi(rdx, bailout());
ASSERT(has_receiver() && receiver()->IsHeapObject());
Handle<HeapObject> object = Handle<HeapObject>::cast(receiver());
Handle<Map> map(object->map());
__ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), map);
__ j(not_equal, bailout());
}
void FastCodeGenerator::EmitGlobalVariableLoad(Handle<String> name) {
// Compile global variable accesses as load IC calls. The only live
// registers are rsi (context) and possibly rdx (this). Both are also
// saved in the stack and rsi is preserved by the call.
__ push(CodeGenerator::GlobalObject());
__ Move(rcx, name);
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
if (has_this_properties()) {
// Restore this.
EmitLoadReceiver(rdx);
} else {
__ nop(); // Not test rax, indicates IC has no inlined code at call site.
}
}
void FastCodeGenerator::EmitThisPropertyStore(Handle<String> name) {
LookupResult lookup;
receiver()->Lookup(*name, &lookup);
ASSERT(lookup.holder() == *receiver());
ASSERT(lookup.type() == FIELD);
Handle<Map> map(Handle<HeapObject>::cast(receiver())->map());
int index = lookup.GetFieldIndex() - map->inobject_properties();
int offset = index * kPointerSize;
// Negative offsets are inobject properties.
if (offset < 0) {
offset += map->instance_size();
__ movq(rcx, rdx); // Copy receiver for write barrier.
} else {
offset += FixedArray::kHeaderSize;
__ movq(rcx, FieldOperand(rdx, JSObject::kPropertiesOffset));
}
// Perform the store.
__ movq(FieldOperand(rcx, offset), rax);
// Preserve value from write barrier in case it's needed.
__ movq(rbx, rax);
__ RecordWrite(rcx, offset, rbx, rdi);
}
void FastCodeGenerator::Generate(FunctionLiteral* fun, CompilationInfo* info) {
ASSERT(function_ == NULL);
ASSERT(info_ == NULL);
function_ = fun;
info_ = info;
// Save the caller's frame pointer and set up our own.
Comment prologue_cmnt(masm(), ";; Prologue");
__ push(rbp);
__ movq(rbp, rsp);
__ push(rsi); // Context.
__ push(rdi); // Closure.
// Note that we keep a live register reference to esi (context) at this
// point.
// Receiver (this) is allocated to rdx if there are this properties.
if (has_this_properties()) EmitReceiverMapCheck();
VisitStatements(fun->body());
Comment return_cmnt(masm(), ";; Return(<undefined>)");
__ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
Comment epilogue_cmnt(masm(), ";; Epilogue");
__ movq(rsp, rbp);
__ pop(rbp);
__ ret((fun->scope()->num_parameters() + 1) * kPointerSize);
__ bind(&bailout_);
}
#undef __
} } // namespace v8::internal
...@@ -51,83 +51,85 @@ namespace internal { ...@@ -51,83 +51,85 @@ namespace internal {
// //
// The function builds a JS frame. Please see JavaScriptFrameConstants in // The function builds a JS frame. Please see JavaScriptFrameConstants in
// frames-x64.h for its layout. // frames-x64.h for its layout.
void FullCodeGenerator::Generate(FunctionLiteral* fun) { void FullCodeGenerator::Generate(FunctionLiteral* fun, Mode mode) {
function_ = fun; function_ = fun;
SetFunctionPosition(fun); SetFunctionPosition(fun);
__ push(rbp); // Caller's frame pointer. if (mode == PRIMARY) {
__ movq(rbp, rsp); __ push(rbp); // Caller's frame pointer.
__ push(rsi); // Callee's context. __ movq(rbp, rsp);
__ push(rdi); // Callee's JS Function. __ push(rsi); // Callee's context.
__ push(rdi); // Callee's JS Function.
{ Comment cmnt(masm_, "[ Allocate locals");
int locals_count = fun->scope()->num_stack_slots(); { Comment cmnt(masm_, "[ Allocate locals");
if (locals_count == 1) { int locals_count = fun->scope()->num_stack_slots();
__ PushRoot(Heap::kUndefinedValueRootIndex); if (locals_count == 1) {
} else if (locals_count > 1) { __ PushRoot(Heap::kUndefinedValueRootIndex);
__ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); } else if (locals_count > 1) {
for (int i = 0; i < locals_count; i++) { __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
__ push(rdx); for (int i = 0; i < locals_count; i++) {
__ push(rdx);
}
} }
} }
}
bool function_in_register = true; bool function_in_register = true;
// Possibly allocate a local context. // Possibly allocate a local context.
if (fun->scope()->num_heap_slots() > 0) { if (fun->scope()->num_heap_slots() > 0) {
Comment cmnt(masm_, "[ Allocate local context"); Comment cmnt(masm_, "[ Allocate local context");
// Argument to NewContext is the function, which is still in rdi. // Argument to NewContext is the function, which is still in rdi.
__ push(rdi); __ push(rdi);
__ CallRuntime(Runtime::kNewContext, 1); __ CallRuntime(Runtime::kNewContext, 1);
function_in_register = false; function_in_register = false;
// Context is returned in both rax and rsi. It replaces the context // Context is returned in both rax and rsi. It replaces the context
// passed to us. It's saved in the stack and kept live in rsi. // passed to us. It's saved in the stack and kept live in rsi.
__ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
// Copy any necessary parameters into the context. // Copy any necessary parameters into the context.
int num_parameters = fun->scope()->num_parameters(); int num_parameters = fun->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) { for (int i = 0; i < num_parameters; i++) {
Slot* slot = fun->scope()->parameter(i)->slot(); Slot* slot = fun->scope()->parameter(i)->slot();
if (slot != NULL && slot->type() == Slot::CONTEXT) { if (slot != NULL && slot->type() == Slot::CONTEXT) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset + int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize; (num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack. // Load parameter from stack.
__ movq(rax, Operand(rbp, parameter_offset)); __ movq(rax, Operand(rbp, parameter_offset));
// Store it in the context // Store it in the context
__ movq(Operand(rsi, Context::SlotOffset(slot->index())), rax); __ movq(Operand(rsi, Context::SlotOffset(slot->index())), rax);
}
} }
} }
}
// Possibly allocate an arguments object. // Possibly allocate an arguments object.
Variable* arguments = fun->scope()->arguments()->AsVariable(); Variable* arguments = fun->scope()->arguments()->AsVariable();
if (arguments != NULL) { if (arguments != NULL) {
// Arguments object must be allocated after the context object, in // Arguments object must be allocated after the context object, in
// case the "arguments" or ".arguments" variables are in the context. // case the "arguments" or ".arguments" variables are in the context.
Comment cmnt(masm_, "[ Allocate arguments object"); Comment cmnt(masm_, "[ Allocate arguments object");
if (function_in_register) { if (function_in_register) {
__ push(rdi); __ push(rdi);
} else { } else {
__ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
}
// The receiver is just before the parameters on the caller's stack.
__ lea(rdx, Operand(rbp, StandardFrameConstants::kCallerSPOffset +
fun->num_parameters() * kPointerSize));
__ push(rdx);
__ Push(Smi::FromInt(fun->num_parameters()));
// Arguments to ArgumentsAccessStub:
// function, receiver address, parameter count.
// The stub will rewrite receiver and parameter count if the previous
// stack frame was an arguments adapter frame.
ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
__ CallStub(&stub);
// Store new arguments object in both "arguments" and ".arguments" slots.
__ movq(rcx, rax);
Move(arguments->slot(), rax, rbx, rdx);
Slot* dot_arguments_slot =
fun->scope()->arguments_shadow()->AsVariable()->slot();
Move(dot_arguments_slot, rcx, rbx, rdx);
} }
// The receiver is just before the parameters on the caller's stack.
__ lea(rdx, Operand(rbp, StandardFrameConstants::kCallerSPOffset +
fun->num_parameters() * kPointerSize));
__ push(rdx);
__ Push(Smi::FromInt(fun->num_parameters()));
// Arguments to ArgumentsAccessStub:
// function, receiver address, parameter count.
// The stub will rewrite receiver and parameter count if the previous
// stack frame was an arguments adapter frame.
ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
__ CallStub(&stub);
// Store new arguments object in both "arguments" and ".arguments" slots.
__ movq(rcx, rax);
Move(arguments->slot(), rax, rbx, rdx);
Slot* dot_arguments_slot =
fun->scope()->arguments_shadow()->AsVariable()->slot();
Move(dot_arguments_slot, rcx, rbx, rdx);
} }
{ Comment cmnt(masm_, "[ Declarations"); { Comment cmnt(masm_, "[ Declarations");
......
...@@ -412,6 +412,7 @@ ...@@ -412,6 +412,7 @@
'../../src/arm/cpu-arm.cc', '../../src/arm/cpu-arm.cc',
'../../src/arm/debug-arm.cc', '../../src/arm/debug-arm.cc',
'../../src/arm/disasm-arm.cc', '../../src/arm/disasm-arm.cc',
'../../src/arm/fast-codegen-arm.cc',
'../../src/arm/frames-arm.cc', '../../src/arm/frames-arm.cc',
'../../src/arm/frames-arm.h', '../../src/arm/frames-arm.h',
'../../src/arm/full-codegen-arm.cc', '../../src/arm/full-codegen-arm.cc',
...@@ -450,6 +451,7 @@ ...@@ -450,6 +451,7 @@
'../../src/ia32/cpu-ia32.cc', '../../src/ia32/cpu-ia32.cc',
'../../src/ia32/debug-ia32.cc', '../../src/ia32/debug-ia32.cc',
'../../src/ia32/disasm-ia32.cc', '../../src/ia32/disasm-ia32.cc',
'../../src/ia32/fast-codegen-ia32.cc',
'../../src/ia32/frames-ia32.cc', '../../src/ia32/frames-ia32.cc',
'../../src/ia32/frames-ia32.h', '../../src/ia32/frames-ia32.h',
'../../src/ia32/full-codegen-ia32.cc', '../../src/ia32/full-codegen-ia32.cc',
...@@ -479,6 +481,7 @@ ...@@ -479,6 +481,7 @@
'../../src/x64/cpu-x64.cc', '../../src/x64/cpu-x64.cc',
'../../src/x64/debug-x64.cc', '../../src/x64/debug-x64.cc',
'../../src/x64/disasm-x64.cc', '../../src/x64/disasm-x64.cc',
'../../src/x64/fast-codegen-x64.cc',
'../../src/x64/frames-x64.cc', '../../src/x64/frames-x64.cc',
'../../src/x64/frames-x64.h', '../../src/x64/frames-x64.h',
'../../src/x64/full-codegen-x64.cc', '../../src/x64/full-codegen-x64.cc',
......
...@@ -396,6 +396,10 @@ ...@@ -396,6 +396,10 @@
RelativePath="..\..\src\factory.h" RelativePath="..\..\src\factory.h"
> >
</File> </File>
<File
RelativePath="..\..\src\ia32\fast-codegen-ia32.cc"
>
</File>
<File <File
RelativePath="..\..\src\fast-codegen.cc" RelativePath="..\..\src\fast-codegen.cc"
> >
......
...@@ -404,6 +404,10 @@ ...@@ -404,6 +404,10 @@
RelativePath="..\..\src\factory.h" RelativePath="..\..\src\factory.h"
> >
</File> </File>
<File
RelativePath="..\..\src\arm\fast-codegen-arm.cc"
>
</File>
<File <File
RelativePath="..\..\src\fast-codegen.cc" RelativePath="..\..\src\fast-codegen.cc"
> >
......
...@@ -396,6 +396,10 @@ ...@@ -396,6 +396,10 @@
RelativePath="..\..\src\factory.h" RelativePath="..\..\src\factory.h"
> >
</File> </File>
<File
RelativePath="..\..\src\x64\fast-codegen-x64.cc"
>
</File>
<File <File
RelativePath="..\..\src\fast-codegen.cc" RelativePath="..\..\src\fast-codegen.cc"
> >
...@@ -441,15 +445,15 @@ ...@@ -441,15 +445,15 @@
> >
</File> </File>
<File <File
RelativePath="..\..\src\full-codegen.cc" RelativePath="..\..\src\x64\full-codegen-x64.cc"
> >
</File> </File>
<File <File
RelativePath="..\..\src\full-codegen.h" RelativePath="..\..\src\full-codegen.cc"
> >
</File> </File>
<File <File
RelativePath="..\..\src\x64\full-codegen-x64.cc" RelativePath="..\..\src\full-codegen.h"
> >
</File> </File>
<File <File
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment