Bug 959597 part 3 - Add ARM simulator for JIT code. r=nbp

This commit is contained in:
Jan de Mooij 2014-01-29 13:34:14 +01:00
parent c0d09abad1
commit f289f537ef
37 changed files with 4922 additions and 74 deletions

View File

@ -34,7 +34,7 @@
#include "assembler/assembler/MacroAssemblerARM.h"
#if WTF_OS_LINUX || WTF_OS_ANDROID
#if (WTF_OS_LINUX || WTF_OS_ANDROID) && !defined(JS_ARM_SIMULATOR)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@ -56,6 +56,9 @@ namespace JSC {
static bool isVFPPresent()
{
#ifdef JS_ARM_SIMULATOR
return true;
#else
#if WTF_OS_LINUX
int fd = open("/proc/self/auxv", O_RDONLY);
if (fd > 0) {
@ -85,8 +88,8 @@ static bool isVFPPresent()
if (strstr(buf, "vfp"))
return true;
#endif
return false;
#endif // JS_ARM_SIMULATOR
}
const bool MacroAssemblerARM::s_isVFPPresent = isVFPPresent();

View File

@ -32,6 +32,7 @@
#include "jsalloc.h"
#include "assembler/wtf/Platform.h"
#include "jit/arm/Simulator-arm.h"
#include "js/HashTable.h"
#include "js/Vector.h"
@ -396,6 +397,11 @@ public:
static void cacheFlush(void*, size_t)
{
}
#elif defined(JS_ARM_SIMULATOR)
static void cacheFlush(void *code, size_t size)
{
js::jit::Simulator::FlushICache(code, size);
}
#elif WTF_CPU_MIPS
static void cacheFlush(void* code, size_t size)
{

View File

@ -366,6 +366,13 @@
#endif /* ARM */
#if defined(JS_ARM_SIMULATOR)
# undef WTF_CPU_X86
# undef WTF_CPU_X64
# define WTF_CPU_ARM_TRADITIONAL 1
# define WTF_CPU_ARM 1
#endif
#if WTF_CPU_ARM || WTF_CPU_MIPS
#define WTF_CPU_NEEDS_ALIGNED_ACCESS 1
#endif

View File

@ -278,10 +278,14 @@ MarkRangeConservativelyAndSkipIon(JSTracer *trc, JSRuntime *rt, const uintptr_t
{
const uintptr_t *i = begin;
#if JS_STACK_GROWTH_DIRECTION < 0 && defined(JS_ION)
#if JS_STACK_GROWTH_DIRECTION < 0 && defined(JS_ION) && !defined(JS_ARM_SIMULATOR)
// Walk only regions in between JIT activations. Note that non-volatile
// registers are spilled to the stack before the entry frame, ensuring
// that the conservative scanner will still see them.
//
// If the ARM simulator is enabled, JIT activations are not on the native
// stack but on the simulator stack, so we don't have to skip JIT regions
// in this case.
for (jit::JitActivationIterator iter(rt); !iter.done(); ++iter) {
uintptr_t *jitMin, *jitEnd;
iter.jitStackRange(jitMin, jitEnd);

View File

@ -18,6 +18,7 @@
#include "frontend/BytecodeCompiler.h"
#include "jit/AsmJSModule.h"
#include "jit/Ion.h"
#include "jit/JitCommon.h"
#ifdef JS_ION_PERF
# include "jit/PerfSpewer.h"
#endif
@ -397,7 +398,8 @@ CallAsmJS(JSContext *cx, unsigned argc, Value *vp)
JitActivation jitActivation(cx, /* firstFrameIsConstructing = */ false, /* active */ false);
// Call the per-exported-function trampoline created by GenerateEntry.
if (!module.entryTrampoline(func)(coercedArgs.begin(), module.globalData()))
AsmJSModule::CodePtr enter = module.entryTrampoline(func);
if (!CALL_GENERATED_ASMJS(enter, coercedArgs.begin(), module.globalData()))
return false;
}

View File

@ -183,10 +183,10 @@ InvokeFromAsmJS_ToNumber(JSContext *cx, int32_t exitIndex, int32_t argc, Value *
#if defined(JS_CODEGEN_ARM)
extern "C" {
extern int
extern int64_t
__aeabi_idivmod(int, int);
extern int
extern int64_t
__aeabi_uidivmod(int, int);
}
@ -199,6 +199,15 @@ FuncCast(F *pf)
return JS_FUNC_TO_DATA_PTR(void *, pf);
}
static void *
RedirectCall(void *fun, ABIFunctionType type)
{
#ifdef JS_ARM_SIMULATOR
fun = Simulator::RedirectNativeFunction(fun, type);
#endif
return fun;
}
static void *
AddressOf(AsmJSImmKind kind, ExclusiveContext *cx)
{
@ -206,79 +215,79 @@ AddressOf(AsmJSImmKind kind, ExclusiveContext *cx)
case AsmJSImm_Runtime:
return cx->runtimeAddressForJit();
case AsmJSImm_StackLimit:
return cx->stackLimitAddress(StackForUntrustedScript);
return cx->stackLimitAddressForJitCode(StackForUntrustedScript);
case AsmJSImm_ReportOverRecursed:
return FuncCast<void (JSContext*)>(js_ReportOverRecursed);
return RedirectCall(FuncCast<void (JSContext*)>(js_ReportOverRecursed), Args_General1);
case AsmJSImm_HandleExecutionInterrupt:
return FuncCast(js_HandleExecutionInterrupt);
return RedirectCall(FuncCast(js_HandleExecutionInterrupt), Args_General1);
case AsmJSImm_InvokeFromAsmJS_Ignore:
return FuncCast(InvokeFromAsmJS_Ignore);
return RedirectCall(FuncCast(InvokeFromAsmJS_Ignore), Args_General4);
case AsmJSImm_InvokeFromAsmJS_ToInt32:
return FuncCast(InvokeFromAsmJS_ToInt32);
return RedirectCall(FuncCast(InvokeFromAsmJS_ToInt32), Args_General4);
case AsmJSImm_InvokeFromAsmJS_ToNumber:
return FuncCast(InvokeFromAsmJS_ToNumber);
return RedirectCall(FuncCast(InvokeFromAsmJS_ToNumber), Args_General4);
case AsmJSImm_CoerceInPlace_ToInt32:
return FuncCast(CoerceInPlace_ToInt32);
return RedirectCall(FuncCast(CoerceInPlace_ToInt32), Args_General2);
case AsmJSImm_CoerceInPlace_ToNumber:
return FuncCast(CoerceInPlace_ToNumber);
return RedirectCall(FuncCast(CoerceInPlace_ToNumber), Args_General2);
case AsmJSImm_ToInt32:
return FuncCast<int32_t (double)>(js::ToInt32);
return RedirectCall(FuncCast<int32_t (double)>(js::ToInt32), Args_Int_Double);
case AsmJSImm_EnableActivationFromAsmJS:
return FuncCast(EnableActivationFromAsmJS);
return RedirectCall(FuncCast(EnableActivationFromAsmJS), Args_General1);
case AsmJSImm_DisableActivationFromAsmJS:
return FuncCast(DisableActivationFromAsmJS);
return RedirectCall(FuncCast(DisableActivationFromAsmJS), Args_General1);
#if defined(JS_CODEGEN_ARM)
case AsmJSImm_aeabi_idivmod:
return FuncCast(__aeabi_idivmod);
return RedirectCall(FuncCast(__aeabi_idivmod), Args_General2);
case AsmJSImm_aeabi_uidivmod:
return FuncCast(__aeabi_uidivmod);
return RedirectCall(FuncCast(__aeabi_uidivmod), Args_General2);
#endif
case AsmJSImm_ModD:
return FuncCast(NumberMod);
return RedirectCall(FuncCast(NumberMod), Args_Double_DoubleDouble);
case AsmJSImm_SinD:
return FuncCast<double (double)>(sin);
return RedirectCall(FuncCast<double (double)>(sin), Args_Double_Double);
case AsmJSImm_SinF:
return FuncCast<float (float)>(sinf);
return RedirectCall(FuncCast<float (float)>(sinf), Args_Float32_Float32);
case AsmJSImm_CosD:
return FuncCast<double (double)>(cos);
return RedirectCall(FuncCast<double (double)>(cos), Args_Double_Double);
case AsmJSImm_CosF:
return FuncCast<float (float)>(cosf);
return RedirectCall(FuncCast<float (float)>(cosf), Args_Float32_Float32);
case AsmJSImm_TanD:
return FuncCast<double (double)>(tan);
return RedirectCall(FuncCast<double (double)>(tan), Args_Double_Double);
case AsmJSImm_TanF:
return FuncCast<float (float)>(tanf);
return RedirectCall(FuncCast<float (float)>(tanf), Args_Float32_Float32);
case AsmJSImm_ASinD:
return FuncCast<double (double)>(asin);
return RedirectCall(FuncCast<double (double)>(asin), Args_Double_Double);
case AsmJSImm_ASinF:
return FuncCast<float (float)>(asinf);
return RedirectCall(FuncCast<float (float)>(asinf), Args_Float32_Float32);
case AsmJSImm_ACosD:
return FuncCast<double (double)>(acos);
return RedirectCall(FuncCast<double (double)>(acos), Args_Double_Double);
case AsmJSImm_ACosF:
return FuncCast<float (float)>(acosf);
return RedirectCall(FuncCast<float (float)>(acosf), Args_Float32_Float32);
case AsmJSImm_ATanD:
return FuncCast<double (double)>(atan);
return RedirectCall(FuncCast<double (double)>(atan), Args_Double_Double);
case AsmJSImm_ATanF:
return FuncCast<float (float)>(atanf);
return RedirectCall(FuncCast<float (float)>(atanf), Args_Float32_Float32);
case AsmJSImm_CeilD:
return FuncCast<double (double)>(ceil);
return RedirectCall(FuncCast<double (double)>(ceil), Args_Double_Double);
case AsmJSImm_CeilF:
return FuncCast<float (float)>(ceilf);
return RedirectCall(FuncCast<float (float)>(ceilf), Args_Float32_Float32);
case AsmJSImm_FloorD:
return FuncCast<double (double)>(floor);
return RedirectCall(FuncCast<double (double)>(floor), Args_Double_Double);
case AsmJSImm_FloorF:
return FuncCast<float (float)>(floorf);
return RedirectCall(FuncCast<float (float)>(floorf), Args_Float32_Float32);
case AsmJSImm_ExpD:
return FuncCast<double (double)>(exp);
return RedirectCall(FuncCast<double (double)>(exp), Args_Double_Double);
case AsmJSImm_ExpF:
return FuncCast<float (float)>(expf);
return RedirectCall(FuncCast<float (float)>(expf), Args_Float32_Float32);
case AsmJSImm_LogD:
return FuncCast<double (double)>(log);
return RedirectCall(FuncCast<double (double)>(log), Args_Double_Double);
case AsmJSImm_LogF:
return FuncCast<float (float)>(logf);
return RedirectCall(FuncCast<float (float)>(logf), Args_Float32_Float32);
case AsmJSImm_PowD:
return FuncCast(ecmaPow);
return RedirectCall(FuncCast(ecmaPow), Args_Double_DoubleDouble);
case AsmJSImm_ATan2D:
return FuncCast(ecmaAtan2);
return RedirectCall(FuncCast(ecmaAtan2), Args_Double_DoubleDouble);
case AsmJSImm_Invalid:
break;
}

View File

@ -332,6 +332,29 @@ static bool IsSignalHandlingBroken() { return false; }
# define PC_sig(p) R15_sig(p)
#endif
static bool
HandleSimulatorInterrupt(JSRuntime *rt, AsmJSActivation *activation, void *faultingAddress)
{
// If the ARM simulator is enabled, the pc is in the simulator C++ code and
// not in the generated code, so we check the simulator's pc manually. Also
// note that we can't simply use simulator->set_pc() here because the
// simulator could be in the middle of an instruction. On ARM, the signal
// handlers are currently only used for Odin code, see bug 964258.
#ifdef JS_ARM_SIMULATOR
const AsmJSModule &module = activation->module();
if (module.containsPC((void *)rt->mainThread.simulator()->get_pc()) &&
module.containsPC(faultingAddress))
{
activation->setResumePC(nullptr);
int32_t nextpc = int32_t(module.operationCallbackExit());
rt->mainThread.simulator()->set_resume_pc(nextpc);
return true;
}
#endif
return false;
}
#if !defined(XP_MACOSX)
static uint8_t **
ContextToPC(CONTEXT *context)
@ -621,6 +644,11 @@ HandleMachException(JSRuntime *rt, const ExceptionRequest &request)
return false;
const AsmJSModule &module = activation->module();
if (HandleSimulatorInterrupt(rt, activation, faultingAddress)) {
mprotect(module.codeBase(), module.functionBytes(), PROT_EXEC);
return true;
}
if (!module.containsPC(pc))
return false;
@ -863,6 +891,11 @@ HandleSignal(int signum, siginfo_t *info, void *ctx)
return false;
const AsmJSModule &module = activation->module();
if (HandleSimulatorInterrupt(rt, activation, faultingAddress)) {
mprotect(module.codeBase(), module.functionBytes(), PROT_EXEC);
return true;
}
if (!module.containsPC(pc))
return false;

View File

@ -4,6 +4,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jit/arm/Simulator-arm.h"
#include "jit/BaselineIC.h"
#include "jit/BaselineJIT.h"
#include "jit/CompileInfo.h"
@ -1336,7 +1337,12 @@ jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIt
// Do stack check.
bool overRecursed = false;
uint8_t *newsp = info->incomingStack - (info->copyStackTop - info->copyStackBottom);
#ifdef JS_ARM_SIMULATOR
if (Simulator::Current()->overRecursed(uintptr_t(newsp)))
overRecursed = true;
#else
JS_CHECK_RECURSION_WITH_SP_DONT_REPORT(cx, newsp, overRecursed = true);
#endif
if (overRecursed) {
IonSpew(IonSpew_BaselineBailouts, " Overrecursion check failed!");
return BAILOUT_RETURN_OVERRECURSED;

View File

@ -8722,7 +8722,15 @@ ICCall_Native::Compiler::generateStubCode(MacroAssembler &masm)
masm.passABIArg(scratch);
masm.passABIArg(argcReg);
masm.passABIArg(vpReg);
#ifdef JS_ARM_SIMULATOR
// The simulator requires VM calls to be redirected to a special swi
// instruction to handle them, so we store the redirected pointer in the
// stub and use that instead of the original one.
masm.callWithABI(Address(BaselineStubReg, ICCall_Native::offsetOfNative()));
#else
masm.callWithABI(Address(callee, JSFunction::offsetOfNativeOrScript()));
#endif
// Test for failure.
masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
@ -9832,7 +9840,15 @@ ICCall_Native::ICCall_Native(JitCode *stubCode, ICStub *firstMonitorStub,
callee_(callee),
templateObject_(templateObject),
pcOffset_(pcOffset)
{ }
{
#ifdef JS_ARM_SIMULATOR
// The simulator requires VM calls to be redirected to a special swi
// instruction to handle them. To make this work, we store the redirected
// pointer in the stub.
native_ = Simulator::RedirectNativeFunction(JS_FUNC_TO_DATA_PTR(void *, callee->native()),
Args_General3);
#endif
}
ICGetPropCallDOMProxyNativeStub::ICGetPropCallDOMProxyNativeStub(Kind kind, JitCode *stubCode,
ICStub *firstMonitorStub,

View File

@ -5414,6 +5414,10 @@ class ICCall_Native : public ICMonitoredStub
HeapPtrObject templateObject_;
uint32_t pcOffset_;
#ifdef JS_ARM_SIMULATOR
void *native_;
#endif
ICCall_Native(JitCode *stubCode, ICStub *firstMonitorStub,
HandleFunction callee, HandleObject templateObject,
uint32_t pcOffset);
@ -5443,6 +5447,12 @@ class ICCall_Native : public ICMonitoredStub
return offsetof(ICCall_Native, pcOffset_);
}
#ifdef JS_ARM_SIMULATOR
static size_t offsetOfNative() {
return offsetof(ICCall_Native, native_);
}
#endif
// Compiler for this stub kind.
class Compiler : public ICCallStubCompiler {
protected:

View File

@ -12,6 +12,7 @@
#include "jit/BaselineIC.h"
#include "jit/CompileInfo.h"
#include "jit/IonSpewer.h"
#include "jit/JitCommon.h"
#include "vm/Interpreter.h"
#include "jsgcinlines.h"
@ -118,8 +119,8 @@ EnterBaseline(JSContext *cx, EnterJitData &data)
JS_ASSERT_IF(data.osrFrame, !IsJSDEnabled(cx));
// Single transition point from Interpreter to Baseline.
enter(data.jitcode, data.maxArgc, data.maxArgv, data.osrFrame, data.calleeToken,
data.scopeChain, data.osrNumStackValues, data.result.address());
CALL_GENERATED_CODE(enter, data.jitcode, data.maxArgc, data.maxArgv, data.osrFrame, data.calleeToken,
data.scopeChain.get(), data.osrNumStackValues, data.result.address());
if (data.osrFrame)
data.osrFrame->clearRunningInJit();

View File

@ -30,6 +30,7 @@
#include "jit/IonBuilder.h"
#include "jit/IonOptimizationLevels.h"
#include "jit/IonSpewer.h"
#include "jit/JitCommon.h"
#include "jit/JitCompartment.h"
#include "jit/LICM.h"
#include "jit/LinearScan.h"
@ -2231,9 +2232,8 @@ EnterIon(JSContext *cx, EnterJitData &data)
JSAutoResolveFlags rf(cx, RESOLVE_INFER);
AutoFlushInhibitor afi(cx->runtime()->jitRuntime());
// Single transition point from Interpreter to Baseline.
enter(data.jitcode, data.maxArgc, data.maxArgv, /* osrFrame = */nullptr, data.calleeToken,
/* scopeChain = */ nullptr, 0, data.result.address());
CALL_GENERATED_CODE(enter, data.jitcode, data.maxArgc, data.maxArgv, /* osrFrame = */nullptr, data.calleeToken,
/* scopeChain = */ nullptr, 0, data.result.address());
}
JS_ASSERT(!cx->runtime()->hasIonReturnOverride());
@ -2342,8 +2342,9 @@ jit::FastInvoke(JSContext *cx, HandleFunction fun, CallArgs &args)
JS_ASSERT(args.length() >= fun->nargs());
JSAutoResolveFlags rf(cx, RESOLVE_INFER);
enter(jitcode, args.length() + 1, args.array() - 1, nullptr, calleeToken,
/* scopeChain = */ nullptr, 0, result.address());
CALL_GENERATED_CODE(enter, jitcode, args.length() + 1, args.array() - 1, /* osrFrame = */nullptr,
calleeToken, /* scopeChain = */ nullptr, 0, result.address());
JS_ASSERT(!cx->runtime()->hasIonReturnOverride());

View File

@ -244,6 +244,64 @@ IsNullOrUndefined(MIRType type)
# endif
#endif
enum {
ArgType_General = 0x1,
ArgType_Double = 0x2,
ArgType_Float32 = 0x3,
RetType_Shift = 0x0,
ArgType_Shift = 0x2,
ArgType_Mask = 0x3
};
enum ABIFunctionType
{
// VM functions that take 0-9 non-double arguments
// and return a non-double value.
Args_General0 = ArgType_General << RetType_Shift,
Args_General1 = Args_General0 | (ArgType_General << (ArgType_Shift * 1)),
Args_General2 = Args_General1 | (ArgType_General << (ArgType_Shift * 2)),
Args_General3 = Args_General2 | (ArgType_General << (ArgType_Shift * 3)),
Args_General4 = Args_General3 | (ArgType_General << (ArgType_Shift * 4)),
Args_General5 = Args_General4 | (ArgType_General << (ArgType_Shift * 5)),
Args_General6 = Args_General5 | (ArgType_General << (ArgType_Shift * 6)),
Args_General7 = Args_General6 | (ArgType_General << (ArgType_Shift * 7)),
Args_General8 = Args_General7 | (ArgType_General << (ArgType_Shift * 8)),
// double f()
Args_Double_None = ArgType_Double << RetType_Shift,
// int f(double)
Args_Int_Double = Args_General0 | (ArgType_Double << ArgType_Shift),
// float f(float)
Args_Float32_Float32 = (ArgType_Float32 << RetType_Shift) | (ArgType_Float32 << ArgType_Shift),
// double f(double)
Args_Double_Double = Args_Double_None | (ArgType_Double << ArgType_Shift),
// double f(int)
Args_Double_Int = Args_Double_None | (ArgType_General << ArgType_Shift),
// double f(double, int)
Args_Double_DoubleInt = Args_Double_None |
(ArgType_General << (ArgType_Shift * 1)) |
(ArgType_Double << (ArgType_Shift * 2)),
// double f(double, double)
Args_Double_DoubleDouble = Args_Double_Double | (ArgType_Double << (ArgType_Shift * 2)),
// double f(int, double)
Args_Double_IntDouble = Args_Double_None |
(ArgType_Double << (ArgType_Shift * 1)) |
(ArgType_General << (ArgType_Shift * 2)),
// int f(int, double)
Args_Int_IntDouble = Args_General0 |
(ArgType_Double << (ArgType_Shift * 1)) |
(ArgType_General << (ArgType_Shift * 2))
};
} // namespace jit
} // namespace js

46
js/src/jit/JitCommon.h Normal file
View File

@ -0,0 +1,46 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef jit_JitCommon_h
#define jit_JitCommon_h
// Various macros used by all JITs, including YARR.
#ifdef JS_ARM_SIMULATOR
#include "jit/arm/Simulator-arm.h"
// Call into cross-jitted code by following the ABI of the simulated architecture.
#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \
(js::jit::Simulator::Current()->call( \
JS_FUNC_TO_DATA_PTR(uint8_t *, entry), 8, p0, p1, p2, p3, p4, p5, p6, p7) & 0xffffffff)
#define CALL_GENERATED_YARR_CODE3(entry, p0, p1, p2) \
js::jit::Simulator::Current()->call(JS_FUNC_TO_DATA_PTR(uint8_t *, entry), 3, p0, p1, p2)
#define CALL_GENERATED_YARR_CODE4(entry, p0, p1, p2, p3) \
js::jit::Simulator::Current()->call(JS_FUNC_TO_DATA_PTR(uint8_t *, entry), 4, p0, p1, p2, p3)
#define CALL_GENERATED_ASMJS(entry, p0, p1) \
(Simulator::Current()->call(JS_FUNC_TO_DATA_PTR(uint8_t *, entry), 2, p0, p1) & 0xffffffff)
#else
// Call into jitted code by following the ABI of the native architecture.
#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \
entry(p0, p1, p2, p3, p4, p5, p6, p7)
#define CALL_GENERATED_YARR_CODE3(entry, p0, p1, p2) \
entry(p0, p1, p2)
#define CALL_GENERATED_YARR_CODE4(entry, p0, p1, p2, p3) \
entry(p0, p1, p2, p3)
#define CALL_GENERATED_ASMJS(entry, p0, p1) \
entry(p0, p1)
#endif
#endif // jit_JitCommon_h

View File

@ -7,6 +7,7 @@
#include "jit/ParallelFunctions.h"
#include "builtin/TypedObject.h"
#include "jit/arm/Simulator-arm.h"
#include "vm/ArrayObject.h"
#include "jsgcinlines.h"
@ -190,6 +191,13 @@ jit::CheckOverRecursedPar(ForkJoinSlice *slice)
// limit, but we do still call into this routine if the interrupt
// flag is set, so we still need to double check.
#ifdef JS_ARM_SIMULATOR
if (Simulator::Current()->overRecursed()) {
slice->bailoutRecord->setCause(ParallelBailoutOverRecursed);
return false;
}
#endif
uintptr_t realStackLimit;
if (slice->isMainThread())
realStackLimit = GetNativeStackLimit(slice);

View File

@ -31,6 +31,11 @@ struct Register {
Register r = { (Registers::Code)i };
return r;
}
static Register FromName(const char *name) {
Registers::Code code = Registers::FromName(name);
Register r = { code };
return r;
}
Code code() const {
JS_ASSERT((uint32_t)code_ < Registers::Total);
return code_;
@ -60,6 +65,11 @@ struct FloatRegister {
FloatRegister r = { (FloatRegisters::Code)i };
return r;
}
static FloatRegister FromName(const char *name) {
FloatRegisters::Code code = FloatRegisters::FromName(name);
FloatRegister r = { code };
return r;
}
Code code() const {
JS_ASSERT((uint32_t)code_ < FloatRegisters::Total);
return code_;

View File

@ -8,6 +8,7 @@
#include "builtin/TypedObject.h"
#include "frontend/BytecodeCompiler.h"
#include "jit/arm/Simulator-arm.h"
#include "jit/BaselineIC.h"
#include "jit/IonFrames.h"
#include "jit/JitCompartment.h"
@ -119,7 +120,11 @@ CheckOverRecursed(JSContext *cx)
// has not yet been set to 1. That's okay; it will be set to 1 very shortly,
// and in the interim we might just fire a few useless calls to
// CheckOverRecursed.
#ifdef JS_ARM_SIMULATOR
JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, 0, return false);
#else
JS_CHECK_RECURSION(cx, return false);
#endif
if (cx->runtime()->interrupt)
return InterruptCheck(cx);
@ -148,7 +153,12 @@ CheckOverRecursedWithExtra(JSContext *cx, BaselineFrame *frame,
uint8_t spDummy;
uint8_t *checkSp = (&spDummy) - extra;
if (earlyCheck) {
#ifdef JS_ARM_SIMULATOR
(void)checkSp;
JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, extra, frame->setOverRecursed());
#else
JS_CHECK_RECURSION_WITH_SP(cx, checkSp, frame->setOverRecursed());
#endif
return true;
}
@ -157,7 +167,11 @@ CheckOverRecursedWithExtra(JSContext *cx, BaselineFrame *frame,
if (frame->overRecursed())
return false;
#ifdef JS_ARM_SIMULATOR
JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, extra, return false);
#else
JS_CHECK_RECURSION_WITH_SP(cx, checkSp, return false);
#endif
if (cx->runtime()->interrupt)
return InterruptCheck(cx);

View File

@ -6,13 +6,16 @@
#include "jit/arm/Architecture-arm.h"
#ifndef JS_ARM_SIMULATOR
#include <elf.h>
#endif
#include <fcntl.h>
#include <unistd.h>
#include "jit/arm/Assembler-arm.h"
#if !(defined(ANDROID) || defined(MOZ_B2G))
#if !(defined(ANDROID) || defined(MOZ_B2G)) && !defined(JS_ARM_SIMULATOR)
#define HWCAP_ARMv7 (1 << 29)
#include <asm/hwcap.h>
#else
@ -36,6 +39,12 @@ uint32_t GetARMFlags()
if (isSet)
return flags;
#ifdef JS_ARM_SIMULATOR
isSet = true;
flags = HWCAP_ARMv7 | HWCAP_VFP | HWCAP_VFPv4 | HWCAP_NEON;
return flags;
#else
#if WTF_OS_LINUX
int fd = open("/proc/self/auxv", O_RDONLY);
if (fd > 0) {
@ -105,6 +114,7 @@ uint32_t GetARMFlags()
#endif
return 0;
#endif // JS_ARM_SIMULATOR
}
bool hasMOVWT()
@ -138,6 +148,37 @@ bool hasIDIV()
#endif
}
Registers::Code
Registers::FromName(const char *name)
{
// Check for some register aliases first.
if (strcmp(name, "ip") == 0)
return ip;
if (strcmp(name, "r13") == 0)
return r13;
if (strcmp(name, "lr") == 0)
return lr;
if (strcmp(name, "r15") == 0)
return r15;
for (size_t i = 0; i < Total; i++) {
if (strcmp(GetName(i), name) == 0)
return Code(i);
}
return Invalid;
}
FloatRegisters::Code
FloatRegisters::FromName(const char *name)
{
for (size_t i = 0; i < Total; i++) {
if (strcmp(GetName(i), name) == 0)
return Code(i);
}
return Invalid;
}
} // namespace jit
} // namespace js

View File

@ -10,6 +10,8 @@
#include <limits.h>
#include <stdint.h>
#include "js/Utility.h"
// gcc appears to use __ARM_PCS_VFP to denote that the target is a hard-float target.
#ifdef __ARM_PCS_VFP
#define JS_CODEGEN_ARM_HARDFP
@ -75,6 +77,12 @@ class Registers
"r8", "r9", "r10", "r11", "r12", "sp", "r14", "pc"};
return Names[code];
}
static const char *GetName(uint32_t i) {
MOZ_ASSERT(i < Total);
return GetName(Code(i));
}
static Code FromName(const char *name);
static const Code StackPointer = sp;
static const Code Invalid = invalid_reg;
@ -180,6 +188,12 @@ class FloatRegisters
"d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15"};
return Names[code];
}
static const char *GetName(uint32_t i) {
JS_ASSERT(i < Total);
return GetName(Code(i));
}
static Code FromName(const char *name);
static const Code Invalid = invalid_freg;

View File

@ -1021,15 +1021,6 @@ class Imm16
}
};
// FP Instructions use a different set of registers,
// with a different encoding, so this calls for a different class.
// which will be implemented later
// IIRC, this has been subsumed by vfpreg.
class FloatOp
{
uint32_t data;
};
/* I would preffer that these do not exist, since there are essentially
* no instructions that would ever take more than one of these, however,
* the MIR wants to only have one type of arguments to functions, so bugger.

View File

@ -71,7 +71,7 @@ ICCompare_Double::Compiler::generateStubCode(MacroAssembler &masm)
// ICBinaryArith_Int32
extern "C" {
extern int __aeabi_idivmod(int,int);
extern int64_t __aeabi_idivmod(int,int);
}
bool

View File

@ -609,8 +609,8 @@ CodeGeneratorARM::visitDivI(LDivI *ins)
}
extern "C" {
extern int __aeabi_idivmod(int,int);
extern int __aeabi_uidivmod(int,int);
extern int64_t __aeabi_idivmod(int,int);
extern int64_t __aeabi_uidivmod(int,int);
}
bool

View File

@ -204,6 +204,7 @@ typedef CodeGeneratorARM CodeGeneratorSpecific;
// An out-of-line bailout thunk.
class OutOfLineBailout : public OutOfLineCodeBase<CodeGeneratorARM>
{
protected: // Silence Clang warning.
LSnapshot *snapshot_;
uint32_t frameSize_;

View File

@ -9,6 +9,7 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/MathAlgorithms.h"
#include "jit/arm/Simulator-arm.h"
#include "jit/Bailouts.h"
#include "jit/BaselineFrame.h"
#include "jit/MoveEmitter.h"
@ -3479,6 +3480,7 @@ MacroAssemblerARMCompat::setupABICall(uint32_t args)
inCall_ = true;
args_ = args;
passedArgs_ = 0;
passedArgTypes_ = 0;
#ifdef JS_CODEGEN_ARM_HARDFP
usedIntSlots_ = 0;
usedFloatSlots_ = 0;
@ -3512,6 +3514,7 @@ MacroAssemblerARMCompat::setupUnalignedABICall(uint32_t args, const Register &sc
ma_and(Imm32(~(StackAlignment - 1)), sp, sp);
ma_push(scratch);
}
#ifdef JS_CODEGEN_ARM_HARDFP
void
MacroAssemblerARMCompat::passABIArg(const MoveOperand &from, MoveOp::Type type)
@ -3537,6 +3540,10 @@ MacroAssemblerARMCompat::passABIArg(const MoveOperand &from, MoveOp::Type type)
to = MoveOperand(sp, disp);
}
usedFloatSlots_++;
if (type == MoveOp::FLOAT32)
passedArgTypes_ = (passedArgTypes_ << ArgType_Shift) | ArgType_Float32;
else
passedArgTypes_ = (passedArgTypes_ << ArgType_Shift) | ArgType_Double;
break;
}
case MoveOp::GENERAL: {
@ -3552,6 +3559,7 @@ MacroAssemblerARMCompat::passABIArg(const MoveOperand &from, MoveOp::Type type)
to = MoveOperand(sp, disp);
}
usedIntSlots_++;
passedArgTypes_ = (passedArgTypes_ << ArgType_Shift) | ArgType_General;
break;
}
default:
@ -3575,9 +3583,13 @@ MacroAssemblerARMCompat::passABIArg(const MoveOperand &from, MoveOp::Type type)
// boundary, even if it is in a register!
usedSlots_ = (usedSlots_ + 1) & ~1;
increment = 2;
passedArgTypes_ = (passedArgTypes_ << ArgType_Shift) | ArgType_Double;
break;
case MoveOp::FLOAT32:
passedArgTypes_ = (passedArgTypes_ << ArgType_Shift) | ArgType_Float32;
break;
case MoveOp::GENERAL:
passedArgTypes_ = (passedArgTypes_ << ArgType_Shift) | ArgType_General;
break;
default:
MOZ_ASSUME_UNREACHABLE("Unexpected argument type");
@ -3723,9 +3735,53 @@ MacroAssemblerARMCompat::callWithABIPost(uint32_t stackAdjust, MoveOp::Type resu
inCall_ = false;
}
#if defined(DEBUG) && defined(JS_ARM_SIMULATOR)
static void
AssertValidABIFunctionType(uint32_t passedArgTypes)
{
switch (passedArgTypes) {
case Args_General0:
case Args_General1:
case Args_General2:
case Args_General3:
case Args_General4:
case Args_General5:
case Args_General6:
case Args_General7:
case Args_General8:
case Args_Double_None:
case Args_Int_Double:
case Args_Float32_Float32:
case Args_Double_Double:
case Args_Double_Int:
case Args_Double_DoubleInt:
case Args_Double_DoubleDouble:
case Args_Double_IntDouble:
case Args_Int_IntDouble:
break;
default:
MOZ_ASSUME_UNREACHABLE("Unexpected type");
}
}
#endif
void
MacroAssemblerARMCompat::callWithABI(void *fun, MoveOp::Type result)
{
#ifdef JS_ARM_SIMULATOR
MOZ_ASSERT(passedArgs_ <= 15);
passedArgTypes_ <<= ArgType_Shift;
switch (result) {
case MoveOp::GENERAL: passedArgTypes_ |= ArgType_General; break;
case MoveOp::DOUBLE: passedArgTypes_ |= ArgType_Double; break;
case MoveOp::FLOAT32: passedArgTypes_ |= ArgType_Float32; break;
default: MOZ_ASSUME_UNREACHABLE("Invalid return type");
}
AssertValidABIFunctionType(passedArgTypes_);
ABIFunctionType type = ABIFunctionType(passedArgTypes_);
fun = Simulator::RedirectNativeFunction(fun, type);
#endif
uint32_t stackAdjust;
callWithABIPre(&stackAdjust);
ma_call(ImmPtr(fun));

View File

@ -443,6 +443,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
// The actual number of arguments that were passed, used to assert that
// the initial number of arguments declared was correct.
uint32_t passedArgs_;
uint32_t passedArgTypes_;
#ifdef JS_CODEGEN_ARM_HARDFP
uint32_t usedIntSlots_;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,364 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef jit_arm_Simulator_arm_h
#define jit_arm_Simulator_arm_h
#ifdef JS_ARM_SIMULATOR
#include "jit/IonTypes.h"
namespace js {
namespace jit {
class SimulatorRuntime;
SimulatorRuntime *CreateSimulatorRuntime();
void DestroySimulatorRuntime(SimulatorRuntime *srt);
// VFP rounding modes. See ARM DDI 0406B Page A2-29.
enum VFPRoundingMode {
SimRN = 0 << 22, // Round to Nearest.
SimRP = 1 << 22, // Round towards Plus Infinity.
SimRM = 2 << 22, // Round towards Minus Infinity.
SimRZ = 3 << 22, // Round towards zero.
// Aliases.
kRoundToNearest = SimRN,
kRoundToPlusInf = SimRP,
kRoundToMinusInf = SimRM,
kRoundToZero = SimRZ
};
const uint32_t kVFPRoundingModeMask = 3 << 22;
typedef int32_t Instr;
class SimInstruction;
class Simulator
{
friend class Redirection;
public:
friend class ArmDebugger;
enum Register {
no_reg = -1,
r0 = 0, r1, r2, r3, r4, r5, r6, r7,
r8, r9, r10, r11, r12, r13, r14, r15,
num_registers,
sp = 13,
lr = 14,
pc = 15,
s0 = 0, s1, s2, s3, s4, s5, s6, s7,
s8, s9, s10, s11, s12, s13, s14, s15,
s16, s17, s18, s19, s20, s21, s22, s23,
s24, s25, s26, s27, s28, s29, s30, s31,
num_s_registers = 32,
d0 = 0, d1, d2, d3, d4, d5, d6, d7,
d8, d9, d10, d11, d12, d13, d14, d15,
d16, d17, d18, d19, d20, d21, d22, d23,
d24, d25, d26, d27, d28, d29, d30, d31,
num_d_registers = 32,
q0 = 0, q1, q2, q3, q4, q5, q6, q7,
q8, q9, q10, q11, q12, q13, q14, q15,
num_q_registers = 16
};
explicit Simulator(SimulatorRuntime *srt);
~Simulator();
// The currently executing Simulator instance. Potentially there can be one
// for each native thread.
static Simulator *Current();
static inline uintptr_t StackLimit() {
return Simulator::Current()->stackLimit();
}
// Accessors for register state. Reading the pc value adheres to the ARM
// architecture specification and is off by a 8 from the currently executing
// instruction.
void set_register(int reg, int32_t value);
int32_t get_register(int reg) const;
double get_double_from_register_pair(int reg);
void set_register_pair_from_double(int reg, double* value);
void set_dw_register(int dreg, const int* dbl);
// Support for VFP.
void get_d_register(int dreg, uint64_t* value);
void set_d_register(int dreg, const uint64_t* value);
void get_d_register(int dreg, uint32_t* value);
void set_d_register(int dreg, const uint32_t* value);
void get_q_register(int qreg, uint64_t* value);
void set_q_register(int qreg, const uint64_t* value);
void get_q_register(int qreg, uint32_t* value);
void set_q_register(int qreg, const uint32_t* value);
void set_s_register(int reg, unsigned int value);
unsigned int get_s_register(int reg) const;
void set_d_register_from_double(int dreg, const double& dbl) {
setVFPRegister<double, 2>(dreg, dbl);
}
double get_double_from_d_register(int dreg) {
return getFromVFPRegister<double, 2>(dreg);
}
void set_s_register_from_float(int sreg, const float flt) {
setVFPRegister<float, 1>(sreg, flt);
}
float get_float_from_s_register(int sreg) {
return getFromVFPRegister<float, 1>(sreg);
}
void set_s_register_from_sinteger(int sreg, const int sint) {
setVFPRegister<int, 1>(sreg, sint);
}
int get_sinteger_from_s_register(int sreg) {
return getFromVFPRegister<int, 1>(sreg);
}
// Special case of set_register and get_register to access the raw PC value.
void set_pc(int32_t value);
int32_t get_pc() const;
void set_resume_pc(int32_t value) {
resume_pc_ = value;
}
uintptr_t stackLimit() const;
bool overRecursed(uintptr_t newsp = 0) const;
bool overRecursedWithExtra(uint32_t extra) const;
// Executes ARM instructions until the PC reaches end_sim_pc.
void execute();
// Sets up the simulator state and grabs the result on return.
int64_t call(uint8_t* entry, int argument_count, ...);
// Debugger input.
void setLastDebuggerInput(char *input);
char *lastDebuggerInput() { return lastDebuggerInput_; }
// Returns true if pc register contains one of the 'special_values' defined
// below (bad_lr, end_sim_pc).
bool has_bad_pc() const;
// EABI variant for double arguments in use.
bool use_eabi_hardfloat() {
#if USE_EABI_HARDFLOAT
return true;
#else
return false;
#endif
}
private:
enum special_values {
// Known bad pc value to ensure that the simulator does not execute
// without being properly setup.
bad_lr = -1,
// A pc value used to signal the simulator to stop execution. Generally
// the lr is set to this value on transition from native C code to
// simulated execution, so that the simulator can "return" to the native
// C code.
end_sim_pc = -2
};
// Checks if the current instruction should be executed based on its
// condition bits.
inline bool conditionallyExecute(SimInstruction* instr);
// Helper functions to set the conditional flags in the architecture state.
void setNZFlags(int32_t val);
void setCFlag(bool val);
void setVFlag(bool val);
bool carryFrom(int32_t left, int32_t right, int32_t carry = 0);
bool borrowFrom(int32_t left, int32_t right);
bool overflowFrom(int32_t alu_out, int32_t left, int32_t right, bool addition);
inline int getCarry() { return c_flag_ ? 1 : 0; };
// Support for VFP.
void compute_FPSCR_Flags(double val1, double val2);
void copy_FPSCR_to_APSR();
inline double canonicalizeNaN(double value);
// Helper functions to decode common "addressing" modes
int32_t getShiftRm(SimInstruction *instr, bool* carry_out);
int32_t getImm(SimInstruction *instr, bool* carry_out);
int32_t processPU(SimInstruction *instr, int num_regs, int operand_size,
intptr_t *start_address, intptr_t *end_address);
void handleRList(SimInstruction *instr, bool load);
void handleVList(SimInstruction *inst);
void softwareInterrupt(SimInstruction *instr);
// Stop helper functions.
inline bool isStopInstruction(SimInstruction *instr);
inline bool isWatchedStop(uint32_t bkpt_code);
inline bool isEnabledStop(uint32_t bkpt_code);
inline void enableStop(uint32_t bkpt_code);
inline void disableStop(uint32_t bkpt_code);
inline void increaseStopCounter(uint32_t bkpt_code);
void printStopInfo(uint32_t code);
// Read and write memory.
inline uint8_t readBU(int32_t addr);
inline int8_t readB(int32_t addr);
inline void writeB(int32_t addr, uint8_t value);
inline void writeB(int32_t addr, int8_t value);
inline uint16_t readHU(int32_t addr, SimInstruction *instr);
inline int16_t readH(int32_t addr, SimInstruction *instr);
// Note: Overloaded on the sign of the value.
inline void writeH(int32_t addr, uint16_t value, SimInstruction *instr);
inline void writeH(int32_t addr, int16_t value, SimInstruction *instr);
inline int readW(int32_t addr, SimInstruction *instr);
inline void writeW(int32_t addr, int value, SimInstruction *instr);
int32_t *readDW(int32_t addr);
void writeDW(int32_t addr, int32_t value1, int32_t value2);
// Executing is handled based on the instruction type.
// Both type 0 and type 1 rolled into one.
void decodeType01(SimInstruction *instr);
void decodeType2(SimInstruction *instr);
void decodeType3(SimInstruction *instr);
void decodeType4(SimInstruction *instr);
void decodeType5(SimInstruction *instr);
void decodeType6(SimInstruction *instr);
void decodeType7(SimInstruction *instr);
// Support for VFP.
void decodeTypeVFP(SimInstruction *instr);
void decodeType6CoprocessorIns(SimInstruction *instr);
void decodeSpecialCondition(SimInstruction *instr);
void decodeVMOVBetweenCoreAndSinglePrecisionRegisters(SimInstruction *instr);
void decodeVCMP(SimInstruction *instr);
void decodeVCVTBetweenDoubleAndSingle(SimInstruction *instr);
void decodeVCVTBetweenFloatingPointAndInteger(SimInstruction *instr);
// Executes one instruction.
void instructionDecode(SimInstruction *instr);
public:
static bool ICacheCheckingEnabled;
static void FlushICache(void *start, size_t size);
// Runtime call support.
static void *RedirectNativeFunction(void *nativeFunction, ABIFunctionType type);
private:
// Handle arguments and return value for runtime FP functions.
void getFpArgs(double *x, double *y, int32_t *z);
void setCallResultDouble(double result);
void setCallResultFloat(float result);
void setCallResult(int64_t res);
template<class ReturnType, int register_size>
ReturnType getFromVFPRegister(int reg_index);
template<class InputType, int register_size>
void setVFPRegister(int reg_index, const InputType& value);
void callInternal(uint8_t* entry);
// Architecture state.
// Saturating instructions require a Q flag to indicate saturation.
// There is currently no way to read the CPSR directly, and thus read the Q
// flag, so this is left unimplemented.
int32_t registers_[16];
bool n_flag_;
bool z_flag_;
bool c_flag_;
bool v_flag_;
// VFP architecture state.
uint32_t vfp_registers_[num_d_registers * 2];
bool n_flag_FPSCR_;
bool z_flag_FPSCR_;
bool c_flag_FPSCR_;
bool v_flag_FPSCR_;
// VFP rounding mode. See ARM DDI 0406B Page A2-29.
VFPRoundingMode FPSCR_rounding_mode_;
bool FPSCR_default_NaN_mode_;
// VFP FP exception flags architecture state.
bool inv_op_vfp_flag_;
bool div_zero_vfp_flag_;
bool overflow_vfp_flag_;
bool underflow_vfp_flag_;
bool inexact_vfp_flag_;
// Simulator support.
char *stack_;
bool pc_modified_;
int icount_;
int32_t resume_pc_;
// Debugger input.
char *lastDebuggerInput_;
// Registered breakpoints.
SimInstruction *break_pc_;
Instr break_instr_;
SimulatorRuntime *srt_;
// A stop is watched if its code is less than kNumOfWatchedStops.
// Only watched stops support enabling/disabling and the counter feature.
static const uint32_t kNumOfWatchedStops = 256;
// Breakpoint is disabled if bit 31 is set.
static const uint32_t kStopDisabledBit = 1 << 31;
// A stop is enabled, meaning the simulator will stop when meeting the
// instruction, if bit 31 of watched_stops_[code].count is unset.
// The value watched_stops_[code].count & ~(1 << 31) indicates how many times
// the breakpoint was hit or gone through.
struct StopCountAndDesc {
uint32_t count;
char *desc;
};
StopCountAndDesc watched_stops_[kNumOfWatchedStops];
};
#define JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, extra, onerror) \
JS_BEGIN_MACRO \
if (cx->mainThread().simulator()->overRecursedWithExtra(extra)) { \
js_ReportOverRecursed(cx); \
onerror; \
} \
JS_END_MACRO
} // namespace jit
} // namespace js
#endif /* JS_ARM_SIMULATOR */
#endif /* jit_arm_Simulator_arm_h */

View File

@ -235,7 +235,7 @@ static int getId() {
return NULL_ID;
}
#endif
static void spewEntry(uint8_t *ptr, int length) {
static inline void spewEntry(uint8_t *ptr, int length) {
#if IS_LITTLE_ENDIAN
for (int idx = 0; idx < length; idx++) {
IonSpewCont(IonSpew_Pools, "%02x", ptr[length - idx - 1]);

View File

@ -36,6 +36,14 @@ class Registers {
return Names[code];
}
static Code FromName(const char *name) {
for (size_t i = 0; i < Total; i++) {
if (strcmp(GetName(Code(i)), name) == 0)
return Code(i);
}
return Invalid;
}
static const Code StackPointer = JSC::X86Registers::esp;
static const Code Invalid = JSC::X86Registers::invalid_reg;
@ -116,6 +124,14 @@ class FloatRegisters {
return Names[code];
}
static Code FromName(const char *name) {
for (size_t i = 0; i < Total; i++) {
if (strcmp(GetName(Code(i)), name) == 0)
return Code(i);
}
return Invalid;
}
static const Code Invalid = JSC::X86Registers::invalid_xmm;
static const uint32_t Total = 16;

View File

@ -43,6 +43,14 @@ class Registers {
return Names[code];
}
static Code FromName(const char *name) {
for (size_t i = 0; i < Total; i++) {
if (strcmp(GetName(Code(i)), name) == 0)
return Code(i);
}
return Invalid;
}
static const Code StackPointer = JSC::X86Registers::esp;
static const Code Invalid = JSC::X86Registers::invalid_reg;
@ -105,6 +113,14 @@ class FloatRegisters {
return Names[code];
}
static Code FromName(const char *name) {
for (size_t i = 0; i < Total; i++) {
if (strcmp(GetName(Code(i)), name) == 0)
return Code(i);
}
return Invalid;
}
static const Code Invalid = JSC::X86Registers::invalid_xmm;
static const uint32_t Total = 8;

View File

@ -62,6 +62,7 @@
#include "frontend/Parser.h" // for JS_BufferIsCompileableUnit
#include "gc/Marking.h"
#include "jit/AsmJSLink.h"
#include "jit/JitCommon.h"
#include "js/CharacterEncoding.h"
#include "js/SliceBudget.h"
#include "js/StructuredClone.h"
@ -2179,8 +2180,12 @@ js::RecomputeStackLimit(JSRuntime *rt, StackKind kind)
#ifdef JS_ION
if (kind == StackForUntrustedScript) {
JSRuntime::AutoLockForOperationCallback lock(rt);
if (rt->mainThread.ionStackLimit != uintptr_t(-1))
if (rt->mainThread.ionStackLimit != uintptr_t(-1)) {
rt->mainThread.ionStackLimit = rt->mainThread.nativeStackLimit[kind];
#ifdef JS_ARM_SIMULATOR
rt->mainThread.ionStackLimit = jit::Simulator::StackLimit();
#endif
}
}
#endif
}

View File

@ -1291,6 +1291,15 @@ JSContext::mark(JSTracer *trc)
MarkValueRoot(trc, &iterValue, "iterValue");
}
void *
ThreadSafeContext::stackLimitAddressForJitCode(StackKind kind)
{
#ifdef JS_ARM_SIMULATOR
return runtime_->mainThread.addressOfSimulatorStackLimit();
#endif
return stackLimitAddress(kind);
}
JSVersion
JSContext::findVersion() const
{

View File

@ -287,6 +287,7 @@ struct ThreadSafeContext : ContextFriendFields,
size_t workerThreadCount() { return runtime_->workerThreadCount(); }
void *runtimeAddressForJit() { return runtime_; }
void *stackLimitAddress(StackKind kind) { return &runtime_->mainThread.nativeStackLimit[kind]; }
void *stackLimitAddressForJitCode(StackKind kind);
size_t gcSystemPageSize() { return runtime_->gcSystemPageSize; }
bool signalHandlersInstalled() const { return runtime_->signalHandlersInstalled(); }
bool jitSupportsFloatingPoint() const { return runtime_->jitSupportsFloatingPoint; }

View File

@ -1300,8 +1300,8 @@ class ParallelIonInvoke
bool invoke(PerThreadData *perThread) {
RootedValue result(perThread);
enter_(jitcode_, argc_ + 1, argv_ + 1, nullptr, calleeToken_, nullptr, 0,
result.address());
CALL_GENERATED_CODE(enter_, jitcode_, argc_ + 1, argv_ + 1, nullptr, calleeToken_,
nullptr, 0, result.address());
return !result.isMagic();
}
};
@ -1443,6 +1443,10 @@ ForkJoinShared::executeFromWorker(uint16_t sliceId, uint32_t workerId, uintptr_t
}
TlsPerThreadData.set(&thisThread);
#ifdef JS_ARM_SIMULATOR
stackLimit = Simulator::StackLimit();
#endif
// Don't use setIonStackLimit() because that acquires the ionStackLimitLock, and the
// lock has not been initialized in these cases.
thisThread.ionStackLimit = stackLimit;

View File

@ -32,6 +32,7 @@
#if defined(JS_ION)
# include "assembler/assembler/MacroAssembler.h"
#endif
#include "jit/arm/Simulator-arm.h"
#include "jit/AsmJSSignalHandlers.h"
#include "jit/JitCompartment.h"
#include "jit/PcScriptCache.h"
@ -73,6 +74,10 @@ PerThreadData::PerThreadData(JSRuntime *runtime)
ionStackLimit(0),
activation_(nullptr),
asmJSActivationStack_(nullptr),
#ifdef JS_ARM_SIMULATOR
simulator_(nullptr),
simulatorStackLimit_(0),
#endif
dtoaState(nullptr),
suppressGC(0),
#ifdef DEBUG
@ -88,6 +93,10 @@ PerThreadData::~PerThreadData()
if (isInList())
removeFromThreadList();
#ifdef JS_ARM_SIMULATOR
js_delete(simulator_);
#endif
}
bool
@ -255,6 +264,9 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
gcFinalizeCallback(nullptr),
gcMallocBytes(0),
gcMallocGCTriggered(false),
#ifdef JS_ARM_SIMULATOR
simulatorRuntime_(nullptr),
#endif
scriptAndCountsVector(nullptr),
NaNValue(DoubleNaNValue()),
negativeInfinityValue(DoubleValue(NegativeInfinity())),
@ -428,6 +440,12 @@ JSRuntime::init(uint32_t maxbytes)
if (!evalCache.init())
return false;
#ifdef JS_ARM_SIMULATOR
simulatorRuntime_ = js::jit::CreateSimulatorRuntime();
if (!simulatorRuntime_)
return false;
#endif
nativeStackBase = GetNativeStackBase();
jitSupportsFloatingPoint = JitSupportsFloatingPoint();
@ -558,6 +576,10 @@ JSRuntime::~JSRuntime()
gcNursery.disable();
#endif
#ifdef JS_ARM_SIMULATOR
js::jit::DestroySimulatorRuntime(simulatorRuntime_);
#endif
DebugOnly<size_t> oldCount = liveRuntimesCount--;
JS_ASSERT(oldCount > 0);
@ -581,6 +603,17 @@ NewObjectCache::clearNurseryObjects(JSRuntime *rt)
}
}
void
JSRuntime::resetIonStackLimit()
{
AutoLockForOperationCallback lock(this);
mainThread.setIonStackLimit(mainThread.nativeStackLimit[js::StackForUntrustedScript]);
#ifdef JS_ARM_SIMULATOR
mainThread.setIonStackLimit(js::jit::Simulator::StackLimit());
#endif
}
void
JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes *rtSizes)
{

View File

@ -89,6 +89,8 @@ namespace jit {
class JitRuntime;
class JitActivation;
struct PcScriptCache;
class Simulator;
class SimulatorRuntime;
}
/*
@ -546,6 +548,11 @@ class PerThreadData : public PerThreadDataFriendFields,
/* See AsmJSActivation comment. Protected by rt->operationCallbackLock. */
js::AsmJSActivation *asmJSActivationStack_;
#ifdef JS_ARM_SIMULATOR
js::jit::Simulator *simulator_;
uintptr_t simulatorStackLimit_;
#endif
public:
js::Activation *const *addressOfActivation() const {
return &activation_;
@ -600,6 +607,13 @@ class PerThreadData : public PerThreadDataFriendFields,
inline bool exclusiveThreadsPresent();
inline void addActiveCompilation();
inline void removeActiveCompilation();
#ifdef JS_ARM_SIMULATOR
js::jit::Simulator *simulator() const;
void setSimulator(js::jit::Simulator *sim);
js::jit::SimulatorRuntime *simulatorRuntime() const;
uintptr_t *addressOfSimulatorStackLimit();
#endif
};
template<class Client>
@ -1336,6 +1350,10 @@ struct JSRuntime : public JS::shadow::Runtime,
*/
mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> gcMallocGCTriggered;
#ifdef JS_ARM_SIMULATOR
js::jit::SimulatorRuntime *simulatorRuntime_;
#endif
public:
void setNeedsBarrier(bool needs) {
needsBarrier_ = needs;
@ -1353,6 +1371,11 @@ struct JSRuntime : public JS::shadow::Runtime,
{}
};
#ifdef JS_ARM_SIMULATOR
js::jit::SimulatorRuntime *simulatorRuntime() const;
void setSimulatorRuntime(js::jit::SimulatorRuntime *srt);
#endif
/*
* The trace operations to trace embedding-specific GC roots. One is for
* tracing through black roots and the other is for tracing through gray
@ -1651,10 +1674,7 @@ struct JSRuntime : public JS::shadow::Runtime,
// Used to reset stack limit after a signaled interrupt (i.e. ionStackLimit_ = -1)
// has been noticed by Ion/Baseline.
void resetIonStackLimit() {
AutoLockForOperationCallback lock(this);
mainThread.setIonStackLimit(mainThread.nativeStackLimit[js::StackForUntrustedScript]);
}
void resetIonStackLimit();
// Cache for jit::GetPcScript().
js::jit::PcScriptCache *ionPcScriptCache;

View File

@ -47,6 +47,8 @@
#include "TraceLogging.h"
#endif
#include "jit/JitCommon.h"
namespace JSC {
class JSGlobalData;
@ -131,7 +133,7 @@ public:
#endif
YarrJITCode16 fn = JS_FUNC_TO_DATA_PTR(YarrJITCode16, m_ref16.code().executableAddress());
return MatchResult(fn(input, start, length, output));
return MatchResult(CALL_GENERATED_YARR_CODE4(fn, input, start, length, output));
}
MatchResult execute(const UChar* input, unsigned start, unsigned length)
@ -145,7 +147,7 @@ public:
#endif
YarrJITCodeMatchOnly16 fn = JS_FUNC_TO_DATA_PTR(YarrJITCodeMatchOnly16, m_matchOnly16.code().executableAddress());
return MatchResult(fn(input, start, length));
return MatchResult(CALL_GENERATED_YARR_CODE3(fn, input, start, length));
}
#if ENABLE_REGEXP_TRACING