MIPS: Implement crankshaft support for nested object literals.

Port r10061 (c648e1d1)

Original commit message:
This generates optimized code for deep-copying of nested object literal
boilerplates which are statically known. Most of the boilerplates have
already been generated at crankshaft time, so this optimization should
kick in for virtually every object literal. Only nested object literal
graphs up to a certain depth and containing up to a certain total number
of properties are considered for this optimization. This will prevent
explosion of code size due to large object literals (e.g. eval on JSON).
Improves splay performance because object literals are created often.

BUG=
TEST=

Review URL: http://codereview.chromium.org/8745012
Patch from Daniel Kalmar <kalmard@homejinni.com>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10128 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
mstarzinger@chromium.org 2011-12-01 14:32:26 +00:00
parent 8acd4accac
commit 830f763b07
4 changed files with 95 additions and 7 deletions

View File

@ -4174,7 +4174,74 @@ void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
}
void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
Register result,
Register source,
int* offset) {
ASSERT(!source.is(a2));
ASSERT(!result.is(a2));
// Increase the offset so that subsequent objects end up right after
// this one.
int current_offset = *offset;
int size = object->map()->instance_size();
*offset += size;
// Copy object header.
ASSERT(object->properties()->length() == 0);
ASSERT(object->elements()->length() == 0 ||
object->elements()->map() == isolate()->heap()->fixed_cow_array_map());
int inobject_properties = object->map()->inobject_properties();
int header_size = size - inobject_properties * kPointerSize;
for (int i = 0; i < header_size; i += kPointerSize) {
__ lw(a2, FieldMemOperand(source, i));
__ sw(a2, FieldMemOperand(result, current_offset + i));
}
// Copy in-object properties.
for (int i = 0; i < inobject_properties; i++) {
int total_offset = current_offset + object->GetInObjectPropertyOffset(i);
Handle<Object> value = Handle<Object>(object->InObjectPropertyAt(i));
if (value->IsJSObject()) {
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
__ Addu(a2, result, Operand(*offset));
__ sw(a2, FieldMemOperand(result, total_offset));
LoadHeapObject(source, value_object);
EmitDeepCopy(value_object, result, source, offset);
} else if (value->IsHeapObject()) {
LoadHeapObject(a2, Handle<HeapObject>::cast(value));
__ sw(a2, FieldMemOperand(result, total_offset));
} else {
__ li(a2, Operand(value));
__ sw(a2, FieldMemOperand(result, total_offset));
}
}
}
void LCodeGen::DoObjectLiteralFast(LObjectLiteralFast* instr) {
int size = instr->hydrogen()->total_size();
// Allocate all objects that are part of the literal in one big
// allocation. This avoids multiple limit checks.
Label allocated, runtime_allocate;
__ AllocateInNewSpace(size, v0, a2, a3, &runtime_allocate, TAG_OBJECT);
__ jmp(&allocated);
__ bind(&runtime_allocate);
__ li(a0, Operand(Smi::FromInt(size)));
__ push(a0);
CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
__ bind(&allocated);
int offset = 0;
LoadHeapObject(a1, instr->hydrogen()->boilerplate());
EmitDeepCopy(instr->hydrogen()->boilerplate(), v0, a1, &offset);
ASSERT_EQ(size, offset);
}
void LCodeGen::DoObjectLiteralGeneric(LObjectLiteralGeneric* instr) {
ASSERT(ToRegister(instr->result()).is(v0));
Handle<FixedArray> constant_properties =

View File

@ -316,6 +316,13 @@ class LCodeGen BASE_EMBEDDED {
Handle<Map> type,
Handle<String> name);
// Emits optimized code to deep-copy the contents of statically known
// object graphs (e.g. object literal boilerplate).
void EmitDeepCopy(Handle<JSObject> object,
Register result,
Register source,
int* offset);
struct JumpTableEntry {
explicit inline JumpTableEntry(Address entry)
: label(),

View File

@ -2071,8 +2071,14 @@ LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
}
LInstruction* LChunkBuilder::DoObjectLiteral(HObjectLiteral* instr) {
return MarkAsCall(DefineFixed(new LObjectLiteral, v0), instr);
LInstruction* LChunkBuilder::DoObjectLiteralFast(HObjectLiteralFast* instr) {
return MarkAsCall(DefineFixed(new LObjectLiteralFast, v0), instr);
}
LInstruction* LChunkBuilder::DoObjectLiteralGeneric(
HObjectLiteralGeneric* instr) {
return MarkAsCall(DefineFixed(new LObjectLiteralGeneric, v0), instr);
}

View File

@ -134,7 +134,8 @@ class LCodeGen;
V(NumberTagD) \
V(NumberTagI) \
V(NumberUntagD) \
V(ObjectLiteral) \
V(ObjectLiteralFast) \
V(ObjectLiteralGeneric) \
V(OsrEntry) \
V(OuterContext) \
V(Parameter) \
@ -1899,10 +1900,17 @@ class LArrayLiteral: public LTemplateInstruction<1, 0, 0> {
};
class LObjectLiteral: public LTemplateInstruction<1, 0, 0> {
class LObjectLiteralFast: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ObjectLiteral, "object-literal")
DECLARE_HYDROGEN_ACCESSOR(ObjectLiteral)
DECLARE_CONCRETE_INSTRUCTION(ObjectLiteralFast, "object-literal-fast")
DECLARE_HYDROGEN_ACCESSOR(ObjectLiteralFast)
};
class LObjectLiteralGeneric: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ObjectLiteralGeneric, "object-literal-generic")
DECLARE_HYDROGEN_ACCESSOR(ObjectLiteralGeneric)
};