| Index: src/code-stubs.h
|
| ===================================================================
|
| --- src/code-stubs.h (revision 9531)
|
| +++ src/code-stubs.h (working copy)
|
| @@ -45,15 +45,11 @@
|
| V(Compare) \
|
| V(CompareIC) \
|
| V(MathPow) \
|
| + V(RecordWrite) \
|
| + V(StoreBufferOverflow) \
|
| + V(RegExpExec) \
|
| V(TranscendentalCache) \
|
| V(Instanceof) \
|
| - /* All stubs above this line only exist in a few versions, which are */ \
|
| - /* generated ahead of time. Therefore compiling a call to one of */ \
|
| - /* them can't cause a new stub to be compiled, so compiling a call to */ \
|
| - /* them is GC safe. The ones below this line exist in many variants */ \
|
| - /* so code compiling a call to one can cause a GC. This means they */ \
|
| - /* can't be called from other stubs, since stub generation code is */ \
|
| - /* not GC safe. */ \
|
| V(ConvertToDouble) \
|
| V(WriteInt32ToHeapNumber) \
|
| V(StackCheck) \
|
| @@ -65,7 +61,6 @@
|
| V(ToNumber) \
|
| V(CounterOp) \
|
| V(ArgumentsAccess) \
|
| - V(RegExpExec) \
|
| V(RegExpConstructResult) \
|
| V(NumberToString) \
|
| V(CEntry) \
|
| @@ -73,7 +68,7 @@
|
| V(KeyedLoadElement) \
|
| V(KeyedStoreElement) \
|
| V(DebuggerStatement) \
|
| - V(StringDictionaryNegativeLookup)
|
| + V(StringDictionaryLookup)
|
|
|
| // List of code stubs only used on ARM platforms.
|
| #ifdef V8_TARGET_ARCH_ARM
|
| @@ -142,6 +137,27 @@
|
|
|
| virtual ~CodeStub() {}
|
|
|
| + bool CompilingCallsToThisStubIsGCSafe() {
|
| + bool is_pregenerated = IsPregenerated();
|
| + Code* code = NULL;
|
| + CHECK(!is_pregenerated || FindCodeInCache(&code));
|
| + return is_pregenerated;
|
| + }
|
| +
|
| + // See comment above, where Instanceof is defined.
|
| + virtual bool IsPregenerated() { return false; }
|
| +
|
| + static void GenerateStubsAheadOfTime();
|
| + static void GenerateFPStubs();
|
| +
|
| + // Some stubs put untagged junk on the stack that cannot be scanned by the
|
| + // GC. This means that we must be statically sure that no GC can occur while
|
| + // they are running. If that is the case they should override this to return
|
| + // true, which will cause an assertion if we try to call something that can
|
| + // GC or if we try to put a stack frame on top of the junk, which would not
|
| + // result in a traversable stack.
|
| + virtual bool SometimesSetsUpAFrame() { return true; }
|
| +
|
| protected:
|
| static const int kMajorBits = 6;
|
| static const int kMinorBits = kBitsPerInt - kSmiTagSize - kMajorBits;
|
| @@ -164,6 +180,14 @@
|
| // Finish the code object after it has been generated.
|
| virtual void FinishCode(Code* code) { }
|
|
|
| + // Returns true if TryGetCode should fail if it failed
|
| + // to register newly generated stub in the stub cache.
|
| + virtual bool MustBeInStubCache() { return false; }
|
| +
|
| + // Activate newly generated stub. Is called after
|
| + // registering stub in the stub cache.
|
| + virtual void Activate(Code* code) { }
|
| +
|
| // Returns information for computing the number key.
|
| virtual Major MajorKey() = 0;
|
| virtual int MinorKey() = 0;
|
| @@ -178,9 +202,7 @@
|
|
|
| // Returns a name for logging/debugging purposes.
|
| SmartArrayPointer<const char> GetName();
|
| - virtual void PrintName(StringStream* stream) {
|
| - stream->Add("%s", MajorName(MajorKey(), false));
|
| - }
|
| + virtual void PrintName(StringStream* stream);
|
|
|
| // Returns whether the code generated for this stub needs to be allocated as
|
| // a fixed (non-moveable) code object.
|
| @@ -193,9 +215,6 @@
|
| MajorKeyBits::encode(MajorKey());
|
| }
|
|
|
| - // See comment above, where Instanceof is defined.
|
| - bool AllowsStubCalls() { return MajorKey() <= Instanceof; }
|
| -
|
| class MajorKeyBits: public BitField<uint32_t, 0, kMajorBits> {};
|
| class MinorKeyBits: public BitField<uint32_t, kMajorBits, kMinorBits> {};
|
|
|
| @@ -531,12 +550,19 @@
|
|
|
| class CEntryStub : public CodeStub {
|
| public:
|
| - explicit CEntryStub(int result_size)
|
| - : result_size_(result_size), save_doubles_(false) { }
|
| + explicit CEntryStub(int result_size,
|
| + SaveFPRegsMode save_doubles = kDontSaveFPRegs)
|
| + : result_size_(result_size), save_doubles_(save_doubles) { }
|
|
|
| void Generate(MacroAssembler* masm);
|
| - void SaveDoubles() { save_doubles_ = true; }
|
|
|
| + // The version of this stub that doesn't save doubles is generated ahead of
|
| + // time, so it's OK to call it from other stubs that can't cope with GC during
|
| + // their code generation. On machines that always have gp registers (x64) we
|
| + // can generate both variants ahead of time.
|
| + virtual bool IsPregenerated();
|
| + static void GenerateAheadOfTime();
|
| +
|
| private:
|
| void GenerateCore(MacroAssembler* masm,
|
| Label* throw_normal_exception,
|
| @@ -550,7 +576,7 @@
|
|
|
| // Number of pointers/values returned.
|
| const int result_size_;
|
| - bool save_doubles_;
|
| + SaveFPRegsMode save_doubles_;
|
|
|
| Major MajorKey() { return CEntry; }
|
| int MinorKey();
|
| @@ -647,10 +673,32 @@
|
|
|
| void Generate(MacroAssembler* masm);
|
|
|
| + virtual void FinishCode(Code* code);
|
| +
|
| + static void Clear(Heap* heap, Address address);
|
| +
|
| + static Object* GetCachedValue(Address address);
|
| +
|
| static int ExtractArgcFromMinorKey(int minor_key) {
|
| return ArgcBits::decode(minor_key);
|
| }
|
|
|
| + // The object that indicates an uninitialized cache.
|
| + static Handle<Object> UninitializedSentinel(Isolate* isolate) {
|
| + return isolate->factory()->the_hole_value();
|
| + }
|
| +
|
| + // A raw version of the uninitialized sentinel that's safe to read during
|
| + // garbage collection (e.g., for patching the cache).
|
| + static Object* RawUninitializedSentinel(Heap* heap) {
|
| + return heap->raw_unchecked_the_hole_value();
|
| + }
|
| +
|
| + // The object that indicates a megamorphic state.
|
| + static Handle<Object> MegamorphicSentinel(Isolate* isolate) {
|
| + return isolate->factory()->undefined_value();
|
| + }
|
| +
|
| private:
|
| int argc_;
|
| CallFunctionFlags flags_;
|
| @@ -658,8 +706,8 @@
|
| virtual void PrintName(StringStream* stream);
|
|
|
| // Minor key encoding in 32 bits with Bitfield <Type, shift, size>.
|
| - class FlagBits: public BitField<CallFunctionFlags, 0, 1> {};
|
| - class ArgcBits: public BitField<unsigned, 1, 32 - 1> {};
|
| + class FlagBits: public BitField<CallFunctionFlags, 0, 2> {};
|
| + class ArgcBits: public BitField<unsigned, 2, 32 - 2> {};
|
|
|
| Major MajorKey() { return CallFunction; }
|
| int MinorKey() {
|
| @@ -670,6 +718,10 @@
|
| bool ReceiverMightBeImplicit() {
|
| return (flags_ & RECEIVER_MIGHT_BE_IMPLICIT) != 0;
|
| }
|
| +
|
| + bool RecordCallTarget() {
|
| + return (flags_ & RECORD_CALL_TARGET) != 0;
|
| + }
|
| };
|
|
|
|
|
| @@ -934,6 +986,8 @@
|
| virtual int GetCodeKind() { return Code::TO_BOOLEAN_IC; }
|
| virtual void PrintName(StringStream* stream);
|
|
|
| + virtual bool SometimesSetsUpAFrame() { return false; }
|
| +
|
| private:
|
| Major MajorKey() { return ToBoolean; }
|
| int MinorKey() { return (tos_.code() << NUMBER_OF_TYPES) | types_.ToByte(); }
|
|
|