Commit 782322fe authored by Tobias Tebbi's avatar Tobias Tebbi Committed by Commit Bot

[torque] allow untagged builtin parameters

For this, all Torque stub-linkage builtins use TFC instead of TFS,
with a custom descriptor added to interface-descriptors.h

To avoid having complex logic in the generated code, the new class
TorqueInterfaceDescriptor contains the logic to create a
CallInterfaceDescriptor from a signature consisting of TNode types.

As an example and test, this CL ports StringCharAt to Torque.

Bug: v8:7793
Change-Id: I8339d2ad6e4f908ebdc3b8d30244e4bcbd974f21
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1798427Reviewed-by: 's avatarHannes Payer <hpayer@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#64148}
parent d22b954c
...@@ -1092,6 +1092,7 @@ action("run_torque") { ...@@ -1092,6 +1092,7 @@ action("run_torque") {
outputs = [ outputs = [
"$target_gen_dir/torque-generated/builtin-definitions-tq.h", "$target_gen_dir/torque-generated/builtin-definitions-tq.h",
"$target_gen_dir/torque-generated/interface-descriptors-tq.inc",
"$target_gen_dir/torque-generated/field-offsets-tq.h", "$target_gen_dir/torque-generated/field-offsets-tq.h",
"$target_gen_dir/torque-generated/class-verifiers-tq.cc", "$target_gen_dir/torque-generated/class-verifiers-tq.cc",
"$target_gen_dir/torque-generated/class-verifiers-tq.h", "$target_gen_dir/torque-generated/class-verifiers-tq.h",
......
...@@ -102,7 +102,6 @@ namespace internal { ...@@ -102,7 +102,6 @@ namespace internal {
ASM(ResumeGeneratorTrampoline, ResumeGenerator) \ ASM(ResumeGeneratorTrampoline, ResumeGenerator) \
\ \
/* String helpers */ \ /* String helpers */ \
TFC(StringCharAt, StringAt) \
TFC(StringCodePointAt, StringAt) \ TFC(StringCodePointAt, StringAt) \
TFC(StringFromCodePointAt, StringAtAsString) \ TFC(StringFromCodePointAt, StringAtAsString) \
TFC(StringEqual, Compare) \ TFC(StringEqual, Compare) \
......
...@@ -760,19 +760,6 @@ TF_BUILTIN(StringGreaterThanOrEqual, StringBuiltinsAssembler) { ...@@ -760,19 +760,6 @@ TF_BUILTIN(StringGreaterThanOrEqual, StringBuiltinsAssembler) {
Operation::kGreaterThanOrEqual); Operation::kGreaterThanOrEqual);
} }
TF_BUILTIN(StringCharAt, StringBuiltinsAssembler) {
TNode<String> receiver = CAST(Parameter(Descriptor::kReceiver));
TNode<IntPtrT> position =
UncheckedCast<IntPtrT>(Parameter(Descriptor::kPosition));
// Load the character code at the {position} from the {receiver}.
TNode<Int32T> code = StringCharCodeAt(receiver, position);
// And return the single character string with only that {code}
TNode<String> result = StringFromSingleCharCode(code);
Return(result);
}
TF_BUILTIN(StringCodePointAt, StringBuiltinsAssembler) { TF_BUILTIN(StringCodePointAt, StringBuiltinsAssembler) {
Node* receiver = Parameter(Descriptor::kReceiver); Node* receiver = Parameter(Descriptor::kReceiver);
Node* position = Parameter(Descriptor::kPosition); Node* position = Parameter(Descriptor::kPosition);
......
...@@ -188,4 +188,12 @@ namespace string { ...@@ -188,4 +188,12 @@ namespace string {
left: String, right: JSAny): String { left: String, right: JSAny): String {
return left + ToStringImpl(context, ToPrimitiveDefault(right)); return left + ToStringImpl(context, ToPrimitiveDefault(right));
} }
builtin StringCharAt(implicit context: Context)(
receiver: String, position: intptr): String {
// Load the character code at the {position} from the {receiver}.
const code: int32 = StringCharCodeAt(receiver, position);
// And return the single character string with only that {code}
return StringFromSingleCharCode(code);
}
} }
...@@ -9,12 +9,17 @@ ...@@ -9,12 +9,17 @@
#include "src/codegen/machine-type.h" #include "src/codegen/machine-type.h"
#include "src/codegen/register-arch.h" #include "src/codegen/register-arch.h"
#include "src/codegen/tnode.h"
#include "src/common/globals.h" #include "src/common/globals.h"
#include "src/execution/isolate.h" #include "src/execution/isolate.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
#define TORQUE_BUILTIN_LIST_TFC(V) \
BUILTIN_LIST_FROM_TORQUE(IGNORE_BUILTIN, IGNORE_BUILTIN, V, IGNORE_BUILTIN, \
IGNORE_BUILTIN, IGNORE_BUILTIN)
#define INTERFACE_DESCRIPTOR_LIST(V) \ #define INTERFACE_DESCRIPTOR_LIST(V) \
V(Abort) \ V(Abort) \
V(Allocate) \ V(Allocate) \
...@@ -90,7 +95,8 @@ namespace internal { ...@@ -90,7 +95,8 @@ namespace internal {
V(WasmTableGet) \ V(WasmTableGet) \
V(WasmTableSet) \ V(WasmTableSet) \
V(WasmThrow) \ V(WasmThrow) \
BUILTIN_LIST_TFS(V) BUILTIN_LIST_TFS(V) \
TORQUE_BUILTIN_LIST_TFC(V)
class V8_EXPORT_PRIVATE CallInterfaceDescriptorData { class V8_EXPORT_PRIVATE CallInterfaceDescriptorData {
public: public:
...@@ -487,6 +493,46 @@ class V8_EXPORT_PRIVATE VoidDescriptor : public CallInterfaceDescriptor { ...@@ -487,6 +493,46 @@ class V8_EXPORT_PRIVATE VoidDescriptor : public CallInterfaceDescriptor {
DECLARE_DESCRIPTOR(VoidDescriptor, CallInterfaceDescriptor) DECLARE_DESCRIPTOR(VoidDescriptor, CallInterfaceDescriptor)
}; };
// This class is subclassed by Torque-generated call interface descriptors.
template <int parameter_count>
class TorqueInterfaceDescriptor : public CallInterfaceDescriptor {
public:
static constexpr int kDescriptorFlags = CallInterfaceDescriptorData::kNoFlags;
static constexpr int kParameterCount = parameter_count;
enum ParameterIndices { kContext = kParameterCount };
template <int i>
static ParameterIndices ParameterIndex() {
STATIC_ASSERT(0 <= i && i < kParameterCount);
return static_cast<ParameterIndices>(i);
}
static constexpr int kReturnCount = 1;
using CallInterfaceDescriptor::CallInterfaceDescriptor;
protected:
static const int kRegisterParams =
kParameterCount > kMaxTFSBuiltinRegisterParams
? kMaxTFSBuiltinRegisterParams
: kParameterCount;
static const int kStackParams = kParameterCount - kRegisterParams;
virtual MachineType ReturnType() = 0;
virtual std::array<MachineType, kParameterCount> ParameterTypes() = 0;
void InitializePlatformSpecific(CallInterfaceDescriptorData* data) override {
DefaultInitializePlatformSpecific(data, kRegisterParams);
}
void InitializePlatformIndependent(
CallInterfaceDescriptorData* data) override {
std::vector<MachineType> machine_types = {ReturnType()};
auto parameter_types = ParameterTypes();
machine_types.insert(machine_types.end(), parameter_types.begin(),
parameter_types.end());
DCHECK_EQ(kReturnCount + kParameterCount, machine_types.size());
data->InitializePlatformIndependent(Flags(kDescriptorFlags), kReturnCount,
kParameterCount, machine_types.data(),
static_cast<int>(machine_types.size()));
}
};
// Dummy descriptor used to mark builtins that don't yet have their proper // Dummy descriptor used to mark builtins that don't yet have their proper
// descriptor associated. // descriptor associated.
using DummyDescriptor = VoidDescriptor; using DummyDescriptor = VoidDescriptor;
...@@ -1309,6 +1355,11 @@ class CloneObjectWithVectorDescriptor final : public CallInterfaceDescriptor { ...@@ -1309,6 +1355,11 @@ class CloneObjectWithVectorDescriptor final : public CallInterfaceDescriptor {
BUILTIN_LIST_TFS(DEFINE_TFS_BUILTIN_DESCRIPTOR) BUILTIN_LIST_TFS(DEFINE_TFS_BUILTIN_DESCRIPTOR)
#undef DEFINE_TFS_BUILTIN_DESCRIPTOR #undef DEFINE_TFS_BUILTIN_DESCRIPTOR
// This file contains interface descriptor class definitions for builtins
// defined in Torque. It is included here because the class definitions need to
// precede the definition of name##Descriptor::key() below.
#include "torque-generated/interface-descriptors-tq.inc"
#undef DECLARE_DEFAULT_DESCRIPTOR #undef DECLARE_DEFAULT_DESCRIPTOR
#undef DECLARE_DESCRIPTOR_WITH_BASE #undef DECLARE_DESCRIPTOR_WITH_BASE
#undef DECLARE_DESCRIPTOR #undef DECLARE_DESCRIPTOR
......
...@@ -1007,6 +1007,13 @@ class MachineRepresentationChecker { ...@@ -1007,6 +1007,13 @@ class MachineRepresentationChecker {
return IsAnyCompressed(actual); return IsAnyCompressed(actual);
case MachineRepresentation::kTaggedSigned: case MachineRepresentation::kTaggedSigned:
case MachineRepresentation::kTaggedPointer: case MachineRepresentation::kTaggedPointer:
// TODO(tebbi): At the moment, the machine graph doesn't contain
// reliable information if a node is kTaggedSigned, kTaggedPointer or
// kTagged, and often this is context-dependent. We should at least
// check for obvious violations: kTaggedSigned where we expect
// kTaggedPointer and the other way around, but at the moment, this
// happens in dead code.
return IsAnyTagged(actual);
case MachineRepresentation::kCompressedSigned: case MachineRepresentation::kCompressedSigned:
case MachineRepresentation::kCompressedPointer: case MachineRepresentation::kCompressedPointer:
case MachineRepresentation::kFloat32: case MachineRepresentation::kFloat32:
......
...@@ -93,20 +93,6 @@ Builtin* DeclarationVisitor::CreateBuiltin(BuiltinDeclaration* decl, ...@@ -93,20 +93,6 @@ Builtin* DeclarationVisitor::CreateBuiltin(BuiltinDeclaration* decl,
} }
} }
if (TorqueBuiltinDeclaration::DynamicCast(decl)) {
for (size_t i = 0; i < signature.types().size(); ++i) {
const Type* type = signature.types()[i];
if (!type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
const Identifier* id = signature.parameter_names.size() > i
? signature.parameter_names[i]
: nullptr;
Error("Untagged argument ", id ? (id->value + " ") : "", "at position ",
i, " to builtin ", decl->name, " is not supported.")
.Position(id ? id->pos : decl->pos);
}
}
}
if (const StructType* struct_type = if (const StructType* struct_type =
StructType::DynamicCast(signature.return_type)) { StructType::DynamicCast(signature.return_type)) {
Error("Builtins ", decl->name, " cannot return structs ", Error("Builtins ", decl->name, " cannot return structs ",
......
...@@ -526,7 +526,6 @@ void ImplementationVisitor::Visit(Builtin* builtin) { ...@@ -526,7 +526,6 @@ void ImplementationVisitor::Visit(Builtin* builtin) {
source_out() << " USE(" << parameter0 << ");\n"; source_out() << " USE(" << parameter0 << ");\n";
for (size_t i = 1; i < signature.parameter_names.size(); ++i) { for (size_t i = 1; i < signature.parameter_names.size(); ++i) {
const std::string& parameter_name = signature.parameter_names[i]->value;
const Type* type = signature.types()[i]; const Type* type = signature.types()[i];
const bool mark_as_used = signature.implicit_count > i; const bool mark_as_used = signature.implicit_count > i;
std::string var = AddParameter(i, builtin, &parameters, &parameter_types, std::string var = AddParameter(i, builtin, &parameters, &parameter_types,
...@@ -534,8 +533,8 @@ void ImplementationVisitor::Visit(Builtin* builtin) { ...@@ -534,8 +533,8 @@ void ImplementationVisitor::Visit(Builtin* builtin) {
source_out() << " " << type->GetGeneratedTypeName() << " " << var source_out() << " " << type->GetGeneratedTypeName() << " " << var
<< " = " << " = "
<< "UncheckedCast<" << type->GetGeneratedTNodeTypeName() << "UncheckedCast<" << type->GetGeneratedTNodeTypeName()
<< ">(Parameter(Descriptor::k" << ">(Parameter(Descriptor::ParameterIndex<" << (i - 1)
<< CamelifyString(parameter_name) << "));\n"; << ">()));\n";
source_out() << " USE(" << var << ");\n"; source_out() << " USE(" << var << ");\n";
} }
} }
...@@ -2670,13 +2669,34 @@ void ImplementationVisitor::Visit(Declarable* declarable) { ...@@ -2670,13 +2669,34 @@ void ImplementationVisitor::Visit(Declarable* declarable) {
} }
} }
void ImplementationVisitor::GenerateBuiltinDefinitions( std::string MachineTypeString(const Type* type) {
if (type->IsSubtypeOf(TypeOracle::GetSmiType())) {
return "MachineType::TaggedSigned()";
}
if (type->IsSubtypeOf(TypeOracle::GetHeapObjectType())) {
return "MachineType::TaggedPointer()";
}
if (type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
return "MachineType::AnyTagged()";
}
return "MachineTypeOf<" + type->GetGeneratedTNodeTypeName() + ">::value";
}
void ImplementationVisitor::GenerateBuiltinDefinitionsAndInterfaceDescriptors(
const std::string& output_directory) { const std::string& output_directory) {
std::stringstream new_contents_stream; std::stringstream builtin_definitions;
std::string file_name = "builtin-definitions-tq.h"; std::string builtin_definitions_file_name = "builtin-definitions-tq.h";
// This file contains plain interface descriptor definitions and has to be
// included in the middle of interface-descriptors.h. Thus it is not a normal
// header file and uses the .inc suffix instead of the .h suffix.
std::stringstream interface_descriptors;
std::string interface_descriptors_file_name = "interface-descriptors-tq.inc";
{ {
IncludeGuardScope include_guard(new_contents_stream, file_name); IncludeGuardScope builtin_definitions_include_guard(
new_contents_stream builtin_definitions, builtin_definitions_file_name);
builtin_definitions
<< "\n" << "\n"
"#define BUILTIN_LIST_FROM_TORQUE(CPP, TFJ, TFC, TFS, TFH, " "#define BUILTIN_LIST_FROM_TORQUE(CPP, TFJ, TFC, TFS, TFH, "
"ASM) " "ASM) "
...@@ -2684,40 +2704,67 @@ void ImplementationVisitor::GenerateBuiltinDefinitions( ...@@ -2684,40 +2704,67 @@ void ImplementationVisitor::GenerateBuiltinDefinitions(
for (auto& declarable : GlobalContext::AllDeclarables()) { for (auto& declarable : GlobalContext::AllDeclarables()) {
Builtin* builtin = Builtin::DynamicCast(declarable.get()); Builtin* builtin = Builtin::DynamicCast(declarable.get());
if (!builtin || builtin->IsExternal()) continue; if (!builtin || builtin->IsExternal()) continue;
size_t firstParameterIndex = 1;
bool declareParameters = true;
if (builtin->IsStub()) { if (builtin->IsStub()) {
new_contents_stream << "TFS(" << builtin->ExternalName(); builtin_definitions << "TFC(" << builtin->ExternalName() << ", "
<< builtin->ExternalName();
std::string descriptor_name = builtin->ExternalName() + "Descriptor";
constexpr size_t kFirstNonContextParameter = 1;
size_t parameter_count =
builtin->parameter_names().size() - kFirstNonContextParameter;
interface_descriptors << "class " << descriptor_name
<< " : public TorqueInterfaceDescriptor<"
<< parameter_count << "> {\n";
interface_descriptors << " DECLARE_DESCRIPTOR_WITH_BASE("
<< descriptor_name
<< ", TorqueInterfaceDescriptor)\n";
interface_descriptors << " MachineType ReturnType() override {\n";
interface_descriptors
<< " return "
<< MachineTypeString(builtin->signature().return_type) << ";\n";
interface_descriptors << " }\n";
interface_descriptors << " std::array<MachineType, " << parameter_count
<< "> ParameterTypes() override {\n";
interface_descriptors << " return {";
for (size_t i = kFirstNonContextParameter;
i < builtin->parameter_names().size(); ++i) {
bool last = i + 1 == builtin->parameter_names().size();
const Type* type = builtin->signature().parameter_types.types[i];
interface_descriptors << MachineTypeString(type)
<< (last ? "" : ", ");
}
interface_descriptors << "};\n";
interface_descriptors << " }\n";
interface_descriptors << "};\n\n";
} else { } else {
new_contents_stream << "TFJ(" << builtin->ExternalName(); builtin_definitions << "TFJ(" << builtin->ExternalName();
if (builtin->IsVarArgsJavaScript()) { if (builtin->IsVarArgsJavaScript()) {
new_contents_stream builtin_definitions
<< ", SharedFunctionInfo::kDontAdaptArgumentsSentinel"; << ", SharedFunctionInfo::kDontAdaptArgumentsSentinel";
declareParameters = false;
} else { } else {
DCHECK(builtin->IsFixedArgsJavaScript()); DCHECK(builtin->IsFixedArgsJavaScript());
// FixedArg javascript builtins need to offer the parameter // FixedArg javascript builtins need to offer the parameter
// count. // count.
int parameter_count = int parameter_count =
static_cast<int>(builtin->signature().ExplicitCount()); static_cast<int>(builtin->signature().ExplicitCount());
new_contents_stream << ", " << parameter_count; builtin_definitions << ", " << parameter_count;
// And the receiver is explicitly declared. // And the receiver is explicitly declared.
new_contents_stream << ", kReceiver"; builtin_definitions << ", kReceiver";
firstParameterIndex = builtin->signature().implicit_count; for (size_t i = builtin->signature().implicit_count;
} i < builtin->parameter_names().size(); ++i) {
} Identifier* parameter = builtin->parameter_names()[i];
if (declareParameters) { builtin_definitions << ", k" << CamelifyString(parameter->value);
for (size_t i = firstParameterIndex; }
i < builtin->parameter_names().size(); ++i) {
Identifier* parameter = builtin->parameter_names()[i];
new_contents_stream << ", k" << CamelifyString(parameter->value);
} }
} }
new_contents_stream << ") \\\n"; builtin_definitions << ") \\\n";
} }
new_contents_stream << "\n"; builtin_definitions << "\n";
new_contents_stream builtin_definitions
<< "#define TORQUE_FUNCTION_POINTER_TYPE_TO_BUILTIN_MAP(V) \\\n"; << "#define TORQUE_FUNCTION_POINTER_TYPE_TO_BUILTIN_MAP(V) \\\n";
for (const BuiltinPointerType* type : for (const BuiltinPointerType* type :
TypeOracle::AllBuiltinPointerTypes()) { TypeOracle::AllBuiltinPointerTypes()) {
...@@ -2728,13 +2775,15 @@ void ImplementationVisitor::GenerateBuiltinDefinitions( ...@@ -2728,13 +2775,15 @@ void ImplementationVisitor::GenerateBuiltinDefinitions(
SourcePosition{CurrentSourceFile::Get(), {-1, -1}, {-1, -1}}); SourcePosition{CurrentSourceFile::Get(), {-1, -1}, {-1, -1}});
ReportError("unable to find any builtin with type \"", *type, "\""); ReportError("unable to find any builtin with type \"", *type, "\"");
} }
new_contents_stream << " V(" << type->function_pointer_type_id() << "," builtin_definitions << " V(" << type->function_pointer_type_id() << ","
<< example_builtin->ExternalName() << ")\\\n"; << example_builtin->ExternalName() << ")\\\n";
} }
new_contents_stream << "\n"; builtin_definitions << "\n";
} }
std::string new_contents(new_contents_stream.str()); WriteFile(output_directory + "/" + builtin_definitions_file_name,
WriteFile(output_directory + "/" + file_name, new_contents); builtin_definitions.str());
WriteFile(output_directory + "/" + interface_descriptors_file_name,
interface_descriptors.str());
} }
namespace { namespace {
......
...@@ -343,7 +343,8 @@ bool IsCompatibleSignature(const Signature& sig, const TypeVector& types, ...@@ -343,7 +343,8 @@ bool IsCompatibleSignature(const Signature& sig, const TypeVector& types,
class ImplementationVisitor { class ImplementationVisitor {
public: public:
void GenerateBuiltinDefinitions(const std::string& output_directory); void GenerateBuiltinDefinitionsAndInterfaceDescriptors(
const std::string& output_directory);
void GenerateClassFieldOffsets(const std::string& output_directory); void GenerateClassFieldOffsets(const std::string& output_directory);
void GeneratePrintDefinitions(const std::string& output_directory); void GeneratePrintDefinitions(const std::string& output_directory);
void GenerateClassDefinitions(const std::string& output_directory); void GenerateClassDefinitions(const std::string& output_directory);
......
...@@ -79,7 +79,8 @@ void CompileCurrentAst(TorqueCompilerOptions options) { ...@@ -79,7 +79,8 @@ void CompileCurrentAst(TorqueCompilerOptions options) {
ReportAllUnusedMacros(); ReportAllUnusedMacros();
implementation_visitor.GenerateBuiltinDefinitions(output_directory); implementation_visitor.GenerateBuiltinDefinitionsAndInterfaceDescriptors(
output_directory);
implementation_visitor.GenerateClassFieldOffsets(output_directory); implementation_visitor.GenerateClassFieldOffsets(output_directory);
implementation_visitor.GeneratePrintDefinitions(output_directory); implementation_visitor.GeneratePrintDefinitions(output_directory);
implementation_visitor.GenerateClassDefinitions(output_directory); implementation_visitor.GenerateClassDefinitions(output_directory);
......
...@@ -102,6 +102,7 @@ class HeapTester { ...@@ -102,6 +102,7 @@ class HeapTester {
// test-heap.cc // test-heap.cc
static AllocationResult AllocateByteArrayForTest(Heap* heap, int length, static AllocationResult AllocateByteArrayForTest(Heap* heap, int length,
AllocationType allocation); AllocationType allocation);
static bool CodeEnsureLinearAllocationArea(Heap* heap, int size_in_bytes);
// test-mark-compact.cc // test-mark-compact.cc
static AllocationResult AllocateMapForTest(v8::internal::Isolate* isolate); static AllocationResult AllocateMapForTest(v8::internal::Isolate* isolate);
......
...@@ -5337,6 +5337,11 @@ AllocationResult HeapTester::AllocateByteArrayForTest( ...@@ -5337,6 +5337,11 @@ AllocationResult HeapTester::AllocateByteArrayForTest(
return result; return result;
} }
bool HeapTester::CodeEnsureLinearAllocationArea(Heap* heap, int size_in_bytes) {
return heap->code_space()->EnsureLinearAllocationArea(
size_in_bytes, AllocationOrigin::kRuntime);
}
HEAP_TEST(Regress587004) { HEAP_TEST(Regress587004) {
ManualGCScope manual_gc_scope; ManualGCScope manual_gc_scope;
#ifdef VERIFY_HEAP #ifdef VERIFY_HEAP
...@@ -6788,11 +6793,13 @@ TEST(CodeObjectRegistry) { ...@@ -6788,11 +6793,13 @@ TEST(CodeObjectRegistry) {
HandleScope outer_scope(heap->isolate()); HandleScope outer_scope(heap->isolate());
Address code2_address; Address code2_address;
{ {
// Ensure that both code objects end up on the same page.
CHECK(HeapTester::CodeEnsureLinearAllocationArea(
heap, kMaxRegularHeapObjectSize));
code1 = DummyOptimizedCode(isolate); code1 = DummyOptimizedCode(isolate);
Handle<Code> code2 = DummyOptimizedCode(isolate); Handle<Code> code2 = DummyOptimizedCode(isolate);
code2_address = code2->address(); code2_address = code2->address();
// If this check breaks, change the allocation to ensure that both code
// objects are on the same page.
CHECK_EQ(MemoryChunk::FromHeapObject(*code1), CHECK_EQ(MemoryChunk::FromHeapObject(*code1),
MemoryChunk::FromHeapObject(*code2)); MemoryChunk::FromHeapObject(*code2));
CHECK(MemoryChunk::FromHeapObject(*code1)->Contains(code1->address())); CHECK(MemoryChunk::FromHeapObject(*code1)->Contains(code1->address()));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment