diff options
Diffstat (limited to 'deps/v8/src/hydrogen-instructions.h')
-rw-r--r-- | deps/v8/src/hydrogen-instructions.h | 323 |
1 files changed, 253 insertions, 70 deletions
diff --git a/deps/v8/src/hydrogen-instructions.h b/deps/v8/src/hydrogen-instructions.h index 780d57d61a..6c938cd4bf 100644 --- a/deps/v8/src/hydrogen-instructions.h +++ b/deps/v8/src/hydrogen-instructions.h @@ -124,7 +124,6 @@ class LChunkBuilder; V(IsStringAndBranch) \ V(IsSmiAndBranch) \ V(IsUndetectableAndBranch) \ - V(StringCompareAndBranch) \ V(JSArrayLength) \ V(LeaveInlined) \ V(LoadContextSlot) \ @@ -140,7 +139,9 @@ class LChunkBuilder; V(LoadNamedField) \ V(LoadNamedFieldPolymorphic) \ V(LoadNamedGeneric) \ + V(MapEnumLength) \ V(MathFloorOfDiv) \ + V(MathMinMax) \ V(Mod) \ V(Mul) \ V(ObjectLiteral) \ @@ -170,6 +171,7 @@ class LChunkBuilder; V(StringAdd) \ V(StringCharCodeAt) \ V(StringCharFromCode) \ + V(StringCompareAndBranch) \ V(StringLength) \ V(Sub) \ V(ThisFunction) \ @@ -224,6 +226,16 @@ class LChunkBuilder; virtual Opcode opcode() const { return HValue::k##type; } +#ifdef DEBUG +#define ASSERT_ALLOCATION_DISABLED do { \ + OptimizingCompilerThread* thread = \ + ISOLATE->optimizing_compiler_thread(); \ + ASSERT(thread->IsOptimizerThread() || !HEAP->IsAllocationAllowed()); \ + } while (0) +#else +#define ASSERT_ALLOCATION_DISABLED do {} while (0) +#endif + class Range: public ZoneObject { public: Range() @@ -276,6 +288,8 @@ class Range: public ZoneObject { void Intersect(Range* other); void Union(Range* other); + void CombinedMax(Range* other); + void CombinedMin(Range* other); void AddConstant(int32_t value); void Sar(int32_t value); @@ -549,7 +563,14 @@ class HValue: public ZoneObject { kIsArguments, kTruncatingToInt32, kIsDead, - kLastFlag = kIsDead + // Instructions that are allowed to produce full range unsigned integer + // values are marked with kUint32 flag. If arithmetic shift or a load from + // EXTERNAL_UNSIGNED_INT_ELEMENTS array is not marked with this flag + // it will deoptimize if result does not fit into signed integer range. + // HGraph::ComputeSafeUint32Operations is responsible for setting this + // flag. + kUint32, + kLastFlag = kUint32 }; STATIC_ASSERT(kLastFlag < kBitsPerInt); @@ -857,9 +878,14 @@ class HInstruction: public HValue { void InsertBefore(HInstruction* next); void InsertAfter(HInstruction* previous); + // The position is a write-once variable. int position() const { return position_; } bool has_position() const { return position_ != RelocInfo::kNoPosition; } - void set_position(int position) { position_ = position; } + void set_position(int position) { + ASSERT(!has_position()); + ASSERT(position != RelocInfo::kNoPosition); + position_ = position; + } bool CanTruncateToInt32() const { return CheckFlag(kTruncatingToInt32); } @@ -1281,7 +1307,7 @@ class HClampToUint8: public HUnaryOperation { class HSimulate: public HInstruction { public: - HSimulate(int ast_id, int pop_count, Zone* zone) + HSimulate(BailoutId ast_id, int pop_count, Zone* zone) : ast_id_(ast_id), pop_count_(pop_count), values_(2, zone), @@ -1291,9 +1317,9 @@ class HSimulate: public HInstruction { virtual void PrintDataTo(StringStream* stream); - bool HasAstId() const { return ast_id_ != AstNode::kNoNumber; } - int ast_id() const { return ast_id_; } - void set_ast_id(int id) { + bool HasAstId() const { return !ast_id_.IsNone(); } + BailoutId ast_id() const { return ast_id_; } + void set_ast_id(BailoutId id) { ASSERT(!HasAstId()); ast_id_ = id; } @@ -1341,7 +1367,7 @@ class HSimulate: public HInstruction { // use lists are correctly updated. SetOperandAt(values_.length() - 1, value); } - int ast_id_; + BailoutId ast_id_; int pop_count_; ZoneList<HValue*> values_; ZoneList<int> assigned_indexes_; @@ -1385,20 +1411,29 @@ class HStackCheck: public HTemplateInstruction<1> { }; +enum InliningKind { + NORMAL_RETURN, // Normal function/method call and return. + DROP_EXTRA_ON_RETURN, // Drop an extra value from the environment on return. + CONSTRUCT_CALL_RETURN, // Either use allocated receiver or return value. + GETTER_CALL_RETURN, // Returning from a getter, need to restore context. + SETTER_CALL_RETURN // Use the RHS of the assignment as the return value. +}; + + class HEnterInlined: public HTemplateInstruction<0> { public: HEnterInlined(Handle<JSFunction> closure, int arguments_count, FunctionLiteral* function, CallKind call_kind, - bool is_construct, + InliningKind inlining_kind, Variable* arguments_var, ZoneList<HValue*>* arguments_values) : closure_(closure), arguments_count_(arguments_count), function_(function), call_kind_(call_kind), - is_construct_(is_construct), + inlining_kind_(inlining_kind), arguments_var_(arguments_var), arguments_values_(arguments_values) { } @@ -1409,7 +1444,7 @@ class HEnterInlined: public HTemplateInstruction<0> { int arguments_count() const { return arguments_count_; } FunctionLiteral* function() const { return function_; } CallKind call_kind() const { return call_kind_; } - bool is_construct() const { return is_construct_; } + InliningKind inlining_kind() const { return inlining_kind_; } virtual Representation RequiredInputRepresentation(int index) { return Representation::None(); @@ -1425,7 +1460,7 @@ class HEnterInlined: public HTemplateInstruction<0> { int arguments_count_; FunctionLiteral* function_; CallKind call_kind_; - bool is_construct_; + InliningKind inlining_kind_; Variable* arguments_var_; ZoneList<HValue*>* arguments_values_; }; @@ -1469,7 +1504,7 @@ class HPushArgument: public HUnaryOperation { class HThisFunction: public HTemplateInstruction<0> { public: - explicit HThisFunction(Handle<JSFunction> closure) : closure_(closure) { + HThisFunction() { set_representation(Representation::Tagged()); SetFlag(kUseGVN); } @@ -1478,18 +1513,10 @@ class HThisFunction: public HTemplateInstruction<0> { return Representation::None(); } - Handle<JSFunction> closure() const { return closure_; } - DECLARE_CONCRETE_INSTRUCTION(ThisFunction) protected: - virtual bool DataEquals(HValue* other) { - HThisFunction* b = HThisFunction::cast(other); - return *closure() == *b->closure(); - } - - private: - Handle<JSFunction> closure_; + virtual bool DataEquals(HValue* other) { return true; } }; @@ -1881,6 +1908,7 @@ class HJSArrayLength: public HTemplateInstruction<2> { class HFixedArrayBaseLength: public HUnaryOperation { public: explicit HFixedArrayBaseLength(HValue* value) : HUnaryOperation(value) { + set_type(HType::Smi()); set_representation(Representation::Tagged()); SetFlag(kUseGVN); SetGVNFlag(kDependsOnArrayLengths); @@ -1897,6 +1925,26 @@ class HFixedArrayBaseLength: public HUnaryOperation { }; +class HMapEnumLength: public HUnaryOperation { + public: + explicit HMapEnumLength(HValue* value) : HUnaryOperation(value) { + set_type(HType::Smi()); + set_representation(Representation::Tagged()); + SetFlag(kUseGVN); + SetGVNFlag(kDependsOnMaps); + } + + virtual Representation RequiredInputRepresentation(int index) { + return Representation::Tagged(); + } + + DECLARE_CONCRETE_INSTRUCTION(MapEnumLength) + + protected: + virtual bool DataEquals(HValue* other) { return true; } +}; + + class HElementsKind: public HUnaryOperation { public: explicit HElementsKind(HValue* value) : HUnaryOperation(value) { @@ -2021,14 +2069,18 @@ class HUnaryMathOperation: public HTemplateInstruction<2> { }; -class HLoadElements: public HUnaryOperation { +class HLoadElements: public HTemplateInstruction<2> { public: - explicit HLoadElements(HValue* value) : HUnaryOperation(value) { + HLoadElements(HValue* value, HValue* typecheck) { + SetOperandAt(0, value); + SetOperandAt(1, typecheck); set_representation(Representation::Tagged()); SetFlag(kUseGVN); SetGVNFlag(kDependsOnElementsPointer); } + HValue* value() { return OperandAt(0); } + virtual Representation RequiredInputRepresentation(int index) { return Representation::Tagged(); } @@ -2289,8 +2341,10 @@ class HCheckPrototypeMaps: public HTemplateInstruction<0> { return Representation::None(); } + virtual void PrintDataTo(StringStream* stream); + virtual intptr_t Hashcode() { - ASSERT(!HEAP->IsAllocationAllowed()); + ASSERT_ALLOCATION_DISABLED; intptr_t hash = reinterpret_cast<intptr_t>(*prototype()); hash = 17 * hash + reinterpret_cast<intptr_t>(*holder()); return hash; @@ -2459,20 +2513,42 @@ class HArgumentsObject: public HTemplateInstruction<0> { class HConstant: public HTemplateInstruction<0> { public: HConstant(Handle<Object> handle, Representation r); + HConstant(int32_t value, Representation r); + HConstant(double value, Representation r); - Handle<Object> handle() const { return handle_; } + Handle<Object> handle() { + if (handle_.is_null()) { + handle_ = FACTORY->NewNumber(double_value_, TENURED); + } + ASSERT(has_int32_value_ || !handle_->IsSmi()); + return handle_; + } bool InOldSpace() const { return !HEAP->InNewSpace(*handle_); } bool ImmortalImmovable() const { + if (has_int32_value_) { + return false; + } + if (has_double_value_) { + if (BitCast<int64_t>(double_value_) == BitCast<int64_t>(-0.0) || + isnan(double_value_)) { + return true; + } + return false; + } + + ASSERT(!handle_.is_null()); Heap* heap = HEAP; + // We should have handled minus_zero_value and nan_value in the + // has_double_value_ clause above. + ASSERT(*handle_ != heap->minus_zero_value()); + ASSERT(*handle_ != heap->nan_value()); if (*handle_ == heap->undefined_value()) return true; if (*handle_ == heap->null_value()) return true; if (*handle_ == heap->true_value()) return true; if (*handle_ == heap->false_value()) return true; if (*handle_ == heap->the_hole_value()) return true; - if (*handle_ == heap->minus_zero_value()) return true; - if (*handle_ == heap->nan_value()) return true; if (*handle_ == heap->empty_string()) return true; return false; } @@ -2482,18 +2558,14 @@ class HConstant: public HTemplateInstruction<0> { } virtual bool IsConvertibleToInteger() const { - if (handle_->IsSmi()) return true; - if (handle_->IsHeapNumber() && - (HeapNumber::cast(*handle_)->value() == - static_cast<double>(NumberToInt32(*handle_)))) return true; - return false; + return has_int32_value_; } virtual bool EmitAtUses() { return !representation().IsDouble(); } virtual HValue* Canonicalize(); virtual void PrintDataTo(StringStream* stream); virtual HType CalculateInferredType(); - bool IsInteger() const { return handle_->IsSmi(); } + bool IsInteger() { return handle()->IsSmi(); } HConstant* CopyToRepresentation(Representation r, Zone* zone) const; HConstant* CopyToTruncatedInt32(Zone* zone) const; bool HasInteger32Value() const { return has_int32_value_; } @@ -2506,24 +2578,35 @@ class HConstant: public HTemplateInstruction<0> { ASSERT(HasDoubleValue()); return double_value_; } - bool HasNumberValue() const { return has_int32_value_ || has_double_value_; } + bool HasNumberValue() const { return has_double_value_; } int32_t NumberValueAsInteger32() const { ASSERT(HasNumberValue()); - if (has_int32_value_) return int32_value_; - return DoubleToInt32(double_value_); + // Irrespective of whether a numeric HConstant can be safely + // represented as an int32, we store the (in some cases lossy) + // representation of the number in int32_value_. + return int32_value_; } - bool HasStringValue() const { return handle_->IsString(); } - bool ToBoolean() const; + bool ToBoolean(); + + bool IsUint32() { + return HasInteger32Value() && (Integer32Value() >= 0); + } virtual intptr_t Hashcode() { - ASSERT(!HEAP->allow_allocation(false)); - intptr_t hash = reinterpret_cast<intptr_t>(*handle()); - // Prevent smis from having fewer hash values when truncated to - // the least significant bits. - const int kShiftSize = kSmiShiftSize + kSmiTagSize; - STATIC_ASSERT(kShiftSize != 0); - return hash ^ (hash >> kShiftSize); + ASSERT_ALLOCATION_DISABLED; + intptr_t hash; + + if (has_int32_value_) { + hash = static_cast<intptr_t>(int32_value_); + } else if (has_double_value_) { + hash = static_cast<intptr_t>(BitCast<int64_t>(double_value_)); + } else { + ASSERT(!handle_.is_null()); + hash = reinterpret_cast<intptr_t>(*handle_); + } + + return hash; } #ifdef DEBUG @@ -2537,15 +2620,32 @@ class HConstant: public HTemplateInstruction<0> { virtual bool DataEquals(HValue* other) { HConstant* other_constant = HConstant::cast(other); - return handle().is_identical_to(other_constant->handle()); + if (has_int32_value_) { + return other_constant->has_int32_value_ && + int32_value_ == other_constant->int32_value_; + } else if (has_double_value_) { + return other_constant->has_double_value_ && + BitCast<int64_t>(double_value_) == + BitCast<int64_t>(other_constant->double_value_); + } else { + ASSERT(!handle_.is_null()); + return !other_constant->handle_.is_null() && + *handle_ == *other_constant->handle_; + } } private: + // If this is a numerical constant, handle_ either points to to the + // HeapObject the constant originated from or is null. If the + // constant is non-numeric, handle_ always points to a valid + // constant HeapObject. Handle<Object> handle_; - // The following two values represent the int32 and the double value of the - // given constant if there is a lossless conversion between the constant - // and the specific representation. + // We store the HConstant in the most specific form safely possible. + // The two flags, has_int32_value_ and has_double_value_ tell us if + // int32_value_ and double_value_ hold valid, safe representations + // of the constant. has_int32_value_ implies has_double_value_ but + // not the converse. bool has_int32_value_ : 1; bool has_double_value_ : 1; int32_t int32_value_; @@ -2706,16 +2806,42 @@ class HAccessArgumentsAt: public HTemplateInstruction<3> { }; +enum BoundsCheckKeyMode { + DONT_ALLOW_SMI_KEY, + ALLOW_SMI_KEY +}; + + class HBoundsCheck: public HTemplateInstruction<2> { public: - HBoundsCheck(HValue* index, HValue* length) { + HBoundsCheck(HValue* index, HValue* length, + BoundsCheckKeyMode key_mode = DONT_ALLOW_SMI_KEY) + : key_mode_(key_mode) { SetOperandAt(0, index); SetOperandAt(1, length); set_representation(Representation::Integer32()); SetFlag(kUseGVN); } - virtual Representation RequiredInputRepresentation(int index) { + virtual Representation RequiredInputRepresentation(int arg_index) { + if (key_mode_ == DONT_ALLOW_SMI_KEY || + !length()->representation().IsTagged()) { + return Representation::Integer32(); + } + // If the index is tagged and isn't constant, then allow the length + // to be tagged, since it is usually already tagged from loading it out of + // the length field of a JSArray. This allows for direct comparison without + // untagging. + if (index()->representation().IsTagged() && !index()->IsConstant()) { + return Representation::Tagged(); + } + // Also allow the length to be tagged if the index is constant, because + // it can be tagged to allow direct comparison. + if (index()->IsConstant() && + index()->representation().IsInteger32() && + arg_index == 1) { + return Representation::Tagged(); + } return Representation::Integer32(); } @@ -2728,6 +2854,7 @@ class HBoundsCheck: public HTemplateInstruction<2> { protected: virtual bool DataEquals(HValue* other) { return true; } + BoundsCheckKeyMode key_mode_; }; @@ -2782,8 +2909,11 @@ class HMathFloorOfDiv: public HBinaryOperation { : HBinaryOperation(context, left, right) { set_representation(Representation::Integer32()); SetFlag(kUseGVN); + SetFlag(kCanOverflow); } + virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited); + virtual Representation RequiredInputRepresentation(int index) { return Representation::Integer32(); } @@ -3388,6 +3518,47 @@ class HDiv: public HArithmeticBinaryOperation { }; +class HMathMinMax: public HArithmeticBinaryOperation { + public: + enum Operation { kMathMin, kMathMax }; + + HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op) + : HArithmeticBinaryOperation(context, left, right), + operation_(op) { } + + virtual Representation RequiredInputRepresentation(int index) { + return index == 0 + ? Representation::Tagged() + : representation(); + } + + virtual Representation InferredRepresentation() { + if (left()->representation().IsInteger32() && + right()->representation().IsInteger32()) { + return Representation::Integer32(); + } + return Representation::Double(); + } + + virtual bool IsCommutative() const { return true; } + + Operation operation() { return operation_; } + + DECLARE_CONCRETE_INSTRUCTION(MathMinMax) + + protected: + virtual bool DataEquals(HValue* other) { + return other->IsMathMinMax() && + HMathMinMax::cast(other)->operation_ == operation_; + } + + virtual Range* InferRange(Zone* zone); + + private: + Operation operation_; +}; + + class HBitwise: public HBitwiseBinaryOperation { public: HBitwise(Token::Value op, HValue* context, HValue* left, HValue* right) @@ -3484,11 +3655,11 @@ class HSar: public HBitwiseBinaryOperation { class HOsrEntry: public HTemplateInstruction<0> { public: - explicit HOsrEntry(int ast_id) : ast_id_(ast_id) { + explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) { SetGVNFlag(kChangesOsrEntries); } - int ast_id() const { return ast_id_; } + BailoutId ast_id() const { return ast_id_; } virtual Representation RequiredInputRepresentation(int index) { return Representation::None(); @@ -3497,7 +3668,7 @@ class HOsrEntry: public HTemplateInstruction<0> { DECLARE_CONCRETE_INSTRUCTION(OsrEntry) private: - int ast_id_; + BailoutId ast_id_; }; @@ -3596,7 +3767,7 @@ class HLoadGlobalCell: public HTemplateInstruction<0> { virtual void PrintDataTo(StringStream* stream); virtual intptr_t Hashcode() { - ASSERT(!HEAP->allow_allocation(false)); + ASSERT_ALLOCATION_DISABLED; return reinterpret_cast<intptr_t>(*cell_); } @@ -3983,10 +4154,11 @@ class ArrayInstructionInterface { }; class HLoadKeyedFastElement - : public HTemplateInstruction<2>, public ArrayInstructionInterface { + : public HTemplateInstruction<3>, public ArrayInstructionInterface { public: HLoadKeyedFastElement(HValue* obj, HValue* key, + HValue* dependency, ElementsKind elements_kind = FAST_ELEMENTS) : bit_field_(0) { ASSERT(IsFastSmiOrObjectElementsKind(elements_kind)); @@ -3997,6 +4169,7 @@ class HLoadKeyedFastElement } SetOperandAt(0, obj); SetOperandAt(1, key); + SetOperandAt(2, dependency); set_representation(Representation::Tagged()); SetGVNFlag(kDependsOnArrayElements); SetFlag(kUseGVN); @@ -4004,6 +4177,7 @@ class HLoadKeyedFastElement HValue* object() { return OperandAt(0); } HValue* key() { return OperandAt(1); } + HValue* dependency() { return OperandAt(2); } uint32_t index_offset() { return IndexOffsetField::decode(bit_field_); } void SetIndexOffset(uint32_t index_offset) { bit_field_ = IndexOffsetField::update(bit_field_, index_offset); @@ -4020,9 +4194,9 @@ class HLoadKeyedFastElement virtual Representation RequiredInputRepresentation(int index) { // The key is supposed to be Integer32. - return index == 0 - ? Representation::Tagged() - : Representation::Integer32(); + if (index == 0) return Representation::Tagged(); + if (index == 1) return Representation::Integer32(); + return Representation::None(); } virtual void PrintDataTo(StringStream* stream); @@ -4052,17 +4226,19 @@ enum HoleCheckMode { PERFORM_HOLE_CHECK, OMIT_HOLE_CHECK }; class HLoadKeyedFastDoubleElement - : public HTemplateInstruction<2>, public ArrayInstructionInterface { + : public HTemplateInstruction<3>, public ArrayInstructionInterface { public: HLoadKeyedFastDoubleElement( HValue* elements, HValue* key, + HValue* dependency, HoleCheckMode hole_check_mode = PERFORM_HOLE_CHECK) : index_offset_(0), is_dehoisted_(false), hole_check_mode_(hole_check_mode) { SetOperandAt(0, elements); SetOperandAt(1, key); + SetOperandAt(2, dependency); set_representation(Representation::Double()); SetGVNFlag(kDependsOnDoubleArrayElements); SetFlag(kUseGVN); @@ -4070,6 +4246,7 @@ class HLoadKeyedFastDoubleElement HValue* elements() { return OperandAt(0); } HValue* key() { return OperandAt(1); } + HValue* dependency() { return OperandAt(2); } uint32_t index_offset() { return index_offset_; } void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; } HValue* GetKey() { return key(); } @@ -4079,9 +4256,9 @@ class HLoadKeyedFastDoubleElement virtual Representation RequiredInputRepresentation(int index) { // The key is supposed to be Integer32. - return index == 0 - ? Representation::Tagged() - : Representation::Integer32(); + if (index == 0) return Representation::Tagged(); + if (index == 1) return Representation::Integer32(); + return Representation::None(); } bool RequiresHoleCheck() { @@ -4108,16 +4285,18 @@ class HLoadKeyedFastDoubleElement class HLoadKeyedSpecializedArrayElement - : public HTemplateInstruction<2>, public ArrayInstructionInterface { + : public HTemplateInstruction<3>, public ArrayInstructionInterface { public: HLoadKeyedSpecializedArrayElement(HValue* external_elements, HValue* key, + HValue* dependency, ElementsKind elements_kind) : elements_kind_(elements_kind), index_offset_(0), is_dehoisted_(false) { SetOperandAt(0, external_elements); SetOperandAt(1, key); + SetOperandAt(2, dependency); if (elements_kind == EXTERNAL_FLOAT_ELEMENTS || elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { set_representation(Representation::Double()); @@ -4133,15 +4312,15 @@ class HLoadKeyedSpecializedArrayElement virtual void PrintDataTo(StringStream* stream); virtual Representation RequiredInputRepresentation(int index) { - // The key is supposed to be Integer32, but the base pointer - // for the element load is a naked pointer. - return index == 0 - ? Representation::External() - : Representation::Integer32(); + // The key is supposed to be Integer32. + if (index == 0) return Representation::External(); + if (index == 1) return Representation::Integer32(); + return Representation::None(); } HValue* external_pointer() { return OperandAt(0); } HValue* key() { return OperandAt(1); } + HValue* dependency() { return OperandAt(2); } ElementsKind elements_kind() const { return elements_kind_; } uint32_t index_offset() { return index_offset_; } void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; } @@ -4797,10 +4976,12 @@ class HObjectLiteral: public HMaterializedLiteral<1> { class HRegExpLiteral: public HMaterializedLiteral<1> { public: HRegExpLiteral(HValue* context, + Handle<FixedArray> literals, Handle<String> pattern, Handle<String> flags, int literal_index) : HMaterializedLiteral<1>(literal_index, 0), + literals_(literals), pattern_(pattern), flags_(flags) { SetOperandAt(0, context); @@ -4808,6 +4989,7 @@ class HRegExpLiteral: public HMaterializedLiteral<1> { } HValue* context() { return OperandAt(0); } + Handle<FixedArray> literals() { return literals_; } Handle<String> pattern() { return pattern_; } Handle<String> flags() { return flags_; } @@ -4819,6 +5001,7 @@ class HRegExpLiteral: public HMaterializedLiteral<1> { DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral) private: + Handle<FixedArray> literals_; Handle<String> pattern_; Handle<String> flags_; }; |