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(); } |