author | Tom Schuster <evilpies@gmail.com> |
Wed, 15 Apr 2020 15:36:22 +0000 | |
changeset 524192 | 706e0a08e6fadb0076f8ac965a7c0a5b851b192c |
parent 524191 | 02970449a7bee151d7a2f4939369cb9bc562e4c3 |
child 524193 | 0c092e04a5a907dc7d6fce1d415215bbd5f33fe7 |
push id | 113041 |
push user | evilpies@gmail.com |
push date | Wed, 15 Apr 2020 15:59:25 +0000 |
treeherder | autoland@706e0a08e6fa [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jandem |
bugs | 1629867 |
milestone | 77.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
js/src/jit/WarpCacheIRTranspiler.cpp | file | annotate | diff | comparison | revisions | |
js/src/jit/WarpCacheIRTranspiler.h | file | annotate | diff | comparison | revisions |
--- a/js/src/jit/WarpCacheIRTranspiler.cpp +++ b/js/src/jit/WarpCacheIRTranspiler.cpp @@ -56,16 +56,18 @@ class MOZ_RAII WarpCacheIRTranspiler { return reinterpret_cast<Shape*>(readStubWord(offset)); } int32_t int32StubField(uint32_t offset) { return static_cast<int32_t>(readStubWord(offset)); } bool transpileGuardTo(MIRType type); + MInstruction* addBoundsCheck(MDefinition* index, MDefinition* length); + #define DEFINE_OP(op, ...) MOZ_MUST_USE bool transpile_##op(); WARP_CACHE_IR_OPS(DEFINE_OP) #undef DEFINE_OP public: WarpCacheIRTranspiler(MIRGenerator& mirGen, MBasicBlock* current, const WarpCacheIR* snapshot, TranspilerOutput& output) : alloc_(mirGen.alloc()), @@ -270,46 +272,87 @@ bool WarpCacheIRTranspiler::transpile_Lo auto* length = MStringLength::New(alloc(), str); current->add(length); setResult(length); return true; } +MInstruction* WarpCacheIRTranspiler::addBoundsCheck(MDefinition* index, + MDefinition* length) { + MInstruction* check = MBoundsCheck::New(alloc(), index, length); + current->add(check); + + if (JitOptions.spectreIndexMasking) { + // Use a separate MIR instruction for the index masking. Doing this as + // part of MBoundsCheck would be unsound because bounds checks can be + // optimized or eliminated completely. Consider this: + // + // for (var i = 0; i < x; i++) + // res = arr[i]; + // + // If we can prove |x < arr.length|, we are able to eliminate the bounds + // check, but we should not get rid of the index masking because the + // |i < x| branch could still be mispredicted. + // + // Using a separate instruction lets us eliminate the bounds check + // without affecting the index masking. + check = MSpectreMaskIndex::New(alloc(), check, length); + current->add(check); + } + + return check; +} + bool WarpCacheIRTranspiler::transpile_LoadDenseElementResult() { ObjOperandId objId = reader.objOperandId(); Int32OperandId indexId = reader.int32OperandId(); MDefinition* obj = getOperand(objId); MDefinition* index = getOperand(indexId); auto* elements = MElements::New(alloc(), obj); current->add(elements); auto* length = MInitializedLength::New(alloc(), elements); current->add(length); - MInstruction* check = MBoundsCheck::New(alloc(), index, length); - current->add(check); - - if (JitOptions.spectreIndexMasking) { - check = MSpectreMaskIndex::New(alloc(), check, length); - current->add(check); - } + index = addBoundsCheck(index, length); bool needsHoleCheck = true; bool loadDouble = false; // TODO: Ion-only optimization. auto* load = - MLoadElement::New(alloc(), elements, check, needsHoleCheck, loadDouble); + MLoadElement::New(alloc(), elements, index, needsHoleCheck, loadDouble); current->add(load); setResult(load); return true; } +bool WarpCacheIRTranspiler::transpile_LoadStringCharResult() { + StringOperandId strId = reader.stringOperandId(); + Int32OperandId indexId = reader.int32OperandId(); + MDefinition* str = getOperand(strId); + MDefinition* index = getOperand(indexId); + + auto* length = MStringLength::New(alloc(), str); + current->add(length); + + index = addBoundsCheck(index, length); + + auto* charCode = MCharCodeAt::New(alloc(), str, index); + current->add(charCode); + + auto* fromCharCode = MFromCharCode::New(alloc(), charCode); + current->add(fromCharCode); + + setResult(fromCharCode); + return true; +} + bool WarpCacheIRTranspiler::transpile_TypeMonitorResult() { MOZ_ASSERT(output_.result, "Didn't set result MDefinition"); return true; } bool WarpCacheIRTranspiler::transpile_ReturnFromIC() { return true; } bool jit::TranspileCacheIRToMIR(MIRGenerator& mirGen, MBasicBlock* current,
--- a/js/src/jit/WarpCacheIRTranspiler.h +++ b/js/src/jit/WarpCacheIRTranspiler.h @@ -32,16 +32,17 @@ using MDefinitionStackVector = Vector<MD _(LoadEnclosingEnvironment) \ _(LoadDynamicSlotResult) \ _(LoadFixedSlotResult) \ _(LoadEnvironmentFixedSlotResult) \ _(LoadEnvironmentDynamicSlotResult) \ _(LoadInt32ArrayLengthResult) \ _(LoadStringLengthResult) \ _(LoadDenseElementResult) \ + _(LoadStringCharResult) \ _(TypeMonitorResult) \ _(ReturnFromIC) // TranspilerOutput contains information from the transpiler that needs to be // passed back to WarpBuilder. struct MOZ_STACK_CLASS TranspilerOutput { // For ICs that return a result, this is the corresponding MIR instruction. MDefinition* result = nullptr;