Commit 2506963a authored by Daniel Clifford's avatar Daniel Clifford Committed by Commit Bot

[torque] Correctly generate one .h/.cc file pair per module

In the process and as a test case of the module/file-handling, separate
Array.p.forEach into its own Torque file.

Bug: v8:7793
Change-Id: If45103a9df3bf8fade34e7bcf7c7c9c060e25966
Reviewed-on: https://chromium-review.googlesource.com/1097755Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Commit-Queue: Daniel Clifford <danno@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53703}
parent 98d7b23e
......@@ -868,6 +868,7 @@ action("postmortem-metadata") {
torque_files = [
"src/builtins/base.tq",
"src/builtins/array.tq",
"src/builtins/array-foreach.tq",
"src/builtins/typed-array.tq",
"src/builtins/data-view.tq",
"test/torque/test-torque.tq",
......
// 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.
module array {
macro ArrayForEachTorqueContinuation(
context: Context, o: Object, len: Number, callbackfn: Callable,
thisArg: Object, initial_k: Smi): Object {
// 5. Let k be 0.
// 6. Repeat, while k < len
for (let k: Smi = initial_k; k < len; k = k + 1) {
// 6a. Let Pk be ! ToString(k).
let pK: String = ToString_Inline(context, k);
// 6b. Let kPresent be ? HasProperty(O, Pk).
let kPresent: Oddball = HasPropertyObject(o, pK, context, kHasProperty);
// 6c. If kPresent is true, then
if (kPresent == True) {
// 6c. i. Let kValue be ? Get(O, Pk).
let kValue: Object = GetProperty(context, o, pK);
// 6c. ii. Perform ? Call(callbackfn, T, <kValue, k, O>).
Call(context, callbackfn, thisArg, kValue, k, o);
}
// 6d. Increase k by 1. (done by the loop).
}
return Undefined;
}
javascript builtin ArrayForEachLoopEagerDeoptContinuation(
context: Context, receiver: Object, callback: Object, thisArg: Object,
initialK: Object, length: Object): Object {
return ArrayForEachLoopContinuation(
context, receiver, callback, thisArg, Undefined, receiver, initialK,
length, Undefined);
}
javascript builtin ArrayForEachLoopLazyDeoptContinuation(
context: Context, receiver: Object, callback: Object, thisArg: Object,
initialK: Object, length: Object, result: Object): Object {
return ArrayForEachLoopContinuation(
context, receiver, callback, thisArg, Undefined, receiver, initialK,
length, Undefined);
}
builtin ArrayForEachLoopContinuation(
context: Context, receiver: Object, callback: Object, thisArg: Object,
array: Object, object: Object, initialK: Object, length: Object,
to: Object): Object {
try {
let callbackfn: Callable = cast<Callable>(callback) otherwise Unexpected;
let k: Smi = cast<Smi>(initialK) otherwise Unexpected;
let number_length: Number = cast<Number>(length) otherwise Unexpected;
return ArrayForEachTorqueContinuation(
context, object, number_length, callbackfn, thisArg, k);
}
label Unexpected {
unreachable;
}
}
macro VisitAllElements<FixedArrayType : type>(
context: Context, a: JSArray, len: Smi, callbackfn: Callable,
thisArg: Object): void labels
Bailout(Smi) {
let k: Smi = 0;
let map: Map = a.map;
try {
// Build a fast loop over the smi array.
for (; k < len; k = k + 1) {
// Ensure that the map didn't change.
if (map != a.map) goto Slow;
// Ensure that we haven't walked beyond a possibly updated length.
if (k >= a.length) goto Slow;
try {
let value: Object =
LoadElementNoHole<FixedArrayType>(a, k) otherwise FoundHole;
Call(context, callbackfn, thisArg, value, k, a);
}
label FoundHole {
// If we found the hole, we need to bail out if the initial
// array prototype has had elements inserted. This is preferable
// to walking the prototype chain looking for elements.
if (IsNoElementsProtectorCellInvalid()) goto Bailout(k);
}
}
}
label Slow {
goto Bailout(k);
}
}
macro FastArrayForEach(
context: Context, o: Object, len: Number, callbackfn: Callable,
thisArg: Object): Object labels
Bailout(Smi) {
let k: Smi = 0;
try {
let smi_len: Smi = cast<Smi>(len) otherwise Slow;
let a: JSArray = cast<JSArray>(o) otherwise Slow;
let map: Map = a.map;
if (!IsPrototypeInitialArrayPrototype(context, map)) goto Slow;
let elementsKind: ElementsKind = map.elements_kind;
if (!IsFastElementsKind(elementsKind)) goto Slow;
if (IsElementsKindGreaterThan(elementsKind, HOLEY_ELEMENTS)) {
VisitAllElements<FixedDoubleArray>(
context, a, smi_len, callbackfn, thisArg)
otherwise Bailout;
} else {
VisitAllElements<FixedArray>(context, a, smi_len, callbackfn, thisArg)
otherwise Bailout;
}
}
label Slow {
goto Bailout(k);
}
return Undefined;
}
// https://tc39.github.io/ecma262/#sec-array.prototype.foreach
javascript builtin ArrayForEach(
context: Context, receiver: Object, ...arguments): Object {
try {
if (IsNullOrUndefined(receiver)) {
goto NullOrUndefinedError;
}
// 1. Let O be ? ToObject(this value).
let o: Object = ToObject(context, receiver);
// 2. Let len be ? ToLength(? Get(O, "length")).
let len: Number =
ToLength_Inline(context, GetProperty(context, o, 'length'));
// 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
if (arguments.length == 0) {
goto TypeError;
}
let callbackfn: Callable =
cast<Callable>(arguments[0]) otherwise TypeError;
// 4. If thisArg is present, let T be thisArg; else let T be undefined.
let thisArg: Object = arguments.length > 1 ? arguments[1] : Undefined;
// Special cases.
let k: Smi = 0;
try {
return FastArrayForEach(context, o, len, callbackfn, thisArg)
otherwise Bailout;
}
label Bailout(k_value: Smi) {
k = k_value;
}
return ArrayForEachTorqueContinuation(
context, o, len, callbackfn, thisArg, k);
}
label TypeError {
ThrowTypeError(context, kCalledNonCallable, arguments[0]);
}
label NullOrUndefinedError {
ThrowTypeError(
context, kCalledOnNullOrUndefined, 'Array.prototype.forEach');
}
}
}
......@@ -298,175 +298,6 @@ module array {
return a;
}
macro ArrayForEachTorqueContinuation(
context: Context, o: Object, len: Number, callbackfn: Callable,
thisArg: Object, initial_k: Smi): Object {
// 5. Let k be 0.
// 6. Repeat, while k < len
for (let k: Smi = initial_k; k < len; k = k + 1) {
// 6a. Let Pk be ! ToString(k).
let pK: String = ToString_Inline(context, k);
// 6b. Let kPresent be ? HasProperty(O, Pk).
let kPresent: Oddball = HasPropertyObject(o, pK, context, kHasProperty);
// 6c. If kPresent is true, then
if (kPresent == True) {
// 6c. i. Let kValue be ? Get(O, Pk).
let kValue: Object = GetProperty(context, o, pK);
// 6c. ii. Perform ? Call(callbackfn, T, <kValue, k, O>).
Call(context, callbackfn, thisArg, kValue, k, o);
}
// 6d. Increase k by 1. (done by the loop).
}
return Undefined;
}
javascript builtin ArrayForEachLoopEagerDeoptContinuation(
context: Context, receiver: Object, callback: Object, thisArg: Object,
initialK: Object, length: Object): Object {
return ArrayForEachLoopContinuation(
context, receiver, callback, thisArg, Undefined, receiver, initialK,
length, Undefined);
}
javascript builtin ArrayForEachLoopLazyDeoptContinuation(
context: Context, receiver: Object, callback: Object, thisArg: Object,
initialK: Object, length: Object, result: Object): Object {
return ArrayForEachLoopContinuation(
context, receiver, callback, thisArg, Undefined, receiver, initialK,
length, Undefined);
}
builtin ArrayForEachLoopContinuation(
context: Context, receiver: Object, callback: Object, thisArg: Object,
array: Object, object: Object, initialK: Object, length: Object,
to: Object): Object {
try {
let callbackfn: Callable = cast<Callable>(callback) otherwise Unexpected;
let k: Smi = cast<Smi>(initialK) otherwise Unexpected;
let number_length: Number = cast<Number>(length) otherwise Unexpected;
return ArrayForEachTorqueContinuation(
context, object, number_length, callbackfn, thisArg, k);
}
label Unexpected {
unreachable;
}
}
macro VisitAllElements<FixedArrayType : type>(
context: Context, a: JSArray, len: Smi, callbackfn: Callable,
thisArg: Object): void labels
Bailout(Smi) {
let k: Smi = 0;
let map: Map = a.map;
try {
// Build a fast loop over the smi array.
for (; k < len; k = k + 1) {
// Ensure that the map didn't change.
if (map != a.map) goto Slow;
// Ensure that we haven't walked beyond a possibly updated length.
if (k >= a.length) goto Slow;
try {
let value: Object =
LoadElementNoHole<FixedArrayType>(a, k) otherwise FoundHole;
Call(context, callbackfn, thisArg, value, k, a);
}
label FoundHole {
// If we found the hole, we need to bail out if the initial
// array prototype has had elements inserted. This is preferable
// to walking the prototype chain looking for elements.
if (IsNoElementsProtectorCellInvalid()) goto Bailout(k);
}
}
}
label Slow {
goto Bailout(k);
}
}
macro FastArrayForEach(
context: Context, o: Object, len: Number, callbackfn: Callable,
thisArg: Object): Object labels
Bailout(Smi) {
let k: Smi = 0;
try {
let smi_len: Smi = cast<Smi>(len) otherwise Slow;
let a: JSArray = cast<JSArray>(o) otherwise Slow;
let map: Map = a.map;
if (!IsPrototypeInitialArrayPrototype(context, map)) goto Slow;
let elementsKind: ElementsKind = map.elements_kind;
if (!IsFastElementsKind(elementsKind)) goto Slow;
if (IsElementsKindGreaterThan(elementsKind, HOLEY_ELEMENTS)) {
VisitAllElements<FixedDoubleArray>(
context, a, smi_len, callbackfn, thisArg)
otherwise Bailout;
} else {
VisitAllElements<FixedArray>(context, a, smi_len, callbackfn, thisArg)
otherwise Bailout;
}
}
label Slow {
goto Bailout(k);
}
return Undefined;
}
// https://tc39.github.io/ecma262/#sec-array.prototype.foreach
javascript builtin ArrayForEach(
context: Context, receiver: Object, ...arguments): Object {
try {
if (IsNullOrUndefined(receiver)) {
goto NullOrUndefinedError;
}
// 1. Let O be ? ToObject(this value).
let o: Object = ToObject(context, receiver);
// 2. Let len be ? ToLength(? Get(O, "length")).
let len: Number =
ToLength_Inline(context, GetProperty(context, o, 'length'));
// 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
if (arguments.length == 0) {
goto TypeError;
}
let callbackfn: Callable =
cast<Callable>(arguments[0]) otherwise TypeError;
// 4. If thisArg is present, let T be thisArg; else let T be undefined.
let thisArg: Object = arguments.length > 1 ? arguments[1] : Undefined;
// Special cases.
let k: Smi = 0;
try {
return FastArrayForEach(context, o, len, callbackfn, thisArg)
otherwise Bailout;
}
label Bailout(k_value: Smi) {
k = k_value;
}
return ArrayForEachTorqueContinuation(
context, o, len, callbackfn, thisArg, k);
}
label TypeError {
ThrowTypeError(context, kCalledNonCallable, arguments[0]);
}
label NullOrUndefinedError {
ThrowTypeError(
context, kCalledOnNullOrUndefined, 'Array.prototype.forEach');
}
}
// Naming convention from elements.cc. We have a similar intent but implement
// fastpaths using generics instead of using a class hierarchy for elements
// kinds specific implementations.
......
......@@ -22,8 +22,10 @@ class TypeOracle;
class Module {
public:
explicit Module(const std::string& name) : name_(name) {}
explicit Module(const std::string& name, bool is_default)
: name_(name), is_default_(is_default) {}
const std::string& name() const { return name_; }
bool IsDefault() const { return is_default_; }
std::ostream& source_stream() { return source_stream_; }
std::ostream& header_stream() { return header_stream_; }
std::string source() { return source_stream_.str(); }
......@@ -31,6 +33,7 @@ class Module {
private:
std::string name_;
bool is_default_;
std::stringstream header_stream_;
std::stringstream source_stream_;
};
......@@ -56,15 +59,15 @@ class GlobalContext {
explicit GlobalContext(Ast ast)
: verbose_(false),
next_label_number_(0),
default_module_(GetModule("base")),
default_module_(GetModule("base", true)),
ast_(std::move(ast)) {}
Module* GetDefaultModule() { return default_module_; }
Module* GetModule(const std::string& name) {
Module* GetModule(const std::string& name, bool is_default = false) {
auto i = modules_.find(name);
if (i != modules_.end()) {
return i->second.get();
}
Module* module = new Module(name);
Module* module = new Module(name, is_default);
modules_[name] = std::unique_ptr<Module>(module);
return module;
}
......
......@@ -66,13 +66,11 @@ void ImplementationVisitor::Visit(CallableNode* decl,
}
}
void ImplementationVisitor::Visit(ModuleDeclaration* decl) {
Module* module = decl->GetModule();
void ImplementationVisitor::BeginModuleFile(Module* module) {
std::ostream& source = module->source_stream();
std::ostream& header = module->header_stream();
if (decl->IsDefault()) {
if (module->IsDefault()) {
source << "#include \"src/code-stub-assembler.h\"";
} else {
source << "#include \"src/builtins/builtins-" +
......@@ -103,7 +101,7 @@ void ImplementationVisitor::Visit(ModuleDeclaration* decl) {
std::string("V8_TORQUE_") + upper_name + "_FROM_DSL_BASE_H__";
header << "#ifndef " << headerDefine << std::endl;
header << "#define " << headerDefine << std::endl << std::endl;
if (decl->IsDefault()) {
if (module->IsDefault()) {
header << "#include \"src/code-stub-assembler.h\"";
} else {
header << "#include \"src/builtins/builtins-" +
......@@ -130,15 +128,20 @@ void ImplementationVisitor::Visit(ModuleDeclaration* decl) {
header << " template <class T>" << std::endl;
header << " using SloppyTNode = compiler::SloppyTNode<T>;" << std::endl
<< std::endl;
}
Module* saved_module = module_;
module_ = module;
Declarations::NodeScopeActivator scope(declarations(), decl);
for (auto& child : decl->declarations) Visit(child);
module_ = saved_module;
void ImplementationVisitor::EndModuleFile(Module* module) {
std::ostream& source = module->source_stream();
std::ostream& header = module->header_stream();
DrainSpecializationQueue();
std::string upper_name(module->name());
transform(upper_name.begin(), upper_name.end(), upper_name.begin(),
::toupper);
std::string headerDefine =
std::string("V8_TORQUE_") + upper_name + "_FROM_DSL_BASE_H__";
source << "} // namepsace internal" << std::endl
<< "} // namespace v8" << std::endl
<< "" << std::endl;
......@@ -150,6 +153,15 @@ void ImplementationVisitor::Visit(ModuleDeclaration* decl) {
header << "#endif // " << headerDefine << std::endl;
}
void ImplementationVisitor::Visit(ModuleDeclaration* decl) {
Module* module = decl->GetModule();
Module* saved_module = module_;
module_ = module;
Declarations::NodeScopeActivator scope(declarations(), decl);
for (auto& child : decl->declarations) Visit(child);
module_ = saved_module;
}
void ImplementationVisitor::Visit(TorqueMacroDeclaration* decl,
const Signature& sig, Statement* body) {
Signature signature = MakeSignature(decl->signature.get());
......
......@@ -140,6 +140,9 @@ class ImplementationVisitor : public FileVisitor {
const Type* Visit(DebugStatement* stmt);
const Type* Visit(AssertStatement* stmt);
void BeginModuleFile(Module* module);
void EndModuleFile(Module* module);
void GenerateImplementation(const std::string& dir, Module* module);
private:
......
......@@ -115,9 +115,14 @@ int WrappedMain(int argc, const char** argv) {
}
ImplementationVisitor visitor(global_context);
for (auto& module : global_context.GetModules()) {
visitor.BeginModuleFile(module.second.get());
}
visitor.Visit(global_context.ast());
for (auto& module : global_context.GetModules()) {
visitor.EndModuleFile(module.second.get());
visitor.GenerateImplementation(output_directory, module.second.get());
}
}
......
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