Commit 32a92cf5 authored by Daniel Clifford's avatar Daniel Clifford Committed by Commit Bot

[torque] Correctly support JSObject allocation with 'new'

This requires honoring the instance size of the object stored in the
map for JSObject. To do this, allocation is now split into two
instrinsics, one that calculates the base size of the allocated object
(%GetAllocationBaseSize) and one that actually allocates (%Allocate).

In the process, remove objects.tq, which only existed to contain a
macro to fetch the default JSObject map, which is functionality that
is now in the JSObject class constructor.

Bug: v8:7793
Change-Id: I426a7943aac67eacad46d4ff39f5c821489a04bc
Reviewed-on: https://chromium-review.googlesource.com/c/1426959
Commit-Queue: Daniel Clifford <danno@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59052}
parent f4978ed3
...@@ -873,7 +873,6 @@ torque_files = [ ...@@ -873,7 +873,6 @@ torque_files = [
"src/builtins/collections.tq", "src/builtins/collections.tq",
"src/builtins/data-view.tq", "src/builtins/data-view.tq",
"src/builtins/extras-utils.tq", "src/builtins/extras-utils.tq",
"src/builtins/object.tq",
"src/builtins/object-fromentries.tq", "src/builtins/object-fromentries.tq",
"src/builtins/iterator.tq", "src/builtins/iterator.tq",
"src/builtins/typed-array.tq", "src/builtins/typed-array.tq",
......
...@@ -52,6 +52,8 @@ type Number = Smi | HeapNumber; ...@@ -52,6 +52,8 @@ type Number = Smi | HeapNumber;
type BigInt extends HeapObject generates 'TNode<BigInt>'; type BigInt extends HeapObject generates 'TNode<BigInt>';
type Numeric = Number | BigInt; type Numeric = Number | BigInt;
type RootIndex generates 'TNode<Int32T>' constexpr 'RootIndex';
type Map extends HeapObject generates 'TNode<Map>'; type Map extends HeapObject generates 'TNode<Map>';
// The accessors for HeapObject's map cannot be declared before Map // The accessors for HeapObject's map cannot be declared before Map
// is declared because forward declarations are not (yet) supported. // is declared because forward declarations are not (yet) supported.
...@@ -61,9 +63,10 @@ type Map extends HeapObject generates 'TNode<Map>'; ...@@ -61,9 +63,10 @@ type Map extends HeapObject generates 'TNode<Map>';
extern operator '.map' macro LoadMap(HeapObject): Map; extern operator '.map' macro LoadMap(HeapObject): Map;
extern transitioning operator '.map=' macro StoreMap(HeapObject, Map); extern transitioning operator '.map=' macro StoreMap(HeapObject, Map);
// This intrinsic should never be called from Torque code. It's used internally // These intrinsics should never be called from Torque code. They're used
// by the 'new' operator and only declared here because it's simpler than // internally by the 'new' operator and only declared here because it's simpler
// building the definition from C++. // than building the definition from C++.
intrinsic %GetAllocationBaseSize<Class: type>(map: Map): intptr;
intrinsic %Allocate<Class: type>(size: intptr): Class; intrinsic %Allocate<Class: type>(size: intptr): Class;
type FixedArrayBase extends HeapObject generates 'TNode<FixedArrayBase>'; type FixedArrayBase extends HeapObject generates 'TNode<FixedArrayBase>';
...@@ -79,6 +82,17 @@ type Constructor extends JSReceiver generates 'TNode<JSReceiver>'; ...@@ -79,6 +82,17 @@ type Constructor extends JSReceiver generates 'TNode<JSReceiver>';
type JSProxy extends JSReceiver generates 'TNode<JSProxy>'; type JSProxy extends JSReceiver generates 'TNode<JSProxy>';
class JSObject extends JSReceiver { class JSObject extends JSReceiver {
constructor(map: Map, properties: FixedArrayBase, elements: FixedArrayBase) {
super(map, properties);
this.elements = elements;
}
constructor(implicit context: Context)() {
const objectFunction: JSFunction = GetObjectFunction();
const map: Map = Cast<Map>(objectFunction.prototype_or_initial_map)
otherwise unreachable;
super(map, kEmptyFixedArray);
this.elements = kEmptyFixedArray;
}
elements: FixedArrayBase; elements: FixedArrayBase;
} }
...@@ -149,7 +163,7 @@ type NumberDictionary extends HeapObject ...@@ -149,7 +163,7 @@ type NumberDictionary extends HeapObject
// RawObjectCasts should *never* be used anywhere in Torque code except for // RawObjectCasts should *never* be used anywhere in Torque code except for
// in Torque-based UnsafeCast operators preceeded by an appropriate // in Torque-based UnsafeCast operators preceeded by an appropriate
// type assert() // type assert()
intrinsic %RawObjectCast<A: type>(o: Object): A; intrinsic %RawObjectCast<A: type>(o: Tagged): A;
intrinsic %RawPointerCast<A: type>(p: RawPtr): A; intrinsic %RawPointerCast<A: type>(p: RawPtr): A;
intrinsic %RawConstexprCast<To: type, From: type>(f: From): To; intrinsic %RawConstexprCast<To: type, From: type>(f: From): To;
...@@ -188,7 +202,6 @@ type ExtractFixedArrayFlags ...@@ -188,7 +202,6 @@ type ExtractFixedArrayFlags
constexpr 'CodeStubAssembler::ExtractFixedArrayFlags'; constexpr 'CodeStubAssembler::ExtractFixedArrayFlags';
type ParameterMode type ParameterMode
generates 'TNode<Int32T>' constexpr 'ParameterMode'; generates 'TNode<Int32T>' constexpr 'ParameterMode';
type RootIndex generates 'TNode<Int32T>' constexpr 'RootIndex';
type WriteBarrierMode type WriteBarrierMode
generates 'TNode<Int32T>' constexpr 'WriteBarrierMode'; generates 'TNode<Int32T>' constexpr 'WriteBarrierMode';
......
...@@ -11,7 +11,7 @@ namespace object { ...@@ -11,7 +11,7 @@ namespace object {
const elements: FixedArray = const elements: FixedArray =
Cast<FixedArray>(array.elements) otherwise IfSlow; Cast<FixedArray>(array.elements) otherwise IfSlow;
const length: Smi = array.length; const length: Smi = array.length;
const result: JSObject = AllocateEmptyJSObject(); const result: JSObject = new JSObject{};
for (let k: Smi = 0; k < length; ++k) { for (let k: Smi = 0; k < length; ++k) {
const value: Object = array::LoadElementOrUndefined(elements, k); const value: Object = array::LoadElementOrUndefined(elements, k);
...@@ -41,7 +41,7 @@ namespace object { ...@@ -41,7 +41,7 @@ namespace object {
return ObjectFromEntriesFastCase(iterable) otherwise IfSlow; return ObjectFromEntriesFastCase(iterable) otherwise IfSlow;
} }
label IfSlow { label IfSlow {
const result: JSObject = AllocateEmptyJSObject(); const result: JSObject = new JSObject{};
const fastIteratorResultMap: Map = const fastIteratorResultMap: Map =
Cast<Map>(LoadNativeContext(context)[ITERATOR_RESULT_MAP_INDEX]) Cast<Map>(LoadNativeContext(context)[ITERATOR_RESULT_MAP_INDEX])
otherwise unreachable; otherwise unreachable;
......
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
namespace object {
macro AllocateEmptyJSObject(implicit context: Context)(): JSObject {
const objectFunction: JSFunction = GetObjectFunction();
const map: Map = Cast<Map>(objectFunction.prototype_or_initial_map)
otherwise unreachable;
return AllocateJSObjectFromMap(map);
}
}
...@@ -234,6 +234,24 @@ void CSAGenerator::EmitInstruction(const CallIntrinsicInstruction& instruction, ...@@ -234,6 +234,24 @@ void CSAGenerator::EmitInstruction(const CallIntrinsicInstruction& instruction,
s << "%FromConstexpr does not support return type " << *return_type; s << "%FromConstexpr does not support return type " << *return_type;
ReportError(s.str()); ReportError(s.str());
} }
} else if (instruction.intrinsic->ExternalName() ==
"%GetAllocationBaseSize") {
if (instruction.specialization_types.size() != 1) {
ReportError(
"incorrect number of specialization classes for "
"%GetAllocationBaseSize (should be one)");
}
const ClassType* class_type =
ClassType::cast(instruction.specialization_types[0]);
// Special case classes that may not always have a fixed size (e.g.
// JSObjects). Their size must be fetched from the map.
if (class_type != TypeOracle::GetJSObjectType()) {
out_ << "CodeStubAssembler(state_).IntPtrConstant((";
args[0] = std::to_string(class_type->size());
} else {
out_ << "CodeStubAssembler(state_).TimesTaggedSize(CodeStubAssembler("
"state_).LoadMapInstanceSizeInWords(";
}
} else if (instruction.intrinsic->ExternalName() == "%Allocate") { } else if (instruction.intrinsic->ExternalName() == "%Allocate") {
out_ << "ca_.UncheckedCast<" << return_type->GetGeneratedTNodeTypeName() out_ << "ca_.UncheckedCast<" << return_type->GetGeneratedTNodeTypeName()
<< ">(CodeStubAssembler(state_).Allocate"; << ">(CodeStubAssembler(state_).Allocate";
...@@ -245,11 +263,21 @@ void CSAGenerator::EmitInstruction(const CallIntrinsicInstruction& instruction, ...@@ -245,11 +263,21 @@ void CSAGenerator::EmitInstruction(const CallIntrinsicInstruction& instruction,
out_ << "("; out_ << "(";
PrintCommaSeparatedList(out_, args); PrintCommaSeparatedList(out_, args);
if (instruction.intrinsic->ExternalName() == "%Allocate") out_ << ")"; if (instruction.intrinsic->ExternalName() == "%Allocate") out_ << ")";
if (instruction.intrinsic->ExternalName() == "%GetAllocationBaseSize")
out_ << "))";
if (return_type->IsStructType()) { if (return_type->IsStructType()) {
out_ << ").Flatten();\n"; out_ << ").Flatten();\n";
} else { } else {
out_ << ");\n"; out_ << ");\n";
} }
if (instruction.intrinsic->ExternalName() == "%Allocate") {
out_ << " CodeStubAssembler(state_).InitializeFieldsWithRoot("
<< results[0] << ", ";
out_ << "CodeStubAssembler(state_).IntPtrConstant("
<< std::to_string(ClassType::cast(return_type)->size()) << "), ";
PrintCommaSeparatedList(out_, args);
out_ << ", RootIndex::kUndefinedValue);\n";
}
} }
void CSAGenerator::EmitInstruction(const CallCsaMacroInstruction& instruction, void CSAGenerator::EmitInstruction(const CallCsaMacroInstruction& instruction,
......
...@@ -274,7 +274,7 @@ void DeclarationVisitor::DeclareMethods( ...@@ -274,7 +274,7 @@ void DeclarationVisitor::DeclareMethods(
} }
} }
if (container_type->Constructors().size() != 0) return; if (constructor_this_type->Constructors().size() != 0) return;
// Generate default constructor. // Generate default constructor.
Signature constructor_signature; Signature constructor_signature;
......
...@@ -1251,9 +1251,18 @@ VisitResult ImplementationVisitor::Visit(NewExpression* expr) { ...@@ -1251,9 +1251,18 @@ VisitResult ImplementationVisitor::Visit(NewExpression* expr) {
// Output the code to generate an unitialized object of the class size in the // Output the code to generate an unitialized object of the class size in the
// GC heap. // GC heap.
VisitResult raw_object_map =
ProjectStructField(new_struct_result, "map_untyped");
Arguments map_cast_arguments;
map_cast_arguments.parameters.push_back(raw_object_map);
VisitResult object_map = GenerateCall("%RawObjectCast", map_cast_arguments,
{TypeOracle::GetMapType()}, false);
Arguments size_arguments;
size_arguments.parameters.push_back(object_map);
VisitResult object_size = GenerateCall("%GetAllocationBaseSize",
size_arguments, {class_type}, false);
Arguments allocate_arguments; Arguments allocate_arguments;
allocate_arguments.parameters.push_back(VisitResult( allocate_arguments.parameters.push_back(object_size);
TypeOracle::GetConstInt31Type(), std::to_string(class_type->size())));
VisitResult allocate_result = VisitResult allocate_result =
GenerateCall("%Allocate", allocate_arguments, {class_type}, false); GenerateCall("%Allocate", allocate_arguments, {class_type}, false);
DCHECK(allocate_result.IsOnStack()); DCHECK(allocate_result.IsOnStack());
...@@ -2083,8 +2092,8 @@ VisitResult ImplementationVisitor::GenerateCall( ...@@ -2083,8 +2092,8 @@ VisitResult ImplementationVisitor::GenerateCall(
result << ")"; result << ")";
return VisitResult(return_type, result.str()); return VisitResult(return_type, result.str());
} else { } else {
assembler().Emit( assembler().Emit(CallIntrinsicInstruction{intrinsic, specialization_types,
CallIntrinsicInstruction{intrinsic, constexpr_arguments}); constexpr_arguments});
size_t return_slot_count = size_t return_slot_count =
LoweredSlotCount(intrinsic->signature().return_type); LoweredSlotCount(intrinsic->signature().return_type);
return VisitResult(return_type, assembler().TopRange(return_slot_count)); return VisitResult(return_type, assembler().TopRange(return_slot_count));
......
...@@ -230,10 +230,14 @@ struct StoreObjectFieldInstruction : InstructionBase { ...@@ -230,10 +230,14 @@ struct StoreObjectFieldInstruction : InstructionBase {
struct CallIntrinsicInstruction : InstructionBase { struct CallIntrinsicInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE() TORQUE_INSTRUCTION_BOILERPLATE()
CallIntrinsicInstruction(Intrinsic* intrinsic, CallIntrinsicInstruction(Intrinsic* intrinsic,
TypeVector specialization_types,
std::vector<std::string> constexpr_arguments) std::vector<std::string> constexpr_arguments)
: intrinsic(intrinsic), constexpr_arguments(constexpr_arguments) {} : intrinsic(intrinsic),
specialization_types(std::move(specialization_types)),
constexpr_arguments(constexpr_arguments) {}
Intrinsic* intrinsic; Intrinsic* intrinsic;
TypeVector specialization_types;
std::vector<std::string> constexpr_arguments; std::vector<std::string> constexpr_arguments;
}; };
......
...@@ -107,10 +107,18 @@ class TypeOracle : public ContextualClass<TypeOracle> { ...@@ -107,10 +107,18 @@ class TypeOracle : public ContextualClass<TypeOracle> {
return Get().GetBuiltinType(RAWPTR_TYPE_STRING); return Get().GetBuiltinType(RAWPTR_TYPE_STRING);
} }
static const Type* GetMapType() {
return Get().GetBuiltinType(MAP_TYPE_STRING);
}
static const Type* GetObjectType() { static const Type* GetObjectType() {
return Get().GetBuiltinType(OBJECT_TYPE_STRING); return Get().GetBuiltinType(OBJECT_TYPE_STRING);
} }
static const Type* GetJSObjectType() {
return Get().GetBuiltinType(JSOBJECT_TYPE_STRING);
}
static const Type* GetTaggedType() { static const Type* GetTaggedType() {
return Get().GetBuiltinType(TAGGED_TYPE_STRING); return Get().GetBuiltinType(TAGGED_TYPE_STRING);
} }
......
...@@ -26,7 +26,9 @@ static const char* const BOOL_TYPE_STRING = "bool"; ...@@ -26,7 +26,9 @@ static const char* const BOOL_TYPE_STRING = "bool";
static const char* const VOID_TYPE_STRING = "void"; static const char* const VOID_TYPE_STRING = "void";
static const char* const ARGUMENTS_TYPE_STRING = "constexpr Arguments"; static const char* const ARGUMENTS_TYPE_STRING = "constexpr Arguments";
static const char* const CONTEXT_TYPE_STRING = "Context"; static const char* const CONTEXT_TYPE_STRING = "Context";
static const char* const MAP_TYPE_STRING = "Map";
static const char* const OBJECT_TYPE_STRING = "Object"; static const char* const OBJECT_TYPE_STRING = "Object";
static const char* const JSOBJECT_TYPE_STRING = "JSObject";
static const char* const SMI_TYPE_STRING = "Smi"; static const char* const SMI_TYPE_STRING = "Smi";
static const char* const TAGGED_TYPE_STRING = "Tagged"; static const char* const TAGGED_TYPE_STRING = "Tagged";
static const char* const RAWPTR_TYPE_STRING = "RawPtr"; static const char* const RAWPTR_TYPE_STRING = "RawPtr";
......
...@@ -46,11 +46,12 @@ def preprocess(input): ...@@ -46,11 +46,12 @@ def preprocess(input):
return input return input
def postprocess(output): def postprocess(output):
output = re.sub(r'% RawObjectCast', r'%RawObjectCast', output) output = re.sub(r'%\s*RawObjectCast', r'%RawObjectCast', output)
output = re.sub(r'% RawPointerCast', r'%RawPointerCast', output) output = re.sub(r'%\s*RawPointerCast', r'%RawPointerCast', output)
output = re.sub(r'% RawConstexprCast', r'%RawConstexprCast', output) output = re.sub(r'%\s*RawConstexprCast', r'%RawConstexprCast', output)
output = re.sub(r'% FromConstexpr', r'%FromConstexpr', output) output = re.sub(r'%\s*FromConstexpr', r'%FromConstexpr', output)
output = re.sub(r'% Allocate', r'%Allocate', output) output = re.sub(r'%\s*Allocate', r'%Allocate', output)
output = re.sub(r'%\s*GetAllocationBaseSize', r'%GetAllocationBaseSize', output)
output = re.sub(r'\/\*COxp\*\/', r'constexpr', output) output = re.sub(r'\/\*COxp\*\/', r'constexpr', output)
output = re.sub(r'(\S+)\s*: type([,>])', r'\1: type\2', output) output = re.sub(r'(\S+)\s*: type([,>])', r'\1: type\2', output)
output = re.sub(r'(\n\s*)labels( [A-Z])', r'\1 labels\2', output) output = re.sub(r'(\n\s*)labels( [A-Z])', r'\1 labels\2', output)
......
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