Implement code generation for conditional expressions and regexp

literals.  Regexp literals will not really work before we can
bootstrap, but the right code is being called with the right
arguments.

Finish implementation of object literals.  We can now call through the
StoreIC_Miss stub into the runtime system to do stores.

Restore comment that I accidentally removed in my last commit.
Review URL: http://codereview.chromium.org/140068

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2244 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
ager@chromium.org 2009-06-22 19:25:41 +00:00
parent a874dcdd5d
commit ad970953f8
5 changed files with 210 additions and 39 deletions

View File

@ -165,8 +165,10 @@ void CodeGenerator::TestCodeGenerator() {
" test_nesting_calls(test_local_variables(1,3), 42, 47),"
" test_local_variables(-25.3, 2));"
" // return test_recursion_with_base(0, 0, 0, 47);\n"
" var o = { x: 42 };"
" var x_value = 42;"
" var o = { x: x_value };"
" var a = [ 1, 2, 3 ];"
" var x = true ? 42 : 32;"
" return test_if_then_else(0, 46, 47);"
"})()")),
Factory::NewStringFromAscii(CStrVector("CodeGeneratorTestScript")),
@ -472,8 +474,11 @@ void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) {
}
void CodeGenerator::VisitEmptyStatement(EmptyStatement* a) {
UNIMPLEMENTED();
void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) {
ASSERT(!in_spilled_code());
Comment cmnt(masm_, "// EmptyStatement");
CodeForStatementPosition(node);
// nothing to do
}
@ -676,10 +681,38 @@ void CodeGenerator::VisitFunctionBoilerplateLiteral(
}
void CodeGenerator::VisitConditional(Conditional* a) {
UNIMPLEMENTED();
void CodeGenerator::VisitConditional(Conditional* node) {
Comment cmnt(masm_, "[ Conditional");
JumpTarget then;
JumpTarget else_;
JumpTarget exit;
ControlDestination dest(&then, &else_, true);
LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true);
if (dest.false_was_fall_through()) {
// The else target was bound, so we compile the else part first.
Load(node->else_expression(), typeof_state());
if (then.is_linked()) {
exit.Jump();
then.Bind();
Load(node->then_expression(), typeof_state());
}
} else {
// The then target was bound, so we compile the then part first.
Load(node->then_expression(), typeof_state());
if (else_.is_linked()) {
exit.Jump();
else_.Bind();
Load(node->else_expression(), typeof_state());
}
}
exit.Bind();
}
void CodeGenerator::VisitSlot(Slot* node) {
Comment cmnt(masm_, "[ Slot");
LoadFromSlot(node, typeof_state());
@ -706,8 +739,76 @@ void CodeGenerator::VisitLiteral(Literal* node) {
}
void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* a) {
UNIMPLEMENTED();
// Materialize the regexp literal 'node' in the literals array
// 'literals' of the function. Leave the regexp boilerplate in
// 'boilerplate'.
class DeferredRegExpLiteral: public DeferredCode {
public:
DeferredRegExpLiteral(Register boilerplate,
Register literals,
RegExpLiteral* node)
: boilerplate_(boilerplate), literals_(literals), node_(node) {
set_comment("[ DeferredRegExpLiteral");
}
void Generate();
private:
Register boilerplate_;
Register literals_;
RegExpLiteral* node_;
};
void DeferredRegExpLiteral::Generate() {
// Since the entry is undefined we call the runtime system to
// compute the literal.
// Literal array (0).
__ push(literals_);
// Literal index (1).
__ push(Immediate(Smi::FromInt(node_->literal_index())));
// RegExp pattern (2).
__ Push(node_->pattern());
// RegExp flags (3).
__ Push(node_->flags());
__ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
if (!boilerplate_.is(rax)) __ movq(boilerplate_, rax);
}
void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) {
Comment cmnt(masm_, "[ RegExp Literal");
// Retrieve the literals array and check the allocated entry. Begin
// with a writable copy of the function of this activation in a
// register.
frame_->PushFunction();
Result literals = frame_->Pop();
literals.ToRegister();
frame_->Spill(literals.reg());
// Load the literals array of the function.
__ movq(literals.reg(),
FieldOperand(literals.reg(), JSFunction::kLiteralsOffset));
// Load the literal at the ast saved index.
Result boilerplate = allocator_->Allocate();
ASSERT(boilerplate.is_valid());
int literal_offset =
FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
__ movq(boilerplate.reg(), FieldOperand(literals.reg(), literal_offset));
// Check whether we need to materialize the RegExp object. If so,
// jump to the deferred code passing the literals array.
DeferredRegExpLiteral* deferred =
new DeferredRegExpLiteral(boilerplate.reg(), literals.reg(), node);
__ Cmp(boilerplate.reg(), Factory::undefined_value());
deferred->Branch(equal);
deferred->BindExit();
literals.Unuse();
// Push the boilerplate object.
frame_->Push(&boilerplate);
}
@ -797,8 +898,18 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
if (CompileTimeValue::IsCompileTimeValue(property->value())) break;
// else fall through.
case ObjectLiteral::Property::COMPUTED: {
// TODO(X64): Implement setting of computed values in object literals.
UNIMPLEMENTED();
Handle<Object> key(property->key()->handle());
if (key->IsSymbol()) {
// Duplicate the object as the IC receiver.
frame_->Dup();
Load(property->value());
frame_->Push(key);
Result ignored = frame_->CallStoreIC();
// Drop the duplicated receiver and ignore the result.
frame_->Drop();
break;
}
// Fall through
}
case ObjectLiteral::Property::PROTOTYPE: {
// Duplicate the object as an argument to the runtime call.
@ -1889,6 +2000,10 @@ void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) {
} else if (slot->type() == Slot::LOCAL) {
frame_->StoreToLocalAt(slot->index());
} else {
// The other slot types (LOOKUP and GLOBAL) cannot reach here.
//
// The use of SlotOperand below is safe for an unspilled frame
// because the slot is a context slot.
ASSERT(slot->type() == Slot::CONTEXT);
frame_->Dup();
Result value = frame_->Pop();

View File

@ -32,10 +32,36 @@
namespace v8 {
namespace internal {
StackFrame::Type ExitFrame::GetStateForFramePointer(unsigned char* a,
StackFrame::State* b) {
// TODO(X64): UNIMPLEMENTED
return NONE;
StackFrame::Type StackFrame::ComputeType(State* state) {
ASSERT(state->fp != NULL);
if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) {
return ARGUMENTS_ADAPTOR;
}
// The marker and function offsets overlap. If the marker isn't a
// smi then the frame is a JavaScript frame -- and the marker is
// really the function.
const int offset = StandardFrameConstants::kMarkerOffset;
Object* marker = Memory::Object_at(state->fp + offset);
if (!marker->IsSmi()) return JAVA_SCRIPT;
return static_cast<StackFrame::Type>(Smi::cast(marker)->value());
}
StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) {
if (fp == 0) return NONE;
// Compute the stack pointer.
Address sp = Memory::Address_at(fp + ExitFrameConstants::kSPOffset);
// Fill in the state.
state->fp = fp;
state->sp = sp;
state->pc_address = reinterpret_cast<Address*>(sp - 1 * kPointerSize);
// Determine frame type.
if (Memory::Address_at(fp + ExitFrameConstants::kDebugMarkOffset) != 0) {
return EXIT_DEBUG;
} else {
return EXIT;
}
}
int JavaScriptFrame::GetProvidedParametersCount() const {
@ -43,11 +69,6 @@ int JavaScriptFrame::GetProvidedParametersCount() const {
return 0;
}
StackFrame::Type StackFrame::ComputeType(StackFrame::State* a) {
UNIMPLEMENTED();
return NONE;
}
byte* ArgumentsAdaptorFrame::GetCallerStackPointer() const {
UNIMPLEMENTED();
return NULL;

View File

@ -35,6 +35,12 @@
namespace v8 {
namespace internal {
// ----------------------------------------------------------------------------
// Static IC stub generators.
//
#define __ ACCESS_MASM(masm)
void KeyedLoadIC::ClearInlinedVersion(Address address) {
UNIMPLEMENTED();
@ -175,7 +181,21 @@ bool LoadIC::PatchInlinedLoad(Address address, Object* map, int index) {
}
void StoreIC::Generate(MacroAssembler* masm, ExternalReference const& f) {
masm->int3(); // UNIMPLEMENTED.
// ----------- S t a t e -------------
// -- rax : value
// -- rcx : name
// -- rsp[0] : return address
// -- rsp[8] : receiver
// -----------------------------------
// Move the return address below the arguments.
__ pop(rbx);
__ push(Operand(rsp, 0));
__ push(rcx);
__ push(rax);
__ push(rbx);
// Perform tail call to the entry.
__ TailCallRuntime(f, 3);
}
void StoreIC::GenerateExtendStorage(MacroAssembler* masm) {
@ -186,4 +206,8 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
masm->int3(); // UNIMPLEMENTED.
}
#undef __
} } // namespace v8::internal

View File

@ -39,19 +39,11 @@ namespace internal {
void Result::ToRegister() {
ASSERT(is_valid());
if (is_constant()) {
// TODO(X64): Handle constant results.
/*
Result fresh = CodeGeneratorScope::Current()->allocator()->Allocate();
ASSERT(fresh.is_valid());
if (CodeGeneratorScope::Current()->IsUnsafeSmi(handle())) {
CodeGeneratorScope::Current()->LoadUnsafeSmi(fresh.reg(), handle());
} else {
CodeGeneratorScope::Current()->masm()->Set(fresh.reg(),
Immediate(handle()));
}
CodeGeneratorScope::Current()->masm()->Move(fresh.reg(), handle());
// This result becomes a copy of the fresh one.
*this = fresh;
*/
}
ASSERT(is_register());
}
@ -66,17 +58,7 @@ void Result::ToRegister(Register target) {
CodeGeneratorScope::Current()->masm()->movq(fresh.reg(), reg());
} else {
ASSERT(is_constant());
if (handle()->IsSmi()) {
if (CodeGeneratorScope::Current()->IsUnsafeSmi(handle())) {
CodeGeneratorScope::Current()->LoadUnsafeSmi(fresh.reg(), handle());
} else {
CodeGeneratorScope::Current()->masm()->
movq(fresh.reg(), handle(), RelocInfo::NONE);
}
} else {
CodeGeneratorScope::Current()->masm()->
movq(fresh.reg(), handle(), RelocInfo::EMBEDDED_OBJECT);
}
CodeGeneratorScope::Current()->masm()->Move(fresh.reg(), handle());
}
*this = fresh;
} else if (is_register() && reg().is(target)) {

View File

@ -857,6 +857,35 @@ Result VirtualFrame::CallCallIC(RelocInfo::Mode mode,
}
Result VirtualFrame::CallStoreIC() {
// Name, value, and receiver are on top of the frame. The IC
// expects name in rcx, value in rax, and receiver on the stack. It
// does not drop the receiver.
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
Result name = Pop();
Result value = Pop();
PrepareForCall(1, 0); // One stack arg, not callee-dropped.
if (value.is_register() && value.reg().is(rcx)) {
if (name.is_register() && name.reg().is(rax)) {
// Wrong registers.
__ xchg(rax, rcx);
} else {
// Register rax is free for value, which frees rcx for name.
value.ToRegister(rax);
name.ToRegister(rcx);
}
} else {
// Register rcx is free for name, which guarantees rax is free for
// value.
name.ToRegister(rcx);
value.ToRegister(rax);
}
name.Unuse();
value.Unuse();
return RawCallCodeObject(ic, RelocInfo::CODE_TARGET);
}
#undef __