Support for object literals in fast compiler.

I also added more unit tests for literals.

Right now, the fast compiler produces code very similar to
the existing code generator. We may consider different ways to 
further compact the generated code for top-level code.

ARM always goes through a runtime function to initialize computed
properties in an object literal whereas IA32 and x64 use StoreIC.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3129 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent a531c281
......@@ -234,6 +234,98 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
}
void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Comment cmnt(masm_, "[ ObjectLiteral");
Label boilerplate_exists;
__ ldr(r2, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
// r2 = literal array (0).
__ ldr(r2, FieldMemOperand(r2, JSFunction::kLiteralsOffset));
int literal_offset =
FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
__ ldr(r0, FieldMemOperand(r2, literal_offset));
// Check whether we need to materialize the object literal boilerplate.
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
__ cmp(r0, Operand(ip));
__ b(ne, &boilerplate_exists);
// Create boilerplate if it does not exist.
// r1 = literal index (1).
__ mov(r1, Operand(Smi::FromInt(expr->literal_index())));
// r0 = constant properties (2).
__ mov(r0, Operand(expr->constant_properties()));
__ stm(db_w, sp, r2.bit() | r1.bit() | r0.bit());
__ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3);
__ bind(&boilerplate_exists);
// r0 contains boilerplate.
// Clone boilerplate.
__ push(r0);
if (expr->depth() > 1) {
__ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1);
} else {
__ CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1);
}
// If result_saved == true: the result is saved on top of the stack.
// If result_saved == false: the result is in eax.
bool result_saved = false;
for (int i = 0; i < expr->properties()->length(); i++) {
ObjectLiteral::Property* property = expr->properties()->at(i);
Literal* key = property->key();
Expression* value = property->value();
if (property->kind() == ObjectLiteral::Property::CONSTANT) continue;
if (property->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL &&
CompileTimeValue::IsCompileTimeValue(value)) {
continue;
}
if (!result_saved) {
__ push(r0); // Save result on stack
result_saved = true;
}
switch (property->kind()) {
case ObjectLiteral::Property::MATERIALIZED_LITERAL: // fall through
ASSERT(!CompileTimeValue::IsCompileTimeValue(property->value()));
case ObjectLiteral::Property::COMPUTED: // fall through
case ObjectLiteral::Property::PROTOTYPE:
__ push(r0);
Visit(key);
if (key->location().is_constant()) {
__ mov(r1, Operand(key->handle()));
__ push(r1);
}
Visit(value);
ASSERT(value->location().is_temporary());
__ CallRuntime(Runtime::kSetProperty, 3);
__ ldr(r0, MemOperand(sp)); // Restore result into r0
break;
case ObjectLiteral::Property::SETTER: // fall through
case ObjectLiteral::Property::GETTER:
__ push(r0);
Visit(key);
if (key->location().is_constant()) {
__ mov(r1, Operand(key->handle()));
__ push(r1);
}
__ mov(r1, Operand(property->kind() == ObjectLiteral::Property::SETTER ?
Smi::FromInt(1) :
Smi::FromInt(0)));
__ push(r1);
Visit(value);
ASSERT(value->location().is_temporary());
__ CallRuntime(Runtime::kDefineAccessor, 4);
__ ldr(r0, MemOperand(sp)); // Restore result into r0
break;
default: UNREACHABLE();
}
}
if (expr->location().is_nowhere() && result_saved) {
__ pop();
} else if (expr->location().is_temporary() && !result_saved) {
ASSERT(expr->location().is_temporary());
__ push(r0);
}
}
void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
Comment cmnt(masm_, "[ RegExp Literal");
Label done;
......
......@@ -639,7 +639,13 @@ void CodeGenSelector::VisitRegExpLiteral(RegExpLiteral* expr) {
void CodeGenSelector::VisitObjectLiteral(ObjectLiteral* expr) {
BAILOUT("ObjectLiteral");
for (int i = 0; i < expr->properties()->length(); i++) {
ObjectLiteral::Property* property = expr->properties()->at(i);
Visit(property->key());
CHECK_BAILOUT;
Visit(property->value());
CHECK_BAILOUT;
}
}
......
......@@ -284,11 +284,6 @@ void FastCodeGenerator::VisitLiteral(Literal* expr) {
}
void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) {
UNREACHABLE();
}
......
......@@ -221,6 +221,108 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
}
void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Comment cmnt(masm_, "[ ObjectLiteral");
Label exists;
// Registers will be used as follows:
// edi = JS function.
// ebx = literals array.
// eax = boilerplate
__ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
__ mov(ebx, FieldOperand(edi, JSFunction::kLiteralsOffset));
int literal_offset =
FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
__ mov(eax, FieldOperand(ebx, literal_offset));
__ cmp(eax, Factory::undefined_value());
__ j(not_equal, &exists);
// Create boilerplate if it does not exist.
// Literal array (0).
__ push(ebx);
// Literal index (1).
__ push(Immediate(Smi::FromInt(expr->literal_index())));
// Constant properties (2).
__ push(Immediate(expr->constant_properties()));
__ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3);
__ bind(&exists);
// eax contains boilerplate.
// Clone boilerplate.
__ push(eax);
if (expr->depth() == 1) {
__ CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1);
} else {
__ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1);
}
// If result_saved == true: the result is saved on top of the stack.
// If result_saved == false: the result not on the stack, just is in eax.
bool result_saved = false;
for (int i = 0; i < expr->properties()->length(); i++) {
ObjectLiteral::Property* property = expr->properties()->at(i);
Literal* key = property->key();
Expression* value = property->value();
if (property->kind() == ObjectLiteral::Property::CONSTANT) continue;
if (property->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL &&
CompileTimeValue::IsCompileTimeValue(value)) {
continue;
}
if (!result_saved) {
__ push(eax); // Save result on the stack
result_saved = true;
}
switch (property->kind()) {
case ObjectLiteral::Property::MATERIALIZED_LITERAL: // fall through
ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
case ObjectLiteral::Property::COMPUTED:
if (key->handle()->IsSymbol()) {
Visit(value);
ASSERT(value->location().is_temporary());
__ pop(eax);
__ mov(ecx, Immediate(key->handle()));
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
// StoreIC leaves the receiver on the stack.
break;
}
// fall through
case ObjectLiteral::Property::PROTOTYPE:
__ push(eax);
Visit(key);
if (key->location().is_constant()) {
__ push(Immediate(key->handle()));
}
Visit(value);
ASSERT(value->location().is_temporary());
__ CallRuntime(Runtime::kSetProperty, 3);
__ mov(eax, Operand(esp, 0)); // Restore result into eax.
break;
case ObjectLiteral::Property::SETTER: // fall through
case ObjectLiteral::Property::GETTER:
__ push(eax);
Visit(key);
if (key->location().is_constant()) {
__ push(Immediate(key->handle()));
}
__ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ?
Smi::FromInt(1) :
Smi::FromInt(0)));
Visit(value);
ASSERT(value->location().is_temporary());
__ CallRuntime(Runtime::kDefineAccessor, 4);
__ mov(eax, Operand(esp, 0)); // Restore result into eax.
break;
default: UNREACHABLE();
}
}
if (expr->location().is_nowhere() && result_saved) {
__ add(Operand(esp), Immediate(kPointerSize));
} else if (expr->location().is_temporary() && !result_saved) {
__ push(eax);
}
}
void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
Comment cmnt(masm_, "[ RegExp Literal");
Label done;
......
......@@ -237,6 +237,104 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
}
void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Comment cmnt(masm_, "[ ObjectLiteral");
Label boilerplate_exists;
__ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
__ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset));
int literal_offset =
FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
__ movq(rax, FieldOperand(rbx, literal_offset));
__ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
__ j(not_equal, &boilerplate_exists);
// Create boilerplate if it does not exist.
// Literal array (0).
__ push(rbx);
// Literal index (1).
__ Push(Smi::FromInt(expr->literal_index()));
// Constant properties (2).
__ Push(expr->constant_properties());
__ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3);
__ bind(&boilerplate_exists);
// rax contains boilerplate.
// Clone boilerplate.
__ push(rax);
if (expr->depth() == 1) {
__ CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1);
} else {
__ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1);
}
// If result_saved == true: the result is saved on top of the stack.
// If result_saved == false: the result is not on the stack, just in rax.
bool result_saved = false;
for (int i = 0; i < expr->properties()->length(); i++) {
ObjectLiteral::Property* property = expr->properties()->at(i);
Literal* key = property->key();
Expression* value = property->value();
if (property->kind() == ObjectLiteral::Property::CONSTANT) continue;
if (property->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL &&
CompileTimeValue::IsCompileTimeValue(value)) {
continue;
}
if (!result_saved) {
__ push(rax); // Save result on the stack
result_saved = true;
}
switch (property->kind()) {
case ObjectLiteral::Property::MATERIALIZED_LITERAL: // fall through
ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
case ObjectLiteral::Property::COMPUTED:
if (key->handle()->IsSymbol()) {
Visit(value);
ASSERT(value->location().is_temporary());
__ pop(rax);
__ Move(rcx, key->handle());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
// StoreIC leaves the receiver on the stack.
break;
}
// fall through
case ObjectLiteral::Property::PROTOTYPE:
__ push(rax);
Visit(key);
if (key->location().is_constant()) {
__ Push(key->handle());
}
Visit(value);
ASSERT(value->location().is_temporary());
__ CallRuntime(Runtime::kSetProperty, 3);
__ movq(rax, Operand(rsp, 0)); // Restore result into rax.
break;
case ObjectLiteral::Property::SETTER: // fall through
case ObjectLiteral::Property::GETTER:
__ push(rax);
Visit(key);
if (key->location().is_constant()) {
__ Push(key->handle());
}
__ Push(property->kind() == ObjectLiteral::Property::SETTER ?
Smi::FromInt(1) :
Smi::FromInt(0));
Visit(value);
ASSERT(value->location().is_temporary());
__ CallRuntime(Runtime::kDefineAccessor, 4);
__ movq(rax, Operand(rsp, 0)); // Restore result into rax.
break;
default: UNREACHABLE();
}
}
if (expr->location().is_nowhere() && result_saved) {
__ addq(rsp, Immediate(kPointerSize));
} else if (expr->location().is_temporary() && !result_saved) {
__ push(rax);
}
}
void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
Comment cmnt(masm_, "[ RegExp Literal");
Label done;
......
......@@ -69,3 +69,36 @@ code = "(function() {\
})()";
assertEquals(8, eval(code));
// Test object literals.
var a, b;
code = "a = {x:8}";
eval(code);
assertEquals(8, a.x);
code = "b = {x:a, y:'abc'}";
eval(code);
assertEquals(a, b.x);
assertEquals(8, b.x.x);
assertEquals("abc", b.y);
code = "({x:8, y:9}); 10";
assertEquals(10, eval(code));
code = "({x:8, y:9})";
eval(code);
assertEquals(9, eval(code+".y"));
code = "a = {2:8, x:9}";
eval(code);
assertEquals(8, a[2]);
assertEquals(8, a["2"]);
assertEquals(9, a["x"]);
// Test regexp literals.
a = /abc/;
assertEquals(/abc/, a);
code = "/abc/; 8";
assertEquals(8, eval(code));
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