Commit 2e2860f7 authored by Georg Neis's avatar Georg Neis Committed by Commit Bot

[ic] Introduce new IC for storing into array literals.

... and use it in the implementation of array literal spreads,
replacing calls to %AppendElement.

Array spreads in destructuring will be taken care of in a separate CL.

Bug: v8:5940, v8:7446
Change-Id: Idec52398902a7fd3c1244852cf73246f142404f0
Reviewed-on: https://chromium-review.googlesource.com/915364
Commit-Queue: Georg Neis <neis@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarMythri Alle <mythria@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51709}
parent 824358f0
......@@ -214,6 +214,7 @@ namespace internal {
TFH(LoadIC_Uninitialized, LoadWithVector) \
TFH(StoreGlobalIC_Slow, StoreWithVector) \
TFH(StoreIC_Uninitialized, StoreWithVector) \
TFH(StoreInArrayLiteralIC_Slow, StoreWithVector) \
\
/* Microtask helpers */ \
TFS(EnqueueMicrotask, kMicrotask) \
......@@ -598,6 +599,7 @@ namespace internal {
TFH(StoreICTrampoline, Store) \
TFH(KeyedStoreIC, StoreWithVector) \
TFH(KeyedStoreICTrampoline, Store) \
TFH(StoreInArrayLiteralIC, StoreWithVector) \
TFH(LoadGlobalIC, LoadGlobalWithVector) \
TFH(LoadGlobalICInsideTypeof, LoadGlobalWithVector) \
TFH(LoadGlobalICTrampoline, LoadGlobal) \
......
......@@ -55,6 +55,15 @@ TF_BUILTIN(KeyedStoreIC_Slow, CodeStubAssembler) {
receiver, name);
}
TF_BUILTIN(StoreInArrayLiteralIC_Slow, CodeStubAssembler) {
Node* array = Parameter(Descriptor::kReceiver);
Node* index = Parameter(Descriptor::kName);
Node* value = Parameter(Descriptor::kValue);
Node* context = Parameter(Descriptor::kContext);
TailCallRuntime(Runtime::kStoreInArrayLiteralIC_Slow, context, value, array,
index);
}
TF_BUILTIN(LoadGlobalIC_Slow, CodeStubAssembler) {
Node* name = Parameter(Descriptor::kName);
Node* slot = Parameter(Descriptor::kSlot);
......
......@@ -35,6 +35,7 @@ IC_BUILTIN(StoreIC)
IC_BUILTIN(StoreICTrampoline)
IC_BUILTIN(KeyedStoreIC)
IC_BUILTIN(KeyedStoreICTrampoline)
IC_BUILTIN(StoreInArrayLiteralIC)
IC_BUILTIN_PARAM(LoadGlobalIC, LoadGlobalIC, NOT_INSIDE_TYPEOF)
IC_BUILTIN_PARAM(LoadGlobalICInsideTypeof, LoadGlobalIC, INSIDE_TYPEOF)
......
......@@ -506,6 +506,15 @@ TF_STUB(StoreSlowElementStub, CodeStubAssembler) {
receiver, name);
}
TF_STUB(StoreInArrayLiteralSlowStub, CodeStubAssembler) {
Node* array = Parameter(Descriptor::kReceiver);
Node* index = Parameter(Descriptor::kName);
Node* value = Parameter(Descriptor::kValue);
Node* context = Parameter(Descriptor::kContext);
TailCallRuntime(Runtime::kStoreInArrayLiteralIC_Slow, context, value, array,
index);
}
TF_STUB(StoreFastElementStub, CodeStubAssembler) {
Comment("StoreFastElementStub: js_array=%d, elements_kind=%s, store_mode=%d",
stub->is_js_array(), ElementsKindToString(stub->elements_kind()),
......
......@@ -37,8 +37,9 @@ class Node;
V(JSEntry) \
V(MathPow) \
V(ProfileEntryHook) \
V(StoreSlowElement) \
/* --- TurboFanCodeStubs --- */ \
V(StoreSlowElement) \
V(StoreInArrayLiteralSlow) \
V(ArrayNoArgumentConstructor) \
V(ArraySingleArgumentConstructor) \
V(ArrayNArgumentsConstructor) \
......@@ -929,6 +930,18 @@ class StoreSlowElementStub : public TurboFanCodeStub {
DEFINE_TURBOFAN_CODE_STUB(StoreSlowElement, TurboFanCodeStub);
};
class StoreInArrayLiteralSlowStub : public TurboFanCodeStub {
public:
StoreInArrayLiteralSlowStub(Isolate* isolate, KeyedAccessStoreMode mode)
: TurboFanCodeStub(isolate) {
minor_key_ = CommonStoreModeBits::encode(mode);
}
private:
DEFINE_CALL_INTERFACE_DESCRIPTOR(StoreWithVector);
DEFINE_TURBOFAN_CODE_STUB(StoreInArrayLiteralSlow, TurboFanCodeStub);
};
class ElementsTransitionAndStoreStub : public TurboFanCodeStub {
public:
ElementsTransitionAndStoreStub(Isolate* isolate, ElementsKind from_kind,
......
......@@ -1007,6 +1007,32 @@ void BytecodeGraphBuilder::VisitStaGlobal() {
environment()->RecordAfterState(node, Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::VisitStaInArrayLiteral() {
PrepareEagerCheckpoint();
Node* value = environment()->LookupAccumulator();
Node* array =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
Node* index =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
VectorSlotPair feedback =
CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(2));
const Operator* op = javascript()->StoreInArrayLiteral(feedback);
JSTypeHintLowering::LoweringResult lowering =
TryBuildSimplifiedStoreKeyed(op, array, index, value, feedback.slot());
if (lowering.IsExit()) return;
Node* node = nullptr;
if (lowering.IsSideEffectFree()) {
node = lowering.value();
} else {
DCHECK(!lowering.Changed());
node = NewNode(op, array, index, value);
}
environment()->RecordAfterState(node, Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::VisitStaDataPropertyInLiteral() {
PrepareEagerCheckpoint();
......
......@@ -279,6 +279,16 @@ void JSGenericLowering::LowerJSStoreDataPropertyInLiteral(Node* node) {
ReplaceWithRuntimeCall(node, Runtime::kDefineDataPropertyInLiteral);
}
void JSGenericLowering::LowerJSStoreInArrayLiteral(Node* node) {
Callable callable =
Builtins::CallableFor(isolate(), Builtins::kStoreInArrayLiteralIC);
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
FeedbackParameter const& p = FeedbackParameterOf(node->op());
node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.feedback().index()));
node->InsertInput(zone(), 4, jsgraph()->HeapConstant(p.feedback().vector()));
ReplaceWithStubCall(node, callable, flags);
}
void JSGenericLowering::LowerJSDeleteProperty(Node* node) {
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
Callable callable =
......
......@@ -98,6 +98,8 @@ Reduction JSNativeContextSpecialization::Reduce(Node* node) {
return ReduceJSStoreNamedOwn(node);
case IrOpcode::kJSStoreDataPropertyInLiteral:
return ReduceJSStoreDataPropertyInLiteral(node);
case IrOpcode::kJSStoreInArrayLiteral:
return ReduceJSStoreInArrayLiteral(node);
default:
break;
}
......@@ -1126,7 +1128,8 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
AccessMode access_mode, KeyedAccessLoadMode load_mode,
KeyedAccessStoreMode store_mode) {
DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
node->opcode() == IrOpcode::kJSStoreProperty);
node->opcode() == IrOpcode::kJSStoreProperty ||
node->opcode() == IrOpcode::kJSStoreInArrayLiteral);
Node* receiver = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
......@@ -2091,6 +2094,45 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreDataPropertyInLiteral(
return Replace(value);
}
Reduction JSNativeContextSpecialization::ReduceJSStoreInArrayLiteral(
Node* node) {
DCHECK_EQ(IrOpcode::kJSStoreInArrayLiteral, node->opcode());
FeedbackParameter const& p = FeedbackParameterOf(node->op());
Node* const receiver = NodeProperties::GetValueInput(node, 0);
Node* const index = NodeProperties::GetValueInput(node, 1);
Node* const value = NodeProperties::GetValueInput(node, 2);
Node* const effect = NodeProperties::GetEffectInput(node);
// Extract receiver maps from the keyed store IC using the FeedbackNexus.
if (!p.feedback().IsValid()) return NoChange();
FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
// Extract the keyed access store mode from the keyed store IC.
KeyedAccessStoreMode store_mode = nexus.GetKeyedAccessStoreMode();
// Extract receiver maps from the {nexus}.
MapHandles receiver_maps;
if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
return NoChange();
} else if (receiver_maps.empty()) {
if (flags() & kBailoutOnUninitialized) {
return ReduceSoftDeoptimize(
node,
DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess);
}
return NoChange();
}
DCHECK(!nexus.IsUninitialized());
DCHECK_EQ(ELEMENT, nexus.GetKeyType());
if (nexus.ic_state() == MEGAMORPHIC) return NoChange();
// Try to lower the element access based on the {receiver_maps}.
return ReduceElementAccess(node, index, value, receiver_maps,
AccessMode::kStoreInLiteral, STANDARD_LOAD,
store_mode);
}
namespace {
ExternalArrayType GetArrayTypeFromElementsKind(ElementsKind kind) {
......@@ -2113,7 +2155,6 @@ JSNativeContextSpecialization::BuildElementAccess(
Node* receiver, Node* index, Node* value, Node* effect, Node* control,
ElementAccessInfo const& access_info, AccessMode access_mode,
KeyedAccessLoadMode load_mode, KeyedAccessStoreMode store_mode) {
DCHECK_NE(AccessMode::kStoreInLiteral, access_mode);
// TODO(bmeurer): We currently specialize based on elements kind. We should
// also be able to properly support strings and other JSObjects here.
......@@ -2346,7 +2387,8 @@ JSNativeContextSpecialization::BuildElementAccess(
// Check if we might need to grow the {elements} backing store.
if (IsGrowStoreMode(store_mode)) {
// For growing stores we validate the {index} below.
DCHECK_EQ(AccessMode::kStore, access_mode);
DCHECK(access_mode == AccessMode::kStore ||
access_mode == AccessMode::kStoreInLiteral);
} else if (load_mode == LOAD_IGNORE_OUT_OF_BOUNDS &&
CanTreatHoleAsUndefined(receiver_maps)) {
// Check that the {index} is a valid array index, we do the actual
......@@ -2478,7 +2520,8 @@ JSNativeContextSpecialization::BuildElementAccess(
}
}
} else {
DCHECK_EQ(AccessMode::kStore, access_mode);
DCHECK(access_mode == AccessMode::kStore ||
access_mode == AccessMode::kStoreInLiteral);
if (IsSmiElementsKind(elements_kind)) {
value = effect = graph()->NewNode(
simplified()->CheckSmi(VectorSlotPair()), value, effect, control);
......
......@@ -73,6 +73,7 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
Reduction ReduceJSStoreProperty(Node* node);
Reduction ReduceJSStoreNamedOwn(Node* node);
Reduction ReduceJSStoreDataPropertyInLiteral(Node* node);
Reduction ReduceJSStoreInArrayLiteral(Node* node);
Reduction ReduceElementAccess(Node* node, Node* index, Node* value,
MapHandles const& receiver_maps,
......
......@@ -258,7 +258,8 @@ std::ostream& operator<<(std::ostream& os, FeedbackParameter const& p) {
FeedbackParameter const& FeedbackParameterOf(const Operator* op) {
DCHECK(op->opcode() == IrOpcode::kJSCreateEmptyLiteralArray ||
op->opcode() == IrOpcode::kJSInstanceOf ||
op->opcode() == IrOpcode::kJSStoreDataPropertyInLiteral);
op->opcode() == IrOpcode::kJSStoreDataPropertyInLiteral ||
op->opcode() == IrOpcode::kJSStoreInArrayLiteral);
return OpParameter<FeedbackParameter>(op);
}
......@@ -745,6 +746,17 @@ const Operator* JSOperatorBuilder::StoreDataPropertyInLiteral(
parameters); // parameter
}
const Operator* JSOperatorBuilder::StoreInArrayLiteral(
const VectorSlotPair& feedback) {
FeedbackParameter parameters(feedback);
return new (zone()) Operator1<FeedbackParameter>( // --
IrOpcode::kJSStoreInArrayLiteral,
Operator::kNoThrow, // opcode
"JSStoreInArrayLiteral", // name
3, 1, 1, 0, 1, 0, // counts
parameters); // parameter
}
const Operator* JSOperatorBuilder::CallForwardVarargs(size_t arity,
uint32_t start_index) {
CallForwardVarargsParameters parameters(arity, start_index);
......
......@@ -714,6 +714,7 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
const Operator* StoreNamedOwn(Handle<Name> name,
VectorSlotPair const& feedback);
const Operator* StoreDataPropertyInLiteral(const VectorSlotPair& feedback);
const Operator* StoreInArrayLiteral(const VectorSlotPair& feedback);
const Operator* DeleteProperty();
......
......@@ -477,7 +477,8 @@ JSTypeHintLowering::ReduceStoreKeyedOperation(const Operator* op, Node* obj,
Node* key, Node* val,
Node* effect, Node* control,
FeedbackSlot slot) const {
DCHECK_EQ(IrOpcode::kJSStoreProperty, op->opcode());
DCHECK(op->opcode() == IrOpcode::kJSStoreProperty ||
op->opcode() == IrOpcode::kJSStoreInArrayLiteral);
DCHECK(!slot.IsInvalid());
FeedbackNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
......
......@@ -159,6 +159,7 @@
V(JSStoreNamedOwn) \
V(JSStoreGlobal) \
V(JSStoreDataPropertyInLiteral) \
V(JSStoreInArrayLiteral) \
V(JSDeleteProperty) \
V(JSHasProperty) \
V(JSGetSuperConstructor)
......
......@@ -1374,6 +1374,8 @@ Type* Typer::Visitor::TypeJSStoreDataPropertyInLiteral(Node* node) {
UNREACHABLE();
}
Type* Typer::Visitor::TypeJSStoreInArrayLiteral(Node* node) { UNREACHABLE(); }
Type* Typer::Visitor::TypeJSDeleteProperty(Node* node) {
return Type::Boolean();
}
......
......@@ -739,8 +739,10 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
CHECK(StoreNamedOwnParametersOf(node->op()).feedback().IsValid());
break;
case IrOpcode::kJSStoreDataPropertyInLiteral:
case IrOpcode::kJSStoreInArrayLiteral:
// Type is empty.
CheckNotTyped(node);
CHECK(FeedbackParameterOf(node->op()).feedback().IsValid());
break;
case IrOpcode::kJSDeleteProperty:
case IrOpcode::kJSHasProperty:
......
......@@ -933,6 +933,7 @@ class RuntimeCallTimer final {
V(KeyedStoreIC_SlowStub) \
V(KeyedStoreIC_StoreFastElementStub) \
V(KeyedStoreIC_StoreElementStub) \
V(StoreInArrayLiteralIC_SlowStub) \
V(LoadGlobalIC_LoadScriptContextField) \
V(LoadGlobalIC_SlowStub) \
V(LoadIC_FunctionPrototypeStub) \
......
......@@ -64,6 +64,7 @@ int FeedbackMetadata::GetSlotSize(FeedbackSlotKind kind) {
case FeedbackSlotKind::kStoreGlobalStrict:
case FeedbackSlotKind::kStoreKeyedSloppy:
case FeedbackSlotKind::kStoreKeyedStrict:
case FeedbackSlotKind::kStoreInArrayLiteral:
case FeedbackSlotKind::kStoreDataPropertyInLiteral:
return 2;
......@@ -247,6 +248,7 @@ void FeedbackVector::ComputeCounts(int* with_type_info, int* generic,
case FeedbackSlotKind::kStoreGlobalStrict:
case FeedbackSlotKind::kStoreKeyedSloppy:
case FeedbackSlotKind::kStoreKeyedStrict:
case FeedbackSlotKind::kStoreInArrayLiteral:
case FeedbackSlotKind::kStoreDataPropertyInLiteral:
case FeedbackSlotKind::kTypeProfile: {
if (obj->IsWeakCell() || obj->IsFixedArray() || obj->IsString()) {
......
......@@ -163,6 +163,8 @@ const char* FeedbackMetadata::Kind2String(FeedbackSlotKind kind) {
return "StoreKeyedSloppy";
case FeedbackSlotKind::kStoreKeyedStrict:
return "StoreKeyedStrict";
case FeedbackSlotKind::kStoreInArrayLiteral:
return "StoreInArrayLiteral";
case FeedbackSlotKind::kBinaryOp:
return "BinaryOp";
case FeedbackSlotKind::kCompareOp:
......@@ -268,6 +270,7 @@ Handle<FeedbackVector> FeedbackVector::New(Isolate* isolate,
case FeedbackSlotKind::kStoreOwnNamed:
case FeedbackSlotKind::kStoreKeyedSloppy:
case FeedbackSlotKind::kStoreKeyedStrict:
case FeedbackSlotKind::kStoreInArrayLiteral:
case FeedbackSlotKind::kStoreDataPropertyInLiteral:
case FeedbackSlotKind::kTypeProfile:
case FeedbackSlotKind::kInstanceOf:
......@@ -469,6 +472,7 @@ bool FeedbackNexus::Clear() {
case FeedbackSlotKind::kStoreNamedStrict:
case FeedbackSlotKind::kStoreKeyedSloppy:
case FeedbackSlotKind::kStoreKeyedStrict:
case FeedbackSlotKind::kStoreInArrayLiteral:
case FeedbackSlotKind::kStoreOwnNamed:
case FeedbackSlotKind::kLoadProperty:
case FeedbackSlotKind::kLoadKeyed:
......@@ -548,10 +552,12 @@ InlineCacheState FeedbackNexus::StateFromFeedback() const {
}
return UNINITIALIZED;
}
case FeedbackSlotKind::kStoreNamedSloppy:
case FeedbackSlotKind::kStoreNamedStrict:
case FeedbackSlotKind::kStoreKeyedSloppy:
case FeedbackSlotKind::kStoreKeyedStrict:
case FeedbackSlotKind::kStoreInArrayLiteral:
case FeedbackSlotKind::kStoreOwnNamed:
case FeedbackSlotKind::kLoadProperty:
case FeedbackSlotKind::kLoadKeyed: {
......@@ -773,7 +779,8 @@ void FeedbackNexus::ConfigurePolymorphic(Handle<Name> name,
int FeedbackNexus::ExtractMaps(MapHandles* maps) const {
DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()));
IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) ||
IsStoreInArrayLiteralICKind(kind()));
Isolate* isolate = GetIsolate();
Object* feedback = GetFeedback();
......@@ -851,7 +858,8 @@ MaybeHandle<Object> FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
bool FeedbackNexus::FindHandlers(ObjectHandles* code_list, int length) const {
DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()));
IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) ||
IsStoreInArrayLiteralICKind(kind()));
Object* feedback = GetFeedback();
Isolate* isolate = GetIsolate();
......@@ -914,7 +922,7 @@ KeyedAccessLoadMode FeedbackNexus::GetKeyedAccessLoadMode() const {
}
KeyedAccessStoreMode FeedbackNexus::GetKeyedAccessStoreMode() const {
DCHECK(IsKeyedStoreICKind(kind()));
DCHECK(IsKeyedStoreICKind(kind()) || IsStoreInArrayLiteralICKind(kind()));
KeyedAccessStoreMode mode = STANDARD_STORE;
MapHandles maps;
ObjectHandles handlers;
......@@ -956,7 +964,8 @@ KeyedAccessStoreMode FeedbackNexus::GetKeyedAccessStoreMode() const {
}
IcCheckType FeedbackNexus::GetKeyType() const {
DCHECK(IsKeyedStoreICKind(kind()) || IsKeyedLoadICKind(kind()));
DCHECK(IsKeyedStoreICKind(kind()) || IsKeyedLoadICKind(kind()) ||
IsStoreInArrayLiteralICKind(kind()));
Object* feedback = GetFeedback();
if (feedback == *FeedbackVector::MegamorphicSentinel(GetIsolate())) {
return static_cast<IcCheckType>(Smi::ToInt(GetFeedbackExtra()));
......
......@@ -42,6 +42,7 @@ enum class FeedbackSlotKind {
kStoreNamedStrict,
kStoreOwnNamed,
kStoreKeyedStrict,
kStoreInArrayLiteral,
kBinaryOp,
kCompareOp,
kStoreDataPropertyInLiteral,
......@@ -94,6 +95,10 @@ inline bool IsKeyedStoreICKind(FeedbackSlotKind kind) {
kind == FeedbackSlotKind::kStoreKeyedStrict;
}
inline bool IsStoreInArrayLiteralICKind(FeedbackSlotKind kind) {
return kind == FeedbackSlotKind::kStoreInArrayLiteral;
}
inline bool IsGlobalICKind(FeedbackSlotKind kind) {
return IsLoadGlobalICKind(kind) || IsStoreGlobalICKind(kind);
}
......@@ -364,6 +369,10 @@ class V8_EXPORT_PRIVATE FeedbackVectorSpec {
: FeedbackSlotKind::kStoreKeyedSloppy);
}
FeedbackSlot AddStoreInArrayLiteralICSlot() {
return AddSlot(FeedbackSlotKind::kStoreInArrayLiteral);
}
FeedbackSlot AddBinaryOpICSlot() {
return AddSlot(FeedbackSlotKind::kBinaryOp);
}
......
......@@ -2840,6 +2840,86 @@ void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p) {
}
}
void AccessorAssembler::StoreInArrayLiteralIC(const StoreICParameters* p) {
Label miss(this, Label::kDeferred);
{
VARIABLE(var_handler, MachineRepresentation::kTagged);
Label if_handler(this, &var_handler),
try_polymorphic(this, Label::kDeferred),
try_megamorphic(this, Label::kDeferred);
Node* array_map = LoadReceiverMap(p->receiver);
GotoIf(IsDeprecatedMap(array_map), &miss);
Node* feedback =
TryMonomorphicCase(p->slot, p->vector, array_map, &if_handler,
&var_handler, &try_polymorphic);
BIND(&if_handler);
{
Comment("StoreInArrayLiteralIC_if_handler");
// This is a stripped-down version of HandleStoreICHandlerCase.
Node* handler = var_handler.value();
Label if_transitioning_element_store(this);
GotoIfNot(IsCode(handler), &if_transitioning_element_store);
StoreWithVectorDescriptor descriptor(isolate());
TailCallStub(descriptor, handler, p->context, p->receiver, p->name,
p->value, p->slot, p->vector);
BIND(&if_transitioning_element_store);
{
Node* transition_map_cell = LoadHandlerDataField(handler, 1);
Node* transition_map = LoadWeakCellValue(transition_map_cell, &miss);
CSA_ASSERT(this, IsMap(transition_map));
GotoIf(IsDeprecatedMap(transition_map), &miss);
Node* code = LoadObjectField(handler, StoreHandler::kSmiHandlerOffset);
CSA_ASSERT(this, IsCode(code));
StoreTransitionDescriptor descriptor(isolate());
TailCallStub(descriptor, code, p->context, p->receiver, p->name,
transition_map, p->value, p->slot, p->vector);
}
}
BIND(&try_polymorphic);
{
Comment("StoreInArrayLiteralIC_try_polymorphic");
GotoIfNot(
WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)),
&try_megamorphic);
HandlePolymorphicCase(array_map, feedback, &if_handler, &var_handler,
&miss, 2);
}
BIND(&try_megamorphic);
{
Comment("StoreInArrayLiteralIC_try_megamorphic");
CSA_ASSERT(
this,
Word32Or(
Word32Or(
IsWeakCellMap(LoadMap(feedback)),
WordEqual(feedback,
LoadRoot(Heap::kuninitialized_symbolRootIndex))),
WordEqual(feedback,
LoadRoot(Heap::kmegamorphic_symbolRootIndex))));
GotoIfNot(
WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
&miss);
TailCallRuntime(Runtime::kStoreInArrayLiteralIC_Slow, p->context,
p->value, p->receiver, p->name);
}
}
BIND(&miss);
{
Comment("StoreInArrayLiteralIC_miss");
// TODO(neis): Introduce Runtime::kStoreInArrayLiteralIC_Miss.
TailCallRuntime(Runtime::kKeyedStoreIC_Miss, p->context, p->value, p->slot,
p->vector, p->receiver, p->name);
}
}
//////////////////// Public methods.
void AccessorAssembler::GenerateLoadIC() {
......@@ -3096,5 +3176,19 @@ void AccessorAssembler::GenerateKeyedStoreICTrampoline() {
TailCallStub(callable, context, receiver, name, value, slot, vector);
}
void AccessorAssembler::GenerateStoreInArrayLiteralIC() {
typedef StoreWithVectorDescriptor Descriptor;
Node* array = Parameter(Descriptor::kReceiver);
Node* index = Parameter(Descriptor::kName);
Node* value = Parameter(Descriptor::kValue);
Node* slot = Parameter(Descriptor::kSlot);
Node* vector = Parameter(Descriptor::kVector);
Node* context = Parameter(Descriptor::kContext);
StoreICParameters p(context, array, index, value, slot, vector);
StoreInArrayLiteralIC(&p);
}
} // namespace internal
} // namespace v8
......@@ -43,6 +43,8 @@ class AccessorAssembler : public CodeStubAssembler {
void GenerateKeyedStoreIC();
void GenerateKeyedStoreICTrampoline();
void GenerateStoreInArrayLiteralIC();
void TryProbeStubCache(StubCache* stub_cache, Node* receiver, Node* name,
Label* if_handler, Variable* var_handler,
Label* if_miss);
......@@ -127,6 +129,7 @@ class AccessorAssembler : public CodeStubAssembler {
void StoreGlobalIC_PropertyCellCase(Node* property_cell, Node* value,
ExitPoint* exit_point, Label* miss);
void KeyedStoreIC(const StoreICParameters* p);
void StoreInArrayLiteralIC(const StoreICParameters* p);
// IC dispatcher behavior.
......
......@@ -95,14 +95,16 @@ void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
if (IsKeyedLoadIC()) {
KeyedAccessLoadMode mode = nexus()->GetKeyedAccessLoadMode();
modifier = GetModifier(mode);
} else if (IsKeyedStoreIC()) {
} else if (IsKeyedStoreIC() || IsStoreInArrayLiteralICKind(kind())) {
KeyedAccessStoreMode mode = nexus()->GetKeyedAccessStoreMode();
modifier = GetModifier(mode);
}
bool keyed_prefix = is_keyed() && !IsStoreInArrayLiteralICKind(kind());
if (!(FLAG_ic_stats &
v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING)) {
LOG(isolate(), ICEvent(type, is_keyed(), map, *name,
LOG(isolate(), ICEvent(type, keyed_prefix, map, *name,
TransitionMarkFromState(old_state),
TransitionMarkFromState(new_state), modifier,
slow_stub_reason_));
......@@ -111,7 +113,7 @@ void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
ICStats::instance()->Begin();
ICInfo& ic_info = ICStats::instance()->Current();
ic_info.type = is_keyed() ? "Keyed" : "";
ic_info.type = keyed_prefix ? "Keyed" : "";
ic_info.type += type;
Object* maybe_function =
......@@ -1690,6 +1692,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
for (Handle<Map> map : target_receiver_maps) {
if (!map.is_null() && map->instance_type() == JS_VALUE_TYPE) {
DCHECK(!IsStoreInArrayLiteralICKind(kind()));
set_slow_stub_reason("JSValue");
return;
}
......@@ -1776,11 +1779,13 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
size_t external_arrays = 0;
for (Handle<Map> map : target_receiver_maps) {
if (map->has_fixed_typed_array_elements()) {
DCHECK(!IsStoreInArrayLiteralICKind(kind()));
external_arrays++;
}
}
if (external_arrays != 0 &&
external_arrays != target_receiver_maps.size()) {
DCHECK(!IsStoreInArrayLiteralICKind(kind()));
set_slow_stub_reason(
"unsupported combination of external and normal arrays");
return;
......@@ -1834,7 +1839,8 @@ Handle<Object> KeyedStoreIC::StoreElementHandler(
store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW ||
store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
store_mode == STORE_NO_TRANSITION_HANDLE_COW);
DCHECK(!receiver_map->DictionaryElementsInPrototypeChainOnly());
DCHECK_IMPLIES(receiver_map->DictionaryElementsInPrototypeChainOnly(),
IsStoreInArrayLiteralICKind(kind()));
if (receiver_map->IsJSProxyMap()) {
return StoreHandler::StoreProxy(isolate());
......@@ -1854,11 +1860,17 @@ Handle<Object> KeyedStoreIC::StoreElementHandler(
StoreFastElementStub(isolate(), is_jsarray, elements_kind, store_mode)
.GetCode();
if (receiver_map->has_fixed_typed_array_elements()) return stub;
} else if (IsStoreInArrayLiteralICKind(kind())) {
TRACE_HANDLER_STATS(isolate(), StoreInArrayLiteralIC_SlowStub);
stub = StoreInArrayLiteralSlowStub(isolate(), store_mode).GetCode();
} else {
TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreElementStub);
DCHECK_EQ(DICTIONARY_ELEMENTS, elements_kind);
stub = StoreSlowElementStub(isolate(), store_mode).GetCode();
}
if (IsStoreInArrayLiteralICKind(kind())) return stub;
Handle<Object> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
if (validity_cell.is_null()) return stub;
......@@ -1892,7 +1904,7 @@ void KeyedStoreIC::StoreElementPolymorphicHandlers(
// TODO(mvstanton): Consider embedding store_mode in the state of the slow
// keyed store ic for uniformity.
TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_SlowStub);
handler = BUILTIN_CODE(isolate(), KeyedStoreIC_Slow);
handler = slow_stub();
} else {
{
......@@ -2092,7 +2104,56 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
return store_handle;
}
namespace {
void StoreOwnElement(Handle<JSArray> array, Handle<Object> index,
Handle<Object> value) {
DCHECK(index->IsNumber());
bool success = false;
LookupIterator it = LookupIterator::PropertyOrElement(
array->GetIsolate(), array, index, &success, LookupIterator::OWN);
DCHECK(success);
CHECK(JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE,
kThrowOnError)
.FromJust());
}
} // namespace
void StoreInArrayLiteralIC::Store(Handle<JSArray> array, Handle<Object> index,
Handle<Object> value) {
DCHECK(!array->map()->IsMapInArrayPrototypeChain());
DCHECK(index->IsNumber());
if (!FLAG_use_ic || MigrateDeprecated(array)) {
StoreOwnElement(array, index, value);
TraceIC("StoreInArrayLiteralIC", index);
return;
}
// TODO(neis): Convert HeapNumber to Smi if possible?
KeyedAccessStoreMode store_mode = STANDARD_STORE;
if (index->IsSmi()) {
DCHECK_GE(Smi::ToInt(*index), 0);
uint32_t index32 = static_cast<uint32_t>(Smi::ToInt(*index));
store_mode = GetStoreMode(array, index32, value);
}
Handle<Map> old_array_map(array->map(), isolate());
StoreOwnElement(array, index, value);
if (index->IsSmi()) {
DCHECK(!old_array_map->is_abandoned_prototype_map());
UpdateStoreElement(old_array_map, store_mode);
} else {
set_slow_stub_reason("index out of Smi range");
}
if (vector_needs_update()) {
ConfigureVectorState(MEGAMORPHIC, index);
}
TraceIC("StoreInArrayLiteralIC", index);
}
// ----------------------------------------------------------------------------
// Static IC stub generators.
......@@ -2312,11 +2373,24 @@ RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) {
Handle<Object> receiver = args.at(3);
Handle<Object> key = args.at(4);
FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
KeyedStoreIC ic(isolate, vector, vector_slot);
ic.UpdateState(receiver, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
}
FeedbackSlotKind kind = vector->GetKind(vector_slot);
// The elements store stubs miss into this function, but they are shared by
// different ICs.
if (IsKeyedStoreICKind(kind)) {
KeyedStoreIC ic(isolate, vector, vector_slot);
ic.UpdateState(receiver, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
} else {
DCHECK(IsStoreInArrayLiteralICKind(kind));
DCHECK(receiver->IsJSArray());
DCHECK(key->IsNumber());
StoreInArrayLiteralIC ic(isolate, vector, vector_slot);
ic.UpdateState(receiver, key);
ic.Store(Handle<JSArray>::cast(receiver), key, value);
return *value;
}
}
RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) {
HandleScope scope(isolate);
......@@ -2328,12 +2402,24 @@ RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) {
Handle<Object> object = args.at(3);
Handle<Object> key = args.at(4);
FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
LanguageMode language_mode = vector->GetLanguageMode(vector_slot);
FeedbackSlotKind kind = vector->GetKind(vector_slot);
DCHECK(IsStoreICKind(kind) || IsKeyedStoreICKind(kind));
LanguageMode language_mode = GetLanguageModeFromSlotKind(kind);
RETURN_RESULT_OR_FAILURE(
isolate,
Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
}
RUNTIME_FUNCTION(Runtime_StoreInArrayLiteralIC_Slow) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
// Runtime functions don't follow the IC's calling convention.
Handle<Object> value = args.at(0);
Handle<Object> array = args.at(1);
Handle<Object> index = args.at(2);
StoreOwnElement(Handle<JSArray>::cast(array), index, value);
return *value;
}
RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) {
HandleScope scope(isolate);
......@@ -2346,14 +2432,23 @@ RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) {
Handle<Smi> slot = args.at<Smi>(4);
Handle<FeedbackVector> vector = args.at<FeedbackVector>(5);
FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
LanguageMode language_mode = vector->GetLanguageMode(vector_slot);
FeedbackSlotKind kind = vector->GetKind(vector_slot);
if (object->IsJSObject()) {
JSObject::TransitionElementsKind(Handle<JSObject>::cast(object),
map->elements_kind());
}
RETURN_RESULT_OR_FAILURE(
isolate,
Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
if (IsStoreInArrayLiteralICKind(kind)) {
StoreOwnElement(Handle<JSArray>::cast(object), key, value);
return *value;
} else {
DCHECK(IsKeyedStoreICKind(kind) || IsStoreICKind(kind));
LanguageMode language_mode = GetLanguageModeFromSlotKind(kind);
RETURN_RESULT_OR_FAILURE(
isolate,
Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
}
}
......
......@@ -58,7 +58,7 @@ class IC {
}
bool IsAnyStore() const {
return IsStoreIC() || IsStoreOwnIC() || IsStoreGlobalIC() ||
IsKeyedStoreIC();
IsKeyedStoreIC() || IsStoreInArrayLiteralICKind(kind());
}
static inline bool IsHandler(Object* object);
......@@ -131,7 +131,10 @@ class IC {
bool IsStoreIC() const { return IsStoreICKind(kind_); }
bool IsStoreOwnIC() const { return IsStoreOwnICKind(kind_); }
bool IsKeyedStoreIC() const { return IsKeyedStoreICKind(kind_); }
bool is_keyed() const { return IsKeyedLoadIC() || IsKeyedStoreIC(); }
bool is_keyed() const {
return IsKeyedLoadIC() || IsKeyedStoreIC() ||
IsStoreInArrayLiteralICKind(kind_);
}
bool ShouldRecomputeHandler(Handle<String> name);
Handle<Map> receiver_map() { return receiver_map_; }
......@@ -368,6 +371,10 @@ class KeyedStoreIC : public StoreIC {
void UpdateStoreElement(Handle<Map> receiver_map,
KeyedAccessStoreMode store_mode);
Handle<Code> slow_stub() const override {
return BUILTIN_CODE(isolate(), KeyedStoreIC_Slow);
}
private:
Handle<Map> ComputeTransitionedMap(Handle<Map> map,
KeyedAccessStoreMode store_mode);
......@@ -382,6 +389,22 @@ class KeyedStoreIC : public StoreIC {
friend class IC;
};
class StoreInArrayLiteralIC : public KeyedStoreIC {
public:
StoreInArrayLiteralIC(Isolate* isolate, Handle<FeedbackVector> vector,
FeedbackSlot slot)
: KeyedStoreIC(isolate, vector, slot) {
DCHECK(IsStoreInArrayLiteralICKind(kind()));
}
void Store(Handle<JSArray> array, Handle<Object> index, Handle<Object> value);
private:
Handle<Code> slow_stub() const override {
return BUILTIN_CODE(isolate(), StoreInArrayLiteralIC_Slow);
}
};
} // namespace internal
} // namespace v8
......
......@@ -864,6 +864,12 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreKeyedProperty(
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::StoreInArrayLiteral(
Register array, Register index, int feedback_slot) {
OutputStaInArrayLiteral(array, index, feedback_slot);
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::StoreHomeObjectProperty(
Register object, int feedback_slot, LanguageMode language_mode) {
size_t name_index = HomeObjectSymbolConstantPoolEntry();
......
......@@ -160,6 +160,10 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final {
BytecodeArrayBuilder& StoreKeyedProperty(Register object, Register key,
int feedback_slot,
LanguageMode language_mode);
// Store an own element in an array literal. The value to be stored should be
// in the accumulator.
BytecodeArrayBuilder& StoreInArrayLiteral(Register array, Register index,
int feedback_slot);
// Store the home object property. The value to be stored should be in the
// accumulator.
BytecodeArrayBuilder& StoreHomeObjectProperty(Register object,
......
......@@ -2300,17 +2300,18 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
builder()->CreateArrayLiteral(entry, literal_index, flags);
array_literals_.push_back(std::make_pair(expr, entry));
Register index = register_allocator()->NewRegister();
Register literal = register_allocator()->NewRegister();
builder()->StoreAccumulatorInRegister(literal);
// We'll reuse the same literal slot for all of the non-constant
// subexpressions that use a keyed store IC.
Register index = register_allocator()->NewRegister();
int array_index = 0;
// Evaluate all the non-constant subexpressions and store them into the
// newly cloned array.
FeedbackSlot slot;
int array_index = 0;
ZoneList<Expression*>::iterator iter = expr->BeginValue();
for (; iter != expr->FirstSpreadOrEndValue(); ++iter, array_index++) {
Expression* subexpr = *iter;
......@@ -2326,32 +2327,37 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
builder()->StoreKeyedProperty(literal, index, feedback_index(slot),
language_mode());
}
if (iter != expr->EndValue()) {
builder()->LoadLiteral(array_index).StoreAccumulatorInRegister(index);
}
// Handle spread elements and elements following.
// Handle the first spread element and everything that follows.
FeedbackSlot element_slot = feedback_spec()->AddStoreInArrayLiteralICSlot();
FeedbackSlot index_slot = feedback_spec()->AddBinaryOpICSlot();
FeedbackSlot length_slot =
feedback_spec()->AddStoreICSlot(LanguageMode::kStrict);
for (; iter != expr->EndValue(); ++iter) {
Expression* subexpr = *iter;
if (subexpr->IsSpread()) {
BuildArrayLiteralSpread(subexpr->AsSpread(), literal);
BuildArrayLiteralSpread(subexpr->AsSpread(), literal, index, index_slot,
element_slot);
} else if (!subexpr->IsTheHoleLiteral()) {
// Perform %AppendElement(array, <subexpr>)
RegisterAllocationScope register_scope(this);
RegisterList args = register_allocator()->NewRegisterList(2);
builder()->MoveRegister(literal, args[0]);
VisitForRegisterValue(subexpr, args[1]);
builder()->CallRuntime(Runtime::kAppendElement, args);
// literal[index++] = subexpr
VisitForAccumulatorValue(subexpr);
builder()
->StoreInArrayLiteral(literal, index, feedback_index(element_slot))
.LoadAccumulatorWithRegister(index)
.UnaryOperation(Token::INC, feedback_index(index_slot))
.StoreAccumulatorInRegister(index);
} else {
// Peform ++<array>.length;
// TODO(caitp): Why can't we just %AppendElement(array, <The Hole>?)
// literal.length = ++index
auto length = ast_string_constants()->length_string();
builder()->LoadNamedProperty(
literal, length, feedback_index(feedback_spec()->AddLoadICSlot()));
builder()->UnaryOperation(
Token::INC, feedback_index(feedback_spec()->AddBinaryOpICSlot()));
builder()->StoreNamedProperty(
literal, length,
feedback_index(
feedback_spec()->AddStoreICSlot(LanguageMode::kStrict)),
LanguageMode::kStrict);
builder()
->LoadAccumulatorWithRegister(index)
.UnaryOperation(Token::INC, feedback_index(index_slot))
.StoreAccumulatorInRegister(index)
.StoreNamedProperty(literal, length, feedback_index(length_slot),
LanguageMode::kStrict);
}
}
......@@ -2359,34 +2365,41 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
builder()->LoadAccumulatorWithRegister(literal);
}
void BytecodeGenerator::BuildArrayLiteralSpread(Spread* spread,
Register array) {
void BytecodeGenerator::BuildArrayLiteralSpread(Spread* spread, Register array,
Register index,
FeedbackSlot index_slot,
FeedbackSlot element_slot) {
RegisterAllocationScope register_scope(this);
RegisterList args = register_allocator()->NewRegisterList(2);
builder()->MoveRegister(array, args[0]);
Register next_result = args[1];
Register value = register_allocator()->NewRegister();
builder()->SetExpressionAsStatementPosition(spread->expression());
IteratorRecord iterator =
BuildGetIteratorRecord(spread->expression(), IteratorType::kNormal);
LoopBuilder loop_builder(builder(), nullptr, nullptr);
loop_builder.LoopHeader();
// Call the iterator's .next() method. Break from the loop if the `done`
// property is truthy, otherwise load the value from the iterator result and
// append the argument.
BuildIteratorNext(iterator, next_result);
BuildIteratorNext(iterator, value);
builder()->LoadNamedProperty(
next_result, ast_string_constants()->done_string(),
value, ast_string_constants()->done_string(),
feedback_index(feedback_spec()->AddLoadICSlot()));
loop_builder.BreakIfTrue(ToBooleanMode::kConvertToBoolean);
loop_builder.LoopBody();
builder()
->LoadNamedProperty(next_result, ast_string_constants()->value_string(),
// value = value.value
->LoadNamedProperty(value, ast_string_constants()->value_string(),
feedback_index(feedback_spec()->AddLoadICSlot()))
.StoreAccumulatorInRegister(args[1])
.CallRuntime(Runtime::kAppendElement, args);
.StoreAccumulatorInRegister(value)
// array[index] = value
.StoreInArrayLiteral(array, index, feedback_index(element_slot))
// index++
.LoadAccumulatorWithRegister(index)
.UnaryOperation(Token::INC, feedback_index(index_slot))
.StoreAccumulatorInRegister(index);
loop_builder.BindContinueTarget();
loop_builder.JumpToHeader(loop_depth_);
}
......
......@@ -173,7 +173,9 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
BytecodeLabel* if_called,
BytecodeLabels* if_notcalled);
void BuildArrayLiteralSpread(Spread* spread, Register array);
void BuildArrayLiteralSpread(Spread* spread, Register array, Register index,
FeedbackSlot index_slot,
FeedbackSlot element_slot);
void AllocateTopLevelRegisters();
void VisitArgumentsObject(Variable* variable);
......
......@@ -97,6 +97,8 @@ namespace interpreter {
OperandType::kIdx, OperandType::kIdx) \
V(StaKeyedProperty, AccumulatorUse::kReadWrite, OperandType::kReg, \
OperandType::kReg, OperandType::kIdx) \
V(StaInArrayLiteral, AccumulatorUse::kReadWrite, OperandType::kReg, \
OperandType::kReg, OperandType::kIdx) \
V(StaDataPropertyInLiteral, AccumulatorUse::kRead, OperandType::kReg, \
OperandType::kReg, OperandType::kFlag8, OperandType::kIdx) \
V(CollectTypeProfile, AccumulatorUse::kRead, OperandType::kImm) \
......
......@@ -555,7 +555,9 @@ class InterpreterStoreNamedPropertyAssembler : public InterpreterAssembler {
Node* context = GetContext();
Node* result = CallStub(ic.descriptor(), code_target, context, object, name,
value, smi_slot, feedback_vector);
// It doesn't really matter what we write to the accumulator here, since we
// To avoid special logic in the deoptimizer to re-materialize the value in
// the accumulator, we overwrite the accumulator after the IC call. It
// doesn't really matter what we write to the accumulator here, since we
// restore to the correct value on the outside. Storing the result means we
// don't need to keep unnecessary state alive across the callstub.
SetAccumulator(result);
......@@ -599,7 +601,35 @@ IGNITION_HANDLER(StaKeyedProperty, InterpreterAssembler) {
Node* context = GetContext();
Node* result = CallStub(ic.descriptor(), code_target, context, object, name,
value, smi_slot, feedback_vector);
// It doesn't really matter what we write to the accumulator here, since we
// To avoid special logic in the deoptimizer to re-materialize the value in
// the accumulator, we overwrite the accumulator after the IC call. It
// doesn't really matter what we write to the accumulator here, since we
// restore to the correct value on the outside. Storing the result means we
// don't need to keep unnecessary state alive across the callstub.
SetAccumulator(result);
Dispatch();
}
// StaInArrayLiteral <array> <index> <slot>
//
// Calls the StoreInArrayLiteralIC at FeedbackVector slot <slot> for <array> and
// the key <index> with the value in the accumulator.
IGNITION_HANDLER(StaInArrayLiteral, InterpreterAssembler) {
Callable ic =
Builtins::CallableFor(isolate(), Builtins::kStoreInArrayLiteralIC);
Node* code_target = HeapConstant(ic.code());
Node* array = LoadRegisterAtOperandIndex(0);
Node* index = LoadRegisterAtOperandIndex(1);
Node* value = GetAccumulator();
Node* raw_slot = BytecodeOperandIdx(2);
Node* smi_slot = SmiTag(raw_slot);
Node* feedback_vector = LoadFeedbackVector();
Node* context = GetContext();
Node* result = CallStub(ic.descriptor(), code_target, context, array, index,
value, smi_slot, feedback_vector);
// To avoid special logic in the deoptimizer to re-materialize the value in
// the accumulator, we overwrite the accumulator after the IC call. It
// doesn't really matter what we write to the accumulator here, since we
// restore to the correct value on the outside. Storing the result means we
// don't need to keep unnecessary state alive across the callstub.
SetAccumulator(result);
......
......@@ -859,7 +859,8 @@ void FeedbackNexus::Print(std::ostream& os) { // NOLINT
case FeedbackSlotKind::kStoreKeyedSloppy:
case FeedbackSlotKind::kInstanceOf:
case FeedbackSlotKind::kStoreDataPropertyInLiteral:
case FeedbackSlotKind::kStoreKeyedStrict: {
case FeedbackSlotKind::kStoreKeyedStrict:
case FeedbackSlotKind::kStoreInArrayLiteral: {
os << ICState2String(StateFromFeedback());
break;
}
......
......@@ -577,6 +577,8 @@ void PatternRewriter::VisitArrayLiteral(ArrayLiteral* node,
// A spread can only occur as the last component. It is not handled by
// RecurseIntoSubpattern above.
// TODO(neis): Use IC instead of %AppendElement.
// let array = [];
// while (!done) {
// done = true; // If .next, .done or .value throws, don't close.
......
......@@ -637,6 +637,7 @@ namespace internal {
F(LoadGlobalIC_Slow, 3, 1) \
F(LoadIC_Miss, 4, 1) \
F(LoadPropertyWithInterceptor, 5, 1) \
F(StoreInArrayLiteralIC_Slow, 5, 1) \
F(StoreCallbackProperty, 6, 1) \
F(StoreGlobalIC_Miss, 4, 1) \
F(StoreGlobalIC_Slow, 5, 1) \
......
......@@ -35,17 +35,17 @@ bytecodes: [
/* 42 S> */ B(LdaSmi), I8(1),
B(Star), R(0),
/* 45 S> */ B(CreateArrayLiteral), U8(0), U8(0), U8(37),
B(Star), R(2),
B(LdaZero),
B(Star), R(1),
B(LdaZero),
B(Star), R(2),
B(Ldar), R(0),
/* 54 E> */ B(StaKeyedProperty), R(2), R(1), U8(1),
/* 54 E> */ B(StaKeyedProperty), R(1), R(2), U8(1),
B(LdaSmi), I8(1),
B(Star), R(1),
B(Star), R(2),
B(Ldar), R(0),
/* 59 E> */ B(AddSmi), I8(1), U8(3),
B(StaKeyedProperty), R(2), R(1), U8(1),
B(Ldar), R(2),
B(StaKeyedProperty), R(1), R(2), U8(1),
B(Ldar), R(1),
/* 65 S> */ B(Return),
]
constant pool: [
......@@ -84,29 +84,29 @@ bytecodes: [
/* 42 S> */ B(LdaSmi), I8(1),
B(Star), R(0),
/* 45 S> */ B(CreateArrayLiteral), U8(0), U8(0), U8(4),
B(Star), R(2),
B(LdaZero),
B(Star), R(1),
B(CreateArrayLiteral), U8(1), U8(3), U8(37),
B(Star), R(4),
B(LdaZero),
B(Star), R(2),
B(CreateArrayLiteral), U8(1), U8(3), U8(37),
B(Star), R(3),
B(LdaZero),
B(Star), R(4),
B(Ldar), R(0),
/* 56 E> */ B(StaKeyedProperty), R(4), R(3), U8(4),
B(Ldar), R(4),
B(StaKeyedProperty), R(2), R(1), U8(1),
/* 56 E> */ B(StaKeyedProperty), R(3), R(4), U8(4),
B(Ldar), R(3),
B(StaKeyedProperty), R(1), R(2), U8(1),
B(LdaSmi), I8(1),
B(Star), R(1),
B(CreateArrayLiteral), U8(2), U8(6), U8(37),
B(Star), R(4),
B(LdaZero),
B(Star), R(2),
B(CreateArrayLiteral), U8(2), U8(11), U8(37),
B(Star), R(3),
B(LdaZero),
B(Star), R(4),
B(Ldar), R(0),
/* 68 E> */ B(AddSmi), I8(2), U8(9),
B(StaKeyedProperty), R(4), R(3), U8(7),
B(Ldar), R(4),
B(StaKeyedProperty), R(2), R(1), U8(1),
B(Ldar), R(2),
/* 68 E> */ B(AddSmi), I8(2), U8(14),
B(StaKeyedProperty), R(3), R(4), U8(12),
B(Ldar), R(3),
B(StaKeyedProperty), R(1), R(2), U8(1),
B(Ldar), R(1),
/* 76 S> */ B(Return),
]
constant pool: [
......
......@@ -282,23 +282,23 @@ bytecodes: [
B(Mov), R(context), R(18),
/* 36 S> */ B(CreateArrayLiteral), U8(5), U8(0), U8(37),
B(Star), R(19),
B(LdaNamedProperty), R(19), U8(6), U8(1),
B(LdaNamedProperty), R(19), U8(6), U8(6),
B(Star), R(20),
B(CallProperty0), R(20), R(19), U8(3),
B(CallProperty0), R(20), R(19), U8(8),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(4),
/* 36 E> */ B(LdaNamedProperty), R(4), U8(7), U8(5),
/* 36 E> */ B(LdaNamedProperty), R(4), U8(7), U8(10),
B(Star), R(5),
/* 31 S> */ B(CallProperty0), R(5), R(4), U8(7),
/* 31 S> */ B(CallProperty0), R(5), R(4), U8(12),
B(Star), R(6),
/* 31 E> */ B(InvokeIntrinsic), U8(Runtime::k_IsJSReceiver), R(6), U8(1),
B(ToBooleanLogicalNot),
B(JumpIfFalse), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(6), U8(1),
B(LdaNamedProperty), R(6), U8(8), U8(9),
B(LdaNamedProperty), R(6), U8(8), U8(14),
B(JumpIfToBooleanTrue), U8(68),
B(LdaNamedProperty), R(6), U8(9), U8(11),
B(LdaNamedProperty), R(6), U8(9), U8(16),
B(Star), R(8),
B(LdaSmi), I8(2),
B(Star), R(7),
......@@ -334,7 +334,7 @@ bytecodes: [
B(Ldar), R(18),
B(PushContext), R(19),
B(LdaSmi), I8(2),
B(TestEqualStrict), R(7), U8(13),
B(TestEqualStrict), R(7), U8(18),
B(JumpIfFalse), U8(6),
B(LdaSmi), I8(1),
B(Star), R(7),
......@@ -353,15 +353,15 @@ bytecodes: [
B(SetPendingMessage),
B(Star), R(17),
B(LdaZero),
B(TestEqualStrict), R(7), U8(14),
B(TestEqualStrict), R(7), U8(19),
B(JumpIfTrue), U8(90),
B(LdaNamedProperty), R(4), U8(14), U8(15),
B(LdaNamedProperty), R(4), U8(14), U8(20),
B(Star), R(9),
B(TestUndetectable),
B(JumpIfFalse), U8(4),
B(Jump), U8(79),
B(LdaSmi), I8(1),
B(TestEqualStrict), R(7), U8(17),
B(TestEqualStrict), R(7), U8(22),
B(JumpIfFalse), U8(47),
B(Ldar), R(9),
B(TestTypeOf), U8(6),
......
......@@ -20,7 +20,7 @@ bytecodes: [
B(Star), R(0),
B(CreateArrayLiteral), U8(2), U8(4), U8(37),
B(Star), R(2),
/* 39 E> */ B(CallWithSpread), R(0), R(1), U8(2), U8(5),
/* 39 E> */ B(CallWithSpread), R(0), R(1), U8(2), U8(10),
B(LdaUndefined),
/* 58 S> */ B(Return),
]
......@@ -49,7 +49,7 @@ bytecodes: [
B(Star), R(2),
B(CreateArrayLiteral), U8(2), U8(4), U8(37),
B(Star), R(3),
/* 39 E> */ B(CallWithSpread), R(0), R(1), U8(3), U8(5),
/* 39 E> */ B(CallWithSpread), R(0), R(1), U8(3), U8(10),
B(LdaUndefined),
/* 61 S> */ B(Return),
]
......@@ -65,9 +65,9 @@ handlers: [
snippet: "
Math.max(0, ...[1, 2, 3], 4);
"
frame size: 11
frame size: 10
parameter count: 1
bytecode array length: 109
bytecode array length: 112
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaGlobal), U8(0), U8(0),
......@@ -75,34 +75,38 @@ bytecodes: [
B(LdaNamedProperty), R(0), U8(1), U8(2),
B(Star), R(1),
B(CreateArrayLiteral), U8(2), U8(4), U8(37),
B(Star), R(3),
B(LdaConstant), U8(3),
B(Star), R(4),
/* 49 S> */ B(CreateArrayLiteral), U8(3), U8(5), U8(37),
/* 49 S> */ B(CreateArrayLiteral), U8(4), U8(10), U8(37),
B(Star), R(8),
B(LdaNamedProperty), R(8), U8(5), U8(16),
B(Star), R(9),
B(LdaNamedProperty), R(9), U8(4), U8(6),
B(Star), R(10),
B(CallProperty0), R(10), R(9), U8(8),
B(CallProperty0), R(9), R(8), U8(18),
B(Mov), R(0), R(2),
B(Mov), R(4), R(5),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(8),
B(LdaNamedProperty), R(8), U8(5), U8(10),
B(Star), R(7),
B(CallProperty0), R(7), R(8), U8(12),
B(LdaNamedProperty), R(7), U8(6), U8(20),
B(Star), R(6),
B(CallProperty0), R(6), R(7), U8(22),
B(Star), R(5),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(6), U8(1),
B(LdaNamedProperty), R(6), U8(6), U8(14),
B(JumpIfToBooleanTrue), U8(16),
B(LdaNamedProperty), R(6), U8(7), U8(16),
B(Star), R(6),
B(CallRuntime), U16(Runtime::kAppendElement), R(5), U8(2),
B(JumpLoop), U8(30), I8(0),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(5), U8(1),
B(LdaNamedProperty), R(5), U8(7), U8(24),
B(JumpIfToBooleanTrue), U8(21),
B(LdaNamedProperty), R(5), U8(8), U8(26),
B(Star), R(5),
B(StaInArrayLiteral), R(3), R(4), U8(5),
B(Ldar), R(4),
B(Inc), U8(7),
B(Star), R(4),
B(JumpLoop), U8(35), I8(0),
B(LdaSmi), I8(4),
B(Star), R(6),
B(Mov), R(4), R(5),
B(CallRuntime), U16(Runtime::kAppendElement), R(5), U8(2),
B(Mov), R(5), R(3),
B(StaInArrayLiteral), R(3), R(4), U8(5),
B(Ldar), R(4),
B(Inc), U8(7),
B(Star), R(4),
B(CallJSRuntime), U8(%reflect_apply), R(1), U8(3),
B(LdaUndefined),
/* 64 S> */ B(Return),
......@@ -111,6 +115,7 @@ constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE ["Math"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["max"],
TUPLE2_TYPE,
Smi [1],
TUPLE2_TYPE,
SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
......
......@@ -270,13 +270,13 @@ bytecodes: [
/* 55 S> */ B(CreateArrayLiteral), U8(0), U8(0), U8(37),
B(Star), R(1),
/* 63 S> */ B(Ldar), R(0),
B(ToNumeric), U8(1),
B(ToNumeric), U8(6),
B(Star), R(3),
B(Inc), U8(1),
B(Inc), U8(6),
B(Star), R(0),
B(LdaSmi), I8(2),
B(Star), R(4),
/* 79 E> */ B(StaKeyedProperty), R(1), R(3), U8(2),
/* 79 E> */ B(StaKeyedProperty), R(1), R(3), U8(7),
B(Ldar), R(4),
/* 83 S> */ B(Return),
]
......
......@@ -123,7 +123,7 @@ bytecodes: [
/* 45 E> */ B(StackCheck),
B(Star), R(2),
/* 70 S> */ B(Ldar), R(1),
/* 75 E> */ B(Add), R(0), U8(2),
/* 75 E> */ B(Add), R(0), U8(7),
B(Mov), R(0), R(8),
B(Star), R(0),
/* 72 E> */ B(ForInStep), R(7),
......@@ -167,18 +167,18 @@ bytecodes: [
B(JumpIfUndefined), U8(41),
B(Star), R(6),
B(Ldar), R(6),
/* 67 E> */ B(StaNamedProperty), R(0), U8(2), U8(3),
/* 67 E> */ B(StaNamedProperty), R(0), U8(2), U8(8),
/* 62 E> */ B(StackCheck),
/* 100 S> */ B(LdaNamedProperty), R(0), U8(2), U8(5),
/* 100 S> */ B(LdaNamedProperty), R(0), U8(2), U8(10),
B(Star), R(6),
B(LdaSmi), I8(10),
/* 106 E> */ B(TestEqual), R(6), U8(7),
/* 106 E> */ B(TestEqual), R(6), U8(12),
B(JumpIfFalse), U8(4),
/* 113 S> */ B(Jump), U8(17),
/* 130 S> */ B(LdaNamedProperty), R(0), U8(2), U8(8),
/* 130 S> */ B(LdaNamedProperty), R(0), U8(2), U8(13),
B(Star), R(6),
B(LdaSmi), I8(20),
/* 136 E> */ B(TestEqual), R(6), U8(10),
/* 136 E> */ B(TestEqual), R(6), U8(15),
B(JumpIfFalse), U8(4),
/* 143 S> */ B(Jump), U8(9),
B(ForInStep), R(5),
......@@ -207,26 +207,26 @@ bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(CreateArrayLiteral), U8(0), U8(0), U8(37),
B(Star), R(0),
/* 72 S> */ B(CreateArrayLiteral), U8(1), U8(2), U8(37),
/* 72 S> */ B(CreateArrayLiteral), U8(1), U8(7), U8(37),
B(JumpIfUndefined), U8(51),
B(JumpIfNull), U8(49),
B(ToObject), R(1),
B(ForInEnumerate), R(1),
B(ForInPrepare), R(2), U8(1),
B(ForInPrepare), R(2), U8(6),
B(LdaZero),
B(Star), R(5),
/* 65 S> */ B(ForInContinue), R(5), R(4),
B(JumpIfFalse), U8(34),
B(ForInNext), R(1), R(5), R(2), U8(1),
B(ForInNext), R(1), R(5), R(2), U8(6),
B(JumpIfUndefined), U8(20),
B(Star), R(6),
B(LdaZero),
B(Star), R(8),
B(Ldar), R(6),
/* 64 E> */ B(StaKeyedProperty), R(0), R(8), U8(3),
/* 64 E> */ B(StaKeyedProperty), R(0), R(8), U8(13),
/* 59 E> */ B(StackCheck),
/* 83 S> */ B(LdaSmi), I8(3),
/* 91 E> */ B(LdaKeyedProperty), R(0), U8(5),
/* 91 E> */ B(LdaKeyedProperty), R(0), U8(15),
/* 95 S> */ B(Return),
B(ForInStep), R(5),
B(Star), R(5),
......
......@@ -20,23 +20,23 @@ bytecodes: [
B(Mov), R(context), R(12),
/* 48 S> */ B(CreateArrayLiteral), U8(0), U8(0), U8(37),
B(Star), R(13),
B(LdaNamedProperty), R(13), U8(1), U8(1),
B(LdaNamedProperty), R(13), U8(1), U8(6),
B(Star), R(14),
B(CallProperty0), R(14), R(13), U8(3),
B(CallProperty0), R(14), R(13), U8(8),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(2),
/* 48 E> */ B(LdaNamedProperty), R(2), U8(2), U8(5),
/* 48 E> */ B(LdaNamedProperty), R(2), U8(2), U8(10),
B(Star), R(3),
/* 43 S> */ B(CallProperty0), R(3), R(2), U8(7),
/* 43 S> */ B(CallProperty0), R(3), R(2), U8(12),
B(Star), R(4),
/* 43 E> */ B(InvokeIntrinsic), U8(Runtime::k_IsJSReceiver), R(4), U8(1),
B(ToBooleanLogicalNot),
B(JumpIfFalse), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(4), U8(1),
B(LdaNamedProperty), R(4), U8(3), U8(9),
B(LdaNamedProperty), R(4), U8(3), U8(14),
B(JumpIfToBooleanTrue), U8(25),
B(LdaNamedProperty), R(4), U8(4), U8(11),
B(LdaNamedProperty), R(4), U8(4), U8(16),
B(Star), R(6),
B(LdaSmi), I8(2),
B(Star), R(5),
......@@ -53,7 +53,7 @@ bytecodes: [
B(PushContext), R(13),
B(Star), R(12),
B(LdaSmi), I8(2),
B(TestEqualStrict), R(5), U8(13),
B(TestEqualStrict), R(5), U8(18),
B(JumpIfFalse), U8(6),
B(LdaSmi), I8(1),
B(Star), R(5),
......@@ -72,15 +72,15 @@ bytecodes: [
B(SetPendingMessage),
B(Star), R(11),
B(LdaZero),
B(TestEqualStrict), R(5), U8(14),
B(TestEqualStrict), R(5), U8(19),
B(JumpIfTrue), U8(90),
B(LdaNamedProperty), R(2), U8(7), U8(15),
B(LdaNamedProperty), R(2), U8(7), U8(20),
B(Star), R(7),
B(TestUndetectable),
B(JumpIfFalse), U8(4),
B(Jump), U8(79),
B(LdaSmi), I8(1),
B(TestEqualStrict), R(5), U8(17),
B(TestEqualStrict), R(5), U8(22),
B(JumpIfFalse), U8(47),
B(Ldar), R(7),
B(TestTypeOf), U8(6),
......@@ -292,23 +292,23 @@ bytecodes: [
B(Mov), R(context), R(12),
/* 48 S> */ B(CreateArrayLiteral), U8(0), U8(0), U8(37),
B(Star), R(13),
B(LdaNamedProperty), R(13), U8(1), U8(1),
B(LdaNamedProperty), R(13), U8(1), U8(6),
B(Star), R(14),
B(CallProperty0), R(14), R(13), U8(3),
B(CallProperty0), R(14), R(13), U8(8),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(2),
/* 48 E> */ B(LdaNamedProperty), R(2), U8(2), U8(5),
/* 48 E> */ B(LdaNamedProperty), R(2), U8(2), U8(10),
B(Star), R(3),
/* 43 S> */ B(CallProperty0), R(3), R(2), U8(7),
/* 43 S> */ B(CallProperty0), R(3), R(2), U8(12),
B(Star), R(4),
/* 43 E> */ B(InvokeIntrinsic), U8(Runtime::k_IsJSReceiver), R(4), U8(1),
B(ToBooleanLogicalNot),
B(JumpIfFalse), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(4), U8(1),
B(LdaNamedProperty), R(4), U8(3), U8(9),
B(LdaNamedProperty), R(4), U8(3), U8(14),
B(JumpIfToBooleanTrue), U8(43),
B(LdaNamedProperty), R(4), U8(4), U8(11),
B(LdaNamedProperty), R(4), U8(4), U8(16),
B(Star), R(6),
B(LdaSmi), I8(2),
B(Star), R(5),
......@@ -316,11 +316,11 @@ bytecodes: [
/* 34 E> */ B(StackCheck),
B(Mov), R(0), R(1),
/* 66 S> */ B(LdaSmi), I8(10),
/* 72 E> */ B(TestEqual), R(1), U8(13),
/* 72 E> */ B(TestEqual), R(1), U8(18),
B(JumpIfFalse), U8(4),
/* 79 S> */ B(Jump), U8(14),
/* 91 S> */ B(LdaSmi), I8(20),
/* 97 E> */ B(TestEqual), R(1), U8(14),
/* 97 E> */ B(TestEqual), R(1), U8(19),
B(JumpIfFalse), U8(4),
/* 104 S> */ B(Jump), U8(8),
B(LdaZero),
......@@ -333,7 +333,7 @@ bytecodes: [
B(PushContext), R(13),
B(Star), R(12),
B(LdaSmi), I8(2),
B(TestEqualStrict), R(5), U8(15),
B(TestEqualStrict), R(5), U8(20),
B(JumpIfFalse), U8(6),
B(LdaSmi), I8(1),
B(Star), R(5),
......@@ -352,15 +352,15 @@ bytecodes: [
B(SetPendingMessage),
B(Star), R(11),
B(LdaZero),
B(TestEqualStrict), R(5), U8(16),
B(TestEqualStrict), R(5), U8(21),
B(JumpIfTrue), U8(90),
B(LdaNamedProperty), R(2), U8(7), U8(17),
B(LdaNamedProperty), R(2), U8(7), U8(22),
B(Star), R(7),
B(TestUndetectable),
B(JumpIfFalse), U8(4),
B(Jump), U8(79),
B(LdaSmi), I8(1),
B(TestEqualStrict), R(5), U8(19),
B(TestEqualStrict), R(5), U8(24),
B(JumpIfFalse), U8(47),
B(Ldar), R(7),
B(TestTypeOf), U8(6),
......@@ -434,30 +434,30 @@ bytecodes: [
B(Mov), R(context), R(11),
/* 77 S> */ B(CreateArrayLiteral), U8(1), U8(1), U8(37),
B(Star), R(12),
B(LdaNamedProperty), R(12), U8(2), U8(2),
B(LdaNamedProperty), R(12), U8(2), U8(7),
B(Star), R(13),
B(CallProperty0), R(13), R(12), U8(4),
B(CallProperty0), R(13), R(12), U8(9),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(1),
/* 77 E> */ B(LdaNamedProperty), R(1), U8(3), U8(6),
/* 77 E> */ B(LdaNamedProperty), R(1), U8(3), U8(11),
B(Star), R(2),
/* 68 S> */ B(CallProperty0), R(2), R(1), U8(8),
/* 68 S> */ B(CallProperty0), R(2), R(1), U8(13),
B(Star), R(3),
/* 68 E> */ B(InvokeIntrinsic), U8(Runtime::k_IsJSReceiver), R(3), U8(1),
B(ToBooleanLogicalNot),
B(JumpIfFalse), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(3), U8(1),
B(LdaNamedProperty), R(3), U8(4), U8(10),
B(LdaNamedProperty), R(3), U8(4), U8(15),
B(JumpIfToBooleanTrue), U8(30),
/* 67 E> */ B(LdaNamedProperty), R(3), U8(5), U8(12),
/* 67 E> */ B(LdaNamedProperty), R(3), U8(5), U8(17),
B(Star), R(5),
B(LdaSmi), I8(2),
B(Star), R(4),
B(Ldar), R(5),
B(StaNamedProperty), R(0), U8(6), U8(14),
B(StaNamedProperty), R(0), U8(6), U8(19),
/* 62 E> */ B(StackCheck),
/* 96 S> */ B(LdaNamedProperty), R(0), U8(6), U8(16),
/* 96 S> */ B(LdaNamedProperty), R(0), U8(6), U8(21),
B(Star), R(9),
B(LdaZero),
B(Star), R(8),
......@@ -469,7 +469,7 @@ bytecodes: [
B(PushContext), R(12),
B(Star), R(11),
B(LdaSmi), I8(2),
B(TestEqualStrict), R(4), U8(18),
B(TestEqualStrict), R(4), U8(23),
B(JumpIfFalse), U8(6),
B(LdaSmi), I8(1),
B(Star), R(4),
......@@ -488,15 +488,15 @@ bytecodes: [
B(SetPendingMessage),
B(Star), R(10),
B(LdaZero),
B(TestEqualStrict), R(4), U8(19),
B(TestEqualStrict), R(4), U8(24),
B(JumpIfTrue), U8(90),
B(LdaNamedProperty), R(1), U8(9), U8(20),
B(LdaNamedProperty), R(1), U8(9), U8(25),
B(Star), R(6),
B(TestUndetectable),
B(JumpIfFalse), U8(4),
B(Jump), U8(79),
B(LdaSmi), I8(1),
B(TestEqualStrict), R(4), U8(22),
B(TestEqualStrict), R(4), U8(27),
B(JumpIfFalse), U8(47),
B(Ldar), R(6),
B(TestTypeOf), U8(6),
......
......@@ -123,23 +123,23 @@ bytecodes: [
B(Mov), R(context), R(14),
/* 30 S> */ B(CreateArrayLiteral), U8(4), U8(0), U8(37),
B(Star), R(15),
B(LdaNamedProperty), R(15), U8(5), U8(1),
B(LdaNamedProperty), R(15), U8(5), U8(6),
B(Star), R(16),
B(CallProperty0), R(16), R(15), U8(3),
B(CallProperty0), R(16), R(15), U8(8),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(4),
/* 30 E> */ B(LdaNamedProperty), R(4), U8(6), U8(5),
/* 30 E> */ B(LdaNamedProperty), R(4), U8(6), U8(10),
B(Star), R(5),
/* 25 S> */ B(CallProperty0), R(5), R(4), U8(7),
/* 25 S> */ B(CallProperty0), R(5), R(4), U8(12),
B(Star), R(6),
/* 25 E> */ B(InvokeIntrinsic), U8(Runtime::k_IsJSReceiver), R(6), U8(1),
B(ToBooleanLogicalNot),
B(JumpIfFalse), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(6), U8(1),
B(LdaNamedProperty), R(6), U8(7), U8(9),
B(LdaNamedProperty), R(6), U8(7), U8(14),
B(JumpIfToBooleanTrue), U8(65),
B(LdaNamedProperty), R(6), U8(8), U8(11),
B(LdaNamedProperty), R(6), U8(8), U8(16),
B(Star), R(8),
B(LdaSmi), I8(2),
B(Star), R(7),
......@@ -171,7 +171,7 @@ bytecodes: [
B(PushContext), R(15),
B(Star), R(14),
B(LdaSmi), I8(2),
B(TestEqualStrict), R(7), U8(13),
B(TestEqualStrict), R(7), U8(18),
B(JumpIfFalse), U8(6),
B(LdaSmi), I8(1),
B(Star), R(7),
......@@ -190,15 +190,15 @@ bytecodes: [
B(SetPendingMessage),
B(Star), R(13),
B(LdaZero),
B(TestEqualStrict), R(7), U8(14),
B(TestEqualStrict), R(7), U8(19),
B(JumpIfTrue), U8(90),
B(LdaNamedProperty), R(4), U8(13), U8(15),
B(LdaNamedProperty), R(4), U8(13), U8(20),
B(Star), R(9),
B(TestUndetectable),
B(JumpIfFalse), U8(4),
B(Jump), U8(79),
B(LdaSmi), I8(1),
B(TestEqualStrict), R(7), U8(17),
B(TestEqualStrict), R(7), U8(22),
B(JumpIfFalse), U8(47),
B(Ldar), R(9),
B(TestTypeOf), U8(6),
......
......@@ -29,7 +29,7 @@ bytecodes: [
/* 89 S> */ B(CreateArrayLiteral), U8(2), U8(1), U8(37),
B(Star), R(3),
B(Ldar), R(1),
/* 89 E> */ B(ConstructWithSpread), R(2), R(3), U8(1), U8(2),
/* 89 E> */ B(ConstructWithSpread), R(2), R(3), U8(1), U8(7),
B(LdaUndefined),
/* 110 S> */ B(Return),
]
......@@ -67,7 +67,7 @@ bytecodes: [
B(CreateArrayLiteral), U8(2), U8(1), U8(37),
B(Star), R(4),
B(Ldar), R(1),
/* 89 E> */ B(ConstructWithSpread), R(2), R(3), U8(2), U8(2),
/* 89 E> */ B(ConstructWithSpread), R(2), R(3), U8(2), U8(7),
B(LdaUndefined),
/* 113 S> */ B(Return),
]
......@@ -84,9 +84,9 @@ snippet: "
class A { constructor(...args) { this.args = args; } }
new A(0, ...[1, 2, 3], 4);
"
frame size: 11
frame size: 10
parameter count: 1
bytecode array length: 124
bytecode array length: 127
bytecodes: [
/* 30 E> */ B(StackCheck),
B(LdaTheHole),
......@@ -101,33 +101,37 @@ bytecodes: [
B(Mov), R(4), R(0),
B(Mov), R(0), R(1),
/* 89 S> */ B(CreateArrayLiteral), U8(2), U8(1), U8(37),
B(Star), R(3),
B(LdaConstant), U8(3),
B(Star), R(4),
/* 101 S> */ B(CreateArrayLiteral), U8(3), U8(2), U8(37),
/* 101 S> */ B(CreateArrayLiteral), U8(4), U8(7), U8(37),
B(Star), R(8),
B(LdaNamedProperty), R(8), U8(5), U8(13),
B(Star), R(9),
B(LdaNamedProperty), R(9), U8(4), U8(3),
B(Star), R(10),
B(CallProperty0), R(10), R(9), U8(5),
B(Mov), R(4), R(5),
B(CallProperty0), R(9), R(8), U8(15),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(8),
B(LdaNamedProperty), R(8), U8(5), U8(7),
B(Star), R(7),
B(CallProperty0), R(7), R(8), U8(9),
B(LdaNamedProperty), R(7), U8(6), U8(17),
B(Star), R(6),
B(CallProperty0), R(6), R(7), U8(19),
B(Star), R(5),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(6), U8(1),
B(LdaNamedProperty), R(6), U8(6), U8(11),
B(JumpIfToBooleanTrue), U8(16),
B(LdaNamedProperty), R(6), U8(7), U8(13),
B(Star), R(6),
B(CallRuntime), U16(Runtime::kAppendElement), R(5), U8(2),
B(JumpLoop), U8(30), I8(0),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(5), U8(1),
B(LdaNamedProperty), R(5), U8(7), U8(21),
B(JumpIfToBooleanTrue), U8(21),
B(LdaNamedProperty), R(5), U8(8), U8(23),
B(Star), R(5),
B(StaInArrayLiteral), R(3), R(4), U8(2),
B(Ldar), R(4),
B(Inc), U8(4),
B(Star), R(4),
B(JumpLoop), U8(35), I8(0),
B(LdaSmi), I8(4),
B(Star), R(6),
B(Mov), R(4), R(5),
B(CallRuntime), U16(Runtime::kAppendElement), R(5), U8(2),
B(Mov), R(5), R(3),
B(StaInArrayLiteral), R(3), R(4), U8(2),
B(Ldar), R(4),
B(Inc), U8(4),
B(Star), R(4),
B(CallJSRuntime), U8(%reflect_construct), R(2), U8(2),
B(LdaUndefined),
/* 116 S> */ B(Return),
......@@ -136,6 +140,7 @@ constant pool: [
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
TUPLE2_TYPE,
Smi [1],
TUPLE2_TYPE,
SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
......
......@@ -91,9 +91,9 @@ snippet: "
test = new B(1, 2, 3).constructor;
})();
"
frame size: 13
frame size: 12
parameter count: 1
bytecode array length: 121
bytecode array length: 124
bytecodes: [
B(CreateRestParameter),
B(Star), R(2),
......@@ -103,32 +103,36 @@ bytecodes: [
/* 140 S> */ B(CallRuntime), U16(Runtime::k_GetSuperConstructor), R(closure), U8(1),
B(Star), R(4),
B(CreateArrayLiteral), U8(0), U8(0), U8(37),
B(Star), R(5),
B(LdaConstant), U8(1),
/* 152 S> */ B(Star), R(6),
B(LdaNamedProperty), R(2), U8(1), U8(1),
B(Star), R(12),
B(CallProperty0), R(12), R(2), U8(3),
B(Mov), R(2), R(11),
B(Mov), R(6), R(7),
B(LdaNamedProperty), R(2), U8(2), U8(6),
B(Star), R(11),
B(CallProperty0), R(11), R(2), U8(8),
B(Mov), R(2), R(10),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(10),
B(LdaNamedProperty), R(10), U8(2), U8(5),
B(Star), R(9),
B(CallProperty0), R(9), R(10), U8(7),
B(LdaNamedProperty), R(9), U8(3), U8(10),
B(Star), R(8),
B(CallProperty0), R(8), R(9), U8(12),
B(Star), R(7),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(8), U8(1),
B(LdaNamedProperty), R(8), U8(3), U8(9),
B(JumpIfToBooleanTrue), U8(16),
B(LdaNamedProperty), R(8), U8(4), U8(11),
B(Star), R(8),
B(CallRuntime), U16(Runtime::kAppendElement), R(7), U8(2),
B(JumpLoop), U8(30), I8(0),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(7), U8(1),
B(LdaNamedProperty), R(7), U8(4), U8(14),
B(JumpIfToBooleanTrue), U8(21),
B(LdaNamedProperty), R(7), U8(5), U8(16),
B(Star), R(7),
B(StaInArrayLiteral), R(5), R(6), U8(1),
B(Ldar), R(6),
B(Inc), U8(3),
B(Star), R(6),
B(JumpLoop), U8(35), I8(0),
B(LdaSmi), I8(1),
B(Star), R(8),
B(Mov), R(6), R(7),
B(CallRuntime), U16(Runtime::kAppendElement), R(7), U8(2),
B(Mov), R(7), R(5),
B(StaInArrayLiteral), R(5), R(6), U8(1),
B(Ldar), R(6),
B(Inc), U8(3),
B(Star), R(6),
B(Mov), R(0), R(6),
/* 140 E> */ B(CallJSRuntime), U8(%reflect_construct), R(4), U8(3),
B(Star), R(4),
......@@ -141,6 +145,7 @@ bytecodes: [
]
constant pool: [
TUPLE2_TYPE,
Smi [1],
SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
......
This diff is collapsed.
......@@ -104,6 +104,8 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
FeedbackSlot strict_keyed_store_slot =
feedback_spec.AddKeyedStoreICSlot(LanguageMode::kStrict);
FeedbackSlot store_own_slot = feedback_spec.AddStoreOwnICSlot();
FeedbackSlot store_array_element_slot =
feedback_spec.AddStoreInArrayLiteralICSlot();
// Emit global load / store operations.
const AstRawString* name = ast_factory.GetOneByteString("var_name");
......@@ -141,7 +143,8 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
LanguageMode::kStrict)
.StoreKeyedProperty(reg, reg, strict_keyed_store_slot.ToInt(),
LanguageMode::kStrict)
.StoreNamedOwnProperty(reg, name, store_own_slot.ToInt());
.StoreNamedOwnProperty(reg, name, store_own_slot.ToInt())
.StoreInArrayLiteral(reg, reg, store_array_element_slot.ToInt());
// Emit load / store lookup slots.
builder.LoadLookupSlot(name, TypeofMode::NOT_INSIDE_TYPEOF)
......
......@@ -56,6 +56,9 @@ function IcProcessor() {
'KeyedStoreIC': {
parsers : propertyICParser,
processor: this.processPropertyIC.bind(this, "KeyedStoreIC") },
'StoreInArrayLiteralIC': {
parsers : propertyICParser,
processor: this.processPropertyIC.bind(this, "StoreInArrayLiteralIC") },
});
this.deserializedEntriesNames_ = [];
this.profile_ = new Profile();
......@@ -64,6 +67,7 @@ function IcProcessor() {
this.StoreIC = 0;
this.KeyedLoadIC = 0;
this.KeyedStoreIC = 0;
this.StoreInArrayLiteralIC = 0;
}
inherits(IcProcessor, LogReader);
......@@ -104,6 +108,7 @@ IcProcessor.prototype.processLogFile = function(fileName) {
print("Store: " + this.StoreIC);
print("KeyedLoad: " + this.KeyedLoadIC);
print("KeyedStore: " + this.KeyedStoreIC);
print("StoreInArrayLiteral: " + this.StoreInArrayLiteralIC);
};
IcProcessor.prototype.addEntry = function(entry) {
......
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