mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 846111 - Part 2: Teach VMFunction about parallel execution. (r=nbp)
This commit is contained in:
parent
11252a0c6d
commit
1ac435419e
@ -144,6 +144,7 @@ class IonFrameIterator
|
||||
return type_ == IonFrame_Entry;
|
||||
}
|
||||
bool isFunctionFrame() const;
|
||||
bool isParallelFunctionFrame() const;
|
||||
|
||||
bool isConstructing() const;
|
||||
|
||||
|
@ -103,9 +103,9 @@ IonFrameIterator::frameSize() const
|
||||
|
||||
// Returns the JSScript associated with the topmost Ion frame.
|
||||
inline RawScript
|
||||
GetTopIonJSScript(JSContext *cx, const SafepointIndex **safepointIndexOut, void **returnAddrOut)
|
||||
GetTopIonJSScript(PerThreadData *pt, const SafepointIndex **safepointIndexOut, void **returnAddrOut)
|
||||
{
|
||||
IonFrameIterator iter(cx->mainThread().ionTop);
|
||||
IonFrameIterator iter(pt->ionTop);
|
||||
JS_ASSERT(iter.type() == IonFrame_Exit);
|
||||
++iter;
|
||||
|
||||
@ -126,6 +126,13 @@ GetTopIonJSScript(JSContext *cx, const SafepointIndex **safepointIndexOut, void
|
||||
return iter.script();
|
||||
}
|
||||
|
||||
|
||||
inline RawScript
|
||||
GetTopIonJSScript(JSContext *cx, const SafepointIndex **safepointIndexOut, void **returnAddrOut)
|
||||
{
|
||||
return GetTopIonJSScript(&cx->mainThread(), safepointIndexOut, returnAddrOut);
|
||||
}
|
||||
|
||||
inline BaselineFrame *
|
||||
GetTopBaselineFrame(JSContext *cx)
|
||||
{
|
||||
|
@ -26,6 +26,8 @@
|
||||
#include "Safepoints.h"
|
||||
#include "VMFunctions.h"
|
||||
|
||||
#include "vm/ParallelDo.h"
|
||||
|
||||
namespace js {
|
||||
namespace ion {
|
||||
|
||||
@ -61,8 +63,14 @@ IonFrameIterator::checkInvalidation(IonScript **ionScriptOut) const
|
||||
RawScript script = this->script();
|
||||
// N.B. the current IonScript is not the same as the frame's
|
||||
// IonScript if the frame has since been invalidated.
|
||||
bool invalidated = !script->hasIonScript() ||
|
||||
!script->ionScript()->containsReturnAddress(returnAddr);
|
||||
bool invalidated;
|
||||
if (isParallelFunctionFrame()) {
|
||||
invalidated = !script->hasParallelIonScript() ||
|
||||
!script->parallelIonScript()->containsReturnAddress(returnAddr);
|
||||
} else {
|
||||
invalidated = !script->hasIonScript() ||
|
||||
!script->ionScript()->containsReturnAddress(returnAddr);
|
||||
}
|
||||
if (!invalidated)
|
||||
return false;
|
||||
|
||||
@ -84,8 +92,10 @@ JSFunction *
|
||||
IonFrameIterator::callee() const
|
||||
{
|
||||
if (isScripted()) {
|
||||
JS_ASSERT(isFunctionFrame());
|
||||
return CalleeTokenToFunction(calleeToken());
|
||||
JS_ASSERT(isFunctionFrame() || isParallelFunctionFrame());
|
||||
if (isFunctionFrame())
|
||||
return CalleeTokenToFunction(calleeToken());
|
||||
return CalleeTokenToParallelFunction(calleeToken());
|
||||
}
|
||||
|
||||
JS_ASSERT(isNative());
|
||||
@ -95,7 +105,7 @@ IonFrameIterator::callee() const
|
||||
JSFunction *
|
||||
IonFrameIterator::maybeCallee() const
|
||||
{
|
||||
if ((isScripted() && isFunctionFrame()) || isNative())
|
||||
if ((isScripted() && (isFunctionFrame() || isParallelFunctionFrame())) || isNative())
|
||||
return callee();
|
||||
return NULL;
|
||||
}
|
||||
@ -138,6 +148,12 @@ IonFrameIterator::isFunctionFrame() const
|
||||
return CalleeTokenIsFunction(calleeToken());
|
||||
}
|
||||
|
||||
bool
|
||||
IonFrameIterator::isParallelFunctionFrame() const
|
||||
{
|
||||
return GetCalleeTokenTag(calleeToken()) == CalleeToken_ParallelFunction;
|
||||
}
|
||||
|
||||
bool
|
||||
IonFrameIterator::isEntryJSFrame() const
|
||||
{
|
||||
@ -497,6 +513,23 @@ HandleException(ResumeFromException *rfe)
|
||||
rfe->stackPointer = iter.fp();
|
||||
}
|
||||
|
||||
void
|
||||
HandleParallelFailure(ResumeFromException *rfe)
|
||||
{
|
||||
ForkJoinSlice *slice = ForkJoinSlice::Current();
|
||||
IonFrameIterator iter(slice->perThreadData->ionTop);
|
||||
|
||||
while (!iter.isEntry()) {
|
||||
parallel::Spew(parallel::SpewBailouts, "Bailing from VM reentry");
|
||||
if (!slice->abortedScript && iter.isScripted())
|
||||
slice->abortedScript = iter.script();
|
||||
++iter;
|
||||
}
|
||||
|
||||
rfe->kind = ResumeFromException::RESUME_ENTRY_FRAME;
|
||||
rfe->stackPointer = iter.fp();
|
||||
}
|
||||
|
||||
void
|
||||
EnsureExitFrame(IonCommonFrameLayout *frame)
|
||||
{
|
||||
@ -1091,7 +1124,15 @@ IonFrameIterator::ionScript() const
|
||||
IonScript *ionScript = NULL;
|
||||
if (checkInvalidation(&ionScript))
|
||||
return ionScript;
|
||||
return script()->ionScript();
|
||||
switch (GetCalleeTokenTag(calleeToken())) {
|
||||
case CalleeToken_Function:
|
||||
case CalleeToken_Script:
|
||||
return script()->ionScript();
|
||||
case CalleeToken_ParallelFunction:
|
||||
return script()->parallelIonScript();
|
||||
default:
|
||||
JS_NOT_REACHED("unknown callee token type");
|
||||
}
|
||||
}
|
||||
|
||||
const SafepointIndex *
|
||||
|
@ -28,14 +28,15 @@ typedef void * CalleeToken;
|
||||
enum CalleeTokenTag
|
||||
{
|
||||
CalleeToken_Function = 0x0, // untagged
|
||||
CalleeToken_Script = 0x1
|
||||
CalleeToken_Script = 0x1,
|
||||
CalleeToken_ParallelFunction = 0x2
|
||||
};
|
||||
|
||||
static inline CalleeTokenTag
|
||||
GetCalleeTokenTag(CalleeToken token)
|
||||
{
|
||||
CalleeTokenTag tag = CalleeTokenTag(uintptr_t(token) & 0x3);
|
||||
JS_ASSERT(tag <= CalleeToken_Script);
|
||||
JS_ASSERT(tag <= CalleeToken_ParallelFunction);
|
||||
return tag;
|
||||
}
|
||||
static inline CalleeToken
|
||||
@ -44,6 +45,11 @@ CalleeToToken(JSFunction *fun)
|
||||
return CalleeToken(uintptr_t(fun) | uintptr_t(CalleeToken_Function));
|
||||
}
|
||||
static inline CalleeToken
|
||||
CalleeToParallelToken(JSFunction *fun)
|
||||
{
|
||||
return CalleeToken(uintptr_t(fun) | uintptr_t(CalleeToken_ParallelFunction));
|
||||
}
|
||||
static inline CalleeToken
|
||||
CalleeToToken(RawScript script)
|
||||
{
|
||||
return CalleeToken(uintptr_t(script) | uintptr_t(CalleeToken_Script));
|
||||
@ -59,6 +65,12 @@ CalleeTokenToFunction(CalleeToken token)
|
||||
JS_ASSERT(CalleeTokenIsFunction(token));
|
||||
return (JSFunction *)token;
|
||||
}
|
||||
static inline RawFunction
|
||||
CalleeTokenToParallelFunction(CalleeToken token)
|
||||
{
|
||||
JS_ASSERT(GetCalleeTokenTag(token) == CalleeToken_ParallelFunction);
|
||||
return (JSFunction *)(uintptr_t(token) & ~uintptr_t(0x3));
|
||||
}
|
||||
static inline RawScript
|
||||
CalleeTokenToScript(CalleeToken token)
|
||||
{
|
||||
@ -74,6 +86,8 @@ ScriptFromCalleeToken(CalleeToken token)
|
||||
return CalleeTokenToScript(token);
|
||||
case CalleeToken_Function:
|
||||
return CalleeTokenToFunction(token)->nonLazyScript();
|
||||
case CalleeToken_ParallelFunction:
|
||||
return CalleeTokenToParallelFunction(token)->nonLazyScript();
|
||||
}
|
||||
JS_NOT_REACHED("invalid callee token tag");
|
||||
return NULL;
|
||||
@ -253,6 +267,7 @@ struct ResumeFromException
|
||||
};
|
||||
|
||||
void HandleException(ResumeFromException *rfe);
|
||||
void HandleParallelFailure(ResumeFromException *rfe);
|
||||
|
||||
void EnsureExitFrame(IonCommonFrameLayout *frame);
|
||||
|
||||
|
@ -980,6 +980,101 @@ MacroAssembler::loadBaselineFramePtr(Register framePtr, Register dest)
|
||||
subPtr(Imm32(BaselineFrame::Size()), dest);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::enterParallelExitFrameAndLoadSlice(const VMFunction *f, Register slice,
|
||||
Register scratch)
|
||||
{
|
||||
// Load the current ForkJoinSlice *. If we need a parallel exit frame,
|
||||
// chances are we are about to do something very slow anyways, so just
|
||||
// call ParForkJoinSlice again instead of using the cached version.
|
||||
setupUnalignedABICall(0, scratch);
|
||||
callWithABI(JS_FUNC_TO_DATA_PTR(void *, ParForkJoinSlice));
|
||||
if (ReturnReg != slice)
|
||||
movePtr(ReturnReg, slice);
|
||||
// Load the PerThreadData from from the slice.
|
||||
loadPtr(Address(slice, offsetof(ForkJoinSlice, perThreadData)), scratch);
|
||||
linkParallelExitFrame(scratch);
|
||||
// Push the ioncode.
|
||||
exitCodePatch_ = PushWithPatch(ImmWord(-1));
|
||||
// Push the VMFunction pointer, to mark arguments.
|
||||
Push(ImmWord(f));
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::enterExitFrameAndLoadContext(const VMFunction *f, Register cxReg, Register scratch,
|
||||
ExecutionMode executionMode)
|
||||
{
|
||||
switch (executionMode) {
|
||||
case SequentialExecution:
|
||||
// The scratch register is not used for sequential execution.
|
||||
enterExitFrame(f);
|
||||
loadJSContext(cxReg);
|
||||
break;
|
||||
case ParallelExecution:
|
||||
enterParallelExitFrameAndLoadSlice(f, cxReg, scratch);
|
||||
break;
|
||||
default:
|
||||
JS_NOT_REACHED("No such execution mode");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::handleFailure(ExecutionMode executionMode)
|
||||
{
|
||||
// Re-entry code is irrelevant because the exception will leave the
|
||||
// running function and never come back
|
||||
if (sps_)
|
||||
sps_->skipNextReenter();
|
||||
leaveSPSFrame();
|
||||
|
||||
void *handler;
|
||||
switch (executionMode) {
|
||||
case SequentialExecution:
|
||||
handler = JS_FUNC_TO_DATA_PTR(void *, ion::HandleException);
|
||||
break;
|
||||
case ParallelExecution:
|
||||
handler = JS_FUNC_TO_DATA_PTR(void *, ion::HandleParallelFailure);
|
||||
break;
|
||||
default:
|
||||
JS_NOT_REACHED("No such execution mode");
|
||||
}
|
||||
MacroAssemblerSpecific::handleFailureWithHandler(handler);
|
||||
|
||||
// Doesn't actually emit code, but balances the leave()
|
||||
if (sps_)
|
||||
sps_->reenter(*this, InvalidReg);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::tagCallee(Register callee, ExecutionMode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case SequentialExecution:
|
||||
// CalleeToken_Function is untagged, so we don't need to do anything.
|
||||
return;
|
||||
case ParallelExecution:
|
||||
orPtr(Imm32(CalleeToken_ParallelFunction), callee);
|
||||
return;
|
||||
default:
|
||||
JS_NOT_REACHED("No such execution mode");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::clearCalleeTag(Register callee, ExecutionMode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case SequentialExecution:
|
||||
// CalleeToken_Function is untagged, so we don't need to do anything.
|
||||
return;
|
||||
case ParallelExecution:
|
||||
andPtr(Imm32(~0x3), callee);
|
||||
return;
|
||||
default:
|
||||
JS_NOT_REACHED("No such execution mode");
|
||||
}
|
||||
}
|
||||
|
||||
void printf0_(const char *output) {
|
||||
printf("%s", output);
|
||||
}
|
||||
|
@ -593,6 +593,12 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
Push(ImmWord(uintptr_t(NULL)));
|
||||
}
|
||||
|
||||
void enterParallelExitFrameAndLoadSlice(const VMFunction *f, Register slice,
|
||||
Register scratch);
|
||||
|
||||
void enterExitFrameAndLoadContext(const VMFunction *f, Register cxReg, Register scratch,
|
||||
ExecutionMode executionMode);
|
||||
|
||||
void leaveExitFrame() {
|
||||
freeStack(IonExitFooterFrame::Size());
|
||||
}
|
||||
@ -639,17 +645,11 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
}
|
||||
|
||||
void handleException() {
|
||||
// Re-entry code is irrelevant because the exception will leave the
|
||||
// running function and never come back
|
||||
if (sps_)
|
||||
sps_->skipNextReenter();
|
||||
leaveSPSFrame();
|
||||
MacroAssemblerSpecific::handleException();
|
||||
// Doesn't actually emit code, but balances the leave()
|
||||
if (sps_)
|
||||
sps_->reenter(*this, InvalidReg);
|
||||
handleFailure(SequentialExecution);
|
||||
}
|
||||
|
||||
void handleFailure(ExecutionMode executionMode);
|
||||
|
||||
// see above comment for what is returned
|
||||
uint32_t callIon(const Register &callee) {
|
||||
leaveSPSFrame();
|
||||
@ -692,6 +692,9 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
return truthy ? Assembler::Zero : Assembler::NonZero;
|
||||
}
|
||||
|
||||
void tagCallee(Register callee, ExecutionMode mode);
|
||||
void clearCalleeTag(Register callee, ExecutionMode mode);
|
||||
|
||||
private:
|
||||
// These two functions are helpers used around call sites throughout the
|
||||
// assembler. They are called from the above call wrappers to emit the
|
||||
|
@ -11,6 +11,9 @@
|
||||
#include "jspubtd.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
class ForkJoinSlice;
|
||||
|
||||
namespace ion {
|
||||
|
||||
enum DataType {
|
||||
@ -19,7 +22,8 @@ enum DataType {
|
||||
Type_Int32,
|
||||
Type_Object,
|
||||
Type_Value,
|
||||
Type_Handle
|
||||
Type_Handle,
|
||||
Type_ParallelResult
|
||||
};
|
||||
|
||||
struct PopValues
|
||||
@ -97,6 +101,9 @@ struct VMFunction
|
||||
// arguments of the VM wrapper.
|
||||
uint64_t argumentRootTypes;
|
||||
|
||||
// Does this function take a ForkJoinSlice * or a JSContext *?
|
||||
ExecutionMode executionMode;
|
||||
|
||||
// Number of Values the VM wrapper should pop from the stack when it returns.
|
||||
// Used by baseline IC stubs so that they can use tail calls to call the VM
|
||||
// wrapper.
|
||||
@ -169,23 +176,32 @@ struct VMFunction
|
||||
explicitArgs(0),
|
||||
argumentProperties(0),
|
||||
outParam(Type_Void),
|
||||
returnType(Type_Void)
|
||||
returnType(Type_Void),
|
||||
executionMode(SequentialExecution),
|
||||
extraValuesToPop(0)
|
||||
{
|
||||
}
|
||||
|
||||
VMFunction(void *wrapped, uint32_t explicitArgs, uint32_t argumentProperties, uint64_t argRootTypes,
|
||||
DataType outParam, DataType returnType, uint32_t extraValuesToPop = 0)
|
||||
|
||||
VMFunction(void *wrapped, uint32_t explicitArgs, uint32_t argumentProperties,
|
||||
uint64_t argRootTypes, DataType outParam, DataType returnType,
|
||||
ExecutionMode executionMode, uint32_t extraValuesToPop = 0)
|
||||
: wrapped(wrapped),
|
||||
explicitArgs(explicitArgs),
|
||||
argumentProperties(argumentProperties),
|
||||
outParam(outParam),
|
||||
returnType(returnType),
|
||||
argumentRootTypes(argRootTypes),
|
||||
executionMode(executionMode),
|
||||
extraValuesToPop(extraValuesToPop)
|
||||
{
|
||||
// Check for valid failure/return type.
|
||||
JS_ASSERT_IF(outParam != Type_Void, returnType == Type_Bool);
|
||||
JS_ASSERT(returnType == Type_Bool || returnType == Type_Object);
|
||||
JS_ASSERT_IF(outParam != Type_Void && executionMode == SequentialExecution,
|
||||
returnType == Type_Bool);
|
||||
JS_ASSERT_IF(executionMode == ParallelExecution, returnType == Type_ParallelResult);
|
||||
JS_ASSERT(returnType == Type_Bool ||
|
||||
returnType == Type_Object ||
|
||||
returnType == Type_ParallelResult);
|
||||
}
|
||||
|
||||
VMFunction(const VMFunction &o)
|
||||
@ -213,6 +229,7 @@ template <> struct TypeToDataType<Handle<StaticBlockObject *> > { static const D
|
||||
template <> struct TypeToDataType<HandleScript> { static const DataType result = Type_Handle; };
|
||||
template <> struct TypeToDataType<HandleValue> { static const DataType result = Type_Handle; };
|
||||
template <> struct TypeToDataType<MutableHandleValue> { static const DataType result = Type_Handle; };
|
||||
template <> struct TypeToDataType<ParallelResult> { static const DataType result = Type_ParallelResult; };
|
||||
|
||||
// Convert argument types to properties of the argument known by the jit.
|
||||
template <class T> struct TypeToArgProperties {
|
||||
@ -288,6 +305,14 @@ template <> struct OutParamToDataType<int *> { static const DataType result = Ty
|
||||
template <> struct OutParamToDataType<uint32_t *> { static const DataType result = Type_Int32; };
|
||||
template <> struct OutParamToDataType<MutableHandleValue> { static const DataType result = Type_Handle; };
|
||||
|
||||
template <class> struct MatchContext { };
|
||||
template <> struct MatchContext<JSContext *> {
|
||||
static const ExecutionMode execMode = SequentialExecution;
|
||||
};
|
||||
template <> struct MatchContext<ForkJoinSlice *> {
|
||||
static const ExecutionMode execMode = ParallelExecution;
|
||||
};
|
||||
|
||||
#define FOR_EACH_ARGS_1(Macro, Sep, Last) Macro(1) Last(1)
|
||||
#define FOR_EACH_ARGS_2(Macro, Sep, Last) FOR_EACH_ARGS_1(Macro, Sep, Sep) Macro(2) Last(2)
|
||||
#define FOR_EACH_ARGS_3(Macro, Sep, Last) FOR_EACH_ARGS_2(Macro, Sep, Sep) Macro(3) Last(3)
|
||||
@ -303,6 +328,9 @@ template <> struct OutParamToDataType<MutableHandleValue> { static const DataTyp
|
||||
#define NOTHING(_)
|
||||
|
||||
#define FUNCTION_INFO_STRUCT_BODY(ForEachNb) \
|
||||
static inline ExecutionMode executionMode() { \
|
||||
return MatchContext<Context>::execMode; \
|
||||
} \
|
||||
static inline DataType returnType() { \
|
||||
return TypeToDataType<R>::result; \
|
||||
} \
|
||||
@ -315,16 +343,17 @@ template <> struct OutParamToDataType<MutableHandleValue> { static const DataTyp
|
||||
static inline size_t explicitArgs() { \
|
||||
return NbArgs() - (outParam() != Type_Void ? 1 : 0); \
|
||||
} \
|
||||
static inline uint32_t argumentProperties() { \
|
||||
static inline uint32_t argumentProperties() { \
|
||||
return ForEachNb(COMPUTE_ARG_PROP, SEP_OR, NOTHING); \
|
||||
} \
|
||||
static inline uint64_t argumentRootTypes() { \
|
||||
static inline uint64_t argumentRootTypes() { \
|
||||
return ForEachNb(COMPUTE_ARG_ROOT, SEP_OR, NOTHING); \
|
||||
} \
|
||||
FunctionInfo(pf fun, PopValues extraValuesToPop = PopValues(0)) \
|
||||
: VMFunction(JS_FUNC_TO_DATA_PTR(void *, fun), explicitArgs(), \
|
||||
argumentProperties(),argumentRootTypes(), \
|
||||
outParam(), returnType(), extraValuesToPop.numValues) \
|
||||
outParam(), returnType(), executionMode(), \
|
||||
extraValuesToPop.numValues) \
|
||||
{ }
|
||||
|
||||
template <typename Fun>
|
||||
@ -332,10 +361,13 @@ struct FunctionInfo {
|
||||
};
|
||||
|
||||
// VMFunction wrapper with no explicit arguments.
|
||||
template <class R>
|
||||
struct FunctionInfo<R (*)(JSContext *)> : public VMFunction {
|
||||
typedef R (*pf)(JSContext *);
|
||||
template <class R, class Context>
|
||||
struct FunctionInfo<R (*)(Context)> : public VMFunction {
|
||||
typedef R (*pf)(Context);
|
||||
|
||||
static inline ExecutionMode executionMode() {
|
||||
return MatchContext<Context>::execMode;
|
||||
}
|
||||
static inline DataType returnType() {
|
||||
return TypeToDataType<R>::result;
|
||||
}
|
||||
@ -354,50 +386,51 @@ struct FunctionInfo<R (*)(JSContext *)> : public VMFunction {
|
||||
FunctionInfo(pf fun)
|
||||
: VMFunction(JS_FUNC_TO_DATA_PTR(void *, fun), explicitArgs(),
|
||||
argumentProperties(), argumentRootTypes(),
|
||||
outParam(), returnType())
|
||||
outParam(), returnType(), executionMode())
|
||||
{ }
|
||||
};
|
||||
|
||||
// Specialize the class for each number of argument used by VMFunction.
|
||||
// Keep it verbose unless you find a readable macro for it.
|
||||
template <class R, class A1>
|
||||
struct FunctionInfo<R (*)(JSContext *, A1)> : public VMFunction {
|
||||
typedef R (*pf)(JSContext *, A1);
|
||||
template <class R, class Context, class A1>
|
||||
struct FunctionInfo<R (*)(Context, A1)> : public VMFunction {
|
||||
typedef R (*pf)(Context, A1);
|
||||
FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_1)
|
||||
};
|
||||
|
||||
template <class R, class A1, class A2>
|
||||
struct FunctionInfo<R (*)(JSContext *, A1, A2)> : public VMFunction {
|
||||
typedef R (*pf)(JSContext *, A1, A2);
|
||||
template <class R, class Context, class A1, class A2>
|
||||
struct FunctionInfo<R (*)(Context, A1, A2)> : public VMFunction {
|
||||
typedef R (*pf)(Context, A1, A2);
|
||||
FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_2)
|
||||
};
|
||||
|
||||
template <class R, class A1, class A2, class A3>
|
||||
struct FunctionInfo<R (*)(JSContext *, A1, A2, A3)> : public VMFunction {
|
||||
typedef R (*pf)(JSContext *, A1, A2, A3);
|
||||
template <class R, class Context, class A1, class A2, class A3>
|
||||
struct FunctionInfo<R (*)(Context, A1, A2, A3)> : public VMFunction {
|
||||
typedef R (*pf)(Context, A1, A2, A3);
|
||||
FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_3)
|
||||
};
|
||||
|
||||
template <class R, class A1, class A2, class A3, class A4>
|
||||
struct FunctionInfo<R (*)(JSContext *, A1, A2, A3, A4)> : public VMFunction {
|
||||
typedef R (*pf)(JSContext *, A1, A2, A3, A4);
|
||||
template <class R, class Context, class A1, class A2, class A3, class A4>
|
||||
struct FunctionInfo<R (*)(Context, A1, A2, A3, A4)> : public VMFunction {
|
||||
typedef R (*pf)(Context, A1, A2, A3, A4);
|
||||
FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_4)
|
||||
};
|
||||
|
||||
template <class R, class A1, class A2, class A3, class A4, class A5>
|
||||
struct FunctionInfo<R (*)(JSContext *, A1, A2, A3, A4, A5)> : public VMFunction {
|
||||
typedef R (*pf)(JSContext *, A1, A2, A3, A4, A5);
|
||||
template <class R, class Context, class A1, class A2, class A3, class A4, class A5>
|
||||
struct FunctionInfo<R (*)(Context, A1, A2, A3, A4, A5)> : public VMFunction {
|
||||
typedef R (*pf)(Context, A1, A2, A3, A4, A5);
|
||||
FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_5)
|
||||
};
|
||||
|
||||
template <class R, class A1, class A2, class A3, class A4, class A5, class A6>
|
||||
struct FunctionInfo<R (*)(JSContext *, A1, A2, A3, A4, A5, A6)> : public VMFunction {
|
||||
typedef R (*pf)(JSContext *, A1, A2, A3, A4, A5, A6);
|
||||
template <class R, class Context, class A1, class A2, class A3, class A4, class A5, class A6>
|
||||
struct FunctionInfo<R (*)(Context, A1, A2, A3, A4, A5, A6)> : public VMFunction {
|
||||
typedef R (*pf)(Context, A1, A2, A3, A4, A5, A6);
|
||||
FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_6)
|
||||
};
|
||||
|
||||
#undef FUNCTION_INFO_STRUCT_BODY
|
||||
|
||||
#undef FOR_EACH_ARGS_6
|
||||
#undef FOR_EACH_ARGS_5
|
||||
#undef FOR_EACH_ARGS_4
|
||||
#undef FOR_EACH_ARGS_3
|
||||
|
@ -2830,6 +2830,12 @@ MacroAssemblerARMCompat::linkExitFrame() {
|
||||
ma_str(StackPointer, Operand(ScratchRegister, 0));
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARMCompat::linkParallelExitFrame(const Register &pt)
|
||||
{
|
||||
ma_str(StackPointer, Operand(pt, offsetof(PerThreadData, ionTop)));
|
||||
}
|
||||
|
||||
// ARM says that all reads of pc will return 8 higher than the
|
||||
// address of the currently executing instruction. This means we are
|
||||
// correctly storing the address of the instruction after the call
|
||||
@ -3134,7 +3140,7 @@ MacroAssemblerARMCompat::callWithABI(const Address &fun, Result result)
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARMCompat::handleException()
|
||||
MacroAssemblerARMCompat::handleFailureWithHandler(void *handler)
|
||||
{
|
||||
// Reserve space for exception information.
|
||||
int size = (sizeof(ResumeFromException) + 7) & ~7;
|
||||
@ -3144,7 +3150,7 @@ MacroAssemblerARMCompat::handleException()
|
||||
// Ask for an exception handler.
|
||||
setupUnalignedABICall(1, r1);
|
||||
passABIArg(r0);
|
||||
callWithABI(JS_FUNC_TO_DATA_PTR(void *, ion::HandleException));
|
||||
callWithABI(handler);
|
||||
|
||||
Label catch_;
|
||||
Label entryFrame;
|
||||
|
@ -972,7 +972,8 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
}
|
||||
|
||||
void linkExitFrame();
|
||||
void handleException();
|
||||
void linkParallelExitFrame(const Register &pt);
|
||||
void handleFailureWithHandler(void *handler);
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// Common interface.
|
||||
|
@ -367,6 +367,7 @@ IonRuntime::generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void *
|
||||
|
||||
// Load the number of |undefined|s to push into r6.
|
||||
masm.ma_ldr(DTRAddr(sp, DtrOffImm(IonRectifierFrameLayout::offsetOfCalleeToken())), r1);
|
||||
masm.clearCalleeTag(r1, mode);
|
||||
masm.ma_ldrh(EDtrAddr(r1, EDtrOffImm(offsetof(JSFunction, nargs))), r6);
|
||||
|
||||
masm.ma_sub(r6, r8, r2);
|
||||
@ -603,13 +604,16 @@ IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
|
||||
// Wrapper register set is a superset of Volatile register set.
|
||||
JS_STATIC_ASSERT((Register::Codes::VolatileMask & ~Register::Codes::WrapperMask) == 0);
|
||||
|
||||
// The context is the first argument; r0 is the first argument register.
|
||||
Register cxreg = r0;
|
||||
|
||||
// Stack is:
|
||||
// ... frame ...
|
||||
// +8 [args] + argPadding
|
||||
// +0 ExitFrame
|
||||
//
|
||||
// We're aligned to an exit frame, so link it up.
|
||||
masm.enterExitFrame(&f);
|
||||
masm.enterExitFrameAndLoadContext(&f, cxreg, regs.getAny(), f.executionMode);
|
||||
|
||||
// Save the base of the argument set stored on the stack.
|
||||
Register argsBase = InvalidReg;
|
||||
@ -648,13 +652,7 @@ IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
|
||||
break;
|
||||
}
|
||||
|
||||
Register temp = regs.getAny();
|
||||
masm.setupUnalignedABICall(f.argc(), temp);
|
||||
|
||||
// Initialize and set the context parameter.
|
||||
// r0 is the first argument register.
|
||||
Register cxreg = r0;
|
||||
masm.loadJSContext(cxreg);
|
||||
masm.setupUnalignedABICall(f.argc(), regs.getAny());
|
||||
masm.passABIArg(cxreg);
|
||||
|
||||
size_t argDisp = 0;
|
||||
@ -692,10 +690,20 @@ IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
|
||||
masm.callWithABI(f.wrapped);
|
||||
|
||||
// Test for failure.
|
||||
Label exception;
|
||||
// Called functions return bools, which are 0/false and non-zero/true
|
||||
masm.ma_cmp(r0, Imm32(0));
|
||||
masm.ma_b(&exception, Assembler::Zero);
|
||||
Label failure;
|
||||
switch (f.failType()) {
|
||||
case Type_Object:
|
||||
case Type_Bool:
|
||||
// Called functions return bools, which are 0/false and non-zero/true
|
||||
masm.branch32(Assembler::Equal, r0, Imm32(0), &failure);
|
||||
break;
|
||||
case Type_ParallelResult:
|
||||
masm.branch32(Assembler::NotEqual, r0, Imm32(TP_SUCCESS), &failure);
|
||||
break;
|
||||
default:
|
||||
JS_NOT_REACHED("unknown failure kind");
|
||||
break;
|
||||
}
|
||||
|
||||
// Load the outparam and free any allocated stack.
|
||||
switch (f.outParam) {
|
||||
@ -719,8 +727,8 @@ IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
|
||||
f.explicitStackSlots() * sizeof(void *) +
|
||||
f.extraValuesToPop * sizeof(Value)));
|
||||
|
||||
masm.bind(&exception);
|
||||
masm.handleException();
|
||||
masm.bind(&failure);
|
||||
masm.handleFailure(f.executionMode);
|
||||
|
||||
Linker linker(masm);
|
||||
IonCode *wrapper = linker.newCode(cx, JSC::OTHER_CODE);
|
||||
|
@ -463,12 +463,16 @@ class CodeLocationJump
|
||||
|
||||
void repoint(IonCode *code, MacroAssembler* masm = NULL);
|
||||
|
||||
bool isSet() const {
|
||||
return raw_ != (uint8_t *) 0xdeadc0de;
|
||||
}
|
||||
|
||||
uint8_t *raw() const {
|
||||
JS_ASSERT(absolute_ && raw_ != (uint8_t *) 0xdeadc0de);
|
||||
JS_ASSERT(absolute_ && isSet());
|
||||
return raw_;
|
||||
}
|
||||
uint8_t *offset() const {
|
||||
JS_ASSERT(!absolute_ && raw_ != (uint8_t *) 0xdeadc0de);
|
||||
JS_ASSERT(!absolute_ && isSet());
|
||||
return raw_;
|
||||
}
|
||||
|
||||
@ -526,12 +530,16 @@ class CodeLocationLabel
|
||||
|
||||
void repoint(IonCode *code, MacroAssembler *masm = NULL);
|
||||
|
||||
bool isSet() {
|
||||
return raw_ != (uint8_t *) 0xdeadc0de;
|
||||
}
|
||||
|
||||
uint8_t *raw() {
|
||||
JS_ASSERT(absolute_ && raw_ != (uint8_t *) 0xdeadc0de);
|
||||
JS_ASSERT(absolute_ && isSet());
|
||||
return raw_;
|
||||
}
|
||||
uint8_t *offset() {
|
||||
JS_ASSERT(!absolute_ && raw_ != (uint8_t *) 0xdeadc0de);
|
||||
JS_ASSERT(!absolute_ && isSet());
|
||||
return raw_;
|
||||
}
|
||||
};
|
||||
|
@ -173,6 +173,7 @@ class CodeGeneratorShared : public LInstructionVisitor
|
||||
return index;
|
||||
}
|
||||
|
||||
public:
|
||||
// This is needed by addCache to update the cache with the jump
|
||||
// informations provided by the out-of-line path.
|
||||
IonCache *getCache(size_t index) {
|
||||
|
@ -180,7 +180,7 @@ MacroAssemblerX64::callWithABI(Address fun, Result result)
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX64::handleException()
|
||||
MacroAssemblerX64::handleFailureWithHandler(void *handler)
|
||||
{
|
||||
// Reserve space for exception information.
|
||||
subq(Imm32(sizeof(ResumeFromException)), rsp);
|
||||
@ -189,7 +189,7 @@ MacroAssemblerX64::handleException()
|
||||
// Ask for an exception handler.
|
||||
setupUnalignedABICall(1, rcx);
|
||||
passABIArg(rax);
|
||||
callWithABI(JS_FUNC_TO_DATA_PTR(void *, ion::HandleException));
|
||||
callWithABI(handler);
|
||||
|
||||
Label catch_;
|
||||
Label entryFrame;
|
||||
|
@ -975,7 +975,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
||||
void callWithABI(void *fun, Result result = GENERAL);
|
||||
void callWithABI(Address fun, Result result = GENERAL);
|
||||
|
||||
void handleException();
|
||||
void handleFailureWithHandler(void *handler);
|
||||
|
||||
void makeFrameDescriptor(Register frameSizeReg, FrameType type) {
|
||||
shlq(Imm32(FRAMESIZE_SHIFT), frameSizeReg);
|
||||
@ -983,7 +983,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
||||
}
|
||||
|
||||
// Save an exit frame (which must be aligned to the stack pointer) to
|
||||
// ThreadData::ionTop.
|
||||
// ThreadData::ionTop of the main thread.
|
||||
void linkExitFrame() {
|
||||
mov(ImmWord(GetIonContext()->runtime), ScratchReg);
|
||||
mov(StackPointer, Operand(ScratchReg, offsetof(JSRuntime, mainThread.ionTop)));
|
||||
@ -996,6 +996,12 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
||||
call(target);
|
||||
}
|
||||
|
||||
// Save an exit frame to the thread data of the current thread, given a
|
||||
// register that holds a PerThreadData *.
|
||||
void linkParallelExitFrame(const Register &pt) {
|
||||
mov(StackPointer, Operand(pt, offsetof(PerThreadData, ionTop)));
|
||||
}
|
||||
|
||||
void enterOsr(Register calleeToken, Register code) {
|
||||
push(Imm32(0)); // num actual args.
|
||||
push(calleeToken);
|
||||
|
@ -333,6 +333,7 @@ IonRuntime::generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void *
|
||||
|
||||
// Load the number of |undefined|s to push into %rcx.
|
||||
masm.movq(Operand(rsp, IonRectifierFrameLayout::offsetOfCalleeToken()), rax);
|
||||
masm.clearCalleeTag(rax, mode);
|
||||
masm.movzwl(Operand(rax, offsetof(JSFunction, nargs)), rcx);
|
||||
masm.subq(r8, rcx);
|
||||
|
||||
@ -501,6 +502,9 @@ IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
|
||||
// Wrapper register set is a superset of Volatile register set.
|
||||
JS_STATIC_ASSERT((Register::Codes::VolatileMask & ~Register::Codes::WrapperMask) == 0);
|
||||
|
||||
// The context is the first argument.
|
||||
Register cxreg = IntArgReg0;
|
||||
|
||||
// Stack is:
|
||||
// ... frame ...
|
||||
// +12 [args]
|
||||
@ -508,7 +512,7 @@ IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
|
||||
// +0 returnAddress
|
||||
//
|
||||
// We're aligned to an exit frame, so link it up.
|
||||
masm.enterExitFrame(&f);
|
||||
masm.enterExitFrameAndLoadContext(&f, cxreg, regs.getAny(), f.executionMode);
|
||||
|
||||
// Save the current stack pointer as the base for copying arguments.
|
||||
Register argsBase = InvalidReg;
|
||||
@ -544,12 +548,7 @@ IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
|
||||
break;
|
||||
}
|
||||
|
||||
Register temp = regs.getAny();
|
||||
masm.setupUnalignedABICall(f.argc(), temp);
|
||||
|
||||
// Initialize the context parameter.
|
||||
Register cxreg = IntArgReg0;
|
||||
masm.loadJSContext(cxreg);
|
||||
masm.setupUnalignedABICall(f.argc(), regs.getAny());
|
||||
masm.passABIArg(cxreg);
|
||||
|
||||
size_t argDisp = 0;
|
||||
@ -582,15 +581,17 @@ IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
|
||||
masm.callWithABI(f.wrapped);
|
||||
|
||||
// Test for failure.
|
||||
Label exception;
|
||||
Label failure;
|
||||
switch (f.failType()) {
|
||||
case Type_Object:
|
||||
masm.testq(rax, rax);
|
||||
masm.j(Assembler::Zero, &exception);
|
||||
masm.branchTestPtr(Assembler::Zero, rax, rax, &failure);
|
||||
break;
|
||||
case Type_Bool:
|
||||
masm.testb(rax, rax);
|
||||
masm.j(Assembler::Zero, &exception);
|
||||
masm.j(Assembler::Zero, &failure);
|
||||
break;
|
||||
case Type_ParallelResult:
|
||||
masm.branchPtr(Assembler::NotEqual, rax, Imm32(TP_SUCCESS), &failure);
|
||||
break;
|
||||
default:
|
||||
JS_NOT_REACHED("unknown failure kind");
|
||||
@ -619,8 +620,8 @@ IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
|
||||
f.explicitStackSlots() * sizeof(void *) +
|
||||
f.extraValuesToPop * sizeof(Value)));
|
||||
|
||||
masm.bind(&exception);
|
||||
masm.handleException();
|
||||
masm.bind(&failure);
|
||||
masm.handleFailure(f.executionMode);
|
||||
|
||||
Linker linker(masm);
|
||||
IonCode *wrapper = linker.newCode(cx, JSC::OTHER_CODE);
|
||||
|
@ -70,7 +70,9 @@ class Registers {
|
||||
(1 << JSC::X86Registers::edi) |
|
||||
(1 << JSC::X86Registers::ebp);
|
||||
|
||||
static const uint32_t WrapperMask = VolatileMask;
|
||||
static const uint32_t WrapperMask =
|
||||
VolatileMask |
|
||||
(1 << JSC::X86Registers::ebx);
|
||||
|
||||
static const uint32_t SingleByteRegs =
|
||||
(1 << JSC::X86Registers::eax) |
|
||||
|
@ -195,7 +195,7 @@ MacroAssemblerX86::callWithABI(const Address &fun, Result result)
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX86::handleException()
|
||||
MacroAssemblerX86::handleFailureWithHandler(void *handler)
|
||||
{
|
||||
// Reserve space for exception information.
|
||||
subl(Imm32(sizeof(ResumeFromException)), esp);
|
||||
@ -204,7 +204,7 @@ MacroAssemblerX86::handleException()
|
||||
// Ask for an exception handler.
|
||||
setupUnalignedABICall(1, ecx);
|
||||
passABIArg(eax);
|
||||
callWithABI(JS_FUNC_TO_DATA_PTR(void *, ion::HandleException));
|
||||
callWithABI(handler);
|
||||
|
||||
Label catch_;
|
||||
Label entryFrame;
|
||||
|
@ -854,7 +854,7 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
||||
void callWithABI(const Address &fun, Result result = GENERAL);
|
||||
|
||||
// Used from within an Exit frame to handle a pending exception.
|
||||
void handleException();
|
||||
void handleFailureWithHandler(void *handler);
|
||||
|
||||
void makeFrameDescriptor(Register frameSizeReg, FrameType type) {
|
||||
shll(Imm32(FRAMESIZE_SHIFT), frameSizeReg);
|
||||
@ -862,7 +862,7 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
||||
}
|
||||
|
||||
// Save an exit frame (which must be aligned to the stack pointer) to
|
||||
// ThreadData::ionTop.
|
||||
// ThreadData::ionTop of the main thread.
|
||||
void linkExitFrame() {
|
||||
JSCompartment *compartment = GetIonContext()->compartment;
|
||||
movl(StackPointer, Operand(&compartment->rt->mainThread.ionTop));
|
||||
@ -875,6 +875,12 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
||||
call(target);
|
||||
}
|
||||
|
||||
// Save an exit frame to the thread data of the current thread, given a
|
||||
// register that holds a PerThreadData *.
|
||||
void linkParallelExitFrame(const Register &pt) {
|
||||
movl(StackPointer, Operand(pt, offsetof(PerThreadData, ionTop)));
|
||||
}
|
||||
|
||||
void enterOsr(Register calleeToken, Register code) {
|
||||
push(Imm32(0)); // num actual args.
|
||||
push(calleeToken);
|
||||
|
@ -315,6 +315,7 @@ IonRuntime::generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void *
|
||||
|
||||
// Load the number of |undefined|s to push into %ecx.
|
||||
masm.movl(Operand(esp, IonRectifierFrameLayout::offsetOfCalleeToken()), eax);
|
||||
masm.clearCalleeTag(eax, mode);
|
||||
masm.movzwl(Operand(eax, offsetof(JSFunction, nargs)), ecx);
|
||||
masm.subl(esi, ecx);
|
||||
|
||||
@ -521,6 +522,9 @@ IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
|
||||
// Wrapper register set is a superset of Volatile register set.
|
||||
JS_STATIC_ASSERT((Register::Codes::VolatileMask & ~Register::Codes::WrapperMask) == 0);
|
||||
|
||||
// The context is the first argument.
|
||||
Register cxreg = regs.takeAny();
|
||||
|
||||
// Stack is:
|
||||
// ... frame ...
|
||||
// +8 [args]
|
||||
@ -528,7 +532,7 @@ IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
|
||||
// +0 returnAddress
|
||||
//
|
||||
// We're aligned to an exit frame, so link it up.
|
||||
masm.enterExitFrame(&f);
|
||||
masm.enterExitFrameAndLoadContext(&f, cxreg, regs.getAny(), f.executionMode);
|
||||
|
||||
// Save the current stack pointer as the base for copying arguments.
|
||||
Register argsBase = InvalidReg;
|
||||
@ -563,12 +567,7 @@ IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
|
||||
break;
|
||||
}
|
||||
|
||||
Register temp = regs.getAny();
|
||||
masm.setupUnalignedABICall(f.argc(), temp);
|
||||
|
||||
// Initialize the context parameter.
|
||||
Register cxreg = regs.takeAny();
|
||||
masm.loadJSContext(cxreg);
|
||||
masm.setupUnalignedABICall(f.argc(), regs.getAny());
|
||||
masm.passABIArg(cxreg);
|
||||
|
||||
size_t argDisp = 0;
|
||||
@ -607,15 +606,17 @@ IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
|
||||
masm.callWithABI(f.wrapped);
|
||||
|
||||
// Test for failure.
|
||||
Label exception;
|
||||
Label failure;
|
||||
switch (f.failType()) {
|
||||
case Type_Object:
|
||||
masm.testl(eax, eax);
|
||||
masm.j(Assembler::Zero, &exception);
|
||||
masm.branchTestPtr(Assembler::Zero, eax, eax, &failure);
|
||||
break;
|
||||
case Type_Bool:
|
||||
masm.testb(eax, eax);
|
||||
masm.j(Assembler::Zero, &exception);
|
||||
masm.j(Assembler::Zero, &failure);
|
||||
break;
|
||||
case Type_ParallelResult:
|
||||
masm.branchPtr(Assembler::NotEqual, eax, Imm32(TP_SUCCESS), &failure);
|
||||
break;
|
||||
default:
|
||||
JS_NOT_REACHED("unknown failure kind");
|
||||
@ -644,8 +645,8 @@ IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
|
||||
f.explicitStackSlots() * sizeof(void *) +
|
||||
f.extraValuesToPop * sizeof(Value)));
|
||||
|
||||
masm.bind(&exception);
|
||||
masm.handleException();
|
||||
masm.bind(&failure);
|
||||
masm.handleFailure(f.executionMode);
|
||||
|
||||
Linker linker(masm);
|
||||
IonCode *wrapper = linker.newCode(cx, JSC::OTHER_CODE);
|
||||
|
Loading…
Reference in New Issue
Block a user