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:
parent
8acd4accac
commit
830f763b07
@ -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));
|
ASSERT(ToRegister(instr->result()).is(v0));
|
||||||
|
|
||||||
Handle<FixedArray> constant_properties =
|
Handle<FixedArray> constant_properties =
|
||||||
|
@ -316,6 +316,13 @@ class LCodeGen BASE_EMBEDDED {
|
|||||||
Handle<Map> type,
|
Handle<Map> type,
|
||||||
Handle<String> name);
|
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 {
|
struct JumpTableEntry {
|
||||||
explicit inline JumpTableEntry(Address entry)
|
explicit inline JumpTableEntry(Address entry)
|
||||||
: label(),
|
: label(),
|
||||||
|
@ -2071,8 +2071,14 @@ LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LInstruction* LChunkBuilder::DoObjectLiteral(HObjectLiteral* instr) {
|
LInstruction* LChunkBuilder::DoObjectLiteralFast(HObjectLiteralFast* instr) {
|
||||||
return MarkAsCall(DefineFixed(new LObjectLiteral, v0), instr);
|
return MarkAsCall(DefineFixed(new LObjectLiteralFast, v0), instr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LInstruction* LChunkBuilder::DoObjectLiteralGeneric(
|
||||||
|
HObjectLiteralGeneric* instr) {
|
||||||
|
return MarkAsCall(DefineFixed(new LObjectLiteralGeneric, v0), instr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -134,7 +134,8 @@ class LCodeGen;
|
|||||||
V(NumberTagD) \
|
V(NumberTagD) \
|
||||||
V(NumberTagI) \
|
V(NumberTagI) \
|
||||||
V(NumberUntagD) \
|
V(NumberUntagD) \
|
||||||
V(ObjectLiteral) \
|
V(ObjectLiteralFast) \
|
||||||
|
V(ObjectLiteralGeneric) \
|
||||||
V(OsrEntry) \
|
V(OsrEntry) \
|
||||||
V(OuterContext) \
|
V(OuterContext) \
|
||||||
V(Parameter) \
|
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:
|
public:
|
||||||
DECLARE_CONCRETE_INSTRUCTION(ObjectLiteral, "object-literal")
|
DECLARE_CONCRETE_INSTRUCTION(ObjectLiteralFast, "object-literal-fast")
|
||||||
DECLARE_HYDROGEN_ACCESSOR(ObjectLiteral)
|
DECLARE_HYDROGEN_ACCESSOR(ObjectLiteralFast)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class LObjectLiteralGeneric: public LTemplateInstruction<1, 0, 0> {
|
||||||
|
public:
|
||||||
|
DECLARE_CONCRETE_INSTRUCTION(ObjectLiteralGeneric, "object-literal-generic")
|
||||||
|
DECLARE_HYDROGEN_ACCESSOR(ObjectLiteralGeneric)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user