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 = {
arm/cpu-arm.cc
arm/debug-arm.cc
arm/disasm-arm.cc
arm/fast-codegen-arm.cc
arm/frames-arm.cc
arm/full-codegen-arm.cc
arm/ic-arm.cc
......@@ -137,6 +138,7 @@ SOURCES = {
ia32/cpu-ia32.cc
ia32/debug-ia32.cc
ia32/disasm-ia32.cc
ia32/fast-codegen-ia32.cc
ia32/frames-ia32.cc
ia32/full-codegen-ia32.cc
ia32/ic-ia32.cc
......@@ -154,6 +156,7 @@ SOURCES = {
x64/cpu-x64.cc
x64/debug-x64.cc
x64/disasm-x64.cc
x64/fast-codegen-x64.cc
x64/frames-x64.cc
x64/full-codegen-x64.cc
x64/ic-x64.cc
......
......@@ -444,6 +444,7 @@ class CodeGenerator: public AstVisitor {
friend class VirtualFrame;
friend class JumpTarget;
friend class Reference;
friend class FastCodeGenerator;
friend class FullCodeGenerator;
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 {
//
// The function builds a JS frame. Please see JavaScriptFrameConstants in
// frames-arm.h for its layout.
void FullCodeGenerator::Generate(FunctionLiteral* fun) {
void FullCodeGenerator::Generate(FunctionLiteral* fun, Mode mode) {
function_ = fun;
SetFunctionPosition(fun);
int locals_count = fun->scope()->num_stack_slots();
__ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
if (locals_count > 0) {
// 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));
if (mode == PRIMARY) {
int locals_count = fun->scope()->num_stack_slots();
{ Comment cmnt(masm_, "[ Allocate locals");
for (int i = 0; i < locals_count; i++) {
__ push(ip);
__ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
if (locals_count > 0) {
// 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.
if (fun->scope()->num_heap_slots() > 0) {
Comment cmnt(masm_, "[ Allocate local context");
// Argument to NewContext is the function, which is in r1.
__ push(r1);
__ CallRuntime(Runtime::kNewContext, 1);
function_in_register = false;
// Context is returned in both r0 and cp. It replaces the context
// passed to us. It's saved in the stack and kept live in cp.
__ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
// Copy any necessary parameters into the context.
int num_parameters = fun->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
Slot* slot = fun->scope()->parameter(i)->slot();
if (slot != NULL && slot->type() == Slot::CONTEXT) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ ldr(r0, MemOperand(fp, parameter_offset));
// Store it in the context
__ str(r0, MemOperand(cp, Context::SlotOffset(slot->index())));
bool function_in_register = true;
// Possibly allocate a local context.
if (fun->scope()->num_heap_slots() > 0) {
Comment cmnt(masm_, "[ Allocate local context");
// Argument to NewContext is the function, which is in r1.
__ push(r1);
__ CallRuntime(Runtime::kNewContext, 1);
function_in_register = false;
// Context is returned in both r0 and cp. It replaces the context
// passed to us. It's saved in the stack and kept live in cp.
__ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
// Copy any necessary parameters into the context.
int num_parameters = fun->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
Slot* slot = fun->scope()->parameter(i)->slot();
if (slot != NULL && slot->type() == Slot::CONTEXT) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ 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();
if (arguments != NULL) {
// Function uses arguments object.
Comment cmnt(masm_, "[ Allocate arguments object");
if (!function_in_register) {
// Load this again, if it's used by the local context below.
__ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
} else {
__ mov(r3, r1);
Variable* arguments = fun->scope()->arguments()->AsVariable();
if (arguments != NULL) {
// Function uses arguments object.
Comment cmnt(masm_, "[ Allocate arguments object");
if (!function_in_register) {
// Load this again, if it's used by the local context below.
__ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
} else {
__ 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.
......@@ -133,15 +137,15 @@ void FullCodeGenerator::Generate(FunctionLiteral* fun) {
// added to the implicit 8 byte offset that always applies to operations
// with pc and gives a return address 12 bytes down.
{ Comment cmnt(masm_, "[ Stack check");
__ LoadRoot(r2, Heap::kStackLimitRootIndex);
__ add(lr, pc, Operand(Assembler::kInstrSize));
__ cmp(sp, Operand(r2));
StackCheckStub stub;
__ mov(pc,
Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()),
RelocInfo::CODE_TARGET),
LeaveCC,
lo);
__ LoadRoot(r2, Heap::kStackLimitRootIndex);
__ add(lr, pc, Operand(Assembler::kInstrSize));
__ cmp(sp, Operand(r2));
StackCheckStub stub;
__ mov(pc,
Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()),
RelocInfo::CODE_TARGET),
LeaveCC,
lo);
}
{ Comment cmnt(masm_, "[ Declarations");
......
......@@ -112,8 +112,7 @@ static Handle<Code> MakeCode(FunctionLiteral* literal,
FastCodeGenSyntaxChecker checker;
checker.Check(literal, info);
if (checker.has_supported_syntax()) {
// Does not yet generate code.
FastCodeGenerator::MakeCode(literal, script, is_eval, info);
return FastCodeGenerator::MakeCode(literal, script, is_eval, info);
}
}
......@@ -490,8 +489,8 @@ Handle<JSFunction> Compiler::BuildBoilerplate(FunctionLiteral* literal,
FastCodeGenSyntaxChecker checker;
checker.Check(literal, &info);
if (checker.has_supported_syntax()) {
// Does not yet generate code.
FastCodeGenerator::MakeCode(literal, script, false, &info);
code = FastCodeGenerator::MakeCode(literal, script, false, &info);
is_compiled = true;
}
}
......
......@@ -43,7 +43,9 @@ class CompilationInfo BASE_EMBEDDED {
int loop_nesting)
: shared_info_(shared_info),
receiver_(receiver),
loop_nesting_(loop_nesting) {
loop_nesting_(loop_nesting),
has_this_properties_(false),
has_globals_(false) {
}
Handle<SharedFunctionInfo> shared_info() { return shared_info_; }
......@@ -53,10 +55,18 @@ class CompilationInfo BASE_EMBEDDED {
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:
Handle<SharedFunctionInfo> shared_info_;
Handle<Object> receiver_;
int loop_nesting_;
bool has_this_properties_;
bool has_globals_;
};
......
......@@ -196,9 +196,12 @@ void AstLabeler::VisitAssignment(Assignment* expr) {
ASSERT(prop != NULL);
if (prop != NULL) {
ASSERT(prop->key()->IsPropertyName());
if (prop->obj()->AsVariableProxy() == NULL ||
!prop->obj()->AsVariableProxy()->var()->is_this())
VariableProxy* proxy = prop->obj()->AsVariableProxy();
if (proxy != NULL && proxy->var()->is_this()) {
has_this_properties_ = true;
} else {
Visit(prop->obj());
}
}
Visit(expr->value());
expr->set_num(next_number_++);
......
......@@ -38,10 +38,12 @@ namespace internal {
// their evaluation order (post-order left-to-right traversal).
class AstLabeler: public AstVisitor {
public:
AstLabeler() : next_number_(0) {}
AstLabeler() : next_number_(0), has_this_properties_(false) {}
void Label(FunctionLiteral* fun);
bool has_this_properties() { return has_this_properties_; }
private:
void VisitDeclarations(ZoneList<Declaration*>* decls);
void VisitStatements(ZoneList<Statement*>* stmts);
......@@ -54,6 +56,8 @@ class AstLabeler: public AstVisitor {
// Traversal number for labelling AST nodes.
int next_number_;
bool has_this_properties_;
DISALLOW_COPY_AND_ASSIGN(AstLabeler);
};
......
......@@ -27,8 +27,10 @@
#include "v8.h"
#include "codegen-inl.h"
#include "data-flow.h"
#include "fast-codegen.h"
#include "full-codegen.h"
#include "scopes.h"
namespace v8 {
......@@ -54,8 +56,12 @@ void FastCodeGenSyntaxChecker::Check(FunctionLiteral* fun,
CompilationInfo* 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->receiver()->IsJSObject()) BAILOUT("Receiver is not an object");
Handle<JSObject> object = Handle<JSObject>::cast(info->receiver());
if (!object->HasFastProperties()) BAILOUT("Receiver is in dictionary mode");
// We do not support stack or heap slots (both of which require
// allocation).
......@@ -325,25 +331,42 @@ void FastCodeGenSyntaxChecker::VisitThisFunction(ThisFunction* expr) {
#undef CHECK_BAILOUT
void FastCodeGenerator::MakeCode(FunctionLiteral* fun,
Handle<Script> script,
bool is_eval,
CompilationInfo* info) {
#define __ ACCESS_MASM(masm())
Handle<Code> FastCodeGenerator::MakeCode(FunctionLiteral* fun,
Handle<Script> script,
bool is_eval,
CompilationInfo* info) {
// Label the AST before calling MakeCodePrologue, so AST node numbers are
// printed with the AST.
AstLabeler labeler;
FastCodeGenerator cgen(script, is_eval);
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) {
ASSERT(function_ == NULL);
ASSERT(info_ == NULL);
function_ = fun;
info_ = info;
VisitStatements(fun->body());
function_ = NULL;
info_ = NULL;
const int kInitialBufferSize = 4 * KB;
MacroAssembler masm(NULL, kInitialBufferSize);
// Generate the fast-path code.
FastCodeGenerator fast_cgen(&masm, script, is_eval);
fast_cgen.Generate(fun, info);
if (fast_cgen.HasStackOverflow()) {
ASSERT(!Top::has_pending_exception());
return Handle<Code>::null();
}
// Generate the full code for the function in bailout mode, using the same
// macro assembler.
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) {
void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
ASSERT(expr->var()->is_global() && !expr->var()->is_this());
Comment cmnt(masm(), ";; Global");
if (FLAG_print_ir) {
ASSERT(expr->var()->is_global() && !expr->var()->is_this());
SmartPointer<char> name = expr->name()->ToCString();
PrintF("%d: t%d = Global(%s)\n", expr->num(), expr->num(), *name);
}
EmitGlobalVariableLoad(expr->name());
}
......@@ -496,18 +521,22 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
// Known to be a simple this property assignment.
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) {
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> key =
Handle<String>::cast(prop->key()->AsLiteral()->handle());
SmartPointer<char> name = key->ToCString();
SmartPointer<char> name_string = name->ToCString();
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) {
UNREACHABLE();
}
#undef __
} } // namespace v8::internal
......@@ -65,27 +65,54 @@ class FastCodeGenSyntaxChecker: public AstVisitor {
class FastCodeGenerator: public AstVisitor {
public:
FastCodeGenerator(Handle<Script> script, bool is_eval)
: masm_(NULL),
FastCodeGenerator(MacroAssembler* masm, Handle<Script> script, bool is_eval)
: masm_(masm),
script_(script),
is_eval_(is_eval),
function_(NULL),
info_(NULL) {
}
static void MakeCode(FunctionLiteral* fun,
Handle<Script> script,
bool is_eval,
CompilationInfo* info);
static Handle<Code> MakeCode(FunctionLiteral* fun,
Handle<Script> script,
bool is_eval,
CompilationInfo* info);
void Generate(FunctionLiteral* fun, CompilationInfo* info);
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.
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(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_;
Handle<Script> script_;
bool is_eval_;
......@@ -93,6 +120,8 @@ class FastCodeGenerator: public AstVisitor {
FunctionLiteral* function_;
CompilationInfo* info_;
Label bailout_;
DISALLOW_COPY_AND_ASSIGN(FastCodeGenerator);
};
......
......@@ -462,7 +462,7 @@ Handle<Code> FullCodeGenerator::MakeCode(FunctionLiteral* fun,
const int kInitialBufferSize = 4 * KB;
MacroAssembler masm(NULL, kInitialBufferSize);
FullCodeGenerator cgen(&masm, script, is_eval);
cgen.Generate(fun);
cgen.Generate(fun, PRIMARY);
if (cgen.HasStackOverflow()) {
ASSERT(!Top::has_pending_exception());
return Handle<Code>::null();
......@@ -1161,7 +1161,6 @@ int FullCodeGenerator::TryCatch::Exit(int stack_depth) {
return 0;
}
#undef __
......
......@@ -63,11 +63,16 @@ class FullCodeGenSyntaxChecker: public AstVisitor {
class FullCodeGenerator: public AstVisitor {
public:
enum Mode {
PRIMARY,
SECONDARY
};
FullCodeGenerator(MacroAssembler* masm, Handle<Script> script, bool is_eval)
: masm_(masm),
function_(NULL),
script_(script),
is_eval_(is_eval),
function_(NULL),
nesting_stack_(NULL),
loop_depth_(0),
location_(kStack),
......@@ -79,7 +84,7 @@ class FullCodeGenerator: public AstVisitor {
Handle<Script> script,
bool is_eval);
void Generate(FunctionLiteral* fun);
void Generate(FunctionLiteral* fun, Mode mode);
private:
class Breakable;
......@@ -422,9 +427,11 @@ class FullCodeGenerator: public AstVisitor {
void EmitLogicalOperation(BinaryOperation* expr);
MacroAssembler* masm_;
FunctionLiteral* function_;
Handle<Script> script_;
bool is_eval_;
FunctionLiteral* function_;
Label return_label_;
NestedStatement* nesting_stack_;
int loop_depth_;
......
......@@ -633,6 +633,7 @@ class CodeGenerator: public AstVisitor {
friend class JumpTarget;
friend class Reference;
friend class Result;
friend class FastCodeGenerator;
friend class FullCodeGenerator;
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 {
//
// The function builds a JS frame. Please see JavaScriptFrameConstants in
// frames-ia32.h for its layout.
void FullCodeGenerator::Generate(FunctionLiteral* fun) {
void FullCodeGenerator::Generate(FunctionLiteral* fun, Mode mode) {
function_ = fun;
SetFunctionPosition(fun);
__ push(ebp); // Caller's frame pointer.
__ mov(ebp, esp);
__ push(esi); // Callee's context.
__ push(edi); // Callee's JS Function.
{ Comment cmnt(masm_, "[ Allocate locals");
int locals_count = fun->scope()->num_stack_slots();
if (locals_count == 1) {
__ push(Immediate(Factory::undefined_value()));
} else if (locals_count > 1) {
__ mov(eax, Immediate(Factory::undefined_value()));
for (int i = 0; i < locals_count; i++) {
__ push(eax);
if (mode == PRIMARY) {
__ push(ebp); // Caller's frame pointer.
__ mov(ebp, esp);
__ push(esi); // Callee's context.
__ push(edi); // Callee's JS Function.
{ Comment cmnt(masm_, "[ Allocate locals");
int locals_count = fun->scope()->num_stack_slots();
if (locals_count == 1) {
__ push(Immediate(Factory::undefined_value()));
} else if (locals_count > 1) {
__ mov(eax, Immediate(Factory::undefined_value()));
for (int i = 0; i < locals_count; i++) {
__ push(eax);
}
}
}
}
bool function_in_register = true;
// Possibly allocate a local context.
if (fun->scope()->num_heap_slots() > 0) {
Comment cmnt(masm_, "[ Allocate local context");
// Argument to NewContext is the function, which is still in edi.
__ push(edi);
__ CallRuntime(Runtime::kNewContext, 1);
function_in_register = false;
// 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.
__ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
// Copy parameters into context if necessary.
int num_parameters = fun->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
Slot* slot = fun->scope()->parameter(i)->slot();
if (slot != NULL && slot->type() == Slot::CONTEXT) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ mov(eax, Operand(ebp, parameter_offset));
// Store it in the context
__ mov(Operand(esi, Context::SlotOffset(slot->index())), eax);
bool function_in_register = true;
// Possibly allocate a local context.
if (fun->scope()->num_heap_slots() > 0) {
Comment cmnt(masm_, "[ Allocate local context");
// Argument to NewContext is the function, which is still in edi.
__ push(edi);
__ CallRuntime(Runtime::kNewContext, 1);
function_in_register = false;
// 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.
__ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
// Copy parameters into context if necessary.
int num_parameters = fun->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
Slot* slot = fun->scope()->parameter(i)->slot();
if (slot != NULL && slot->type() == Slot::CONTEXT) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ mov(eax, Operand(ebp, parameter_offset));
// Store it in the context
__ mov(Operand(esi, Context::SlotOffset(slot->index())), eax);
}
}
}
}
Variable* arguments = fun->scope()->arguments()->AsVariable();
if (arguments != NULL) {
// Function uses arguments object.
Comment cmnt(masm_, "[ Allocate arguments object");
if (function_in_register) {
__ push(edi);
} else {
__ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Variable* arguments = fun->scope()->arguments()->AsVariable();
if (arguments != NULL) {
// Function uses arguments object.
Comment cmnt(masm_, "[ Allocate arguments object");
if (function_in_register) {
__ push(edi);
} else {
__ 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");
......
......@@ -630,6 +630,7 @@ class CodeGenerator: public AstVisitor {
friend class JumpTarget;
friend class Reference;
friend class Result;
friend class FastCodeGenerator;
friend class FullCodeGenerator;
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 {
//
// The function builds a JS frame. Please see JavaScriptFrameConstants in
// frames-x64.h for its layout.
void FullCodeGenerator::Generate(FunctionLiteral* fun) {
void FullCodeGenerator::Generate(FunctionLiteral* fun, Mode mode) {
function_ = fun;
SetFunctionPosition(fun);
__ push(rbp); // Caller's frame pointer.
__ movq(rbp, rsp);
__ push(rsi); // Callee's context.
__ push(rdi); // Callee's JS Function.
{ Comment cmnt(masm_, "[ Allocate locals");
int locals_count = fun->scope()->num_stack_slots();
if (locals_count == 1) {
__ PushRoot(Heap::kUndefinedValueRootIndex);
} else if (locals_count > 1) {
__ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
for (int i = 0; i < locals_count; i++) {
__ push(rdx);
if (mode == PRIMARY) {
__ push(rbp); // Caller's frame pointer.
__ movq(rbp, rsp);
__ push(rsi); // Callee's context.
__ push(rdi); // Callee's JS Function.
{ Comment cmnt(masm_, "[ Allocate locals");
int locals_count = fun->scope()->num_stack_slots();
if (locals_count == 1) {
__ PushRoot(Heap::kUndefinedValueRootIndex);
} else if (locals_count > 1) {
__ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
for (int i = 0; i < locals_count; i++) {
__ push(rdx);
}
}
}
}
bool function_in_register = true;
// Possibly allocate a local context.
if (fun->scope()->num_heap_slots() > 0) {
Comment cmnt(masm_, "[ Allocate local context");
// Argument to NewContext is the function, which is still in rdi.
__ push(rdi);
__ CallRuntime(Runtime::kNewContext, 1);
function_in_register = false;
// 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.
__ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
// Copy any necessary parameters into the context.
int num_parameters = fun->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
Slot* slot = fun->scope()->parameter(i)->slot();
if (slot != NULL && slot->type() == Slot::CONTEXT) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ movq(rax, Operand(rbp, parameter_offset));
// Store it in the context
__ movq(Operand(rsi, Context::SlotOffset(slot->index())), rax);
bool function_in_register = true;
// Possibly allocate a local context.
if (fun->scope()->num_heap_slots() > 0) {
Comment cmnt(masm_, "[ Allocate local context");
// Argument to NewContext is the function, which is still in rdi.
__ push(rdi);
__ CallRuntime(Runtime::kNewContext, 1);
function_in_register = false;
// 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.
__ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
// Copy any necessary parameters into the context.
int num_parameters = fun->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
Slot* slot = fun->scope()->parameter(i)->slot();
if (slot != NULL && slot->type() == Slot::CONTEXT) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ movq(rax, Operand(rbp, parameter_offset));
// Store it in the context
__ movq(Operand(rsi, Context::SlotOffset(slot->index())), rax);
}
}
}
}
// Possibly allocate an arguments object.
Variable* arguments = fun->scope()->arguments()->AsVariable();
if (arguments != NULL) {
// Arguments object must be allocated after the context object, in
// case the "arguments" or ".arguments" variables are in the context.
Comment cmnt(masm_, "[ Allocate arguments object");
if (function_in_register) {
__ push(rdi);
} else {
__ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
// Possibly allocate an arguments object.
Variable* arguments = fun->scope()->arguments()->AsVariable();
if (arguments != NULL) {
// Arguments object must be allocated after the context object, in
// case the "arguments" or ".arguments" variables are in the context.
Comment cmnt(masm_, "[ Allocate arguments object");
if (function_in_register) {
__ push(rdi);
} else {
__ 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");
......
......@@ -412,6 +412,7 @@
'../../src/arm/cpu-arm.cc',
'../../src/arm/debug-arm.cc',
'../../src/arm/disasm-arm.cc',
'../../src/arm/fast-codegen-arm.cc',
'../../src/arm/frames-arm.cc',
'../../src/arm/frames-arm.h',
'../../src/arm/full-codegen-arm.cc',
......@@ -450,6 +451,7 @@
'../../src/ia32/cpu-ia32.cc',
'../../src/ia32/debug-ia32.cc',
'../../src/ia32/disasm-ia32.cc',
'../../src/ia32/fast-codegen-ia32.cc',
'../../src/ia32/frames-ia32.cc',
'../../src/ia32/frames-ia32.h',
'../../src/ia32/full-codegen-ia32.cc',
......@@ -479,6 +481,7 @@
'../../src/x64/cpu-x64.cc',
'../../src/x64/debug-x64.cc',
'../../src/x64/disasm-x64.cc',
'../../src/x64/fast-codegen-x64.cc',
'../../src/x64/frames-x64.cc',
'../../src/x64/frames-x64.h',
'../../src/x64/full-codegen-x64.cc',
......
......@@ -396,6 +396,10 @@
RelativePath="..\..\src\factory.h"
>
</File>
<File
RelativePath="..\..\src\ia32\fast-codegen-ia32.cc"
>
</File>
<File
RelativePath="..\..\src\fast-codegen.cc"
>
......
......@@ -404,6 +404,10 @@
RelativePath="..\..\src\factory.h"
>
</File>
<File
RelativePath="..\..\src\arm\fast-codegen-arm.cc"
>
</File>
<File
RelativePath="..\..\src\fast-codegen.cc"
>
......
......@@ -396,6 +396,10 @@
RelativePath="..\..\src\factory.h"
>
</File>
<File
RelativePath="..\..\src\x64\fast-codegen-x64.cc"
>
</File>
<File
RelativePath="..\..\src\fast-codegen.cc"
>
......@@ -441,15 +445,15 @@
>
</File>
<File
RelativePath="..\..\src\full-codegen.cc"
RelativePath="..\..\src\x64\full-codegen-x64.cc"
>
</File>
<File
RelativePath="..\..\src\full-codegen.h"
RelativePath="..\..\src\full-codegen.cc"
>
</File>
<File
RelativePath="..\..\src\x64\full-codegen-x64.cc"
RelativePath="..\..\src\full-codegen.h"
>
</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