Compare commits
2 Commits
main
...
tonycloud/dev
| Author | SHA1 | Date | |
|---|---|---|---|
| 57b27a7b44 | |||
| 08139af589 |
@@ -633,6 +633,12 @@ if (is_win) {
|
||||
default_warning_flags += [ "/WX" ] # Treat warnings as errors.
|
||||
}
|
||||
|
||||
# Ensure UTF-8 source encoding on Chinese Windows (codepage 936)
|
||||
default_warning_flags += [
|
||||
"/utf-8",
|
||||
"/wd4819",
|
||||
]
|
||||
|
||||
if (is_clang) {
|
||||
default_warning_flags += [
|
||||
"-Wno-deprecated-declarations", # crashpad
|
||||
|
||||
@@ -17,6 +17,11 @@ import sys
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
if hasattr(sys.stdout, 'reconfigure'):
|
||||
sys.stdout.reconfigure(errors='replace')
|
||||
if hasattr(sys.stderr, 'reconfigure'):
|
||||
sys.stderr.reconfigure(errors='replace')
|
||||
|
||||
# A regex matching an argument corresponding to the output filename passed to
|
||||
# link.exe.
|
||||
_LINK_EXE_OUT_ARG = re.compile('/OUT:(?P<out>.+)$', re.IGNORECASE)
|
||||
@@ -142,7 +147,8 @@ class WinTool(object):
|
||||
env=env,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
universal_newlines=True)
|
||||
universal_newlines=True,
|
||||
errors='replace')
|
||||
# Read output one line at a time as it shows up to avoid OOM failures when
|
||||
# GBs of output is produced.
|
||||
for line in link.stdout:
|
||||
|
||||
+20
-7
@@ -67,6 +67,7 @@ SDK_VERSION = '10.0.26100.0'
|
||||
# which makes a difference for the arm64 runtime.
|
||||
# The second number is an alternate version number, only used in an error string
|
||||
MSVS_VERSIONS = collections.OrderedDict([
|
||||
('2026', '18.0'), # VS 2026 (user-installed) - uses folder name '18'
|
||||
('2022', '17.0'), # The VS version in our packaged toolchain.
|
||||
('2019', '16.0'),
|
||||
('2017', '15.0'),
|
||||
@@ -75,11 +76,20 @@ MSVS_VERSIONS = collections.OrderedDict([
|
||||
# List of preferred VC toolset version based on MSVS
|
||||
# Order is not relevant for this dictionary.
|
||||
MSVC_TOOLSET_VERSION = {
|
||||
'2026': 'VC145',
|
||||
'2022': 'VC143',
|
||||
'2019': 'VC142',
|
||||
'2017': 'VC141',
|
||||
}
|
||||
|
||||
|
||||
def VisualStudioFolderName(version_as_year):
|
||||
"""Return the install folder name for a supported Visual Studio version."""
|
||||
if version_as_year >= '2026':
|
||||
return MSVS_VERSIONS.get(version_as_year, version_as_year).split('.')[0]
|
||||
return version_as_year
|
||||
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
json_data_file = os.path.join(script_dir, 'win_toolchain.json')
|
||||
|
||||
@@ -212,7 +222,8 @@ def GetVisualStudioVersion():
|
||||
else:
|
||||
program_files_path_variable = '%ProgramFiles(x86)%'
|
||||
path = os.path.expandvars(program_files_path_variable +
|
||||
'/Microsoft Visual Studio/%s' % version)
|
||||
'/Microsoft Visual Studio/%s' %
|
||||
VisualStudioFolderName(version))
|
||||
if path and any(
|
||||
os.path.exists(os.path.join(path, edition))
|
||||
for edition in ('Enterprise', 'Professional', 'Community', 'Preview',
|
||||
@@ -242,24 +253,25 @@ def DetectVisualStudioPath():
|
||||
program_files_path_variable = '%ProgramFiles%'
|
||||
else:
|
||||
program_files_path_variable = '%ProgramFiles(x86)%'
|
||||
folder_name = VisualStudioFolderName(version_as_year)
|
||||
for path in (os.environ.get('vs%s_install' % version_as_year),
|
||||
os.path.expandvars(program_files_path_variable +
|
||||
'/Microsoft Visual Studio/%s/Enterprise' %
|
||||
version_as_year),
|
||||
folder_name),
|
||||
os.path.expandvars(program_files_path_variable +
|
||||
'/Microsoft Visual Studio/%s/Professional' %
|
||||
version_as_year),
|
||||
folder_name),
|
||||
os.path.expandvars(program_files_path_variable +
|
||||
'/Microsoft Visual Studio/%s/Community' %
|
||||
version_as_year),
|
||||
folder_name),
|
||||
os.path.expandvars(program_files_path_variable +
|
||||
'/Microsoft Visual Studio/%s/Preview' %
|
||||
version_as_year),
|
||||
folder_name),
|
||||
os.path.expandvars(program_files_path_variable +
|
||||
'/Microsoft Visual Studio/%s/BuildTools' %
|
||||
version_as_year)):
|
||||
folder_name)):
|
||||
if path and os.path.exists(path):
|
||||
return path
|
||||
return path.strip()
|
||||
|
||||
raise Exception('Visual Studio Version %s not found.' % version_as_year)
|
||||
|
||||
@@ -562,6 +574,7 @@ def Update(force=False, no_download=False):
|
||||
|
||||
|
||||
def NormalizePath(path):
|
||||
path = path.strip()
|
||||
while path.endswith('\\'):
|
||||
path = path[:-1]
|
||||
return path
|
||||
|
||||
@@ -38,7 +38,11 @@ void alsoVerySecretFoo() {
|
||||
}
|
||||
""");
|
||||
|
||||
List<MappingPair> mapping = getSnapshotMap(tmpDir, secretfilenameFile);
|
||||
List<MappingPair> mapping = getSnapshotMap(
|
||||
tmpDir,
|
||||
secretfilenameFile,
|
||||
outputPrefix: "base",
|
||||
);
|
||||
bool good = verify(
|
||||
mapping,
|
||||
{
|
||||
@@ -55,13 +59,51 @@ void alsoVerySecretFoo() {
|
||||
},
|
||||
);
|
||||
if (!good) throw "Obfuscation didn't work as expected";
|
||||
|
||||
secretfilename2File.writeAsStringSync("""
|
||||
@pragma('vm:entry-point')
|
||||
void verySecretFoo() {
|
||||
print("foo!");
|
||||
alsoVerySecretFoo();
|
||||
newPatchOnlySecretFoo();
|
||||
}
|
||||
|
||||
void alsoVerySecretFoo() {
|
||||
print("foo too!");
|
||||
}
|
||||
|
||||
void newPatchOnlySecretFoo() {
|
||||
print("patched foo!");
|
||||
}
|
||||
""");
|
||||
|
||||
final File baseObfuscationMapFile = new File.fromUri(
|
||||
tmpDirUri.resolve("obfuscation-base.map"),
|
||||
);
|
||||
List<MappingPair> patchMapping = getSnapshotMap(
|
||||
tmpDir,
|
||||
secretfilenameFile,
|
||||
outputPrefix: "patch",
|
||||
loadObfuscationMapFile: baseObfuscationMapFile,
|
||||
);
|
||||
good = verifyLoadedObfuscationMap(
|
||||
mapping,
|
||||
patchMapping,
|
||||
"newPatchOnlySecretFoo",
|
||||
);
|
||||
if (!good) throw "Loaded obfuscation map didn't work as expected";
|
||||
print("Good");
|
||||
} finally {
|
||||
tmpDir.deleteSync(recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
List<MappingPair> getSnapshotMap(Directory tmpDir, File compileDartFile) {
|
||||
List<MappingPair> getSnapshotMap(
|
||||
Directory tmpDir,
|
||||
File compileDartFile, {
|
||||
required String outputPrefix,
|
||||
File? loadObfuscationMapFile,
|
||||
}) {
|
||||
final Uri genKernel = Platform.script.resolve('../bin/gen_kernel.dart');
|
||||
final File genKernelFile = new File.fromUri(genKernel);
|
||||
if (!genKernelFile.existsSync()) {
|
||||
@@ -96,7 +138,7 @@ List<MappingPair> getSnapshotMap(Directory tmpDir, File compileDartFile) {
|
||||
|
||||
final Uri tmpDirUri = tmpDir.uri;
|
||||
|
||||
final Uri kernelDill = tmpDirUri.resolve("kernel.dill");
|
||||
final Uri kernelDill = tmpDirUri.resolve("kernel-$outputPrefix.dill");
|
||||
final File kernelDillFile = new File.fromUri(kernelDill);
|
||||
|
||||
print("Running gen_kernel");
|
||||
@@ -120,14 +162,14 @@ List<MappingPair> getSnapshotMap(Directory tmpDir, File compileDartFile) {
|
||||
"stderr: ${kernelRun.stderr}";
|
||||
}
|
||||
|
||||
final Uri aotElf = tmpDirUri.resolve("aot.elf");
|
||||
final Uri aotElf = tmpDirUri.resolve("aot-$outputPrefix.elf");
|
||||
final File aotElfFile = new File.fromUri(aotElf);
|
||||
final Uri obfuscationMap = tmpDirUri.resolve("obfuscation.map");
|
||||
final Uri obfuscationMap = tmpDirUri.resolve("obfuscation-$outputPrefix.map");
|
||||
final File obfuscationMapFile = new File.fromUri(obfuscationMap);
|
||||
|
||||
print("Running $genSnapshot");
|
||||
// Extracted from pkg/dart2native/lib/dart2native.dart.
|
||||
final ProcessResult snapshotRun = Process.runSync(genSnapshotFile.path, [
|
||||
final List<String> genSnapshotArgs = [
|
||||
"--snapshot-kind=app-aot-elf",
|
||||
"--elf=${aotElfFile.path}",
|
||||
"--dwarf-stack-traces",
|
||||
@@ -135,7 +177,17 @@ List<MappingPair> getSnapshotMap(Directory tmpDir, File compileDartFile) {
|
||||
"--strip",
|
||||
"--save-obfuscation-map=${obfuscationMapFile.path}",
|
||||
kernelDillFile.path,
|
||||
]);
|
||||
];
|
||||
if (loadObfuscationMapFile != null) {
|
||||
genSnapshotArgs.insert(
|
||||
genSnapshotArgs.length - 1,
|
||||
"--load-obfuscation-map=${loadObfuscationMapFile.path}",
|
||||
);
|
||||
}
|
||||
final ProcessResult snapshotRun = Process.runSync(
|
||||
genSnapshotFile.path,
|
||||
genSnapshotArgs,
|
||||
);
|
||||
|
||||
if (snapshotRun.exitCode != 0) {
|
||||
throw "Got exit code ${snapshotRun.exitCode}\n"
|
||||
@@ -157,6 +209,10 @@ List<MappingPair> readJsonMapping(File file) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Map<String, String> toMap(List<MappingPair> mapping) {
|
||||
return {for (MappingPair pair in mapping) pair.from: pair.to};
|
||||
}
|
||||
|
||||
class MappingPair {
|
||||
final String from;
|
||||
final String to;
|
||||
@@ -200,3 +256,49 @@ bool verify(
|
||||
}
|
||||
return good;
|
||||
}
|
||||
|
||||
bool verifyLoadedObfuscationMap(
|
||||
List<MappingPair> baseMapping,
|
||||
List<MappingPair> patchMapping,
|
||||
String patchOnlyName,
|
||||
) {
|
||||
bool good = true;
|
||||
final Map<String, String> patchMap = toMap(patchMapping);
|
||||
for (MappingPair baseEntry in baseMapping) {
|
||||
final String? patchValue = patchMap[baseEntry.from];
|
||||
if (patchValue == null) {
|
||||
print("Patch map is missing loaded entry ${baseEntry.from}");
|
||||
good = false;
|
||||
} else if (patchValue != baseEntry.to) {
|
||||
print(
|
||||
"Expected ${baseEntry.from} to keep ${baseEntry.to}, "
|
||||
"but patch map used $patchValue",
|
||||
);
|
||||
good = false;
|
||||
}
|
||||
}
|
||||
|
||||
final String? patchOnlyValue = patchMap[patchOnlyName];
|
||||
if (patchOnlyValue == null) {
|
||||
print("Patch map is missing $patchOnlyName");
|
||||
good = false;
|
||||
} else {
|
||||
if (patchOnlyValue == patchOnlyName) {
|
||||
print("Expected $patchOnlyName to be obfuscated");
|
||||
good = false;
|
||||
}
|
||||
final Set<String> baseValues = baseMapping
|
||||
.where((MappingPair pair) => pair.from != pair.to)
|
||||
.map((MappingPair pair) => pair.to)
|
||||
.toSet();
|
||||
if (baseValues.contains(patchOnlyValue)) {
|
||||
print(
|
||||
"Patch-only rename $patchOnlyName->$patchOnlyValue collides with "
|
||||
"the loaded map",
|
||||
);
|
||||
good = false;
|
||||
}
|
||||
}
|
||||
|
||||
return good;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,11 @@ import("runtime_args.gni")
|
||||
|
||||
import("//build/config/sysroot.gni")
|
||||
|
||||
assert(!dart_enable_aot_patching || !dart_dynamic_modules,
|
||||
"dart_enable_aot_patching must be built without dart_dynamic_modules.")
|
||||
assert(!dart_enable_shorebird_interpreter || !dart_dynamic_modules,
|
||||
"dart_enable_shorebird_interpreter must be built without dart_dynamic_modules.")
|
||||
|
||||
config("dart_public_config") {
|
||||
include_dirs = [
|
||||
".",
|
||||
@@ -230,6 +235,16 @@ config("dart_config") {
|
||||
if (dart_dynamic_modules) {
|
||||
defines += [ "DART_DYNAMIC_MODULES" ]
|
||||
}
|
||||
if (dart_dynamic_modules || dart_enable_shorebird_interpreter) {
|
||||
defines += [ "DART_BYTECODE_INTERPRETER=1" ]
|
||||
}
|
||||
if (dart_enable_shorebird_interpreter) {
|
||||
defines += [ "DART_SHOREBIRD_INTERPRETER" ]
|
||||
}
|
||||
|
||||
if (dart_enable_aot_patching) {
|
||||
defines += [ "DART_ENABLE_AOT_PATCHING" ]
|
||||
}
|
||||
|
||||
if (include_experimental_vm_service) {
|
||||
defines += [ "EXPERIMENTAL_VM_SERVICE" ]
|
||||
@@ -371,6 +386,9 @@ library_for_all_configs("libdart") {
|
||||
if (dart_support_perfetto) {
|
||||
extra_deps += [ "//third_party/perfetto:libprotozero" ]
|
||||
}
|
||||
if (dart_enable_aot_patching) {
|
||||
extra_deps += [ "//third_party/boringssl" ]
|
||||
}
|
||||
if (is_fuchsia) {
|
||||
extra_deps += [
|
||||
"$fuchsia_sdk/pkg/fdio",
|
||||
@@ -385,6 +403,9 @@ library_for_all_configs("libdart") {
|
||||
compiler_lib = "vm:libdart_compiler"
|
||||
extra_configs = [ ":dart_shared_lib" ]
|
||||
include_dirs = [ "." ]
|
||||
if (dart_enable_aot_patching) {
|
||||
include_dirs += [ "//third_party/boringssl/src/include" ]
|
||||
}
|
||||
public_configs = [ ":dart_public_config" ]
|
||||
sources = [
|
||||
"$target_gen_dir/version.cc",
|
||||
|
||||
@@ -387,6 +387,7 @@ typedef Dart_Handle (*Dart_LibraryHandleErrorType)(Dart_Handle, Dart_Handle);
|
||||
typedef Dart_Handle (*Dart_LoadLibraryFromKernelType)(const uint8_t*, intptr_t);
|
||||
typedef Dart_Handle (*Dart_LoadLibraryType)(Dart_Handle);
|
||||
typedef Dart_Handle (*Dart_LoadLibraryFromBytecodeType)(Dart_Handle);
|
||||
typedef Dart_Handle (*Dart_ReloadBytecodePatchType)(const uint8_t*, intptr_t);
|
||||
typedef Dart_Handle (*Dart_FinalizeLoadingType)(bool);
|
||||
typedef Dart_Handle (*Dart_GetPeerType)(Dart_Handle, void**);
|
||||
typedef Dart_Handle (*Dart_SetPeerType)(Dart_Handle, void*);
|
||||
@@ -741,6 +742,7 @@ static Dart_LibraryHandleErrorType Dart_LibraryHandleErrorFn = NULL;
|
||||
static Dart_LoadLibraryFromKernelType Dart_LoadLibraryFromKernelFn = NULL;
|
||||
static Dart_LoadLibraryType Dart_LoadLibraryFn = NULL;
|
||||
static Dart_LoadLibraryFromBytecodeType Dart_LoadLibraryFromBytecodeFn = NULL;
|
||||
static Dart_ReloadBytecodePatchType Dart_ReloadBytecodePatchFn = NULL;
|
||||
static Dart_FinalizeLoadingType Dart_FinalizeLoadingFn = NULL;
|
||||
static Dart_GetPeerType Dart_GetPeerFn = NULL;
|
||||
static Dart_SetPeerType Dart_SetPeerFn = NULL;
|
||||
@@ -1313,6 +1315,8 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
|
||||
Dart_LoadLibraryFromBytecodeFn =
|
||||
(Dart_LoadLibraryFromBytecodeType)GetProcAddress(
|
||||
process, "Dart_LoadLibraryFromBytecode");
|
||||
Dart_ReloadBytecodePatchFn = (Dart_ReloadBytecodePatchType)GetProcAddress(
|
||||
process, "Dart_ReloadBytecodePatch");
|
||||
Dart_FinalizeLoadingFn = (Dart_FinalizeLoadingType)GetProcAddress(
|
||||
process, "Dart_FinalizeLoading");
|
||||
Dart_GetPeerFn = (Dart_GetPeerType)GetProcAddress(process, "Dart_GetPeer");
|
||||
@@ -2544,6 +2548,11 @@ Dart_Handle Dart_LoadLibraryFromBytecode(Dart_Handle bytecode_buffer) {
|
||||
return Dart_LoadLibraryFromBytecodeFn(bytecode_buffer);
|
||||
}
|
||||
|
||||
Dart_Handle Dart_ReloadBytecodePatch(const uint8_t* bytecode_buffer,
|
||||
intptr_t bytecode_buffer_size) {
|
||||
return Dart_ReloadBytecodePatchFn(bytecode_buffer, bytecode_buffer_size);
|
||||
}
|
||||
|
||||
Dart_Handle Dart_FinalizeLoading(bool complete_futures) {
|
||||
return Dart_FinalizeLoadingFn(complete_futures);
|
||||
}
|
||||
|
||||
@@ -112,6 +112,7 @@ static const char* const kSnapshotKindNames[] = {
|
||||
V(loading_unit_manifest, loading_unit_manifest_filename) \
|
||||
V(save_debugging_info, debugging_info_filename) \
|
||||
V(save_obfuscation_map, obfuscation_map_filename) \
|
||||
V(load_obfuscation_map, load_obfuscation_map_filename) \
|
||||
V(ffi_callback_stub, ffi_callback_stub_filename)
|
||||
|
||||
#define BOOL_OPTIONS_LIST(V) \
|
||||
@@ -168,6 +169,7 @@ static void PrintUsage() {
|
||||
"[--obfuscate] \n"
|
||||
"[--save-debugging-info=<debug-filename>] \n"
|
||||
"[--save-obfuscation-map=<map-filename>] \n"
|
||||
"[--load-obfuscation-map=<map-filename>] \n"
|
||||
"<dart-kernel-file> \n"
|
||||
" \n"
|
||||
"To create an AOT application snapshot as an ELF shared library: \n"
|
||||
@@ -177,6 +179,7 @@ static void PrintUsage() {
|
||||
"[--obfuscate] \n"
|
||||
"[--save-debugging-info=<debug-filename>] \n"
|
||||
"[--save-obfuscation-map=<map-filename>] \n"
|
||||
"[--load-obfuscation-map=<map-filename>] \n"
|
||||
"<dart-kernel-file> \n"
|
||||
" \n"
|
||||
"To create an AOT application snapshot as an Mach-O dynamic library (dylib): \n"
|
||||
@@ -186,6 +189,7 @@ static void PrintUsage() {
|
||||
"[--obfuscate] \n"
|
||||
"[--save-debugging-info=<debug-filename>] \n"
|
||||
"[--save-obfuscation-map=<map-filename>] \n"
|
||||
"[--load-obfuscation-map=<map-filename>] \n"
|
||||
"<dart-kernel-file> \n"
|
||||
" \n"
|
||||
"AOT snapshots can be obfuscated: that is all identifiers will be renamed \n"
|
||||
@@ -320,6 +324,12 @@ static int ParseArguments(int argc,
|
||||
"obfuscation is enabled by the --obfuscate flag.\n\n");
|
||||
return -1;
|
||||
}
|
||||
if (!obfuscate && load_obfuscation_map_filename != nullptr) {
|
||||
Syslog::PrintErr(
|
||||
"--load-obfuscation_map=<...> should only be specified when "
|
||||
"obfuscation is enabled by the --obfuscate flag.\n\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!IsSnapshottingForPrecompilation()) {
|
||||
if (obfuscate) {
|
||||
@@ -335,6 +345,13 @@ static int ParseArguments(int argc,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (load_obfuscation_map_filename != nullptr) {
|
||||
Syslog::PrintErr(
|
||||
"--load-obfuscation-map=<...> can only be enabled when building an "
|
||||
"AOT snapshot.\n\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strip) {
|
||||
Syslog::PrintErr(
|
||||
"Stripping can only be enabled when building an AOT snapshot.\n\n");
|
||||
@@ -394,6 +411,209 @@ static void MallocFinalizer(void* isolate_callback_data, void* peer) {
|
||||
free(peer);
|
||||
}
|
||||
|
||||
static bool IsJsonWhitespace(uint8_t c) {
|
||||
return c == ' ' || c == '\n' || c == '\r' || c == '\t';
|
||||
}
|
||||
|
||||
static int HexDigit(uint8_t c) {
|
||||
if (c >= '0' && c <= '9') {
|
||||
return c - '0';
|
||||
}
|
||||
if (c >= 'a' && c <= 'f') {
|
||||
return 10 + (c - 'a');
|
||||
}
|
||||
if (c >= 'A' && c <= 'F') {
|
||||
return 10 + (c - 'A');
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void AppendUtf8(char* buffer, intptr_t* length, uint32_t code_point) {
|
||||
if (code_point <= 0x7F) {
|
||||
buffer[(*length)++] = static_cast<char>(code_point);
|
||||
} else if (code_point <= 0x7FF) {
|
||||
buffer[(*length)++] = static_cast<char>(0xC0 | (code_point >> 6));
|
||||
buffer[(*length)++] = static_cast<char>(0x80 | (code_point & 0x3F));
|
||||
} else if (code_point <= 0xFFFF) {
|
||||
buffer[(*length)++] = static_cast<char>(0xE0 | (code_point >> 12));
|
||||
buffer[(*length)++] = static_cast<char>(0x80 | ((code_point >> 6) & 0x3F));
|
||||
buffer[(*length)++] = static_cast<char>(0x80 | (code_point & 0x3F));
|
||||
} else {
|
||||
buffer[(*length)++] = static_cast<char>(0xF0 | (code_point >> 18));
|
||||
buffer[(*length)++] = static_cast<char>(0x80 | ((code_point >> 12) & 0x3F));
|
||||
buffer[(*length)++] = static_cast<char>(0x80 | ((code_point >> 6) & 0x3F));
|
||||
buffer[(*length)++] = static_cast<char>(0x80 | (code_point & 0x3F));
|
||||
}
|
||||
}
|
||||
|
||||
static bool ParseJsonStringArray(const uint8_t* buffer,
|
||||
intptr_t size,
|
||||
MallocGrowableArray<const char*>* strings,
|
||||
const char** error) {
|
||||
intptr_t cursor = 0;
|
||||
auto skip_whitespace = [&]() {
|
||||
while (cursor < size && IsJsonWhitespace(buffer[cursor])) {
|
||||
cursor++;
|
||||
}
|
||||
};
|
||||
|
||||
skip_whitespace();
|
||||
if (cursor >= size || buffer[cursor++] != '[') {
|
||||
*error = "expected '['";
|
||||
return false;
|
||||
}
|
||||
skip_whitespace();
|
||||
if (cursor < size && buffer[cursor] == ']') {
|
||||
cursor++;
|
||||
skip_whitespace();
|
||||
if (cursor != size) {
|
||||
*error = "unexpected characters after ']'";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
while (cursor < size) {
|
||||
if (buffer[cursor++] != '"') {
|
||||
*error = "expected string";
|
||||
return false;
|
||||
}
|
||||
char* value = reinterpret_cast<char*>(malloc(size + 1));
|
||||
if (value == nullptr) {
|
||||
*error = "out of memory";
|
||||
return false;
|
||||
}
|
||||
intptr_t length = 0;
|
||||
while (cursor < size) {
|
||||
uint8_t c = buffer[cursor++];
|
||||
if (c == '"') {
|
||||
value[length] = '\0';
|
||||
strings->Add(value);
|
||||
value = nullptr;
|
||||
break;
|
||||
}
|
||||
if (c != '\\') {
|
||||
value[length++] = static_cast<char>(c);
|
||||
continue;
|
||||
}
|
||||
if (cursor >= size) {
|
||||
free(value);
|
||||
*error = "unterminated escape";
|
||||
return false;
|
||||
}
|
||||
c = buffer[cursor++];
|
||||
switch (c) {
|
||||
case '"':
|
||||
case '\\':
|
||||
case '/':
|
||||
value[length++] = static_cast<char>(c);
|
||||
break;
|
||||
case 'b':
|
||||
value[length++] = '\b';
|
||||
break;
|
||||
case 'f':
|
||||
value[length++] = '\f';
|
||||
break;
|
||||
case 'n':
|
||||
value[length++] = '\n';
|
||||
break;
|
||||
case 'r':
|
||||
value[length++] = '\r';
|
||||
break;
|
||||
case 't':
|
||||
value[length++] = '\t';
|
||||
break;
|
||||
case 'u': {
|
||||
if (cursor + 4 > size) {
|
||||
free(value);
|
||||
*error = "incomplete unicode escape";
|
||||
return false;
|
||||
}
|
||||
uint32_t code_point = 0;
|
||||
for (intptr_t i = 0; i < 4; i++) {
|
||||
const int digit = HexDigit(buffer[cursor++]);
|
||||
if (digit < 0) {
|
||||
free(value);
|
||||
*error = "invalid unicode escape";
|
||||
return false;
|
||||
}
|
||||
code_point = (code_point << 4) | digit;
|
||||
}
|
||||
AppendUtf8(value, &length, code_point);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
free(value);
|
||||
*error = "invalid escape";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (value != nullptr) {
|
||||
free(value);
|
||||
*error = "unterminated string";
|
||||
return false;
|
||||
}
|
||||
|
||||
skip_whitespace();
|
||||
if (cursor < size && buffer[cursor] == ',') {
|
||||
cursor++;
|
||||
skip_whitespace();
|
||||
continue;
|
||||
}
|
||||
if (cursor < size && buffer[cursor] == ']') {
|
||||
cursor++;
|
||||
skip_whitespace();
|
||||
if (cursor != size) {
|
||||
*error = "unexpected characters after ']'";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
*error = "expected ',' or ']'";
|
||||
return false;
|
||||
}
|
||||
|
||||
*error = "unterminated array";
|
||||
return false;
|
||||
}
|
||||
|
||||
static void MaybeLoadObfuscationMap() {
|
||||
if (load_obfuscation_map_filename == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t* buffer = nullptr;
|
||||
intptr_t size = 0;
|
||||
ReadFile(load_obfuscation_map_filename, &buffer, &size);
|
||||
|
||||
MallocGrowableArray<const char*> strings;
|
||||
const char* parse_error = nullptr;
|
||||
if (!ParseJsonStringArray(buffer, size, &strings, &parse_error)) {
|
||||
free(buffer);
|
||||
for (intptr_t i = 0; i < strings.length(); i++) {
|
||||
free(const_cast<char*>(strings[i]));
|
||||
}
|
||||
PrintErrAndExit("Error: Invalid obfuscation map %s: %s\n",
|
||||
load_obfuscation_map_filename, parse_error);
|
||||
}
|
||||
if ((strings.length() % 2) != 0) {
|
||||
free(buffer);
|
||||
for (intptr_t i = 0; i < strings.length(); i++) {
|
||||
free(const_cast<char*>(strings[i]));
|
||||
}
|
||||
PrintErrAndExit(
|
||||
"Error: Invalid obfuscation map %s: expected string pairs\n",
|
||||
load_obfuscation_map_filename);
|
||||
}
|
||||
|
||||
Dart_Handle result = Dart_SetObfuscationMap(strings.data(), strings.length());
|
||||
free(buffer);
|
||||
for (intptr_t i = 0; i < strings.length(); i++) {
|
||||
free(const_cast<char*>(strings[i]));
|
||||
}
|
||||
CHECK_RESULT(result);
|
||||
}
|
||||
|
||||
static void MaybeLoadExtraInputs(const CommandLineOptions& inputs) {
|
||||
for (intptr_t i = 1; i < inputs.count(); i++) {
|
||||
uint8_t* buffer = nullptr;
|
||||
@@ -656,6 +876,8 @@ static void CreateAndWritePrecompiledSnapshot() {
|
||||
ASSERT(kind_str != nullptr);
|
||||
ASSERT(filename != nullptr);
|
||||
|
||||
MaybeLoadObfuscationMap();
|
||||
|
||||
// Precompile with specified embedder entry points
|
||||
Dart_Handle result = Dart_Precompile();
|
||||
CHECK_RESULT(result);
|
||||
|
||||
@@ -3767,6 +3767,26 @@ Dart_LoadLibrary(Dart_Handle kernel_buffer);
|
||||
DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle
|
||||
Dart_LoadLibraryFromBytecode(Dart_Handle bytecode_buffer);
|
||||
|
||||
/**
|
||||
* Applies a Dart bytecode reload patch to the current isolate group.
|
||||
*
|
||||
* The buffer must contain a bytecode delta/full-snapshot payload generated for
|
||||
* the Dart bytecode interpreter. The VM copies the buffer before applying the
|
||||
* reload, so the caller retains ownership of the input. This API does not use
|
||||
* DART_DYNAMIC_MODULES and does not install downloaded native executable code.
|
||||
*
|
||||
* Requires there to be a current isolate.
|
||||
*
|
||||
* \param bytecode_buffer The bytecode patch buffer.
|
||||
* \param bytecode_buffer_size Length of the passed in buffer.
|
||||
*
|
||||
* \return Success if the bytecode reload patch was applied. Otherwise, returns
|
||||
* an error.
|
||||
*/
|
||||
DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle
|
||||
Dart_ReloadBytecodePatch(const uint8_t* bytecode_buffer,
|
||||
intptr_t bytecode_buffer_size);
|
||||
|
||||
/**
|
||||
* Indicates that all outstanding load requests have been satisfied.
|
||||
* This finalizes all the new classes loaded and optionally completes
|
||||
@@ -4241,6 +4261,89 @@ Dart_CreateAppJITSnapshotAsBlobs(uint8_t** snapshot_data_buffer,
|
||||
DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle
|
||||
Dart_GetObfuscationMap(uint8_t** buffer, intptr_t* buffer_length);
|
||||
|
||||
/**
|
||||
* Restore a previously saved obfuscation map before AOT precompilation.
|
||||
*
|
||||
* The map uses the same flat string-pair format returned by
|
||||
* Dart_GetObfuscationMap: [original0, obfuscated0, original1, obfuscated1, ...].
|
||||
* The VM rebuilds the precompiler obfuscation state so subsequent renames are
|
||||
* stable with the release build and newly introduced identifiers receive fresh
|
||||
* obfuscated names.
|
||||
*/
|
||||
DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle
|
||||
Dart_SetObfuscationMap(const char* const* map, intptr_t map_length);
|
||||
|
||||
/*
|
||||
* ========
|
||||
* AOT patching
|
||||
* ========
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
const char* app_id;
|
||||
const char* app_build_id;
|
||||
const char* base_flavor_id;
|
||||
const char* base_license_type;
|
||||
const char* flavor_id;
|
||||
const char* license_type;
|
||||
const char* sdk_hash;
|
||||
const char* base_snapshot_hash;
|
||||
const char* patch_snapshot_hash;
|
||||
const char* obfuscation_map_hash;
|
||||
const char* target_os;
|
||||
const char* target_arch;
|
||||
/*
|
||||
* Optional execution mode expected by the embedder. Missing artifacts are
|
||||
* treated as "native-aot" for backward compatibility. iOS App Store builds
|
||||
* must use the no-DDM interpreter patch mode, not native AOT snapshot text or
|
||||
* DART_DYNAMIC_MODULES.
|
||||
*/
|
||||
const char* runtime_mode;
|
||||
} Dart_AotPatchInstallOptions;
|
||||
|
||||
typedef bool (*Dart_AotPatchKeyCallback)(const char* key_id,
|
||||
uint8_t* key_buffer,
|
||||
intptr_t key_buffer_length,
|
||||
intptr_t* key_length);
|
||||
|
||||
/**
|
||||
* Returns whether this VM was built with compact AOT patching support.
|
||||
*
|
||||
* This feature is intentionally independent of DART_DYNAMIC_MODULES and does
|
||||
* not include the dynamic-module runtime.
|
||||
*/
|
||||
DART_EXPORT bool Dart_AotPatchingEnabled(void);
|
||||
|
||||
/**
|
||||
* Sets the callback used to resolve AES keys for encrypted AOT patch payloads.
|
||||
* The callback is owned by the embedder and must remain valid while patches may
|
||||
* be installed.
|
||||
*/
|
||||
DART_EXPORT void Dart_SetAotPatchKeyCallback(Dart_AotPatchKeyCallback callback);
|
||||
|
||||
/**
|
||||
* Validates an encrypted compact AOT patch artifact before embedder install.
|
||||
*
|
||||
* The VM validates open artifact metadata and requests key material for the
|
||||
* artifact key id, then decrypts the AES-256-GCM compact payload into an owned
|
||||
* buffer. A success result means the artifact is accepted for embedder
|
||||
* installation. The caller owns `patch_payload_buffer` and must release it with
|
||||
* Dart_FreeAotPatchPayload. On iOS, native AOT patch payloads are rejected; the
|
||||
* App Store-safe path is an interpreter payload executed by already-reviewed VM
|
||||
* code and remains independent of DART_DYNAMIC_MODULES.
|
||||
*/
|
||||
DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle
|
||||
Dart_InstallAotPatch(const uint8_t* patch_buffer,
|
||||
intptr_t patch_buffer_length,
|
||||
const Dart_AotPatchInstallOptions* options,
|
||||
uint8_t** patch_payload_buffer,
|
||||
intptr_t* patch_payload_length);
|
||||
|
||||
/**
|
||||
* Frees the buffer returned by Dart_InstallAotPatch.
|
||||
*/
|
||||
DART_EXPORT void Dart_FreeAotPatchPayload(uint8_t* patch_payload_buffer);
|
||||
|
||||
/**
|
||||
* Returns whether the VM only supports running from precompiled snapshots and
|
||||
* not from any other kind of snapshot or from source (that is, the VM was
|
||||
|
||||
@@ -74,6 +74,16 @@ declare_args() {
|
||||
|
||||
# Whether to support dynamic loading and interpretation of Dart bytecode.
|
||||
dart_dynamic_modules = false
|
||||
|
||||
# Whether to support Shorebird's no-DDM bytecode interpreter path. This
|
||||
# enables VM bytecode loading/interpreting without defining
|
||||
# DART_DYNAMIC_MODULES or exposing the dynamic module Dart package API.
|
||||
dart_enable_shorebird_interpreter = false
|
||||
|
||||
# Whether to expose the compact AOT patch installation API. This is separate
|
||||
# from dart_dynamic_modules; iOS may combine it with
|
||||
# dart_enable_shorebird_interpreter for App Store-safe patch payloads.
|
||||
dart_enable_aot_patching = false
|
||||
}
|
||||
|
||||
declare_args() {
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// Verifies that the compact AOT patching API is exported and callable without
|
||||
// enabling DART_DYNAMIC_MODULES or the bytecode interpreter.
|
||||
|
||||
import 'dart:ffi';
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
typedef DartAotPatchingEnabledNative = Bool Function();
|
||||
typedef DartAotPatchingEnabled = bool Function();
|
||||
|
||||
void main() {
|
||||
final enabled = DynamicLibrary.executable()
|
||||
.lookupFunction<DartAotPatchingEnabledNative, DartAotPatchingEnabled>(
|
||||
'Dart_AotPatchingEnabled',
|
||||
)();
|
||||
|
||||
// The value depends on the build flag, but a successful call proves the API
|
||||
// is present in both enabled and default builds.
|
||||
Expect.isTrue(enabled == true || enabled == false);
|
||||
}
|
||||
@@ -59,6 +59,7 @@ main() {
|
||||
|
||||
var expectedSymbols = [
|
||||
"Dart_AddSymbols",
|
||||
"Dart_AotPatchingEnabled",
|
||||
"Dart_Allocate",
|
||||
"Dart_AllocateWithNativeFields",
|
||||
"Dart_BooleanValue",
|
||||
@@ -111,6 +112,7 @@ main() {
|
||||
"Dart_False",
|
||||
"Dart_FinalizeAllClasses",
|
||||
"Dart_FinalizeLoading",
|
||||
"Dart_FreeAotPatchPayload",
|
||||
"Dart_FunctionIsStatic",
|
||||
"Dart_FunctionName",
|
||||
"Dart_FunctionOwner",
|
||||
@@ -158,6 +160,7 @@ main() {
|
||||
"Dart_IdentityEquals",
|
||||
"Dart_Initialize",
|
||||
"Dart_InitializeNativeAssetsResolver",
|
||||
"Dart_InstallAotPatch",
|
||||
"Dart_InstanceGetType",
|
||||
"Dart_IntegerFitsIntoInt64",
|
||||
"Dart_IntegerFitsIntoUint64",
|
||||
@@ -284,6 +287,7 @@ main() {
|
||||
"Dart_PrepareToAbort",
|
||||
"Dart_PropagateError",
|
||||
"Dart_RecordTimelineEvent",
|
||||
"Dart_ReloadBytecodePatch",
|
||||
"Dart_RegisterHeapSamplingCallback",
|
||||
"Dart_RegisterIsolateServiceRequestCallback",
|
||||
"Dart_RegisterRootServiceRequestCallback",
|
||||
@@ -296,6 +300,7 @@ main() {
|
||||
"Dart_SendPortGetId",
|
||||
"Dart_SendPortGetIdEx",
|
||||
"Dart_ServiceSendDataEvent",
|
||||
"Dart_SetAotPatchKeyCallback",
|
||||
"Dart_SetBooleanReturnValue",
|
||||
"Dart_SetCurrentUserTag",
|
||||
"Dart_SetDartLibrarySourcesKernel",
|
||||
@@ -314,6 +319,7 @@ main() {
|
||||
"Dart_SetMessageNotifyCallback",
|
||||
"Dart_SetNativeInstanceField",
|
||||
"Dart_SetNativeResolver",
|
||||
"Dart_SetObfuscationMap",
|
||||
"Dart_SetPausedOnExit",
|
||||
"Dart_SetPausedOnStart",
|
||||
"Dart_SetPeer",
|
||||
|
||||
@@ -2595,6 +2595,11 @@ class CodeSerializationCluster : public SerializationCluster {
|
||||
#if defined(DART_PRECOMPILER)
|
||||
auto const calls_array = code->untag()->static_calls_target_table_;
|
||||
if (calls_array != Array::null()) {
|
||||
#if defined(DART_SHOREBIRD_INTERPRETER)
|
||||
// Keep the full table in Shorebird interpreter snapshots. Runtime
|
||||
// static-call resolution needs Function targets, not just Code reachability.
|
||||
s->Push(calls_array);
|
||||
#else
|
||||
// Some Code entries in the static calls target table may only be
|
||||
// accessible via here, so push the Code objects.
|
||||
array_ = calls_array;
|
||||
@@ -2616,6 +2621,7 @@ class CodeSerializationCluster : public SerializationCluster {
|
||||
s->Push(destination);
|
||||
}
|
||||
}
|
||||
#endif // defined(DART_SHOREBIRD_INTERPRETER)
|
||||
}
|
||||
#else
|
||||
UNREACHABLE();
|
||||
@@ -2922,6 +2928,10 @@ class CodeSerializationCluster : public SerializationCluster {
|
||||
if (kind == Snapshot::kFullJIT) {
|
||||
WriteField(code, deopt_info_array_);
|
||||
WriteField(code, static_calls_target_table_);
|
||||
#if defined(DART_SHOREBIRD_INTERPRETER)
|
||||
} else if (kind == Snapshot::kFullAOT) {
|
||||
WriteField(code, static_calls_target_table_);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(PRODUCT)
|
||||
@@ -3048,6 +3058,10 @@ class CodeDeserializationCluster : public DeserializationCluster {
|
||||
code->untag()->deopt_info_array_ = static_cast<ArrayPtr>(d->ReadRef());
|
||||
code->untag()->static_calls_target_table_ =
|
||||
static_cast<ArrayPtr>(d->ReadRef());
|
||||
#elif defined(DART_SHOREBIRD_INTERPRETER)
|
||||
ASSERT(d->kind() == Snapshot::kFullAOT);
|
||||
code->untag()->static_calls_target_table_ =
|
||||
static_cast<ArrayPtr>(d->ReadRef());
|
||||
#endif // !DART_PRECOMPILED_RUNTIME
|
||||
|
||||
#if !defined(PRODUCT)
|
||||
@@ -3099,7 +3113,7 @@ class CodeDeserializationCluster : public DeserializationCluster {
|
||||
intptr_t deferred_stop_index_;
|
||||
};
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
class BytecodeSerializationCluster : public SerializationCluster {
|
||||
public:
|
||||
@@ -3172,7 +3186,7 @@ class BytecodeDeserializationCluster : public DeserializationCluster {
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
class ObjectPoolSerializationCluster : public SerializationCluster {
|
||||
@@ -8220,7 +8234,7 @@ SerializationCluster* Serializer::NewClusterForClass(intptr_t cid,
|
||||
return new (Z) KernelProgramInfoSerializationCluster();
|
||||
case kCodeCid:
|
||||
return new (Z) CodeSerializationCluster(heap_);
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
case kBytecodeCid:
|
||||
return new (Z) BytecodeSerializationCluster();
|
||||
#endif
|
||||
@@ -9461,7 +9475,7 @@ DeserializationCluster* Deserializer::ReadCluster() {
|
||||
ASSERT(!is_canonical);
|
||||
ASSERT(!is_deeply_immutable);
|
||||
return new (Z) CodeDeserializationCluster();
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
case kBytecodeCid:
|
||||
ASSERT(!is_canonical);
|
||||
ASSERT(!is_deeply_immutable);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "vm/bytecode_reader.h"
|
||||
|
||||
#include "vm/globals.h"
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
#include "vm/bit_vector.h"
|
||||
#include "vm/bootstrap.h"
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "vm/hash_table.h"
|
||||
#include "vm/longjump.h"
|
||||
#include "vm/object.h"
|
||||
#include "vm/os.h"
|
||||
#include "vm/object_store.h"
|
||||
#include "vm/resolver.h"
|
||||
#include "vm/reusable_handles.h"
|
||||
@@ -119,6 +120,22 @@ FunctionPtr BytecodeLoader::LoadBytecode(bool load_code) {
|
||||
return Function::RawCast(bytecode_reader.ReadObject());
|
||||
}
|
||||
|
||||
intptr_t BytecodeLoader::LoadBytecodePatch() {
|
||||
ASSERT(IsolateGroup::Current()->program_lock()->IsCurrentThreadWriter());
|
||||
|
||||
if (bytecode_component_array_.IsNull()) {
|
||||
BytecodeReaderHelper component_reader(thread_, binary_);
|
||||
bytecode_component_array_ = component_reader.ReadBytecodeComponent();
|
||||
}
|
||||
|
||||
BytecodeComponentData bytecode_component(bytecode_component_array_);
|
||||
BytecodeReaderHelper bytecode_reader(thread_, &bytecode_component);
|
||||
AlternativeReadingScope alt(&bytecode_reader.reader(),
|
||||
bytecode_component.GetLibraryIndexOffset());
|
||||
return bytecode_reader.ReadLoadedLibraryBytecodePatch(
|
||||
bytecode_component.GetNumLibraries());
|
||||
}
|
||||
|
||||
void BytecodeLoader::LoadPendingCode() {
|
||||
ASSERT(IsolateGroup::Current()->program_lock()->IsCurrentThreadWriter());
|
||||
ASSERT(!bytecode_component_array_.IsNull());
|
||||
@@ -2577,6 +2594,318 @@ void BytecodeReaderHelper::ReadLibraryDeclarations(
|
||||
}
|
||||
}
|
||||
|
||||
intptr_t BytecodeReaderHelper::ReadLoadedLibraryBytecodePatch(
|
||||
intptr_t num_libraries) {
|
||||
intptr_t installed_functions = 0;
|
||||
auto& library = Library::Handle(Z);
|
||||
auto& uri = String::Handle(Z);
|
||||
|
||||
for (intptr_t i = 0; i < num_libraries; ++i) {
|
||||
uri ^= ReadObject();
|
||||
const intptr_t library_offset =
|
||||
bytecode_component_->GetLibrariesOffset() + reader_.ReadUInt();
|
||||
|
||||
library = Library::LookupLibrary(thread_, uri);
|
||||
if (library.IsNull()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
AlternativeReadingScope alt(&reader_, library_offset);
|
||||
ReadLoadedLibraryPatchDeclaration(library, &installed_functions);
|
||||
}
|
||||
|
||||
return installed_functions;
|
||||
}
|
||||
|
||||
void BytecodeReaderHelper::ReadLoadedLibraryPatchDeclaration(
|
||||
const Library& library,
|
||||
intptr_t* installed_functions) {
|
||||
reader_.ReadUInt(); // Flags.
|
||||
|
||||
ReadObject(); // Library name.
|
||||
ReadObject(); // Script.
|
||||
|
||||
const intptr_t num_classes = reader_.ReadUInt();
|
||||
auto& cls = Class::Handle(Z);
|
||||
auto& name = String::Handle(Z);
|
||||
|
||||
for (intptr_t i = 0; i < num_classes; ++i) {
|
||||
name ^= ReadObject();
|
||||
const intptr_t class_offset =
|
||||
bytecode_component_->GetClassesOffset() + reader_.ReadUInt();
|
||||
|
||||
if (i == 0) {
|
||||
cls = library.toplevel_class();
|
||||
} else {
|
||||
cls = library.LookupClass(name);
|
||||
}
|
||||
if (cls.IsNull()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
AlternativeReadingScope alt(&reader_, class_offset);
|
||||
ReadLoadedClassPatchDeclaration(cls, installed_functions);
|
||||
}
|
||||
}
|
||||
|
||||
void BytecodeReaderHelper::ReadLoadedClassPatchDeclaration(
|
||||
const Class& cls,
|
||||
intptr_t* installed_functions) {
|
||||
const int kHasTypeParamsFlag = 1 << 2;
|
||||
const int kHasTypeArgumentsFlag = 1 << 3;
|
||||
const int kHasSourcePositionsFlag = 1 << 5;
|
||||
const int kHasAnnotationsFlag = 1 << 6;
|
||||
|
||||
const intptr_t flags = reader_.ReadUInt();
|
||||
|
||||
ReadObject(); // Script.
|
||||
|
||||
if ((flags & kHasSourcePositionsFlag) != 0) {
|
||||
reader_.ReadPosition();
|
||||
reader_.ReadPosition();
|
||||
}
|
||||
|
||||
if ((flags & kHasTypeArgumentsFlag) != 0) {
|
||||
reader_.ReadUInt();
|
||||
}
|
||||
|
||||
if ((flags & kHasTypeParamsFlag) != 0) {
|
||||
SkipTypeParametersDeclaration();
|
||||
}
|
||||
|
||||
ReadObject(); // Super type.
|
||||
|
||||
const intptr_t num_interfaces = reader_.ReadUInt();
|
||||
for (intptr_t i = 0; i < num_interfaces; ++i) {
|
||||
ReadObject();
|
||||
}
|
||||
|
||||
if ((flags & kHasAnnotationsFlag) != 0) {
|
||||
SkipAnnotations();
|
||||
}
|
||||
|
||||
const intptr_t members_offset =
|
||||
bytecode_component_->GetMembersOffset() + reader_.ReadUInt();
|
||||
AlternativeReadingScope alt(&reader_, members_offset);
|
||||
ReadLoadedMembersPatch(cls, installed_functions);
|
||||
}
|
||||
|
||||
void BytecodeReaderHelper::ReadLoadedMembersPatch(
|
||||
const Class& cls,
|
||||
intptr_t* installed_functions) {
|
||||
reader_.ReadUInt(); // Total function count, including field accessors.
|
||||
ReadLoadedFieldPatchDeclarations(cls, installed_functions);
|
||||
ReadLoadedFunctionPatchDeclarations(cls, installed_functions);
|
||||
}
|
||||
|
||||
void BytecodeReaderHelper::ReadLoadedFieldPatchDeclarations(
|
||||
const Class& cls,
|
||||
intptr_t* installed_functions) {
|
||||
const int kIsStaticFlag = 1 << 0;
|
||||
const int kIsLateFlag = 1 << 3;
|
||||
const int kHasGetterFlag = 1 << 8;
|
||||
const int kHasSetterFlag = 1 << 9;
|
||||
const int kHasNontrivialInitializerFlag = 1 << 11;
|
||||
const int kHasInitializerCodeFlag = 1 << 12;
|
||||
const int kHasSourcePositionsFlag = 1 << 13;
|
||||
const int kHasAnnotationsFlag = 1 << 14;
|
||||
const int kHasCustomScriptFlag = 1 << 16;
|
||||
|
||||
const intptr_t num_fields = reader_.ReadListLength();
|
||||
auto& name = String::Handle(Z);
|
||||
auto& field = Field::Handle(Z);
|
||||
auto& initializer = Function::Handle(Z);
|
||||
|
||||
for (intptr_t i = 0; i < num_fields; ++i) {
|
||||
const intptr_t flags = reader_.ReadUInt();
|
||||
const bool has_nontrivial_initializer =
|
||||
(flags & kHasNontrivialInitializerFlag) != 0;
|
||||
const bool is_static = (flags & kIsStaticFlag) != 0;
|
||||
const bool is_late = (flags & kIsLateFlag) != 0;
|
||||
|
||||
name ^= ReadObject();
|
||||
ReadObject(); // Field type.
|
||||
field = cls.LookupField(name);
|
||||
|
||||
if ((flags & kHasCustomScriptFlag) != 0) {
|
||||
ReadObject();
|
||||
}
|
||||
|
||||
if ((flags & kHasSourcePositionsFlag) != 0) {
|
||||
reader_.ReadPosition();
|
||||
reader_.ReadPosition();
|
||||
}
|
||||
|
||||
if (!has_nontrivial_initializer) {
|
||||
ReadObject();
|
||||
}
|
||||
|
||||
if ((flags & kHasInitializerCodeFlag) != 0) {
|
||||
const intptr_t code_offset =
|
||||
bytecode_component_->GetCodesOffset() + reader_.ReadUInt();
|
||||
if (!field.IsNull() && (is_static || is_late)) {
|
||||
initializer = field.EnsureInitializerFunction();
|
||||
InstallLoadedFunctionPatch(initializer, code_offset,
|
||||
installed_functions);
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags & kHasGetterFlag) != 0) {
|
||||
ReadObject();
|
||||
}
|
||||
if ((flags & kHasSetterFlag) != 0) {
|
||||
ReadObject();
|
||||
}
|
||||
|
||||
if ((flags & kHasAnnotationsFlag) != 0) {
|
||||
SkipAnnotations();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BytecodeReaderHelper::ReadLoadedFunctionPatchDeclarations(
|
||||
const Class& cls,
|
||||
intptr_t* installed_functions) {
|
||||
const int kIsStaticFlag = 1 << 0;
|
||||
const int kIsAbstractFlag = 1 << 1;
|
||||
const int kIsGetterFlag = 1 << 2;
|
||||
const int kIsConstructorFlag = 1 << 4;
|
||||
const int kIsFactoryFlag = 1 << 5;
|
||||
const int kHasOptionalPositionalParamsFlag = 1 << 7;
|
||||
const int kHasOptionalNamedParamsFlag = 1 << 8;
|
||||
const int kHasTypeParamsFlag = 1 << 9;
|
||||
const int kHasParameterFlagsFlag = 1 << 10;
|
||||
const int kIsNativeFlag = 1 << 19;
|
||||
const int kHasSourcePositionsFlag = 1 << 20;
|
||||
const int kHasAnnotationsFlag = 1 << 21;
|
||||
const int kHasCustomScriptFlag = 1 << 23;
|
||||
|
||||
const intptr_t num_functions = reader_.ReadListLength();
|
||||
auto& name = String::Handle(Z);
|
||||
auto& function = Function::Handle(Z);
|
||||
auto& error = Error::Handle(Z);
|
||||
|
||||
for (intptr_t i = 0; i < num_functions; ++i) {
|
||||
const intptr_t flags = reader_.ReadUInt();
|
||||
const bool is_static = (flags & kIsStaticFlag) != 0;
|
||||
const bool is_constructor =
|
||||
(flags & (kIsConstructorFlag | kIsFactoryFlag)) != 0;
|
||||
const bool has_optional_named_params =
|
||||
(flags & kHasOptionalNamedParamsFlag) != 0;
|
||||
|
||||
name ^= ReadObject();
|
||||
|
||||
if ((flags & kHasCustomScriptFlag) != 0) {
|
||||
ReadObject();
|
||||
}
|
||||
|
||||
if ((flags & kHasSourcePositionsFlag) != 0) {
|
||||
reader_.ReadPosition();
|
||||
reader_.ReadPosition();
|
||||
}
|
||||
|
||||
if (is_constructor) {
|
||||
name = ConstructorName(cls, name);
|
||||
}
|
||||
|
||||
error = is_constructor ? cls.EnsureIsAllocateFinalized(thread_)
|
||||
: cls.EnsureIsFinalized(thread_);
|
||||
if (!error.IsNull()) {
|
||||
Exceptions::PropagateError(error);
|
||||
UNREACHABLE();
|
||||
}
|
||||
function = Resolver::ResolveFunction(Z, cls, name);
|
||||
if (function.IsNull() && ((flags & kIsGetterFlag) != 0)) {
|
||||
String& method_name = String::Handle(Z, Field::NameFromGetter(name));
|
||||
function = Resolver::ResolveFunction(Z, cls, method_name);
|
||||
if (!function.IsNull()) {
|
||||
function = Function::Handle(Z, function.ptr()).GetMethodExtractor(name);
|
||||
}
|
||||
}
|
||||
|
||||
FunctionType& signature = FunctionType::Handle(Z);
|
||||
if (function.IsNull()) {
|
||||
signature = FunctionType::null();
|
||||
} else {
|
||||
signature = function.signature();
|
||||
}
|
||||
FunctionTypeScope function_type_scope(this, signature);
|
||||
|
||||
if ((flags & kHasTypeParamsFlag) != 0) {
|
||||
SkipTypeParametersDeclaration();
|
||||
}
|
||||
|
||||
const intptr_t num_implicit_params = is_static ? 0 : 1;
|
||||
const intptr_t num_params = num_implicit_params + reader_.ReadUInt();
|
||||
intptr_t num_required_params = num_params;
|
||||
if ((flags & (kHasOptionalPositionalParamsFlag |
|
||||
kHasOptionalNamedParamsFlag)) != 0) {
|
||||
num_required_params = num_implicit_params + reader_.ReadUInt();
|
||||
}
|
||||
|
||||
for (intptr_t param_index = num_implicit_params; param_index < num_params;
|
||||
++param_index) {
|
||||
name ^= ReadObject();
|
||||
USE(name);
|
||||
ReadObject();
|
||||
}
|
||||
|
||||
if ((flags & kHasParameterFlagsFlag) != 0) {
|
||||
RELEASE_ASSERT(has_optional_named_params);
|
||||
const intptr_t length = reader_.ReadUInt();
|
||||
for (intptr_t j = 0; j < length; j++) {
|
||||
reader_.ReadUInt();
|
||||
}
|
||||
}
|
||||
|
||||
ReadObject(); // Result type.
|
||||
|
||||
if ((flags & kIsNativeFlag) != 0) {
|
||||
ReadObject();
|
||||
}
|
||||
|
||||
if ((flags & kIsAbstractFlag) == 0) {
|
||||
const intptr_t code_offset =
|
||||
bytecode_component_->GetCodesOffset() + reader_.ReadUInt();
|
||||
InstallLoadedFunctionPatch(function, code_offset, installed_functions);
|
||||
}
|
||||
|
||||
if ((flags & kHasAnnotationsFlag) != 0) {
|
||||
SkipAnnotations();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BytecodeReaderHelper::InstallLoadedFunctionPatch(
|
||||
const Function& function,
|
||||
intptr_t code_offset,
|
||||
intptr_t* installed_functions) {
|
||||
if (function.IsNull() || function.is_abstract()) {
|
||||
return;
|
||||
}
|
||||
|
||||
OS::PrintErr("Dart bytecode patch: installing %s\n",
|
||||
function.ToFullyQualifiedCString());
|
||||
ReadCode(function, code_offset);
|
||||
*installed_functions += 1;
|
||||
}
|
||||
|
||||
void BytecodeReaderHelper::SkipTypeParametersDeclaration() {
|
||||
const intptr_t num_type_params = reader_.ReadUInt();
|
||||
ASSERT(num_type_params > 0);
|
||||
for (intptr_t i = 0; i < num_type_params; ++i) {
|
||||
ReadObject();
|
||||
}
|
||||
for (intptr_t i = 0; i < num_type_params; ++i) {
|
||||
ReadObject();
|
||||
ReadObject();
|
||||
}
|
||||
}
|
||||
|
||||
void BytecodeReaderHelper::SkipAnnotations() {
|
||||
reader_.ReadUInt();
|
||||
}
|
||||
|
||||
void BytecodeReaderHelper::ReadPendingCode(
|
||||
const GrowableObjectArray& pending_objects) {
|
||||
auto& obj = Object::Handle(Z);
|
||||
@@ -3167,4 +3496,4 @@ LocalVarDescriptorsPtr BytecodeReader::ComputeLocalVarDescriptors(
|
||||
} // namespace bytecode
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#define RUNTIME_VM_BYTECODE_READER_H_
|
||||
|
||||
#include "vm/globals.h"
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
#include "vm/bit_vector.h"
|
||||
#include "vm/constants_kbc.h"
|
||||
@@ -24,6 +24,7 @@ class BytecodeLoader {
|
||||
~BytecodeLoader();
|
||||
|
||||
FunctionPtr LoadBytecode(bool load_code = true);
|
||||
intptr_t LoadBytecodePatch();
|
||||
void LoadPendingCode();
|
||||
|
||||
TypedDataBasePtr binary() const { return binary_.ptr(); }
|
||||
@@ -250,6 +251,7 @@ class BytecodeReaderHelper : public ValueObject {
|
||||
void ReadLibraryDeclarations(intptr_t num_libraries,
|
||||
const GrowableObjectArray& pending_objects,
|
||||
bool load_code);
|
||||
intptr_t ReadLoadedLibraryBytecodePatch(intptr_t num_libraries);
|
||||
void ReadPendingCode(const GrowableObjectArray& pending_objects);
|
||||
void FindModifiedLibraries(BitVector* modified_libs, intptr_t num_libraries);
|
||||
|
||||
@@ -368,6 +370,20 @@ class BytecodeReaderHelper : public ValueObject {
|
||||
};
|
||||
|
||||
void ReadClosureDeclaration(const Function& function, intptr_t closureIndex);
|
||||
void ReadLoadedLibraryPatchDeclaration(const Library& library,
|
||||
intptr_t* installed_functions);
|
||||
void ReadLoadedClassPatchDeclaration(const Class& cls,
|
||||
intptr_t* installed_functions);
|
||||
void ReadLoadedMembersPatch(const Class& cls, intptr_t* installed_functions);
|
||||
void ReadLoadedFieldPatchDeclarations(const Class& cls,
|
||||
intptr_t* installed_functions);
|
||||
void ReadLoadedFunctionPatchDeclarations(const Class& cls,
|
||||
intptr_t* installed_functions);
|
||||
void InstallLoadedFunctionPatch(const Function& function,
|
||||
intptr_t code_offset,
|
||||
intptr_t* installed_functions);
|
||||
void SkipTypeParametersDeclaration();
|
||||
void SkipAnnotations();
|
||||
FunctionTypePtr ReadFunctionSignature(const FunctionType& signature,
|
||||
const Function& closure_function,
|
||||
bool has_optional_positional_params,
|
||||
@@ -773,5 +789,5 @@ class BytecodeRecordedCoverageIterator : ValueObject {
|
||||
} // namespace bytecode
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
#endif // RUNTIME_VM_BYTECODE_READER_H_
|
||||
|
||||
@@ -439,7 +439,7 @@ AbstractTypePtr ClassFinalizer::FinalizeType(const AbstractType& type,
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
#if defined(TARGET_ARCH_X64)
|
||||
static bool IsPotentialExactGeneric(const AbstractType& type) {
|
||||
@@ -531,7 +531,7 @@ void ClassFinalizer::FinalizeMemberTypes(const Class& cls) {
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
void ClassFinalizer::FinalizeTypesInClass(const Class& cls) {
|
||||
Thread* thread = Thread::Current();
|
||||
@@ -541,7 +541,7 @@ void ClassFinalizer::FinalizeTypesInClass(const Class& cls) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER)
|
||||
Zone* zone = thread->zone();
|
||||
SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
|
||||
if (cls.is_type_finalized()) {
|
||||
@@ -603,7 +603,7 @@ void ClassFinalizer::FinalizeTypesInClass(const Class& cls) {
|
||||
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
@@ -700,7 +700,7 @@ void ClassFinalizer::FinalizeClass(const Class& cls) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_BYTECODE_INTERPRETER)
|
||||
UNREACHABLE();
|
||||
#else
|
||||
Thread* thread = Thread::Current();
|
||||
@@ -724,7 +724,7 @@ void ClassFinalizer::FinalizeClass(const Class& cls) {
|
||||
(cls.kernel_offset() > 0));
|
||||
if (!cls.is_loaded()) {
|
||||
if (cls.is_declared_in_bytecode()) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
bytecode::BytecodeReader::FinishClassLoading(cls);
|
||||
#else
|
||||
UNREACHABLE();
|
||||
@@ -772,7 +772,7 @@ void ClassFinalizer::FinalizeClass(const Class& cls) {
|
||||
cls.set_is_allocate_finalized();
|
||||
}
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME)
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
@@ -830,7 +830,7 @@ ErrorPtr ClassFinalizer::AllocateFinalizeClass(const Class& cls) {
|
||||
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER)
|
||||
ErrorPtr ClassFinalizer::LoadClassMembers(const Class& cls) {
|
||||
ASSERT(IsolateGroup::Current()->program_lock()->IsCurrentThreadWriter());
|
||||
ASSERT(!cls.is_finalized());
|
||||
@@ -894,7 +894,7 @@ void ClassFinalizer::PrintClassInformation(const Class& cls) {
|
||||
}
|
||||
}
|
||||
#endif // !defined(PRODUCT)
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
|
||||
@@ -65,13 +65,13 @@ class ClassFinalizer : public AllStatic {
|
||||
static ErrorPtr AllocateFinalizeClass(const Class& cls);
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER)
|
||||
// Completes loading of the class, this populates the function
|
||||
// and fields of the class.
|
||||
//
|
||||
// Returns Error::null() if there is no loading error.
|
||||
static ErrorPtr LoadClassMembers(const Class& cls);
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
// Verify that the classes have been properly prefinalized. This is
|
||||
@@ -90,7 +90,7 @@ class ClassFinalizer : public AllStatic {
|
||||
const TypeParameters& type_params,
|
||||
FinalizationKind finalization);
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER)
|
||||
static void FinalizeMemberTypes(const Class& cls);
|
||||
#if !defined(PRODUCT)
|
||||
static void PrintClassInformation(const Class& cls);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#include "vm/code_patcher.h"
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
#include "vm/constants_kbc.h"
|
||||
#endif
|
||||
#include "vm/cpu.h"
|
||||
@@ -64,7 +64,7 @@ bool MatchesPattern(uword end, const int16_t* pattern, intptr_t size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#if !defined(PRODUCT) && defined(DART_DYNAMIC_MODULES)
|
||||
#if !defined(PRODUCT) && defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
uint32_t BytecodePatcher::AddBreakpointAt(uword return_address,
|
||||
const Bytecode& bytecode) {
|
||||
@@ -110,6 +110,6 @@ void BytecodePatcher::RemoveBreakpointAtWithMutatorsStopped(
|
||||
static_cast<KernelBytecode::Opcode>(opcode)));
|
||||
*instr = opcode;
|
||||
}
|
||||
#endif // !defined(PRODUCT) && defined(DART_DYNAMIC_MODULES)
|
||||
#endif // !defined(PRODUCT) && defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
} // namespace dart
|
||||
|
||||
@@ -94,7 +94,7 @@ class CodePatcher : public AllStatic {
|
||||
static intptr_t GetSubtypeTestCachePoolIndex(uword return_address);
|
||||
};
|
||||
|
||||
#if !defined(PRODUCT) && defined(DART_DYNAMIC_MODULES)
|
||||
#if !defined(PRODUCT) && defined(DART_BYTECODE_INTERPRETER)
|
||||
class BytecodePatcher : public AllStatic {
|
||||
public:
|
||||
// Patch call instruction prior to return_address to add a breakpoint.
|
||||
@@ -118,7 +118,7 @@ class BytecodePatcher : public AllStatic {
|
||||
const Bytecode& bytecode,
|
||||
uint32_t opcode);
|
||||
};
|
||||
#endif // !defined(PRODUCT) && defined(DART_DYNAMIC_MODULES)
|
||||
#endif // !defined(PRODUCT) && defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
// Beginning from [end - size] we compare [size] bytes with [pattern]. All
|
||||
// [0..255] values in [pattern] have to match, negative values are skipped.
|
||||
|
||||
@@ -603,7 +603,7 @@ void Precompiler::DoCompileAll() {
|
||||
IG->object_store()->set_simple_instance_of_true_function(null_function);
|
||||
IG->object_store()->set_simple_instance_of_false_function(
|
||||
null_function);
|
||||
#if !defined(DART_DYNAMIC_MODULES)
|
||||
#if !defined(DART_BYTECODE_INTERPRETER)
|
||||
IG->object_store()->set_async_star_stream_controller(null_class);
|
||||
#endif
|
||||
IG->object_store()->set_native_assets_library(null_library);
|
||||
@@ -1953,14 +1953,14 @@ void Precompiler::TraceForRetainedFunctions() {
|
||||
function.DropUncompiledImplicitClosureFunction();
|
||||
|
||||
bool retained = possibly_retained_functions_.ContainsKey(function);
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
// Retain abstract functions annotated with entry point
|
||||
// pragmas as they can be used as targets of interface calls.
|
||||
if (function.is_abstract() &&
|
||||
functions_with_entry_point_pragmas_.ContainsKey(function)) {
|
||||
retained = true;
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
if (retained) {
|
||||
AddTypesOf(function);
|
||||
}
|
||||
@@ -2066,6 +2066,7 @@ void Precompiler::FinalizeDispatchTable() {
|
||||
|
||||
void Precompiler::ReplaceFunctionStaticCallEntries() {
|
||||
PRECOMPILER_TIMER_SCOPE(this, ReplaceFunctionStaticCallEntries);
|
||||
|
||||
class StaticCallTableEntryFixer : public CodeVisitor {
|
||||
public:
|
||||
explicit StaticCallTableEntryFixer(Zone* zone)
|
||||
@@ -2106,6 +2107,19 @@ void Precompiler::ReplaceFunctionStaticCallEntries() {
|
||||
|
||||
ASSERT(view.Get<Code::kSCallTableCodeOrTypeTarget>() == Code::null());
|
||||
ASSERT(target_function_.HasCode());
|
||||
#if defined(DART_SHOREBIRD_INTERPRETER)
|
||||
if (target_function_.IsShorebirdPatchable()) {
|
||||
// Keep patchable functions as Function targets. Runtime dispatch will
|
||||
// read the current Function::entry_point, which can point at
|
||||
// InterpretCall after a bytecode patch is loaded.
|
||||
if (FLAG_trace_precompiler) {
|
||||
THR_Print("Kept patchable static call entry for %s in \"%s\"\n",
|
||||
target_function_.ToFullyQualifiedCString(),
|
||||
code.ToCString());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
target_code_ = target_function_.CurrentCode();
|
||||
ASSERT(!target_code_.IsStubCode());
|
||||
view.Set<Code::kSCallTableCodeOrTypeTarget>(target_code_);
|
||||
@@ -2583,13 +2597,13 @@ void Precompiler::DropTransitiveUserDefinedConstants() {
|
||||
if (cls.constants() == Array::null()) {
|
||||
continue;
|
||||
}
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
// Retain constant tables of exported classes to allow constant
|
||||
// canonicalization at runtime.
|
||||
if (HasApiUse(cls)) {
|
||||
continue;
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
typedef UnorderedHashSet<CanonicalInstanceTraits> CanonicalInstancesSet;
|
||||
|
||||
@@ -2929,6 +2943,7 @@ void Precompiler::DiscardCodeObjects() {
|
||||
loading_unit_(LoadingUnit::Handle(zone)),
|
||||
static_calls_target_table_(Array::Handle(zone)),
|
||||
kind_and_offset_(Smi::Handle(zone)),
|
||||
function_target_(Function::Handle(zone)),
|
||||
call_target_(Code::Handle(zone)),
|
||||
targets_of_calls_via_code_(
|
||||
GrowableObjectArray::Handle(zone, GrowableObjectArray::New())),
|
||||
@@ -2947,6 +2962,16 @@ void Precompiler::DiscardCodeObjects() {
|
||||
kind_and_offset_ = view.Get<Code::kSCallTableKindAndOffset>();
|
||||
auto const kind = Code::KindField::decode(kind_and_offset_.Value());
|
||||
if (kind == Code::kCallViaCode) {
|
||||
#if defined(DART_SHOREBIRD_INTERPRETER)
|
||||
function_target_ =
|
||||
view.Get<Code::kSCallTableFunctionTarget>();
|
||||
if (!function_target_.IsNull()) {
|
||||
ASSERT(function_target_.HasCode());
|
||||
call_target_ = function_target_.CurrentCode();
|
||||
targets_of_calls_via_code_.Add(call_target_);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
call_target_ =
|
||||
Code::RawCast(view.Get<Code::kSCallTableCodeOrTypeTarget>());
|
||||
ASSERT(!call_target_.IsNull());
|
||||
@@ -3070,6 +3095,7 @@ void Precompiler::DiscardCodeObjects() {
|
||||
LoadingUnit& loading_unit_;
|
||||
Array& static_calls_target_table_;
|
||||
Smi& kind_and_offset_;
|
||||
Function& function_target_;
|
||||
Code& call_target_;
|
||||
GrowableObjectArray& targets_of_calls_via_code_;
|
||||
const FunctionSet& functions_to_retain_;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#include "vm/globals.h"
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
#include "vm/compiler/assembler/disassembler_kbc.h"
|
||||
|
||||
@@ -583,4 +583,4 @@ void KernelBytecodeDisassembler::PrintLocalVariablesInfo(
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#define RUNTIME_VM_COMPILER_ASSEMBLER_DISASSEMBLER_KBC_H_
|
||||
|
||||
#include "vm/globals.h"
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
#include "vm/compiler/assembler/disassembler.h"
|
||||
|
||||
@@ -114,6 +114,6 @@ class KernelBytecodeDisassembler : public AllStatic {
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
#endif // RUNTIME_VM_COMPILER_ASSEMBLER_DISASSEMBLER_KBC_H_
|
||||
|
||||
@@ -3516,9 +3516,18 @@ void FlowGraphCompiler::EmitMoveConst(const compiler::ffi::NativeLocation& dst,
|
||||
}
|
||||
|
||||
bool FlowGraphCompiler::CanPcRelativeCall(const Function& target) const {
|
||||
return FLAG_precompiled_mode && !FLAG_force_indirect_calls &&
|
||||
(LoadingUnit::LoadingUnitOf(function()) ==
|
||||
LoadingUnit::LoadingUnitOf(target));
|
||||
const bool can_pc_relative =
|
||||
FLAG_precompiled_mode && !FLAG_force_indirect_calls &&
|
||||
(LoadingUnit::LoadingUnitOf(function()) ==
|
||||
LoadingUnit::LoadingUnitOf(target));
|
||||
#if defined(DART_SHOREBIRD_INTERPRETER)
|
||||
// Shorebird's interpreter patching updates Function::entry_point at runtime.
|
||||
// Keep only explicitly patchable entry points indirect so patched functions
|
||||
// are observed without rewriting executable AOT instructions.
|
||||
return can_pc_relative && !target.IsShorebirdPatchable();
|
||||
#else
|
||||
return can_pc_relative;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FlowGraphCompiler::CanPcRelativeCall(const Code& target) const {
|
||||
|
||||
@@ -809,7 +809,7 @@ void ClosureCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
// R0: Closure with a cached entry point.
|
||||
__ ldr(R2, compiler::FieldAddress(
|
||||
R0, compiler::target::Closure::entry_point_offset()));
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
ASSERT(FUNCTION_REG != R2);
|
||||
__ ldr(FUNCTION_REG, compiler::FieldAddress(
|
||||
R0, compiler::target::Closure::function_offset()));
|
||||
|
||||
@@ -652,7 +652,7 @@ void ClosureCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
// R0: Closure with a cached entry point.
|
||||
__ LoadFieldFromOffset(R2, R0,
|
||||
compiler::target::Closure::entry_point_offset());
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
ASSERT(FUNCTION_REG != R2);
|
||||
__ LoadCompressedFieldFromOffset(
|
||||
FUNCTION_REG, R0, compiler::target::Closure::function_offset());
|
||||
|
||||
@@ -690,7 +690,7 @@ void ClosureCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
// T0: Closure with a cached entry point.
|
||||
__ LoadFieldFromOffset(A1, T0,
|
||||
compiler::target::Closure::entry_point_offset());
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
ASSERT(FUNCTION_REG != A1);
|
||||
__ LoadCompressedFieldFromOffset(
|
||||
FUNCTION_REG, T0, compiler::target::Closure::function_offset());
|
||||
|
||||
@@ -6528,7 +6528,7 @@ void ClosureCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
// RAX: Closure with cached entry point.
|
||||
__ movq(RCX, compiler::FieldAddress(
|
||||
RAX, compiler::target::Closure::entry_point_offset()));
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
ASSERT(FUNCTION_REG != RCX);
|
||||
__ LoadCompressed(FUNCTION_REG,
|
||||
compiler::FieldAddress(
|
||||
|
||||
@@ -20069,7 +20069,11 @@ static constexpr dart::compiler::target::word
|
||||
AOT_Closure_elements_start_offset = 0x28;
|
||||
static constexpr dart::compiler::target::word AOT_Closure_element_size = 0x8;
|
||||
static constexpr dart::compiler::target::word AOT_Code_elements_start_offset =
|
||||
#if defined(DART_SHOREBIRD_INTERPRETER)
|
||||
0x80;
|
||||
#else
|
||||
0x78;
|
||||
#endif
|
||||
static constexpr dart::compiler::target::word AOT_Code_element_size = 0x4;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_Context_elements_start_offset = 0x18;
|
||||
|
||||
@@ -230,14 +230,14 @@ void StubCodeCompiler::GenerateInitLateInstanceFieldStub(bool is_final) {
|
||||
if (!FLAG_precompiled_mode) {
|
||||
__ LoadCompressedFieldFromOffset(CODE_REG, FUNCTION_REG,
|
||||
target::Function::code_offset());
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
// InterpretCall stub needs arguments descriptor for all function calls.
|
||||
__ LoadObject(ARGS_DESC_REG, ArgumentsDescriptorBoxed(/*type_args_len=*/0,
|
||||
/*num_arguments=*/1));
|
||||
#else
|
||||
// Load a GC-safe value for the arguments descriptor (unused but tagged).
|
||||
__ LoadImmediate(ARGS_DESC_REG, 0);
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
if (FLAG_target_thread_sanitizer) {
|
||||
__ TsanFuncEntry();
|
||||
@@ -2481,7 +2481,7 @@ void StubCodeCompiler::GenerateResumeStub() {
|
||||
static_assert((kStackTrace != CODE_REG) && (kStackTrace != PP),
|
||||
"should not interfere");
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
Label resume_interpreter;
|
||||
__ CompareWithMemoryValue(
|
||||
kResumePc,
|
||||
@@ -2489,7 +2489,7 @@ void StubCodeCompiler::GenerateResumeStub() {
|
||||
compiler::target::Thread::
|
||||
resume_interpreter_adjusted_entry_point_offset()));
|
||||
__ BranchIf(EQUAL, &resume_interpreter);
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
// Set return address as if suspended Dart function called
|
||||
// stub with kResumePc as a return address.
|
||||
@@ -2516,7 +2516,7 @@ void StubCodeCompiler::GenerateResumeStub() {
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_ARM64)
|
||||
// This case is used when Dart frame is still on the stack.
|
||||
if (FLAG_precompiled_mode) {
|
||||
@@ -2535,7 +2535,7 @@ void StubCodeCompiler::GenerateResumeStub() {
|
||||
__ PopRegister(CallingConventions::kReturnReg); // Get result.
|
||||
__ LeaveDartFrame();
|
||||
__ Ret();
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
void StubCodeCompiler::GenerateReturnStub(
|
||||
|
||||
@@ -572,6 +572,17 @@ void StubCodeCompiler::GenerateCallStaticFunctionStub() {
|
||||
__ LoadImmediate(R0, 0);
|
||||
__ PushList((1 << R0) | (1 << ARGS_DESC_REG));
|
||||
__ CallRuntime(kPatchStaticCallRuntimeEntry, 0);
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && defined(DART_SHOREBIRD_INTERPRETER)
|
||||
// Get Function object result and restore arguments descriptor array.
|
||||
__ PopList((1 << R0) | (1 << ARGS_DESC_REG));
|
||||
// Remove the stub frame.
|
||||
__ LeaveStubFrame();
|
||||
// Jump through Function::entry_point so bytecode-attached functions enter
|
||||
// the interpreter without rewriting executable AOT instructions.
|
||||
__ LoadCompressedFieldFromOffset(CODE_REG, FUNCTION_REG,
|
||||
target::Function::code_offset());
|
||||
__ Branch(FieldAddress(FUNCTION_REG, target::Function::entry_point_offset()));
|
||||
#else
|
||||
// Get Code object result and restore arguments descriptor array.
|
||||
__ PopList((1 << R0) | (1 << ARGS_DESC_REG));
|
||||
// Remove the stub frame.
|
||||
@@ -579,6 +590,7 @@ void StubCodeCompiler::GenerateCallStaticFunctionStub() {
|
||||
// Jump to the dart function.
|
||||
__ mov(CODE_REG, Operand(R0));
|
||||
__ Branch(FieldAddress(R0, target::Code::entry_point_offset()));
|
||||
#endif
|
||||
}
|
||||
|
||||
// Called from a static call only when an invalid code has been entered
|
||||
@@ -1290,7 +1302,7 @@ void StubCodeCompiler::GenerateInvokeDartCodeStub() {
|
||||
// R2 : address of first argument.
|
||||
// R3 : current thread.
|
||||
void StubCodeCompiler::GenerateInvokeDartCodeFromBytecodeStub() {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
SPILLS_LR_TO_FRAME(__ EnterFrame((1 << FP) | (1 << LR), 0));
|
||||
|
||||
// Push code object to PC marker slot.
|
||||
@@ -1416,7 +1428,7 @@ void StubCodeCompiler::GenerateInvokeDartCodeFromBytecodeStub() {
|
||||
|
||||
#else
|
||||
__ Stop("Not using Dart dynamic modules");
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
// Helper to generate space allocation of context stub.
|
||||
@@ -2696,7 +2708,7 @@ void StubCodeCompiler::GenerateLazyCompileStub() {
|
||||
// R4: Arguments descriptor.
|
||||
// R0: Function.
|
||||
void StubCodeCompiler::GenerateInterpretCallStub() {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
__ EnterStubFrame();
|
||||
|
||||
@@ -2770,7 +2782,7 @@ void StubCodeCompiler::GenerateInterpretCallStub() {
|
||||
|
||||
#else
|
||||
__ Stop("Not using Dart dynamic modules");
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
// R9: Contains an ICData.
|
||||
|
||||
@@ -795,6 +795,20 @@ void StubCodeCompiler::GenerateCallStaticFunctionStub() {
|
||||
__ Push(ARGS_DESC_REG);
|
||||
__ Push(ZR);
|
||||
__ CallRuntime(kPatchStaticCallRuntimeEntry, 0);
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && defined(DART_SHOREBIRD_INTERPRETER)
|
||||
// Get Function object result and restore arguments descriptor array.
|
||||
__ Pop(FUNCTION_REG);
|
||||
__ Pop(ARGS_DESC_REG);
|
||||
// Remove the stub frame.
|
||||
__ LeaveStubFrame();
|
||||
// Jump through Function::entry_point so bytecode-attached functions enter
|
||||
// the interpreter without rewriting executable AOT instructions.
|
||||
__ LoadCompressedFieldFromOffset(CODE_REG, FUNCTION_REG,
|
||||
target::Function::code_offset());
|
||||
__ LoadFieldFromOffset(TMP, FUNCTION_REG,
|
||||
target::Function::entry_point_offset());
|
||||
__ br(TMP);
|
||||
#else
|
||||
// Get Code object result and restore arguments descriptor array.
|
||||
__ Pop(CODE_REG);
|
||||
__ Pop(ARGS_DESC_REG);
|
||||
@@ -803,6 +817,7 @@ void StubCodeCompiler::GenerateCallStaticFunctionStub() {
|
||||
// Jump to the dart function.
|
||||
__ LoadFieldFromOffset(R0, CODE_REG, target::Code::entry_point_offset());
|
||||
__ br(R0);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Called from a static call only when an invalid code has been entered
|
||||
@@ -1617,7 +1632,7 @@ void StubCodeCompiler::GenerateInvokeDartCodeStub() {
|
||||
// R2 : address of first argument.
|
||||
// R3 : current thread.
|
||||
void StubCodeCompiler::GenerateInvokeDartCodeFromBytecodeStub() {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
__ Comment("InvokeDartCodeFromBytecodeStub");
|
||||
|
||||
// Copy the C stack pointer (CSP/R31) into the stack pointer we'll actually
|
||||
@@ -1755,7 +1770,7 @@ void StubCodeCompiler::GenerateInvokeDartCodeFromBytecodeStub() {
|
||||
|
||||
#else
|
||||
__ Stop("Not using Dart dynamic modules");
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
// Helper to generate space allocation of context stub.
|
||||
@@ -3098,7 +3113,7 @@ void StubCodeCompiler::GenerateLazyCompileStub() {
|
||||
// R4: Arguments descriptor.
|
||||
// R0: Function.
|
||||
void StubCodeCompiler::GenerateInterpretCallStub() {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
__ SetPrologueOffset();
|
||||
__ EnterStubFrame();
|
||||
@@ -3186,7 +3201,7 @@ void StubCodeCompiler::GenerateInterpretCallStub() {
|
||||
|
||||
#else
|
||||
__ Stop("Not using Dart dynamic modules");
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
// R5: Contains an ICData.
|
||||
|
||||
@@ -1134,7 +1134,7 @@ void StubCodeCompiler::GenerateInvokeDartCodeStub() {
|
||||
// ESP + 12: address of first argument.
|
||||
// ESP + 16 : current thread.
|
||||
void StubCodeCompiler::GenerateInvokeDartCodeFromBytecodeStub() {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
const intptr_t kTargetCodeOffset = 2 * target::kWordSize;
|
||||
const intptr_t kArgumentsDescOffset = 3 * target::kWordSize;
|
||||
const intptr_t kArgumentsOffset = 4 * target::kWordSize;
|
||||
@@ -1254,7 +1254,7 @@ void StubCodeCompiler::GenerateInvokeDartCodeFromBytecodeStub() {
|
||||
|
||||
#else
|
||||
__ Stop("Not using Dart dynamic modules");
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
// Helper to generate space allocation of context stub.
|
||||
@@ -2432,7 +2432,7 @@ void StubCodeCompiler::GenerateLazyCompileStub() {
|
||||
// EDX: Arguments descriptor.
|
||||
// EAX: Function.
|
||||
void StubCodeCompiler::GenerateInterpretCallStub() {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
__ EnterStubFrame();
|
||||
|
||||
@@ -2505,7 +2505,7 @@ void StubCodeCompiler::GenerateInterpretCallStub() {
|
||||
|
||||
#else
|
||||
__ Stop("Not using Dart dynamic modules");
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
// ECX: Contains an ICData.
|
||||
|
||||
@@ -619,6 +619,20 @@ void StubCodeCompiler::GenerateCallStaticFunctionStub() {
|
||||
Address(SP, 1 * target::kWordSize)); // Preserve args descriptor.
|
||||
__ sx(ZR, Address(SP, 0 * target::kWordSize)); // Result slot.
|
||||
__ CallRuntime(kPatchStaticCallRuntimeEntry, 0);
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && defined(DART_SHOREBIRD_INTERPRETER)
|
||||
__ lx(FUNCTION_REG, Address(SP, 0 * target::kWordSize)); // Result.
|
||||
__ lx(ARGS_DESC_REG,
|
||||
Address(SP, 1 * target::kWordSize)); // Restore args descriptor.
|
||||
__ addi(SP, SP, 2 * target::kWordSize);
|
||||
__ LeaveStubFrame();
|
||||
// Jump through Function::entry_point so bytecode-attached functions enter
|
||||
// the interpreter without rewriting executable AOT instructions.
|
||||
__ LoadCompressedFieldFromOffset(CODE_REG, FUNCTION_REG,
|
||||
target::Function::code_offset());
|
||||
__ LoadFieldFromOffset(TMP, FUNCTION_REG,
|
||||
target::Function::entry_point_offset());
|
||||
__ jr(TMP);
|
||||
#else
|
||||
__ lx(CODE_REG, Address(SP, 0 * target::kWordSize)); // Result.
|
||||
__ lx(ARGS_DESC_REG,
|
||||
Address(SP, 1 * target::kWordSize)); // Restore args descriptor.
|
||||
@@ -627,6 +641,7 @@ void StubCodeCompiler::GenerateCallStaticFunctionStub() {
|
||||
// Jump to the dart function.
|
||||
__ LoadFieldFromOffset(TMP, CODE_REG, target::Code::entry_point_offset());
|
||||
__ jr(TMP);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Called from a static call only when an invalid code has been entered
|
||||
|
||||
@@ -804,6 +804,16 @@ void StubCodeCompiler::GenerateCallStaticFunctionStub() {
|
||||
// Setup space on stack for return value.
|
||||
__ pushq(Immediate(0));
|
||||
__ CallRuntime(kPatchStaticCallRuntimeEntry, 0);
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && defined(DART_SHOREBIRD_INTERPRETER)
|
||||
__ popq(FUNCTION_REG); // Get Function object result.
|
||||
__ popq(ARGS_DESC_REG); // Restore arguments descriptor array.
|
||||
// Remove the stub frame as we are about to jump to the dart function.
|
||||
__ LeaveStubFrame();
|
||||
|
||||
__ LoadCompressed(
|
||||
CODE_REG, FieldAddress(FUNCTION_REG, target::Function::code_offset()));
|
||||
__ jmp(FieldAddress(FUNCTION_REG, target::Function::entry_point_offset()));
|
||||
#else
|
||||
__ popq(CODE_REG); // Get Code object result.
|
||||
__ popq(ARGS_DESC_REG); // Restore arguments descriptor array.
|
||||
// Remove the stub frame as we are about to jump to the dart function.
|
||||
@@ -811,6 +821,7 @@ void StubCodeCompiler::GenerateCallStaticFunctionStub() {
|
||||
|
||||
__ movq(RBX, FieldAddress(CODE_REG, target::Code::entry_point_offset()));
|
||||
__ jmp(RBX);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Called from a static call only when an invalid code has been entered
|
||||
@@ -1606,7 +1617,7 @@ void StubCodeCompiler::GenerateInvokeDartCodeStub() {
|
||||
// RDX : address of first argument.
|
||||
// RCX : current thread.
|
||||
void StubCodeCompiler::GenerateInvokeDartCodeFromBytecodeStub() {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
__ EnterFrame(0);
|
||||
|
||||
const Register kTargetReg = CallingConventions::kArg1Reg;
|
||||
@@ -1750,7 +1761,7 @@ void StubCodeCompiler::GenerateInvokeDartCodeFromBytecodeStub() {
|
||||
|
||||
#else
|
||||
__ Stop("Not using Dart dynamic modules");
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
// Helper to generate space allocation of context stub.
|
||||
@@ -3022,7 +3033,7 @@ void StubCodeCompiler::GenerateLazyCompileStub() {
|
||||
// ARGS_DESC_REG: Arguments descriptor.
|
||||
// FUNCTION_REG: Function.
|
||||
void StubCodeCompiler::GenerateInterpretCallStub() {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
__ EnterStubFrame();
|
||||
|
||||
@@ -3070,7 +3081,7 @@ void StubCodeCompiler::GenerateInterpretCallStub() {
|
||||
__ movq(CallingConventions::kArg3Reg, R11); // Negative argc.
|
||||
__ movq(CallingConventions::kArg4Reg, R12); // Argv.
|
||||
|
||||
#if defined(TARGET_OS_WINDOWS)
|
||||
#if defined(DART_TARGET_OS_WINDOWS)
|
||||
__ movq(Address(RSP, 0 * target::kWordSize), THR); // Thread.
|
||||
#else
|
||||
__ movq(CallingConventions::kArg5Reg, THR); // Thread.
|
||||
@@ -3106,7 +3117,7 @@ void StubCodeCompiler::GenerateInterpretCallStub() {
|
||||
|
||||
#else
|
||||
__ Stop("Not using Dart dynamic modules");
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
// RBX: Contains an ICData.
|
||||
|
||||
+878
-9
@@ -9,6 +9,11 @@
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#if defined(DART_ENABLE_AOT_PATCHING)
|
||||
#include <openssl/aead.h>
|
||||
#include <openssl/sha.h>
|
||||
#endif
|
||||
|
||||
#include "lib/stacktrace.h"
|
||||
#include "platform/address_sanitizer.h"
|
||||
#include "platform/assert.h"
|
||||
@@ -16,6 +21,7 @@
|
||||
#include "platform/thread_sanitizer.h"
|
||||
#include "platform/unicode.h"
|
||||
#include "vm/app_snapshot.h"
|
||||
#include "vm/base64.h"
|
||||
#include "vm/bytecode_reader.h"
|
||||
#include "vm/class_finalizer.h"
|
||||
#include "vm/compiler/jit/compiler.h"
|
||||
@@ -33,6 +39,7 @@
|
||||
#include "vm/heap/verifier.h"
|
||||
#include "vm/image_snapshot.h"
|
||||
#include "vm/isolate_reload.h"
|
||||
#include "vm/json_stream.h"
|
||||
#include "vm/kernel_isolate.h"
|
||||
#include "vm/lockers.h"
|
||||
#include "vm/mach_o.h"
|
||||
@@ -5594,7 +5601,7 @@ DART_EXPORT Dart_Handle Dart_LoadScriptFromKernel(const uint8_t* buffer,
|
||||
|
||||
DART_EXPORT Dart_Handle Dart_LoadScriptFromBytecode(const uint8_t* buffer,
|
||||
intptr_t buffer_size) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
DARTSCOPE(Thread::Current());
|
||||
API_TIMELINE_DURATION(T);
|
||||
StackZone zone(T);
|
||||
@@ -5628,9 +5635,9 @@ DART_EXPORT Dart_Handle Dart_LoadScriptFromBytecode(const uint8_t* buffer,
|
||||
return Api::NewHandle(T, library.ptr());
|
||||
#else
|
||||
return Api::NewError(
|
||||
"%s: Cannot load bytecode as dynamic modules are disabled.",
|
||||
"%s: Cannot load bytecode because the bytecode interpreter is disabled.",
|
||||
CURRENT_FUNC);
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle
|
||||
@@ -5992,7 +5999,7 @@ DART_EXPORT Dart_Handle Dart_LoadLibrary(Dart_Handle kernel_buffer) {
|
||||
|
||||
DART_EXPORT Dart_Handle
|
||||
Dart_LoadLibraryFromBytecode(Dart_Handle bytecode_buffer) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
DARTSCOPE(Thread::Current());
|
||||
const ExternalTypedData& td =
|
||||
Api::UnwrapExternalTypedDataHandle(Z, bytecode_buffer);
|
||||
@@ -6008,9 +6015,101 @@ Dart_LoadLibraryFromBytecode(Dart_Handle bytecode_buffer) {
|
||||
return Api::NewHandle(T, Class::Handle(function.Owner()).library());
|
||||
#else
|
||||
return Api::NewError(
|
||||
"%s: Cannot load bytecode as dynamic modules are disabled.",
|
||||
"%s: Cannot load bytecode because the bytecode interpreter is disabled.",
|
||||
CURRENT_FUNC);
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
DART_EXPORT Dart_Handle
|
||||
Dart_ReloadBytecodePatch(const uint8_t* bytecode_buffer,
|
||||
intptr_t bytecode_buffer_size) {
|
||||
#if defined(DART_SHOREBIRD_INTERPRETER) && defined(DART_BYTECODE_INTERPRETER) && \
|
||||
defined(DART_PRECOMPILED_RUNTIME)
|
||||
Thread* thread = Thread::Current();
|
||||
DARTSCOPE(thread);
|
||||
API_TIMELINE_DURATION(thread);
|
||||
|
||||
if (bytecode_buffer == nullptr) {
|
||||
RETURN_NULL_ERROR(bytecode_buffer);
|
||||
}
|
||||
if (bytecode_buffer_size <= 0) {
|
||||
return Api::NewError("Bytecode patch buffer must not be empty.");
|
||||
}
|
||||
if (!Dart_IsBytecode(bytecode_buffer, bytecode_buffer_size)) {
|
||||
return Api::NewError(
|
||||
"Bytecode patch buffer is not a Dart bytecode program.");
|
||||
}
|
||||
|
||||
uint8_t* owned_buffer = reinterpret_cast<uint8_t*>(
|
||||
malloc(Utils::Maximum<intptr_t>(bytecode_buffer_size, 1)));
|
||||
if (owned_buffer == nullptr) {
|
||||
return Api::NewError("Failed to allocate Dart bytecode patch buffer.");
|
||||
}
|
||||
memmove(owned_buffer, bytecode_buffer, bytecode_buffer_size);
|
||||
|
||||
const ExternalTypedData& typed_data = ExternalTypedData::Handle(
|
||||
thread->zone(), ExternalTypedData::New(kExternalTypedDataUint8ArrayCid,
|
||||
owned_buffer,
|
||||
bytecode_buffer_size));
|
||||
intptr_t installed_functions = 0;
|
||||
{
|
||||
SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
|
||||
bytecode::BytecodeLoader loader(thread, typed_data);
|
||||
installed_functions = loader.LoadBytecodePatch();
|
||||
}
|
||||
|
||||
if (installed_functions == 0) {
|
||||
free(owned_buffer);
|
||||
return Api::NewError(
|
||||
"Dart bytecode patch did not match any loaded app functions.");
|
||||
}
|
||||
return Api::Success();
|
||||
#elif defined(DART_SUPPORT_RELOAD) && defined(DART_BYTECODE_INTERPRETER)
|
||||
Thread* thread = Thread::Current();
|
||||
DARTSCOPE(thread);
|
||||
API_TIMELINE_DURATION(thread);
|
||||
|
||||
if (bytecode_buffer == nullptr) {
|
||||
RETURN_NULL_ERROR(bytecode_buffer);
|
||||
}
|
||||
if (bytecode_buffer_size <= 0) {
|
||||
return Api::NewError("Bytecode patch buffer must not be empty.");
|
||||
}
|
||||
if (!Dart_IsBytecode(bytecode_buffer, bytecode_buffer_size)) {
|
||||
return Api::NewError(
|
||||
"Bytecode patch buffer is not a Dart bytecode program.");
|
||||
}
|
||||
|
||||
IsolateGroup* isolate_group = thread->isolate_group();
|
||||
CHECK_ISOLATE_GROUP(isolate_group);
|
||||
if (isolate_group->IsReloading()) {
|
||||
return Api::NewError("A Dart bytecode patch reload is already active.");
|
||||
}
|
||||
if (!isolate_group->CanReload()) {
|
||||
return Api::NewError(
|
||||
"The current isolate group cannot apply a Dart bytecode patch reload.");
|
||||
}
|
||||
|
||||
uint8_t* owned_buffer = reinterpret_cast<uint8_t*>(
|
||||
malloc(Utils::Maximum<intptr_t>(bytecode_buffer_size, 1)));
|
||||
if (owned_buffer == nullptr) {
|
||||
return Api::NewError("Failed to allocate Dart bytecode patch buffer.");
|
||||
}
|
||||
memmove(owned_buffer, bytecode_buffer, bytecode_buffer_size);
|
||||
|
||||
JSONStream js;
|
||||
const bool success = isolate_group->ReloadKernel(
|
||||
&js, /*force_reload=*/false, owned_buffer, bytecode_buffer_size);
|
||||
if (!success) {
|
||||
return Api::NewError("Dart bytecode patch reload failed: %s",
|
||||
js.ToCString());
|
||||
}
|
||||
return Api::Success();
|
||||
#else
|
||||
return Api::NewError(
|
||||
"%s: Dart bytecode patch reload is not enabled in this VM.",
|
||||
CURRENT_FUNC);
|
||||
#endif // defined(DART_SUPPORT_RELOAD) && defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
// Finalizes classes and invokes Dart core library function that completes
|
||||
@@ -6721,9 +6820,10 @@ static void CreateAppAOTSnapshotHelper(
|
||||
};
|
||||
|
||||
Dwarf* const dwarf =
|
||||
(format == Dart_AotBinaryFormat_Assembly || strip) ? nullptr
|
||||
: generate_debug ? debug_dwarf
|
||||
: new (Z) Dwarf(Z, deobfuscation_trie, identifier);
|
||||
(format == Dart_AotBinaryFormat_Assembly || strip)
|
||||
? nullptr
|
||||
: generate_debug ? debug_dwarf
|
||||
: new (Z) Dwarf(Z, deobfuscation_trie, identifier);
|
||||
SharedObjectWriter* so = nullptr;
|
||||
if (format == Dart_AotBinaryFormat_Elf) {
|
||||
so = new (Z)
|
||||
@@ -7122,6 +7222,126 @@ Dart_CreateAppJITSnapshotAsBlobs(uint8_t** isolate_snapshot_data_buffer,
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_IA32)
|
||||
static bool IsObfuscationNameChar(char c) {
|
||||
return (('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z'));
|
||||
}
|
||||
|
||||
static intptr_t ObfuscationNameCharRank(char c) {
|
||||
if (('a' <= c) && (c <= 'z')) {
|
||||
return c - 'a';
|
||||
}
|
||||
ASSERT(('A' <= c) && (c <= 'Z'));
|
||||
return 26 + (c - 'A');
|
||||
}
|
||||
|
||||
static bool IsObfuscationNameGreater(const char* left, const char* right) {
|
||||
const intptr_t left_length = strlen(left);
|
||||
const intptr_t right_length = strlen(right);
|
||||
if (left_length != right_length) {
|
||||
return left_length > right_length;
|
||||
}
|
||||
for (intptr_t i = left_length - 1; i >= 0; i--) {
|
||||
const intptr_t left_rank = ObfuscationNameCharRank(left[i]);
|
||||
const intptr_t right_rank = ObfuscationNameCharRank(right[i]);
|
||||
if (left_rank != right_rank) {
|
||||
return left_rank > right_rank;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ExtractObfuscationRenameStem(const char* rename,
|
||||
char* stem,
|
||||
intptr_t stem_length) {
|
||||
ASSERT(stem_length > 0);
|
||||
const char* cursor = rename;
|
||||
if (strncmp(cursor, "get:", 4) == 0 || strncmp(cursor, "set:", 4) == 0) {
|
||||
cursor += 4;
|
||||
}
|
||||
if (*cursor == '_') {
|
||||
cursor++;
|
||||
}
|
||||
intptr_t written = 0;
|
||||
while (*cursor != '\0' && *cursor != '@') {
|
||||
if (!IsObfuscationNameChar(*cursor)) {
|
||||
return false;
|
||||
}
|
||||
if (written >= stem_length - 1) {
|
||||
return false;
|
||||
}
|
||||
stem[written++] = *cursor++;
|
||||
}
|
||||
if (written == 0) {
|
||||
return false;
|
||||
}
|
||||
stem[written] = '\0';
|
||||
return true;
|
||||
}
|
||||
#endif // defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_IA32)
|
||||
|
||||
DART_EXPORT Dart_Handle Dart_SetObfuscationMap(const char* const* map,
|
||||
intptr_t map_length) {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
return Api::NewError("No obfuscation map to load on an AOT runtime.");
|
||||
#elif !defined(DART_PRECOMPILER)
|
||||
return Api::NewError("Obfuscation is only supported for AOT compiler.");
|
||||
#elif defined(TARGET_ARCH_IA32)
|
||||
return Api::NewError("Obfuscation is not supported on IA32.");
|
||||
#else
|
||||
Thread* thread = Thread::Current();
|
||||
DARTSCOPE(thread);
|
||||
auto isolate_group = thread->isolate_group();
|
||||
|
||||
if (map == nullptr) {
|
||||
RETURN_NULL_ERROR(map);
|
||||
}
|
||||
if (map_length < 0 || (map_length % 2) != 0) {
|
||||
return Api::NewError(
|
||||
"Obfuscation map must contain an even number of strings.");
|
||||
}
|
||||
if (!isolate_group->obfuscate()) {
|
||||
return Api::NewError(
|
||||
"Obfuscation map can only be loaded when --obfuscate is enabled.");
|
||||
}
|
||||
|
||||
const intptr_t map_entries = map_length / 2;
|
||||
const intptr_t initial_capacity =
|
||||
Utils::Maximum(map_entries, static_cast<intptr_t>(16));
|
||||
ObfuscationMap renames(
|
||||
HashTables::New<ObfuscationMap>(initial_capacity, Heap::kOld));
|
||||
String& key = String::Handle(Z);
|
||||
String& value = String::Handle(Z);
|
||||
char last_name[100];
|
||||
last_name[0] = '\0';
|
||||
|
||||
for (intptr_t i = 0; i < map_length; i += 2) {
|
||||
if (map[i] == nullptr || map[i + 1] == nullptr) {
|
||||
renames.Release();
|
||||
return Api::NewError("Obfuscation map contains a null string.");
|
||||
}
|
||||
key = Symbols::New(thread, map[i]);
|
||||
value = Symbols::New(thread, map[i + 1]);
|
||||
renames.UpdateOrInsert(key, value);
|
||||
|
||||
if (strcmp(map[i], map[i + 1]) != 0) {
|
||||
char stem[100];
|
||||
if (ExtractObfuscationRenameStem(map[i + 1], stem, sizeof(stem)) &&
|
||||
(last_name[0] == '\0' || IsObfuscationNameGreater(stem, last_name))) {
|
||||
strncpy(last_name, stem, sizeof(last_name));
|
||||
last_name[sizeof(last_name) - 1] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Array& state = Array::Handle(Z, Array::New(2, Heap::kOld));
|
||||
state.SetAt(0, String::Handle(Z, String::New(last_name, Heap::kOld)));
|
||||
state.SetAt(1, renames.Release());
|
||||
isolate_group->object_store()->set_obfuscation_map(state);
|
||||
return Api::Success();
|
||||
#endif
|
||||
}
|
||||
|
||||
DART_EXPORT Dart_Handle Dart_GetObfuscationMap(uint8_t** buffer,
|
||||
intptr_t* buffer_length) {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
@@ -7163,6 +7383,655 @@ DART_EXPORT Dart_Handle Dart_GetObfuscationMap(uint8_t** buffer,
|
||||
#endif
|
||||
}
|
||||
|
||||
Dart_AotPatchKeyCallback g_aot_patch_key_callback = nullptr;
|
||||
|
||||
#if defined(DART_ENABLE_AOT_PATCHING) && defined(DART_DYNAMIC_MODULES)
|
||||
#error DART_ENABLE_AOT_PATCHING must be built without DART_DYNAMIC_MODULES.
|
||||
#endif
|
||||
|
||||
#if defined(DART_ENABLE_AOT_PATCHING)
|
||||
static constexpr const char* kAotPatchRuntimeModeNativeAot = "native-aot";
|
||||
static constexpr const char* kAotPatchRuntimeModeInterpreter =
|
||||
"dart-bytecode-interpreter";
|
||||
static constexpr const char* kAotPatchRuntimeModeDynamicModules =
|
||||
"dart-dynamic-modules";
|
||||
static constexpr const char* kAotPatchRuntimeModeDynamicModulesLegacy =
|
||||
"dynamic-modules";
|
||||
static constexpr const char* kAotPatchPayloadKindEmpty = "empty";
|
||||
static constexpr const char* kAotPatchPayloadKindFullSnapshot =
|
||||
"full-snapshot";
|
||||
static constexpr const char* kAotPatchPayloadKindBinaryDiff = "binary-diff-v1";
|
||||
|
||||
struct AotPatchJsonString {
|
||||
const char* chars;
|
||||
intptr_t length;
|
||||
};
|
||||
|
||||
static bool IsAotPatchJsonWhitespace(char c) {
|
||||
return c == ' ' || c == '\n' || c == '\r' || c == '\t';
|
||||
}
|
||||
|
||||
static void SkipAotPatchJsonWhitespace(const char* json,
|
||||
intptr_t json_length,
|
||||
intptr_t* cursor) {
|
||||
while (*cursor < json_length && IsAotPatchJsonWhitespace(json[*cursor])) {
|
||||
(*cursor)++;
|
||||
}
|
||||
}
|
||||
|
||||
static bool ParseAotPatchJsonString(const char* json,
|
||||
intptr_t json_length,
|
||||
intptr_t* cursor,
|
||||
AotPatchJsonString* out) {
|
||||
if (*cursor >= json_length || json[*cursor] != '"') {
|
||||
return false;
|
||||
}
|
||||
(*cursor)++;
|
||||
const intptr_t start = *cursor;
|
||||
while (*cursor < json_length) {
|
||||
const char c = json[*cursor];
|
||||
if (c == '\\') {
|
||||
// Open patch artifacts use stable ASCII metadata. Reject escaped fields
|
||||
// in the VM validator instead of accepting ambiguous raw comparisons.
|
||||
return false;
|
||||
}
|
||||
if (c == '"') {
|
||||
out->chars = json + start;
|
||||
out->length = *cursor - start;
|
||||
(*cursor)++;
|
||||
return true;
|
||||
}
|
||||
if (static_cast<unsigned char>(c) < 0x20) {
|
||||
return false;
|
||||
}
|
||||
(*cursor)++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool AotPatchJsonStringEquals(const AotPatchJsonString& value,
|
||||
const char* expected) {
|
||||
const intptr_t expected_length = strlen(expected);
|
||||
return value.length == expected_length &&
|
||||
strncmp(value.chars, expected, value.length) == 0;
|
||||
}
|
||||
|
||||
static bool FindAotPatchJsonString(const char* json,
|
||||
intptr_t json_length,
|
||||
const char* key,
|
||||
AotPatchJsonString* out) {
|
||||
intptr_t cursor = 0;
|
||||
while (cursor < json_length) {
|
||||
if (json[cursor] != '"') {
|
||||
cursor++;
|
||||
continue;
|
||||
}
|
||||
|
||||
AotPatchJsonString current_key;
|
||||
if (!ParseAotPatchJsonString(json, json_length, &cursor, ¤t_key)) {
|
||||
return false;
|
||||
}
|
||||
SkipAotPatchJsonWhitespace(json, json_length, &cursor);
|
||||
if (cursor >= json_length || json[cursor] != ':') {
|
||||
continue;
|
||||
}
|
||||
cursor++;
|
||||
SkipAotPatchJsonWhitespace(json, json_length, &cursor);
|
||||
|
||||
if (!AotPatchJsonStringEquals(current_key, key)) {
|
||||
continue;
|
||||
}
|
||||
return ParseAotPatchJsonString(json, json_length, &cursor, out);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static Dart_Handle ValidateAotPatchJsonField(const char* json,
|
||||
intptr_t json_length,
|
||||
const char* field,
|
||||
const char* expected) {
|
||||
AotPatchJsonString actual;
|
||||
if (!FindAotPatchJsonString(json, json_length, field, &actual)) {
|
||||
return Api::NewError("AOT patch artifact is missing field \"%s\".", field);
|
||||
}
|
||||
if (!AotPatchJsonStringEquals(actual, expected)) {
|
||||
return Api::NewError("AOT patch artifact field \"%s\" does not match.",
|
||||
field);
|
||||
}
|
||||
return Api::Success();
|
||||
}
|
||||
|
||||
static char* CopyAotPatchJsonString(Thread* thread,
|
||||
const AotPatchJsonString& value) {
|
||||
char* copy = thread->zone()->Alloc<char>(value.length + 1);
|
||||
memmove(copy, value.chars, value.length);
|
||||
copy[value.length] = '\0';
|
||||
return copy;
|
||||
}
|
||||
|
||||
static bool AotPatchRuntimeModeNameEquals(const char* actual,
|
||||
const char* expected) {
|
||||
return actual != nullptr && strcmp(actual, expected) == 0;
|
||||
}
|
||||
|
||||
static bool IsAotPatchRuntimeModeDynamicModules(const char* runtime_mode) {
|
||||
return AotPatchRuntimeModeNameEquals(runtime_mode,
|
||||
kAotPatchRuntimeModeDynamicModules) ||
|
||||
AotPatchRuntimeModeNameEquals(
|
||||
runtime_mode, kAotPatchRuntimeModeDynamicModulesLegacy);
|
||||
}
|
||||
|
||||
static bool IsAotPatchRuntimeModeDynamicModules(
|
||||
const AotPatchJsonString& runtime_mode) {
|
||||
return AotPatchJsonStringEquals(runtime_mode,
|
||||
kAotPatchRuntimeModeDynamicModules) ||
|
||||
AotPatchJsonStringEquals(runtime_mode,
|
||||
kAotPatchRuntimeModeDynamicModulesLegacy);
|
||||
}
|
||||
|
||||
static bool IsAotPatchRuntimeModeInterpreter(const char* runtime_mode) {
|
||||
return AotPatchRuntimeModeNameEquals(runtime_mode,
|
||||
kAotPatchRuntimeModeInterpreter);
|
||||
}
|
||||
|
||||
static bool IsAotPatchRuntimeModeInterpreter(
|
||||
const AotPatchJsonString& runtime_mode) {
|
||||
return AotPatchJsonStringEquals(runtime_mode,
|
||||
kAotPatchRuntimeModeInterpreter);
|
||||
}
|
||||
|
||||
static bool IsAotPatchRuntimeModeSupported(const char* runtime_mode) {
|
||||
return AotPatchRuntimeModeNameEquals(runtime_mode,
|
||||
kAotPatchRuntimeModeNativeAot) ||
|
||||
AotPatchRuntimeModeNameEquals(runtime_mode,
|
||||
kAotPatchRuntimeModeInterpreter);
|
||||
}
|
||||
|
||||
static bool IsAotPatchRuntimeModeSupported(
|
||||
const AotPatchJsonString& runtime_mode) {
|
||||
return AotPatchJsonStringEquals(runtime_mode,
|
||||
kAotPatchRuntimeModeNativeAot) ||
|
||||
AotPatchJsonStringEquals(runtime_mode,
|
||||
kAotPatchRuntimeModeInterpreter);
|
||||
}
|
||||
|
||||
static Dart_Handle ValidateAotPatchRuntimeMode(
|
||||
const char* json,
|
||||
intptr_t json_length,
|
||||
const Dart_AotPatchInstallOptions* options) {
|
||||
AotPatchJsonString runtime_mode;
|
||||
const bool has_runtime_mode =
|
||||
FindAotPatchJsonString(json, json_length, "runtime_mode", &runtime_mode);
|
||||
|
||||
if (options->runtime_mode != nullptr) {
|
||||
if (IsAotPatchRuntimeModeDynamicModules(options->runtime_mode)) {
|
||||
return Api::NewError(
|
||||
"DART_DYNAMIC_MODULES is not supported for AOT patch artifacts.");
|
||||
}
|
||||
if (!IsAotPatchRuntimeModeSupported(options->runtime_mode)) {
|
||||
return Api::NewError("Unsupported AOT patch runtime mode \"%s\".",
|
||||
options->runtime_mode);
|
||||
}
|
||||
if (has_runtime_mode) {
|
||||
if (!AotPatchJsonStringEquals(runtime_mode, options->runtime_mode)) {
|
||||
return Api::NewError(
|
||||
"AOT patch artifact field \"runtime_mode\" does not match.");
|
||||
}
|
||||
} else if (!AotPatchRuntimeModeNameEquals(options->runtime_mode,
|
||||
kAotPatchRuntimeModeNativeAot)) {
|
||||
return Api::NewError(
|
||||
"AOT patch artifact is missing field "
|
||||
"\"runtime_mode\".");
|
||||
}
|
||||
}
|
||||
|
||||
if (has_runtime_mode) {
|
||||
if (IsAotPatchRuntimeModeDynamicModules(runtime_mode)) {
|
||||
return Api::NewError(
|
||||
"DART_DYNAMIC_MODULES is not supported for AOT patch artifacts.");
|
||||
}
|
||||
if (!IsAotPatchRuntimeModeSupported(runtime_mode)) {
|
||||
return Api::NewError("Unsupported AOT patch runtime mode.");
|
||||
}
|
||||
}
|
||||
|
||||
const bool is_native_aot =
|
||||
!has_runtime_mode ||
|
||||
AotPatchJsonStringEquals(runtime_mode, kAotPatchRuntimeModeNativeAot);
|
||||
if (strcmp(options->target_os, "ios") == 0 && is_native_aot) {
|
||||
return Api::NewError(
|
||||
"iOS AOT patches must use the no-DDM interpreter runtime mode.");
|
||||
}
|
||||
return Api::Success();
|
||||
}
|
||||
|
||||
static bool IsAotPatchPayloadKindSupported(
|
||||
const AotPatchJsonString& payload_kind) {
|
||||
return AotPatchJsonStringEquals(payload_kind, kAotPatchPayloadKindEmpty) ||
|
||||
AotPatchJsonStringEquals(payload_kind,
|
||||
kAotPatchPayloadKindFullSnapshot) ||
|
||||
AotPatchJsonStringEquals(payload_kind,
|
||||
kAotPatchPayloadKindBinaryDiff);
|
||||
}
|
||||
|
||||
static bool AotPatchEffectiveRuntimeModeIsInterpreter(
|
||||
const char* json,
|
||||
intptr_t json_length,
|
||||
const Dart_AotPatchInstallOptions* options) {
|
||||
if (options->runtime_mode != nullptr) {
|
||||
return IsAotPatchRuntimeModeInterpreter(options->runtime_mode);
|
||||
}
|
||||
|
||||
AotPatchJsonString runtime_mode;
|
||||
return FindAotPatchJsonString(json, json_length, "runtime_mode",
|
||||
&runtime_mode) &&
|
||||
IsAotPatchRuntimeModeInterpreter(runtime_mode);
|
||||
}
|
||||
|
||||
static Dart_Handle ValidateAotPatchPayloadKind(
|
||||
const char* json,
|
||||
intptr_t json_length,
|
||||
const Dart_AotPatchInstallOptions* options) {
|
||||
const bool is_interpreter =
|
||||
AotPatchEffectiveRuntimeModeIsInterpreter(json, json_length, options);
|
||||
AotPatchJsonString payload_kind;
|
||||
if (!FindAotPatchJsonString(json, json_length, "payload_kind",
|
||||
&payload_kind)) {
|
||||
if (is_interpreter) {
|
||||
return Api::NewError(
|
||||
"Dart bytecode interpreter AOT patches must declare payload_kind "
|
||||
"\"full-snapshot\".");
|
||||
}
|
||||
return Api::Success();
|
||||
}
|
||||
if (!IsAotPatchPayloadKindSupported(payload_kind)) {
|
||||
return Api::NewError("Unsupported AOT patch payload kind.");
|
||||
}
|
||||
if (is_interpreter &&
|
||||
!AotPatchJsonStringEquals(payload_kind,
|
||||
kAotPatchPayloadKindFullSnapshot)) {
|
||||
return Api::NewError(
|
||||
"Dart bytecode interpreter AOT patches must use payload_kind "
|
||||
"\"full-snapshot\" until runtime reconstruction is available.");
|
||||
}
|
||||
return Api::Success();
|
||||
}
|
||||
|
||||
struct AotPatchOwnedBuffer {
|
||||
uint8_t* data = nullptr;
|
||||
intptr_t length = 0;
|
||||
|
||||
~AotPatchOwnedBuffer() { free(data); }
|
||||
|
||||
uint8_t* Release() {
|
||||
uint8_t* result = data;
|
||||
data = nullptr;
|
||||
length = 0;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
static Dart_Handle DecodeAotPatchBase64(Thread* thread,
|
||||
const AotPatchJsonString& value,
|
||||
const char* field,
|
||||
AotPatchOwnedBuffer* out) {
|
||||
if (value.length == 0) {
|
||||
out->data = reinterpret_cast<uint8_t*>(malloc(1));
|
||||
out->length = 0;
|
||||
if (out->data == nullptr) {
|
||||
return Api::NewError("Unable to allocate AOT patch field \"%s\".", field);
|
||||
}
|
||||
return Api::Success();
|
||||
}
|
||||
|
||||
intptr_t decoded_length = 0;
|
||||
uint8_t* decoded =
|
||||
DecodeBase64(CopyAotPatchJsonString(thread, value), &decoded_length);
|
||||
if (decoded == nullptr) {
|
||||
return Api::NewError("AOT patch field \"%s\" is not valid base64.", field);
|
||||
}
|
||||
out->data = decoded;
|
||||
out->length = decoded_length;
|
||||
return Api::Success();
|
||||
}
|
||||
|
||||
static intptr_t AotPatchHexDigit(char c) {
|
||||
if ('0' <= c && c <= '9') return c - '0';
|
||||
if ('a' <= c && c <= 'f') return 10 + (c - 'a');
|
||||
if ('A' <= c && c <= 'F') return 10 + (c - 'A');
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool AotPatchDigestEqualsHex(const uint8_t* digest,
|
||||
intptr_t digest_length,
|
||||
const AotPatchJsonString& expected) {
|
||||
if (expected.length != digest_length * 2) {
|
||||
return false;
|
||||
}
|
||||
for (intptr_t i = 0; i < digest_length; i++) {
|
||||
const intptr_t high = AotPatchHexDigit(expected.chars[i * 2]);
|
||||
const intptr_t low = AotPatchHexDigit(expected.chars[(i * 2) + 1]);
|
||||
if (high < 0 || low < 0) {
|
||||
return false;
|
||||
}
|
||||
if (digest[i] != static_cast<uint8_t>((high << 4) | low)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void AppendAotPatchJsonString(ZoneTextBuffer* buffer,
|
||||
const AotPatchJsonString& value) {
|
||||
buffer->AddChar('"');
|
||||
buffer->AddEscapedUTF8(value.chars, value.length);
|
||||
buffer->AddChar('"');
|
||||
}
|
||||
|
||||
static Dart_Handle AppendAotPatchMetadataField(ZoneTextBuffer* buffer,
|
||||
const char* json,
|
||||
intptr_t json_length,
|
||||
const char* field,
|
||||
bool required,
|
||||
bool* first) {
|
||||
AotPatchJsonString value;
|
||||
if (!FindAotPatchJsonString(json, json_length, field, &value)) {
|
||||
if (required) {
|
||||
return Api::NewError("AOT patch artifact is missing field \"%s\".",
|
||||
field);
|
||||
}
|
||||
return Api::Success();
|
||||
}
|
||||
if (!*first) {
|
||||
buffer->AddChar(',');
|
||||
}
|
||||
*first = false;
|
||||
buffer->Printf("\"%s\":", field);
|
||||
AppendAotPatchJsonString(buffer, value);
|
||||
return Api::Success();
|
||||
}
|
||||
|
||||
static Dart_Handle BuildAotPatchMetadataAad(const char* json,
|
||||
intptr_t json_length,
|
||||
ZoneTextBuffer* out) {
|
||||
bool first = true;
|
||||
out->AddChar('{');
|
||||
#define APPEND_FIELD(name, required) \
|
||||
do { \
|
||||
Dart_Handle append_result = AppendAotPatchMetadataField( \
|
||||
out, json, json_length, name, required, &first); \
|
||||
if (Api::IsError(append_result)) return append_result; \
|
||||
} while (0)
|
||||
|
||||
APPEND_FIELD("app_build_id", true);
|
||||
APPEND_FIELD("app_id", true);
|
||||
APPEND_FIELD("base_flavor_id", false);
|
||||
APPEND_FIELD("base_license_type", false);
|
||||
APPEND_FIELD("base_snapshot_hash", true);
|
||||
APPEND_FIELD("flavor_id", true);
|
||||
APPEND_FIELD("license_type", true);
|
||||
APPEND_FIELD("obfuscation_map_hash", false);
|
||||
APPEND_FIELD("offline_expires_at", false);
|
||||
APPEND_FIELD("patch_snapshot_hash", true);
|
||||
APPEND_FIELD("runtime_mode", false);
|
||||
APPEND_FIELD("sdk_hash", true);
|
||||
APPEND_FIELD("target_arch", true);
|
||||
APPEND_FIELD("target_os", true);
|
||||
#undef APPEND_FIELD
|
||||
out->AddChar('}');
|
||||
return Api::Success();
|
||||
}
|
||||
#endif // defined(DART_ENABLE_AOT_PATCHING)
|
||||
|
||||
DART_EXPORT bool Dart_AotPatchingEnabled() {
|
||||
#if defined(DART_ENABLE_AOT_PATCHING)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
DART_EXPORT void Dart_SetAotPatchKeyCallback(
|
||||
Dart_AotPatchKeyCallback callback) {
|
||||
g_aot_patch_key_callback = callback;
|
||||
}
|
||||
|
||||
DART_EXPORT Dart_Handle
|
||||
Dart_InstallAotPatch(const uint8_t* patch_buffer,
|
||||
intptr_t patch_buffer_length,
|
||||
const Dart_AotPatchInstallOptions* options,
|
||||
uint8_t** patch_payload_buffer,
|
||||
intptr_t* patch_payload_length) {
|
||||
#if !defined(DART_ENABLE_AOT_PATCHING)
|
||||
return Api::NewError(
|
||||
"Compact AOT patching is not enabled in this VM. Rebuild with "
|
||||
"dart_enable_aot_patching=true.");
|
||||
#else
|
||||
Thread* thread = Thread::Current();
|
||||
DARTSCOPE(thread);
|
||||
API_TIMELINE_DURATION(thread);
|
||||
|
||||
if (patch_buffer == nullptr) {
|
||||
RETURN_NULL_ERROR(patch_buffer);
|
||||
}
|
||||
if (patch_buffer_length <= 0) {
|
||||
return Api::NewError("Patch buffer must not be empty.");
|
||||
}
|
||||
if (options == nullptr) {
|
||||
RETURN_NULL_ERROR(options);
|
||||
}
|
||||
if (patch_payload_buffer == nullptr) {
|
||||
RETURN_NULL_ERROR(patch_payload_buffer);
|
||||
}
|
||||
if (patch_payload_length == nullptr) {
|
||||
RETURN_NULL_ERROR(patch_payload_length);
|
||||
}
|
||||
*patch_payload_buffer = nullptr;
|
||||
*patch_payload_length = 0;
|
||||
if (options->app_id == nullptr || options->app_build_id == nullptr ||
|
||||
options->flavor_id == nullptr || options->license_type == nullptr ||
|
||||
options->sdk_hash == nullptr || options->base_snapshot_hash == nullptr ||
|
||||
options->patch_snapshot_hash == nullptr ||
|
||||
options->target_os == nullptr || options->target_arch == nullptr) {
|
||||
return Api::NewError("AOT patch install options are incomplete.");
|
||||
}
|
||||
if (g_aot_patch_key_callback == nullptr) {
|
||||
return Api::NewError("No AOT patch AES key callback has been configured.");
|
||||
}
|
||||
|
||||
const char* json = reinterpret_cast<const char*>(patch_buffer);
|
||||
Dart_Handle result = ValidateAotPatchJsonField(
|
||||
json, patch_buffer_length, "format", "open-aot-vmcode-encrypted-v1");
|
||||
if (Api::IsError(result)) return result;
|
||||
|
||||
result = ValidateAotPatchJsonField(json, patch_buffer_length, "app_id",
|
||||
options->app_id);
|
||||
if (Api::IsError(result)) return result;
|
||||
result = ValidateAotPatchJsonField(json, patch_buffer_length, "app_build_id",
|
||||
options->app_build_id);
|
||||
if (Api::IsError(result)) return result;
|
||||
if (options->base_flavor_id != nullptr) {
|
||||
result = ValidateAotPatchJsonField(
|
||||
json, patch_buffer_length, "base_flavor_id", options->base_flavor_id);
|
||||
if (Api::IsError(result)) return result;
|
||||
}
|
||||
if (options->base_license_type != nullptr) {
|
||||
result = ValidateAotPatchJsonField(json, patch_buffer_length,
|
||||
"base_license_type",
|
||||
options->base_license_type);
|
||||
if (Api::IsError(result)) return result;
|
||||
}
|
||||
result = ValidateAotPatchJsonField(json, patch_buffer_length, "flavor_id",
|
||||
options->flavor_id);
|
||||
if (Api::IsError(result)) return result;
|
||||
result = ValidateAotPatchJsonField(json, patch_buffer_length, "license_type",
|
||||
options->license_type);
|
||||
if (Api::IsError(result)) return result;
|
||||
result = ValidateAotPatchJsonField(json, patch_buffer_length, "sdk_hash",
|
||||
options->sdk_hash);
|
||||
if (Api::IsError(result)) return result;
|
||||
result =
|
||||
ValidateAotPatchJsonField(json, patch_buffer_length, "base_snapshot_hash",
|
||||
options->base_snapshot_hash);
|
||||
if (Api::IsError(result)) return result;
|
||||
result = ValidateAotPatchJsonField(json, patch_buffer_length,
|
||||
"patch_snapshot_hash",
|
||||
options->patch_snapshot_hash);
|
||||
if (Api::IsError(result)) return result;
|
||||
result = ValidateAotPatchJsonField(json, patch_buffer_length, "target_os",
|
||||
options->target_os);
|
||||
if (Api::IsError(result)) return result;
|
||||
result = ValidateAotPatchJsonField(json, patch_buffer_length, "target_arch",
|
||||
options->target_arch);
|
||||
if (Api::IsError(result)) return result;
|
||||
if (options->obfuscation_map_hash != nullptr) {
|
||||
result = ValidateAotPatchJsonField(json, patch_buffer_length,
|
||||
"obfuscation_map_hash",
|
||||
options->obfuscation_map_hash);
|
||||
if (Api::IsError(result)) return result;
|
||||
}
|
||||
result = ValidateAotPatchRuntimeMode(json, patch_buffer_length, options);
|
||||
if (Api::IsError(result)) return result;
|
||||
result = ValidateAotPatchPayloadKind(json, patch_buffer_length, options);
|
||||
if (Api::IsError(result)) return result;
|
||||
|
||||
AotPatchJsonString key_id;
|
||||
if (!FindAotPatchJsonString(json, patch_buffer_length, "key_id", &key_id)) {
|
||||
return Api::NewError("AOT patch artifact is missing encryption key_id.");
|
||||
}
|
||||
if (key_id.length == 0) {
|
||||
return Api::NewError("AOT patch artifact encryption key_id is empty.");
|
||||
}
|
||||
result = ValidateAotPatchJsonField(json, patch_buffer_length, "algorithm",
|
||||
"AES-256-GCM");
|
||||
if (Api::IsError(result)) return result;
|
||||
AotPatchJsonString encrypted_payload;
|
||||
if (!FindAotPatchJsonString(json, patch_buffer_length,
|
||||
"encrypted_payload_base64", &encrypted_payload)) {
|
||||
return Api::NewError(
|
||||
"AOT patch artifact is missing encrypted_payload_base64.");
|
||||
}
|
||||
AotPatchJsonString nonce;
|
||||
if (!FindAotPatchJsonString(json, patch_buffer_length, "nonce_base64",
|
||||
&nonce)) {
|
||||
return Api::NewError("AOT patch artifact is missing nonce_base64.");
|
||||
}
|
||||
AotPatchJsonString tag;
|
||||
if (!FindAotPatchJsonString(json, patch_buffer_length, "tag_base64", &tag)) {
|
||||
return Api::NewError("AOT patch artifact is missing tag_base64.");
|
||||
}
|
||||
AotPatchJsonString aad_sha256;
|
||||
if (!FindAotPatchJsonString(json, patch_buffer_length, "aad_sha256",
|
||||
&aad_sha256)) {
|
||||
return Api::NewError("AOT patch artifact is missing aad_sha256.");
|
||||
}
|
||||
AotPatchJsonString payload_sha256;
|
||||
if (!FindAotPatchJsonString(json, patch_buffer_length, "payload_sha256",
|
||||
&payload_sha256)) {
|
||||
return Api::NewError("AOT patch artifact is missing payload_sha256.");
|
||||
}
|
||||
|
||||
AotPatchOwnedBuffer encrypted_payload_buffer;
|
||||
result = DecodeAotPatchBase64(thread, encrypted_payload,
|
||||
"encrypted_payload_base64",
|
||||
&encrypted_payload_buffer);
|
||||
if (Api::IsError(result)) return result;
|
||||
AotPatchOwnedBuffer nonce_buffer;
|
||||
result = DecodeAotPatchBase64(thread, nonce, "nonce_base64", &nonce_buffer);
|
||||
if (Api::IsError(result)) return result;
|
||||
if (nonce_buffer.length != 12) {
|
||||
return Api::NewError("AOT patch AES-GCM nonce must be 12 bytes.");
|
||||
}
|
||||
AotPatchOwnedBuffer tag_buffer;
|
||||
result = DecodeAotPatchBase64(thread, tag, "tag_base64", &tag_buffer);
|
||||
if (Api::IsError(result)) return result;
|
||||
if (tag_buffer.length != 16) {
|
||||
return Api::NewError("AOT patch AES-GCM tag must be 16 bytes.");
|
||||
}
|
||||
|
||||
ZoneTextBuffer aad(thread->zone(), 512);
|
||||
result = BuildAotPatchMetadataAad(json, patch_buffer_length, &aad);
|
||||
if (Api::IsError(result)) return result;
|
||||
uint8_t aad_digest[SHA256_DIGEST_LENGTH];
|
||||
SHA256(reinterpret_cast<const uint8_t*>(aad.buffer()), aad.length(),
|
||||
aad_digest);
|
||||
if (!AotPatchDigestEqualsHex(aad_digest, SHA256_DIGEST_LENGTH, aad_sha256)) {
|
||||
return Api::NewError("AOT patch artifact metadata AAD hash mismatch.");
|
||||
}
|
||||
|
||||
uint8_t key_buffer[32];
|
||||
intptr_t key_length = 0;
|
||||
const bool key_ok =
|
||||
g_aot_patch_key_callback(CopyAotPatchJsonString(thread, key_id),
|
||||
key_buffer, sizeof(key_buffer), &key_length);
|
||||
if (!key_ok || key_length != 32) {
|
||||
memset(key_buffer, 0, sizeof(key_buffer));
|
||||
return Api::NewError(
|
||||
"AOT patch AES key callback failed to provide a 32-byte key.");
|
||||
}
|
||||
|
||||
AotPatchOwnedBuffer sealed_payload;
|
||||
sealed_payload.length = encrypted_payload_buffer.length + tag_buffer.length;
|
||||
sealed_payload.data = reinterpret_cast<uint8_t*>(
|
||||
malloc(Utils::Maximum<intptr_t>(sealed_payload.length, 1)));
|
||||
if (sealed_payload.data == nullptr) {
|
||||
return Api::NewError("Unable to allocate AOT patch sealed payload.");
|
||||
}
|
||||
memmove(sealed_payload.data, encrypted_payload_buffer.data,
|
||||
encrypted_payload_buffer.length);
|
||||
memmove(sealed_payload.data + encrypted_payload_buffer.length,
|
||||
tag_buffer.data, tag_buffer.length);
|
||||
|
||||
AotPatchOwnedBuffer decrypted_payload_buffer;
|
||||
decrypted_payload_buffer.length = sealed_payload.length;
|
||||
decrypted_payload_buffer.data = reinterpret_cast<uint8_t*>(
|
||||
malloc(Utils::Maximum<intptr_t>(decrypted_payload_buffer.length, 1)));
|
||||
if (decrypted_payload_buffer.data == nullptr) {
|
||||
return Api::NewError("Unable to allocate AOT patch payload.");
|
||||
}
|
||||
|
||||
EVP_AEAD_CTX ctx;
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
if (EVP_AEAD_CTX_init(&ctx, EVP_aead_aes_256_gcm(), key_buffer,
|
||||
sizeof(key_buffer), tag_buffer.length, nullptr) != 1) {
|
||||
memset(key_buffer, 0, sizeof(key_buffer));
|
||||
return Api::NewError("Failed to initialize AOT patch AES-GCM context.");
|
||||
}
|
||||
size_t decrypted_length = 0;
|
||||
const int decrypt_ok = EVP_AEAD_CTX_open(
|
||||
&ctx, decrypted_payload_buffer.data, &decrypted_length,
|
||||
decrypted_payload_buffer.length, nonce_buffer.data, nonce_buffer.length,
|
||||
sealed_payload.data, sealed_payload.length,
|
||||
reinterpret_cast<const uint8_t*>(aad.buffer()), aad.length());
|
||||
EVP_AEAD_CTX_cleanup(&ctx);
|
||||
memset(key_buffer, 0, sizeof(key_buffer));
|
||||
if (decrypt_ok != 1) {
|
||||
return Api::NewError("AOT patch AES-GCM decryption failed.");
|
||||
}
|
||||
decrypted_payload_buffer.length = decrypted_length;
|
||||
|
||||
uint8_t payload_digest[SHA256_DIGEST_LENGTH];
|
||||
SHA256(decrypted_payload_buffer.data, decrypted_payload_buffer.length,
|
||||
payload_digest);
|
||||
if (!AotPatchDigestEqualsHex(payload_digest, SHA256_DIGEST_LENGTH,
|
||||
payload_sha256)) {
|
||||
return Api::NewError("AOT patch decrypted payload hash mismatch.");
|
||||
}
|
||||
|
||||
// This VM API validates the open artifact envelope and key contract. The
|
||||
// iOS-safe AOT patch model maps patched isolate data/instructions before
|
||||
// isolate startup, so embedders should install the decrypted artifact through
|
||||
// their snapshot mapping path rather than mutating executable code here.
|
||||
*patch_payload_buffer = decrypted_payload_buffer.Release();
|
||||
*patch_payload_length = static_cast<intptr_t>(decrypted_length);
|
||||
return Api::Success();
|
||||
#endif
|
||||
}
|
||||
|
||||
DART_EXPORT void Dart_FreeAotPatchPayload(uint8_t* patch_payload_buffer) {
|
||||
free(patch_payload_buffer);
|
||||
}
|
||||
|
||||
DART_EXPORT bool Dart_IsPrecompiledRuntime() {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
return true;
|
||||
|
||||
@@ -297,7 +297,8 @@ TEST_CASE(DartAPI_IsolateOwnership) {
|
||||
EXPECT_EQ(false, Dart_GetCurrentThreadOwnsIsolate(ILLEGAL_PORT));
|
||||
|
||||
Dart_ShutdownIsolate();
|
||||
}).join();
|
||||
})
|
||||
.join();
|
||||
|
||||
EXPECT_EQ(true, Dart_GetCurrentThreadOwnsIsolate(port));
|
||||
EXPECT_EQ(false, Dart_GetCurrentThreadOwnsIsolate(other_port));
|
||||
@@ -352,7 +353,8 @@ TEST_CASE_WITH_EXPECTATION(
|
||||
// Causes an assertion failure, because the isolate is already owned by
|
||||
// another thread.
|
||||
Dart_EnterIsolate(isolate);
|
||||
}).join();
|
||||
})
|
||||
.join();
|
||||
|
||||
Dart_EnterIsolate(isolate);
|
||||
}
|
||||
@@ -10913,6 +10915,167 @@ TEST_CASE(Dart_SetFfiNativeResolver_DoesNotResolve) {
|
||||
EXPECT_ERROR(result, "Couldn't resolve function: 'DoesNotResolve'");
|
||||
}
|
||||
|
||||
#if defined(DART_ENABLE_AOT_PATCHING)
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#error DART_ENABLE_AOT_PATCHING must not require DART_DYNAMIC_MODULES.
|
||||
#endif
|
||||
|
||||
static bool TestAotPatchKeyCallback(const char* key_id,
|
||||
uint8_t* key_buffer,
|
||||
intptr_t key_buffer_length,
|
||||
intptr_t* key_length) {
|
||||
EXPECT_STREQ(key_id, "test-key");
|
||||
EXPECT(key_buffer_length >= 32);
|
||||
memset(key_buffer, 0x42, 32);
|
||||
*key_length = 32;
|
||||
return true;
|
||||
}
|
||||
#endif // defined(DART_ENABLE_AOT_PATCHING)
|
||||
|
||||
TEST_CASE(DartAPI_AotPatchingConfiguration) {
|
||||
const char patch[] = R"json({
|
||||
"format": "open-aot-vmcode-encrypted-v1",
|
||||
"metadata": {
|
||||
"app_id": "app.test",
|
||||
"app_build_id": "1",
|
||||
"base_flavor_id": "free",
|
||||
"base_license_type": "free",
|
||||
"flavor_id": "pro",
|
||||
"license_type": "pro",
|
||||
"sdk_hash": "sdk",
|
||||
"base_snapshot_hash": "cae662172fd450bb0cd710a769079c05bfc5d8e35efa6576edc7d0377afdd4a2",
|
||||
"patch_snapshot_hash": "05d9426b9dd03e5cc3404aab6c7c45ac24e0b90e840f4bd6da83c342430533dc",
|
||||
"target_os": "windows",
|
||||
"target_arch": "x64"
|
||||
},
|
||||
"payload_kind": "full-snapshot",
|
||||
"reconstructed_size": 13,
|
||||
"payload_sha256": "05d9426b9dd03e5cc3404aab6c7c45ac24e0b90e840f4bd6da83c342430533dc",
|
||||
"encrypted_payload_base64": "hNOLmjSh9YbgIyRuVQ==",
|
||||
"encryption": {
|
||||
"algorithm": "AES-256-GCM",
|
||||
"key_id": "test-key",
|
||||
"nonce_base64": "AAAAAAAAAAAAAAAA",
|
||||
"tag_base64": "W8uOg/f+g2SS3Ahxfaeuyg==",
|
||||
"aad_sha256": "1a0c6003fec49bbc26fbaaf0a6dfcd557061b4ae5f22e4b1114afe3b1a8d9796"
|
||||
}
|
||||
})json";
|
||||
const char ios_native_patch[] = R"json({
|
||||
"format": "open-aot-vmcode-encrypted-v1",
|
||||
"metadata": {
|
||||
"app_id": "app.test",
|
||||
"app_build_id": "1",
|
||||
"base_flavor_id": "free",
|
||||
"base_license_type": "free",
|
||||
"flavor_id": "pro",
|
||||
"license_type": "pro",
|
||||
"sdk_hash": "sdk",
|
||||
"base_snapshot_hash": "cae662172fd450bb0cd710a769079c05bfc5d8e35efa6576edc7d0377afdd4a2",
|
||||
"patch_snapshot_hash": "05d9426b9dd03e5cc3404aab6c7c45ac24e0b90e840f4bd6da83c342430533dc",
|
||||
"target_os": "ios",
|
||||
"target_arch": "arm64"
|
||||
}
|
||||
})json";
|
||||
const char ios_interpreter_compact_patch[] = R"json({
|
||||
"format": "open-aot-vmcode-encrypted-v1",
|
||||
"metadata": {
|
||||
"app_id": "app.test",
|
||||
"app_build_id": "1",
|
||||
"base_flavor_id": "free",
|
||||
"base_license_type": "free",
|
||||
"flavor_id": "pro",
|
||||
"license_type": "pro",
|
||||
"sdk_hash": "sdk",
|
||||
"base_snapshot_hash": "cae662172fd450bb0cd710a769079c05bfc5d8e35efa6576edc7d0377afdd4a2",
|
||||
"patch_snapshot_hash": "05d9426b9dd03e5cc3404aab6c7c45ac24e0b90e840f4bd6da83c342430533dc",
|
||||
"target_os": "ios",
|
||||
"target_arch": "arm64",
|
||||
"runtime_mode": "dart-bytecode-interpreter"
|
||||
},
|
||||
"payload_kind": "binary-diff-v1"
|
||||
})json";
|
||||
Dart_AotPatchInstallOptions options = {};
|
||||
options.app_id = "app.test";
|
||||
options.app_build_id = "1";
|
||||
options.base_flavor_id = "free";
|
||||
options.base_license_type = "free";
|
||||
options.flavor_id = "pro";
|
||||
options.license_type = "pro";
|
||||
options.sdk_hash = "sdk";
|
||||
options.base_snapshot_hash =
|
||||
"cae662172fd450bb0cd710a769079c05bfc5d8e35efa6576edc7d0377afdd4a2";
|
||||
options.patch_snapshot_hash =
|
||||
"05d9426b9dd03e5cc3404aab6c7c45ac24e0b90e840f4bd6da83c342430533dc";
|
||||
options.target_os = "windows";
|
||||
options.target_arch = "x64";
|
||||
|
||||
uint8_t* patch_payload = nullptr;
|
||||
intptr_t patch_payload_length = 0;
|
||||
#if defined(DART_ENABLE_AOT_PATCHING)
|
||||
EXPECT(Dart_AotPatchingEnabled());
|
||||
Dart_SetAotPatchKeyCallback(TestAotPatchKeyCallback);
|
||||
Dart_Handle result = Dart_InstallAotPatch(
|
||||
reinterpret_cast<const uint8_t*>(patch), strlen(patch), &options,
|
||||
&patch_payload, &patch_payload_length);
|
||||
EXPECT_VALID(result);
|
||||
EXPECT_EQ(13, patch_payload_length);
|
||||
EXPECT_EQ(0, memcmp("patch-payload", patch_payload, patch_payload_length));
|
||||
Dart_FreeAotPatchPayload(patch_payload);
|
||||
|
||||
Dart_AotPatchInstallOptions ios_options = options;
|
||||
ios_options.target_os = "ios";
|
||||
ios_options.target_arch = "arm64";
|
||||
ios_options.runtime_mode = "native-aot";
|
||||
result =
|
||||
Dart_InstallAotPatch(reinterpret_cast<const uint8_t*>(ios_native_patch),
|
||||
strlen(ios_native_patch), &ios_options,
|
||||
&patch_payload, &patch_payload_length);
|
||||
EXPECT_ERROR(result,
|
||||
"iOS AOT patches must use the no-DDM interpreter runtime mode");
|
||||
|
||||
Dart_AotPatchInstallOptions ios_interpreter_options = ios_options;
|
||||
ios_interpreter_options.runtime_mode = "dart-bytecode-interpreter";
|
||||
result = Dart_InstallAotPatch(
|
||||
reinterpret_cast<const uint8_t*>(ios_interpreter_compact_patch),
|
||||
strlen(ios_interpreter_compact_patch), &ios_interpreter_options,
|
||||
&patch_payload, &patch_payload_length);
|
||||
EXPECT_ERROR(result,
|
||||
"Dart bytecode interpreter AOT patches must use payload_kind "
|
||||
"\"full-snapshot\"");
|
||||
|
||||
Dart_AotPatchInstallOptions dynamic_modules_options = options;
|
||||
dynamic_modules_options.runtime_mode = "dart-dynamic-modules";
|
||||
result = Dart_InstallAotPatch(reinterpret_cast<const uint8_t*>(patch),
|
||||
strlen(patch), &dynamic_modules_options,
|
||||
&patch_payload, &patch_payload_length);
|
||||
EXPECT_ERROR(result,
|
||||
"DART_DYNAMIC_MODULES is not supported for AOT patch artifacts");
|
||||
Dart_SetAotPatchKeyCallback(nullptr);
|
||||
#else
|
||||
EXPECT(!Dart_AotPatchingEnabled());
|
||||
Dart_Handle result = Dart_InstallAotPatch(
|
||||
reinterpret_cast<const uint8_t*>(patch), strlen(patch), &options,
|
||||
&patch_payload, &patch_payload_length);
|
||||
EXPECT_ERROR(result, "Compact AOT patching is not enabled");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE(DartAPI_BytecodePatchReloadConfiguration) {
|
||||
#if defined(DART_SUPPORT_RELOAD) && defined(DART_BYTECODE_INTERPRETER)
|
||||
Dart_Handle result = Dart_ReloadBytecodePatch(nullptr, 0);
|
||||
EXPECT_ERROR(result, "bytecode_buffer");
|
||||
|
||||
const uint8_t invalid_patch[] = {0x00, 0x01, 0x02, 0x03};
|
||||
result = Dart_ReloadBytecodePatch(invalid_patch, sizeof(invalid_patch));
|
||||
EXPECT_ERROR(result, "not a Dart bytecode program");
|
||||
#else
|
||||
const uint8_t invalid_patch[] = {0x00, 0x01, 0x02, 0x03};
|
||||
Dart_Handle result =
|
||||
Dart_ReloadBytecodePatch(invalid_patch, sizeof(invalid_patch));
|
||||
EXPECT_ERROR(result, "Dart bytecode patch reload is not enabled");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE(DartAPI_UserTags) {
|
||||
Dart_Handle default_tag = Dart_GetDefaultUserTag();
|
||||
EXPECT_VALID(default_tag);
|
||||
|
||||
@@ -139,14 +139,14 @@ ObjectPtr DartEntry::InvokeFunction(const Function& function,
|
||||
ASSERT(thread->IsDartMutatorThread());
|
||||
ASSERT(!function.IsNull());
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
if (function.IsInterpreted()) {
|
||||
// SuspendLongJumpScope suspend_long_jump_scope(thread);
|
||||
TransitionToGenerated transition(thread);
|
||||
return Interpreter::Current()->Call(function, arguments_descriptor,
|
||||
arguments, thread);
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
if (!function.HasCode()) {
|
||||
|
||||
+15
-15
@@ -500,7 +500,7 @@ ActivationFrame::Relation ActivationFrame::CompareTo(bool is_interpreted,
|
||||
if (fp == other_fp) {
|
||||
return kSelf;
|
||||
}
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
if (is_interpreted) {
|
||||
// Unlike compiled code, interpreted stacks grow towards higher addresses.
|
||||
return fp > other_fp ? kCallee : kCaller;
|
||||
@@ -641,7 +641,7 @@ void ActivationFrame::PrintContextLevelError(const char* message) {
|
||||
OS::PrintErr("context_level_ %" Px "\n", context_level_);
|
||||
OS::PrintErr("token_pos_ %s\n", token_pos_.ToCString());
|
||||
if (IsInterpreted() && bytecode().HasLocalVariablesInfo()) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
Zone* const zone = Thread::Current()->zone();
|
||||
ZoneTextBuffer buffer(zone);
|
||||
KernelBytecodeDisassembler::PrintLocalVariablesInfo(
|
||||
@@ -672,7 +672,7 @@ intptr_t ActivationFrame::ContextLevel() {
|
||||
ASSERT(IsInterpreted() || !code().is_optimized());
|
||||
bool found = false;
|
||||
if (IsInterpreted()) {
|
||||
#if defined(DART_DYNAMIC_MODULES) && !defined(PRODUCT) && \
|
||||
#if defined(DART_BYTECODE_INTERPRETER) && !defined(PRODUCT) && \
|
||||
!defined(DART_PRECOMPILED_RUNTIME)
|
||||
const intptr_t pc_offset = pc() - PayloadStart();
|
||||
DEBUG_ONLY(intptr_t closest_start = 0);
|
||||
@@ -1475,7 +1475,7 @@ CodeBreakpoint::~CodeBreakpoint() {
|
||||
void CodeBreakpoint::Enable() {
|
||||
if (enabled_count_ == 0) {
|
||||
if (bytecode_ != Bytecode::null()) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
ASSERT_EQUAL(saved_opcode_, kMaxUint32);
|
||||
saved_opcode_ =
|
||||
BytecodePatcher::AddBreakpointAt(pc_, Bytecode::Handle(bytecode_));
|
||||
@@ -1492,7 +1492,7 @@ void CodeBreakpoint::Enable() {
|
||||
void CodeBreakpoint::Disable() {
|
||||
if (enabled_count_ == 1) {
|
||||
if (bytecode_ != Bytecode::null()) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
BytecodePatcher::RemoveBreakpointAt(pc_, Bytecode::Handle(bytecode_),
|
||||
saved_opcode_);
|
||||
saved_opcode_ = kMaxUint32;
|
||||
@@ -2318,11 +2318,11 @@ static TokenPosition ResolveBreakpointPos(const Function& func,
|
||||
Zone* zone = Thread::Current()->zone();
|
||||
Script& script = Script::Handle(zone, func.script());
|
||||
PcDescriptors& desc = PcDescriptors::Handle(zone);
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
auto& bytecode = Bytecode::Handle(zone);
|
||||
#endif
|
||||
if (func.HasBytecode()) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
bytecode = func.GetBytecode();
|
||||
ASSERT(!bytecode.IsNull());
|
||||
if (!bytecode.HasSourcePositions()) {
|
||||
@@ -2345,7 +2345,7 @@ static TokenPosition ResolveBreakpointPos(const Function& func,
|
||||
intptr_t best_line = INT_MAX;
|
||||
|
||||
if (func.HasBytecode()) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
// Only compiled code has synthetic token positions.
|
||||
ASSERT(!requested_token_pos.IsSynthetic());
|
||||
bytecode::BytecodeSourcePositionsIterator iter(zone, bytecode);
|
||||
@@ -2424,7 +2424,7 @@ static TokenPosition ResolveBreakpointPos(const Function& func,
|
||||
|
||||
uword lowest_pc_offset = kUwordMax;
|
||||
if (func.HasBytecode()) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
bytecode::BytecodeSourcePositionsIterator iter(zone, bytecode);
|
||||
while (iter.MoveNext()) {
|
||||
const TokenPosition& pos = iter.TokenPos();
|
||||
@@ -2528,7 +2528,7 @@ void GroupDebugger::MakeCodeBreakpointAtUnsafe(Thread* thread,
|
||||
// Find the safe point with the lowest compiled code address
|
||||
// that maps to the token position of the source breakpoint.
|
||||
if (func.HasBytecode()) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
bytecode = func.GetBytecode();
|
||||
ASSERT(!bytecode.IsNull());
|
||||
if (!bytecode.HasSourcePositions()) {
|
||||
@@ -3497,7 +3497,7 @@ void Debugger::EnterSingleStepMode() {
|
||||
|
||||
void Debugger::ResetSteppingFramePointer() {
|
||||
stepping_fp_ = 0;
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
stepping_fp_from_interpreted_frame_ = false;
|
||||
#endif
|
||||
}
|
||||
@@ -3533,7 +3533,7 @@ bool Debugger::MatchesLastSteppingInformation(ActivationFrame* frame) {
|
||||
|
||||
void Debugger::SetSyncSteppingFramePointer(ActivationFrame* frame) {
|
||||
stepping_fp_ = frame->fp();
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
stepping_fp_from_interpreted_frame_ = frame->IsInterpreted();
|
||||
#endif
|
||||
}
|
||||
@@ -3963,7 +3963,7 @@ static bool IsAtAsyncJump(ActivationFrame* top_frame) {
|
||||
return false;
|
||||
}
|
||||
if (top_frame->IsInterpreted()) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
const auto& bytecode = top_frame->bytecode();
|
||||
ASSERT(bytecode.HasSourcePositions());
|
||||
const uword pc_offset = top_frame->pc() - bytecode.PayloadStart();
|
||||
@@ -3998,7 +3998,7 @@ static bool IsAtAsyncJump(ActivationFrame* top_frame) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
static ActivationFrame::Relation CompareTopDartFrameTo(uword other_fp,
|
||||
bool is_interpreted) {
|
||||
StackFrameIterator iterator(ValidationPolicy::kDontValidateFrames,
|
||||
@@ -4041,7 +4041,7 @@ ErrorPtr Debugger::PauseStepping() {
|
||||
// interested in. If we saved the frame pointer of a stack frame
|
||||
// the user is interested in, we ignore the single step if we are
|
||||
// in a callee of that frame.
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
auto const relation =
|
||||
stepping_fp_from_interpreted_frame_ == frame->IsInterpreted()
|
||||
? frame->CompareTo(stepping_fp_)
|
||||
|
||||
@@ -218,7 +218,7 @@ class CodeBreakpoint {
|
||||
// Used by GroupDebugger to find CodeBreakpoint associated with
|
||||
// particular function.
|
||||
FunctionPtr function() const {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
if (bytecode_ != Bytecode::null()) {
|
||||
return Bytecode::Handle(bytecode_).function();
|
||||
}
|
||||
@@ -1011,7 +1011,7 @@ class Debugger {
|
||||
// frame corresponds to this fp value, or if the top frame is
|
||||
// lower on the stack.
|
||||
uword stepping_fp_;
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
bool stepping_fp_from_interpreted_frame_ = false;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -587,13 +587,13 @@ NO_SANITIZE_SAFE_STACK // This function manipulates the safestack pointer.
|
||||
// in the previous frames.
|
||||
StackResource::Unwind(thread);
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
Interpreter* interpreter = thread->interpreter();
|
||||
if ((interpreter != nullptr) && interpreter->HasFrame(frame_pointer)) {
|
||||
interpreter->JumpToFrame(program_counter, stack_pointer, frame_pointer,
|
||||
thread);
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
// If execution exited generated code through FFI then exit the safepoint
|
||||
// and transition back to kThreadInGenerated execution state. JumpToFrame
|
||||
|
||||
@@ -12,11 +12,11 @@
|
||||
#define LOCAL_SYMBOL(x) .L##x
|
||||
#endif
|
||||
|
||||
#if defined(__aarch64__) && (defined(SIMULATOR_FFI) || (defined(DART_DYNAMIC_MODULES) && !defined(DART_PRECOMPILED_RUNTIME)))
|
||||
#if defined(__aarch64__) && (defined(SIMULATOR_FFI) || (defined(DART_BYTECODE_INTERPRETER) && !defined(DART_PRECOMPILED_RUNTIME)))
|
||||
|
||||
.text
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_BYTECODE_INTERPRETER) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
#if defined(__APPLE__)
|
||||
.globl _FfiCallTrampoline
|
||||
@@ -73,7 +73,7 @@ LOCAL_SYMBOL(copy1):
|
||||
.size FfiCallTrampoline,.-FfiCallTrampoline
|
||||
#endif
|
||||
|
||||
#endif // defined(DART_DYNAMIC_MODULES) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
#if defined(SIMULATOR_FFI)
|
||||
|
||||
@@ -216,4 +216,4 @@ SimulatorFfiCallbackTrampolineEnd:
|
||||
|
||||
#endif // defined(SIMULATOR_FFI)
|
||||
|
||||
#endif // defined(__aarch64__) && (defined(SIMULATOR_FFI) || (defined(DART_DYNAMIC_MODULES) && !defined(DART_PRECOMPILED_RUNTIME)))
|
||||
#endif // defined(__aarch64__) && (defined(SIMULATOR_FFI) || (defined(DART_BYTECODE_INTERPRETER) && !defined(DART_PRECOMPILED_RUNTIME)))
|
||||
|
||||
@@ -87,7 +87,7 @@ void _printGeneratedStackTrace(uword fp, uword sp, uword pc) {
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
// Like _printDartStackTrace, but works in the interpreter loop.
|
||||
// Must be called with the current interpreter fp, sp, and pc.
|
||||
// Note that sp[0] is not modified, but sp[1] will be trashed.
|
||||
@@ -107,7 +107,7 @@ void _printInterpreterStackTrace(ObjectPtr* fp,
|
||||
thread->set_execution_state(Thread::kThreadInGenerated);
|
||||
thread->set_top_exit_frame_info(0);
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
class PrintObjectPointersVisitor : public ObjectPointerVisitor {
|
||||
public:
|
||||
|
||||
@@ -87,6 +87,26 @@ const intptr_t kDefaultNewGenSemiMaxSize = (kWordSize <= 4) ? 8 : 16;
|
||||
#error DART_PRECOMPILED_RUNTIME and DART_NOSNAPSHOT are mutually exclusive
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME) && defined(DART_NOSNAPSHOT)
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES) && defined(DART_SHOREBIRD_INTERPRETER)
|
||||
#error DART_DYNAMIC_MODULES and DART_SHOREBIRD_INTERPRETER are mutually exclusive
|
||||
#endif
|
||||
|
||||
#if (defined(DART_DYNAMIC_MODULES) || defined(DART_SHOREBIRD_INTERPRETER)) && \
|
||||
!defined(DART_BYTECODE_INTERPRETER)
|
||||
#define DART_BYTECODE_INTERPRETER 1
|
||||
#endif
|
||||
|
||||
#if defined(DART_SHOREBIRD_INTERPRETER) && \
|
||||
defined(DART_BYTECODE_INTERPRETER) && !defined(PRODUCT) && \
|
||||
!defined(DART_PRECOMPILED_RUNTIME)
|
||||
#define DART_ENABLE_BYTECODE_PATCH_RELOAD 1
|
||||
#endif
|
||||
|
||||
#if defined(DART_ENABLE_BYTECODE_PATCH_RELOAD) || \
|
||||
(!defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME))
|
||||
#define DART_SUPPORT_RELOAD 1
|
||||
#endif
|
||||
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
#define NOT_IN_PRECOMPILED(code)
|
||||
#define ONLY_IN_PRECOMPILED(code) code
|
||||
|
||||
@@ -734,7 +734,7 @@ void GCMarker::Prologue() {
|
||||
isolate_group_->ReleaseStoreBuffers();
|
||||
new_marking_stack_.PushAll(tlab_deferred_marking_stack_.PopAll());
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
isolate_group_->ForEachIsolate(
|
||||
[&](Isolate* isolate) {
|
||||
Thread* mutator_thread = isolate->mutator_thread();
|
||||
@@ -746,7 +746,7 @@ void GCMarker::Prologue() {
|
||||
}
|
||||
},
|
||||
/*at_safepoint=*/true);
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
void GCMarker::Epilogue() {}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "vm/globals.h"
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
#include "vm/interpreter.h"
|
||||
|
||||
@@ -44,7 +44,7 @@ DEFINE_FLAG(uint64_t,
|
||||
100 * MB,
|
||||
"Maximum size in bytes of the interpreter trace file");
|
||||
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_SHOREBIRD_INTERPRETER)
|
||||
constexpr bool kDefaultCheckDynamicCalls = true;
|
||||
#else
|
||||
constexpr bool kDefaultCheckDynamicCalls = false;
|
||||
@@ -2078,7 +2078,7 @@ SwitchDispatch:
|
||||
#undef TARGET
|
||||
#endif // !defined(PRODUCT)
|
||||
default:
|
||||
FATAL1("Undefined opcode: %d\n", op);
|
||||
FATAL("Undefined opcode: %d\n", op);
|
||||
}
|
||||
#if !defined(PRODUCT)
|
||||
SwitchDispatchNoSingleStep:
|
||||
@@ -2089,7 +2089,7 @@ SwitchDispatchNoSingleStep:
|
||||
KERNEL_BYTECODES_LIST(TARGET)
|
||||
#undef TARGET
|
||||
default:
|
||||
FATAL1("Undefined opcode: %d\n", op);
|
||||
FATAL("Undefined opcode: %d\n", op);
|
||||
}
|
||||
#endif // !defined(PRODUCT)
|
||||
#endif // defined(DART_HAS_COMPUTED_GOTO)
|
||||
@@ -4827,4 +4827,4 @@ void Interpreter::VisitObjectPointers(ObjectPointerVisitor* visitor) {
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#define RUNTIME_VM_INTERPRETER_H_
|
||||
|
||||
#include "vm/globals.h"
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
#include "platform/utils.h"
|
||||
#include "vm/class_table.h"
|
||||
@@ -326,6 +326,6 @@ class Interpreter {
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
#endif // RUNTIME_VM_INTERPRETER_H_
|
||||
|
||||
+17
-17
@@ -70,11 +70,11 @@ DECLARE_FLAG(int, old_gen_growth_time_ratio);
|
||||
|
||||
// Reload flags.
|
||||
DECLARE_FLAG(int, reload_every);
|
||||
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_SUPPORT_RELOAD)
|
||||
DECLARE_FLAG(bool, check_reloaded);
|
||||
DECLARE_FLAG(bool, reload_every_back_off);
|
||||
DECLARE_FLAG(bool, trace_reload);
|
||||
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#endif // defined(DART_SUPPORT_RELOAD)
|
||||
|
||||
static void DeterministicModeHandler(bool value) {
|
||||
if (value) {
|
||||
@@ -315,7 +315,7 @@ IsolateGroup::IsolateGroup(std::shared_ptr<IsolateGroupSource> source,
|
||||
mutators_(),
|
||||
start_time_micros_(OS::GetCurrentMonotonicMicros()),
|
||||
is_system_isolate_group_(source->flags.is_system_isolate),
|
||||
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_SUPPORT_RELOAD)
|
||||
last_reload_timestamp_(OS::GetCurrentTimeMillis()),
|
||||
reload_every_n_stack_overflow_checks_(FLAG_reload_every),
|
||||
#endif
|
||||
@@ -392,10 +392,10 @@ IsolateGroup::IsolateGroup(std::shared_ptr<IsolateGroupSource> source,
|
||||
: IsolateGroup(source, embedder_data, nullptr, api_flags) {}
|
||||
|
||||
IsolateGroup::~IsolateGroup() {
|
||||
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_SUPPORT_RELOAD)
|
||||
RELEASE_ASSERT(group_reload_context_ == nullptr);
|
||||
RELEASE_ASSERT(program_reload_context_ == nullptr);
|
||||
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#endif // defined(DART_SUPPORT_RELOAD)
|
||||
|
||||
// Ensure we destroy the heap before the other members.
|
||||
heap_ = nullptr;
|
||||
@@ -789,12 +789,12 @@ Bequest::~Bequest() {
|
||||
}
|
||||
|
||||
void IsolateGroup::RegisterClass(const Class& cls) {
|
||||
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_SUPPORT_RELOAD)
|
||||
if (IsReloading()) {
|
||||
program_reload_context()->RegisterClass(cls);
|
||||
return;
|
||||
}
|
||||
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#endif // defined(DART_SUPPORT_RELOAD)
|
||||
if (cls.IsTopLevel()) {
|
||||
class_table()->RegisterTopLevel(cls);
|
||||
} else {
|
||||
@@ -872,7 +872,7 @@ void IsolateGroup::RegisterStaticField(const Field& field,
|
||||
}
|
||||
|
||||
void IsolateGroup::FreeStaticField(const Field& field) {
|
||||
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_SUPPORT_RELOAD)
|
||||
// This can only be called during hot-reload.
|
||||
ASSERT(program_reload_context() != nullptr);
|
||||
#endif
|
||||
@@ -1385,7 +1385,7 @@ ErrorPtr IsolateMessageHandler::HandleLibMessage(const Array& message) {
|
||||
}
|
||||
case Isolate::kCheckForReload: {
|
||||
// [ OOB, kCheckForReload, ignored ]
|
||||
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_SUPPORT_RELOAD)
|
||||
{
|
||||
ReloadParticipationScope allow_reload(T);
|
||||
T->CheckForSafepoint();
|
||||
@@ -2075,7 +2075,7 @@ void Isolate::BuildName(const char* name_prefix) {
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_SUPPORT_RELOAD)
|
||||
bool IsolateGroup::CanReload() {
|
||||
// We only call this method on the mutator thread. Normally the caller is
|
||||
// inside of the "reloadSources" service OOB message handler. Though
|
||||
@@ -2172,7 +2172,7 @@ void IsolateGroup::DeleteReloadContext() {
|
||||
delete program_reload_context_;
|
||||
program_reload_context_ = nullptr;
|
||||
}
|
||||
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#endif // defined(DART_SUPPORT_RELOAD)
|
||||
|
||||
const char* Isolate::MakeRunnable() {
|
||||
MutexLocker ml(&mutex_);
|
||||
@@ -2565,7 +2565,7 @@ void Isolate::LowLevelShutdown() {
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_SUPPORT_RELOAD)
|
||||
void IsolateGroup::MaybeIncreaseReloadEveryNStackOverflowChecks() {
|
||||
if (FLAG_reload_every_back_off) {
|
||||
if (reload_every_n_stack_overflow_checks_ < 5000) {
|
||||
@@ -2580,7 +2580,7 @@ void IsolateGroup::MaybeIncreaseReloadEveryNStackOverflowChecks() {
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#endif // defined(DART_SUPPORT_RELOAD)
|
||||
|
||||
void Isolate::Shutdown() {
|
||||
Thread* thread = Thread::Current();
|
||||
@@ -2601,7 +2601,7 @@ void Isolate::Shutdown() {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_SUPPORT_RELOAD)
|
||||
if (FLAG_check_reloaded && is_runnable() && !Isolate::IsSystemIsolate(this)) {
|
||||
if (!group()->HasAttemptedReload()) {
|
||||
FATAL(
|
||||
@@ -2609,7 +2609,7 @@ void Isolate::Shutdown() {
|
||||
"--check-reloaded is enabled.\n");
|
||||
}
|
||||
}
|
||||
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#endif // defined(DART_SUPPORT_RELOAD)
|
||||
|
||||
// Then, proceed with low-level teardown.
|
||||
Isolate::UnMarkIsolateReady(this);
|
||||
@@ -2985,13 +2985,13 @@ void IsolateGroup::VisitSharedPointers(ObjectPointerVisitor* visitor,
|
||||
#endif
|
||||
break;
|
||||
case kReloadContext:
|
||||
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_SUPPORT_RELOAD)
|
||||
if (program_reload_context() != nullptr) {
|
||||
program_reload_context()->VisitObjectPointers(visitor);
|
||||
program_reload_context()->group_reload_context()->VisitObjectPointers(
|
||||
visitor);
|
||||
}
|
||||
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#endif // defined(DART_SUPPORT_RELOAD)
|
||||
break;
|
||||
case kLoadedBlobs:
|
||||
if (source()->loaded_blobs_ != nullptr) {
|
||||
|
||||
+10
-12
@@ -523,8 +523,7 @@ class IsolateGroup : public IntrusiveDListEntry<IsolateGroup> {
|
||||
isolate_group_flags_.UpdateBool<DwarfStackTracesBit>(value);
|
||||
}
|
||||
|
||||
#if !defined(PRODUCT)
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_SUPPORT_RELOAD)
|
||||
bool HasAttemptedReload() const {
|
||||
return isolate_group_flags_.Read<HasAttemptedReloadBit>();
|
||||
}
|
||||
@@ -537,8 +536,7 @@ class IsolateGroup : public IntrusiveDListEntry<IsolateGroup> {
|
||||
}
|
||||
#else
|
||||
bool HasAttemptedReload() const { return false; }
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#endif // !defined(PRODUCT)
|
||||
#endif // defined(DART_SUPPORT_RELOAD)
|
||||
|
||||
bool has_seen_oom() const {
|
||||
return isolate_group_flags_.Read<HasSeenOOMBit>();
|
||||
@@ -587,9 +585,9 @@ class IsolateGroup : public IntrusiveDListEntry<IsolateGroup> {
|
||||
Mutex* unlinked_call_map_mutex() { return &unlinked_call_map_mutex_; }
|
||||
#endif
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER)
|
||||
Mutex* initializer_functions_mutex() { return &initializer_functions_mutex_; }
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
SafepointRwLock* shared_field_initializer_rwlock() {
|
||||
return &shared_field_initializer_rwlock_;
|
||||
@@ -678,7 +676,7 @@ class IsolateGroup : public IntrusiveDListEntry<IsolateGroup> {
|
||||
void PrintMemoryUsageJSON(JSONStream* stream);
|
||||
#endif
|
||||
|
||||
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_SUPPORT_RELOAD)
|
||||
// By default the reload context is deleted. This parameter allows
|
||||
// the caller to delete is separately if it is still needed.
|
||||
bool ReloadSources(JSONStream* js,
|
||||
@@ -710,10 +708,10 @@ class IsolateGroup : public IntrusiveDListEntry<IsolateGroup> {
|
||||
bool CanReload();
|
||||
#else
|
||||
bool CanReload() { return false; }
|
||||
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#endif // defined(DART_SUPPORT_RELOAD)
|
||||
|
||||
bool IsReloading() const {
|
||||
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_SUPPORT_RELOAD)
|
||||
return group_reload_context_ != nullptr;
|
||||
#else
|
||||
return false;
|
||||
@@ -926,7 +924,7 @@ class IsolateGroup : public IntrusiveDListEntry<IsolateGroup> {
|
||||
bool is_system_isolate_group_;
|
||||
bool bootstrapping_ = true;
|
||||
|
||||
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_SUPPORT_RELOAD)
|
||||
int64_t last_reload_timestamp_;
|
||||
std::shared_ptr<IsolateGroupReloadContext> group_reload_context_;
|
||||
// Per-isolate-group copy of FLAG_reload_every.
|
||||
@@ -992,9 +990,9 @@ class IsolateGroup : public IntrusiveDListEntry<IsolateGroup> {
|
||||
Mutex unlinked_call_map_mutex_;
|
||||
#endif
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER)
|
||||
Mutex initializer_functions_mutex_;
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
// Ensure exclusive execution of shared field initializers.
|
||||
SafepointRwLock shared_field_initializer_rwlock_;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "vm/bytecode_reader.h"
|
||||
#include "vm/compiler/jit/compiler.h"
|
||||
#include "vm/dart_api_impl.h"
|
||||
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_SUPPORT_RELOAD)
|
||||
#include "vm/hash.h"
|
||||
#endif
|
||||
#include "vm/hash_table.h"
|
||||
@@ -38,7 +38,7 @@ namespace dart {
|
||||
DEFINE_FLAG(int, reload_every, 0, "Reload every N stack overflow checks.");
|
||||
DEFINE_FLAG(bool, trace_reload, false, "Trace isolate reloading");
|
||||
|
||||
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_SUPPORT_RELOAD)
|
||||
DEFINE_FLAG(bool,
|
||||
trace_reload_verbose,
|
||||
false,
|
||||
@@ -735,7 +735,7 @@ class KernelDeltaProgram : public DeltaProgram {
|
||||
std::unique_ptr<kernel::Program> kernel_program_;
|
||||
};
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
class BytecodeDeltaProgram : public DeltaProgram {
|
||||
public:
|
||||
explicit BytecodeDeltaProgram(const ExternalTypedData& typed_data)
|
||||
@@ -769,7 +769,7 @@ class BytecodeDeltaProgram : public DeltaProgram {
|
||||
private:
|
||||
bytecode::BytecodeLoader loader_;
|
||||
};
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
std::unique_ptr<DeltaProgram> DeltaProgram::ReadFromTypedData(
|
||||
const ExternalTypedData& typed_data) {
|
||||
@@ -781,12 +781,12 @@ std::unique_ptr<DeltaProgram> DeltaProgram::ReadFromTypedData(
|
||||
}
|
||||
return std::make_unique<KernelDeltaProgram>(std::move(kernel_program));
|
||||
}
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
if (Dart_IsBytecode(reinterpret_cast<const uint8_t*>(typed_data.DataAddr(0)),
|
||||
typed_data.LengthInBytes())) {
|
||||
return std::make_unique<BytecodeDeltaProgram>(typed_data);
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -2194,12 +2194,12 @@ ErrorPtr ProgramReloadContext::RunInvalidationVisitors() {
|
||||
StackZone stack_zone(thread);
|
||||
Zone* zone = stack_zone.GetZone();
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
Interpreter* interpreter = thread->interpreter();
|
||||
if (interpreter != nullptr) {
|
||||
interpreter->ClearLookupCache();
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
GrowableArray<const Function*> functions(4 * KB);
|
||||
GrowableArray<const KernelProgramInfo*> kernel_infos(KB);
|
||||
@@ -2275,9 +2275,9 @@ void ProgramReloadContext::InvalidateFunctions(
|
||||
Library& owning_lib = Library::Handle(zone);
|
||||
Code& code = Code::Handle(zone);
|
||||
Field& field = Field::Handle(zone);
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
Bytecode& bytecode = Bytecode::Handle(zone);
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
|
||||
for (intptr_t i = 0; i < functions.length(); i++) {
|
||||
@@ -2316,12 +2316,12 @@ void ProgramReloadContext::InvalidateFunctions(
|
||||
// they're held.
|
||||
resetter.ZeroEdgeCounters(func);
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
if (func.HasBytecode()) {
|
||||
bytecode = func.GetBytecode();
|
||||
resetter.RebindBytecode(bytecode);
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
if (stub_code) {
|
||||
// Nothing to reset.
|
||||
@@ -2925,6 +2925,6 @@ void ProgramReloadContext::RestoreClassHierarchyInvariants() {
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#endif // defined(DART_SUPPORT_RELOAD)
|
||||
|
||||
} // namespace dart
|
||||
|
||||
@@ -30,7 +30,7 @@ DECLARE_FLAG(bool, trace_reload_verbose);
|
||||
#define VTIR_Print(format, ...) \
|
||||
if (FLAG_trace_reload_verbose) Log::Current()->Print(format, ##__VA_ARGS__)
|
||||
|
||||
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_SUPPORT_RELOAD)
|
||||
|
||||
namespace dart {
|
||||
|
||||
@@ -458,6 +458,6 @@ class CallSiteResetter : public ValueObject {
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#endif // defined(DART_SUPPORT_RELOAD)
|
||||
|
||||
#endif // RUNTIME_VM_ISOLATE_RELOAD_H_
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
#include "vm/line_starts_reader.h"
|
||||
#include "vm/object.h"
|
||||
@@ -71,4 +71,4 @@ bool LineStartsReader::TokenRangeAtLine(intptr_t line_number,
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#ifndef RUNTIME_VM_LINE_STARTS_READER_H_
|
||||
#define RUNTIME_VM_LINE_STARTS_READER_H_
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
#include <memory>
|
||||
|
||||
@@ -56,5 +56,5 @@ class LineStartsReader : public ValueObject {
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER)
|
||||
#endif // RUNTIME_VM_LINE_STARTS_READER_H_
|
||||
|
||||
@@ -188,7 +188,7 @@ class NativeArguments {
|
||||
friend class NativeEntry;
|
||||
friend class Simulator;
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
NativeArguments(Thread* thread,
|
||||
int argc_tag,
|
||||
ObjectPtr* argv,
|
||||
@@ -198,7 +198,7 @@ class NativeArguments {
|
||||
argv_(argv),
|
||||
retval_(retval) {}
|
||||
NativeArguments() = default;
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
// Since this function is passed an ObjectPtr directly, we need to be
|
||||
// exceedingly careful when we use it. If there are any other side
|
||||
|
||||
+105
-70
@@ -469,7 +469,7 @@ static type SpecialCharacter(type value) {
|
||||
return '\0';
|
||||
}
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
static BytecodePtr CreateVMInternalBytecode(KernelBytecode::Opcode opcode) {
|
||||
const KBCInstr* instructions = nullptr;
|
||||
intptr_t instructions_size = 0;
|
||||
@@ -487,7 +487,7 @@ static BytecodePtr CreateVMInternalBytecode(KernelBytecode::Opcode opcode) {
|
||||
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
return bytecode.ptr();
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
void Object::InitNullAndBool(IsolateGroup* isolate_group) {
|
||||
Thread* thread = Thread::Current();
|
||||
@@ -1151,7 +1151,7 @@ void Object::Init(IsolateGroup* isolate_group) {
|
||||
// synthetic_getter_parameter_names_ object needs to be created earlier as
|
||||
// VM isolate snapshot reader references it before Object::FinalizeVMIsolate.
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
Roots::implicit_getter_bytecode().initRO(
|
||||
CreateVMInternalBytecode(KernelBytecode::kVMInternal_ImplicitGetter));
|
||||
Roots::implicit_setter_bytecode().initRO(
|
||||
@@ -1203,7 +1203,7 @@ void Object::Init(IsolateGroup* isolate_group) {
|
||||
Roots::implicit_static_closure_bytecode().initRO(Bytecode::null());
|
||||
Roots::implicit_instance_closure_bytecode().initRO(Bytecode::null());
|
||||
Roots::implicit_constructor_closure_bytecode().initRO(Bytecode::null());
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
Roots::uninitialized_index().initRO(
|
||||
TypedData::New(kTypedDataUint32ArrayCid,
|
||||
@@ -2920,7 +2920,7 @@ ClassPtr Class::New(IsolateGroup* isolate_group, bool register_class) {
|
||||
return result.ptr();
|
||||
}
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER)
|
||||
static void ReportTooManyTypeArguments(const Class& cls) {
|
||||
Report::MessageF(Report::kError, Script::Handle(cls.script()),
|
||||
cls.token_pos(), Report::AtLocation,
|
||||
@@ -2929,10 +2929,10 @@ static void ReportTooManyTypeArguments(const Class& cls) {
|
||||
String::Handle(cls.Name()).ToCString());
|
||||
UNREACHABLE();
|
||||
}
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
void Class::set_num_type_arguments(intptr_t value) const {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_BYTECODE_INTERPRETER)
|
||||
UNREACHABLE();
|
||||
#else
|
||||
if (!Utils::IsInt(16, value)) {
|
||||
@@ -2944,7 +2944,7 @@ void Class::set_num_type_arguments(intptr_t value) const {
|
||||
DEBUG_ASSERT(old_value == kUnknownNumTypeArguments || old_value == value);
|
||||
StoreNonPointer<int16_t, int16_t, std::memory_order_relaxed>(
|
||||
&untag()->num_type_arguments_, value);
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
void Class::set_num_type_arguments_unsafe(intptr_t value) const {
|
||||
@@ -3781,7 +3781,7 @@ FunctionPtr Class::CreateInvocationDispatcher(
|
||||
signature ^= ClassFinalizer::FinalizeType(signature);
|
||||
invocation.SetSignature(signature);
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
const bool attach_bytecode = true;
|
||||
#else
|
||||
@@ -3799,7 +3799,7 @@ FunctionPtr Class::CreateInvocationDispatcher(
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
return invocation.ptr();
|
||||
}
|
||||
@@ -3853,7 +3853,7 @@ FunctionPtr Function::CreateMethodExtractor(const String& getter_name) const {
|
||||
signature ^= ClassFinalizer::FinalizeType(signature);
|
||||
extractor.SetSignature(signature);
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
const bool attach_bytecode = true;
|
||||
#else
|
||||
@@ -3873,7 +3873,7 @@ FunctionPtr Function::CreateMethodExtractor(const String& getter_name) const {
|
||||
extractor.AttachBytecode(Object::method_extractor_without_ita_bytecode());
|
||||
}
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
owner.AddFunction(extractor);
|
||||
|
||||
@@ -4086,7 +4086,7 @@ StringPtr Function::CreateDynamicInvocationForwarderName(const String& name) {
|
||||
return Symbols::FromConcat(Thread::Current(), Symbols::DynamicPrefix(), name);
|
||||
}
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER)
|
||||
FunctionPtr Function::CreateDynamicInvocationForwarder(
|
||||
const String& mangled_name) const {
|
||||
Thread* thread = Thread::Current();
|
||||
@@ -4114,7 +4114,7 @@ FunctionPtr Function::CreateDynamicInvocationForwarder(
|
||||
// blocks inlining and can't take Function-s only Code objects.
|
||||
forwarder.set_is_visible(false);
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
if (HasBytecode()) {
|
||||
forwarder.ClearBytecode();
|
||||
}
|
||||
@@ -4132,7 +4132,7 @@ FunctionPtr Function::CreateDynamicInvocationForwarder(
|
||||
forwarder.InheritKernelOffsetFrom(*this);
|
||||
forwarder.SetForwardingTarget(*this);
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
// Allow the creation of a lazily created interpreted dynamic invocation
|
||||
// forwarders for compiled code that does not already have one created,
|
||||
@@ -4273,7 +4273,7 @@ bool Function::NeedsDynamicInvocationForwarder() const {
|
||||
void Function::ReadParameterCovariance(
|
||||
BitVector* is_covariant,
|
||||
BitVector* is_generic_covariant_impl) const {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
if (is_declared_in_bytecode()) {
|
||||
bytecode::BytecodeReader::ReadParameterCovariance(
|
||||
*this, is_covariant, is_generic_covariant_impl);
|
||||
@@ -4971,7 +4971,7 @@ static ObjectPtr LoadExpressionEvaluationFunction(
|
||||
const ExternalTypedData& kernel_buffer,
|
||||
const Class& klass) {
|
||||
Zone* zone = thread->zone();
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
if (Dart_IsBytecode(
|
||||
reinterpret_cast<const uint8_t*>(kernel_buffer.DataAddr(0)),
|
||||
kernel_buffer.LengthInBytes())) {
|
||||
@@ -4981,7 +4981,7 @@ static ObjectPtr LoadExpressionEvaluationFunction(
|
||||
loader.LoadBytecode();
|
||||
return loader.GetExpressionEvaluationFunction();
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
std::unique_ptr<kernel::Program> kernel_pgm =
|
||||
kernel::Program::ReadFromTypedData(kernel_buffer);
|
||||
@@ -5139,7 +5139,7 @@ ObjectPtr Instance::EvaluateCompiledExpression(
|
||||
|
||||
void Class::EnsureDeclarationLoaded() const {
|
||||
if (!is_declaration_loaded()) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
// Loading of class declaration can be postponed until needed
|
||||
// if class comes from bytecode.
|
||||
if (is_declared_in_bytecode()) {
|
||||
@@ -5154,7 +5154,7 @@ void Class::EnsureDeclarationLoaded() const {
|
||||
ASSERT(is_type_finalized());
|
||||
return;
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
UNREACHABLE();
|
||||
#else
|
||||
@@ -5165,7 +5165,7 @@ void Class::EnsureDeclarationLoaded() const {
|
||||
|
||||
// Ensure that top level parsing of the class has been done.
|
||||
ErrorPtr Class::EnsureIsFinalized(Thread* thread) const {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_BYTECODE_INTERPRETER)
|
||||
RELEASE_ASSERT(is_finalized());
|
||||
return Error::null();
|
||||
#else
|
||||
@@ -5191,7 +5191,7 @@ ErrorPtr Class::EnsureIsFinalized(Thread* thread) const {
|
||||
}
|
||||
}
|
||||
return error.ptr();
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
// Ensure that code outdated by finalized class is cleaned up, new instance of
|
||||
@@ -5973,12 +5973,12 @@ void Class::set_is_loaded(bool value) const {
|
||||
set_state_bits(IsLoadedBit::update(value, state_bits()));
|
||||
}
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
void Class::set_is_declared_in_bytecode(bool value) const {
|
||||
ASSERT(IsolateGroup::Current()->program_lock()->IsCurrentThreadWriter());
|
||||
set_state_bits(IsDeclaredInBytecodeBit::update(value, state_bits()));
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
void Class::set_is_finalized() const {
|
||||
ASSERT(IsolateGroup::Current()->program_lock()->IsCurrentThreadWriter());
|
||||
@@ -8133,18 +8133,53 @@ bool Function::HasCode() const {
|
||||
return untag()->code() != StubCode::LazyCompile().ptr();
|
||||
}
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_SHOREBIRD_INTERPRETER)
|
||||
bool Function::IsShorebirdPatchable() const {
|
||||
if (IsNull() || !has_pragma()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Thread* thread = dart::Thread::Current();
|
||||
Object& options = Object::Handle(thread->zone());
|
||||
if (!Library::FindPragma(thread, /*only_core=*/false, *this,
|
||||
Symbols::vm_entry_point(), /*multiple=*/false,
|
||||
&options)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return options.ptr() == Bool::null() || options.ptr() == Bool::True().ptr() ||
|
||||
options.ptr() == Symbols::call().ptr();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
void Function::AttachBytecode(const Bytecode& value) const {
|
||||
ASSERT(IsolateGroup::Current()->program_lock()->IsCurrentThreadWriter());
|
||||
ASSERT(!value.IsNull());
|
||||
// Finish setting up code before activating it.
|
||||
value.set_function(*this);
|
||||
ASSERT(untag()->ic_data_array_or_bytecode() == Object::null());
|
||||
ASSERT(untag()->ic_data_array_or_bytecode() == Object::null() ||
|
||||
untag()->ic_data_array_or_bytecode()->IsBytecode());
|
||||
untag()->set_ic_data_array_or_bytecode(value.ptr());
|
||||
|
||||
// Set the code entry_point to InterpretCall stub.
|
||||
SetInstructions(StubCode::InterpretCall());
|
||||
|
||||
if (!IsImplicitClosureFunction() && HasImplicitClosureFunction()) {
|
||||
const Function& closure_function =
|
||||
Function::Handle(ImplicitClosureFunction());
|
||||
if (closure_function.IsImplicitStaticClosureFunction()) {
|
||||
closure_function.AttachBytecode(Object::implicit_static_closure_bytecode());
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
const Closure& closure =
|
||||
Closure::Handle(closure_function.implicit_static_closure());
|
||||
if (!closure.IsNull()) {
|
||||
closure.set_entry_point(closure_function.entry_point());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Function::ClearBytecode() const {
|
||||
@@ -8157,7 +8192,7 @@ bool Function::IsInterpreted(FunctionPtr function) {
|
||||
return function->untag()->code() == StubCode::InterpretCall().ptr();
|
||||
}
|
||||
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
bool Function::HasCode(FunctionPtr function) {
|
||||
NoSafepointScope no_safepoint;
|
||||
@@ -8166,16 +8201,16 @@ bool Function::HasCode(FunctionPtr function) {
|
||||
}
|
||||
|
||||
void Function::ClearCode() const {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_BYTECODE_INTERPRETER)
|
||||
UNREACHABLE();
|
||||
#else
|
||||
ASSERT(IsolateGroup::Current()->program_lock()->IsCurrentThreadWriter());
|
||||
ClearCodeSafe();
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
void Function::ClearCodeSafe() const {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_BYTECODE_INTERPRETER)
|
||||
UNREACHABLE();
|
||||
#else
|
||||
// This may get called when lazily creating dynamic invocation forwarders
|
||||
@@ -8186,7 +8221,7 @@ void Function::ClearCodeSafe() const {
|
||||
untag()->set_unoptimized_code(Code::null());
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
SetInstructionsSafe(StubCode::LazyCompile());
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
void Function::EnsureHasCompiledUnoptimizedCode() const {
|
||||
@@ -8896,7 +8931,7 @@ StringPtr FunctionType::ParameterNameAt(intptr_t index) const {
|
||||
|
||||
void FunctionType::SetParameterNameAt(intptr_t index,
|
||||
const String& value) const {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_BYTECODE_INTERPRETER)
|
||||
UNREACHABLE();
|
||||
#else
|
||||
ASSERT(!value.IsNull() && value.IsSymbol());
|
||||
@@ -8931,7 +8966,7 @@ void Function::CreateNameArray(Heap::Space space) const {
|
||||
}
|
||||
|
||||
void FunctionType::CreateNameArrayIncludingFlags(Heap::Space space) const {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_BYTECODE_INTERPRETER)
|
||||
UNREACHABLE();
|
||||
#else
|
||||
const intptr_t num_named_parameters = NumOptionalNamedParameters();
|
||||
@@ -10613,7 +10648,7 @@ FunctionPtr Function::ImplicitClosureFunction() const {
|
||||
return implicit_closure_function();
|
||||
}
|
||||
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_BYTECODE_INTERPRETER)
|
||||
// In AOT mode all implicit closures are pre-created.
|
||||
FATAL("Cannot create implicit closure in AOT!");
|
||||
return Function::null();
|
||||
@@ -10823,7 +10858,7 @@ FunctionPtr Function::ImplicitClosureFunction() const {
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
const bool attach_bytecode = true;
|
||||
#else
|
||||
@@ -11097,7 +11132,7 @@ ClassPtr Function::Owner(FunctionPtr function) {
|
||||
return PatchClass::RawCast(owner)->untag()->wrapped_class();
|
||||
}
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
bool Function::is_declared_in_bytecode() const {
|
||||
return Class::Handle(Owner()).is_declared_in_bytecode();
|
||||
}
|
||||
@@ -11105,7 +11140,7 @@ bool Function::is_declared_in_bytecode() const {
|
||||
|
||||
void Function::InheritKernelOffsetFrom(const Function& src) const {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if !defined(DART_DYNAMIC_MODULES)
|
||||
#if !defined(DART_BYTECODE_INTERPRETER)
|
||||
UNREACHABLE();
|
||||
#endif
|
||||
#else
|
||||
@@ -11115,7 +11150,7 @@ void Function::InheritKernelOffsetFrom(const Function& src) const {
|
||||
|
||||
void Function::InheritKernelOffsetFrom(const Field& src) const {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if !defined(DART_DYNAMIC_MODULES)
|
||||
#if !defined(DART_BYTECODE_INTERPRETER)
|
||||
UNREACHABLE();
|
||||
#endif
|
||||
#else
|
||||
@@ -11551,7 +11586,7 @@ void Function::RestoreICDataMap(
|
||||
}
|
||||
|
||||
TypedDataPtr Function::GetCoverageArray() const {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
if (HasBytecode()) {
|
||||
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
const auto& bytecode = Bytecode::Handle(GetBytecode());
|
||||
@@ -11570,7 +11605,7 @@ TypedDataPtr Function::GetCoverageArray() const {
|
||||
}
|
||||
|
||||
void Function::set_ic_data_array(const Array& value) const {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
ASSERT(!HasBytecode());
|
||||
#endif
|
||||
untag()->set_ic_data_array_or_bytecode<std::memory_order_release>(
|
||||
@@ -11580,7 +11615,7 @@ void Function::set_ic_data_array(const Array& value) const {
|
||||
ArrayPtr Function::ic_data_array() const {
|
||||
ObjectPtr value =
|
||||
untag()->ic_data_array_or_bytecode<std::memory_order_acquire>();
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
if (value->IsBytecode()) {
|
||||
return Array::null();
|
||||
}
|
||||
@@ -11757,7 +11792,7 @@ bool Function::HasDynamicCallers(Zone* zone) const {
|
||||
}
|
||||
|
||||
bool Function::PrologueNeedsArgumentsDescriptor() const {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
// Entering interpreter needs arguments descriptor.
|
||||
if (is_declared_in_bytecode()) {
|
||||
return true;
|
||||
@@ -12235,7 +12270,7 @@ uint32_t Field::Hash() const {
|
||||
return String::HashRawSymbol(name());
|
||||
}
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
bool Field::is_declared_in_bytecode() const {
|
||||
return Class::Handle(Owner()).is_declared_in_bytecode();
|
||||
}
|
||||
@@ -12617,7 +12652,7 @@ FunctionPtr Field::EnsureInitializerFunction() const {
|
||||
Zone* zone = thread->zone();
|
||||
Function& initializer = Function::Handle(zone, InitializerFunction());
|
||||
if (initializer.IsNull()) {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_BYTECODE_INTERPRETER)
|
||||
UNREACHABLE();
|
||||
#else
|
||||
SafepointMutexLocker ml(
|
||||
@@ -12632,7 +12667,7 @@ FunctionPtr Field::EnsureInitializerFunction() const {
|
||||
return initializer.ptr();
|
||||
}
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
FunctionPtr Field::CreateFieldInitializerFunction(Thread* thread) const {
|
||||
Zone* zone = thread->zone();
|
||||
@@ -12712,7 +12747,7 @@ void Field::SetInitializerFunction(const Function& initializer) const {
|
||||
initializer.ptr());
|
||||
}
|
||||
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
bool Field::HasInitializerFunction() const {
|
||||
return untag()->initializer_function() != Function::null();
|
||||
@@ -12836,7 +12871,7 @@ ObjectPtr Field::EvaluateInitializer() const {
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
if (is_static() && is_const()) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
if (is_declared_in_bytecode()) {
|
||||
const auto& initializer = Function::Handle(InitializerFunction());
|
||||
ASSERT(!initializer.IsNull());
|
||||
@@ -12847,7 +12882,7 @@ ObjectPtr Field::EvaluateInitializer() const {
|
||||
ASSERT(pool.Length() == 1);
|
||||
return pool.ObjectAt(0);
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
return kernel::EvaluateStaticConstFieldInitializer(*this);
|
||||
}
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
@@ -13599,7 +13634,7 @@ void Script::set_source(const String& value) const {
|
||||
TypedDataViewPtr Script::kernel_constant_coverage() const {
|
||||
return TypedDataView::RawCast(untag()->constant_coverage());
|
||||
}
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
ArrayPtr Script::collected_constant_coverage() const {
|
||||
return Array::RawCast(untag()->constant_coverage());
|
||||
}
|
||||
@@ -13616,7 +13651,7 @@ bool Script::HasCollectedConstantCoverage() const {
|
||||
return untag()->constant_coverage()->IsArray() ||
|
||||
untag()->constant_coverage()->IsImmutableArray();
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
TypedDataPtr Script::line_starts() const {
|
||||
@@ -13662,7 +13697,7 @@ void Script::CollectDebugTokenPositions() const {
|
||||
if (kernel_program_info() != Object::null()) {
|
||||
kernel::CollectScriptTokenPositionsFromKernel(*this, &token_positions);
|
||||
} else {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
bytecode::BytecodeReader::CollectScriptTokenPositionsFromBytecode(
|
||||
*this, &token_positions);
|
||||
#else
|
||||
@@ -13678,11 +13713,11 @@ void Script::CollectDebugTokenPositions() const {
|
||||
|
||||
ArrayPtr Script::CollectConstConstructorCoverageFrom() const {
|
||||
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
if (HasCollectedConstantCoverage()) {
|
||||
return Array::RawCast(untag()->constant_coverage());
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
return CollectConstConstructorCoverageFromKernel();
|
||||
#else
|
||||
return Object::empty_array().ptr();
|
||||
@@ -13758,7 +13793,7 @@ bool Script::GetTokenLocation(const TokenPosition& token_pos,
|
||||
intptr_t* line,
|
||||
intptr_t* column) const {
|
||||
ASSERT(line != nullptr);
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_BYTECODE_INTERPRETER)
|
||||
// Scripts in the AOT snapshot do not have a line starts array.
|
||||
return false;
|
||||
#else
|
||||
@@ -13769,7 +13804,7 @@ bool Script::GetTokenLocation(const TokenPosition& token_pos,
|
||||
if (line_starts_data.IsNull()) return false;
|
||||
LineStartsReader line_starts_reader(line_starts_data);
|
||||
return line_starts_reader.LocationForPosition(token_pos.Pos(), line, column);
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
intptr_t Script::GetTokenLength(const TokenPosition& token_pos) const {
|
||||
@@ -13797,7 +13832,7 @@ bool Script::TokenRangeAtLine(intptr_t line_number,
|
||||
TokenPosition* first_token_index,
|
||||
TokenPosition* last_token_index) const {
|
||||
ASSERT(first_token_index != nullptr && last_token_index != nullptr);
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_BYTECODE_INTERPRETER)
|
||||
// Scripts in the AOT snapshot do not have a line starts array.
|
||||
return false;
|
||||
#else
|
||||
@@ -13826,7 +13861,7 @@ bool Script::TokenRangeAtLine(intptr_t line_number,
|
||||
ASSERT(last_token_index->Serialize() <= source_length);
|
||||
#endif
|
||||
return true;
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
// Returns the index in the given source string for the given (1-based) absolute
|
||||
@@ -18163,7 +18198,7 @@ void Code::set_deopt_info_array(const Array& array) const {
|
||||
}
|
||||
|
||||
void Code::set_static_calls_target_table(const Array& value) const {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_SHOREBIRD_INTERPRETER)
|
||||
UNREACHABLE();
|
||||
#else
|
||||
untag()->set_static_calls_target_table(value.ptr());
|
||||
@@ -18233,7 +18268,7 @@ TypedDataPtr Code::GetDeoptInfoAtPc(uword pc,
|
||||
}
|
||||
|
||||
intptr_t Code::BinarySearchInSCallTable(uword pc) const {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_SHOREBIRD_INTERPRETER)
|
||||
UNREACHABLE();
|
||||
#else
|
||||
NoSafepointScope no_safepoint;
|
||||
@@ -18259,7 +18294,7 @@ intptr_t Code::BinarySearchInSCallTable(uword pc) const {
|
||||
}
|
||||
|
||||
FunctionPtr Code::GetStaticCallTargetFunctionAt(uword pc) const {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_SHOREBIRD_INTERPRETER)
|
||||
UNREACHABLE();
|
||||
return Function::null();
|
||||
#else
|
||||
@@ -18960,7 +18995,7 @@ void Code::DumpSourcePositions(bool relative_addresses) const {
|
||||
|
||||
void Bytecode::Disassemble(DisassemblyFormatter* formatter) const {
|
||||
#if !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
if (!FLAG_support_disassembler) {
|
||||
return;
|
||||
}
|
||||
@@ -18972,7 +19007,7 @@ void Bytecode::Disassemble(DisassemblyFormatter* formatter) const {
|
||||
KernelBytecodeDisassembler::Disassemble(start, start + size, formatter,
|
||||
*this);
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
#endif // !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
|
||||
}
|
||||
|
||||
@@ -19001,7 +19036,7 @@ BytecodePtr Bytecode::New(uword instructions,
|
||||
}
|
||||
|
||||
TokenPosition Bytecode::GetTokenIndexOfPC(uword return_address) const {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
if (!HasSourcePositions()) {
|
||||
return TokenPosition::kNoSource;
|
||||
}
|
||||
@@ -19024,7 +19059,7 @@ TokenPosition Bytecode::GetTokenIndexOfPC(uword return_address) const {
|
||||
}
|
||||
|
||||
intptr_t Bytecode::GetTryIndexAtPc(uword return_address) const {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
intptr_t try_index = -1;
|
||||
const uword pc_offset = return_address - PayloadStart();
|
||||
const PcDescriptors& descriptors = PcDescriptors::Handle(pc_descriptors());
|
||||
@@ -19053,7 +19088,7 @@ intptr_t Bytecode::GetTryIndexAtPc(uword return_address) const {
|
||||
}
|
||||
|
||||
uword Bytecode::GetInstructionBefore(uword return_address) const {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
const uword start = PayloadStart();
|
||||
// return_address could be the end of the bytecode instructions
|
||||
// if the last instruction is Throw.
|
||||
@@ -19076,7 +19111,7 @@ uword Bytecode::GetInstructionBefore(uword return_address) const {
|
||||
|
||||
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
LocalVarDescriptorsPtr Bytecode::GetLocalVarDescriptors() const {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
Zone* zone = Thread::Current()->zone();
|
||||
auto& var_descs = LocalVarDescriptors::Handle(zone, var_descriptors());
|
||||
if (var_descs.IsNull()) {
|
||||
@@ -19094,7 +19129,7 @@ LocalVarDescriptorsPtr Bytecode::GetLocalVarDescriptors() const {
|
||||
}
|
||||
|
||||
TypedDataPtr Bytecode::EnsureCoverageArray(Thread* thread) const {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
// Should only be called for bytecode with RecordCoverage instructions.
|
||||
ASSERT(HasRecordedCoverage());
|
||||
if (coverage_array() == TypedData::null()) {
|
||||
@@ -19188,7 +19223,7 @@ const char* Bytecode::FullyQualifiedName() const {
|
||||
}
|
||||
|
||||
BytecodePtr Bytecode::FindBytecode(uword pc) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
class SlowFindBytecodeVisitor : public ObjectVisitor {
|
||||
public:
|
||||
explicit SlowFindBytecodeVisitor(uword pc)
|
||||
@@ -27024,7 +27059,7 @@ const char* StackTrace::ToCString() const {
|
||||
// A visible frame ends any gap we might be in.
|
||||
in_gap = false;
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
if (code_object.IsBytecode()) {
|
||||
const auto& bytecode = Bytecode::Cast(code_object);
|
||||
function = bytecode.function();
|
||||
@@ -27038,7 +27073,7 @@ const char* StackTrace::ToCString() const {
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
ASSERT(code_object.IsCode());
|
||||
code ^= code_object.ptr();
|
||||
|
||||
+21
-17
@@ -1772,14 +1772,14 @@ class Class : public Object {
|
||||
bool is_loaded() const { return IsLoadedBit::decode(state_bits()); }
|
||||
void set_is_loaded(bool value) const;
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
bool is_declared_in_bytecode() const {
|
||||
return IsDeclaredInBytecodeBit::decode(state_bits());
|
||||
}
|
||||
void set_is_declared_in_bytecode(bool value) const;
|
||||
#else
|
||||
bool is_declared_in_bytecode() const { return false; }
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
uint16_t num_native_fields() const { return untag()->num_native_fields_; }
|
||||
void set_num_native_fields(uint16_t value) const {
|
||||
@@ -3176,6 +3176,10 @@ class Function : public Object {
|
||||
bool HasCode() const;
|
||||
static bool HasCode(FunctionPtr function);
|
||||
|
||||
#if defined(DART_SHOREBIRD_INTERPRETER)
|
||||
bool IsShorebirdPatchable() const;
|
||||
#endif
|
||||
|
||||
static intptr_t code_offset() { return OFFSET_OF(UntaggedFunction, code_); }
|
||||
|
||||
uword entry_point() const { return EntryPointOf(ptr()); }
|
||||
@@ -3199,7 +3203,7 @@ class Function : public Object {
|
||||
return OFFSET_OF(UntaggedFunction, unchecked_entry_point_);
|
||||
}
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
void AttachBytecode(const Bytecode& bytecode) const;
|
||||
void ClearBytecode() const;
|
||||
inline BytecodePtr GetBytecode() const;
|
||||
@@ -3537,11 +3541,11 @@ class Function : public Object {
|
||||
|
||||
#undef DEFINE_GETTERS_AND_SETTERS
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
bool is_declared_in_bytecode() const;
|
||||
#else
|
||||
bool is_declared_in_bytecode() const { return false; }
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
intptr_t kernel_offset() const {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
@@ -4034,7 +4038,7 @@ class Function : public Object {
|
||||
|
||||
static StringPtr CreateDynamicInvocationForwarderName(const String& name);
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER)
|
||||
FunctionPtr CreateDynamicInvocationForwarder(
|
||||
const String& mangled_name) const;
|
||||
|
||||
@@ -4507,11 +4511,11 @@ class Field : public Object {
|
||||
return untag()->kind_bits_.Read<IsDynamicallyCallableBit>();
|
||||
}
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
bool is_declared_in_bytecode() const;
|
||||
#else
|
||||
bool is_declared_in_bytecode() const { return false; }
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
intptr_t kernel_offset() const {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
@@ -4832,10 +4836,10 @@ class Field : public Object {
|
||||
return OFFSET_OF(UntaggedField, initializer_function_);
|
||||
}
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER)
|
||||
FunctionPtr CreateFieldInitializerFunction(Thread* thread) const;
|
||||
void SetInitializerFunction(const Function& initializer) const;
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
// Constructs getter and setter names for fields and vice versa.
|
||||
static StringPtr GetterName(const String& field_name);
|
||||
@@ -5067,19 +5071,19 @@ class Script : public Object {
|
||||
|
||||
ArrayPtr CollectConstConstructorCoverageFrom() const;
|
||||
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
void set_collected_constant_coverage(const Array& value) const;
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
private:
|
||||
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
TypedDataViewPtr kernel_constant_coverage() const;
|
||||
ArrayPtr CollectConstConstructorCoverageFromKernel() const;
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
ArrayPtr collected_constant_coverage() const;
|
||||
bool HasCollectedConstantCoverage() const;
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
void set_debug_positions(const Array& value) const;
|
||||
@@ -7122,7 +7126,7 @@ class Code : public Object {
|
||||
|
||||
void set_static_calls_target_table(const Array& value) const;
|
||||
ArrayPtr static_calls_target_table() const {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_SHOREBIRD_INTERPRETER)
|
||||
UNREACHABLE();
|
||||
return nullptr;
|
||||
#else
|
||||
@@ -13555,7 +13559,7 @@ void Object::setPtr(ObjectPtr value, intptr_t default_cid) {
|
||||
set_vtable(builtin_vtables_[cid]);
|
||||
}
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
BytecodePtr Function::GetBytecode() const {
|
||||
return GetBytecode(ptr());
|
||||
}
|
||||
@@ -13571,7 +13575,7 @@ bool Function::HasBytecode() const {
|
||||
bool Function::HasBytecode(FunctionPtr function) {
|
||||
return function.untag()->ic_data_array_or_bytecode()->IsBytecode();
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
intptr_t Field::HostOffset() const {
|
||||
ASSERT(is_instance()); // Valid only for dart instance fields.
|
||||
|
||||
@@ -1133,7 +1133,7 @@ class RetainingPath {
|
||||
Function& function = Function::Handle(zone_);
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(PRODUCT)
|
||||
Code& code = Code::Handle(zone_);
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
Bytecode& bytecode = Bytecode::Handle(zone_);
|
||||
#endif
|
||||
LocalVarDescriptors& var_descriptors = LocalVarDescriptors::Handle(zone_);
|
||||
@@ -1194,12 +1194,12 @@ class RetainingPath {
|
||||
// Attempt to convert "instance <- Context+ <- Closure" into
|
||||
// "instance <- local var name in Closure".
|
||||
if (function.is_declared_in_bytecode()) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
bytecode = function.GetBytecode();
|
||||
var_descriptors = bytecode.GetLocalVarDescriptors();
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
} else {
|
||||
if (!function.ForceOptimize()) {
|
||||
function.EnsureHasCompiledUnoptimizedCode();
|
||||
|
||||
@@ -844,7 +844,7 @@ void CallSiteResetter::Reset(const ICData& ic) {
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
static ArrayPtr PrepareNoSuchMethodErrorArguments(const Function& target,
|
||||
bool incompatible_arguments) {
|
||||
InvocationMirror::Kind kind = InvocationMirror::Kind::kMethod;
|
||||
@@ -891,10 +891,10 @@ static ArrayPtr PrepareNoSuchMethodErrorArguments(const Function& target,
|
||||
args.SetAt(6, Object::null_object());
|
||||
return args.ptr();
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
void CallSiteResetter::RebindBytecode(const Bytecode& bytecode) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
pool_ = bytecode.object_pool();
|
||||
ASSERT(!pool_.IsNull());
|
||||
|
||||
@@ -991,7 +991,7 @@ void CallSiteResetter::RebindBytecode(const Bytecode& bytecode) {
|
||||
}
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
@@ -509,7 +509,7 @@ void Profiler::DumpStackTrace(uword sp, uword fp, uword pc, bool for_crash) {
|
||||
StackFrame::DumpCurrentTrace();
|
||||
} else if (thread->execution_state() == Thread::kThreadInGenerated) {
|
||||
// No exit frame, walk from the crash's registers.
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
if (thread->vm_tag() == VMTag::kDartInterpretedTagId) {
|
||||
Interpreter* interpreter = thread->interpreter();
|
||||
sp = interpreter->get_sp();
|
||||
@@ -517,7 +517,7 @@ void Profiler::DumpStackTrace(uword sp, uword fp, uword pc, bool for_crash) {
|
||||
pc = interpreter->get_pc();
|
||||
StackFrame::DumpCurrentTrace(sp, fp, pc);
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
if (thread->vm_tag() == VMTag::kDartTagId) {
|
||||
StackFrame::DumpCurrentTrace(sp, fp, pc);
|
||||
}
|
||||
@@ -1098,7 +1098,7 @@ class ProfilerDartStackWalker : public ProfilerStackWalker {
|
||||
}
|
||||
|
||||
bool IsInterpretedFrame() const {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
Interpreter* interpreter = thread_->interpreter();
|
||||
return (interpreter != nullptr) &&
|
||||
interpreter->HasFrame(reinterpret_cast<uword>(fp_));
|
||||
@@ -1366,7 +1366,7 @@ void Profiler::SampleThread(Thread* thread,
|
||||
lr = simulator->get_lr();
|
||||
}
|
||||
#endif
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
if (thread->vm_tag() == VMTag::kDartInterpretedTagId) {
|
||||
sp = 0;
|
||||
pc = thread->interpreter()->get_pc();
|
||||
|
||||
@@ -1101,7 +1101,7 @@ class ProfileBuilder : public ValueObject {
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
if (profile_code->code().IsBytecode()) {
|
||||
const auto& bytecode =
|
||||
Bytecode::CheckedHandle(zone, profile_code->code().ptr());
|
||||
|
||||
@@ -384,6 +384,16 @@ void ProgramVisitor::BindStaticCalls(Thread* thread) {
|
||||
// Cf. runtime entry PatchStaticCall called from CallStaticFunction
|
||||
// stub.
|
||||
const auto& fun = Function::Cast(target_);
|
||||
#if defined(DART_SHOREBIRD_INTERPRETER)
|
||||
if (FLAG_precompiled_mode) {
|
||||
// Precompiler::ReplaceFunctionStaticCallEntries has already converted
|
||||
// non-patchable Function targets to Code targets. Any remaining
|
||||
// Function target must stay indirect so runtime dispatch observes the
|
||||
// current Function::entry_point without executable writes.
|
||||
only_call_via_code = false;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
ASSERT(!FLAG_precompiled_mode || fun.HasCode());
|
||||
target_code_ = fun.HasCode() ? fun.CurrentCode()
|
||||
: StubCode::CallStaticFunction().ptr();
|
||||
|
||||
@@ -2058,8 +2058,12 @@ class UntaggedCode : public UntaggedObject {
|
||||
POINTER_FIELD(CodeSourceMapPtr, code_source_map)
|
||||
NOT_IN_PRECOMPILED(POINTER_FIELD(InstructionsPtr, active_instructions))
|
||||
NOT_IN_PRECOMPILED(POINTER_FIELD(ArrayPtr, deopt_info_array))
|
||||
// (code-offset, function, code) triples.
|
||||
NOT_IN_PRECOMPILED(POINTER_FIELD(ArrayPtr, static_calls_target_table))
|
||||
// (code-offset, function, code) triples. Normally omitted from the
|
||||
// precompiled runtime, but retained for Shorebird interpreter patching so
|
||||
// static calls can resolve the current Function::entry_point at runtime.
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_SHOREBIRD_INTERPRETER)
|
||||
POINTER_FIELD(ArrayPtr, static_calls_target_table)
|
||||
#endif
|
||||
// If return_address_metadata_ is a Smi, it is the offset to the prologue.
|
||||
// Else, return_address_metadata_ is null.
|
||||
NOT_IN_PRODUCT(POINTER_FIELD(ObjectPtr, return_address_metadata))
|
||||
@@ -2068,7 +2072,7 @@ class UntaggedCode : public UntaggedObject {
|
||||
|
||||
#if !defined(PRODUCT)
|
||||
VISIT_TO(comments);
|
||||
#elif defined(DART_PRECOMPILED_RUNTIME)
|
||||
#elif defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_SHOREBIRD_INTERPRETER)
|
||||
VISIT_TO(code_source_map);
|
||||
#else
|
||||
VISIT_TO(static_calls_target_table);
|
||||
|
||||
@@ -211,7 +211,11 @@ namespace dart {
|
||||
F(TypedDataView, typed_data_) \
|
||||
F(TypedDataView, offset_in_bytes_)
|
||||
|
||||
#if defined(DART_SHOREBIRD_INTERPRETER)
|
||||
#define AOT_CLASSES_AND_FIELDS(F) F(Code, static_calls_target_table_)
|
||||
#else
|
||||
#define AOT_CLASSES_AND_FIELDS(F)
|
||||
#endif
|
||||
|
||||
#define AOT_NON_PRODUCT_CLASSES_AND_FIELDS(F) \
|
||||
F(Class, direct_implementors_) \
|
||||
|
||||
@@ -22,7 +22,7 @@ static FunctionPtr ResolveDynamicAnyArgsWithCustomLookup(
|
||||
const String& function_name,
|
||||
bool allow_add,
|
||||
std::function<FunctionPtr(Class&, const String&)> lookup) {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_BYTECODE_INTERPRETER)
|
||||
// No methods can be added in the precompiled runtime unless dynamic
|
||||
// modules are enabled. In this case, calls from dynamic modules may
|
||||
// necessitate the creation of (interpreted) forwarders, even for
|
||||
@@ -69,7 +69,7 @@ static FunctionPtr ResolveDynamicAnyArgsWithCustomLookup(
|
||||
SafepointReadRwLocker ml(thread, thread->isolate_group()->program_lock());
|
||||
function = lookup(cls, *demangled_name);
|
||||
}
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER)
|
||||
if (allow_add && is_dyn_call && !function.IsNull()) {
|
||||
// In JIT mode or if dynamic modules are enabled, lazily create a dyn:*
|
||||
// forwarder if one is required.
|
||||
|
||||
+56
-43
@@ -637,7 +637,7 @@ static void ThrowIfError(const Object& result) {
|
||||
// Return value: newly allocated object.
|
||||
DEFINE_RUNTIME_ENTRY(AllocateObject, 2) {
|
||||
const Class& cls = Class::CheckedHandle(zone, arguments.ArgAt(0));
|
||||
#if defined(DART_DYNAMIC_MODULES) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_BYTECODE_INTERPRETER) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
if (!cls.is_allocate_finalized()) {
|
||||
const Error& error =
|
||||
Error::Handle(zone, cls.EnsureIsAllocateFinalized(thread));
|
||||
@@ -1004,13 +1004,13 @@ DEFINE_RUNTIME_ENTRY(CloneSuspendState, 1) {
|
||||
// Allocate a new SubtypeTestCache for use in interpreted implicit setters.
|
||||
// Return value: newly allocated SubtypeTestCache.
|
||||
DEFINE_RUNTIME_ENTRY(AllocateSubtypeTestCache, 0) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
const auto& cache = SubtypeTestCache::Handle(
|
||||
zone, SubtypeTestCache::New(SubtypeTestCache::kMaxInputs));
|
||||
arguments.SetReturn(cache);
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
// Invoke field getter before dispatch.
|
||||
@@ -1018,7 +1018,7 @@ DEFINE_RUNTIME_ENTRY(AllocateSubtypeTestCache, 0) {
|
||||
// Arg1: field name (may be demangled during call).
|
||||
// Return value: field value.
|
||||
DEFINE_RUNTIME_ENTRY(GetFieldForDispatch, 2) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
const Instance& receiver = Instance::CheckedHandle(zone, arguments.ArgAt(0));
|
||||
String& name = String::CheckedHandle(zone, arguments.ArgAt(1));
|
||||
const Class& receiver_class = Class::Handle(zone, receiver.clazz());
|
||||
@@ -1043,7 +1043,7 @@ DEFINE_RUNTIME_ENTRY(GetFieldForDispatch, 2) {
|
||||
arguments.SetReturn(result);
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
// Converts arguments descriptor passed to an implicit closure
|
||||
@@ -1053,7 +1053,7 @@ DEFINE_RUNTIME_ENTRY(GetFieldForDispatch, 2) {
|
||||
// Arg2: new type args length
|
||||
// Return value: target arguments descriptor
|
||||
DEFINE_RUNTIME_ENTRY(AdjustArgumentsDesciptorForImplicitClosure, 3) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
const auto& descriptor = Array::CheckedHandle(zone, arguments.ArgAt(0));
|
||||
const auto& target = Function::CheckedHandle(zone, arguments.ArgAt(1));
|
||||
intptr_t type_args_len = Smi::CheckedHandle(zone, arguments.ArgAt(2)).Value();
|
||||
@@ -1079,7 +1079,7 @@ DEFINE_RUNTIME_ENTRY(AdjustArgumentsDesciptorForImplicitClosure, 3) {
|
||||
arguments.SetReturn(result);
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
// Converts type arguments passed to a constructor tear-off
|
||||
@@ -1088,7 +1088,7 @@ DEFINE_RUNTIME_ENTRY(AdjustArgumentsDesciptorForImplicitClosure, 3) {
|
||||
// Arg1: type arguments
|
||||
// Return value: instance type arguments
|
||||
DEFINE_RUNTIME_ENTRY(ConvertToInstanceTypeArguments, 2) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
const auto& cls = Class::CheckedHandle(zone, arguments.ArgAt(0));
|
||||
const auto& type_args =
|
||||
TypeArguments::CheckedHandle(zone, arguments.ArgAt(1));
|
||||
@@ -1097,7 +1097,7 @@ DEFINE_RUNTIME_ENTRY(ConvertToInstanceTypeArguments, 2) {
|
||||
arguments.SetReturn(result);
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
// Check that arguments are valid for the given closure.
|
||||
@@ -1105,7 +1105,7 @@ DEFINE_RUNTIME_ENTRY(ConvertToInstanceTypeArguments, 2) {
|
||||
// Arg1: arguments descriptor
|
||||
// Return value: whether the arguments are valid
|
||||
DEFINE_RUNTIME_ENTRY(ClosureArgumentsValid, 2) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
const auto& closure = Closure::CheckedHandle(zone, arguments.ArgAt(0));
|
||||
const auto& descriptor = Array::CheckedHandle(zone, arguments.ArgAt(1));
|
||||
|
||||
@@ -1122,7 +1122,7 @@ DEFINE_RUNTIME_ENTRY(ClosureArgumentsValid, 2) {
|
||||
}
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
// Resolve 'call' function of receiver.
|
||||
@@ -1130,7 +1130,7 @@ DEFINE_RUNTIME_ENTRY(ClosureArgumentsValid, 2) {
|
||||
// Arg1: arguments descriptor
|
||||
// Return value: 'call' function'.
|
||||
DEFINE_RUNTIME_ENTRY(ResolveCallFunction, 2) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
const Instance& receiver = Instance::CheckedHandle(zone, arguments.ArgAt(0));
|
||||
const Array& descriptor = Array::CheckedHandle(zone, arguments.ArgAt(1));
|
||||
ArgumentsDescriptor args_desc(descriptor);
|
||||
@@ -1143,14 +1143,14 @@ DEFINE_RUNTIME_ENTRY(ResolveCallFunction, 2) {
|
||||
arguments.SetReturn(call_function);
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
// Resolve external method call from the interpreter.
|
||||
// Arg0: function.
|
||||
// Arg1: pool index to store resolved trampoline and native function.
|
||||
DEFINE_RUNTIME_ENTRY(ResolveExternalCall, 2) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
const auto& function = Function::CheckedHandle(zone, arguments.ArgAt(0));
|
||||
const intptr_t pool_index =
|
||||
Smi::CheckedHandle(zone, arguments.ArgAt(1)).Value();
|
||||
@@ -1194,10 +1194,10 @@ DEFINE_RUNTIME_ENTRY(ResolveExternalCall, 2) {
|
||||
pool.SetRawValueAt(pool_index + 1, reinterpret_cast<uword>(target_function));
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_BYTECODE_INTERPRETER) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
struct FfiCallArguments {
|
||||
uword stack_area;
|
||||
@@ -1442,13 +1442,13 @@ static uword ResolveFfiNativeTarget(Thread* thread, const Function& function) {
|
||||
return static_cast<uword>(Integer::Cast(result).Value());
|
||||
}
|
||||
|
||||
#endif // defined(DART_DYNAMIC_MODULES) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
// Perform FFI call from the interpreter.
|
||||
// Arg0: function.
|
||||
// Arg1: constant pool index to store resolved target.
|
||||
DEFINE_RUNTIME_ENTRY(FfiCall, 2) {
|
||||
#if defined(DART_DYNAMIC_MODULES) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_BYTECODE_INTERPRETER) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
const auto& function = Function::CheckedZoneHandle(zone, arguments.ArgAt(0));
|
||||
const intptr_t pool_index =
|
||||
Smi::CheckedHandle(zone, arguments.ArgAt(1)).Value();
|
||||
@@ -1533,7 +1533,7 @@ DEFINE_RUNTIME_ENTRY(FfiCall, 2) {
|
||||
Object::Handle(zone, ReceiveFfiCallResult(thread, marshaller, &args)));
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif // defined(DART_DYNAMIC_MODULES) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
}
|
||||
|
||||
// Check that argument types are valid for the given function.
|
||||
@@ -1542,7 +1542,7 @@ DEFINE_RUNTIME_ENTRY(FfiCall, 2) {
|
||||
// Arg2: arguments
|
||||
// Return value: whether the arguments are valid
|
||||
DEFINE_RUNTIME_ENTRY(CheckFunctionArgumentTypes, 3) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
const auto& function = Function::CheckedHandle(zone, arguments.ArgAt(0));
|
||||
const auto& descriptor = Array::CheckedHandle(zone, arguments.ArgAt(1));
|
||||
const auto& args = Array::CheckedHandle(zone, arguments.ArgAt(2));
|
||||
@@ -1560,7 +1560,7 @@ DEFINE_RUNTIME_ENTRY(CheckFunctionArgumentTypes, 3) {
|
||||
}
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
// Helper routine for tracing a type check.
|
||||
@@ -1608,7 +1608,7 @@ static void PrintTypeCheck(const char* message,
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(TARGET_ARCH_IA32) || defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(TARGET_ARCH_IA32) || defined(DART_BYTECODE_INTERPRETER)
|
||||
static BoolPtr CheckHashBasedSubtypeTestCache(
|
||||
Zone* zone,
|
||||
Thread* thread,
|
||||
@@ -1660,7 +1660,7 @@ static BoolPtr CheckHashBasedSubtypeTestCache(
|
||||
|
||||
return Bool::null();
|
||||
}
|
||||
#endif // defined(TARGET_ARCH_IA32) || defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(TARGET_ARCH_IA32) || defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
// This updates the type test cache, an array containing 8 elements:
|
||||
// - instance class (or function if the instance is a closure)
|
||||
@@ -1897,7 +1897,7 @@ DEFINE_RUNTIME_ENTRY(TypeCheck, 7) {
|
||||
ASSERT(mode == kTypeCheckFromInline);
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_ARCH_IA32) || defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(TARGET_ARCH_IA32) || defined(DART_BYTECODE_INTERPRETER)
|
||||
// Hash-based caches are not handled by the inline AssertAssignable
|
||||
// on IA32 and in the interpreter.
|
||||
if ((mode == kTypeCheckFromInline) && cache.IsHash()) {
|
||||
@@ -1911,7 +1911,7 @@ DEFINE_RUNTIME_ENTRY(TypeCheck, 7) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif // defined(TARGET_ARCH_IA32) || defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(TARGET_ARCH_IA32) || defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
// This is guaranteed on the calling side.
|
||||
ASSERT(!dst_type.IsDynamicType());
|
||||
@@ -2175,7 +2175,20 @@ DEFINE_RUNTIME_ENTRY(ReThrow, 3) {
|
||||
// Patches static call in optimized code with the target's entry point.
|
||||
// Compiles target if necessary.
|
||||
DEFINE_RUNTIME_ENTRY(PatchStaticCall, 0) {
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) && defined(DART_SHOREBIRD_INTERPRETER)
|
||||
DartFrameIterator iterator(thread,
|
||||
StackFrameIterator::kNoCrossThreadIteration);
|
||||
StackFrame* caller_frame = iterator.NextFrame();
|
||||
ASSERT(caller_frame != nullptr);
|
||||
ASSERT(!caller_frame->is_interpreted());
|
||||
const Code& caller_code = Code::Handle(zone, caller_frame->LookupDartCode());
|
||||
ASSERT(!caller_code.IsNull());
|
||||
const Function& target_function = Function::Handle(
|
||||
zone, caller_code.GetStaticCallTargetFunctionAt(caller_frame->pc()));
|
||||
RELEASE_ASSERT(!target_function.IsNull());
|
||||
ASSERT(target_function.HasCode());
|
||||
arguments.SetReturn(target_function);
|
||||
#elif !defined(DART_PRECOMPILED_RUNTIME)
|
||||
DartFrameIterator iterator(thread,
|
||||
StackFrameIterator::kNoCrossThreadIteration);
|
||||
StackFrame* caller_frame = iterator.NextFrame();
|
||||
@@ -2252,7 +2265,7 @@ DEFINE_RUNTIME_ENTRY(SingleStepHandler, 0) {
|
||||
}
|
||||
|
||||
DEFINE_RUNTIME_ENTRY(ResumptionBreakpointHandler, 0) {
|
||||
#if defined(DART_DYNAMIC_MODULES) && !defined(PRODUCT)
|
||||
#if defined(DART_BYTECODE_INTERPRETER) && !defined(PRODUCT)
|
||||
isolate->debugger()->ResumptionBreakpoint();
|
||||
#else
|
||||
UNREACHABLE();
|
||||
@@ -3459,7 +3472,7 @@ DEFINE_RUNTIME_ENTRY(SwitchableCallMiss, 2) {
|
||||
// Returns: target function (can only be null in AOT runtime)
|
||||
// Modifies the instance call table in current interpreter.
|
||||
DEFINE_RUNTIME_ENTRY(InterpretedInstanceCallMissHandler, 3) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
const Instance& receiver = Instance::CheckedHandle(zone, arguments.ArgAt(0));
|
||||
const String& target_name = String::CheckedHandle(zone, arguments.ArgAt(1));
|
||||
const Array& arg_desc = Array::CheckedHandle(zone, arguments.ArgAt(2));
|
||||
@@ -3491,7 +3504,7 @@ DEFINE_RUNTIME_ENTRY(InterpretedInstanceCallMissHandler, 3) {
|
||||
arguments.SetReturn(target_function);
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
@@ -3739,7 +3752,7 @@ DEFINE_RUNTIME_ENTRY(NoSuchMethodError, 1) {
|
||||
// Arg2: arguments descriptor array.
|
||||
// Arg3: arguments array.
|
||||
DEFINE_RUNTIME_ENTRY(InvokeNoSuchMethod, 4) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
const Instance& receiver = Instance::CheckedHandle(zone, arguments.ArgAt(0));
|
||||
const String& original_function_name =
|
||||
String::CheckedHandle(zone, arguments.ArgAt(1));
|
||||
@@ -3763,7 +3776,7 @@ DEFINE_RUNTIME_ENTRY(InvokeNoSuchMethod, 4) {
|
||||
arguments.SetReturn(result);
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
@@ -3976,13 +3989,13 @@ DEFINE_RUNTIME_ENTRY(InterruptOrStackOverflow, 0) {
|
||||
uword stack_overflow_flags = thread->GetAndClearStackOverflowFlags();
|
||||
|
||||
bool interpreter_stack_overflow = false;
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
Interpreter* interpreter = thread->interpreter();
|
||||
if (interpreter != nullptr) {
|
||||
interpreter_stack_overflow =
|
||||
interpreter->get_sp() >= interpreter->overflow_stack_limit();
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
// If an interrupt happens at the same time as a stack overflow, we
|
||||
// process the stack overflow now and leave the interrupt for next
|
||||
@@ -3993,13 +4006,13 @@ DEFINE_RUNTIME_ENTRY(InterruptOrStackOverflow, 0) {
|
||||
OS::PrintErr("Stack overflow\n");
|
||||
OS::PrintErr(" Native SP = %" Px ", stack limit = %" Px "\n", stack_pos,
|
||||
thread->saved_stack_limit());
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
if (thread->interpreter() != nullptr) {
|
||||
OS::PrintErr(" Interpreter SP = %" Px ", stack limit = %" Px "\n",
|
||||
thread->interpreter()->get_sp(),
|
||||
thread->interpreter()->overflow_stack_limit());
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
OS::PrintErr("Call stack:\n");
|
||||
OS::PrintErr("size | frame\n");
|
||||
@@ -4821,7 +4834,7 @@ DEFINE_LEAF_RUNTIME_ENTRY(MemoryMove,
|
||||
/*argument_count=*/3,
|
||||
static_cast<MemMoveCFunction>(memmove));
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
// Interpret a function call. Should be called only for non-jitted functions.
|
||||
// argc indicates the number of arguments, including the type arguments.
|
||||
// argv points to the first argument.
|
||||
@@ -4867,10 +4880,10 @@ extern "C" uword /*ObjectPtr*/ InterpretCall(uword /*FunctionPtr*/ function_in,
|
||||
}
|
||||
return static_cast<uword>(result);
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
uword RuntimeEntry::InterpretCallEntry() {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
uword entry = reinterpret_cast<uword>(InterpretCall);
|
||||
#if defined(DART_INCLUDE_SIMULATOR)
|
||||
if (FLAG_use_simulator) {
|
||||
@@ -4881,7 +4894,7 @@ uword RuntimeEntry::InterpretCallEntry() {
|
||||
return entry;
|
||||
#else
|
||||
return 0;
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
// Restore suspended interpreter frame and resume execution.
|
||||
@@ -4890,7 +4903,7 @@ uword RuntimeEntry::InterpretCallEntry() {
|
||||
// Arg1: exception
|
||||
// Arg2: stack trace
|
||||
DEFINE_RUNTIME_ENTRY(ResumeInterpreter, 3) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
const Instance& value = Instance::CheckedHandle(zone, arguments.ArgAt(0));
|
||||
const Instance& exception = Instance::CheckedHandle(zone, arguments.ArgAt(1));
|
||||
const Instance& stack_trace =
|
||||
@@ -4928,14 +4941,14 @@ DEFINE_RUNTIME_ENTRY(ResumeInterpreter, 3) {
|
||||
arguments.SetReturn(result);
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
// Lazily allocates a coverage array for bytecode prior to recording coverage.
|
||||
//
|
||||
// Arg0: Bytecode object that needs an allocated coverage array.
|
||||
DEFINE_RUNTIME_ENTRY(AllocateBytecodeCoverageArray, 1) {
|
||||
#if defined(DART_DYNAMIC_MODULES) && !defined(PRODUCT) && \
|
||||
#if defined(DART_BYTECODE_INTERPRETER) && !defined(PRODUCT) && \
|
||||
!defined(DART_PRECOMPILED_RUNTIME)
|
||||
const auto& bytecode = Bytecode::CheckedHandle(zone, arguments.ArgAt(0));
|
||||
const auto& coverage_array =
|
||||
@@ -4943,7 +4956,7 @@ DEFINE_RUNTIME_ENTRY(AllocateBytecodeCoverageArray, 1) {
|
||||
arguments.SetReturn(coverage_array);
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif // defined(DART_DYNAMIC_MODULES) && !defined(PRODUCT) &&
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER) && !defined(PRODUCT) &&
|
||||
// !defined(DART_PRECOMPILED_RUNTIME)
|
||||
}
|
||||
|
||||
|
||||
@@ -2199,7 +2199,7 @@ static ObjectPtr LookupHeapObjectCode(char** parts, int num_parts) {
|
||||
if (!code.IsNull()) {
|
||||
return code.ptr();
|
||||
}
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
const auto& bytecode = Bytecode::Handle(Bytecode::FindBytecode(pc));
|
||||
if (!bytecode.IsNull()) {
|
||||
return bytecode.ptr();
|
||||
|
||||
@@ -456,7 +456,7 @@ ISOLATE_UNIT_TEST_CASE(Service_LocalVarDescriptors) {
|
||||
EXPECT(!function_c.IsNull());
|
||||
LocalVarDescriptors& descriptors = LocalVarDescriptors::Handle();
|
||||
if (function_c.IsInterpreted()) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
const Bytecode& bytecode_c = Bytecode::Handle(function_c.GetBytecode());
|
||||
EXPECT(!bytecode_c.IsNull());
|
||||
descriptors = bytecode_c.var_descriptors();
|
||||
|
||||
@@ -443,7 +443,7 @@ void SourceReport::PrintPossibleBreakpointsData(JSONObject* jsobj,
|
||||
BitVector possible(zone(), func_length);
|
||||
|
||||
if (func.HasBytecode()) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
const auto& bytecode = Bytecode::Handle(zone(), func.GetBytecode());
|
||||
// Currently, every source position is a possible breakpoint.
|
||||
bytecode::BytecodeSourcePositionsIterator iter(zone(), bytecode);
|
||||
|
||||
+11
-11
@@ -176,7 +176,7 @@ const char* StackFrame::ToCString() const {
|
||||
const char* name = nullptr;
|
||||
uword start = 0;
|
||||
if (is_interpreted()) {
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
if (IsEntryFrame()) {
|
||||
name = "[Interpreter] Entry frame";
|
||||
} else if (IsExitFrame()) {
|
||||
@@ -192,7 +192,7 @@ const char* StackFrame::ToCString() const {
|
||||
}
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
} else if (IsEntryFrame()) {
|
||||
name = "[Stub] Entry frame";
|
||||
} else if (IsExitFrame()) {
|
||||
@@ -606,7 +606,7 @@ void StackFrameIterator::SetupLastExitFrameData() {
|
||||
frames_.fp_ = exit_marker;
|
||||
frames_.sp_ = 0;
|
||||
frames_.pc_ = 0;
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
frames_.CheckIfInterpreted(exit_marker);
|
||||
#endif
|
||||
frames_.Unpoison();
|
||||
@@ -622,7 +622,7 @@ void StackFrameIterator::SetupNextExitFrameData() {
|
||||
frames_.fp_ = exit_marker;
|
||||
frames_.sp_ = 0;
|
||||
frames_.pc_ = 0;
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
frames_.CheckIfInterpreted(exit_marker);
|
||||
#endif
|
||||
frames_.Unpoison();
|
||||
@@ -657,7 +657,7 @@ StackFrameIterator::StackFrameIterator(uword last_fp,
|
||||
frames_.fp_ = last_fp;
|
||||
frames_.sp_ = 0;
|
||||
frames_.pc_ = 0;
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
frames_.CheckIfInterpreted(last_fp);
|
||||
#endif
|
||||
frames_.Unpoison();
|
||||
@@ -680,7 +680,7 @@ StackFrameIterator::StackFrameIterator(uword fp,
|
||||
frames_.fp_ = fp;
|
||||
frames_.sp_ = sp;
|
||||
frames_.pc_ = pc;
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
frames_.CheckIfInterpreted(fp);
|
||||
#endif
|
||||
frames_.Unpoison();
|
||||
@@ -753,14 +753,14 @@ StackFrame* StackFrameIterator::NextFrame() {
|
||||
return current_frame_;
|
||||
}
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
void StackFrameIterator::FrameSetIterator::CheckIfInterpreted(
|
||||
uword exit_marker) {
|
||||
Interpreter* interpreter = thread_->interpreter();
|
||||
is_interpreted_ =
|
||||
(interpreter != nullptr) && interpreter->HasFrame(exit_marker);
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
|
||||
// Tell MemorySanitizer that generated code initializes part of the stack.
|
||||
void StackFrameIterator::FrameSetIterator::Unpoison() {
|
||||
@@ -794,7 +794,7 @@ StackFrame* StackFrameIterator::FrameSetIterator::NextFrame(bool validate) {
|
||||
frame->sp_ = sp_;
|
||||
frame->fp_ = fp_;
|
||||
frame->pc_ = pc_;
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
frame->is_interpreted_ = is_interpreted();
|
||||
#endif
|
||||
sp_ = frame->GetCallerSp();
|
||||
@@ -810,7 +810,7 @@ ExitFrame* StackFrameIterator::NextExitFrame() {
|
||||
exit_.sp_ = frames_.sp_;
|
||||
exit_.fp_ = frames_.fp_;
|
||||
exit_.pc_ = frames_.pc_;
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
exit_.is_interpreted_ = frames_.is_interpreted();
|
||||
#endif
|
||||
frames_.sp_ = exit_.GetCallerSp();
|
||||
@@ -827,7 +827,7 @@ EntryFrame* StackFrameIterator::NextEntryFrame() {
|
||||
entry_.sp_ = frames_.sp_;
|
||||
entry_.fp_ = frames_.fp_;
|
||||
entry_.pc_ = frames_.pc_;
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
entry_.is_interpreted_ = frames_.is_interpreted();
|
||||
#endif
|
||||
SetupNextExitFrameData(); // Setup data for next exit frame in chain.
|
||||
|
||||
@@ -112,7 +112,7 @@ class StackFrame : public ValueObject {
|
||||
virtual bool IsEntryFrame() const { return false; }
|
||||
virtual bool IsExitFrame() const { return false; }
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
bool is_interpreted() const { return is_interpreted_; }
|
||||
#else
|
||||
bool is_interpreted() const { return false; }
|
||||
@@ -182,7 +182,7 @@ class StackFrame : public ValueObject {
|
||||
uword pc_;
|
||||
Thread* thread_;
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
bool is_interpreted_ = false;
|
||||
#endif
|
||||
|
||||
@@ -308,7 +308,7 @@ class StackFrameIterator {
|
||||
explicit FrameSetIterator(Thread* thread)
|
||||
: fp_(0), sp_(0), pc_(0), stack_frame_(thread), thread_(thread) {}
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
bool is_interpreted() const { return is_interpreted_; }
|
||||
void CheckIfInterpreted(uword exit_marker);
|
||||
#else
|
||||
@@ -323,7 +323,7 @@ class StackFrameIterator {
|
||||
StackFrame stack_frame_; // Singleton frame returned by NextFrame().
|
||||
Thread* thread_;
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
bool is_interpreted_ = false;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -342,33 +342,33 @@ void AsyncAwareStackUnwinder::Unwind(
|
||||
code_ = SuspendState::Cast(awaiter_frame_.next).GetCodeObject();
|
||||
pc_offset = pc - code_.PayloadStart();
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
if (pc == StubCode::ResumeInterpreter().EntryPoint()) {
|
||||
bytecode_ = Interpreter::Current()->GetSuspendedLocation(
|
||||
SuspendState::Cast(awaiter_frame_.next), &pc_offset);
|
||||
ASSERT(!bytecode_.IsNull());
|
||||
code_ = Code::null();
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
} else {
|
||||
// This is an asynchronous continuation represented by a closure which
|
||||
// will handle successful completion. This function is not yet executing
|
||||
// so we have to use artificial marker offset (1).
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
if (function_.IsInterpreted()) {
|
||||
bytecode_ = function_.GetBytecode();
|
||||
code_ = Code::null();
|
||||
pc_offset = StackTraceUtils::kFutureListenerPcOffset;
|
||||
} else {
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
code_ = function_.EnsureHasCode();
|
||||
RELEASE_ASSERT(!code_.IsNull());
|
||||
pc_offset = (function_.entry_point() +
|
||||
StackTraceUtils::kFutureListenerPcOffset) -
|
||||
code_.PayloadStart();
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
}
|
||||
|
||||
handle_frame(gap_frame);
|
||||
|
||||
@@ -137,7 +137,7 @@ bool StubCode::InInvocationStub(Thread* T,
|
||||
Roots* roots = T->isolate_group()->roots();
|
||||
if (roots == nullptr) return false;
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
if (is_interpreted_frame) {
|
||||
// Recognize special marker set up by interpreter in entry frame.
|
||||
return Interpreter::IsEntryFrameMarker(
|
||||
@@ -151,7 +151,7 @@ bool StubCode::InInvocationStub(Thread* T,
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif // defined(DART_DYNAMIC_MODULES)
|
||||
#endif // defined(DART_BYTECODE_INTERPRETER)
|
||||
const Code& stub = roots->x_stub_handle(kInvokeDartCodeIndex);
|
||||
uword entry = Code::StubEntryPointOf(stub.ptr());
|
||||
uword size = Code::StubPayloadSizeOf(stub.ptr());
|
||||
|
||||
@@ -47,7 +47,7 @@ Thread::~Thread() {
|
||||
ASSERT(!ActiveMutatorStolenField::decode(safepoint_state_));
|
||||
ASSERT(deopt_context_ ==
|
||||
nullptr); // No deopt in progress when thread is deleted.
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
delete interpreter_;
|
||||
interpreter_ = nullptr;
|
||||
#endif
|
||||
@@ -1135,7 +1135,7 @@ void Thread::VisitObjectPointers(ObjectPointerVisitor* visitor,
|
||||
visitor->VisitPointer(reinterpret_cast<ObjectPtr*>(&active_stacktrace_));
|
||||
visitor->VisitPointer(reinterpret_cast<ObjectPtr*>(&sticky_error_));
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
if (interpreter() != nullptr) {
|
||||
interpreter()->VisitObjectPointers(visitor);
|
||||
}
|
||||
@@ -1409,7 +1409,7 @@ bool Thread::TopErrorHandlerIsSetJump() const {
|
||||
// False positives: simulator stack and native stack are unordered.
|
||||
return true;
|
||||
#else
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
// False positives: interpreter stack and native stack are unordered.
|
||||
if ((interpreter_ != nullptr) && interpreter_->HasFrame(top_exit_frame_info_))
|
||||
return true;
|
||||
@@ -1425,7 +1425,7 @@ bool Thread::TopErrorHandlerIsExitFrame() const {
|
||||
// False positives: simulator stack and native stack are unordered.
|
||||
return true;
|
||||
#else
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
// False positives: interpreter stack and native stack are unordered.
|
||||
if ((interpreter_ != nullptr) && interpreter_->HasFrame(top_exit_frame_info_))
|
||||
return true;
|
||||
|
||||
+2
-2
@@ -1325,7 +1325,7 @@ class Thread : public ThreadState, public IntrusiveDListEntry<Thread> {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
Interpreter* interpreter() const { return interpreter_; }
|
||||
void set_interpreter(Interpreter* value) { interpreter_ = value; }
|
||||
|
||||
@@ -1646,7 +1646,7 @@ class Thread : public ThreadState, public IntrusiveDListEntry<Thread> {
|
||||
HeapProfileSampler heap_sampler_;
|
||||
#endif
|
||||
|
||||
#if defined(DART_DYNAMIC_MODULES)
|
||||
#if defined(DART_BYTECODE_INTERPRETER)
|
||||
Interpreter* interpreter_ = nullptr;
|
||||
bytecode::BytecodeLoader* bytecode_loader_ = nullptr;
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user