[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, chromium:746935 Change-Id: I891eaa778e4e81e138e483a65f04ae00ae30bd28 Reviewed-on: https://chromium-review.googlesource.com/580932 Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> Reviewed-by: Igor Sheludko <ishell@chromium.org> Commit-Queue: Camillo Bruni <cbruni@chromium.org> Cr-Commit-Position: refs/heads/master@{#46875}
This commit is contained in:
parent
b3ff283754
commit
0392eb20ac
@ -1442,6 +1442,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();
|
||||
|
||||
|
@ -192,14 +192,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);
|
||||
}
|
||||
@ -560,6 +552,56 @@ 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);
|
||||
{
|
||||
Node* feedback_vector = LoadFeedbackVector(closure);
|
||||
allocation_site.Bind(
|
||||
CreateAllocationSiteInFeedbackVector(feedback_vector, 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(Descriptor::kClosure);
|
||||
Node* literal_index = Parameter(Descriptor::kLiteralIndex);
|
||||
Node* context = Parameter(Descriptor::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);
|
||||
|
@ -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,7 +45,6 @@ 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);
|
||||
};
|
||||
|
@ -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) \
|
||||
|
@ -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));
|
||||
@ -4944,6 +4953,16 @@ Node* CodeStubAssembler::DecodeWord(Node* word, uint32_t shift, uint32_t mask) {
|
||||
return WordShr(WordAnd(word, IntPtrConstant(mask)), static_cast<int>(shift));
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::UpdateWord(Node* word, Node* value, uint32_t shift,
|
||||
uint32_t mask) {
|
||||
Node* encoded_value = WordShl(value, static_cast<int>(shift));
|
||||
Node* inverted_mask = IntPtrConstant(~static_cast<intptr_t>(mask));
|
||||
// Ensure the {value} fits fully in the mask.
|
||||
CSA_ASSERT(this, WordEqual(WordAnd(encoded_value, inverted_mask),
|
||||
IntPtrConstant(0)));
|
||||
return WordOr(WordAnd(word, inverted_mask), encoded_value);
|
||||
}
|
||||
|
||||
void CodeStubAssembler::SetCounter(StatsCounter* counter, int value) {
|
||||
if (FLAG_native_code_counters && counter->Enabled()) {
|
||||
Node* counter_address = ExternalConstant(ExternalReference(counter));
|
||||
@ -6334,11 +6353,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,
|
||||
@ -6942,11 +6980,12 @@ Node* CodeStubAssembler::CreateAllocationSiteInFeedbackVector(
|
||||
Node* feedback_vector, Node* slot) {
|
||||
Node* size = IntPtrConstant(AllocationSite::kSize);
|
||||
Node* site = Allocate(size, CodeStubAssembler::kPretenured);
|
||||
|
||||
StoreMap(site, AllocationSiteMapConstant());
|
||||
Node* kind = SmiConstant(GetInitialFastElementsKind());
|
||||
StoreMapNoWriteBarrier(site, Heap::kAllocationSiteMapRootIndex);
|
||||
// Should match AllocationSite::Initialize.
|
||||
Node* field = UpdateWord<AllocationSite::ElementsKindBits>(
|
||||
IntPtrConstant(0), IntPtrConstant(GetInitialFastElementsKind()));
|
||||
StoreObjectFieldNoWriteBarrier(
|
||||
site, AllocationSite::kTransitionInfoOrBoilerplateOffset, kind);
|
||||
site, AllocationSite::kTransitionInfoOrBoilerplateOffset, SmiTag(field));
|
||||
|
||||
// Unlike literals, constructed arrays don't have nested sites
|
||||
Node* zero = SmiConstant(0);
|
||||
|
@ -488,6 +488,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);
|
||||
@ -949,31 +950,31 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
|
||||
ToIntegerTruncationMode mode = kNoTruncation);
|
||||
|
||||
// Returns a node that contains a decoded (unsigned!) value of a bit
|
||||
// field |T| in |word32|. Returns result as an uint32 node.
|
||||
template <typename T>
|
||||
// field |BitField| in |word32|. Returns result as an uint32 node.
|
||||
template <typename BitField>
|
||||
Node* DecodeWord32(Node* word32) {
|
||||
return DecodeWord32(word32, T::kShift, T::kMask);
|
||||
return DecodeWord32(word32, BitField::kShift, BitField::kMask);
|
||||
}
|
||||
|
||||
// Returns a node that contains a decoded (unsigned!) value of a bit
|
||||
// field |T| in |word|. Returns result as a word-size node.
|
||||
template <typename T>
|
||||
// field |BitField| in |word|. Returns result as a word-size node.
|
||||
template <typename BitField>
|
||||
Node* DecodeWord(Node* word) {
|
||||
return DecodeWord(word, T::kShift, T::kMask);
|
||||
return DecodeWord(word, BitField::kShift, BitField::kMask);
|
||||
}
|
||||
|
||||
// Returns a node that contains a decoded (unsigned!) value of a bit
|
||||
// field |T| in |word32|. Returns result as a word-size node.
|
||||
template <typename T>
|
||||
// field |BitField| in |word32|. Returns result as a word-size node.
|
||||
template <typename BitField>
|
||||
Node* DecodeWordFromWord32(Node* word32) {
|
||||
return DecodeWord<T>(ChangeUint32ToWord(word32));
|
||||
return DecodeWord<BitField>(ChangeUint32ToWord(word32));
|
||||
}
|
||||
|
||||
// Returns a node that contains a decoded (unsigned!) value of a bit
|
||||
// field |T| in |word|. Returns result as an uint32 node.
|
||||
template <typename T>
|
||||
// field |BitField| in |word|. Returns result as an uint32 node.
|
||||
template <typename BitField>
|
||||
Node* DecodeWord32FromWord(Node* word) {
|
||||
return TruncateWordToWord32(DecodeWord<T>(word));
|
||||
return TruncateWordToWord32(DecodeWord<BitField>(word));
|
||||
}
|
||||
|
||||
// Decodes an unsigned (!) value from |word32| to an uint32 node.
|
||||
@ -982,6 +983,16 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
|
||||
// Decodes an unsigned (!) value from |word| to a word-size node.
|
||||
Node* DecodeWord(Node* word, uint32_t shift, uint32_t mask);
|
||||
|
||||
// Returns a node that contains the updated values of a |BitField|.
|
||||
template <typename BitField>
|
||||
Node* UpdateWord(Node* word, Node* value) {
|
||||
return UpdateWord(word, value, BitField::kShift, BitField::kMask);
|
||||
}
|
||||
|
||||
// Returns a node that contains the updated {value} inside {word} starting
|
||||
// at {shift} and fitting in {mask}.
|
||||
Node* UpdateWord(Node* word, Node* value, uint32_t shift, uint32_t mask);
|
||||
|
||||
// Returns true if any of the |T|'s bits in given |word32| are set.
|
||||
template <typename T>
|
||||
Node* IsSetWord32(Node* word32) {
|
||||
@ -1302,6 +1313,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);
|
||||
|
@ -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(
|
||||
|
@ -223,6 +223,8 @@ Reduction JSCreateLowering::Reduce(Node* node) {
|
||||
return ReduceJSCreateLiteralArrayOrObject(node);
|
||||
case IrOpcode::kJSCreateLiteralRegExp:
|
||||
return ReduceJSCreateLiteralRegExp(node);
|
||||
case IrOpcode::kJSCreateEmptyLiteralArray:
|
||||
return ReduceJSCreateEmptyLiteralArray(node);
|
||||
case IrOpcode::kJSCreateFunctionContext:
|
||||
return ReduceJSCreateFunctionContext(node);
|
||||
case IrOpcode::kJSCreateWithContext:
|
||||
@ -623,7 +625,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);
|
||||
|
||||
@ -918,6 +921,23 @@ Reduction JSCreateLowering::ReduceJSCreateLiteralArrayOrObject(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();
|
||||
}
|
||||
|
||||
Reduction JSCreateLowering::ReduceJSCreateLiteralRegExp(Node* node) {
|
||||
DCHECK(node->opcode() == IrOpcode::kJSCreateLiteralRegExp);
|
||||
CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
|
||||
|
@ -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 ReduceJSCreateLiteralArrayOrObject(Node* node);
|
||||
Reduction ReduceJSCreateLiteralRegExp(Node* node);
|
||||
Reduction ReduceJSCreateFunctionContext(Node* node);
|
||||
|
@ -476,6 +476,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());
|
||||
|
@ -1020,6 +1020,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) {
|
||||
|
@ -636,6 +636,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);
|
||||
|
@ -135,6 +135,7 @@
|
||||
V(JSCreateIterResultObject) \
|
||||
V(JSCreateKeyValueArray) \
|
||||
V(JSCreateLiteralArray) \
|
||||
V(JSCreateEmptyLiteralArray) \
|
||||
V(JSCreateLiteralObject) \
|
||||
V(JSCreateLiteralRegExp) \
|
||||
V(JSLoadProperty) \
|
||||
|
@ -1124,6 +1124,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();
|
||||
|
@ -611,6 +611,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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -2049,12 +2049,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;
|
||||
|
@ -227,6 +227,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) \
|
||||
\
|
||||
|
@ -2654,6 +2654,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
|
||||
|
@ -4435,6 +4435,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)
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -4011,6 +4011,95 @@ TEST(EnsureAllocationSiteDependentCodesProcessed) {
|
||||
WeakCell::cast(site->dependent_code()->object_at(0))->cleared());
|
||||
}
|
||||
|
||||
TEST(AllocationSiteCreation) {
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
Heap* heap = isolate->heap();
|
||||
HandleScope scope(isolate);
|
||||
|
||||
int prev_count = 0;
|
||||
int count = 0;
|
||||
|
||||
// Array literals.
|
||||
prev_count = AllocationSitesCount(heap);
|
||||
CompileRun("(function f1() { return []; })()");
|
||||
count = AllocationSitesCount(heap);
|
||||
CHECK_EQ(1, count - prev_count);
|
||||
|
||||
prev_count = count;
|
||||
CompileRun("(function f2() { return [1, 2]; })()");
|
||||
count = AllocationSitesCount(heap);
|
||||
CHECK_EQ(1, count - prev_count);
|
||||
|
||||
prev_count = count;
|
||||
CompileRun("(function f3() { return [[1], [2]]; })()");
|
||||
count = AllocationSitesCount(heap);
|
||||
CHECK_EQ(3, count - prev_count);
|
||||
|
||||
prev_count = count;
|
||||
CompileRun(
|
||||
"(function f4() { "
|
||||
"return [0, [1, 1.1, 1.2, "
|
||||
"], 1.5, [2.1, 2.2], 3];"
|
||||
"})()");
|
||||
count = AllocationSitesCount(heap);
|
||||
CHECK_EQ(3, count - prev_count);
|
||||
|
||||
// Object literals have lazy AllocationSites
|
||||
prev_count = AllocationSitesCount(heap);
|
||||
CompileRun("function f5() { return {}; }; f5(); ");
|
||||
count = AllocationSitesCount(heap);
|
||||
CHECK_EQ(0, count - prev_count);
|
||||
// Allocation-sites + boilerplates are created on the second run only.
|
||||
prev_count = AllocationSitesCount(heap);
|
||||
CompileRun("f5(); ");
|
||||
count = AllocationSitesCount(heap);
|
||||
CHECK_EQ(1, count - prev_count);
|
||||
|
||||
prev_count = AllocationSitesCount(heap);
|
||||
CompileRun("function f6() { return {a:1}; }; f6(); ");
|
||||
count = AllocationSitesCount(heap);
|
||||
CHECK_EQ(0, count - prev_count);
|
||||
prev_count = AllocationSitesCount(heap);
|
||||
CompileRun("f6(); ");
|
||||
count = AllocationSitesCount(heap);
|
||||
CHECK_EQ(1, count - prev_count);
|
||||
|
||||
prev_count = AllocationSitesCount(heap);
|
||||
CompileRun("function f7() { return {a:1, b:2}; }; f7(); ");
|
||||
count = AllocationSitesCount(heap);
|
||||
CHECK_EQ(0, count - prev_count);
|
||||
prev_count = AllocationSitesCount(heap);
|
||||
CompileRun("f7(); ");
|
||||
count = AllocationSitesCount(heap);
|
||||
CHECK_EQ(1, count - prev_count);
|
||||
|
||||
prev_count = AllocationSitesCount(heap);
|
||||
CompileRun(
|
||||
"function f8() {"
|
||||
"return {a:{}, b:{ a:2, c:{ d:{f:{}}} } }; "
|
||||
"}; f8(); ");
|
||||
count = AllocationSitesCount(heap);
|
||||
CHECK_EQ(0, count - prev_count);
|
||||
prev_count = AllocationSitesCount(heap);
|
||||
CompileRun("f8(); ");
|
||||
count = AllocationSitesCount(heap);
|
||||
CHECK_EQ(6, count - prev_count);
|
||||
|
||||
// We currently eagerly create allocation sites if there are sub-arrays.
|
||||
prev_count = AllocationSitesCount(heap);
|
||||
CompileRun(
|
||||
"function f9() {"
|
||||
"return {a:[1, 2, 3], b:{ a:2, c:{ d:{f:[]} } }}; "
|
||||
"}; f9(); ");
|
||||
count = AllocationSitesCount(heap);
|
||||
CHECK_EQ(6, count - prev_count);
|
||||
prev_count = AllocationSitesCount(heap);
|
||||
CompileRun("f9(); ");
|
||||
count = AllocationSitesCount(heap);
|
||||
// No new AllocationSites created on the second invocation.
|
||||
CHECK_EQ(0, count - prev_count);
|
||||
}
|
||||
|
||||
TEST(CellsInOptimizedCodeAreWeak) {
|
||||
if (FLAG_always_opt || !FLAG_opt) return;
|
||||
|
@ -2526,6 +2526,29 @@ 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->native_context()->GetInitialJSArrayMap(elements_kind));
|
||||
CHECK_EQ(*csa_result, *result);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -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));
|
||||
})();
|
||||
|
@ -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);
|
||||
|
112
test/mjsunit/regress/regress-crbug-746835.js
Normal file
112
test/mjsunit/regress/regress-crbug-746835.js
Normal file
@ -0,0 +1,112 @@
|
||||
// Copyright 2017 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// This example crashes if the AllocationSites have not been properly added to
|
||||
// the allocation_sites_list.
|
||||
|
||||
// Flags: --expose-gc
|
||||
|
||||
function __getProperties() {
|
||||
return [];
|
||||
let properties = [];
|
||||
for (let name of Object.getOwnPropertyNames()) {;
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
function __getRandomProperty() {
|
||||
let properties = __getProperties();
|
||||
if (!properties.length)
|
||||
return undefined;
|
||||
return properties[seed % properties.length];
|
||||
}
|
||||
var kWasmH0 = 0;
|
||||
var kWasmH1 = 0x61;
|
||||
var kWasmH2 = 0x73;
|
||||
var kWasmH3 = 0x6d;
|
||||
var kWasmV0 = 0x1;
|
||||
var kWasmV1 = 0;
|
||||
var kWasmV2 = 0;
|
||||
var kWasmV3 = 0;
|
||||
class Binary extends Array {
|
||||
emit_header() {
|
||||
this.push(kWasmH0, kWasmH1, kWasmH2, kWasmH3,
|
||||
kWasmV0, kWasmV1, kWasmV2, kWasmV3);
|
||||
}
|
||||
}
|
||||
class WasmModuleBuilder {
|
||||
constructor() {
|
||||
this.exports = [];
|
||||
}
|
||||
addImportedMemory() {}
|
||||
setFunctionTableLength() {}
|
||||
toArray() {
|
||||
let binary = new Binary;
|
||||
let wasm = this;
|
||||
binary.emit_header();
|
||||
"emitting imports @ " + binary.length;
|
||||
section => {};
|
||||
var mem_export = (wasm.memory !== undefined && wasm.memory.exp);
|
||||
var exports_count = wasm.exports.length + (mem_export ? 1 : 0);
|
||||
return binary;
|
||||
}
|
||||
toBuffer() {
|
||||
let bytes = this.toArray();
|
||||
let buffer = new ArrayBuffer(bytes.length);
|
||||
let view = new Uint8Array(buffer);
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
let val = bytes[i];
|
||||
view[i] = val | 0;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
instantiate(ffi) {
|
||||
let module = new WebAssembly.Module(this.toBuffer());
|
||||
let instance = new WebAssembly.Instance(module);
|
||||
}
|
||||
}
|
||||
|
||||
var v_40 = 0;
|
||||
var v_43 = NaN;
|
||||
|
||||
try {
|
||||
v_23 = new WasmModuleBuilder();
|
||||
} catch (e) {
|
||||
print("Caught: " + e);
|
||||
}
|
||||
|
||||
try {
|
||||
v_31 = [0xff];
|
||||
v_29 = [v_31];
|
||||
} catch (e) {
|
||||
print("Caught: " + e);
|
||||
}
|
||||
|
||||
try {
|
||||
v_25 = ["main"];
|
||||
gc();
|
||||
} catch (e) {
|
||||
print("Caught: " + e);
|
||||
}
|
||||
for (var v_28 of [[2]]) {
|
||||
try {
|
||||
gc();
|
||||
} catch (e) {
|
||||
print("Caught: " + e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
module = v_23.instantiate();
|
||||
} catch (e) {
|
||||
print("Caught: " + e);
|
||||
}
|
||||
try {
|
||||
v_41 = [];
|
||||
} catch (e) {;
|
||||
}
|
||||
for (var v_43 = 0; v_43 < 100000; v_43++) try {
|
||||
v_41[v_43] = [];
|
||||
} catch (e) {
|
||||
"Caught: " + e;
|
||||
}
|
@ -351,6 +351,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.
|
||||
|
Loading…
Reference in New Issue
Block a user