Implement fast literal support in Crankshaft.
This extends the current support for nested object literals we already have in Crankshaft, to also support nested array literals and mixed nested literals containing arrays and objects. All three types are generated by the unified HFastLiteral instruction. All previous upper bounds on nested literal graphs remain unchanged, keeping the size of generated code in check. The main intention is to boost performance of two-dimensional array literals containing constant elements (aka. matrices). R=danno@chromium.org TEST=mjsunit/compiler/literals-optimized Review URL: https://chromiumcodereview.appspot.com/9403018 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10734 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
15c368ce4c
commit
1dd2b094a5
@ -2093,19 +2093,18 @@ LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoFastLiteral(HFastLiteral* instr) {
|
||||
return MarkAsCall(DefineFixed(new LFastLiteral, r0), instr);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
|
||||
return MarkAsCall(DefineFixed(new LArrayLiteral, r0), instr);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoObjectLiteralFast(HObjectLiteralFast* instr) {
|
||||
return MarkAsCall(DefineFixed(new LObjectLiteralFast, r0), instr);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoObjectLiteralGeneric(
|
||||
HObjectLiteralGeneric* instr) {
|
||||
return MarkAsCall(DefineFixed(new LObjectLiteralGeneric, r0), instr);
|
||||
LInstruction* LChunkBuilder::DoObjectLiteral(HObjectLiteral* instr) {
|
||||
return MarkAsCall(DefineFixed(new LObjectLiteral, r0), instr);
|
||||
}
|
||||
|
||||
|
||||
|
@ -93,6 +93,7 @@ class LCodeGen;
|
||||
V(DivI) \
|
||||
V(DoubleToI) \
|
||||
V(ElementsKind) \
|
||||
V(FastLiteral) \
|
||||
V(FixedArrayBaseLength) \
|
||||
V(FunctionLiteral) \
|
||||
V(GetCachedArrayIndex) \
|
||||
@ -135,8 +136,7 @@ class LCodeGen;
|
||||
V(NumberTagD) \
|
||||
V(NumberTagI) \
|
||||
V(NumberUntagD) \
|
||||
V(ObjectLiteralFast) \
|
||||
V(ObjectLiteralGeneric) \
|
||||
V(ObjectLiteral) \
|
||||
V(OsrEntry) \
|
||||
V(OuterContext) \
|
||||
V(Parameter) \
|
||||
@ -1917,6 +1917,13 @@ class LClampTToUint8: public LTemplateInstruction<1, 1, 1> {
|
||||
};
|
||||
|
||||
|
||||
class LFastLiteral: public LTemplateInstruction<1, 0, 0> {
|
||||
public:
|
||||
DECLARE_CONCRETE_INSTRUCTION(FastLiteral, "fast-literal")
|
||||
DECLARE_HYDROGEN_ACCESSOR(FastLiteral)
|
||||
};
|
||||
|
||||
|
||||
class LArrayLiteral: public LTemplateInstruction<1, 0, 0> {
|
||||
public:
|
||||
DECLARE_CONCRETE_INSTRUCTION(ArrayLiteral, "array-literal")
|
||||
@ -1924,17 +1931,10 @@ class LArrayLiteral: public LTemplateInstruction<1, 0, 0> {
|
||||
};
|
||||
|
||||
|
||||
class LObjectLiteralFast: public LTemplateInstruction<1, 0, 0> {
|
||||
class LObjectLiteral: public LTemplateInstruction<1, 0, 0> {
|
||||
public:
|
||||
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)
|
||||
DECLARE_CONCRETE_INSTRUCTION(ObjectLiteral, "object-literal")
|
||||
DECLARE_HYDROGEN_ACCESSOR(ObjectLiteral)
|
||||
};
|
||||
|
||||
|
||||
|
@ -4380,26 +4380,35 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
|
||||
ASSERT(!source.is(r2));
|
||||
ASSERT(!result.is(r2));
|
||||
|
||||
// Only elements backing stores for non-COW arrays need to be copied.
|
||||
Handle<FixedArrayBase> elements(object->elements());
|
||||
bool has_elements = elements->length() > 0 &&
|
||||
elements->map() != isolate()->heap()->fixed_cow_array_map();
|
||||
|
||||
// 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;
|
||||
// this object and its backing store.
|
||||
int object_offset = *offset;
|
||||
int object_size = object->map()->instance_size();
|
||||
int elements_offset = *offset + object_size;
|
||||
int elements_size = has_elements ? elements->Size() : 0;
|
||||
*offset += object_size + elements_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;
|
||||
int header_size = object_size - inobject_properties * kPointerSize;
|
||||
for (int i = 0; i < header_size; i += kPointerSize) {
|
||||
__ ldr(r2, FieldMemOperand(source, i));
|
||||
__ str(r2, FieldMemOperand(result, current_offset + i));
|
||||
if (has_elements && i == JSObject::kElementsOffset) {
|
||||
__ add(r2, result, Operand(elements_offset));
|
||||
} else {
|
||||
__ ldr(r2, FieldMemOperand(source, i));
|
||||
}
|
||||
__ str(r2, FieldMemOperand(result, object_offset + i));
|
||||
}
|
||||
|
||||
// Copy in-object properties.
|
||||
for (int i = 0; i < inobject_properties; i++) {
|
||||
int total_offset = current_offset + object->GetInObjectPropertyOffset(i);
|
||||
int total_offset = object_offset + object->GetInObjectPropertyOffset(i);
|
||||
Handle<Object> value = Handle<Object>(object->InObjectPropertyAt(i));
|
||||
if (value->IsJSObject()) {
|
||||
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
|
||||
@ -4415,10 +4424,41 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
|
||||
__ str(r2, FieldMemOperand(result, total_offset));
|
||||
}
|
||||
}
|
||||
|
||||
// Copy elements backing store header.
|
||||
ASSERT(!has_elements || elements->IsFixedArray());
|
||||
if (has_elements) {
|
||||
__ LoadHeapObject(source, elements);
|
||||
for (int i = 0; i < FixedArray::kHeaderSize; i += kPointerSize) {
|
||||
__ ldr(r2, FieldMemOperand(source, i));
|
||||
__ str(r2, FieldMemOperand(result, elements_offset + i));
|
||||
}
|
||||
}
|
||||
|
||||
// Copy elements backing store content.
|
||||
ASSERT(!has_elements || elements->IsFixedArray());
|
||||
int elements_length = has_elements ? elements->length() : 0;
|
||||
for (int i = 0; i < elements_length; i++) {
|
||||
int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i);
|
||||
Handle<Object> value = JSObject::GetElement(object, i);
|
||||
if (value->IsJSObject()) {
|
||||
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
|
||||
__ add(r2, result, Operand(*offset));
|
||||
__ str(r2, FieldMemOperand(result, total_offset));
|
||||
__ LoadHeapObject(source, value_object);
|
||||
EmitDeepCopy(value_object, result, source, offset);
|
||||
} else if (value->IsHeapObject()) {
|
||||
__ LoadHeapObject(r2, Handle<HeapObject>::cast(value));
|
||||
__ str(r2, FieldMemOperand(result, total_offset));
|
||||
} else {
|
||||
__ mov(r2, Operand(value));
|
||||
__ str(r2, FieldMemOperand(result, total_offset));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoObjectLiteralFast(LObjectLiteralFast* instr) {
|
||||
void LCodeGen::DoFastLiteral(LFastLiteral* instr) {
|
||||
int size = instr->hydrogen()->total_size();
|
||||
|
||||
// Allocate all objects that are part of the literal in one big
|
||||
@ -4440,7 +4480,7 @@ void LCodeGen::DoObjectLiteralFast(LObjectLiteralFast* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoObjectLiteralGeneric(LObjectLiteralGeneric* instr) {
|
||||
void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
|
||||
Handle<FixedArray> literals(instr->environment()->closure()->literals());
|
||||
Handle<FixedArray> constant_properties =
|
||||
instr->hydrogen()->constant_properties();
|
||||
|
@ -1841,17 +1841,18 @@ HType HStringCharFromCode::CalculateInferredType() {
|
||||
}
|
||||
|
||||
|
||||
HType HFastLiteral::CalculateInferredType() {
|
||||
// TODO(mstarzinger): Be smarter, could also be JSArray here.
|
||||
return HType::JSObject();
|
||||
}
|
||||
|
||||
|
||||
HType HArrayLiteral::CalculateInferredType() {
|
||||
return HType::JSArray();
|
||||
}
|
||||
|
||||
|
||||
HType HObjectLiteralFast::CalculateInferredType() {
|
||||
return HType::JSObject();
|
||||
}
|
||||
|
||||
|
||||
HType HObjectLiteralGeneric::CalculateInferredType() {
|
||||
HType HObjectLiteral::CalculateInferredType() {
|
||||
return HType::JSObject();
|
||||
}
|
||||
|
||||
|
@ -103,6 +103,7 @@ class LChunkBuilder;
|
||||
V(Div) \
|
||||
V(ElementsKind) \
|
||||
V(EnterInlined) \
|
||||
V(FastLiteral) \
|
||||
V(FixedArrayBaseLength) \
|
||||
V(ForceRepresentation) \
|
||||
V(FunctionLiteral) \
|
||||
@ -140,8 +141,7 @@ class LChunkBuilder;
|
||||
V(LoadNamedGeneric) \
|
||||
V(Mod) \
|
||||
V(Mul) \
|
||||
V(ObjectLiteralFast) \
|
||||
V(ObjectLiteralGeneric) \
|
||||
V(ObjectLiteral) \
|
||||
V(OsrEntry) \
|
||||
V(OuterContext) \
|
||||
V(Parameter) \
|
||||
@ -4348,6 +4348,41 @@ class HMaterializedLiteral: public HTemplateInstruction<V> {
|
||||
};
|
||||
|
||||
|
||||
class HFastLiteral: public HMaterializedLiteral<1> {
|
||||
public:
|
||||
HFastLiteral(HValue* context,
|
||||
Handle<JSObject> boilerplate,
|
||||
int total_size,
|
||||
int literal_index,
|
||||
int depth)
|
||||
: HMaterializedLiteral<1>(literal_index, depth),
|
||||
boilerplate_(boilerplate),
|
||||
total_size_(total_size) {
|
||||
SetOperandAt(0, context);
|
||||
}
|
||||
|
||||
// Maximum depth and total number of elements and properties for literal
|
||||
// graphs to be considered for fast deep-copying.
|
||||
static const int kMaxLiteralDepth = 3;
|
||||
static const int kMaxLiteralProperties = 8;
|
||||
|
||||
HValue* context() { return OperandAt(0); }
|
||||
Handle<JSObject> boilerplate() const { return boilerplate_; }
|
||||
int total_size() const { return total_size_; }
|
||||
|
||||
virtual Representation RequiredInputRepresentation(int index) {
|
||||
return Representation::Tagged();
|
||||
}
|
||||
virtual HType CalculateInferredType();
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(FastLiteral)
|
||||
|
||||
private:
|
||||
Handle<JSObject> boilerplate_;
|
||||
int total_size_;
|
||||
};
|
||||
|
||||
|
||||
class HArrayLiteral: public HMaterializedLiteral<1> {
|
||||
public:
|
||||
HArrayLiteral(HValue* context,
|
||||
@ -4386,49 +4421,14 @@ class HArrayLiteral: public HMaterializedLiteral<1> {
|
||||
};
|
||||
|
||||
|
||||
class HObjectLiteralFast: public HMaterializedLiteral<1> {
|
||||
class HObjectLiteral: public HMaterializedLiteral<1> {
|
||||
public:
|
||||
HObjectLiteralFast(HValue* context,
|
||||
Handle<JSObject> boilerplate,
|
||||
int total_size,
|
||||
int literal_index,
|
||||
int depth)
|
||||
: HMaterializedLiteral<1>(literal_index, depth),
|
||||
boilerplate_(boilerplate),
|
||||
total_size_(total_size) {
|
||||
SetOperandAt(0, context);
|
||||
}
|
||||
|
||||
// Maximum depth and total number of properties for object literal
|
||||
// graphs to be considered for fast deep-copying.
|
||||
static const int kMaxObjectLiteralDepth = 3;
|
||||
static const int kMaxObjectLiteralProperties = 8;
|
||||
|
||||
HValue* context() { return OperandAt(0); }
|
||||
Handle<JSObject> boilerplate() const { return boilerplate_; }
|
||||
int total_size() const { return total_size_; }
|
||||
|
||||
virtual Representation RequiredInputRepresentation(int index) {
|
||||
return Representation::Tagged();
|
||||
}
|
||||
virtual HType CalculateInferredType();
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(ObjectLiteralFast)
|
||||
|
||||
private:
|
||||
Handle<JSObject> boilerplate_;
|
||||
int total_size_;
|
||||
};
|
||||
|
||||
|
||||
class HObjectLiteralGeneric: public HMaterializedLiteral<1> {
|
||||
public:
|
||||
HObjectLiteralGeneric(HValue* context,
|
||||
Handle<FixedArray> constant_properties,
|
||||
bool fast_elements,
|
||||
int literal_index,
|
||||
int depth,
|
||||
bool has_function)
|
||||
HObjectLiteral(HValue* context,
|
||||
Handle<FixedArray> constant_properties,
|
||||
bool fast_elements,
|
||||
int literal_index,
|
||||
int depth,
|
||||
bool has_function)
|
||||
: HMaterializedLiteral<1>(literal_index, depth),
|
||||
constant_properties_(constant_properties),
|
||||
fast_elements_(fast_elements),
|
||||
@ -4448,7 +4448,7 @@ class HObjectLiteralGeneric: public HMaterializedLiteral<1> {
|
||||
}
|
||||
virtual HType CalculateInferredType();
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(ObjectLiteralGeneric)
|
||||
DECLARE_CONCRETE_INSTRUCTION(ObjectLiteral)
|
||||
|
||||
private:
|
||||
Handle<FixedArray> constant_properties_;
|
||||
@ -4543,7 +4543,7 @@ class HToFastProperties: public HUnaryOperation {
|
||||
// This instruction is not marked as having side effects, but
|
||||
// changes the map of the input operand. Use it only when creating
|
||||
// object literals.
|
||||
ASSERT(value->IsObjectLiteralGeneric() || value->IsObjectLiteralFast());
|
||||
ASSERT(value->IsObjectLiteral() || value->IsFastLiteral());
|
||||
set_representation(Representation::Tagged());
|
||||
}
|
||||
|
||||
|
102
src/hydrogen.cc
102
src/hydrogen.cc
@ -3458,19 +3458,35 @@ void HGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
|
||||
}
|
||||
|
||||
|
||||
// Determines whether the given object literal boilerplate satisfies all
|
||||
// limits to be considered for fast deep-copying and computes the total
|
||||
// Determines whether the given array or object literal boilerplate satisfies
|
||||
// all limits to be considered for fast deep-copying and computes the total
|
||||
// size of all objects that are part of the graph.
|
||||
static bool IsFastObjectLiteral(Handle<JSObject> boilerplate,
|
||||
int max_depth,
|
||||
int* max_properties,
|
||||
int* total_size) {
|
||||
if (max_depth <= 0) return false;
|
||||
static bool IsFastLiteral(Handle<JSObject> boilerplate,
|
||||
int max_depth,
|
||||
int* max_properties,
|
||||
int* total_size) {
|
||||
ASSERT(max_depth >= 0 && *max_properties >= 0);
|
||||
if (max_depth == 0) return false;
|
||||
|
||||
Handle<FixedArrayBase> elements(boilerplate->elements());
|
||||
if (elements->length() > 0 &&
|
||||
elements->map() != HEAP->fixed_cow_array_map()) {
|
||||
return false;
|
||||
elements->map() != boilerplate->GetHeap()->fixed_cow_array_map()) {
|
||||
if (!boilerplate->HasFastElements()) return false;
|
||||
int length = elements->length();
|
||||
for (int i = 0; i < length; i++) {
|
||||
if ((*max_properties)-- == 0) return false;
|
||||
Handle<Object> value = JSObject::GetElement(boilerplate, i);
|
||||
if (value->IsJSObject()) {
|
||||
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
|
||||
if (!IsFastLiteral(value_object,
|
||||
max_depth - 1,
|
||||
max_properties,
|
||||
total_size)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
*total_size += FixedArray::SizeFor(length);
|
||||
}
|
||||
|
||||
Handle<FixedArray> properties(boilerplate->properties());
|
||||
@ -3479,14 +3495,14 @@ static bool IsFastObjectLiteral(Handle<JSObject> boilerplate,
|
||||
} else {
|
||||
int nof = boilerplate->map()->inobject_properties();
|
||||
for (int i = 0; i < nof; i++) {
|
||||
if ((*max_properties)-- <= 0) return false;
|
||||
if ((*max_properties)-- == 0) return false;
|
||||
Handle<Object> value(boilerplate->InObjectPropertyAt(i));
|
||||
if (value->IsJSObject()) {
|
||||
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
|
||||
if (!IsFastObjectLiteral(value_object,
|
||||
max_depth - 1,
|
||||
max_properties,
|
||||
total_size)) {
|
||||
if (!IsFastLiteral(value_object,
|
||||
max_depth - 1,
|
||||
max_properties,
|
||||
total_size)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -3508,26 +3524,26 @@ void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
|
||||
|
||||
// Check whether to use fast or slow deep-copying for boilerplate.
|
||||
int total_size = 0;
|
||||
int max_properties = HObjectLiteralFast::kMaxObjectLiteralProperties;
|
||||
int max_properties = HFastLiteral::kMaxLiteralProperties;
|
||||
Handle<Object> boilerplate(closure->literals()->get(expr->literal_index()));
|
||||
if (boilerplate->IsJSObject() &&
|
||||
IsFastObjectLiteral(Handle<JSObject>::cast(boilerplate),
|
||||
HObjectLiteralFast::kMaxObjectLiteralDepth,
|
||||
&max_properties,
|
||||
&total_size)) {
|
||||
IsFastLiteral(Handle<JSObject>::cast(boilerplate),
|
||||
HFastLiteral::kMaxLiteralDepth,
|
||||
&max_properties,
|
||||
&total_size)) {
|
||||
Handle<JSObject> boilerplate_object = Handle<JSObject>::cast(boilerplate);
|
||||
literal = new(zone()) HObjectLiteralFast(context,
|
||||
boilerplate_object,
|
||||
total_size,
|
||||
expr->literal_index(),
|
||||
expr->depth());
|
||||
literal = new(zone()) HFastLiteral(context,
|
||||
boilerplate_object,
|
||||
total_size,
|
||||
expr->literal_index(),
|
||||
expr->depth());
|
||||
} else {
|
||||
literal = new(zone()) HObjectLiteralGeneric(context,
|
||||
expr->constant_properties(),
|
||||
expr->fast_elements(),
|
||||
expr->literal_index(),
|
||||
expr->depth(),
|
||||
expr->has_function());
|
||||
literal = new(zone()) HObjectLiteral(context,
|
||||
expr->constant_properties(),
|
||||
expr->fast_elements(),
|
||||
expr->literal_index(),
|
||||
expr->depth(),
|
||||
expr->has_function());
|
||||
}
|
||||
|
||||
// The object is expected in the bailout environment during computation
|
||||
@ -3598,6 +3614,7 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
ZoneList<Expression*>* subexprs = expr->values();
|
||||
int length = subexprs->length();
|
||||
HValue* context = environment()->LookupContext();
|
||||
HInstruction* literal;
|
||||
|
||||
Handle<FixedArray> literals(environment()->closure()->literals());
|
||||
Handle<Object> raw_boilerplate(literals->get(expr->literal_index()));
|
||||
@ -3619,12 +3636,25 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
ElementsKind boilerplate_elements_kind =
|
||||
Handle<JSObject>::cast(boilerplate)->GetElementsKind();
|
||||
|
||||
HArrayLiteral* literal = new(zone()) HArrayLiteral(
|
||||
context,
|
||||
boilerplate,
|
||||
length,
|
||||
expr->literal_index(),
|
||||
expr->depth());
|
||||
// Check whether to use fast or slow deep-copying for boilerplate.
|
||||
int total_size = 0;
|
||||
int max_properties = HFastLiteral::kMaxLiteralProperties;
|
||||
if (IsFastLiteral(boilerplate,
|
||||
HFastLiteral::kMaxLiteralDepth,
|
||||
&max_properties,
|
||||
&total_size)) {
|
||||
literal = new(zone()) HFastLiteral(context,
|
||||
boilerplate,
|
||||
total_size,
|
||||
expr->literal_index(),
|
||||
expr->depth());
|
||||
} else {
|
||||
literal = new(zone()) HArrayLiteral(context,
|
||||
boilerplate,
|
||||
length,
|
||||
expr->literal_index(),
|
||||
expr->depth());
|
||||
}
|
||||
|
||||
// The array is expected in the bailout environment during computation
|
||||
// of the property values and is the value of the entire expression.
|
||||
|
@ -4259,26 +4259,35 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
|
||||
__ Assert(equal, "Unexpected object literal boilerplate");
|
||||
}
|
||||
|
||||
// Only elements backing stores for non-COW arrays need to be copied.
|
||||
Handle<FixedArrayBase> elements(object->elements());
|
||||
bool has_elements = elements->length() > 0 &&
|
||||
elements->map() != isolate()->heap()->fixed_cow_array_map();
|
||||
|
||||
// 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;
|
||||
// this object and its backing store.
|
||||
int object_offset = *offset;
|
||||
int object_size = object->map()->instance_size();
|
||||
int elements_offset = *offset + object_size;
|
||||
int elements_size = has_elements ? elements->Size() : 0;
|
||||
*offset += object_size + elements_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;
|
||||
int header_size = object_size - inobject_properties * kPointerSize;
|
||||
for (int i = 0; i < header_size; i += kPointerSize) {
|
||||
__ mov(ecx, FieldOperand(source, i));
|
||||
__ mov(FieldOperand(result, current_offset + i), ecx);
|
||||
if (has_elements && i == JSObject::kElementsOffset) {
|
||||
__ lea(ecx, Operand(result, elements_offset));
|
||||
} else {
|
||||
__ mov(ecx, FieldOperand(source, i));
|
||||
}
|
||||
__ mov(FieldOperand(result, object_offset + i), ecx);
|
||||
}
|
||||
|
||||
// Copy in-object properties.
|
||||
for (int i = 0; i < inobject_properties; i++) {
|
||||
int total_offset = current_offset + object->GetInObjectPropertyOffset(i);
|
||||
int total_offset = object_offset + object->GetInObjectPropertyOffset(i);
|
||||
Handle<Object> value = Handle<Object>(object->InObjectPropertyAt(i));
|
||||
if (value->IsJSObject()) {
|
||||
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
|
||||
@ -4293,10 +4302,40 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
|
||||
__ mov(FieldOperand(result, total_offset), Immediate(value));
|
||||
}
|
||||
}
|
||||
|
||||
// Copy elements backing store header.
|
||||
ASSERT(!has_elements || elements->IsFixedArray());
|
||||
if (has_elements) {
|
||||
__ LoadHeapObject(source, elements);
|
||||
for (int i = 0; i < FixedArray::kHeaderSize; i += kPointerSize) {
|
||||
__ mov(ecx, FieldOperand(source, i));
|
||||
__ mov(FieldOperand(result, elements_offset + i), ecx);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy elements backing store content.
|
||||
ASSERT(!has_elements || elements->IsFixedArray());
|
||||
int elements_length = has_elements ? elements->length() : 0;
|
||||
for (int i = 0; i < elements_length; i++) {
|
||||
int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i);
|
||||
Handle<Object> value = JSObject::GetElement(object, i);
|
||||
if (value->IsJSObject()) {
|
||||
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
|
||||
__ lea(ecx, Operand(result, *offset));
|
||||
__ mov(FieldOperand(result, total_offset), ecx);
|
||||
__ LoadHeapObject(source, value_object);
|
||||
EmitDeepCopy(value_object, result, source, offset);
|
||||
} else if (value->IsHeapObject()) {
|
||||
__ LoadHeapObject(ecx, Handle<HeapObject>::cast(value));
|
||||
__ mov(FieldOperand(result, total_offset), ecx);
|
||||
} else {
|
||||
__ mov(FieldOperand(result, total_offset), Immediate(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoObjectLiteralFast(LObjectLiteralFast* instr) {
|
||||
void LCodeGen::DoFastLiteral(LFastLiteral* instr) {
|
||||
ASSERT(ToRegister(instr->context()).is(esi));
|
||||
int size = instr->hydrogen()->total_size();
|
||||
|
||||
@ -4318,7 +4357,7 @@ void LCodeGen::DoObjectLiteralFast(LObjectLiteralFast* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoObjectLiteralGeneric(LObjectLiteralGeneric* instr) {
|
||||
void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
|
||||
ASSERT(ToRegister(instr->context()).is(esi));
|
||||
Handle<FixedArray> literals(instr->environment()->closure()->literals());
|
||||
Handle<FixedArray> constant_properties =
|
||||
|
@ -2212,6 +2212,13 @@ LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoFastLiteral(HFastLiteral* instr) {
|
||||
LOperand* context = UseFixed(instr->context(), esi);
|
||||
return MarkAsCall(
|
||||
DefineFixed(new(zone()) LFastLiteral(context), eax), instr);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
|
||||
LOperand* context = UseFixed(instr->context(), esi);
|
||||
return MarkAsCall(
|
||||
@ -2219,18 +2226,10 @@ LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoObjectLiteralFast(HObjectLiteralFast* instr) {
|
||||
LInstruction* LChunkBuilder::DoObjectLiteral(HObjectLiteral* instr) {
|
||||
LOperand* context = UseFixed(instr->context(), esi);
|
||||
return MarkAsCall(
|
||||
DefineFixed(new(zone()) LObjectLiteralFast(context), eax), instr);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoObjectLiteralGeneric(
|
||||
HObjectLiteralGeneric* instr) {
|
||||
LOperand* context = UseFixed(instr->context(), esi);
|
||||
return MarkAsCall(
|
||||
DefineFixed(new(zone()) LObjectLiteralGeneric(context), eax), instr);
|
||||
DefineFixed(new(zone()) LObjectLiteral(context), eax), instr);
|
||||
}
|
||||
|
||||
|
||||
|
@ -87,6 +87,7 @@ class LCodeGen;
|
||||
V(DivI) \
|
||||
V(DoubleToI) \
|
||||
V(ElementsKind) \
|
||||
V(FastLiteral) \
|
||||
V(FixedArrayBaseLength) \
|
||||
V(FunctionLiteral) \
|
||||
V(GetCachedArrayIndex) \
|
||||
@ -130,8 +131,7 @@ class LCodeGen;
|
||||
V(NumberTagD) \
|
||||
V(NumberTagI) \
|
||||
V(NumberUntagD) \
|
||||
V(ObjectLiteralFast) \
|
||||
V(ObjectLiteralGeneric) \
|
||||
V(ObjectLiteral) \
|
||||
V(OsrEntry) \
|
||||
V(OuterContext) \
|
||||
V(Parameter) \
|
||||
@ -1991,6 +1991,19 @@ class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> {
|
||||
};
|
||||
|
||||
|
||||
class LFastLiteral: public LTemplateInstruction<1, 1, 0> {
|
||||
public:
|
||||
explicit LFastLiteral(LOperand* context) {
|
||||
inputs_[0] = context;
|
||||
}
|
||||
|
||||
LOperand* context() { return inputs_[0]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(FastLiteral, "fast-literal")
|
||||
DECLARE_HYDROGEN_ACCESSOR(FastLiteral)
|
||||
};
|
||||
|
||||
|
||||
class LArrayLiteral: public LTemplateInstruction<1, 1, 0> {
|
||||
public:
|
||||
explicit LArrayLiteral(LOperand* context) {
|
||||
@ -2004,29 +2017,16 @@ class LArrayLiteral: public LTemplateInstruction<1, 1, 0> {
|
||||
};
|
||||
|
||||
|
||||
class LObjectLiteralFast: public LTemplateInstruction<1, 1, 0> {
|
||||
class LObjectLiteral: public LTemplateInstruction<1, 1, 0> {
|
||||
public:
|
||||
explicit LObjectLiteralFast(LOperand* context) {
|
||||
explicit LObjectLiteral(LOperand* context) {
|
||||
inputs_[0] = context;
|
||||
}
|
||||
|
||||
LOperand* context() { return inputs_[0]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(ObjectLiteralFast, "object-literal-fast")
|
||||
DECLARE_HYDROGEN_ACCESSOR(ObjectLiteralFast)
|
||||
};
|
||||
|
||||
|
||||
class LObjectLiteralGeneric: public LTemplateInstruction<1, 1, 0> {
|
||||
public:
|
||||
explicit LObjectLiteralGeneric(LOperand* context) {
|
||||
inputs_[0] = context;
|
||||
}
|
||||
|
||||
LOperand* context() { return inputs_[0]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(ObjectLiteralGeneric, "object-literal-generic")
|
||||
DECLARE_HYDROGEN_ACCESSOR(ObjectLiteralGeneric)
|
||||
DECLARE_CONCRETE_INSTRUCTION(ObjectLiteral, "object-literal")
|
||||
DECLARE_HYDROGEN_ACCESSOR(ObjectLiteral)
|
||||
};
|
||||
|
||||
|
||||
|
@ -4272,26 +4272,35 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
|
||||
ASSERT(!source.is(a2));
|
||||
ASSERT(!result.is(a2));
|
||||
|
||||
// Only elements backing stores for non-COW arrays need to be copied.
|
||||
Handle<FixedArrayBase> elements(object->elements());
|
||||
bool has_elements = elements->length() > 0 &&
|
||||
elements->map() != isolate()->heap()->fixed_cow_array_map();
|
||||
|
||||
// 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;
|
||||
// this object and its backing store.
|
||||
int object_offset = *offset;
|
||||
int object_size = object->map()->instance_size();
|
||||
int elements_offset = *offset + object_size;
|
||||
int elements_size = has_elements ? elements->Size() : 0;
|
||||
*offset += object_size + elements_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;
|
||||
int header_size = object_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));
|
||||
if (has_elements && i == JSObject::kElementsOffset) {
|
||||
__ Addu(a2, result, Operand(elements_offset));
|
||||
} else {
|
||||
__ lw(a2, FieldMemOperand(source, i));
|
||||
}
|
||||
__ sw(a2, FieldMemOperand(result, object_offset + i));
|
||||
}
|
||||
|
||||
// Copy in-object properties.
|
||||
for (int i = 0; i < inobject_properties; i++) {
|
||||
int total_offset = current_offset + object->GetInObjectPropertyOffset(i);
|
||||
int total_offset = object_offset + object->GetInObjectPropertyOffset(i);
|
||||
Handle<Object> value = Handle<Object>(object->InObjectPropertyAt(i));
|
||||
if (value->IsJSObject()) {
|
||||
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
|
||||
@ -4307,10 +4316,42 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
|
||||
__ sw(a2, FieldMemOperand(result, total_offset));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Copy elements backing store header.
|
||||
ASSERT(!has_elements || elements->IsFixedArray());
|
||||
if (has_elements) {
|
||||
__ LoadHeapObject(source, elements);
|
||||
for (int i = 0; i < FixedArray::kHeaderSize; i += kPointerSize) {
|
||||
__ lw(a2, FieldMemOperand(source, i));
|
||||
__ sw(a2, FieldMemOperand(result, elements_offset + i));
|
||||
}
|
||||
}
|
||||
|
||||
// Copy elements backing store content.
|
||||
ASSERT(!has_elements || elements->IsFixedArray());
|
||||
int elements_length = has_elements ? elements->length() : 0;
|
||||
for (int i = 0; i < elements_length; i++) {
|
||||
int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i);
|
||||
Handle<Object> value = JSObject::GetElement(object, 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) {
|
||||
void LCodeGen::DoFastLiteral(LFastLiteral* instr) {
|
||||
int size = instr->hydrogen()->total_size();
|
||||
|
||||
// Allocate all objects that are part of the literal in one big
|
||||
@ -4332,7 +4373,7 @@ void LCodeGen::DoObjectLiteralFast(LObjectLiteralFast* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoObjectLiteralGeneric(LObjectLiteralGeneric* instr) {
|
||||
void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
|
||||
ASSERT(ToRegister(instr->result()).is(v0));
|
||||
Handle<FixedArray> literals(instr->environment()->closure()->literals());
|
||||
Handle<FixedArray> constant_properties =
|
||||
|
@ -2093,19 +2093,18 @@ LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoFastLiteral(HFastLiteral* instr) {
|
||||
return MarkAsCall(DefineFixed(new LFastLiteral, v0), instr);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
|
||||
return MarkAsCall(DefineFixed(new LArrayLiteral, 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);
|
||||
LInstruction* LChunkBuilder::DoObjectLiteral(HObjectLiteral* instr) {
|
||||
return MarkAsCall(DefineFixed(new LObjectLiteral, v0), instr);
|
||||
}
|
||||
|
||||
|
||||
|
@ -92,6 +92,7 @@ class LCodeGen;
|
||||
V(DivI) \
|
||||
V(DoubleToI) \
|
||||
V(ElementsKind) \
|
||||
V(FastLiteral) \
|
||||
V(FixedArrayBaseLength) \
|
||||
V(FunctionLiteral) \
|
||||
V(GetCachedArrayIndex) \
|
||||
@ -134,8 +135,7 @@ class LCodeGen;
|
||||
V(NumberTagD) \
|
||||
V(NumberTagI) \
|
||||
V(NumberUntagD) \
|
||||
V(ObjectLiteralFast) \
|
||||
V(ObjectLiteralGeneric) \
|
||||
V(ObjectLiteral) \
|
||||
V(OsrEntry) \
|
||||
V(OuterContext) \
|
||||
V(Parameter) \
|
||||
@ -1909,6 +1909,13 @@ class LClampTToUint8: public LTemplateInstruction<1, 1, 1> {
|
||||
};
|
||||
|
||||
|
||||
class LFastLiteral: public LTemplateInstruction<1, 0, 0> {
|
||||
public:
|
||||
DECLARE_CONCRETE_INSTRUCTION(FastLiteral, "fast-literal")
|
||||
DECLARE_HYDROGEN_ACCESSOR(FastLiteral)
|
||||
};
|
||||
|
||||
|
||||
class LArrayLiteral: public LTemplateInstruction<1, 0, 0> {
|
||||
public:
|
||||
DECLARE_CONCRETE_INSTRUCTION(ArrayLiteral, "array-literal")
|
||||
@ -1916,17 +1923,10 @@ class LArrayLiteral: public LTemplateInstruction<1, 0, 0> {
|
||||
};
|
||||
|
||||
|
||||
class LObjectLiteralFast: public LTemplateInstruction<1, 0, 0> {
|
||||
class LObjectLiteral: public LTemplateInstruction<1, 0, 0> {
|
||||
public:
|
||||
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)
|
||||
DECLARE_CONCRETE_INSTRUCTION(ObjectLiteral, "object-literal")
|
||||
DECLARE_HYDROGEN_ACCESSOR(ObjectLiteral)
|
||||
};
|
||||
|
||||
|
||||
|
@ -3975,26 +3975,35 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
|
||||
ASSERT(!source.is(rcx));
|
||||
ASSERT(!result.is(rcx));
|
||||
|
||||
// Only elements backing stores for non-COW arrays need to be copied.
|
||||
Handle<FixedArrayBase> elements(object->elements());
|
||||
bool has_elements = elements->length() > 0 &&
|
||||
elements->map() != isolate()->heap()->fixed_cow_array_map();
|
||||
|
||||
// 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;
|
||||
// this object and its backing store.
|
||||
int object_offset = *offset;
|
||||
int object_size = object->map()->instance_size();
|
||||
int elements_offset = *offset + object_size;
|
||||
int elements_size = has_elements ? elements->Size() : 0;
|
||||
*offset += object_size + elements_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;
|
||||
int header_size = object_size - inobject_properties * kPointerSize;
|
||||
for (int i = 0; i < header_size; i += kPointerSize) {
|
||||
__ movq(rcx, FieldOperand(source, i));
|
||||
__ movq(FieldOperand(result, current_offset + i), rcx);
|
||||
if (has_elements && i == JSObject::kElementsOffset) {
|
||||
__ lea(rcx, Operand(result, elements_offset));
|
||||
} else {
|
||||
__ movq(rcx, FieldOperand(source, i));
|
||||
}
|
||||
__ movq(FieldOperand(result, object_offset + i), rcx);
|
||||
}
|
||||
|
||||
// Copy in-object properties.
|
||||
for (int i = 0; i < inobject_properties; i++) {
|
||||
int total_offset = current_offset + object->GetInObjectPropertyOffset(i);
|
||||
int total_offset = object_offset + object->GetInObjectPropertyOffset(i);
|
||||
Handle<Object> value = Handle<Object>(object->InObjectPropertyAt(i));
|
||||
if (value->IsJSObject()) {
|
||||
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
|
||||
@ -4010,10 +4019,41 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
|
||||
__ movq(FieldOperand(result, total_offset), rcx);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy elements backing store header.
|
||||
ASSERT(!has_elements || elements->IsFixedArray());
|
||||
if (has_elements) {
|
||||
__ LoadHeapObject(source, elements);
|
||||
for (int i = 0; i < FixedArray::kHeaderSize; i += kPointerSize) {
|
||||
__ movq(rcx, FieldOperand(source, i));
|
||||
__ movq(FieldOperand(result, elements_offset + i), rcx);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy elements backing store content.
|
||||
ASSERT(!has_elements || elements->IsFixedArray());
|
||||
int elements_length = has_elements ? elements->length() : 0;
|
||||
for (int i = 0; i < elements_length; i++) {
|
||||
int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i);
|
||||
Handle<Object> value = JSObject::GetElement(object, i);
|
||||
if (value->IsJSObject()) {
|
||||
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
|
||||
__ lea(rcx, Operand(result, *offset));
|
||||
__ movq(FieldOperand(result, total_offset), rcx);
|
||||
__ LoadHeapObject(source, value_object);
|
||||
EmitDeepCopy(value_object, result, source, offset);
|
||||
} else if (value->IsHeapObject()) {
|
||||
__ LoadHeapObject(rcx, Handle<HeapObject>::cast(value));
|
||||
__ movq(FieldOperand(result, total_offset), rcx);
|
||||
} else {
|
||||
__ movq(rcx, value, RelocInfo::NONE);
|
||||
__ movq(FieldOperand(result, total_offset), rcx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoObjectLiteralFast(LObjectLiteralFast* instr) {
|
||||
void LCodeGen::DoFastLiteral(LFastLiteral* instr) {
|
||||
int size = instr->hydrogen()->total_size();
|
||||
|
||||
// Allocate all objects that are part of the literal in one big
|
||||
@ -4034,7 +4074,7 @@ void LCodeGen::DoObjectLiteralFast(LObjectLiteralFast* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoObjectLiteralGeneric(LObjectLiteralGeneric* instr) {
|
||||
void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
|
||||
Handle<FixedArray> literals(instr->environment()->closure()->literals());
|
||||
Handle<FixedArray> constant_properties =
|
||||
instr->hydrogen()->constant_properties();
|
||||
|
@ -2094,19 +2094,18 @@ LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoFastLiteral(HFastLiteral* instr) {
|
||||
return MarkAsCall(DefineFixed(new LFastLiteral, rax), instr);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
|
||||
return MarkAsCall(DefineFixed(new LArrayLiteral, rax), instr);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoObjectLiteralFast(HObjectLiteralFast* instr) {
|
||||
return MarkAsCall(DefineFixed(new LObjectLiteralFast, rax), instr);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoObjectLiteralGeneric(
|
||||
HObjectLiteralGeneric* instr) {
|
||||
return MarkAsCall(DefineFixed(new LObjectLiteralGeneric, rax), instr);
|
||||
LInstruction* LChunkBuilder::DoObjectLiteral(HObjectLiteral* instr) {
|
||||
return MarkAsCall(DefineFixed(new LObjectLiteral, rax), instr);
|
||||
}
|
||||
|
||||
|
||||
|
@ -93,6 +93,7 @@ class LCodeGen;
|
||||
V(DivI) \
|
||||
V(DoubleToI) \
|
||||
V(ElementsKind) \
|
||||
V(FastLiteral) \
|
||||
V(FixedArrayBaseLength) \
|
||||
V(FunctionLiteral) \
|
||||
V(GetCachedArrayIndex) \
|
||||
@ -135,8 +136,7 @@ class LCodeGen;
|
||||
V(NumberTagD) \
|
||||
V(NumberTagI) \
|
||||
V(NumberUntagD) \
|
||||
V(ObjectLiteralFast) \
|
||||
V(ObjectLiteralGeneric) \
|
||||
V(ObjectLiteral) \
|
||||
V(OsrEntry) \
|
||||
V(OuterContext) \
|
||||
V(Parameter) \
|
||||
@ -1906,6 +1906,13 @@ class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> {
|
||||
};
|
||||
|
||||
|
||||
class LFastLiteral: public LTemplateInstruction<1, 0, 0> {
|
||||
public:
|
||||
DECLARE_CONCRETE_INSTRUCTION(FastLiteral, "fast-literal")
|
||||
DECLARE_HYDROGEN_ACCESSOR(FastLiteral)
|
||||
};
|
||||
|
||||
|
||||
class LArrayLiteral: public LTemplateInstruction<1, 0, 0> {
|
||||
public:
|
||||
DECLARE_CONCRETE_INSTRUCTION(ArrayLiteral, "array-literal")
|
||||
@ -1913,17 +1920,10 @@ class LArrayLiteral: public LTemplateInstruction<1, 0, 0> {
|
||||
};
|
||||
|
||||
|
||||
class LObjectLiteralFast: public LTemplateInstruction<1, 0, 0> {
|
||||
class LObjectLiteral: public LTemplateInstruction<1, 0, 0> {
|
||||
public:
|
||||
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)
|
||||
DECLARE_CONCRETE_INSTRUCTION(ObjectLiteral, "object-literal")
|
||||
DECLARE_HYDROGEN_ACCESSOR(ObjectLiteral)
|
||||
};
|
||||
|
||||
|
||||
|
121
test/mjsunit/compiler/literals-optimized.js
Normal file
121
test/mjsunit/compiler/literals-optimized.js
Normal file
@ -0,0 +1,121 @@
|
||||
// Copyright 2012 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.
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
// Test optimized versions of array and object literals.
|
||||
|
||||
function TestOptimizedLiteral(create, verify) {
|
||||
verify(create(1, 2, 3), 1, 2, 3);
|
||||
verify(create(3, 5, 7), 3, 5, 7);
|
||||
%OptimizeFunctionOnNextCall(create);
|
||||
verify(create(11, 23, 42), 11, 23, 42);
|
||||
}
|
||||
|
||||
|
||||
// Test shallow array literal.
|
||||
function create_arr_shallow(a, b, c) {
|
||||
return [0, a, 0, b, 0, c];
|
||||
}
|
||||
function verify_arr_shallow(array, a, b, c) {
|
||||
assertSame(6, array.length);
|
||||
assertSame(0, array[0]);
|
||||
assertSame(a, array[1]);
|
||||
assertSame(0, array[2]);
|
||||
assertSame(b, array[3]);
|
||||
assertSame(0, array[4]);
|
||||
assertSame(c, array[5]);
|
||||
}
|
||||
TestOptimizedLiteral(create_arr_shallow, verify_arr_shallow);
|
||||
|
||||
|
||||
// Test nested array literal.
|
||||
function create_arr_nested(a, b, c) {
|
||||
return [[0, a], [b, c], [1, 2], 3];
|
||||
}
|
||||
function verify_arr_nested(array, a, b, c) {
|
||||
assertSame(4, array.length);
|
||||
assertSame(2, array[0].length);
|
||||
assertSame(0, array[0][0]);
|
||||
assertSame(a, array[0][1]);
|
||||
assertSame(2, array[1].length);
|
||||
assertSame(b, array[1][0]);
|
||||
assertSame(c, array[1][1]);
|
||||
assertSame(2, array[2].length);
|
||||
assertSame(1, array[2][0]);
|
||||
assertSame(2, array[2][1]);
|
||||
assertSame(3, array[3]);
|
||||
}
|
||||
TestOptimizedLiteral(create_arr_nested, verify_arr_nested);
|
||||
|
||||
|
||||
// Test shallow object literal.
|
||||
function create_obj_shallow(a, b, c) {
|
||||
return { x:a, y:b, z:c, v:'foo', 9:'bar' };
|
||||
}
|
||||
function verify_obj_shallow(object, a, b, c) {
|
||||
assertSame(a, object.x);
|
||||
assertSame(b, object.y);
|
||||
assertSame(c, object.z);
|
||||
assertSame('foo', object.v);
|
||||
assertSame('bar', object[9]);
|
||||
}
|
||||
TestOptimizedLiteral(create_obj_shallow, verify_obj_shallow);
|
||||
|
||||
|
||||
// Test nested object literal.
|
||||
function create_obj_nested(a, b, c) {
|
||||
return { x:{ v:a, w:b }, y:{ v:1, w:2 }, z:c, v:'foo', 9:'bar' };
|
||||
}
|
||||
function verify_obj_nested(object, a, b, c) {
|
||||
assertSame(a, object.x.v);
|
||||
assertSame(b, object.x.w);
|
||||
assertSame(1, object.y.v);
|
||||
assertSame(2, object.y.w);
|
||||
assertSame(c, object.z);
|
||||
assertSame('foo', object.v);
|
||||
assertSame('bar', object[9]);
|
||||
}
|
||||
TestOptimizedLiteral(create_obj_nested, verify_obj_nested);
|
||||
|
||||
|
||||
// Test mixed array and object literal.
|
||||
function create_mixed_nested(a, b, c) {
|
||||
return { x:[1, 2], y:[a, b], z:c, v:{ v:'foo' }, 9:'bar' };
|
||||
}
|
||||
function verify_mixed_nested(object, a, b, c) {
|
||||
assertSame(2, object.x.length);
|
||||
assertSame(1, object.x[0]);
|
||||
assertSame(2, object.x[1]);
|
||||
assertSame(2, object.y.length);
|
||||
assertSame(a, object.y[0]);
|
||||
assertSame(b, object.y[1]);
|
||||
assertSame(c, object.z);
|
||||
assertSame('foo', object.v.v);
|
||||
assertSame('bar', object[9]);
|
||||
}
|
||||
TestOptimizedLiteral(create_mixed_nested, verify_mixed_nested);
|
Loading…
Reference in New Issue
Block a user