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
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
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
friend class VirtualFrame;
friend class JumpTarget;
friend class Reference;
+ friend class FastCodeGenerator;
friend class FullCodeGenerator;
friend class FullCodeGenSyntaxChecker;
--- /dev/null
+// 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
//
// 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.
// 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");
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);
}
}
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;
}
}
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_; }
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_;
};
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_++);
// 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);
// Traversal number for labelling AST nodes.
int next_number_;
+ bool has_this_properties_;
+
DISALLOW_COPY_AND_ASSIGN(AstLabeler);
};
#include "v8.h"
+#include "codegen-inl.h"
#include "data-flow.h"
#include "fast-codegen.h"
+#include "full-codegen.h"
#include "scopes.h"
namespace v8 {
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).
#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);
}
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());
}
// 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);
}
UNREACHABLE();
}
+#undef __
+
+
} } // namespace v8::internal
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_;
FunctionLiteral* function_;
CompilationInfo* info_;
+ Label bailout_;
+
DISALLOW_COPY_AND_ASSIGN(FastCodeGenerator);
};
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();
return 0;
}
-
#undef __
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),
Handle<Script> script,
bool is_eval);
- void Generate(FunctionLiteral* fun);
+ void Generate(FunctionLiteral* fun, Mode mode);
private:
class Breakable;
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_;
friend class JumpTarget;
friend class Reference;
friend class Result;
+ friend class FastCodeGenerator;
friend class FullCodeGenerator;
friend class FullCodeGenSyntaxChecker;
--- /dev/null
+// 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
//
// 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");
friend class JumpTarget;
friend class Reference;
friend class Result;
+ friend class FastCodeGenerator;
friend class FullCodeGenerator;
friend class FullCodeGenSyntaxChecker;
--- /dev/null
+// 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
//
// 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");
'../../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',
'../../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',
'../../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',
RelativePath="..\..\src\factory.h"
>
</File>
+ <File
+ RelativePath="..\..\src\ia32\fast-codegen-ia32.cc"
+ >
+ </File>
<File
RelativePath="..\..\src\fast-codegen.cc"
>
RelativePath="..\..\src\factory.h"
>
</File>
+ <File
+ RelativePath="..\..\src\arm\fast-codegen-arm.cc"
+ >
+ </File>
<File
RelativePath="..\..\src\fast-codegen.cc"
>
RelativePath="..\..\src\factory.h"
>
</File>
+ <File
+ RelativePath="..\..\src\x64\fast-codegen-x64.cc"
+ >
+ </File>
<File
RelativePath="..\..\src\fast-codegen.cc"
>
>
</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