Skip to content

Commit

Permalink
[jdwp] fix types
Browse files Browse the repository at this point in the history
This commit separates types representing ids of internal vm objects from opaque
types that map to types that are provided by the language or the debugger runtime.

While doing so I noticed that command sets cannot be imported due to runtime errors.
I would have expected pyre would have caught those errors, but apparently not. While
there I fixed issues and added a test case preventing this from happening again.
  • Loading branch information
michalgr committed Nov 22, 2023
1 parent 16396ad commit a74c2d5
Show file tree
Hide file tree
Showing 11 changed files with 146 additions and 110 deletions.
26 changes: 8 additions & 18 deletions projects/jdwp/codegen/new_type_generator.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,16 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.

from projects.jdwp.defs.schema import PrimitiveType
import typing
from projects.jdwp.defs.schema import IdType
from projects.jdwp.codegen.types import python_type_for


def get_python_type(jdwp_type: PrimitiveType) -> str:
"""Map JDWP type to Python type."""
mapping = {
PrimitiveType.STRING: "str",
PrimitiveType.BOOLEAN: "bool",
}
return mapping.get(jdwp_type, "int")


def get_type_alias_definition(jdwp_type: PrimitiveType) -> str:
"""Return the type alias definition for a given JDWP type."""
python_type = get_python_type(jdwp_type)
new_type_name = f"{jdwp_type.name.capitalize()}Type"
return f"{new_type_name} = typing.NewType('{new_type_name}', {python_type})"
def get_type_alias_definition(jdwp_type: IdType) -> str:
"""Return the type alias definition for a given IdType."""
python_type = python_type_for(jdwp_type)
return f"{python_type} = typing.NewType('{python_type}', int)"


def generate_new_types():
for jdwp_type in PrimitiveType:
type_alias_definition = get_type_alias_definition(jdwp_type)
for id_type in IdType:
type_alias_definition = get_type_alias_definition(id_type)
print(type_alias_definition)
23 changes: 23 additions & 0 deletions projects/jdwp/codegen/types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.

from projects.jdwp.defs.schema import OpaqueType, IdType, IntegralType, Type
import typing


__OPAQUE_TYPE_MAPPING = {
OpaqueType.BOOLEAN: "bool",
OpaqueType.LOCATION: "typing.Any",
OpaqueType.STRING: "str",
}


def python_type_for(jdwp_type: Type) -> str:
match jdwp_type:
case OpaqueType():
return __OPAQUE_TYPE_MAPPING[jdwp_type]
case IdType():
return jdwp_type.value[0].upper() + jdwp_type.value[1:] + "Type"
case IntegralType():
return "int"
case _:
raise Exception("not implemented")
29 changes: 16 additions & 13 deletions projects/jdwp/defs/command_sets/event_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
Array,
TaggedUnion,
UnionTag,
Type,
IdType,
OpaqueType,
)
from projects.jdwp.defs.constants import ErrorType, ModifierKind

Expand All @@ -21,53 +22,55 @@

ConditionalModifier = Struct([Field("exprID", IntegralType.INT, "For the future")])

ThreadOnlyModifier = Struct([Field("thread", Type.THREAD_ID, "Required thread")])
ThreadOnlyModifier = Struct([Field("thread", IdType.THREAD_ID, "Required thread")])

ClassOnlyModifier = Struct([Field("clazz", Type.REFERENCE_TYPE_ID, "Required class")])
ClassOnlyModifier = Struct([Field("clazz", IdType.REFERENCE_TYPE_ID, "Required class")])

ClassMatchModifier = Struct(
[Field("classPattern", Type.STRING, "Restricted class pattern")]
[Field("classPattern", OpaqueType.STRING, "Restricted class pattern")]
)

StepModifier = Struct(
[
Field("thread", Type.THREAD_ID, "Required thread"),
Field("thread", IdType.THREAD_ID, "Required thread"),
Field("size", IntegralType.INT, "Size of each step"),
Field("depth", IntegralType.INT, "Relative call stack limit"),
]
)

ClassExcludeModifier = Struct(
[Field("classPattern", Type.STRING, "Disallowed class pattern")]
[Field("classPattern", OpaqueType.STRING, "Disallowed class pattern")]
)

LocationOnlyModifier = Struct([Field("loc", Type.LOCATION, "Required location")])
LocationOnlyModifier = Struct([Field("loc", OpaqueType.LOCATION, "Required location")])

ExceptionOnlyModifier = Struct(
[
Field(
"exceptionOrNull",
Type.REFERENCE_TYPE_ID,
IdType.REFERENCE_TYPE_ID,
"Exception to report. Null (0) means report exceptions of all types.",
),
Field("caught", Type.BOOLEAN, "True if exception was caught"),
Field("uncaught", Type.BOOLEAN, "True if exception was uncaught"),
Field("caught", OpaqueType.BOOLEAN, "True if exception was caught"),
Field("uncaught", OpaqueType.BOOLEAN, "True if exception was uncaught"),
]
)

FieldOnlyModifier = Struct(
[
Field("declaring", Type.REFERENCE_TYPE_ID, "Type in which field is declared."),
Field(
"declaring", IdType.REFERENCE_TYPE_ID, "Type in which field is declared."
),
Field("fieldID", IntegralType.INT, "Required field"),
]
)

InstanceOnlyModifier = Struct(
[Field("instance", Type.OBJECT_ID, "Required 'this' object")]
[Field("instance", IdType.OBJECT_ID, "Required 'this' object")]
)

SourceNameMatchModifier = Struct(
[Field("sourceNamePattern", Type.STRING, " Required source name pattern")]
[Field("sourceNamePattern", OpaqueType.STRING, "Required source name pattern")]
)

__SetCommand_out_modKind = Field(
Expand Down
15 changes: 12 additions & 3 deletions projects/jdwp/defs/command_sets/reference_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@
"""Command Set: ReferenceType."""


from projects.jdwp.defs.schema import Command, Field, Struct, CommandSet, Type
from projects.jdwp.defs.schema import (
Command,
Field,
Struct,
CommandSet,
IdType,
OpaqueType,
)
from projects.jdwp.defs.constants import ErrorType


Expand All @@ -12,13 +19,15 @@
id=1,
out=Struct(
[
Field("refType", Type.REFERENCE_TYPE_ID, "The Reference type ID."),
Field("refType", IdType.REFERENCE_TYPE_ID, "The Reference type ID."),
]
),
reply=Struct(
[
Field(
"signature", Type.STRING, "The JNI signature for the reference type."
"signature",
OpaqueType.STRING,
"The JNI signature for the reference type.",
),
]
),
Expand Down
25 changes: 16 additions & 9 deletions projects/jdwp/defs/command_sets/virtual_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
Command,
Field,
Struct,
Type,
IdType,
OpaqueType,
Array,
CommandSet,
ArrayLength,
Expand All @@ -25,9 +26,11 @@
__AllClasses_reply_classesArray_element = Struct(
[
Field("refTypeTag", IntegralType.BYTE, "Kind of following reference type"),
Field("typeID", Type.REFERENCE_TYPE_ID, "Loaded reference type"),
Field("typeID", IdType.REFERENCE_TYPE_ID, "Loaded reference type"),
Field(
"signature", Type.STRING, "The JNI signature of the loaded reference type"
"signature",
OpaqueType.STRING,
"The JNI signature of the loaded reference type",
),
Field("status", IntegralType.INT, "The current class status"),
]
Expand Down Expand Up @@ -56,15 +59,19 @@

__Version_reply = Struct(
[
Field("description", Type.STRING, "Text information on the VM version"),
Field("description", OpaqueType.STRING, "Text information on the VM version"),
Field("jdwpMajor", IntegralType.INT, "JDWP major version number"),
Field("jdwpMinor", IntegralType.INT, "JDWP minor version number"),
Field(
"vmVersion",
Type.STRING,
OpaqueType.STRING,
"Target VM JRE version, as in the java.version property",
),
Field("vmName", Type.STRING, "Target VM name, as in the java.vm.name property"),
Field(
"vmName",
OpaqueType.STRING,
"Target VM name, as in the java.vm.name property",
),
]
)

Expand Down Expand Up @@ -110,7 +117,7 @@

__ClassPaths_replyArray_element = Struct(
[
Field("classpaths", Type.STRING, "List of classpath entries"),
Field("classpaths", OpaqueType.STRING, "List of classpath entries"),
]
)

Expand All @@ -122,15 +129,15 @@

__BootClassPaths_replyArray_element = Struct(
[
Field("bootclasspaths", Type.STRING, "List of bootclasspath entries"),
Field("bootclasspaths", OpaqueType.STRING, "List of bootclasspath entries"),
]
)

__ClassPaths_reply = Struct(
[
Field(
"baseDir",
Type.STRING,
OpaqueType.STRING,
"Base directory used to resolve relative paths in either of the following lists.",
),
__ClassPaths_reply_ClassPaths,
Expand Down
51 changes: 32 additions & 19 deletions projects/jdwp/defs/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,41 +12,54 @@


Type = Union[
"PrimitiveType",
"Array",
"TaggedUnion",
"IntegralType",
"ArrayLength",
"IdType",
"IntegralType",
"OpaqueType",
"Struct",
"TaggedUnion",
"UnionTag",
]


class PrimitiveType(Enum):
"""Primitive type class."""
class OpaqueType(Enum):
"""Opaque types whose implementation is provided by debugger runtime library or language."""

STRING = "string"
BOOLEAN = "boolean"
DICT = "dict"
REFERENCE_TYPE_ID = "referenceTypeID"
CLASS_LOADER = "classLoader"
FIELD_ID = "fieldID"
METHOD_ID = "methodID"
VALUE = "value"
INTERFACE_ID = "interfaceID"
CLASS_OBJECT_ID = "classObjectID"
TAGGED_OBJECT_ID = "taggedObjectID"
# TAGGED_OBJECT_ID = "tagged-objectID"
LOCATION = "location"
STRING = "string"
# VALUE = "value"
# UNTAGGED_VALUE = "untagged-value"
# ARRAY_REGION = "arrayregion"


class IdType(Enum):
"""Types representing numeric IDs of internal VM objects."""

OBJECT_ID = "objectID"
THREAD_ID = "threadID"
THREAD_GROUP_ID = "threadGroupID"
OBJECT_ID = "objectID"
LOCATION = "location"
STRING_ID = "stringId"
CLASS_LOADER_ID = "classLoaderID"
CLASS_OBJECT_ID = "classObjectID"
ARRAY_ID = "arrayID"
REFERENCE_TYPE_ID = "referenceTypeID"
CLASS_ID = "classID"
INTERFACE_ID = "interfaceID"
ARRAY_TYPE_ID = "arrayTypeID"
METHOD_ID = "methodID"
FIELD_ID = "fieldID"
FRAME_ID = "frameID"


class IntegralType(Enum):
"""Integral type class."""
"""Integer types of different precision."""

INT = "int"
BYTE = "byte"
INT = "int"
LONG = "long"


@dataclass(frozen=True)
Expand Down
9 changes: 8 additions & 1 deletion projects/jdwp/tests/defs/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,11 @@

class SchemaTests(unittest.TestCase):
def test_schema_can_be_imported(self):
from projects.jdwp.defs.schema import PrimitiveType
from projects.jdwp.defs.schema import OpaqueType

def test_command_sets_can_be_imported(self):
from projects.jdwp.defs.command_sets import (
event_request,
reference_type,
virtual_machine,
)
16 changes: 16 additions & 0 deletions projects/jdwp/tests/test_new_type_generator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.

import unittest
from projects.jdwp.defs.schema import IdType
from projects.jdwp.codegen.new_type_generator import get_type_alias_definition


class TestTypeAliasDefinition(unittest.TestCase):
def test_specific_type_alias_definitions(self):
expected_object_id_type_definition = (
"ObjectIDType = typing.NewType('ObjectIDType', int)"
)
self.assertEqual(
get_type_alias_definition(IdType.OBJECT_ID),
expected_object_id_type_definition,
)
19 changes: 0 additions & 19 deletions projects/jdwp/tests/test_primitve_type.py

This file was deleted.

28 changes: 0 additions & 28 deletions projects/jdwp/tests/test_type_alias_definition.py

This file was deleted.

Loading

0 comments on commit a74c2d5

Please sign in to comment.