[codegen][debug] generation debug info for vals.
This commit is contained in:
committed by
Vasily Levchenko
parent
b6713df52a
commit
fea734ec83
+1
-1
@@ -365,6 +365,6 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
|
||||
}
|
||||
}
|
||||
|
||||
lateinit var debugInfo:DebugInfo
|
||||
lateinit var debugInfo: DebugInfo
|
||||
}
|
||||
|
||||
|
||||
+9
-2
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
||||
|
||||
internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
|
||||
@@ -478,6 +479,12 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
private fun position() = basicBlockToLastLocation[currentBlock]
|
||||
|
||||
|
||||
internal fun mapParameterForDebug(index: Int, value: LLVMValueRef) {
|
||||
appendingTo(localsInitBb) {
|
||||
LLVMBuildStore(builder, value, vars.addressOf(index))
|
||||
}
|
||||
}
|
||||
|
||||
internal fun prologue() {
|
||||
assert(returns.isEmpty())
|
||||
if (isObjectType(returnType!!)) {
|
||||
@@ -505,7 +512,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
Int32(slotCount * codegen.runtime.pointerSize).llvm,
|
||||
Int32(codegen.runtime.pointerAlignment).llvm,
|
||||
Int1(0).llvm))
|
||||
call(context.llvm.enterFrameFunction, listOf(slots, Int32(slotCount).llvm))
|
||||
call(context.llvm.enterFrameFunction, listOf(slots, Int32(vars.skip).llvm, Int32(slotCount).llvm))
|
||||
}
|
||||
addPhiIncoming(slotsPhi!!, prologueBb to slots)
|
||||
memScoped {
|
||||
@@ -669,7 +676,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
private fun releaseVars() {
|
||||
if (needSlots) {
|
||||
call(context.llvm.leaveFrameFunction,
|
||||
listOf(slotsPhi!!, Int32(slotCount).llvm))
|
||||
listOf(slotsPhi!!, Int32(vars.skip).llvm, Int32(slotCount).llvm))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+73
-34
@@ -31,8 +31,10 @@ import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.SourceManager
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltinOperatorDescriptorBase
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl
|
||||
import org.jetbrains.kotlin.ir.util.getArguments
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
@@ -463,17 +465,30 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
/**
|
||||
* The scope of parameter visibility.
|
||||
*/
|
||||
private open inner class ParameterScope(private val functionGenerationContext: FunctionGenerationContext,
|
||||
parameters: Map<ParameterDescriptor, LLVMValueRef>): InnerScopeImpl() {
|
||||
private open inner class ParameterScope(
|
||||
function: IrFunction?,
|
||||
private val functionGenerationContext: FunctionGenerationContext): InnerScopeImpl() {
|
||||
|
||||
// Note: it is possible to generate access to a parameter without any variables,
|
||||
// however variables are named and thus the resulting bitcode can be more readable.
|
||||
val parameters = bindParameters(function?.descriptor)
|
||||
|
||||
init {
|
||||
parameters.map { (descriptor, value) ->
|
||||
functionGenerationContext.vars.createImmutable(descriptor, value)
|
||||
}
|
||||
if (function != null) {
|
||||
parameters.forEach{
|
||||
val descriptor = it.key
|
||||
val ir = when {
|
||||
descriptor is ValueParameterDescriptor -> function.getIrValueParameter(descriptor)
|
||||
descriptor is ReceiverParameterDescriptor && function.extensionReceiverParameter?.descriptor == descriptor -> function.extensionReceiverParameter!!
|
||||
descriptor is ReceiverParameterDescriptor && function.dispatchReceiverParameter?.descriptor == descriptor-> function.dispatchReceiverParameter!!
|
||||
function.descriptor is ClassConstructorDescriptor && (function.descriptor as ClassConstructorDescriptor).constructedClass.thisAsReceiverParameter == descriptor-> IrValueParameterImpl(function.startOffset, function.startOffset, object: IrDeclarationOriginImpl("THIS"){}, descriptor)
|
||||
else -> TODO()
|
||||
}
|
||||
|
||||
val local = functionGenerationContext.vars.createParameter(descriptor,
|
||||
it.value, debugInfoIfNeeded(function, ir))
|
||||
functionGenerationContext.mapParameterForDebug(local, it.value)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun genGetValue(descriptor: ValueDescriptor): LLVMValueRef {
|
||||
@@ -489,10 +504,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
/**
|
||||
* The [CodeContext] enclosing the entire function body.
|
||||
*/
|
||||
private inner class FunctionScope (val declaration: IrFunction?, val functionGenerationContext: FunctionGenerationContext) :
|
||||
ParameterScope(functionGenerationContext, bindParameters(declaration?.descriptor)) {
|
||||
private inner class FunctionScope (val declaration: IrFunction?, val functionGenerationContext: FunctionGenerationContext) : InnerScopeImpl() {
|
||||
|
||||
|
||||
constructor(llvmFunction:LLVMValueRef, functionGenerationContext: FunctionGenerationContext):this(null, functionGenerationContext) {
|
||||
this.llvmFunction = llvmFunction
|
||||
|
||||
}
|
||||
|
||||
var llvmFunction:LLVMValueRef? = declaration?.let{
|
||||
@@ -531,7 +548,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
/**
|
||||
* Binds LLVM function parameters to IR parameter descriptors.
|
||||
*/
|
||||
private fun bindParameters(descriptor: FunctionDescriptor?): Map<ParameterDescriptor, LLVMValueRef> {
|
||||
private fun bindParameters(descriptor: FunctionDescriptor?): Map<ParameterDescriptor, LLVMValueRef> {
|
||||
if (descriptor == null) return emptyMap()
|
||||
val parameterDescriptors = descriptor.allParameters
|
||||
return parameterDescriptors.mapIndexed { i, parameterDescriptor ->
|
||||
@@ -549,22 +566,27 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
if (declaration.descriptor.isExternal) return
|
||||
if (body == null) return
|
||||
|
||||
val scope = declaration.scope()
|
||||
val startLine = declaration.startLine()
|
||||
val startLocationInfo = LocationInfo(
|
||||
scope = declaration.scope(),
|
||||
line = declaration.startLine(),
|
||||
scope = scope,
|
||||
line = startLine,
|
||||
column = declaration.startColumn())
|
||||
val endLocationInfo = LocationInfo(
|
||||
scope = declaration.scope(),
|
||||
scope = scope,
|
||||
line = declaration.endLine(),
|
||||
column = declaration.endColumn())
|
||||
generateFunction(codegen, declaration.descriptor, startLocationInfo, endLocationInfo) {
|
||||
using(FunctionScope(declaration, it)) {
|
||||
using(VariableScope()) {
|
||||
when (body) {
|
||||
is IrBlockBody -> body.statements.forEach { generateStatement(it) }
|
||||
is IrExpressionBody -> generateStatement(body.expression)
|
||||
is IrSyntheticBody -> throw AssertionError("Synthetic body ${body.kind} has not been lowered")
|
||||
else -> TODO(ir2string(body))
|
||||
val parameterScope = ParameterScope(declaration, functionGenerationContext)
|
||||
using(parameterScope) {
|
||||
using(VariableScope()) {
|
||||
when (body) {
|
||||
is IrBlockBody -> body.statements.forEach { generateStatement(it) }
|
||||
is IrExpressionBody -> generateStatement(body.expression)
|
||||
is IrSyntheticBody -> throw AssertionError("Synthetic body ${body.kind} has not been lowered")
|
||||
else -> TODO(ir2string(body))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1070,25 +1092,41 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun generateVariable(value: IrVariable) {
|
||||
context.log{"generateVariable : ${ir2string(value)}"}
|
||||
val result = value.initializer?.let { evaluateExpression(it) }
|
||||
val variableDescriptor = value.descriptor
|
||||
val functionScope = (currentCodeContext.functionScope() as FunctionScope).declaration?.scope()
|
||||
val variableLocation = if (context.shouldContainDebugInfo() && functionScope != null && variableDescriptor.isVar) {
|
||||
val location = debugLocation(value)
|
||||
val file = (currentCodeContext.fileScope() as FileScope).file.file()
|
||||
val line = value.startLine()
|
||||
functionGenerationContext.vars.debugInfoLocalVariableLocation(
|
||||
private fun debugInfoIfNeeded(function: IrFunction?, element: IrElement): VariableDebugLocation? {
|
||||
if (function == null || !context.shouldContainDebugInfo()) return null
|
||||
val functionScope = function?.scope()
|
||||
if (functionScope == null || !element.needDebugInfo(context)) return null
|
||||
val location = debugLocation(element)
|
||||
val file = (currentCodeContext.fileScope() as FileScope).file.file()
|
||||
val line = element.startLine()
|
||||
return when (element) {
|
||||
is IrVariable -> debugInfoLocalVariableLocation(
|
||||
builder = context.debugInfo.builder,
|
||||
functionScope = functionScope,
|
||||
diType = variableDescriptor.type.diType(context, functionGenerationContext.llvmTargetData),
|
||||
name = variableDescriptor.name,
|
||||
diType = element.descriptor.type.diType(context, codegen.llvmTargetData),
|
||||
name = element.descriptor.name,
|
||||
file = file,
|
||||
line = line,
|
||||
location = location)
|
||||
} else null
|
||||
currentCodeContext.genDeclareVariable(variableDescriptor, result, variableLocation)
|
||||
is IrValueParameter -> debugInfoParameterLocation(
|
||||
builder = context.debugInfo.builder,
|
||||
functionScope = functionScope,
|
||||
diType = element.descriptor.type.diType(context, codegen.llvmTargetData),
|
||||
name = element.descriptor.name,
|
||||
argNo = (element.descriptor as? ValueParameterDescriptor)?.index ?: 0,
|
||||
file = file,
|
||||
line = line,
|
||||
location = location)
|
||||
else -> throw Error("Unsupported element type: ${ir2string(element)}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateVariable(variable: IrVariable) {
|
||||
context.log{"generateVariable : ${ir2string(variable)}"}
|
||||
val value = variable.initializer?.let { evaluateExpression(it) }
|
||||
currentCodeContext.genDeclareVariable(
|
||||
variable.descriptor, value, debugInfoIfNeeded(
|
||||
(currentCodeContext.functionScope() as FunctionScope)?.declaration, variable))
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
@@ -2414,3 +2452,4 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
|
||||
internal data class LocationInfo(val scope:DIScopeOpaqueRef?, val line:Int, val column:Int)
|
||||
|
||||
private fun IrFunction.hasNotReceiver() = this.extensionReceiverParameter == null && this.dispatchReceiverParameter == null
|
||||
+62
-18
@@ -17,9 +17,13 @@
|
||||
package org.jetbrains.kotlin.backend.konan.llvm
|
||||
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
internal fun IrElement.needDebugInfo(context: Context) = context.shouldContainDebugInfo() || (this is IrVariable && this.descriptor.isVar)
|
||||
|
||||
internal class VariableManager(val functionGenerationContext: FunctionGenerationContext) {
|
||||
internal interface Record {
|
||||
@@ -35,6 +39,13 @@ internal class VariableManager(val functionGenerationContext: FunctionGeneration
|
||||
override fun toString() = (if (refSlot) "refslot" else "slot") + " for ${address}"
|
||||
}
|
||||
|
||||
inner class ParameterRecord(val address: LLVMValueRef, val refSlot: Boolean) : Record {
|
||||
override fun load() : LLVMValueRef = functionGenerationContext.loadSlot(address, false)
|
||||
override fun store(value: LLVMValueRef) = throw Error("writing to parameter")
|
||||
override fun address() : LLVMValueRef = this.address
|
||||
override fun toString() = (if (refSlot) "refslot" else "slot") + " for ${address}"
|
||||
}
|
||||
|
||||
class ValueRecord(val value: LLVMValueRef, val name: Name) : Record {
|
||||
override fun load() : LLVMValueRef = value
|
||||
override fun store(value: LLVMValueRef) = throw Error("writing to immutable: ${name}")
|
||||
@@ -51,19 +62,20 @@ internal class VariableManager(val functionGenerationContext: FunctionGeneration
|
||||
contextVariablesToIndex.clear()
|
||||
}
|
||||
|
||||
fun createVariable(descriptor: VariableDescriptor, value: LLVMValueRef? = null, variableLocation: VariableDebugLocation?) : Int {
|
||||
fun createVariable(descriptor: ValueDescriptor, value: LLVMValueRef? = null, variableLocation: VariableDebugLocation?) : Int {
|
||||
val isVar = descriptor is VariableDescriptor && descriptor.isVar
|
||||
// Note that we always create slot for object references for memory management.
|
||||
if (!descriptor.isVar && value != null)
|
||||
if (!functionGenerationContext.context.shouldContainDebugInfo() && !isVar && value != null)
|
||||
return createImmutable(descriptor, value)
|
||||
else
|
||||
// Unfortunately, we have to create mutable slots here,
|
||||
// as even vals can be assigned on multiple paths. However, we use varness
|
||||
// knowledge, as anonymous slots are created only for true vars (for vals
|
||||
// their single assigner already have slot).
|
||||
return createMutable(descriptor, descriptor.isVar, value, variableLocation)
|
||||
return createMutable(descriptor, isVar, value, variableLocation)
|
||||
}
|
||||
|
||||
fun createMutable(descriptor: VariableDescriptor,
|
||||
internal fun createMutable(descriptor: ValueDescriptor,
|
||||
isVar: Boolean, value: LLVMValueRef? = null, variableLocation: VariableDebugLocation?) : Int {
|
||||
assert(!contextVariablesToIndex.contains(descriptor))
|
||||
val index = variables.size
|
||||
@@ -76,6 +88,20 @@ internal class VariableManager(val functionGenerationContext: FunctionGeneration
|
||||
return index
|
||||
}
|
||||
|
||||
internal var skip = 0
|
||||
internal fun createParameter(descriptor: ValueDescriptor, value: LLVMValueRef? = null, variableLocation: VariableDebugLocation?) : Int {
|
||||
assert(!contextVariablesToIndex.contains(descriptor))
|
||||
val index = variables.size
|
||||
val type = functionGenerationContext.getLLVMType(descriptor.type)
|
||||
val slot = functionGenerationContext.alloca(type, "p-${descriptor.name.asString()}", variableLocation)
|
||||
val isObject = functionGenerationContext.isObjectType(type)
|
||||
variables.add(ParameterRecord(slot, isObject))
|
||||
contextVariablesToIndex[descriptor] = index
|
||||
if (isObject)
|
||||
skip++
|
||||
return index
|
||||
}
|
||||
|
||||
// Creates anonymous mutable variable.
|
||||
// Think of slot reuse.
|
||||
fun createAnonymousSlot(value: LLVMValueRef? = null) : LLVMValueRef {
|
||||
@@ -92,7 +118,7 @@ internal class VariableManager(val functionGenerationContext: FunctionGeneration
|
||||
return index
|
||||
}
|
||||
|
||||
fun createImmutable(descriptor: ValueDescriptor, value: LLVMValueRef) : Int {
|
||||
internal fun createImmutable(descriptor: ValueDescriptor, value: LLVMValueRef) : Int {
|
||||
if (contextVariablesToIndex.containsKey(descriptor))
|
||||
throw Error("$descriptor is already defined")
|
||||
val index = variables.size
|
||||
@@ -116,18 +142,36 @@ internal class VariableManager(val functionGenerationContext: FunctionGeneration
|
||||
fun store(value: LLVMValueRef, index: Int) {
|
||||
variables[index].store(value)
|
||||
}
|
||||
|
||||
fun debugInfoLocalVariableLocation(functionScope: DIScopeOpaqueRef, diType: DITypeOpaqueRef, name:Name, file: DIFileRef, line: Int, location: DILocationRef?):VariableDebugLocation {
|
||||
val variableDeclaration = DICreateAutoVariable(
|
||||
builder = functionGenerationContext.context.debugInfo.builder,
|
||||
scope = functionScope,
|
||||
name = name.asString(),
|
||||
file = file,
|
||||
line = line,
|
||||
type = diType)
|
||||
|
||||
return VariableDebugLocation(localVariable = variableDeclaration!!, location = location, file = file, line = line)
|
||||
}
|
||||
}
|
||||
|
||||
internal data class VariableDebugLocation(val localVariable: DILocalVariableRef, val location:DILocationRef?, val file:DIFileRef, val line:Int)
|
||||
internal data class VariableDebugLocation(val localVariable: DILocalVariableRef, val location:DILocationRef?, val file:DIFileRef, val line:Int)
|
||||
|
||||
internal fun debugInfoLocalVariableLocation(builder: DIBuilderRef?,
|
||||
functionScope: DIScopeOpaqueRef, diType: DITypeOpaqueRef, name:Name, file: DIFileRef, line: Int,
|
||||
location: DILocationRef?): VariableDebugLocation {
|
||||
val variableDeclaration = DICreateAutoVariable(
|
||||
builder = builder,
|
||||
scope = functionScope,
|
||||
name = name.asString(),
|
||||
file = file,
|
||||
line = line,
|
||||
type = diType)
|
||||
|
||||
return VariableDebugLocation(localVariable = variableDeclaration!!, location = location, file = file, line = line)
|
||||
}
|
||||
|
||||
internal fun debugInfoParameterLocation(builder: DIBuilderRef?,
|
||||
functionScope: DIScopeOpaqueRef, diType: DITypeOpaqueRef,
|
||||
name:Name, argNo: Int, file: DIFileRef, line: Int,
|
||||
location: DILocationRef?): VariableDebugLocation {
|
||||
val variableDeclaration = DICreateParameterVariable(
|
||||
builder = builder,
|
||||
scope = functionScope,
|
||||
name = name.asString(),
|
||||
argNo = argNo,
|
||||
file = file,
|
||||
line = line,
|
||||
type = diType)
|
||||
|
||||
return VariableDebugLocation(localVariable = variableDeclaration!!, location = location, file = file, line = line)
|
||||
}
|
||||
@@ -214,6 +214,16 @@ DILocalVariableRef DICreateAutoVariable(DIBuilderRef builder, DIScopeOpaqueRef s
|
||||
llvm::unwrap(type)));
|
||||
}
|
||||
|
||||
DILocalVariableRef DICreateParameterVariable(DIBuilderRef builder, DIScopeOpaqueRef scope, const char *name, unsigned argNo, DIFileRef file, unsigned line, DITypeOpaqueRef type) {
|
||||
return llvm::wrap(llvm::unwrap(builder)->createParameterVariable(
|
||||
llvm::unwrap(scope),
|
||||
name,
|
||||
argNo,
|
||||
llvm::unwrap(file),
|
||||
line,
|
||||
llvm::unwrap(type)));
|
||||
}
|
||||
|
||||
DIExpressionRef DICreateEmptyExpression(DIBuilderRef builder) {
|
||||
return llvm::wrap(llvm::unwrap(builder)->createExpression());
|
||||
}
|
||||
|
||||
@@ -93,6 +93,7 @@ DISubroutineTypeRef DICreateSubroutineType(DIBuilderRef builder,
|
||||
unsigned typesCount);
|
||||
|
||||
DILocalVariableRef DICreateAutoVariable(DIBuilderRef builder, DIScopeOpaqueRef scope, const char *name, DIFileRef file, unsigned line, DITypeOpaqueRef type);
|
||||
DILocalVariableRef DICreateParameterVariable(DIBuilderRef builder, DIScopeOpaqueRef scope, const char *name, unsigned argNo, DIFileRef file, unsigned line, DITypeOpaqueRef type);
|
||||
void DIInsertDeclaration(DIBuilderRef builder, LLVMValueRef value, DILocalVariableRef localVariable, DILocationRef location, LLVMBasicBlockRef bb, int64_t *expr, uint64_t exprCount);
|
||||
DIExpressionRef DICreateEmptyExpression(DIBuilderRef builder);
|
||||
void DIFunctionAddSubprogram(LLVMValueRef fn, DISubprogramRef sp);
|
||||
|
||||
@@ -1080,13 +1080,13 @@ void UpdateRef(ObjHeader** location, const ObjHeader* object) {
|
||||
}
|
||||
}
|
||||
|
||||
void EnterFrame(ObjHeader** start, int count) {
|
||||
MEMORY_LOG("EnterFrame %p .. %p\n", start, start + count)
|
||||
void EnterFrame(ObjHeader** start, int parameters, int count) {
|
||||
MEMORY_LOG("EnterFrame %p .. %p\n", start, start + count + parameters)
|
||||
}
|
||||
|
||||
void LeaveFrame(ObjHeader** start, int count) {
|
||||
MEMORY_LOG("LeaveFrame %p .. %p\n", start, start + count)
|
||||
ReleaseRefs(start + kFrameOverlaySlots, count - kFrameOverlaySlots);
|
||||
void LeaveFrame(ObjHeader** start, int parameters, int count) {
|
||||
MEMORY_LOG("LeaveFrame %p .. %p\n", start, start + count + parameters)
|
||||
ReleaseRefs(start + parameters + kFrameOverlaySlots, count - kFrameOverlaySlots - parameters);
|
||||
if (*start != nullptr) {
|
||||
auto arena = initedArena(start);
|
||||
MEMORY_LOG("LeaveFrame: free arena %p\n", arena)
|
||||
|
||||
@@ -362,9 +362,9 @@ void UpdateReturnRef(ObjHeader** returnSlot, const ObjHeader* object) RUNTIME_NO
|
||||
// Optimization: release all references in range.
|
||||
void ReleaseRefs(ObjHeader** start, int count) RUNTIME_NOTHROW;
|
||||
// Called on frame enter, if it has object slots.
|
||||
void EnterFrame(ObjHeader** start, int count) RUNTIME_NOTHROW;
|
||||
void EnterFrame(ObjHeader** start, int parameters, int count) RUNTIME_NOTHROW;
|
||||
// Called on frame leave, if it has object slots.
|
||||
void LeaveFrame(ObjHeader** start, int count) RUNTIME_NOTHROW;
|
||||
void LeaveFrame(ObjHeader** start, int parameters, int count) RUNTIME_NOTHROW;
|
||||
// Tries to use returnSlot's arena for allocation.
|
||||
ObjHeader** GetReturnSlotIfArena(ObjHeader** returnSlot, ObjHeader** localSlot) RUNTIME_NOTHROW;
|
||||
// Tries to use param's arena for allocation.
|
||||
|
||||
Reference in New Issue
Block a user