Commit 7daf8cf3 authored by Camillo Bruni's avatar Camillo Bruni Committed by Commit Bot

[literals] Add CreateEmptyObjectLiteral bytecode

The quite common empty object literal doesn't need an AllocationSite
since it starts off with the general ElementsKind. By using a separate 
bytecode we can directly instantiate the empty object without jumping
to the runtime first.

Note: this experimentally disables pretenuring for empty object
      literals. Depending on the outcome of our benchmarks pretenuring
      will be enabled again or fully removed for empty object literals.

Bug: v8:6211
Change-Id: I2fee81cbefc70865fc436dbd3bc5fc8de04db91c
Reviewed-on: https://chromium-review.googlesource.com/577555
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47467}
parent 5c47d99e
...@@ -1339,6 +1339,16 @@ class ObjectLiteral final : public AggregateLiteral { ...@@ -1339,6 +1339,16 @@ class ObjectLiteral final : public AggregateLiteral {
return HasNullPrototypeField::decode(bit_field_); return HasNullPrototypeField::decode(bit_field_);
} }
bool is_empty() const {
DCHECK(is_initialized());
return !has_elements() && properties_count() == 0 &&
properties()->length() == 0;
}
bool IsEmptyObjectLiteral() const {
return is_empty() && !has_null_prototype();
}
// Populate the depth field and flags, returns the depth. // Populate the depth field and flags, returns the depth.
int InitDepthAndFlags(); int InitDepthAndFlags();
......
...@@ -777,5 +777,31 @@ TF_BUILTIN(FastCloneShallowObject, ConstructorBuiltinsAssembler) { ...@@ -777,5 +777,31 @@ TF_BUILTIN(FastCloneShallowObject, ConstructorBuiltinsAssembler) {
literals_index, boilerplate_description, flags); literals_index, boilerplate_description, flags);
} }
// Used by the CreateEmptyObjectLiteral stub and bytecode.
Node* ConstructorBuiltinsAssembler::EmitCreateEmptyObjectLiteral(
Node* context) {
// TODO(cbruni): check whether we have to enable pretenuring support again for
// the empty object literal.
Node* native_context = LoadNativeContext(context);
Node* object_function =
LoadContextElement(native_context, Context::OBJECT_FUNCTION_INDEX);
Node* map = LoadObjectField(object_function,
JSFunction::kPrototypeOrInitialMapOffset);
CSA_ASSERT(this, IsMap(map));
Node* empty_fixed_array = EmptyFixedArrayConstant();
Node* result =
AllocateJSObjectFromMap(map, empty_fixed_array, empty_fixed_array);
HandleSlackTracking(context, result, map, JSObject::kHeaderSize);
return result;
}
TF_BUILTIN(CreateEmptyObjectLiteral, ConstructorBuiltinsAssembler) {
// TODO(cbruni): remove closure and literal_index paramters once it's clear
// whether we can live without pretenuring support for the empty object
// literal.
Node* context = Parameter(Descriptor::kContext);
Node* result = EmitCreateEmptyObjectLiteral(context);
Return(result);
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -33,6 +33,7 @@ class ConstructorBuiltinsAssembler : public CodeStubAssembler { ...@@ -33,6 +33,7 @@ class ConstructorBuiltinsAssembler : public CodeStubAssembler {
Node* EmitFastCloneShallowObject(Label* call_runtime, Node* closure, Node* EmitFastCloneShallowObject(Label* call_runtime, Node* closure,
Node* literals_index); Node* literals_index);
Node* EmitCreateEmptyObjectLiteral(Node* context);
Node* EmitFastNewObject(Node* context, Node* target, Node* new_target); Node* EmitFastNewObject(Node* context, Node* target, Node* new_target);
......
...@@ -99,6 +99,7 @@ namespace internal { ...@@ -99,6 +99,7 @@ namespace internal {
TFC(FastCloneShallowArrayTrack, FastCloneShallowArray, 1) \ TFC(FastCloneShallowArrayTrack, FastCloneShallowArray, 1) \
TFC(FastCloneShallowArrayDontTrack, FastCloneShallowArray, 1) \ TFC(FastCloneShallowArrayDontTrack, FastCloneShallowArray, 1) \
TFS(CreateEmptyArrayLiteral, kClosure, kLiteralIndex) \ TFS(CreateEmptyArrayLiteral, kClosure, kLiteralIndex) \
TFS(CreateEmptyObjectLiteral, kClosure, kLiteralIndex) \
TFC(FastCloneShallowObject, FastCloneShallowObject, 1) \ TFC(FastCloneShallowObject, FastCloneShallowObject, 1) \
/* ES6 section 9.5.14 [[Construct]] ( argumentsList, newTarget) */ \ /* ES6 section 9.5.14 [[Construct]] ( argumentsList, newTarget) */ \
TFC(ConstructProxy, ConstructTrampoline, 1) \ TFC(ConstructProxy, ConstructTrampoline, 1) \
......
...@@ -1539,6 +1539,13 @@ void BytecodeGraphBuilder::VisitCreateObjectLiteral() { ...@@ -1539,6 +1539,13 @@ void BytecodeGraphBuilder::VisitCreateObjectLiteral() {
literal, Environment::kAttachFrameState); literal, Environment::kAttachFrameState);
} }
void BytecodeGraphBuilder::VisitCreateEmptyObjectLiteral() {
int literal_index = bytecode_iterator().GetIndexOperand(0);
Node* literal = NewNode(javascript()->CreateEmptyLiteralObject(literal_index),
GetFunctionClosure());
environment()->BindAccumulator(literal);
}
Node* const* BytecodeGraphBuilder::GetCallArgumentsFromRegister( Node* const* BytecodeGraphBuilder::GetCallArgumentsFromRegister(
Node* callee, Node* receiver, interpreter::Register first_arg, Node* callee, Node* receiver, interpreter::Register first_arg,
int arg_count) { int arg_count) {
......
...@@ -225,6 +225,8 @@ Reduction JSCreateLowering::Reduce(Node* node) { ...@@ -225,6 +225,8 @@ Reduction JSCreateLowering::Reduce(Node* node) {
return ReduceJSCreateLiteralRegExp(node); return ReduceJSCreateLiteralRegExp(node);
case IrOpcode::kJSCreateEmptyLiteralArray: case IrOpcode::kJSCreateEmptyLiteralArray:
return ReduceJSCreateEmptyLiteralArray(node); return ReduceJSCreateEmptyLiteralArray(node);
case IrOpcode::kJSCreateEmptyLiteralObject:
return ReduceJSCreateEmptyLiteralObject(node);
case IrOpcode::kJSCreateFunctionContext: case IrOpcode::kJSCreateFunctionContext:
return ReduceJSCreateFunctionContext(node); return ReduceJSCreateFunctionContext(node);
case IrOpcode::kJSCreateWithContext: case IrOpcode::kJSCreateWithContext:
...@@ -892,6 +894,43 @@ Reduction JSCreateLowering::ReduceJSCreateKeyValueArray(Node* node) { ...@@ -892,6 +894,43 @@ Reduction JSCreateLowering::ReduceJSCreateKeyValueArray(Node* node) {
return Changed(node); return Changed(node);
} }
Reduction JSCreateLowering::ReduceNewObject(Node* node,
Handle<AllocationSite> site) {
DCHECK_EQ(IrOpcode::kJSCreateEmptyLiteralObject, node->opcode());
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
// Extract tenuring feedback from the {site} and add appropriate code
// dependencies on the {site} if deoptimization is enabled.
PretenureFlag pretenure = site->GetPretenureMode();
dependencies()->AssumeTenuringDecision(site);
// Retrieve the initial map for the object.
Handle<Map> map = factory()->ObjectLiteralMapFromCache(native_context(), 0);
DCHECK(!map->is_dictionary_map());
DCHECK(!map->IsInobjectSlackTrackingInProgress());
Node* js_object_map = jsgraph()->HeapConstant(map);
// Setup elements and properties.
Node* elements = jsgraph()->EmptyFixedArrayConstant();
Node* properties = jsgraph()->EmptyFixedArrayConstant();
// Perform the allocation of the actual JSArray object.
AllocationBuilder a(jsgraph(), effect, control);
a.Allocate(map->instance_size(), pretenure);
a.Store(AccessBuilder::ForMap(), js_object_map);
a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
a.Store(AccessBuilder::ForJSObjectElements(), elements);
for (int i = 0; i < map->GetInObjectProperties(); i++) {
a.Store(AccessBuilder::ForJSObjectInObjectProperty(map, i),
jsgraph()->UndefinedConstant());
}
RelaxControls(node);
a.FinishAndChange(node);
return Changed(node);
}
Reduction JSCreateLowering::ReduceJSCreateLiteralArrayOrObject(Node* node) { Reduction JSCreateLowering::ReduceJSCreateLiteralArrayOrObject(Node* node) {
DCHECK(node->opcode() == IrOpcode::kJSCreateLiteralArray || DCHECK(node->opcode() == IrOpcode::kJSCreateLiteralArray ||
node->opcode() == IrOpcode::kJSCreateLiteralObject); node->opcode() == IrOpcode::kJSCreateLiteralObject);
...@@ -958,6 +997,23 @@ Reduction JSCreateLowering::ReduceJSCreateLiteralRegExp(Node* node) { ...@@ -958,6 +997,23 @@ Reduction JSCreateLowering::ReduceJSCreateLiteralRegExp(Node* node) {
return NoChange(); return NoChange();
} }
Reduction JSCreateLowering::ReduceJSCreateEmptyLiteralObject(Node* node) {
DCHECK_EQ(node->opcode(), IrOpcode::kJSCreateEmptyLiteralObject);
int literal_index = OpParameter<int>(node);
Handle<FeedbackVector> feedback_vector;
if (GetSpecializationFeedbackVector(node).ToHandle(&feedback_vector)) {
FeedbackSlot slot(FeedbackVector::ToSlot(literal_index));
Handle<Object> raw_site(feedback_vector->Get(slot), isolate());
if (raw_site->IsAllocationSite()) {
Handle<AllocationSite> site = Handle<AllocationSite>::cast(raw_site);
// The empty object literal doesn't need a boilerplate.
DCHECK(!site->PointsToLiteral());
return ReduceNewObject(node, site);
}
}
return NoChange();
}
Reduction JSCreateLowering::ReduceJSCreateFunctionContext(Node* node) { Reduction JSCreateLowering::ReduceJSCreateFunctionContext(Node* node) {
DCHECK_EQ(IrOpcode::kJSCreateFunctionContext, node->opcode()); DCHECK_EQ(IrOpcode::kJSCreateFunctionContext, node->opcode());
const CreateFunctionContextParameters& parameters = const CreateFunctionContextParameters& parameters =
......
...@@ -54,8 +54,9 @@ class V8_EXPORT_PRIVATE JSCreateLowering final ...@@ -54,8 +54,9 @@ class V8_EXPORT_PRIVATE JSCreateLowering final
Reduction ReduceJSCreateArray(Node* node); Reduction ReduceJSCreateArray(Node* node);
Reduction ReduceJSCreateIterResultObject(Node* node); Reduction ReduceJSCreateIterResultObject(Node* node);
Reduction ReduceJSCreateKeyValueArray(Node* node); Reduction ReduceJSCreateKeyValueArray(Node* node);
Reduction ReduceJSCreateEmptyLiteralArray(Node* node);
Reduction ReduceJSCreateLiteralArrayOrObject(Node* node); Reduction ReduceJSCreateLiteralArrayOrObject(Node* node);
Reduction ReduceJSCreateEmptyLiteralObject(Node* node);
Reduction ReduceJSCreateEmptyLiteralArray(Node* node);
Reduction ReduceJSCreateLiteralRegExp(Node* node); Reduction ReduceJSCreateLiteralRegExp(Node* node);
Reduction ReduceJSCreateFunctionContext(Node* node); Reduction ReduceJSCreateFunctionContext(Node* node);
Reduction ReduceJSCreateWithContext(Node* node); Reduction ReduceJSCreateWithContext(Node* node);
...@@ -66,6 +67,7 @@ class V8_EXPORT_PRIVATE JSCreateLowering final ...@@ -66,6 +67,7 @@ class V8_EXPORT_PRIVATE JSCreateLowering final
Handle<AllocationSite> site); Handle<AllocationSite> site);
Reduction ReduceNewArray(Node* node, std::vector<Node*> values, Reduction ReduceNewArray(Node* node, std::vector<Node*> values,
Handle<AllocationSite> site); Handle<AllocationSite> site);
Reduction ReduceNewObject(Node* node, Handle<AllocationSite> site);
Node* AllocateArguments(Node* effect, Node* control, Node* frame_state); Node* AllocateArguments(Node* effect, Node* control, Node* frame_state);
Node* AllocateRestArguments(Node* effect, Node* control, Node* frame_state, Node* AllocateRestArguments(Node* effect, Node* control, Node* frame_state,
......
...@@ -505,6 +505,14 @@ void JSGenericLowering::LowerJSCreateLiteralObject(Node* node) { ...@@ -505,6 +505,14 @@ void JSGenericLowering::LowerJSCreateLiteralObject(Node* node) {
} }
} }
void JSGenericLowering::LowerJSCreateEmptyLiteralObject(Node* node) {
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
int literal_index = OpParameter<int>(node->op());
node->InsertInput(zone(), 1, jsgraph()->SmiConstant(literal_index));
Callable callable =
Builtins::CallableFor(isolate(), Builtins::kCreateEmptyObjectLiteral);
ReplaceWithStubCall(node, callable, flags);
}
void JSGenericLowering::LowerJSCreateLiteralRegExp(Node* node) { void JSGenericLowering::LowerJSCreateLiteralRegExp(Node* node) {
CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op()); CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
......
...@@ -1045,6 +1045,14 @@ const Operator* JSOperatorBuilder::CreateLiteralObject( ...@@ -1045,6 +1045,14 @@ const Operator* JSOperatorBuilder::CreateLiteralObject(
parameters); // parameter parameters); // parameter
} }
const Operator* JSOperatorBuilder::CreateEmptyLiteralObject(int literal_index) {
return new (zone()) Operator1<int>( // --
IrOpcode::kJSCreateEmptyLiteralObject, // opcode
Operator::kNoProperties, // properties
"JSCreateEmptyLiteralObject", // name
1, 1, 1, 1, 1, 2, // counts
literal_index); // parameter
}
const Operator* JSOperatorBuilder::CreateLiteralRegExp( const Operator* JSOperatorBuilder::CreateLiteralRegExp(
Handle<String> constant_pattern, int literal_flags, int literal_index) { Handle<String> constant_pattern, int literal_flags, int literal_index) {
......
...@@ -637,6 +637,7 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final ...@@ -637,6 +637,7 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
int literal_flags, int literal_index, int literal_flags, int literal_index,
int number_of_elements); int number_of_elements);
const Operator* CreateEmptyLiteralArray(int literal_index); const Operator* CreateEmptyLiteralArray(int literal_index);
const Operator* CreateEmptyLiteralObject(int literal_index);
const Operator* CreateLiteralObject(Handle<BoilerplateDescription> constant, const Operator* CreateLiteralObject(Handle<BoilerplateDescription> constant,
int literal_flags, int literal_index, int literal_flags, int literal_index,
......
...@@ -139,6 +139,7 @@ ...@@ -139,6 +139,7 @@
V(JSCreateLiteralArray) \ V(JSCreateLiteralArray) \
V(JSCreateEmptyLiteralArray) \ V(JSCreateEmptyLiteralArray) \
V(JSCreateLiteralObject) \ V(JSCreateLiteralObject) \
V(JSCreateEmptyLiteralObject) \
V(JSCreateLiteralRegExp) \ V(JSCreateLiteralRegExp) \
V(JSLoadProperty) \ V(JSLoadProperty) \
V(JSLoadNamed) \ V(JSLoadNamed) \
......
...@@ -1143,6 +1143,9 @@ Type* Typer::Visitor::TypeJSCreateLiteralObject(Node* node) { ...@@ -1143,6 +1143,9 @@ Type* Typer::Visitor::TypeJSCreateLiteralObject(Node* node) {
return Type::OtherObject(); return Type::OtherObject();
} }
Type* Typer::Visitor::TypeJSCreateEmptyLiteralObject(Node* node) {
return Type::OtherObject();
}
Type* Typer::Visitor::TypeJSCreateLiteralRegExp(Node* node) { Type* Typer::Visitor::TypeJSCreateLiteralRegExp(Node* node) {
return Type::OtherObject(); return Type::OtherObject();
......
...@@ -618,6 +618,7 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -618,6 +618,7 @@ void Verifier::Visitor::Check(Node* node) {
CheckTypeIs(node, Type::Array()); CheckTypeIs(node, Type::Array());
break; break;
case IrOpcode::kJSCreateLiteralObject: case IrOpcode::kJSCreateLiteralObject:
case IrOpcode::kJSCreateEmptyLiteralObject:
case IrOpcode::kJSCreateLiteralRegExp: case IrOpcode::kJSCreateLiteralRegExp:
// Type is OtherObject. // Type is OtherObject.
CheckTypeIs(node, Type::OtherObject()); CheckTypeIs(node, Type::OtherObject());
......
...@@ -409,7 +409,9 @@ bool BytecodeHasNoSideEffect(interpreter::Bytecode bytecode) { ...@@ -409,7 +409,9 @@ bool BytecodeHasNoSideEffect(interpreter::Bytecode bytecode) {
case Bytecode::kCreateWithContext: case Bytecode::kCreateWithContext:
// Literals. // Literals.
case Bytecode::kCreateArrayLiteral: case Bytecode::kCreateArrayLiteral:
case Bytecode::kCreateEmptyArrayLiteral:
case Bytecode::kCreateObjectLiteral: case Bytecode::kCreateObjectLiteral:
case Bytecode::kCreateEmptyObjectLiteral:
case Bytecode::kCreateRegExpLiteral: case Bytecode::kCreateRegExpLiteral:
// Allocations. // Allocations.
case Bytecode::kCreateClosure: case Bytecode::kCreateClosure:
......
...@@ -977,6 +977,12 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CreateObjectLiteral( ...@@ -977,6 +977,12 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CreateObjectLiteral(
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::CreateEmptyObjectLiteral(
int literal_index) {
OutputCreateEmptyObjectLiteral(literal_index);
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::PushContext(Register context) { BytecodeArrayBuilder& BytecodeArrayBuilder::PushContext(Register context) {
OutputPushContext(context); OutputPushContext(context);
return *this; return *this;
......
...@@ -225,6 +225,7 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final ...@@ -225,6 +225,7 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final
BytecodeArrayBuilder& CreateObjectLiteral(size_t constant_properties_entry, BytecodeArrayBuilder& CreateObjectLiteral(size_t constant_properties_entry,
int literal_index, int flags, int literal_index, int flags,
Register output); Register output);
BytecodeArrayBuilder& CreateEmptyObjectLiteral(int literal_index);
// Push the context in accumulator as the new context, and store in register // Push the context in accumulator as the new context, and store in register
// |context|. // |context|.
......
...@@ -1892,6 +1892,16 @@ void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { ...@@ -1892,6 +1892,16 @@ void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
} }
void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
int literal_index = feedback_index(expr->literal_slot());
// Fast path for the empty object literal which doesn't need an
// AllocationSite.
if (expr->IsEmptyObjectLiteral()) {
DCHECK(expr->IsFastCloningSupported());
builder()->CreateEmptyObjectLiteral(literal_index);
return;
}
// Deep-copy the literal boilerplate. // Deep-copy the literal boilerplate.
uint8_t flags = CreateObjectLiteralFlags::Encode( uint8_t flags = CreateObjectLiteralFlags::Encode(
expr->ComputeFlags(), expr->IsFastCloningSupported()); expr->ComputeFlags(), expr->IsFastCloningSupported());
...@@ -1909,8 +1919,7 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { ...@@ -1909,8 +1919,7 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
// TODO(cbruni): Directly generate runtime call for literals we cannot // TODO(cbruni): Directly generate runtime call for literals we cannot
// optimize once the FastCloneShallowObject stub is in sync with the TF // optimize once the FastCloneShallowObject stub is in sync with the TF
// optimizations. // optimizations.
builder()->CreateObjectLiteral(entry, feedback_index(expr->literal_slot()), builder()->CreateObjectLiteral(entry, literal_index, flags, literal);
flags, literal);
// Store computed values into the literal. // Store computed values into the literal.
int property_index = 0; int property_index = 0;
......
...@@ -230,6 +230,7 @@ namespace interpreter { ...@@ -230,6 +230,7 @@ namespace interpreter {
V(CreateEmptyArrayLiteral, AccumulatorUse::kWrite, OperandType::kIdx) \ V(CreateEmptyArrayLiteral, AccumulatorUse::kWrite, OperandType::kIdx) \
V(CreateObjectLiteral, AccumulatorUse::kNone, OperandType::kIdx, \ V(CreateObjectLiteral, AccumulatorUse::kNone, OperandType::kIdx, \
OperandType::kIdx, OperandType::kFlag8, OperandType::kRegOut) \ OperandType::kIdx, OperandType::kFlag8, OperandType::kRegOut) \
V(CreateEmptyObjectLiteral, AccumulatorUse::kWrite, OperandType::kIdx) \
\ \
/* Closure allocation */ \ /* Closure allocation */ \
V(CreateClosure, AccumulatorUse::kWrite, OperandType::kIdx, \ V(CreateClosure, AccumulatorUse::kWrite, OperandType::kIdx, \
......
...@@ -2721,6 +2721,19 @@ IGNITION_HANDLER(CreateObjectLiteral, InterpreterAssembler) { ...@@ -2721,6 +2721,19 @@ IGNITION_HANDLER(CreateObjectLiteral, InterpreterAssembler) {
} }
} }
// CreateEmptyObjectLiteral <literal_idx>
//
// Creates an empty JSObject literal for literal index <literal_idx>.
IGNITION_HANDLER(CreateEmptyObjectLiteral, InterpreterAssembler) {
// TODO(cbruni): remove literal_index and closure parameter once we know
// whether empty object literals work without pretenuring support.
Node* context = GetContext();
ConstructorBuiltinsAssembler constructor_assembler(state());
Node* result = constructor_assembler.EmitCreateEmptyObjectLiteral(context);
SetAccumulator(result);
Dispatch();
}
// CreateClosure <index> <slot> <tenured> // CreateClosure <index> <slot> <tenured>
// //
// Creates a new closure for SharedFunctionInfo at position |index| in the // Creates a new closure for SharedFunctionInfo at position |index| in the
......
...@@ -3884,11 +3884,13 @@ TEST(AllocationSiteCreation) { ...@@ -3884,11 +3884,13 @@ TEST(AllocationSiteCreation) {
CompileRun("function f5() { return {}; }; f5(); "); CompileRun("function f5() { return {}; }; f5(); ");
count = AllocationSitesCount(heap); count = AllocationSitesCount(heap);
CHECK_EQ(0, count - prev_count); CHECK_EQ(0, count - prev_count);
// Allocation-sites + boilerplates are created on the second run only. // No AllocationSites are created for the empty object literal.
prev_count = AllocationSitesCount(heap); for (int i = 0; i < 5; i++) {
CompileRun("f5(); "); prev_count = AllocationSitesCount(heap);
count = AllocationSitesCount(heap); CompileRun("f5(); ");
CHECK_EQ(1, count - prev_count); count = AllocationSitesCount(heap);
CHECK_EQ(0, count - prev_count);
}
prev_count = AllocationSitesCount(heap); prev_count = AllocationSitesCount(heap);
CompileRun("function f6() { return {a:1}; }; f6(); "); CompileRun("function f6() { return {a:1}; }; f6(); ");
......
...@@ -9,17 +9,15 @@ wrap: yes ...@@ -9,17 +9,15 @@ wrap: yes
snippet: " snippet: "
return { }; return { };
" "
frame size: 1 frame size: 0
parameter count: 1 parameter count: 1
bytecode array length: 9 bytecode array length: 4
bytecodes: [ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 34 S> */ B(CreateObjectLiteral), U8(0), U8(0), U8(41), R(0), /* 34 S> */ B(CreateEmptyObjectLiteral), U8(0),
B(Ldar), R(0),
/* 45 S> */ B(Return), /* 45 S> */ B(Return),
] ]
constant pool: [ constant pool: [
FIXED_ARRAY_TYPE,
] ]
handlers: [ handlers: [
] ]
...@@ -333,9 +331,9 @@ handlers: [ ...@@ -333,9 +331,9 @@ handlers: [
snippet: " snippet: "
var a = 'test'; return { [a]: 1, __proto__: {} }; var a = 'test'; return { [a]: 1, __proto__: {} };
" "
frame size: 5 frame size: 4
parameter count: 1 parameter count: 1
bytecode array length: 38 bytecode array length: 34
bytecodes: [ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaConstant), U8(0), /* 42 S> */ B(LdaConstant), U8(0),
...@@ -344,9 +342,9 @@ bytecodes: [ ...@@ -344,9 +342,9 @@ bytecodes: [
/* 60 E> */ B(ToName), R(2), /* 60 E> */ B(ToName), R(2),
B(LdaSmi), I8(1), B(LdaSmi), I8(1),
B(StaDataPropertyInLiteral), R(1), R(2), U8(0), U8(2), B(StaDataPropertyInLiteral), R(1), R(2), U8(0), U8(2),
B(CreateObjectLiteral), U8(1), U8(0), U8(41), R(4), B(CreateEmptyObjectLiteral), U8(0),
B(Star), R(3),
B(Mov), R(1), R(2), B(Mov), R(1), R(2),
B(Mov), R(4), R(3),
B(CallRuntime), U16(Runtime::kInternalSetPrototype), R(2), U8(2), B(CallRuntime), U16(Runtime::kInternalSetPrototype), R(2), U8(2),
B(Ldar), R(2), B(Ldar), R(2),
/* 83 S> */ B(Return), /* 83 S> */ B(Return),
......
...@@ -352,7 +352,8 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { ...@@ -352,7 +352,8 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.CreateRegExpLiteral(ast_factory.GetOneByteString("wide_literal"), 0, 0) .CreateRegExpLiteral(ast_factory.GetOneByteString("wide_literal"), 0, 0)
.CreateArrayLiteral(0, 0, 0) .CreateArrayLiteral(0, 0, 0)
.CreateEmptyArrayLiteral(0) .CreateEmptyArrayLiteral(0)
.CreateObjectLiteral(0, 0, 0, reg); .CreateObjectLiteral(0, 0, 0, reg)
.CreateEmptyObjectLiteral(0);
// Emit load and store operations for module variables. // Emit load and store operations for module variables.
builder.LoadModuleVariable(-1, 42) builder.LoadModuleVariable(-1, 42)
......
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