[builtins] Port GetArgumentsFrameAndCount to Torque

In the process, add the bint type (which stands for Best-INTeger),
which implements Torque's idea of CSA's ParameterMode. It maps to
a different type on 32-bit (Smi) and 64-bit (intptr). There are
convert operators that are either no-ops or conversions
to-and-from Smi and intptrs on the each platform, depending on
the underlying type for bint. This allows Torque code to git most
of the benefits of ParameterMode without having to explicitly
pass around the mode, since it is almost always OptimalMode anyways.

Change-Id: I92e08adc1d79cb3e24576c96f9734aec1af54162
Reviewed-on: https://chromium-review.googlesource.com/c/1361160
Commit-Queue: Daniel Clifford <danno@chromium.org>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58253}
This commit is contained in:
Daniel Clifford 2018-12-14 11:35:34 -08:00 committed by Commit Bot
parent 00d6c6677c
commit a74afec6ba
10 changed files with 134 additions and 100 deletions

View File

@ -952,6 +952,8 @@ action("postmortem-metadata") {
torque_files = [
"src/builtins/base.tq",
"src/builtins/frames.tq",
"src/builtins/arguments.tq",
"src/builtins/array.tq",
"src/builtins/array-copywithin.tq",
"src/builtins/array-foreach.tq",
@ -964,7 +966,6 @@ torque_files = [
"src/builtins/array-unshift.tq",
"src/builtins/collections.tq",
"src/builtins/data-view.tq",
"src/builtins/frames.tq",
"src/builtins/object.tq",
"src/builtins/object-fromentries.tq",
"src/builtins/iterator.tq",
@ -975,6 +976,7 @@ torque_files = [
torque_namespaces = [
"base",
"arguments",
"array",
"collections",
"iterator",

44
src/builtins/arguments.tq Normal file
View File

@ -0,0 +1,44 @@
// 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 arguments {
struct ArgumentsInfo {
frame: Frame;
argument_count: bint;
formal_parameter_count: bint;
}
// Calculates and returns the frame pointer, argument count and formal
// parameter count to be used to access a function's parameters, taking
// argument adapter frames into account.
//
// TODO(danno):
// This macro is should only be used in builtins that can be called from
// interpreted or JITted code, not from CSA/Torque builtins (the number of
// returned formal parameters would be wrong).
// It is difficult to actually check/assert this, since interpreted or JITted
// frames are StandardFrames, but so are hand-written builtins. Doing that
// more refined check would be prohibitively expensive.
macro GetArgumentsFrameAndCount(implicit context: Context)(f: JSFunction):
ArgumentsInfo {
let frame: Frame = LoadParentFramePointer();
assert(frame.function == f);
const shared: SharedFunctionInfo = f.shared_function_info;
const formalParameterCount: bint =
Convert<bint>(shared.formal_parameter_count);
let argumentCount: bint = formalParameterCount;
const adaptor: ArgumentsAdaptorFrame =
Cast<ArgumentsAdaptorFrame>(frame.caller)
otherwise return ArgumentsInfo{frame, argumentCount, formalParameterCount};
return ArgumentsInfo{
adaptor,
Convert<bint>(adaptor.length),
formalParameterCount
};
}
}

View File

@ -27,6 +27,7 @@ type uintptr generates 'TNode<UintPtrT>' constexpr 'uintptr_t';
type float32 generates 'TNode<Float32T>' constexpr 'float';
type float64 generates 'TNode<Float64T>' constexpr 'double';
type bool generates 'TNode<BoolT>' constexpr 'bool';
type bint generates 'TNode<BInt>' constexpr 'BInt';
type string constexpr 'const char*';
type int31 extends int32
@ -64,7 +65,15 @@ transient type FastJSArrayForCopy extends FastJSArray
transient type FastJSArrayWithNoCustomIteration extends FastJSArray
generates 'TNode<JSArray>';
type SharedFunctionInfo extends HeapObject
generates 'TNode<SharedFunctionInfo>';
type JSFunction extends JSObject generates 'TNode<JSFunction>';
extern operator '.shared_function_info'
macro LoadJSFunctionSharedFunctionInfo(JSFunction): SharedFunctionInfo;
extern operator '.formal_parameter_count'
macro LoadSharedFunctionInfoFormalParameterCount(SharedFunctionInfo): int32;
type JSBoundFunction extends JSObject generates 'TNode<JSBoundFunction>';
type Callable = JSFunction | JSBoundFunction | JSProxy;
type Map extends HeapObject generates 'TNode<Map>';
@ -924,6 +933,17 @@ Convert<uintptr, RawPtr>(r: RawPtr): uintptr {
Convert<intptr, RawPtr>(r: RawPtr): intptr {
return Signed(r);
}
Convert<bint, int32>(v: int32): bint {
return IntPtrToBInt(Convert<intptr>(v));
}
extern macro IntPtrToBInt(intptr): bint;
Convert<bint, intptr>(v: intptr): bint {
return IntPtrToBInt(v);
}
extern macro SmiToBInt(Smi): bint;
Convert<bint, Smi>(v: Smi): bint {
return SmiToBInt(v);
}
macro BranchIf<A: type, B: type>(implicit context: Context)(o: B): never
labels True, False {

View File

@ -19,52 +19,6 @@ namespace internal {
typedef compiler::Node Node;
std::tuple<Node*, Node*, Node*>
ArgumentsBuiltinsAssembler::GetArgumentsFrameAndCount(Node* function,
ParameterMode mode) {
CSA_ASSERT(this, HasInstanceType(function, JS_FUNCTION_TYPE));
VARIABLE(frame_ptr, MachineType::PointerRepresentation());
frame_ptr.Bind(LoadParentFramePointer());
CSA_ASSERT(this,
WordEqual(function,
LoadBufferObject(frame_ptr.value(),
StandardFrameConstants::kFunctionOffset,
MachineType::Pointer())));
VARIABLE(argument_count, ParameterRepresentation(mode));
VariableList list({&frame_ptr, &argument_count}, zone());
Label done_argument_count(this, list);
// Determine the number of passed parameters, which is either the count stored
// in an arguments adapter frame or fetched from the shared function info.
Node* frame_ptr_above = LoadBufferObject(
frame_ptr.value(), StandardFrameConstants::kCallerFPOffset,
MachineType::Pointer());
Node* shared =
LoadObjectField(function, JSFunction::kSharedFunctionInfoOffset);
CSA_SLOW_ASSERT(this, HasInstanceType(shared, SHARED_FUNCTION_INFO_TYPE));
Node* formal_parameter_count =
LoadObjectField(shared, SharedFunctionInfo::kFormalParameterCountOffset,
MachineType::Uint16());
formal_parameter_count = Int32ToParameter(formal_parameter_count, mode);
argument_count.Bind(formal_parameter_count);
Node* marker_or_function = LoadBufferObject(
frame_ptr_above, CommonFrameConstants::kContextOrFrameTypeOffset);
GotoIf(
MarkerIsNotFrameType(marker_or_function, StackFrame::ARGUMENTS_ADAPTOR),
&done_argument_count);
Node* adapted_parameter_count = LoadBufferObject(
frame_ptr_above, ArgumentsAdaptorFrameConstants::kLengthOffset);
frame_ptr.Bind(frame_ptr_above);
argument_count.Bind(TaggedToParameter(adapted_parameter_count, mode));
Goto(&done_argument_count);
BIND(&done_argument_count);
return std::tuple<Node*, Node*, Node*>(
frame_ptr.value(), argument_count.value(), formal_parameter_count);
}
std::tuple<Node*, Node*, Node*>
ArgumentsBuiltinsAssembler::AllocateArgumentsObject(Node* map,
Node* arguments_count,
@ -155,22 +109,19 @@ Node* ArgumentsBuiltinsAssembler::ConstructParametersObjectFromArgs(
Node* ArgumentsBuiltinsAssembler::EmitFastNewRestParameter(Node* context,
Node* function) {
Node* frame_ptr;
Node* argument_count;
Node* formal_parameter_count;
ParameterMode mode = OptimalParameterMode();
Node* zero = IntPtrOrSmiConstant(0, mode);
std::tie(frame_ptr, argument_count, formal_parameter_count) =
GetArgumentsFrameAndCount(function, mode);
ArgumentsBuiltinsFromDSLAssembler::ArgumentsInfo info =
GetArgumentsFrameAndCount(CAST(context),
UncheckedCast<JSFunction>(function));
VARIABLE(result, MachineRepresentation::kTagged);
Label no_rest_parameters(this), runtime(this, Label::kDeferred),
done(this, &result);
Node* rest_count =
IntPtrOrSmiSub(argument_count, formal_parameter_count, mode);
IntPtrOrSmiSub(info.argument_count, info.formal_parameter_count, mode);
Node* const native_context = LoadNativeContext(context);
Node* const array_map =
LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
@ -183,8 +134,8 @@ Node* ArgumentsBuiltinsAssembler::EmitFastNewRestParameter(Node* context,
// Allocate the Rest JSArray and the elements together and fill in the
// contents with the arguments above |formal_parameter_count|.
result.Bind(ConstructParametersObjectFromArgs(
array_map, frame_ptr, argument_count, formal_parameter_count, rest_count,
mode, JSArray::kSize));
array_map, info.frame, info.argument_count, info.formal_parameter_count,
rest_count, mode, JSArray::kSize));
Goto(&done);
BIND(&no_rest_parameters);
@ -213,27 +164,24 @@ Node* ArgumentsBuiltinsAssembler::EmitFastNewStrictArguments(Node* context,
VARIABLE(result, MachineRepresentation::kTagged);
Label done(this, &result), empty(this), runtime(this, Label::kDeferred);
Node* frame_ptr;
Node* argument_count;
Node* formal_parameter_count;
ParameterMode mode = OptimalParameterMode();
Node* zero = IntPtrOrSmiConstant(0, mode);
std::tie(frame_ptr, argument_count, formal_parameter_count) =
GetArgumentsFrameAndCount(function, mode);
ArgumentsBuiltinsFromDSLAssembler::ArgumentsInfo info =
GetArgumentsFrameAndCount(CAST(context),
UncheckedCast<JSFunction>(function));
GotoIfFixedArraySizeDoesntFitInNewSpace(
argument_count, &runtime,
info.argument_count, &runtime,
JSStrictArgumentsObject::kSize + FixedArray::kHeaderSize, mode);
Node* const native_context = LoadNativeContext(context);
Node* const map =
LoadContextElement(native_context, Context::STRICT_ARGUMENTS_MAP_INDEX);
GotoIf(WordEqual(argument_count, zero), &empty);
GotoIf(WordEqual(info.argument_count, zero), &empty);
result.Bind(ConstructParametersObjectFromArgs(
map, frame_ptr, argument_count, zero, argument_count, mode,
map, info.frame, info.argument_count, zero, info.argument_count, mode,
JSStrictArgumentsObject::kSize));
Goto(&done);
@ -260,9 +208,6 @@ Node* ArgumentsBuiltinsAssembler::EmitFastNewStrictArguments(Node* context,
Node* ArgumentsBuiltinsAssembler::EmitFastNewSloppyArguments(Node* context,
Node* function) {
Node* frame_ptr;
Node* argument_count;
Node* formal_parameter_count;
VARIABLE(result, MachineRepresentation::kTagged);
ParameterMode mode = OptimalParameterMode();
@ -271,25 +216,26 @@ Node* ArgumentsBuiltinsAssembler::EmitFastNewSloppyArguments(Node* context,
Label done(this, &result), empty(this), no_parameters(this),
runtime(this, Label::kDeferred);
std::tie(frame_ptr, argument_count, formal_parameter_count) =
GetArgumentsFrameAndCount(function, mode);
ArgumentsBuiltinsFromDSLAssembler::ArgumentsInfo info =
GetArgumentsFrameAndCount(CAST(context),
UncheckedCast<JSFunction>(function));
GotoIf(WordEqual(argument_count, zero), &empty);
GotoIf(WordEqual(info.argument_count, zero), &empty);
GotoIf(WordEqual(formal_parameter_count, zero), &no_parameters);
GotoIf(WordEqual(info.formal_parameter_count, zero), &no_parameters);
{
Comment("Mapped parameter JSSloppyArgumentsObject");
Node* mapped_count =
IntPtrOrSmiMin(argument_count, formal_parameter_count, mode);
IntPtrOrSmiMin(info.argument_count, info.formal_parameter_count, mode);
Node* parameter_map_size =
IntPtrOrSmiAdd(mapped_count, IntPtrOrSmiConstant(2, mode), mode);
// Verify that the overall allocation will fit in new space.
Node* elements_allocated =
IntPtrOrSmiAdd(argument_count, parameter_map_size, mode);
IntPtrOrSmiAdd(info.argument_count, parameter_map_size, mode);
GotoIfFixedArraySizeDoesntFitInNewSpace(
elements_allocated, &runtime,
JSSloppyArgumentsObject::kSize + FixedArray::kHeaderSize * 2, mode);
@ -301,8 +247,8 @@ Node* ArgumentsBuiltinsAssembler::EmitFastNewSloppyArguments(Node* context,
Node* elements;
Node* map_array;
std::tie(argument_object, elements, map_array) =
AllocateArgumentsObject(map, argument_count, parameter_map_size, mode,
JSSloppyArgumentsObject::kSize);
AllocateArgumentsObject(map, info.argument_count, parameter_map_size,
mode, JSSloppyArgumentsObject::kSize);
StoreObjectFieldNoWriteBarrier(
argument_object, JSSloppyArgumentsObject::kCalleeOffset, function);
StoreFixedArrayElement(CAST(map_array), 0, context, SKIP_WRITE_BARRIER);
@ -310,14 +256,14 @@ Node* ArgumentsBuiltinsAssembler::EmitFastNewSloppyArguments(Node* context,
Comment("Fill in non-mapped parameters");
Node* argument_offset =
ElementOffsetFromIndex(argument_count, PACKED_ELEMENTS, mode,
ElementOffsetFromIndex(info.argument_count, PACKED_ELEMENTS, mode,
FixedArray::kHeaderSize - kHeapObjectTag);
Node* mapped_offset =
ElementOffsetFromIndex(mapped_count, PACKED_ELEMENTS, mode,
FixedArray::kHeaderSize - kHeapObjectTag);
CodeStubArguments arguments(this, argument_count, frame_ptr, mode);
CodeStubArguments arguments(this, info.argument_count, info.frame, mode);
VARIABLE(current_argument, MachineType::PointerRepresentation());
current_argument.Bind(arguments.AtIndexPtr(argument_count, mode));
current_argument.Bind(arguments.AtIndexPtr(info.argument_count, mode));
VariableList var_list1({&current_argument}, zone());
mapped_offset = BuildFastLoop(
var_list1, argument_offset, mapped_offset,
@ -341,7 +287,7 @@ Node* ArgumentsBuiltinsAssembler::EmitFastNewSloppyArguments(Node* context,
VARIABLE(context_index, OptimalParameterRepresentation());
context_index.Bind(IntPtrOrSmiSub(
IntPtrOrSmiAdd(IntPtrOrSmiConstant(Context::MIN_CONTEXT_SLOTS, mode),
formal_parameter_count, mode),
info.formal_parameter_count, mode),
mapped_count, mode));
Node* the_hole = TheHoleConstant();
VariableList var_list2({&context_index}, zone());
@ -372,13 +318,13 @@ Node* ArgumentsBuiltinsAssembler::EmitFastNewSloppyArguments(Node* context,
{
Comment("No parameters JSSloppyArgumentsObject");
GotoIfFixedArraySizeDoesntFitInNewSpace(
argument_count, &runtime,
info.argument_count, &runtime,
JSSloppyArgumentsObject::kSize + FixedArray::kHeaderSize, mode);
Node* const native_context = LoadNativeContext(context);
Node* const map =
LoadContextElement(native_context, Context::SLOPPY_ARGUMENTS_MAP_INDEX);
result.Bind(ConstructParametersObjectFromArgs(
map, frame_ptr, argument_count, zero, argument_count, mode,
map, info.frame, info.argument_count, zero, info.argument_count, mode,
JSSloppyArgumentsObject::kSize));
StoreObjectFieldNoWriteBarrier(
result.value(), JSSloppyArgumentsObject::kCalleeOffset, function);

View File

@ -6,6 +6,7 @@
#define V8_BUILTINS_BUILTINS_ARGUMENTS_GEN_H_
#include "src/code-stub-assembler.h"
#include "torque-generated/builtins-arguments-from-dsl-gen.h"
namespace v8 {
namespace internal {
@ -14,23 +15,17 @@ typedef compiler::Node Node;
typedef compiler::CodeAssemblerState CodeAssemblerState;
typedef compiler::CodeAssemblerLabel CodeAssemblerLabel;
class ArgumentsBuiltinsAssembler : public CodeStubAssembler {
class ArgumentsBuiltinsAssembler : public CodeStubAssembler,
public ArgumentsBuiltinsFromDSLAssembler {
public:
explicit ArgumentsBuiltinsAssembler(CodeAssemblerState* state)
: CodeStubAssembler(state) {}
: CodeStubAssembler(state), ArgumentsBuiltinsFromDSLAssembler(state) {}
Node* EmitFastNewStrictArguments(Node* context, Node* function);
Node* EmitFastNewSloppyArguments(Node* context, Node* function);
Node* EmitFastNewRestParameter(Node* context, Node* function);
private:
// Calculates and returns the the frame pointer, argument count and formal
// parameter count to be used to access a function's parameters, taking
// argument adapter frames into account. The tuple is of the form:
// <frame_ptr, # parameters actually passed, formal parameter count>
std::tuple<Node*, Node*, Node*> GetArgumentsFrameAndCount(Node* function,
ParameterMode mode);
// Allocates an an arguments (either rest, strict or sloppy) together with the
// FixedArray elements for the arguments and a parameter map (for sloppy
// arguments only). A tuple is returned with pointers to the arguments object,

View File

@ -34,11 +34,11 @@ type FrameBase extends RawPtr
generates 'TNode<RawPtrT>' constexpr 'void*';
type StandardFrame extends FrameBase
generates 'TNode<RawPtrT>' constexpr 'void*';
type ArgumentsAdapterFrame extends FrameBase
type ArgumentsAdaptorFrame extends FrameBase
generates 'TNode<RawPtrT>' constexpr 'void*';
type StubFrame extends FrameBase
generates 'TNode<RawPtrT>' constexpr 'void*';
type Frame = ArgumentsAdapterFrame | StandardFrame | StubFrame;
type Frame = ArgumentsAdaptorFrame | StandardFrame | StubFrame;
extern macro LoadFramePointer(): Frame;
extern macro LoadParentFramePointer(): Frame;
@ -101,7 +101,7 @@ const kArgumentsAdaptorFrameLengthOffset: constexpr int31
generates 'ArgumentsAdaptorFrameConstants::kLengthOffset';
operator '.length'
macro LoadLengthFromAdapterFrame(implicit context: Context)(
f: ArgumentsAdapterFrame): Smi {
f: ArgumentsAdaptorFrame): Smi {
return LoadSmiFromFrame(f, kArgumentsAdaptorFrameLengthOffset);
}
@ -129,12 +129,12 @@ Cast<StandardFrame>(implicit context: Context)(f: Frame):
goto CastError;
}
Cast<ArgumentsAdapterFrame>(implicit context: Context)(f: Frame):
ArgumentsAdapterFrame labels CastError {
Cast<ArgumentsAdaptorFrame>(implicit context: Context)(f: Frame):
ArgumentsAdaptorFrame labels CastError {
const t: FrameType =
Cast<FrameType>(f.context_or_frame_type) otherwise CastError;
if (t == ARGUMENTS_ADAPTOR_FRAME) {
return %RawPointerCast<ArgumentsAdapterFrame>(f);
return %RawPointerCast<ArgumentsAdaptorFrame>(f);
}
goto CastError;
}

View File

@ -276,6 +276,24 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
return value;
}
#if defined(V8_HOST_ARCH_32_BIT)
TNode<Smi> BIntToSmi(TNode<BInt> source) { return source; }
TNode<IntPtrT> BIntToIntPtr(TNode<BInt> source) {
return SmiToIntPtr(source);
}
TNode<BInt> SmiToBInt(TNode<Smi> source) { return source; }
TNode<BInt> IntPtrToBInt(TNode<IntPtrT> source) {
return SmiFromIntPtr(source);
}
#elif defined(V8_HOST_ARCH_64_BIT)
TNode<Smi> BIntToSmi(TNode<BInt> source) { return SmiFromIntPtr(source); }
TNode<IntPtrT> BIntToIntPtr(TNode<BInt> source) { return source; }
TNode<BInt> SmiToBInt(TNode<Smi> source) { return SmiToIntPtr(source); }
TNode<BInt> IntPtrToBInt(TNode<IntPtrT> source) { return source; }
#else
#error Unknown architecture.
#endif
TNode<Smi> TaggedToSmi(TNode<Object> value, Label* fail) {
GotoIf(TaggedIsNotSmi(value), fail);
return UncheckedCast<Smi>(value);

View File

@ -1691,6 +1691,15 @@ class CodeAssemblerScopedExceptionHandler {
};
} // namespace compiler
#if defined(V8_HOST_ARCH_32_BIT)
typedef Smi BInt;
#elif defined(V8_HOST_ARCH_64_BIT)
typedef IntPtrT BInt;
#else
#error Unknown architecture.
#endif
} // namespace internal
} // namespace v8

View File

@ -125,8 +125,8 @@ bool IsKeywordLikeName(const std::string& s) {
// naming convention and are those exempt from the normal type convention.
bool IsMachineType(const std::string& s) {
static const char* const machine_types[]{
"void", "never", "int32", "uint32", "int64", "intptr",
"uintptr", "float32", "float64", "bool", "string", "int31"};
"void", "never", "int32", "uint32", "int64", "intptr", "uintptr",
"float32", "float64", "bool", "string", "bint", "int31"};
return std::find(std::begin(machine_types), std::end(machine_types), s) !=
std::end(machine_types);

View File

@ -681,7 +681,7 @@ namespace test {
case (f: StandardFrame): {
unreachable;
}
case (f: ArgumentsAdapterFrame): {
case (f: ArgumentsAdaptorFrame): {
unreachable;
}
case (f: StubFrame): {