Auto merge of #125829 - petrochenkov:upctxt2, r= · rust-lang/rust@225796f (original) (raw)

`@@ -4,10 +4,10 @@ use crate::SPAN_TRACK;

`

4

4

`use crate::{BytePos, SpanData};

`

5

5

``

6

6

`use rustc_data_structures::fx::FxIndexSet;

`

7

``

-

8

7

`// This code is very hot and uses lots of arithmetic, avoid overflow checks for performance.

`

9

8

`// See https://github.com/rust-lang/rust/pull/119440#issuecomment-1874255727

`

10

9

`use rustc_serialize::int_overflow::DebugStrictAdd;

`

``

10

`+

use std::mem::transmute;

`

11

11

``

12

12

`/// A compressed span.

`

13

13

`///

`

`@@ -87,6 +87,115 @@ pub struct Span {

`

87

87

`ctxt_or_parent_or_marker: u16,

`

88

88

`}

`

89

89

``

``

90

`+

// Convenience structures for all span formats.

`

``

91

`+

#[derive(Clone, Copy)]

`

``

92

`+

struct InlineCtxt {

`

``

93

`+

lo: u32,

`

``

94

`+

len: u16,

`

``

95

`+

ctxt: u16,

`

``

96

`+

}

`

``

97

+

``

98

`+

#[derive(Clone, Copy)]

`

``

99

`+

struct InlineParent {

`

``

100

`+

lo: u32,

`

``

101

`+

len_with_tag: u16,

`

``

102

`+

parent: u16,

`

``

103

`+

}

`

``

104

+

``

105

`+

#[derive(Clone, Copy)]

`

``

106

`+

struct PartiallyInterned {

`

``

107

`+

index: u32,

`

``

108

`+

_marker1: u16,

`

``

109

`+

ctxt: u16,

`

``

110

`+

}

`

``

111

+

``

112

`+

#[derive(Clone, Copy)]

`

``

113

`+

struct Interned {

`

``

114

`+

index: u32,

`

``

115

`+

_marker1: u16,

`

``

116

`+

_marker2: u16,

`

``

117

`+

}

`

``

118

+

``

119

`+

enum Fmt<'a> {

`

``

120

`+

InlineCtxt(&'a mut InlineCtxt),

`

``

121

`+

InlineParent(&'a mut InlineParent),

`

``

122

`+

PartiallyInterned(&'a mut PartiallyInterned),

`

``

123

`+

Interned(&'a mut Interned),

`

``

124

`+

}

`

``

125

+

``

126

`+

impl InlineCtxt {

`

``

127

`+

#[inline]

`

``

128

`+

fn data(self) -> SpanData {

`

``

129

`+

let len = self.len as u32;

`

``

130

`+

debug_assert!(len <= MAX_LEN);

`

``

131

`+

SpanData {

`

``

132

`+

lo: BytePos(self.lo),

`

``

133

`+

hi: BytePos(self.lo.debug_strict_add(len)),

`

``

134

`+

ctxt: SyntaxContext::from_u32(self.ctxt as u32),

`

``

135

`+

parent: None,

`

``

136

`+

}

`

``

137

`+

}

`

``

138

`+

#[inline]

`

``

139

`+

fn to_span(self) -> Span {

`

``

140

`+

unsafe { transmute(self) }

`

``

141

`+

}

`

``

142

`+

}

`

``

143

+

``

144

`+

impl InlineParent {

`

``

145

`+

#[inline]

`

``

146

`+

fn data(self) -> SpanData {

`

``

147

`+

let len = (self.len_with_tag & !PARENT_TAG) as u32;

`

``

148

`+

debug_assert!(len <= MAX_LEN);

`

``

149

`+

SpanData {

`

``

150

`+

lo: BytePos(self.lo),

`

``

151

`+

hi: BytePos(self.lo.debug_strict_add(len)),

`

``

152

`+

ctxt: SyntaxContext::root(),

`

``

153

`+

parent: Some(LocalDefId { local_def_index: DefIndex::from_u32(self.parent as u32) }),

`

``

154

`+

}

`

``

155

`+

}

`

``

156

`+

#[inline]

`

``

157

`+

fn to_span(self) -> Span {

`

``

158

`+

unsafe { transmute(self) }

`

``

159

`+

}

`

``

160

`+

}

`

``

161

+

``

162

`+

impl PartiallyInterned {

`

``

163

`+

#[inline]

`

``

164

`+

fn data(self) -> SpanData {

`

``

165

`+

SpanData {

`

``

166

`+

ctxt: SyntaxContext::from_u32(self.ctxt as u32),

`

``

167

`+

..with_span_interner(|interner| interner.spans[self.index as usize])

`

``

168

`+

}

`

``

169

`+

}

`

``

170

`+

#[inline]

`

``

171

`+

fn to_span(self) -> Span {

`

``

172

`+

unsafe { transmute(self) }

`

``

173

`+

}

`

``

174

`+

}

`

``

175

+

``

176

`+

impl Interned {

`

``

177

`+

#[inline]

`

``

178

`+

fn data(self) -> SpanData {

`

``

179

`+

with_span_interner(|interner| interner.spans[self.index as usize])

`

``

180

`+

}

`

``

181

`+

#[inline]

`

``

182

`+

fn to_span(self) -> Span {

`

``

183

`+

unsafe { transmute(self) }

`

``

184

`+

}

`

``

185

`+

}

`

``

186

+

``

187

`+

impl Fmt<'_> {

`

``

188

`+

#[inline]

`

``

189

`+

fn data(self) -> SpanData {

`

``

190

`+

match self {

`

``

191

`+

Fmt::InlineCtxt(span) => span.data(),

`

``

192

`+

Fmt::InlineParent(span) => span.data(),

`

``

193

`+

Fmt::PartiallyInterned(span) => span.data(),

`

``

194

`+

Fmt::Interned(span) => span.data(),

`

``

195

`+

}

`

``

196

`+

}

`

``

197

`+

}

`

``

198

+

90

199

`` // MAX_LEN is chosen so that PARENT_TAG | MAX_LEN is distinct from

``

91

200

`` // BASE_LEN_INTERNED_MARKER. (If MAX_LEN was 1 higher, this wouldn't be true.)

``

92

201

`const MAX_LEN: u32 = 0b0111_1111_1111_1110;

`

`@@ -111,42 +220,48 @@ impl Span {

`

111

220

` std::mem::swap(&mut lo, &mut hi);

`

112

221

`}

`

113

222

``

114

``

`-

let (lo2, len, ctxt2) = (lo.0, hi.0 - lo.0, ctxt.as_u32());

`

115

``

-

``

223

`+

// Small len may enable one of fully inline formats (or may not).

`

``

224

`+

let (len, ctxt32) = (hi.0 - lo.0, ctxt.as_u32());

`

116

225

`if len <= MAX_LEN {

`

117

``

`-

if ctxt2 <= MAX_CTXT && parent.is_none() {

`

118

``

`-

// Inline-context format.

`

119

``

`-

return Span {

`

120

``

`-

lo_or_index: lo2,

`

121

``

`-

len_with_tag_or_marker: len as u16,

`

122

``

`-

ctxt_or_parent_or_marker: ctxt2 as u16,

`

123

``

`-

};

`

124

``

`-

} else if ctxt2 == SyntaxContext::root().as_u32()

`

``

226

`+

if ctxt32 <= MAX_CTXT && parent.is_none() {

`

``

227

`+

return InlineCtxt { lo: lo.0, len: len as u16, ctxt: ctxt32 as u16 }.to_span();

`

``

228

`+

} else if ctxt32 == 0

`

125

229

` && let Some(parent) = parent

`

126

``

`-

&& let parent2 = parent.local_def_index.as_u32()

`

127

``

`-

&& parent2 <= MAX_CTXT

`

``

230

`+

&& let parent32 = parent.local_def_index.as_u32()

`

``

231

`+

&& parent32 <= MAX_CTXT

`

128

232

`{

`

129

``

`-

// Inline-parent format.

`

130

``

`-

return Span {

`

131

``

`-

lo_or_index: lo2,

`

132

``

`-

len_with_tag_or_marker: PARENT_TAG | len as u16,

`

133

``

`-

ctxt_or_parent_or_marker: parent2 as u16,

`

134

``

`-

};

`

``

233

`+

let len_with_tag = PARENT_TAG | len as u16;

`

``

234

`+

return InlineParent { lo: lo.0, len_with_tag, parent: parent32 as u16 }.to_span();

`

135

235

`}

`

136

236

`}

`

137

237

``

138

``

`-

// Partially-interned or fully-interned format.

`

139

``

`-

let index =

`

140

``

`-

with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent }));

`

141

``

`-

let ctxt_or_parent_or_marker = if ctxt2 <= MAX_CTXT {

`

142

``

`-

ctxt2 as u16 // partially-interned

`

143

``

`-

} else {

`

144

``

`-

CTXT_INTERNED_MARKER // fully-interned

`

``

238

`+

// Otherwise small ctxt may enable the partially inline format.

`

``

239

`+

let index = |ctxt| {

`

``

240

`+

with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent }))

`

145

241

`};

`

146

``

`-

Span {

`

147

``

`-

lo_or_index: index,

`

148

``

`-

len_with_tag_or_marker: BASE_LEN_INTERNED_MARKER,

`

149

``

`-

ctxt_or_parent_or_marker,

`

``

242

`+

if ctxt32 <= MAX_CTXT {

`

``

243

`+

let index = index(SyntaxContext::from_u32(u32::MAX)); // any value, should never be read

`

``

244

`+

PartiallyInterned { index, _marker1: BASE_LEN_INTERNED_MARKER, ctxt: ctxt32 as u16 }

`

``

245

`+

.to_span()

`

``

246

`+

} else {

`

``

247

`+

let index = index(ctxt);

`

``

248

`+

Interned { index, _marker1: BASE_LEN_INTERNED_MARKER, _marker2: CTXT_INTERNED_MARKER }

`

``

249

`+

.to_span()

`

``

250

`+

}

`

``

251

`+

}

`

``

252

+

``

253

`+

#[inline]

`

``

254

`+

fn fmt(&mut self) -> Fmt<'_> {

`

``

255

`+

if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {

`

``

256

`+

if self.len_with_tag_or_marker & PARENT_TAG == 0 {

`

``

257

`+

Fmt::InlineCtxt(unsafe { transmute(self) })

`

``

258

`+

} else {

`

``

259

`+

Fmt::InlineParent(unsafe { transmute(self) })

`

``

260

`+

}

`

``

261

`+

} else if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER {

`

``

262

`+

Fmt::PartiallyInterned(unsafe { transmute(self) })

`

``

263

`+

} else {

`

``

264

`+

Fmt::Interned(unsafe { transmute(self) })

`

150

265

`}

`

151

266

`}

`

152

267

``

`@@ -162,39 +277,8 @@ impl Span {

`

162

277

`/// Internal function to translate between an encoded span and the expanded representation.

`

163

278

`/// This function must not be used outside the incremental engine.

`

164

279

`#[inline]

`

165

``

`-

pub fn data_untracked(self) -> SpanData {

`

166

``

`-

if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {

`

167

``

`-

if self.len_with_tag_or_marker & PARENT_TAG == 0 {

`

168

``

`-

// Inline-context format.

`

169

``

`-

let len = self.len_with_tag_or_marker as u32;

`

170

``

`-

debug_assert!(len <= MAX_LEN);

`

171

``

`-

SpanData {

`

172

``

`-

lo: BytePos(self.lo_or_index),

`

173

``

`-

hi: BytePos(self.lo_or_index.debug_strict_add(len)),

`

174

``

`-

ctxt: SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32),

`

175

``

`-

parent: None,

`

176

``

`-

}

`

177

``

`-

} else {

`

178

``

`-

// Inline-parent format.

`

179

``

`-

let len = (self.len_with_tag_or_marker & !PARENT_TAG) as u32;

`

180

``

`-

debug_assert!(len <= MAX_LEN);

`

181

``

`-

let parent = LocalDefId {

`

182

``

`-

local_def_index: DefIndex::from_u32(self.ctxt_or_parent_or_marker as u32),

`

183

``

`-

};

`

184

``

`-

SpanData {

`

185

``

`-

lo: BytePos(self.lo_or_index),

`

186

``

`-

hi: BytePos(self.lo_or_index.debug_strict_add(len)),

`

187

``

`-

ctxt: SyntaxContext::root(),

`

188

``

`-

parent: Some(parent),

`

189

``

`-

}

`

190

``

`-

}

`

191

``

`-

} else {

`

192

``

`-

// Fully-interned or partially-interned format. In either case,

`

193

``

`-

// the interned value contains all the data, so we don't need to

`

194

``

`-

// distinguish them.

`

195

``

`-

let index = self.lo_or_index;

`

196

``

`-

with_span_interner(|interner| interner.spans[index as usize])

`

197

``

`-

}

`

``

280

`+

pub fn data_untracked(mut self) -> SpanData {

`

``

281

`+

self.fmt().data()

`

198

282

`}

`

199

283

``

200

284

`` /// Returns true if this is a dummy span with any hygienic context.

``

`@@ -214,26 +298,28 @@ impl Span {

`

214

298

`}

`

215

299

`}

`

216

300

``

``

301

`+

// For optimization we are interested in cases in which the context is inline and the context

`

``

302

`+

// update doesn't change format. All non-inline or format changing scenarios require accessing

`

``

303

`` +

// interner and can fall back to Span::new.

``

``

304

`+

#[inline]

`

``

305

`+

pub fn update_ctxt(&mut self, update: impl FnOnce(SyntaxContext) -> SyntaxContext) {

`

``

306

`+

// FIXME(#125017): Update ctxt inline without touching interner when possible.

`

``

307

`+

let data = self.data();

`

``

308

`+

*self = data.with_ctxt(update(data.ctxt));

`

``

309

`+

}

`

``

310

+

217

311

`// Returns either syntactic context, if it can be retrieved without taking the interner lock,

`

218

312

`// or an index into the interner if it cannot.

`

219

``

`-

fn inline_ctxt(self) -> Result<SyntaxContext, usize> {

`

220

``

`-

Ok(if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {

`

221

``

`-

if self.len_with_tag_or_marker & PARENT_TAG == 0 {

`

222

``

`-

// Inline-context format.

`

223

``

`-

SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)

`

224

``

`-

} else {

`

225

``

`-

// Inline-parent format. We know that the SyntaxContext is root.

`

226

``

`-

SyntaxContext::root()

`

``

313

`+

#[inline]

`

``

314

`+

fn inline_ctxt(mut self) -> Result<SyntaxContext, usize> {

`

``

315

`+

match self.fmt() {

`

``

316

`+

Fmt::InlineCtxt(InlineCtxt { ctxt, .. })

`

``

317

`+

| Fmt::PartiallyInterned(PartiallyInterned { ctxt, .. }) => {

`

``

318

`+

Ok(SyntaxContext::from_u32(*ctxt as u32))

`

227

319

`}

`

228

``

`-

} else if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER {

`

229

``

`-

// Partially-interned format. This path avoids looking up the

`

230

``

`-

// interned value, and is the whole point of the

`

231

``

`-

// partially-interned format.

`

232

``

`-

SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)

`

233

``

`-

} else {

`

234

``

`-

// Fully-interned format.

`

235

``

`-

return Err(self.lo_or_index as usize);

`

236

``

`-

})

`

``

320

`+

Fmt::InlineParent(_) => Ok(SyntaxContext::root()),

`

``

321

`+

Fmt::Interned(span) => Err(span.index as usize),

`

``

322

`+

}

`

237

323

`}

`

238

324

``

239

325

`` /// This function is used as a fast path when decoding the full SpanData is not necessary.

``