[literals] Introduce CreateEmptyArrayLiteral Bytecode

Empty Array literals are amongst the most commonly used literal types on our
top25 page list. Using a custom bytecode we can drop the boilerplate for empty
Array literals alltogether. However, we still need a proper AllocationSite to
track ElementsKind transitions.

Bug: v8:6211
Change-Id: Id5dbdac0ea8e24dd474e679c902c6e4a2957af1d
Reviewed-on: https://chromium-review.googlesource.com/567079
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Reviewed-by: Michael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46752}
This commit is contained in:
Camillo Bruni 2017-07-19 09:35:52 +02:00 committed by Commit Bot
parent fe046627db
commit 4851745fe3
27 changed files with 376 additions and 30 deletions

View File

@ -1446,6 +1446,12 @@ class ArrayLiteral final : public AggregateLiteral {
ZoneList<Expression*>* values() const { return values_; }
bool is_empty() const {
DCHECK(is_initialized());
return values()->is_empty() &&
(constant_elements().is_null() || constant_elements()->is_empty());
}
// Populate the depth field and flags, returns the depth.
int InitDepthAndFlags();

View File

@ -197,14 +197,6 @@ Node* ConstructorBuiltinsAssembler::EmitFastNewClosure(Node* shared_info,
return result;
}
Node* ConstructorBuiltinsAssembler::LoadFeedbackVectorSlot(
Node* closure, Node* literal_index) {
Node* cell = LoadObjectField(closure, JSFunction::kFeedbackVectorOffset);
Node* feedback_vector = LoadObjectField(cell, Cell::kValueOffset);
return LoadFixedArrayElement(feedback_vector, literal_index, 0,
CodeStubAssembler::SMI_PARAMETERS);
}
Node* ConstructorBuiltinsAssembler::NotHasBoilerplate(Node* literal_site) {
return TaggedIsSmi(literal_site);
}
@ -215,6 +207,29 @@ Node* ConstructorBuiltinsAssembler::LoadAllocationSiteBoilerplate(Node* site) {
AllocationSite::kTransitionInfoOrBoilerplateOffset);
}
Node* ConstructorBuiltinsAssembler::AllocateAllocationSite(
Node* closure, Node* literal_index) {
CSA_ASSERT(this, TaggedIsPositiveSmi(literal_index));
Node* result = Allocate(AllocationSite::kSize);
StoreMapNoWriteBarrier(result, Heap::kAllocationSiteMapRootIndex);
// Should match AllocationSite::Initialize.
StoreObjectFieldNoWriteBarrier(
result, AllocationSite::kTransitionInfoOrBoilerplateOffset,
SmiConstant(0));
StoreObjectFieldNoWriteBarrier(result, AllocationSite::kNestedSiteOffset,
SmiConstant(0));
StoreObjectFieldNoWriteBarrier(result, AllocationSite::kPretenureDataOffset,
SmiConstant(0));
StoreObjectFieldNoWriteBarrier(
result, AllocationSite::kPretenureCreateCountOffset, SmiConstant(0));
StoreObjectFieldNoWriteBarrier(result, AllocationSite::kWeakNextOffset,
SmiConstant(0));
StoreObjectFieldRoot(result, AllocationSite::kDependentCodeOffset,
Heap::kEmptyFixedArrayRootIndex);
StoreFeedbackVectorSlot(closure, literal_index, result);
return result;
}
TF_BUILTIN(FastNewClosure, ConstructorBuiltinsAssembler) {
Node* shared = Parameter(FastNewClosureDescriptor::kSharedFunctionInfo);
Node* context = Parameter(FastNewClosureDescriptor::kContext);
@ -565,6 +580,55 @@ TF_BUILTIN(FastCloneShallowArrayDontTrack, ConstructorBuiltinsAssembler) {
CreateFastCloneShallowArrayBuiltin(DONT_TRACK_ALLOCATION_SITE);
}
Node* ConstructorBuiltinsAssembler::EmitCreateEmptyArrayLiteral(
Node* closure, Node* literal_index, Node* context) {
// Array literals always have a valid AllocationSite to properly track
// elements transitions.
VARIABLE(allocation_site, MachineRepresentation::kTagged,
LoadFeedbackVectorSlot(closure, literal_index));
Label create_empty_array(this),
initialize_allocation_site(this, Label::kDeferred), done(this);
Branch(TaggedIsSmi(allocation_site.value()), &initialize_allocation_site,
&create_empty_array);
// TODO(cbruni): create the AllocationSite in CSA.
BIND(&initialize_allocation_site);
{
allocation_site.Bind(AllocateAllocationSite(closure, literal_index));
Goto(&create_empty_array);
}
BIND(&create_empty_array);
CSA_ASSERT(this, IsAllocationSite(allocation_site.value()));
Node* kind = SmiToWord32(
LoadObjectField(allocation_site.value(),
AllocationSite::kTransitionInfoOrBoilerplateOffset));
CSA_ASSERT(this, IsFastElementsKind(kind));
Node* native_context = LoadNativeContext(context);
Comment("LoadJSArrayElementsMap");
Node* array_map = LoadJSArrayElementsMap(kind, native_context);
Node* zero = SmiConstant(0);
Comment("Allocate JSArray");
Node* result =
AllocateJSArray(GetInitialFastElementsKind(), array_map, zero, zero,
allocation_site.value(), ParameterMode::SMI_PARAMETERS);
Goto(&done);
BIND(&done);
return result;
}
TF_BUILTIN(CreateEmptyArrayLiteral, ConstructorBuiltinsAssembler) {
Node* closure = Parameter(CreateEmptyArrayLiteralDescriptor::kClosure);
Node* literal_index =
Parameter(CreateEmptyArrayLiteralDescriptor::kLiteralIndex);
Node* context = Parameter(CreateEmptyArrayLiteralDescriptor::kContext);
Node* result = EmitCreateEmptyArrayLiteral(closure, literal_index, context);
Return(result);
}
Node* ConstructorBuiltinsAssembler::EmitFastCloneShallowObject(
Label* call_runtime, Node* closure, Node* literals_index) {
Node* allocation_site = LoadFeedbackVectorSlot(closure, literals_index);

View File

@ -26,6 +26,8 @@ class ConstructorBuiltinsAssembler : public CodeStubAssembler {
Node* context, Label* call_runtime,
AllocationSiteMode allocation_site_mode);
Node* EmitCreateEmptyArrayLiteral(Node* closure, Node* iteral_index,
Node* context);
void CreateFastCloneShallowArrayBuiltin(
AllocationSiteMode allocation_site_mode);
@ -43,9 +45,12 @@ class ConstructorBuiltinsAssembler : public CodeStubAssembler {
Node* capacity, ElementsKind kind);
Node* CopyFixedArrayBase(Node* elements);
Node* LoadFeedbackVectorSlot(Node* closure, Node* literal_index);
Node* NotHasBoilerplate(Node* literal_site);
Node* LoadAllocationSiteBoilerplate(Node* allocation_site);
// Allocate an AllocationSite and store it at the {literal_index} in the
// feedback vector of the given {closure}.
Node* AllocateAllocationSite(Node* closure, Node* literal_index);
};
} // namespace internal

View File

@ -103,6 +103,7 @@ namespace internal {
TFC(FastCloneRegExp, FastCloneRegExp, 1) \
TFC(FastCloneShallowArrayTrack, FastCloneShallowArray, 1) \
TFC(FastCloneShallowArrayDontTrack, FastCloneShallowArray, 1) \
TFS(CreateEmptyArrayLiteral, kClosure, kLiteralIndex) \
TFC(FastCloneShallowObject, FastCloneShallowObject, 1) \
/* ES6 section 9.5.14 [[Construct]] ( argumentsList, newTarget) */ \
TFC(ConstructProxy, ConstructTrampoline, 1) \

View File

@ -1430,6 +1430,15 @@ Node* CodeStubAssembler::LoadNativeContext(Node* context) {
return LoadContextElement(context, Context::NATIVE_CONTEXT_INDEX);
}
Node* CodeStubAssembler::LoadJSArrayElementsMap(Node* kind,
Node* native_context) {
CSA_ASSERT(this, IsFastElementsKind(kind));
CSA_ASSERT(this, IsNativeContext(native_context));
Node* offset = IntPtrAdd(IntPtrConstant(Context::FIRST_JS_ARRAY_MAP_SLOT),
ChangeInt32ToIntPtr(kind));
return LoadContextElement(native_context, offset);
}
Node* CodeStubAssembler::LoadJSArrayElementsMap(ElementsKind kind,
Node* native_context) {
CSA_ASSERT(this, IsNativeContext(native_context));
@ -6316,11 +6325,30 @@ Node* CodeStubAssembler::ElementOffsetFromIndex(Node* index_node,
return IntPtrAdd(IntPtrConstant(base_size), shifted_index);
}
Node* CodeStubAssembler::LoadFeedbackVector(Node* closure) {
Node* cell = LoadObjectField(closure, JSFunction::kFeedbackVectorOffset);
return LoadObjectField(cell, Cell::kValueOffset);
}
Node* CodeStubAssembler::LoadFeedbackVectorForStub() {
Node* function =
LoadFromParentFrame(JavaScriptFrameConstants::kFunctionOffset);
Node* cell = LoadObjectField(function, JSFunction::kFeedbackVectorOffset);
return LoadObjectField(cell, Cell::kValueOffset);
return LoadFeedbackVector(function);
}
Node* CodeStubAssembler::LoadFeedbackVectorSlot(Node* closure,
Node* smi_index) {
Node* feedback_vector = LoadFeedbackVector(closure);
return LoadFixedArrayElement(feedback_vector, smi_index, 0,
CodeStubAssembler::SMI_PARAMETERS);
}
void CodeStubAssembler::StoreFeedbackVectorSlot(Node* closure, Node* smi_index,
Node* value) {
Node* feedback_vector = LoadFeedbackVector(closure);
StoreFixedArrayElement(feedback_vector, smi_index, value,
UPDATE_WRITE_BARRIER, 0,
CodeStubAssembler::SMI_PARAMETERS);
}
void CodeStubAssembler::UpdateFeedback(Node* feedback, Node* feedback_vector,

View File

@ -487,6 +487,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Node* LoadNativeContext(Node* context);
Node* LoadJSArrayElementsMap(ElementsKind kind, Node* native_context);
Node* LoadJSArrayElementsMap(Node* kind, Node* native_context);
// Load the "prototype" property of a JSFunction.
Node* LoadJSFunctionPrototype(Node* function, Label* if_bailout);
@ -1301,6 +1302,10 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
// Load type feedback vector from the stub caller's frame.
Node* LoadFeedbackVectorForStub();
Node* LoadFeedbackVector(Node* closure);
Node* LoadFeedbackVectorSlot(Node* closure, Node* smi_index);
void StoreFeedbackVectorSlot(Node* closure, Node* smi_index, Node* value);
// Update the type feedback vector.
void UpdateFeedback(Node* feedback, Node* feedback_vector, Node* slot_id,
Node* function);

View File

@ -1295,6 +1295,13 @@ void BytecodeGraphBuilder::VisitCreateArrayLiteral() {
environment()->BindAccumulator(literal, Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::VisitCreateEmptyArrayLiteral() {
int literal_index = bytecode_iterator().GetIndexOperand(0);
Node* literal = NewNode(javascript()->CreateEmptyLiteralArray(literal_index),
GetFunctionClosure());
environment()->BindAccumulator(literal);
}
void BytecodeGraphBuilder::VisitCreateObjectLiteral() {
Handle<BoilerplateDescription> constant_properties =
Handle<BoilerplateDescription>::cast(

View File

@ -221,6 +221,8 @@ Reduction JSCreateLowering::Reduce(Node* node) {
case IrOpcode::kJSCreateLiteralArray:
case IrOpcode::kJSCreateLiteralObject:
return ReduceJSCreateLiteral(node);
case IrOpcode::kJSCreateEmptyLiteralArray:
return ReduceJSCreateEmptyLiteralArray(node);
case IrOpcode::kJSCreateFunctionContext:
return ReduceJSCreateFunctionContext(node);
case IrOpcode::kJSCreateWithContext:
@ -621,7 +623,8 @@ Reduction JSCreateLowering::ReduceJSCreateGeneratorObject(Node* node) {
Reduction JSCreateLowering::ReduceNewArray(Node* node, Node* length,
int capacity,
Handle<AllocationSite> site) {
DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode());
DCHECK(node->opcode() == IrOpcode::kJSCreateArray ||
node->opcode() == IrOpcode::kJSCreateEmptyLiteralArray);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
@ -915,7 +918,23 @@ Reduction JSCreateLowering::ReduceJSCreateLiteral(Node* node) {
}
}
}
return NoChange();
}
Reduction JSCreateLowering::ReduceJSCreateEmptyLiteralArray(Node* node) {
DCHECK_EQ(node->opcode(), IrOpcode::kJSCreateEmptyLiteralArray);
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);
DCHECK(!site->PointsToLiteral());
Node* length = jsgraph()->ZeroConstant();
return ReduceNewArray(node, length, 0, site);
}
}
return NoChange();
}

View File

@ -54,6 +54,7 @@ class V8_EXPORT_PRIVATE JSCreateLowering final
Reduction ReduceJSCreateArray(Node* node);
Reduction ReduceJSCreateIterResultObject(Node* node);
Reduction ReduceJSCreateKeyValueArray(Node* node);
Reduction ReduceJSCreateEmptyLiteralArray(Node* node);
Reduction ReduceJSCreateLiteral(Node* node);
Reduction ReduceJSCreateFunctionContext(Node* node);
Reduction ReduceJSCreateWithContext(Node* node);

View File

@ -490,6 +490,14 @@ void JSGenericLowering::LowerJSCreateLiteralArray(Node* node) {
}
}
void JSGenericLowering::LowerJSCreateEmptyLiteralArray(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::kCreateEmptyArrayLiteral);
ReplaceWithStubCall(node, callable, flags);
}
void JSGenericLowering::LowerJSCreateLiteralObject(Node* node) {
CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());

View File

@ -1076,6 +1076,15 @@ const Operator* JSOperatorBuilder::CreateLiteralArray(
parameters); // parameter
}
const Operator* JSOperatorBuilder::CreateEmptyLiteralArray(int literal_index) {
return new (zone()) Operator1<int>( // --
IrOpcode::kJSCreateEmptyLiteralArray, // opcode
Operator::kNoProperties, // properties
"JSCreateEmptyLiteralArray", // name
1, 1, 1, 1, 1, 2, // counts
literal_index); // parameter
}
const Operator* JSOperatorBuilder::CreateLiteralObject(
Handle<BoilerplateDescription> constant_properties, int literal_flags,
int literal_index, int number_of_properties) {

View File

@ -682,6 +682,8 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
const Operator* CreateLiteralArray(Handle<ConstantElementsPair> constant,
int literal_flags, int literal_index,
int number_of_elements);
const Operator* CreateEmptyLiteralArray(int literal_index);
const Operator* CreateLiteralObject(Handle<BoilerplateDescription> constant,
int literal_flags, int literal_index,
int number_of_properties);

View File

@ -136,6 +136,7 @@
V(JSCreateIterResultObject) \
V(JSCreateKeyValueArray) \
V(JSCreateLiteralArray) \
V(JSCreateEmptyLiteralArray) \
V(JSCreateLiteralObject) \
V(JSCreateLiteralRegExp) \
V(JSLoadProperty) \

View File

@ -1141,6 +1141,9 @@ Type* Typer::Visitor::TypeJSCreateLiteralArray(Node* node) {
return Type::Array();
}
Type* Typer::Visitor::TypeJSCreateEmptyLiteralArray(Node* node) {
return Type::Array();
}
Type* Typer::Visitor::TypeJSCreateLiteralObject(Node* node) {
return Type::OtherObject();

View File

@ -622,6 +622,10 @@ void Verifier::Visitor::Check(Node* node) {
// Type is Array.
CheckTypeIs(node, Type::Array());
break;
case IrOpcode::kJSCreateEmptyLiteralArray:
// Type is Array.
CheckTypeIs(node, Type::Array());
break;
case IrOpcode::kJSCreateLiteralObject:
case IrOpcode::kJSCreateLiteralRegExp:
// Type is OtherObject.

View File

@ -954,6 +954,12 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CreateRegExpLiteral(
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::CreateEmptyArrayLiteral(
int literal_index) {
OutputCreateEmptyArrayLiteral(literal_index);
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArrayLiteral(
size_t constant_elements_entry, int literal_index, int flags) {
OutputCreateArrayLiteral(constant_elements_entry, literal_index, flags);

View File

@ -220,6 +220,7 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final
int literal_index, int flags);
BytecodeArrayBuilder& CreateArrayLiteral(size_t constant_elements_entry,
int literal_index, int flags);
BytecodeArrayBuilder& CreateEmptyArrayLiteral(int literal_index);
BytecodeArrayBuilder& CreateObjectLiteral(size_t constant_properties_entry,
int literal_index, int flags,
Register output);

View File

@ -2126,12 +2126,18 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
// Deep-copy the literal boilerplate.
int literal_index = feedback_index(expr->literal_slot());
if (expr->is_empty()) {
// Empty array literal fast-path.
DCHECK(expr->IsFastCloningSupported());
builder()->CreateEmptyArrayLiteral(literal_index);
return;
}
uint8_t flags = CreateArrayLiteralFlags::Encode(
expr->IsFastCloningSupported(), expr->ComputeFlags());
size_t entry = builder()->AllocateDeferredConstantPoolEntry();
builder()->CreateArrayLiteral(entry, feedback_index(expr->literal_slot()),
flags);
builder()->CreateArrayLiteral(entry, literal_index, flags);
array_literals_.push_back(std::make_pair(expr, entry));
Register index, literal;

View File

@ -233,6 +233,7 @@ namespace interpreter {
OperandType::kIdx, OperandType::kFlag8) \
V(CreateArrayLiteral, AccumulatorUse::kWrite, OperandType::kIdx, \
OperandType::kIdx, OperandType::kFlag8) \
V(CreateEmptyArrayLiteral, AccumulatorUse::kWrite, OperandType::kIdx) \
V(CreateObjectLiteral, AccumulatorUse::kNone, OperandType::kIdx, \
OperandType::kIdx, OperandType::kFlag8, OperandType::kRegOut) \
\
@ -343,7 +344,7 @@ namespace interpreter {
V(IncBlockCounter, AccumulatorUse::kNone, OperandType::kIdx) \
\
/* Illegal bytecode (terminates execution) */ \
V(Illegal, AccumulatorUse::kNone) \
V(Illegal, AccumulatorUse::kNone)
// List of debug break bytecodes.
#define DEBUG_BREAK_PLAIN_BYTECODE_LIST(V) \

View File

@ -2697,6 +2697,20 @@ IGNITION_HANDLER(CreateArrayLiteral, InterpreterAssembler) {
}
}
// CreateEmptyArrayLiteral <literal_idx>
//
// Creates an empty JSArray literal for literal index <literal_idx>.
IGNITION_HANDLER(CreateEmptyArrayLiteral, InterpreterAssembler) {
Node* literal_index = BytecodeOperandIdxSmi(0);
Node* closure = LoadRegister(Register::function_closure());
Node* context = GetContext();
ConstructorBuiltinsAssembler constructor_assembler(state());
Node* result = constructor_assembler.EmitCreateEmptyArrayLiteral(
closure, literal_index, context);
SetAccumulator(result);
Dispatch();
}
// CreateObjectLiteral <element_idx> <literal_idx> <flags>
//
// Creates an object literal for literal index <literal_idx> with

View File

@ -4421,6 +4421,9 @@ ACCESSORS(ContextExtension, extension, Object, kExtensionOffset)
SMI_ACCESSORS(ConstantElementsPair, elements_kind, kElementsKindOffset)
ACCESSORS(ConstantElementsPair, constant_values, FixedArrayBase,
kConstantValuesOffset)
bool ConstantElementsPair::is_empty() const {
return constant_values()->length() == 0;
}
ACCESSORS(JSModuleNamespace, module, Module, kModuleOffset)

View File

@ -45,6 +45,8 @@ class ConstantElementsPair : public Tuple2 {
DECL_INT_ACCESSORS(elements_kind)
DECL_ACCESSORS(constant_values, FixedArrayBase)
inline bool is_empty() const;
DECL_CAST(ConstantElementsPair)
static const int kElementsKindOffset = kValue1Offset;

View File

@ -16,8 +16,8 @@ namespace internal {
namespace {
bool IsUninitializedLiteralSite(Handle<Object> literal_site) {
return *literal_site == Smi::kZero;
bool IsUninitializedLiteralSite(Object* literal_site) {
return literal_site == Smi::kZero;
}
bool HasBoilerplate(Isolate* isolate, Handle<Object> literal_site) {
@ -478,7 +478,7 @@ MaybeHandle<JSObject> CreateLiteral(Isolate* isolate,
// TODO(cbruni): Even in the case where we need an initial allocation site
// we could still create the boilerplate lazily to save memory.
if (!needs_initial_allocation_site &&
IsUninitializedLiteralSite(literal_site)) {
IsUninitializedLiteralSite(*literal_site)) {
PreInitializeLiteralSite(vector, literals_slot);
boilerplate =
Boilerplate::Create(isolate, description, flags, NOT_TENURED);
@ -559,7 +559,7 @@ RUNTIME_FUNCTION(Runtime_CreateRegExpLiteral) {
if (!HasBoilerplate(isolate, literal_site)) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, boilerplate, JSRegExp::New(pattern, JSRegExp::Flags(flags)));
if (IsUninitializedLiteralSite(literal_site)) {
if (IsUninitializedLiteralSite(*literal_site)) {
PreInitializeLiteralSite(vector, literal_slot);
return *boilerplate;
}

View File

@ -2526,6 +2526,28 @@ TEST(DirectMemoryTest16BitWord32) {
CHECK_EQ(1, ft.CallChecked<Smi>()->value());
}
TEST(LoadJSArrayElementsMap) {
Isolate* isolate(CcTest::InitIsolateOnce());
const int kNumParams = 1;
CodeAssemblerTester asm_tester(isolate, kNumParams);
{
CodeStubAssembler m(asm_tester.state());
Node* context = m.Parameter(kNumParams + 2);
Node* native_context = m.LoadNativeContext(context);
Node* kind = m.SmiToWord32(m.Parameter(0));
m.Return(m.LoadJSArrayElementsMap(kind, native_context));
}
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
for (int kind = 0; kind <= HOLEY_DOUBLE_ELEMENTS; kind++) {
Handle<Map> csa_result =
ft.CallChecked<Map>(handle(Smi::FromInt(kind), isolate));
ElementsKind elements_kind = static_cast<ElementsKind>(kind);
Handle<Map> result(isolate->get_initial_js_array_map(elements_kind));
CHECK_EQ(*csa_result, *result);
}
}
} // namespace compiler
} // namespace internal
} // namespace v8

View File

@ -29,9 +29,9 @@
// Flags: --opt --no-always-opt --no-stress-fullcodegen
var elements_kind = {
fast_smi_only : 'fast smi only elements',
fast : 'fast elements',
fast_double : 'fast double elements',
packed_smi : 'packed smi elements',
packed : 'packed elements',
packed_double : 'packed double elements',
dictionary : 'dictionary elements',
external_byte : 'external byte elements',
external_unsigned_byte : 'external unsigned byte elements',
@ -45,9 +45,9 @@ var elements_kind = {
}
function getKind(obj) {
if (%HasSmiElements(obj)) return elements_kind.fast_smi_only;
if (%HasObjectElements(obj)) return elements_kind.fast;
if (%HasDoubleElements(obj)) return elements_kind.fast_double;
if (%HasSmiElements(obj)) return elements_kind.packed_smi;
if (%HasObjectElements(obj)) return elements_kind.packed;
if (%HasDoubleElements(obj)) return elements_kind.packed_double;
if (%HasDictionaryElements(obj)) return elements_kind.dictionary;
}
@ -93,7 +93,7 @@ assertOptimized(get_literal);
// Test: make sure allocation site information is updated through a
// transition from SMI->DOUBLE->FAST
// transition from SMI->DOUBLE->PACKED
(function() {
function bar(a, b, c) {
return [a, b, c];
@ -103,5 +103,132 @@ assertOptimized(get_literal);
a[0] = 3.5;
a[1] = 'hi';
b = bar(1, 2, 3);
assertKind(elements_kind.fast, b);
assertKind(elements_kind.packed, b);
})();
(function changeOptimizedEmptyArrayKind() {
function f() {
return new Array();
}
var a = f();
assertKind('packed smi elements', a);
a = f();
assertKind('packed smi elements', a);
a = f();
a.push(0.5);
assertKind('packed double elements', a);
%OptimizeFunctionOnNextCall(f);
a = f();
assertKind('packed double elements', a);
})();
(function changeOptimizedArrayLiteralKind() {
function f() {
return [1, 2];
}
var a = f();
assertKind('packed smi elements', a);
a = f();
a.push(0.5);
assertKind('packed double elements', a);
a = f();
assertKind('packed double elements', a);
assertFalse(isHoley(a));
a = f();
a.push(undefined);
assertKind('packed elements', a);
assertFalse(isHoley(a));
a = f();
assertKind('packed elements', a);
assertFalse(isHoley(a));
%OptimizeFunctionOnNextCall(f);
a = f();
assertKind('packed elements', a);
assertFalse(isHoley(a));
a = f();
assertKind('packed elements', a);
assertFalse(isHoley(a));
})();
(function changeOptimizedEmptyArrayLiteralKind() {
function f() {
return [];
}
var a = f();
assertKind('packed smi elements', a);
assertFalse(isHoley(a));
a = f();
a.push(0.5);
assertKind('packed double elements', a);
assertFalse(isHoley(a));
a = f();
assertKind('packed double elements', a);
assertFalse(isHoley(a));
%OptimizeFunctionOnNextCall(f);
a = f();
assertKind('packed double elements', a);
assertFalse(isHoley(a));
a = f();
assertKind('packed double elements', a);
assertFalse(isHoley(a));
})();
(function changeEmptyArrayLiteralKind2() {
function f() {
var literal = [];
%HeapObjectVerify(literal);
return literal;
}
var a = f();
assertKind('packed smi elements', a);
assertFalse(isHoley(a));
a = f();
a.push(0.5);
assertKind('packed double elements', a);
assertFalse(isHoley(a));
a = f();
assertKind('packed double elements', a);
assertFalse(isHoley(a));
a = f();
a.push(undefined);
assertKind('packed elements', a);
assertFalse(isHoley(a));
a = f();
assertKind('packed elements', a);
assertFalse(isHoley(a));
a = f();
a[10] = 1;
assertKind('packed elements', a);
assertTrue(isHoley(a));
a = f();
assertKind('packed elements', a);
assertTrue(isHoley(a));
a = f();
a[10000] = 1;
assertKind('dictionary elements', a);
assertFalse(isHoley(a));
a = f();
assertKind('packed elements', a);
assertTrue(isHoley(a));
})();

View File

@ -147,7 +147,7 @@ array = deopt_array_literal_all_smis(4);
assertEquals(0, array[0]);
assertEquals(1, array[1]);
assertEquals(4, array[2]);
%OptimizeFunctionOnNextCall(deopt_array_literal_all_smis);
%OptimizeFunctionOnNextCall(deopt_array_literal_all_smis);
array = deopt_array_literal_all_smis(5);
array = deopt_array_literal_all_smis(6);
assertOptimized(deopt_array_literal_all_smis);
@ -172,7 +172,7 @@ array = deopt_array_literal_all_doubles(0.5);
assertEquals(0.5, array[0]);
assertEquals(1, array[1]);
assertEquals(0.5, array[2]);
%OptimizeFunctionOnNextCall(deopt_array_literal_all_doubles);
%OptimizeFunctionOnNextCall(deopt_array_literal_all_doubles);
array = deopt_array_literal_all_doubles(5);
array = deopt_array_literal_all_doubles(6);
assertOptimized(deopt_array_literal_all_doubles);

View File

@ -354,6 +354,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
builder
.CreateRegExpLiteral(ast_factory.GetOneByteString("wide_literal"), 0, 0)
.CreateArrayLiteral(0, 0, 0)
.CreateEmptyArrayLiteral(0)
.CreateObjectLiteral(0, 0, 0, reg);
// Emit load and store operations for module variables.