Optimize calls to object literal properties that are initialized with a function literal.

This allows fast calls and inlining of functions like:

var o = {f: function() { return "foo"; }}
o.f();


Object literals that contain function literals are initially created a dictionary mode
object and only transformed to fast properties once all properties are computed and
added. This allows us to create constant function properties for functions declared
inside the object literal. Function literals inside object literals are marked for
pretenuring so that they work as contant function properties.

Object literals without functions should just function as before.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7283 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
fschneider@chromium.org 2011-03-21 12:25:31 +00:00
parent 0dce18e6c2
commit 8066271fd2
19 changed files with 280 additions and 119 deletions

View File

@ -1397,7 +1397,13 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
__ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
__ mov(r2, Operand(Smi::FromInt(expr->literal_index())));
__ mov(r1, Operand(expr->constant_properties()));
__ mov(r0, Operand(Smi::FromInt(expr->fast_elements() ? 1 : 0)));
int flags = expr->fast_elements()
? ObjectLiteral::kFastElements
: ObjectLiteral::kNoFlags;
flags |= expr->has_function()
? ObjectLiteral::kHasFunction
: ObjectLiteral::kNoFlags;
__ mov(r0, Operand(Smi::FromInt(flags)));
__ Push(r3, r2, r1, r0);
if (expr->depth() > 1) {
__ CallRuntime(Runtime::kCreateObjectLiteral, 4);
@ -1476,6 +1482,13 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
}
}
if (expr->has_function()) {
ASSERT(result_saved);
__ ldr(r0, MemOperand(sp));
__ push(r0);
__ CallRuntime(Runtime::kToFastProperties, 1);
}
if (result_saved) {
context()->PlugTOS();
} else {

View File

@ -1996,6 +1996,13 @@ LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
}
LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
LOperand* object = UseFixed(instr->value(), r0);
LToFastProperties* result = new LToFastProperties(object);
return MarkAsCall(DefineFixed(result, r0), instr);
}
LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
LTypeof* result = new LTypeof(UseFixed(instr->value(), r0));
return MarkAsCall(DefineFixed(result, r0), instr);

View File

@ -155,6 +155,7 @@ class LCodeGen;
V(SubI) \
V(TaggedToI) \
V(Throw) \
V(ToFastProperties) \
V(Typeof) \
V(TypeofIs) \
V(TypeofIsAndBranch) \
@ -1767,6 +1768,17 @@ class LFunctionLiteral: public LTemplateInstruction<1, 0, 0> {
};
class LToFastProperties: public LTemplateInstruction<1, 1, 0> {
public:
explicit LToFastProperties(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(ToFastProperties, "to-fast-properties")
DECLARE_HYDROGEN_ACCESSOR(ToFastProperties)
};
class LTypeof: public LTemplateInstruction<1, 1, 0> {
public:
explicit LTypeof(LOperand* value) {

View File

@ -3674,6 +3674,13 @@ void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
}
void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
ASSERT(ToRegister(instr->InputAt(0)).is(r0));
__ push(r0);
CallRuntime(Runtime::kToFastProperties, 1, instr);
}
void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
Label materialized;
// Registers will be used as follows:

View File

@ -985,11 +985,13 @@ class ObjectLiteral: public MaterializedLiteral {
int literal_index,
bool is_simple,
bool fast_elements,
int depth)
int depth,
bool has_function)
: MaterializedLiteral(literal_index, is_simple, depth),
constant_properties_(constant_properties),
properties_(properties),
fast_elements_(fast_elements) {}
fast_elements_(fast_elements),
has_function_(has_function) {}
DECLARE_NODE_TYPE(ObjectLiteral)
@ -1000,16 +1002,24 @@ class ObjectLiteral: public MaterializedLiteral {
bool fast_elements() const { return fast_elements_; }
bool has_function() { return has_function_; }
// Mark all computed expressions that are bound to a key that
// is shadowed by a later occurrence of the same key. For the
// marked expressions, no store code is emitted.
void CalculateEmitStore();
enum Flags {
kNoFlags = 0,
kFastElements = 1,
kHasFunction = 1 << 1
};
private:
Handle<FixedArray> constant_properties_;
ZoneList<Property*>* properties_;
bool fast_elements_;
bool has_function_;
};

View File

@ -958,34 +958,4 @@ bool CompileOptimized(Handle<JSFunction> function,
return CompileLazyHelper(&info, flag);
}
OptimizedObjectForAddingMultipleProperties::
OptimizedObjectForAddingMultipleProperties(Handle<JSObject> object,
int expected_additional_properties,
bool condition) {
object_ = object;
if (condition && object_->HasFastProperties() && !object->IsJSGlobalProxy()) {
// Normalize the properties of object to avoid n^2 behavior
// when extending the object multiple properties. Indicate the number of
// properties to be added.
unused_property_fields_ = object->map()->unused_property_fields();
NormalizeProperties(object_,
KEEP_INOBJECT_PROPERTIES,
expected_additional_properties);
has_been_transformed_ = true;
} else {
has_been_transformed_ = false;
}
}
OptimizedObjectForAddingMultipleProperties::
~OptimizedObjectForAddingMultipleProperties() {
// Reoptimize the object to allow fast property access.
if (has_been_transformed_) {
TransformToFastProperties(object_, unused_property_fields_);
}
}
} } // namespace v8::internal

View File

@ -367,25 +367,6 @@ class NoHandleAllocation BASE_EMBEDDED {
#endif
};
// ----------------------------------------------------------------------------
// Stack allocated wrapper call for optimizing adding multiple
// properties to an object.
class OptimizedObjectForAddingMultipleProperties BASE_EMBEDDED {
public:
OptimizedObjectForAddingMultipleProperties(Handle<JSObject> object,
int expected_property_count,
bool condition = true);
~OptimizedObjectForAddingMultipleProperties();
private:
bool has_been_transformed_; // Tells whether the object has been transformed.
int unused_property_fields_; // Captures the unused number of field.
Handle<JSObject> object_; // The object being optimized.
};
} } // namespace v8::internal
#endif // V8_HANDLES_H_

View File

@ -156,6 +156,7 @@ class LChunkBuilder;
V(Sub) \
V(Test) \
V(Throw) \
V(ToFastProperties) \
V(Typeof) \
V(TypeofIs) \
V(UnaryMathOperation) \
@ -3382,10 +3383,12 @@ class HObjectLiteral: public HMaterializedLiteral<1> {
Handle<FixedArray> constant_properties,
bool fast_elements,
int literal_index,
int depth)
int depth,
bool has_function)
: HMaterializedLiteral<1>(literal_index, depth),
constant_properties_(constant_properties),
fast_elements_(fast_elements) {
fast_elements_(fast_elements),
has_function_(has_function) {
SetOperandAt(0, context);
}
@ -3394,6 +3397,7 @@ class HObjectLiteral: public HMaterializedLiteral<1> {
return constant_properties_;
}
bool fast_elements() const { return fast_elements_; }
bool has_function() const { return has_function_; }
virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Tagged();
@ -3404,6 +3408,7 @@ class HObjectLiteral: public HMaterializedLiteral<1> {
private:
Handle<FixedArray> constant_properties_;
bool fast_elements_;
bool has_function_;
};
@ -3467,6 +3472,24 @@ class HTypeof: public HUnaryOperation {
};
class HToFastProperties: public HUnaryOperation {
public:
explicit HToFastProperties(HValue* value) : HUnaryOperation(value) {
// 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->IsObjectLiteral());
set_representation(Representation::Tagged());
}
virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Tagged();
}
DECLARE_CONCRETE_INSTRUCTION(ToFastProperties, "to_fast_properties")
};
class HValueOf: public HUnaryOperation {
public:
explicit HValueOf(HValue* value) : HUnaryOperation(value) {

View File

@ -2905,7 +2905,8 @@ void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
expr->constant_properties(),
expr->fast_elements(),
expr->literal_index(),
expr->depth()));
expr->depth(),
expr->has_function()));
// The object is expected in the bailout environment during computation
// of the property values and is the value of the entire expression.
PushAndAdd(literal);
@ -2946,7 +2947,19 @@ void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
default: UNREACHABLE();
}
}
ast_context()->ReturnValue(Pop());
if (expr->has_function()) {
// Return the result of the transformation to fast properties
// instead of the original since this operation changes the map
// of the object. This makes sure that the original object won't
// be used by other optimized code before it is transformed
// (e.g. because of code motion).
HToFastProperties* result = new HToFastProperties(Pop());
AddInstruction(result);
ast_context()->ReturnValue(result);
} else {
ast_context()->ReturnValue(Pop());
}
}

View File

@ -1343,7 +1343,13 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
__ push(FieldOperand(edi, JSFunction::kLiteralsOffset));
__ push(Immediate(Smi::FromInt(expr->literal_index())));
__ push(Immediate(expr->constant_properties()));
__ push(Immediate(Smi::FromInt(expr->fast_elements() ? 1 : 0)));
int flags = expr->fast_elements()
? ObjectLiteral::kFastElements
: ObjectLiteral::kNoFlags;
flags |= expr->has_function()
? ObjectLiteral::kHasFunction
: ObjectLiteral::kNoFlags;
__ push(Immediate(Smi::FromInt(flags)));
if (expr->depth() > 1) {
__ CallRuntime(Runtime::kCreateObjectLiteral, 4);
} else {
@ -1415,6 +1421,12 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
}
}
if (expr->has_function()) {
ASSERT(result_saved);
__ push(Operand(esp, 0));
__ CallRuntime(Runtime::kToFastProperties, 1);
}
if (result_saved) {
context()->PlugTOS();
} else {

View File

@ -3676,7 +3676,13 @@ void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
__ push(FieldOperand(eax, JSFunction::kLiteralsOffset));
__ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
__ push(Immediate(instr->hydrogen()->constant_properties()));
__ push(Immediate(Smi::FromInt(instr->hydrogen()->fast_elements() ? 1 : 0)));
int flags = instr->hydrogen()->fast_elements()
? ObjectLiteral::kFastElements
: ObjectLiteral::kNoFlags;
flags |= instr->hydrogen()->has_function()
? ObjectLiteral::kHasFunction
: ObjectLiteral::kNoFlags;
__ push(Immediate(Smi::FromInt(flags)));
// Pick the right runtime function to call.
if (instr->hydrogen()->depth() > 1) {
@ -3687,6 +3693,13 @@ void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
}
void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
ASSERT(ToRegister(instr->InputAt(0)).is(eax));
__ push(eax);
CallRuntime(Runtime::kToFastProperties, 1, instr);
}
void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
NearLabel materialized;
// Registers will be used as follows:

View File

@ -2030,6 +2030,13 @@ LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
}
LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
LOperand* object = UseFixed(instr->value(), eax);
LToFastProperties* result = new LToFastProperties(object);
return MarkAsCall(DefineFixed(result, eax), instr);
}
LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
LTypeof* result = new LTypeof(UseAtStart(instr->value()));
return MarkAsCall(DefineFixed(result, eax), instr);

View File

@ -157,6 +157,7 @@ class LCodeGen;
V(SubI) \
V(TaggedToI) \
V(Throw) \
V(ToFastProperties) \
V(Typeof) \
V(TypeofIs) \
V(TypeofIsAndBranch) \
@ -1847,6 +1848,17 @@ class LFunctionLiteral: public LTemplateInstruction<1, 0, 0> {
};
class LToFastProperties: public LTemplateInstruction<1, 1, 0> {
public:
explicit LToFastProperties(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(ToFastProperties, "to-fast-properties")
DECLARE_HYDROGEN_ACCESSOR(ToFastProperties)
};
class LTypeof: public LTemplateInstruction<1, 1, 0> {
public:
explicit LTypeof(LOperand* value) {

View File

@ -3340,6 +3340,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
ZoneList<ObjectLiteral::Property*>* properties =
new ZoneList<ObjectLiteral::Property*>(4);
int number_of_boilerplate_properties = 0;
bool has_function = false;
ObjectLiteralPropertyChecker checker(this, top_scope_->is_strict_mode());
@ -3428,6 +3429,13 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
ObjectLiteral::Property* property =
new ObjectLiteral::Property(key, value);
// Mark object literals that contain function literals and pretenure the
// literal so it can be added as a constant function property.
if (value->AsFunctionLiteral() != NULL) {
has_function = true;
value->AsFunctionLiteral()->set_pretenure(true);
}
// Count CONSTANT or COMPUTED properties to maintain the enumeration order.
if (IsBoilerplateProperty(property)) number_of_boilerplate_properties++;
// Validate the property
@ -3463,7 +3471,8 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
literal_index,
is_simple,
fast_elements,
depth);
depth,
has_function);
}

View File

@ -304,7 +304,8 @@ static Handle<Object> CreateObjectLiteralBoilerplate(
Isolate* isolate,
Handle<FixedArray> literals,
Handle<FixedArray> constant_properties,
bool should_have_fast_elements) {
bool should_have_fast_elements,
bool has_function_literal) {
// Get the global context from the literals array. This is the
// context in which the function was created and we use the object
// function from this context to create the object literal. We do
@ -314,70 +315,90 @@ static Handle<Object> CreateObjectLiteralBoilerplate(
Handle<Context> context =
Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
bool is_result_from_cache;
Handle<Map> map = ComputeObjectLiteralMap(context,
constant_properties,
&is_result_from_cache);
// In case we have function literals, we want the object to be in
// slow properties mode for now. We don't go in the map cache because
// maps with constant functions can't be shared if the functions are
// not the same (which is the common case).
bool is_result_from_cache = false;
Handle<Map> map = has_function_literal
? Handle<Map>(context->object_function()->initial_map())
: ComputeObjectLiteralMap(context,
constant_properties,
&is_result_from_cache);
Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
// Normalize the elements of the boilerplate to save space if needed.
if (!should_have_fast_elements) NormalizeElements(boilerplate);
{ // Add the constant properties to the boilerplate.
int length = constant_properties->length();
OptimizedObjectForAddingMultipleProperties opt(boilerplate,
length / 2,
!is_result_from_cache);
for (int index = 0; index < length; index +=2) {
Handle<Object> key(constant_properties->get(index+0), isolate);
Handle<Object> value(constant_properties->get(index+1), isolate);
if (value->IsFixedArray()) {
// The value contains the constant_properties of a
// simple object literal.
Handle<FixedArray> array = Handle<FixedArray>::cast(value);
value = CreateLiteralBoilerplate(isolate, literals, array);
if (value.is_null()) return value;
}
Handle<Object> result;
uint32_t element_index = 0;
if (key->IsSymbol()) {
if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
// Array index as string (uint32).
result = SetOwnElement(boilerplate,
element_index,
value,
kNonStrictMode);
} else {
Handle<String> name(String::cast(*key));
ASSERT(!name->AsArrayIndex(&element_index));
result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
value, NONE);
}
} else if (key->ToArrayIndex(&element_index)) {
// Array index (uint32).
// Add the constant properties to the boilerplate.
int length = constant_properties->length();
bool should_transform =
!is_result_from_cache && boilerplate->HasFastProperties();
if (should_transform || has_function_literal) {
// Normalize the properties of object to avoid n^2 behavior
// when extending the object multiple properties. Indicate the number of
// properties to be added.
NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
}
for (int index = 0; index < length; index +=2) {
Handle<Object> key(constant_properties->get(index+0), isolate);
Handle<Object> value(constant_properties->get(index+1), isolate);
if (value->IsFixedArray()) {
// The value contains the constant_properties of a
// simple object or array literal.
Handle<FixedArray> array = Handle<FixedArray>::cast(value);
value = CreateLiteralBoilerplate(isolate, literals, array);
if (value.is_null()) return value;
}
Handle<Object> result;
uint32_t element_index = 0;
if (key->IsSymbol()) {
if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
// Array index as string (uint32).
result = SetOwnElement(boilerplate,
element_index,
value,
kNonStrictMode);
} else {
// Non-uint32 number.
ASSERT(key->IsNumber());
double num = key->Number();
char arr[100];
Vector<char> buffer(arr, ARRAY_SIZE(arr));
const char* str = DoubleToCString(num, buffer);
Handle<String> name =
isolate->factory()->NewStringFromAscii(CStrVector(str));
Handle<String> name(String::cast(*key));
ASSERT(!name->AsArrayIndex(&element_index));
result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
value, NONE);
}
// If setting the property on the boilerplate throws an
// exception, the exception is converted to an empty handle in
// the handle based operations. In that case, we need to
// convert back to an exception.
if (result.is_null()) return result;
} else if (key->ToArrayIndex(&element_index)) {
// Array index (uint32).
result = SetOwnElement(boilerplate,
element_index,
value,
kNonStrictMode);
} else {
// Non-uint32 number.
ASSERT(key->IsNumber());
double num = key->Number();
char arr[100];
Vector<char> buffer(arr, ARRAY_SIZE(arr));
const char* str = DoubleToCString(num, buffer);
Handle<String> name =
isolate->factory()->NewStringFromAscii(CStrVector(str));
result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
value, NONE);
}
// If setting the property on the boilerplate throws an
// exception, the exception is converted to an empty handle in
// the handle based operations. In that case, we need to
// convert back to an exception.
if (result.is_null()) return result;
}
// Transform to fast properties if necessary. For object literals with
// containing function literals we defer this operation until after all
// computed properties have been assigned so that we can generate
// constant function properties.
if (should_transform && !has_function_literal) {
TransformToFastProperties(boilerplate,
boilerplate->map()->unused_property_fields());
}
return boilerplate;
@ -410,7 +431,7 @@ static Handle<Object> CreateArrayLiteralBoilerplate(
for (int i = 0; i < content->length(); i++) {
if (content->get(i)->IsFixedArray()) {
// The value contains the constant_properties of a
// simple object literal.
// simple object or array literal.
Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
Handle<Object> result =
CreateLiteralBoilerplate(isolate, literals, fa);
@ -431,11 +452,20 @@ static Handle<Object> CreateLiteralBoilerplate(
Handle<FixedArray> literals,
Handle<FixedArray> array) {
Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
const bool kHasNoFunctionLiteral = false;
switch (CompileTimeValue::GetType(array)) {
case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
return CreateObjectLiteralBoilerplate(isolate, literals, elements, true);
return CreateObjectLiteralBoilerplate(isolate,
literals,
elements,
true,
kHasNoFunctionLiteral);
case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
return CreateObjectLiteralBoilerplate(isolate, literals, elements, false);
return CreateObjectLiteralBoilerplate(isolate,
literals,
elements,
false,
kHasNoFunctionLiteral);
case CompileTimeValue::ARRAY_LITERAL:
return CreateArrayLiteralBoilerplate(isolate, literals, elements);
default:
@ -476,8 +506,9 @@ static MaybeObject* Runtime_CreateObjectLiteral(RUNTIME_CALLING_CONVENTION) {
CONVERT_ARG_CHECKED(FixedArray, literals, 0);
CONVERT_SMI_CHECKED(literals_index, args[1]);
CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
CONVERT_SMI_CHECKED(fast_elements, args[3]);
bool should_have_fast_elements = fast_elements == 1;
CONVERT_SMI_CHECKED(flags, args[3]);
bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
// Check if boilerplate exists. If not, create it first.
Handle<Object> boilerplate(literals->get(literals_index), isolate);
@ -485,7 +516,8 @@ static MaybeObject* Runtime_CreateObjectLiteral(RUNTIME_CALLING_CONVENTION) {
boilerplate = CreateObjectLiteralBoilerplate(isolate,
literals,
constant_properties,
should_have_fast_elements);
should_have_fast_elements,
has_function_literal);
if (boilerplate.is_null()) return Failure::Exception();
// Update the functions literal and return the boilerplate.
literals->set(literals_index, *boilerplate);
@ -502,8 +534,9 @@ static MaybeObject* Runtime_CreateObjectLiteralShallow(
CONVERT_ARG_CHECKED(FixedArray, literals, 0);
CONVERT_SMI_CHECKED(literals_index, args[1]);
CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
CONVERT_SMI_CHECKED(fast_elements, args[3]);
bool should_have_fast_elements = fast_elements == 1;
CONVERT_SMI_CHECKED(flags, args[3]);
bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
// Check if boilerplate exists. If not, create it first.
Handle<Object> boilerplate(literals->get(literals_index), isolate);
@ -511,7 +544,8 @@ static MaybeObject* Runtime_CreateObjectLiteralShallow(
boilerplate = CreateObjectLiteralBoilerplate(isolate,
literals,
constant_properties,
should_have_fast_elements);
should_have_fast_elements,
has_function_literal);
if (boilerplate.is_null()) return Failure::Exception();
// Update the functions literal and return the boilerplate.
literals->set(literals_index, *boilerplate);

View File

@ -1361,7 +1361,13 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
__ push(FieldOperand(rdi, JSFunction::kLiteralsOffset));
__ Push(Smi::FromInt(expr->literal_index()));
__ Push(expr->constant_properties());
__ Push(Smi::FromInt(expr->fast_elements() ? 1 : 0));
int flags = expr->fast_elements()
? ObjectLiteral::kFastElements
: ObjectLiteral::kNoFlags;
flags |= expr->has_function()
? ObjectLiteral::kHasFunction
: ObjectLiteral::kNoFlags;
__ Push(Smi::FromInt(flags));
if (expr->depth() > 1) {
__ CallRuntime(Runtime::kCreateObjectLiteral, 4);
} else {
@ -1431,6 +1437,12 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
}
}
if (expr->has_function()) {
ASSERT(result_saved);
__ push(Operand(rsp, 0));
__ CallRuntime(Runtime::kToFastProperties, 1);
}
if (result_saved) {
context()->PlugTOS();
} else {

View File

@ -3487,6 +3487,13 @@ void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
}
void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
ASSERT(ToRegister(instr->InputAt(0)).is(rax));
__ push(rax);
CallRuntime(Runtime::kToFastProperties, 1, instr);
}
void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
NearLabel materialized;
// Registers will be used as follows:

View File

@ -1990,6 +1990,13 @@ LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
}
LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
LOperand* object = UseFixed(instr->value(), rax);
LToFastProperties* result = new LToFastProperties(object);
return MarkAsCall(DefineFixed(result, rax), instr);
}
LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
LTypeof* result = new LTypeof(UseAtStart(instr->value()));
return MarkAsCall(DefineFixed(result, rax), instr);

View File

@ -154,6 +154,7 @@ class LCodeGen;
V(StringLength) \
V(SubI) \
V(TaggedToI) \
V(ToFastProperties) \
V(Throw) \
V(Typeof) \
V(TypeofIs) \
@ -1762,6 +1763,17 @@ class LFunctionLiteral: public LTemplateInstruction<1, 0, 0> {
};
class LToFastProperties: public LTemplateInstruction<1, 1, 0> {
public:
explicit LToFastProperties(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(ToFastProperties, "to-fast-properties")
DECLARE_HYDROGEN_ACCESSOR(ToFastProperties)
};
class LTypeof: public LTemplateInstruction<1, 1, 0> {
public:
explicit LTypeof(LOperand* value) {