d8131cd63a
Stubs and builtins are very similar. The main differences are that stubs can be parameterized and may be generated at runtime, whereas builtins are generated at mksnapshot-time and shipped with the snapshot (or embedded into the binary). My main motivation for these conversions is that we can generate faster calls and jumps to (embedded) builtins callees from (embedded) builtin callers. Instead of going through the builtins constants table indirection, we can simply do a pc-relative call/jump. This also unlocks other refactorings, e.g. removal of CallRuntimeDelayed. TBR=mlippautz@chromium.org Bug: v8:6666 Change-Id: I4cd63477f19a330ec70bbf20e2af8a42fb05fabb Reviewed-on: https://chromium-review.googlesource.com/1044245 Reviewed-by: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Commit-Queue: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#53027}
856 lines
28 KiB
C++
856 lines
28 KiB
C++
// Copyright 2012 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.
|
|
|
|
#ifndef V8_CODE_STUBS_H_
|
|
#define V8_CODE_STUBS_H_
|
|
|
|
#include "src/allocation.h"
|
|
#include "src/assembler.h"
|
|
#include "src/globals.h"
|
|
#include "src/heap/factory.h"
|
|
#include "src/interface-descriptors.h"
|
|
#include "src/macro-assembler.h"
|
|
#include "src/ostreams.h"
|
|
#include "src/type-hints.h"
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
|
|
// Forward declarations.
|
|
class CodeStubAssembler;
|
|
namespace compiler {
|
|
class CodeAssemblerLabel;
|
|
class CodeAssemblerState;
|
|
class Node;
|
|
}
|
|
|
|
// List of code stubs used on all platforms.
|
|
#define CODE_STUB_LIST_ALL_PLATFORMS(V) \
|
|
/* --- PlatformCodeStubs --- */ \
|
|
V(ArrayConstructor) \
|
|
V(CallApiCallback) \
|
|
V(CallApiGetter) \
|
|
V(InternalArrayConstructor) \
|
|
V(JSEntry) \
|
|
V(ProfileEntryHook) \
|
|
/* --- TurboFanCodeStubs --- */ \
|
|
V(StoreSlowElement) \
|
|
V(StoreInArrayLiteralSlow) \
|
|
V(ArrayNoArgumentConstructor) \
|
|
V(ArraySingleArgumentConstructor) \
|
|
V(ArrayNArgumentsConstructor) \
|
|
V(InternalArrayNoArgumentConstructor) \
|
|
V(InternalArraySingleArgumentConstructor) \
|
|
V(ElementsTransitionAndStore) \
|
|
V(KeyedLoadSloppyArguments) \
|
|
V(KeyedStoreSloppyArguments) \
|
|
V(StoreFastElement) \
|
|
V(StoreInterceptor) \
|
|
V(TransitionElementsKind) \
|
|
V(LoadIndexedInterceptor)
|
|
|
|
// List of code stubs only used on ARM 32 bits platforms.
|
|
#if V8_TARGET_ARCH_ARM
|
|
#define CODE_STUB_LIST_ARM(V) V(DirectCEntry)
|
|
|
|
#else
|
|
#define CODE_STUB_LIST_ARM(V)
|
|
#endif
|
|
|
|
// List of code stubs only used on ARM 64 bits platforms.
|
|
#if V8_TARGET_ARCH_ARM64
|
|
#define CODE_STUB_LIST_ARM64(V) V(DirectCEntry)
|
|
|
|
#else
|
|
#define CODE_STUB_LIST_ARM64(V)
|
|
#endif
|
|
|
|
// List of code stubs only used on PPC platforms.
|
|
#ifdef V8_TARGET_ARCH_PPC
|
|
#define CODE_STUB_LIST_PPC(V) V(DirectCEntry)
|
|
#else
|
|
#define CODE_STUB_LIST_PPC(V)
|
|
#endif
|
|
|
|
// List of code stubs only used on MIPS platforms.
|
|
#if V8_TARGET_ARCH_MIPS
|
|
#define CODE_STUB_LIST_MIPS(V) V(DirectCEntry)
|
|
#elif V8_TARGET_ARCH_MIPS64
|
|
#define CODE_STUB_LIST_MIPS(V) V(DirectCEntry)
|
|
#else
|
|
#define CODE_STUB_LIST_MIPS(V)
|
|
#endif
|
|
|
|
// List of code stubs only used on S390 platforms.
|
|
#ifdef V8_TARGET_ARCH_S390
|
|
#define CODE_STUB_LIST_S390(V) V(DirectCEntry)
|
|
#else
|
|
#define CODE_STUB_LIST_S390(V)
|
|
#endif
|
|
|
|
// Combined list of code stubs.
|
|
#define CODE_STUB_LIST(V) \
|
|
CODE_STUB_LIST_ALL_PLATFORMS(V) \
|
|
CODE_STUB_LIST_ARM(V) \
|
|
CODE_STUB_LIST_ARM64(V) \
|
|
CODE_STUB_LIST_PPC(V) \
|
|
CODE_STUB_LIST_MIPS(V) \
|
|
CODE_STUB_LIST_S390(V)
|
|
|
|
static const int kHasReturnedMinusZeroSentinel = 1;
|
|
|
|
class CodeStub : public ZoneObject {
|
|
public:
|
|
enum Major {
|
|
// TODO(mvstanton): eliminate the NoCache key by getting rid
|
|
// of the non-monomorphic-cache.
|
|
NoCache = 0, // marker for stubs that do custom caching]
|
|
#define DEF_ENUM(name) name,
|
|
CODE_STUB_LIST(DEF_ENUM)
|
|
#undef DEF_ENUM
|
|
NUMBER_OF_IDS
|
|
};
|
|
|
|
// Retrieve the code for the stub. Generate the code if needed.
|
|
Handle<Code> GetCode();
|
|
|
|
static Major MajorKeyFromKey(uint32_t key) {
|
|
return static_cast<Major>(MajorKeyBits::decode(key));
|
|
}
|
|
static uint32_t MinorKeyFromKey(uint32_t key) {
|
|
return MinorKeyBits::decode(key);
|
|
}
|
|
|
|
// Gets the major key from a code object that is a code stub or binary op IC.
|
|
static Major GetMajorKey(Code* code_stub);
|
|
|
|
static uint32_t NoCacheKey() { return MajorKeyBits::encode(NoCache); }
|
|
|
|
static const char* MajorName(Major major_key);
|
|
|
|
explicit CodeStub(Isolate* isolate) : minor_key_(0), isolate_(isolate) {}
|
|
virtual ~CodeStub() {}
|
|
|
|
static void GenerateStubsAheadOfTime(Isolate* isolate);
|
|
|
|
// 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; }
|
|
|
|
// Lookup the code in the (possibly custom) cache.
|
|
bool FindCodeInCache(Code** code_out);
|
|
|
|
virtual CallInterfaceDescriptor GetCallInterfaceDescriptor() const = 0;
|
|
|
|
virtual int GetStackParameterCount() const {
|
|
return GetCallInterfaceDescriptor().GetStackParameterCount();
|
|
}
|
|
|
|
virtual void InitializeDescriptor(CodeStubDescriptor* descriptor) {}
|
|
|
|
static void InitializeDescriptor(Isolate* isolate, uint32_t key,
|
|
CodeStubDescriptor* desc);
|
|
|
|
static MaybeHandle<Code> GetCode(Isolate* isolate, uint32_t key);
|
|
|
|
// Returns information for computing the number key.
|
|
virtual Major MajorKey() const = 0;
|
|
uint32_t MinorKey() const { return minor_key_; }
|
|
|
|
friend std::ostream& operator<<(std::ostream& os, const CodeStub& s) {
|
|
s.PrintName(os);
|
|
return os;
|
|
}
|
|
|
|
Isolate* isolate() const { return isolate_; }
|
|
void set_isolate(Isolate* isolate) {
|
|
DCHECK_NOT_NULL(isolate);
|
|
DCHECK(isolate_ == nullptr || isolate_ == isolate);
|
|
isolate_ = isolate;
|
|
}
|
|
|
|
void DeleteStubFromCacheForTesting();
|
|
|
|
protected:
|
|
CodeStub(uint32_t key, Isolate* isolate)
|
|
: minor_key_(MinorKeyFromKey(key)), isolate_(isolate) {}
|
|
|
|
// Generates the assembler code for the stub.
|
|
virtual Handle<Code> GenerateCode() = 0;
|
|
|
|
// Returns whether the code generated for this stub needs to be allocated as
|
|
// a fixed (non-moveable) code object.
|
|
// TODO(jgruber): Only required by DirectCEntryStub. Can be removed when/if
|
|
// that is ported to a builtin.
|
|
virtual Movability NeedsImmovableCode() { return kMovable; }
|
|
|
|
virtual void PrintName(std::ostream& os) const; // NOLINT
|
|
virtual void PrintBaseName(std::ostream& os) const; // NOLINT
|
|
virtual void PrintState(std::ostream& os) const { ; } // NOLINT
|
|
|
|
// Computes the key based on major and minor.
|
|
uint32_t GetKey() {
|
|
DCHECK(static_cast<int>(MajorKey()) < NUMBER_OF_IDS);
|
|
return MinorKeyBits::encode(MinorKey()) | MajorKeyBits::encode(MajorKey());
|
|
}
|
|
|
|
uint32_t minor_key_;
|
|
|
|
private:
|
|
// Perform bookkeeping required after code generation when stub code is
|
|
// initially generated.
|
|
void RecordCodeGeneration(Handle<Code> code);
|
|
|
|
// Activate newly generated stub. Is called after
|
|
// registering stub in the stub cache.
|
|
virtual void Activate(Code* code) { }
|
|
|
|
// We use this dispatch to statically instantiate the correct code stub for
|
|
// the given stub key and call the passed function with that code stub.
|
|
typedef void (*DispatchedCall)(CodeStub* stub, void** value_out);
|
|
static void Dispatch(Isolate* isolate, uint32_t key, void** value_out,
|
|
DispatchedCall call);
|
|
|
|
static void GetCodeDispatchCall(CodeStub* stub, void** value_out);
|
|
|
|
STATIC_ASSERT(NUMBER_OF_IDS < (1 << kStubMajorKeyBits));
|
|
class MajorKeyBits: public BitField<uint32_t, 0, kStubMajorKeyBits> {};
|
|
class MinorKeyBits: public BitField<uint32_t,
|
|
kStubMajorKeyBits, kStubMinorKeyBits> {}; // NOLINT
|
|
|
|
friend class BreakPointIterator;
|
|
|
|
Isolate* isolate_;
|
|
};
|
|
|
|
|
|
#define DEFINE_CODE_STUB_BASE(NAME, SUPER) \
|
|
public: \
|
|
NAME(uint32_t key, Isolate* isolate) : SUPER(key, isolate) {} \
|
|
\
|
|
private: \
|
|
DISALLOW_COPY_AND_ASSIGN(NAME)
|
|
|
|
|
|
#define DEFINE_CODE_STUB(NAME, SUPER) \
|
|
public: \
|
|
inline Major MajorKey() const override { return NAME; }; \
|
|
\
|
|
DEFINE_CODE_STUB_BASE(NAME##Stub, SUPER)
|
|
|
|
|
|
#define DEFINE_PLATFORM_CODE_STUB(NAME, SUPER) \
|
|
private: \
|
|
void Generate(MacroAssembler* masm) override; \
|
|
DEFINE_CODE_STUB(NAME, SUPER)
|
|
|
|
|
|
#define DEFINE_TURBOFAN_CODE_STUB(NAME, SUPER) \
|
|
public: \
|
|
void GenerateAssembly(compiler::CodeAssemblerState* state) const override; \
|
|
DEFINE_CODE_STUB(NAME, SUPER)
|
|
|
|
#define DEFINE_CALL_INTERFACE_DESCRIPTOR(NAME) \
|
|
public: \
|
|
typedef NAME##Descriptor Descriptor; \
|
|
CallInterfaceDescriptor GetCallInterfaceDescriptor() const override { \
|
|
return Descriptor(isolate()); \
|
|
}
|
|
|
|
// There are some code stubs we just can't describe right now with a
|
|
// CallInterfaceDescriptor. Isolate behavior for those cases with this macro.
|
|
// An attempt to retrieve a descriptor will fail.
|
|
#define DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR() \
|
|
public: \
|
|
CallInterfaceDescriptor GetCallInterfaceDescriptor() const override { \
|
|
UNREACHABLE(); \
|
|
return CallInterfaceDescriptor(); \
|
|
}
|
|
|
|
|
|
class PlatformCodeStub : public CodeStub {
|
|
public:
|
|
// Retrieve the code for the stub. Generate the code if needed.
|
|
Handle<Code> GenerateCode() override;
|
|
|
|
protected:
|
|
explicit PlatformCodeStub(Isolate* isolate) : CodeStub(isolate) {}
|
|
|
|
// Generates the assembler code for the stub.
|
|
virtual void Generate(MacroAssembler* masm) = 0;
|
|
|
|
// Generates the exception handler table for the stub.
|
|
virtual int GenerateHandlerTable(MacroAssembler* masm);
|
|
|
|
DEFINE_CODE_STUB_BASE(PlatformCodeStub, CodeStub);
|
|
};
|
|
|
|
|
|
enum StubFunctionMode { NOT_JS_FUNCTION_STUB_MODE, JS_FUNCTION_STUB_MODE };
|
|
|
|
|
|
class CodeStubDescriptor {
|
|
public:
|
|
explicit CodeStubDescriptor(CodeStub* stub);
|
|
|
|
CodeStubDescriptor(Isolate* isolate, uint32_t stub_key);
|
|
|
|
void Initialize(Address deoptimization_handler = kNullAddress,
|
|
int hint_stack_parameter_count = -1,
|
|
StubFunctionMode function_mode = NOT_JS_FUNCTION_STUB_MODE);
|
|
void Initialize(Register stack_parameter_count,
|
|
Address deoptimization_handler = kNullAddress,
|
|
int hint_stack_parameter_count = -1,
|
|
StubFunctionMode function_mode = NOT_JS_FUNCTION_STUB_MODE);
|
|
|
|
void SetMissHandler(Runtime::FunctionId id) {
|
|
miss_handler_id_ = id;
|
|
miss_handler_ = ExternalReference::Create(Runtime::FunctionForId(id));
|
|
has_miss_handler_ = true;
|
|
// Our miss handler infrastructure doesn't currently support
|
|
// variable stack parameter counts.
|
|
DCHECK(!stack_parameter_count_.is_valid());
|
|
}
|
|
|
|
void set_call_descriptor(CallInterfaceDescriptor d) { call_descriptor_ = d; }
|
|
CallInterfaceDescriptor call_descriptor() const { return call_descriptor_; }
|
|
|
|
int GetRegisterParameterCount() const {
|
|
return call_descriptor().GetRegisterParameterCount();
|
|
}
|
|
|
|
int GetStackParameterCount() const {
|
|
return call_descriptor().GetStackParameterCount();
|
|
}
|
|
|
|
int GetParameterCount() const {
|
|
return call_descriptor().GetParameterCount();
|
|
}
|
|
|
|
Register GetRegisterParameter(int index) const {
|
|
return call_descriptor().GetRegisterParameter(index);
|
|
}
|
|
|
|
MachineType GetParameterType(int index) const {
|
|
return call_descriptor().GetParameterType(index);
|
|
}
|
|
|
|
ExternalReference miss_handler() const {
|
|
DCHECK(has_miss_handler_);
|
|
return miss_handler_;
|
|
}
|
|
|
|
Runtime::FunctionId miss_handler_id() const {
|
|
DCHECK(has_miss_handler_);
|
|
return miss_handler_id_;
|
|
}
|
|
|
|
bool has_miss_handler() const {
|
|
return has_miss_handler_;
|
|
}
|
|
|
|
int GetHandlerParameterCount() const {
|
|
int params = GetParameterCount();
|
|
if (PassesArgumentsToDeoptimizationHandler()) {
|
|
params += 1;
|
|
}
|
|
return params;
|
|
}
|
|
|
|
int hint_stack_parameter_count() const { return hint_stack_parameter_count_; }
|
|
Register stack_parameter_count() const { return stack_parameter_count_; }
|
|
StubFunctionMode function_mode() const { return function_mode_; }
|
|
Address deoptimization_handler() const { return deoptimization_handler_; }
|
|
|
|
private:
|
|
bool PassesArgumentsToDeoptimizationHandler() const {
|
|
return stack_parameter_count_.is_valid();
|
|
}
|
|
|
|
Isolate* isolate_;
|
|
CallInterfaceDescriptor call_descriptor_;
|
|
Register stack_parameter_count_;
|
|
// If hint_stack_parameter_count_ > 0, the code stub can optimize the
|
|
// return sequence. Default value is -1, which means it is ignored.
|
|
int hint_stack_parameter_count_;
|
|
StubFunctionMode function_mode_;
|
|
|
|
Address deoptimization_handler_;
|
|
|
|
ExternalReference miss_handler_;
|
|
Runtime::FunctionId miss_handler_id_;
|
|
bool has_miss_handler_;
|
|
};
|
|
|
|
|
|
class TurboFanCodeStub : public CodeStub {
|
|
public:
|
|
// Retrieve the code for the stub. Generate the code if needed.
|
|
Handle<Code> GenerateCode() override;
|
|
|
|
int GetStackParameterCount() const override {
|
|
return GetCallInterfaceDescriptor().GetStackParameterCount();
|
|
}
|
|
|
|
protected:
|
|
explicit TurboFanCodeStub(Isolate* isolate) : CodeStub(isolate) {}
|
|
|
|
virtual void GenerateAssembly(compiler::CodeAssemblerState* state) const = 0;
|
|
|
|
private:
|
|
DEFINE_CODE_STUB_BASE(TurboFanCodeStub, CodeStub);
|
|
};
|
|
|
|
} // namespace internal
|
|
} // namespace v8
|
|
|
|
#if V8_TARGET_ARCH_IA32
|
|
#elif V8_TARGET_ARCH_X64
|
|
#elif V8_TARGET_ARCH_ARM64
|
|
#include "src/arm64/code-stubs-arm64.h"
|
|
#elif V8_TARGET_ARCH_ARM
|
|
#include "src/arm/code-stubs-arm.h"
|
|
#elif V8_TARGET_ARCH_PPC
|
|
#include "src/ppc/code-stubs-ppc.h"
|
|
#elif V8_TARGET_ARCH_MIPS
|
|
#include "src/mips/code-stubs-mips.h"
|
|
#elif V8_TARGET_ARCH_MIPS64
|
|
#include "src/mips64/code-stubs-mips64.h"
|
|
#elif V8_TARGET_ARCH_S390
|
|
#include "src/s390/code-stubs-s390.h"
|
|
#else
|
|
#error Unsupported target architecture.
|
|
#endif
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
|
|
// TODO(jgruber): Convert this stub into a builtin.
|
|
class StoreInterceptorStub : public TurboFanCodeStub {
|
|
public:
|
|
explicit StoreInterceptorStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
|
|
|
|
DEFINE_CALL_INTERFACE_DESCRIPTOR(StoreWithVector);
|
|
DEFINE_TURBOFAN_CODE_STUB(StoreInterceptor, TurboFanCodeStub);
|
|
};
|
|
|
|
class TransitionElementsKindStub : public TurboFanCodeStub {
|
|
public:
|
|
TransitionElementsKindStub(Isolate* isolate, ElementsKind from_kind,
|
|
ElementsKind to_kind, bool is_jsarray)
|
|
: TurboFanCodeStub(isolate) {
|
|
set_sub_minor_key(FromKindBits::encode(from_kind) |
|
|
ToKindBits::encode(to_kind) |
|
|
IsJSArrayBits::encode(is_jsarray));
|
|
}
|
|
|
|
void set_sub_minor_key(uint32_t key) { minor_key_ = key; }
|
|
|
|
uint32_t sub_minor_key() const { return minor_key_; }
|
|
|
|
ElementsKind from_kind() const {
|
|
return FromKindBits::decode(sub_minor_key());
|
|
}
|
|
|
|
ElementsKind to_kind() const { return ToKindBits::decode(sub_minor_key()); }
|
|
|
|
bool is_jsarray() const { return IsJSArrayBits::decode(sub_minor_key()); }
|
|
|
|
private:
|
|
class ToKindBits : public BitField<ElementsKind, 0, 8> {};
|
|
class FromKindBits : public BitField<ElementsKind, ToKindBits::kNext, 8> {};
|
|
class IsJSArrayBits : public BitField<bool, FromKindBits::kNext, 1> {};
|
|
|
|
DEFINE_CALL_INTERFACE_DESCRIPTOR(TransitionElementsKind);
|
|
DEFINE_TURBOFAN_CODE_STUB(TransitionElementsKind, TurboFanCodeStub);
|
|
};
|
|
|
|
// TODO(jgruber): Convert this stub into a builtin.
|
|
class LoadIndexedInterceptorStub : public TurboFanCodeStub {
|
|
public:
|
|
explicit LoadIndexedInterceptorStub(Isolate* isolate)
|
|
: TurboFanCodeStub(isolate) {}
|
|
|
|
DEFINE_CALL_INTERFACE_DESCRIPTOR(LoadWithVector);
|
|
DEFINE_TURBOFAN_CODE_STUB(LoadIndexedInterceptor, TurboFanCodeStub);
|
|
};
|
|
|
|
enum AllocationSiteOverrideMode {
|
|
DONT_OVERRIDE,
|
|
DISABLE_ALLOCATION_SITES,
|
|
LAST_ALLOCATION_SITE_OVERRIDE_MODE = DISABLE_ALLOCATION_SITES
|
|
};
|
|
|
|
// TODO(jgruber): Convert this stub into a builtin.
|
|
class ArrayConstructorStub: public PlatformCodeStub {
|
|
public:
|
|
explicit ArrayConstructorStub(Isolate* isolate);
|
|
|
|
private:
|
|
void GenerateDispatchToArrayStub(MacroAssembler* masm,
|
|
AllocationSiteOverrideMode mode);
|
|
|
|
DEFINE_CALL_INTERFACE_DESCRIPTOR(ArrayConstructor);
|
|
DEFINE_PLATFORM_CODE_STUB(ArrayConstructor, PlatformCodeStub);
|
|
};
|
|
|
|
// TODO(jgruber): Convert this stub into a builtin.
|
|
class InternalArrayConstructorStub: public PlatformCodeStub {
|
|
public:
|
|
explicit InternalArrayConstructorStub(Isolate* isolate);
|
|
|
|
private:
|
|
void GenerateCase(MacroAssembler* masm, ElementsKind kind);
|
|
|
|
DEFINE_CALL_INTERFACE_DESCRIPTOR(ArrayNArgumentsConstructor);
|
|
DEFINE_PLATFORM_CODE_STUB(InternalArrayConstructor, PlatformCodeStub);
|
|
};
|
|
|
|
// TODO(jgruber): Convert this stub into a builtin.
|
|
class KeyedLoadSloppyArgumentsStub : public TurboFanCodeStub {
|
|
public:
|
|
explicit KeyedLoadSloppyArgumentsStub(Isolate* isolate)
|
|
: TurboFanCodeStub(isolate) {}
|
|
|
|
protected:
|
|
DEFINE_CALL_INTERFACE_DESCRIPTOR(LoadWithVector);
|
|
DEFINE_TURBOFAN_CODE_STUB(KeyedLoadSloppyArguments, TurboFanCodeStub);
|
|
};
|
|
|
|
|
|
class CommonStoreModeBits : public BitField<KeyedAccessStoreMode, 0, 3> {};
|
|
|
|
class KeyedStoreSloppyArgumentsStub : public TurboFanCodeStub {
|
|
public:
|
|
explicit KeyedStoreSloppyArgumentsStub(Isolate* isolate,
|
|
KeyedAccessStoreMode mode)
|
|
: TurboFanCodeStub(isolate) {
|
|
minor_key_ = CommonStoreModeBits::encode(mode);
|
|
}
|
|
|
|
protected:
|
|
DEFINE_CALL_INTERFACE_DESCRIPTOR(StoreWithVector);
|
|
DEFINE_TURBOFAN_CODE_STUB(KeyedStoreSloppyArguments, TurboFanCodeStub);
|
|
};
|
|
|
|
class CallApiCallbackStub : public PlatformCodeStub {
|
|
public:
|
|
static const int kArgBits = 7;
|
|
static const int kArgMax = (1 << kArgBits) - 1;
|
|
|
|
CallApiCallbackStub(Isolate* isolate, int argc)
|
|
: PlatformCodeStub(isolate) {
|
|
CHECK_LE(0, argc);
|
|
CHECK_LE(argc, kArgMax);
|
|
minor_key_ = ArgumentBits::encode(argc);
|
|
}
|
|
|
|
private:
|
|
int argc() const { return ArgumentBits::decode(minor_key_); }
|
|
|
|
class ArgumentBits : public BitField<int, 0, kArgBits> {};
|
|
|
|
DEFINE_CALL_INTERFACE_DESCRIPTOR(ApiCallback);
|
|
DEFINE_PLATFORM_CODE_STUB(CallApiCallback, PlatformCodeStub);
|
|
};
|
|
|
|
// TODO(jgruber): Convert this stub into a builtin.
|
|
class CallApiGetterStub : public PlatformCodeStub {
|
|
public:
|
|
explicit CallApiGetterStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
|
|
|
|
DEFINE_CALL_INTERFACE_DESCRIPTOR(ApiGetter);
|
|
DEFINE_PLATFORM_CODE_STUB(CallApiGetter, PlatformCodeStub);
|
|
};
|
|
|
|
class JSEntryStub : public PlatformCodeStub {
|
|
public:
|
|
enum class SpecialTarget { kNone, kRunMicrotasks };
|
|
JSEntryStub(Isolate* isolate, StackFrame::Type type)
|
|
: PlatformCodeStub(isolate) {
|
|
DCHECK(type == StackFrame::ENTRY || type == StackFrame::CONSTRUCT_ENTRY);
|
|
minor_key_ = StackFrameTypeBits::encode(type) |
|
|
SpecialTargetBits::encode(SpecialTarget::kNone);
|
|
}
|
|
|
|
JSEntryStub(Isolate* isolate, SpecialTarget target)
|
|
: PlatformCodeStub(isolate) {
|
|
minor_key_ = StackFrameTypeBits::encode(StackFrame::ENTRY) |
|
|
SpecialTargetBits::encode(target);
|
|
}
|
|
|
|
private:
|
|
int GenerateHandlerTable(MacroAssembler* masm) override;
|
|
|
|
void PrintName(std::ostream& os) const override { // NOLINT
|
|
os << (type() == StackFrame::ENTRY ? "JSEntryStub"
|
|
: "JSConstructEntryStub");
|
|
}
|
|
|
|
StackFrame::Type type() const {
|
|
return StackFrameTypeBits::decode(minor_key_);
|
|
}
|
|
|
|
SpecialTarget special_target() const {
|
|
return SpecialTargetBits::decode(minor_key_);
|
|
}
|
|
|
|
Handle<Code> EntryTrampoline() {
|
|
switch (special_target()) {
|
|
case SpecialTarget::kNone:
|
|
return (type() == StackFrame::CONSTRUCT_ENTRY)
|
|
? BUILTIN_CODE(isolate(), JSConstructEntryTrampoline)
|
|
: BUILTIN_CODE(isolate(), JSEntryTrampoline);
|
|
case SpecialTarget::kRunMicrotasks:
|
|
return BUILTIN_CODE(isolate(), RunMicrotasks);
|
|
}
|
|
UNREACHABLE();
|
|
return Handle<Code>();
|
|
}
|
|
|
|
class StackFrameTypeBits : public BitField<StackFrame::Type, 0, 5> {};
|
|
class SpecialTargetBits
|
|
: public BitField<SpecialTarget, StackFrameTypeBits::kNext, 1> {};
|
|
|
|
int handler_offset_;
|
|
|
|
DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
|
|
DEFINE_PLATFORM_CODE_STUB(JSEntry, PlatformCodeStub);
|
|
};
|
|
|
|
class StoreFastElementStub : public TurboFanCodeStub {
|
|
public:
|
|
StoreFastElementStub(Isolate* isolate, bool is_js_array,
|
|
ElementsKind elements_kind, KeyedAccessStoreMode mode)
|
|
: TurboFanCodeStub(isolate) {
|
|
minor_key_ = CommonStoreModeBits::encode(mode) |
|
|
ElementsKindBits::encode(elements_kind) |
|
|
IsJSArrayBits::encode(is_js_array);
|
|
}
|
|
|
|
static void GenerateAheadOfTime(Isolate* isolate);
|
|
|
|
bool is_js_array() const { return IsJSArrayBits::decode(minor_key_); }
|
|
|
|
ElementsKind elements_kind() const {
|
|
return ElementsKindBits::decode(minor_key_);
|
|
}
|
|
|
|
KeyedAccessStoreMode store_mode() const {
|
|
return CommonStoreModeBits::decode(minor_key_);
|
|
}
|
|
|
|
private:
|
|
class ElementsKindBits
|
|
: public BitField<ElementsKind, CommonStoreModeBits::kNext, 8> {};
|
|
class IsJSArrayBits : public BitField<bool, ElementsKindBits::kNext, 1> {};
|
|
|
|
DEFINE_CALL_INTERFACE_DESCRIPTOR(StoreWithVector);
|
|
DEFINE_TURBOFAN_CODE_STUB(StoreFastElement, TurboFanCodeStub);
|
|
};
|
|
|
|
|
|
class CommonArrayConstructorStub : public TurboFanCodeStub {
|
|
protected:
|
|
CommonArrayConstructorStub(Isolate* isolate, ElementsKind kind,
|
|
AllocationSiteOverrideMode override_mode);
|
|
|
|
void set_sub_minor_key(uint32_t key) { minor_key_ = key; }
|
|
|
|
uint32_t sub_minor_key() const { return minor_key_; }
|
|
|
|
CommonArrayConstructorStub(uint32_t key, Isolate* isolate)
|
|
: TurboFanCodeStub(key, isolate) {}
|
|
|
|
public:
|
|
ElementsKind elements_kind() const {
|
|
return ElementsKindBits::decode(sub_minor_key());
|
|
}
|
|
|
|
AllocationSiteOverrideMode override_mode() const {
|
|
return AllocationSiteOverrideModeBits::decode(sub_minor_key());
|
|
}
|
|
|
|
static void GenerateStubsAheadOfTime(Isolate* isolate);
|
|
|
|
private:
|
|
// Ensure data fits within available bits.
|
|
STATIC_ASSERT(LAST_ALLOCATION_SITE_OVERRIDE_MODE == 1);
|
|
|
|
class ElementsKindBits : public BitField<ElementsKind, 0, 8> {};
|
|
class AllocationSiteOverrideModeBits
|
|
: public BitField<AllocationSiteOverrideMode, 8, 1> {}; // NOLINT
|
|
};
|
|
|
|
class ArrayNoArgumentConstructorStub : public CommonArrayConstructorStub {
|
|
public:
|
|
ArrayNoArgumentConstructorStub(
|
|
Isolate* isolate, ElementsKind kind,
|
|
AllocationSiteOverrideMode override_mode = DONT_OVERRIDE)
|
|
: CommonArrayConstructorStub(isolate, kind, override_mode) {}
|
|
|
|
private:
|
|
void PrintName(std::ostream& os) const override { // NOLINT
|
|
os << "ArrayNoArgumentConstructorStub";
|
|
}
|
|
|
|
DEFINE_CALL_INTERFACE_DESCRIPTOR(ArrayNoArgumentConstructor);
|
|
DEFINE_TURBOFAN_CODE_STUB(ArrayNoArgumentConstructor,
|
|
CommonArrayConstructorStub);
|
|
};
|
|
|
|
class InternalArrayNoArgumentConstructorStub
|
|
: public CommonArrayConstructorStub {
|
|
public:
|
|
InternalArrayNoArgumentConstructorStub(Isolate* isolate, ElementsKind kind)
|
|
: CommonArrayConstructorStub(isolate, kind, DONT_OVERRIDE) {}
|
|
|
|
private:
|
|
void PrintName(std::ostream& os) const override { // NOLINT
|
|
os << "InternalArrayNoArgumentConstructorStub";
|
|
}
|
|
|
|
DEFINE_CALL_INTERFACE_DESCRIPTOR(ArrayNoArgumentConstructor);
|
|
DEFINE_TURBOFAN_CODE_STUB(InternalArrayNoArgumentConstructor,
|
|
CommonArrayConstructorStub);
|
|
};
|
|
|
|
class ArraySingleArgumentConstructorStub : public CommonArrayConstructorStub {
|
|
public:
|
|
ArraySingleArgumentConstructorStub(
|
|
Isolate* isolate, ElementsKind kind,
|
|
AllocationSiteOverrideMode override_mode = DONT_OVERRIDE)
|
|
: CommonArrayConstructorStub(isolate, kind, override_mode) {}
|
|
|
|
private:
|
|
void PrintName(std::ostream& os) const override { // NOLINT
|
|
os << "ArraySingleArgumentConstructorStub";
|
|
}
|
|
|
|
DEFINE_CALL_INTERFACE_DESCRIPTOR(ArraySingleArgumentConstructor);
|
|
DEFINE_TURBOFAN_CODE_STUB(ArraySingleArgumentConstructor,
|
|
CommonArrayConstructorStub);
|
|
};
|
|
|
|
class InternalArraySingleArgumentConstructorStub
|
|
: public CommonArrayConstructorStub {
|
|
public:
|
|
InternalArraySingleArgumentConstructorStub(Isolate* isolate,
|
|
ElementsKind kind)
|
|
: CommonArrayConstructorStub(isolate, kind, DONT_OVERRIDE) {}
|
|
|
|
private:
|
|
void PrintName(std::ostream& os) const override { // NOLINT
|
|
os << "InternalArraySingleArgumentConstructorStub";
|
|
}
|
|
|
|
DEFINE_CALL_INTERFACE_DESCRIPTOR(ArraySingleArgumentConstructor);
|
|
DEFINE_TURBOFAN_CODE_STUB(InternalArraySingleArgumentConstructor,
|
|
CommonArrayConstructorStub);
|
|
};
|
|
|
|
// TODO(jgruber): Convert this stub into a builtin.
|
|
class ArrayNArgumentsConstructorStub : public PlatformCodeStub {
|
|
public:
|
|
explicit ArrayNArgumentsConstructorStub(Isolate* isolate)
|
|
: PlatformCodeStub(isolate) {}
|
|
|
|
CallInterfaceDescriptor GetCallInterfaceDescriptor() const override {
|
|
return ArrayNArgumentsConstructorDescriptor(isolate());
|
|
}
|
|
|
|
private:
|
|
DEFINE_PLATFORM_CODE_STUB(ArrayNArgumentsConstructor, PlatformCodeStub);
|
|
};
|
|
|
|
class StoreSlowElementStub : public TurboFanCodeStub {
|
|
public:
|
|
StoreSlowElementStub(Isolate* isolate, KeyedAccessStoreMode mode)
|
|
: TurboFanCodeStub(isolate) {
|
|
minor_key_ = CommonStoreModeBits::encode(mode);
|
|
}
|
|
|
|
private:
|
|
DEFINE_CALL_INTERFACE_DESCRIPTOR(StoreWithVector);
|
|
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,
|
|
ElementsKind to_kind, bool is_jsarray,
|
|
KeyedAccessStoreMode store_mode)
|
|
: TurboFanCodeStub(isolate) {
|
|
minor_key_ = CommonStoreModeBits::encode(store_mode) |
|
|
FromBits::encode(from_kind) | ToBits::encode(to_kind) |
|
|
IsJSArrayBits::encode(is_jsarray);
|
|
}
|
|
|
|
ElementsKind from_kind() const { return FromBits::decode(minor_key_); }
|
|
ElementsKind to_kind() const { return ToBits::decode(minor_key_); }
|
|
bool is_jsarray() const { return IsJSArrayBits::decode(minor_key_); }
|
|
KeyedAccessStoreMode store_mode() const {
|
|
return CommonStoreModeBits::decode(minor_key_);
|
|
}
|
|
|
|
private:
|
|
class FromBits
|
|
: public BitField<ElementsKind, CommonStoreModeBits::kNext, 8> {};
|
|
class ToBits : public BitField<ElementsKind, 11, 8> {};
|
|
class IsJSArrayBits : public BitField<bool, 19, 1> {};
|
|
|
|
DEFINE_CALL_INTERFACE_DESCRIPTOR(StoreTransition);
|
|
DEFINE_TURBOFAN_CODE_STUB(ElementsTransitionAndStore, TurboFanCodeStub);
|
|
};
|
|
|
|
// TODO(jgruber): Convert this stub into a builtin.
|
|
class ProfileEntryHookStub : public PlatformCodeStub {
|
|
public:
|
|
explicit ProfileEntryHookStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
|
|
|
|
// The profile entry hook function is not allowed to cause a GC.
|
|
bool SometimesSetsUpAFrame() override { return false; }
|
|
|
|
// Generates a call to the entry hook if it's enabled.
|
|
static void MaybeCallEntryHook(MacroAssembler* masm);
|
|
static void MaybeCallEntryHookDelayed(TurboAssembler* tasm, Zone* zone);
|
|
|
|
private:
|
|
static void EntryHookTrampoline(intptr_t function,
|
|
intptr_t stack_pointer,
|
|
Isolate* isolate);
|
|
|
|
// ProfileEntryHookStub is called at the start of a function, so it has the
|
|
// same register set.
|
|
DEFINE_CALL_INTERFACE_DESCRIPTOR(CallFunction)
|
|
DEFINE_PLATFORM_CODE_STUB(ProfileEntryHook, PlatformCodeStub);
|
|
};
|
|
|
|
|
|
#undef DEFINE_CALL_INTERFACE_DESCRIPTOR
|
|
#undef DEFINE_PLATFORM_CODE_STUB
|
|
#undef DEFINE_CODE_STUB
|
|
#undef DEFINE_CODE_STUB_BASE
|
|
|
|
} // namespace internal
|
|
} // namespace v8
|
|
|
|
#endif // V8_CODE_STUBS_H_
|