[torque] Implement Rest/Strict/Sloppy argument stubs in Torque
Bug: v8:7793 Change-Id: Ib950ce398f101779a4654353d08ce947b8e05a66 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1526016 Reviewed-by: Tobias Tebbi <tebbi@chromium.org> Commit-Queue: Daniel Clifford <danno@chromium.org> Cr-Commit-Position: refs/heads/master@{#65518}
This commit is contained in:
parent
1b450a1752
commit
bc0c25b4a0
2
BUILD.gn
2
BUILD.gn
@ -1486,8 +1486,6 @@ v8_source_set("v8_initializers") {
|
||||
|
||||
sources = [
|
||||
### gcmole(all) ###
|
||||
"src/builtins/builtins-arguments-gen.cc",
|
||||
"src/builtins/builtins-arguments-gen.h",
|
||||
"src/builtins/builtins-array-gen.cc",
|
||||
"src/builtins/builtins-array-gen.h",
|
||||
"src/builtins/builtins-async-function-gen.cc",
|
||||
|
@ -140,6 +140,10 @@ type NoSharedNameSentinel extends Smi;
|
||||
|
||||
extern class ScopeInfo extends FixedArray;
|
||||
|
||||
operator '[]' macro LoadScopeInfoElement(s: ScopeInfo, i: intptr): Object {
|
||||
return s.objects[i];
|
||||
}
|
||||
|
||||
// Specialized types. The following three type definitions don't correspond to
|
||||
// actual C++ classes, but have Is... methods that check additional constraints.
|
||||
|
||||
@ -331,6 +335,9 @@ extern enum PrimitiveType { kString, kBoolean, kSymbol, kNumber }
|
||||
const kNameDictionaryInitialCapacity:
|
||||
constexpr int32 generates 'NameDictionary::kInitialCapacity';
|
||||
|
||||
const kScopeInfoFlagsIndex:
|
||||
constexpr int32 generates 'ScopeInfo::Fields::kFlags';
|
||||
|
||||
type TheHole extends Oddball;
|
||||
type Null extends Oddball;
|
||||
type Undefined extends Oddball;
|
||||
@ -865,6 +872,7 @@ extern macro EmptyFixedArrayConstant(): EmptyFixedArray;
|
||||
extern macro PromiseCapabilityMapConstant(): Map;
|
||||
extern macro OneByteStringMapConstant(): Map;
|
||||
extern macro StringMapConstant(): Map;
|
||||
extern macro SloppyArgumentsElementsMapConstant(): Map;
|
||||
|
||||
const kFixedArrayMap: Map = FixedArrayMapConstant();
|
||||
const kCOWMap: Map = FixedCOWArrayMapConstant();
|
||||
@ -875,6 +883,7 @@ const kPromiseCapabilityMap: Map = PromiseCapabilityMapConstant();
|
||||
const kOneByteStringMap: Map = OneByteStringMapConstant();
|
||||
// The map of a non-internalized internal SeqTwoByteString.
|
||||
const kStringMap: Map = StringMapConstant();
|
||||
const kSloppyArgumentsElementsMap: Map = SloppyArgumentsElementsMapConstant();
|
||||
|
||||
extern macro IsPrototypeInitialArrayPrototype(implicit context: Context)(Map):
|
||||
bool;
|
||||
@ -985,6 +994,18 @@ macro GetRegExpLastMatchInfo(implicit context: Context)(): RegExpMatchInfo {
|
||||
return %RawDownCast<RegExpMatchInfo>(LoadNativeContext(
|
||||
context)[NativeContextSlot::REGEXP_LAST_MATCH_INFO_INDEX]);
|
||||
}
|
||||
macro GetStrictArgumentsMap(implicit context: Context)(): Map {
|
||||
return UnsafeCast<Map>(LoadNativeContext(
|
||||
context)[NativeContextSlot::STRICT_ARGUMENTS_MAP_INDEX]);
|
||||
}
|
||||
macro GetSloppyArgumentsMap(implicit context: Context)(): Map {
|
||||
return UnsafeCast<Map>(LoadNativeContext(
|
||||
context)[NativeContextSlot::SLOPPY_ARGUMENTS_MAP_INDEX]);
|
||||
}
|
||||
macro GetFastAliasedArgumentsMap(implicit context: Context)(): Map {
|
||||
return UnsafeCast<Map>(LoadNativeContext(
|
||||
context)[NativeContextSlot::FAST_ALIASED_ARGUMENTS_MAP_INDEX]);
|
||||
}
|
||||
|
||||
extern transitioning macro Call(Context, Callable, JSAny): JSAny;
|
||||
extern transitioning macro Call(Context, Callable, JSAny, JSAny): JSAny;
|
||||
@ -1508,3 +1529,5 @@ macro ReplaceTheHoleWithUndefined(o: JSAny|TheHole): JSAny {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern macro DecodeScopeInfoHasContextExtension(intptr): intptr;
|
||||
|
@ -1,348 +0,0 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
#include "src/builtins/builtins-arguments-gen.h"
|
||||
|
||||
#include "src/builtins/builtins-utils-gen.h"
|
||||
#include "src/builtins/builtins.h"
|
||||
#include "src/codegen/code-factory.h"
|
||||
#include "src/codegen/code-stub-assembler.h"
|
||||
#include "src/codegen/interface-descriptors.h"
|
||||
#include "src/execution/arguments.h"
|
||||
#include "src/execution/frame-constants.h"
|
||||
#include "src/objects/arguments.h"
|
||||
#include "src/objects/objects-inl.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
ArgumentsBuiltinsAssembler::ArgumentsAllocationResult
|
||||
ArgumentsBuiltinsAssembler::AllocateArgumentsObject(
|
||||
TNode<Map> map, TNode<BInt> arguments_count,
|
||||
TNode<BInt> parameter_map_count, int base_size) {
|
||||
// Allocate the parameter object (either a Rest parameter object, a strict
|
||||
// argument object or a sloppy arguments object) and the elements/mapped
|
||||
// arguments together.
|
||||
int elements_offset = base_size;
|
||||
TNode<BInt> element_count = arguments_count;
|
||||
if (parameter_map_count != nullptr) {
|
||||
base_size += FixedArray::kHeaderSize;
|
||||
element_count = IntPtrOrSmiAdd(element_count, parameter_map_count);
|
||||
}
|
||||
bool empty = IsIntPtrOrSmiConstantZero(arguments_count);
|
||||
DCHECK_IMPLIES(empty, parameter_map_count == nullptr);
|
||||
TNode<IntPtrT> size =
|
||||
empty ? IntPtrConstant(base_size)
|
||||
: ElementOffsetFromIndex(element_count, PACKED_ELEMENTS,
|
||||
base_size + FixedArray::kHeaderSize);
|
||||
TNode<HeapObject> result = Allocate(size);
|
||||
Comment("Initialize arguments object");
|
||||
StoreMapNoWriteBarrier(result, map);
|
||||
TNode<FixedArray> empty_fixed_array = EmptyFixedArrayConstant();
|
||||
StoreObjectField(result, JSArray::kPropertiesOrHashOffset, empty_fixed_array);
|
||||
TNode<Smi> smi_arguments_count = BIntToSmi(arguments_count);
|
||||
StoreObjectFieldNoWriteBarrier(result, JSArray::kLengthOffset,
|
||||
smi_arguments_count);
|
||||
TNode<HeapObject> arguments;
|
||||
if (!empty) {
|
||||
arguments = InnerAllocate(result, elements_offset);
|
||||
StoreObjectFieldNoWriteBarrier(arguments, FixedArray::kLengthOffset,
|
||||
smi_arguments_count);
|
||||
TNode<Map> fixed_array_map = FixedArrayMapConstant();
|
||||
StoreMapNoWriteBarrier(arguments, fixed_array_map);
|
||||
}
|
||||
TNode<HeapObject> parameter_map;
|
||||
if (!parameter_map_count.is_null()) {
|
||||
TNode<IntPtrT> parameter_map_offset = ElementOffsetFromIndex(
|
||||
arguments_count, PACKED_ELEMENTS, FixedArray::kHeaderSize);
|
||||
parameter_map = InnerAllocate(arguments, parameter_map_offset);
|
||||
StoreObjectFieldNoWriteBarrier(result, JSArray::kElementsOffset,
|
||||
parameter_map);
|
||||
TNode<Map> sloppy_elements_map = SloppyArgumentsElementsMapConstant();
|
||||
StoreMapNoWriteBarrier(parameter_map, sloppy_elements_map);
|
||||
StoreObjectFieldNoWriteBarrier(parameter_map, FixedArray::kLengthOffset,
|
||||
BIntToSmi(parameter_map_count));
|
||||
} else {
|
||||
if (empty) {
|
||||
StoreObjectFieldNoWriteBarrier(result, JSArray::kElementsOffset,
|
||||
empty_fixed_array);
|
||||
} else {
|
||||
StoreObjectFieldNoWriteBarrier(result, JSArray::kElementsOffset,
|
||||
arguments);
|
||||
}
|
||||
}
|
||||
return {CAST(result), UncheckedCast<FixedArray>(arguments),
|
||||
UncheckedCast<FixedArray>(parameter_map)};
|
||||
}
|
||||
|
||||
TNode<JSObject> ArgumentsBuiltinsAssembler::ConstructParametersObjectFromArgs(
|
||||
TNode<Map> map, TNode<RawPtrT> frame_ptr, TNode<BInt> arg_count,
|
||||
TNode<BInt> first_arg, TNode<BInt> rest_count, int base_size) {
|
||||
// Allocate the parameter object (either a Rest parameter object, a strict
|
||||
// argument object or a sloppy arguments object) and the elements together and
|
||||
// fill in the contents with the arguments above |formal_parameter_count|.
|
||||
ArgumentsAllocationResult alloc_result =
|
||||
AllocateArgumentsObject(map, rest_count, {}, base_size);
|
||||
DCHECK(alloc_result.parameter_map.is_null());
|
||||
CodeStubArguments arguments(this, arg_count, frame_ptr);
|
||||
TVARIABLE(IntPtrT, offset,
|
||||
IntPtrConstant(FixedArrayBase::kHeaderSize - kHeapObjectTag));
|
||||
VariableList list({&offset}, zone());
|
||||
arguments.ForEach(
|
||||
list,
|
||||
[&](TNode<Object> arg) {
|
||||
StoreNoWriteBarrier(MachineRepresentation::kTagged,
|
||||
alloc_result.elements, offset.value(), arg);
|
||||
Increment(&offset, kTaggedSize);
|
||||
},
|
||||
first_arg);
|
||||
return alloc_result.arguments_object;
|
||||
}
|
||||
|
||||
TNode<JSObject> ArgumentsBuiltinsAssembler::EmitFastNewRestParameter(
|
||||
TNode<Context> context, TNode<JSFunction> function) {
|
||||
ParameterMode mode = OptimalParameterMode();
|
||||
TNode<BInt> zero = BIntConstant(0);
|
||||
|
||||
TorqueStructArgumentsInfo info = GetArgumentsFrameAndCount(context, function);
|
||||
|
||||
TVARIABLE(JSObject, result);
|
||||
Label no_rest_parameters(this), runtime(this, Label::kDeferred),
|
||||
done(this, &result);
|
||||
|
||||
TNode<BInt> rest_count =
|
||||
IntPtrOrSmiSub(info.argument_count, info.formal_parameter_count);
|
||||
const TNode<NativeContext> native_context = LoadNativeContext(context);
|
||||
const TNode<Map> array_map =
|
||||
LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
|
||||
GotoIf(IntPtrOrSmiLessThanOrEqual(rest_count, zero), &no_rest_parameters);
|
||||
|
||||
GotoIfFixedArraySizeDoesntFitInNewSpace(
|
||||
rest_count, &runtime, JSArray::kHeaderSize + FixedArray::kHeaderSize,
|
||||
mode);
|
||||
|
||||
// Allocate the Rest JSArray and the elements together and fill in the
|
||||
// contents with the arguments above |formal_parameter_count|.
|
||||
result = ConstructParametersObjectFromArgs(
|
||||
array_map, info.frame, info.argument_count, info.formal_parameter_count,
|
||||
rest_count, JSArray::kHeaderSize);
|
||||
Goto(&done);
|
||||
|
||||
BIND(&no_rest_parameters);
|
||||
{
|
||||
ArgumentsAllocationResult alloc_result =
|
||||
AllocateArgumentsObject(array_map, zero, {}, JSArray::kHeaderSize);
|
||||
result = alloc_result.arguments_object;
|
||||
Goto(&done);
|
||||
}
|
||||
|
||||
BIND(&runtime);
|
||||
{
|
||||
result = CAST(CallRuntime(Runtime::kNewRestParameter, context, function));
|
||||
Goto(&done);
|
||||
}
|
||||
|
||||
BIND(&done);
|
||||
return result.value();
|
||||
}
|
||||
|
||||
TNode<JSObject> ArgumentsBuiltinsAssembler::EmitFastNewStrictArguments(
|
||||
TNode<Context> context, TNode<JSFunction> function) {
|
||||
TVARIABLE(JSObject, result);
|
||||
Label done(this, &result), empty(this), runtime(this, Label::kDeferred);
|
||||
|
||||
ParameterMode mode = OptimalParameterMode();
|
||||
TNode<BInt> zero = BIntConstant(0);
|
||||
|
||||
TorqueStructArgumentsInfo info = GetArgumentsFrameAndCount(context, function);
|
||||
|
||||
GotoIfFixedArraySizeDoesntFitInNewSpace(
|
||||
info.argument_count, &runtime,
|
||||
JSStrictArgumentsObject::kSize + FixedArray::kHeaderSize, mode);
|
||||
|
||||
const TNode<NativeContext> native_context = LoadNativeContext(context);
|
||||
TNode<Map> map = CAST(
|
||||
LoadContextElement(native_context, Context::STRICT_ARGUMENTS_MAP_INDEX));
|
||||
GotoIf(BIntEqual(info.argument_count, zero), &empty);
|
||||
|
||||
result = ConstructParametersObjectFromArgs(
|
||||
map, info.frame, info.argument_count, zero, info.argument_count,
|
||||
JSStrictArgumentsObject::kSize);
|
||||
Goto(&done);
|
||||
|
||||
BIND(&empty);
|
||||
{
|
||||
ArgumentsAllocationResult alloc_result =
|
||||
AllocateArgumentsObject(map, zero, {}, JSStrictArgumentsObject::kSize);
|
||||
result = alloc_result.arguments_object;
|
||||
Goto(&done);
|
||||
}
|
||||
|
||||
BIND(&runtime);
|
||||
{
|
||||
result = CAST(CallRuntime(Runtime::kNewStrictArguments, context, function));
|
||||
Goto(&done);
|
||||
}
|
||||
|
||||
BIND(&done);
|
||||
return result.value();
|
||||
}
|
||||
|
||||
TNode<JSObject> ArgumentsBuiltinsAssembler::EmitFastNewSloppyArguments(
|
||||
TNode<Context> context, TNode<JSFunction> function) {
|
||||
TVARIABLE(JSObject, result);
|
||||
|
||||
ParameterMode mode = OptimalParameterMode();
|
||||
TNode<BInt> zero = BIntConstant(0);
|
||||
|
||||
Label done(this, &result), empty(this), no_parameters(this),
|
||||
runtime(this, Label::kDeferred);
|
||||
|
||||
TorqueStructArgumentsInfo info = GetArgumentsFrameAndCount(context, function);
|
||||
|
||||
GotoIf(BIntEqual(info.argument_count, zero), &empty);
|
||||
|
||||
GotoIf(BIntEqual(info.formal_parameter_count, zero), &no_parameters);
|
||||
|
||||
{
|
||||
Comment("Mapped parameter JSSloppyArgumentsObject");
|
||||
|
||||
TNode<BInt> mapped_count =
|
||||
IntPtrOrSmiMin(info.argument_count, info.formal_parameter_count);
|
||||
|
||||
TNode<BInt> parameter_map_size =
|
||||
IntPtrOrSmiAdd(mapped_count, BIntConstant(2));
|
||||
|
||||
// Verify that the overall allocation will fit in new space.
|
||||
TNode<BInt> elements_allocated =
|
||||
IntPtrOrSmiAdd(info.argument_count, parameter_map_size);
|
||||
GotoIfFixedArraySizeDoesntFitInNewSpace(
|
||||
elements_allocated, &runtime,
|
||||
JSSloppyArgumentsObject::kSize + FixedArray::kHeaderSize * 2, mode);
|
||||
|
||||
const TNode<NativeContext> native_context = LoadNativeContext(context);
|
||||
const TNode<Map> map = CAST(LoadContextElement(
|
||||
native_context, Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX));
|
||||
ArgumentsAllocationResult alloc_result =
|
||||
AllocateArgumentsObject(map, info.argument_count, parameter_map_size,
|
||||
JSSloppyArgumentsObject::kSize);
|
||||
StoreObjectFieldNoWriteBarrier(alloc_result.arguments_object,
|
||||
JSSloppyArgumentsObject::kCalleeOffset,
|
||||
function);
|
||||
StoreFixedArrayElement(alloc_result.parameter_map, 0, context,
|
||||
SKIP_WRITE_BARRIER);
|
||||
StoreFixedArrayElement(alloc_result.parameter_map, 1, alloc_result.elements,
|
||||
SKIP_WRITE_BARRIER);
|
||||
|
||||
Comment("Fill in non-mapped parameters");
|
||||
TNode<IntPtrT> argument_offset =
|
||||
ElementOffsetFromIndex(info.argument_count, PACKED_ELEMENTS,
|
||||
FixedArray::kHeaderSize - kHeapObjectTag);
|
||||
TNode<IntPtrT> mapped_offset =
|
||||
ElementOffsetFromIndex(mapped_count, PACKED_ELEMENTS,
|
||||
FixedArray::kHeaderSize - kHeapObjectTag);
|
||||
CodeStubArguments arguments(this, info.argument_count, info.frame);
|
||||
TVARIABLE(RawPtrT, current_argument,
|
||||
arguments.AtIndexPtr(info.argument_count));
|
||||
VariableList var_list1({¤t_argument}, zone());
|
||||
mapped_offset = BuildFastLoop<IntPtrT>(
|
||||
var_list1, argument_offset, mapped_offset,
|
||||
[&](TNode<IntPtrT> offset) {
|
||||
Increment(¤t_argument, kSystemPointerSize);
|
||||
TNode<Object> arg = LoadBufferObject(
|
||||
ReinterpretCast<RawPtrT>(current_argument.value()), 0);
|
||||
StoreNoWriteBarrier(MachineRepresentation::kTagged,
|
||||
alloc_result.elements, offset, arg);
|
||||
return;
|
||||
},
|
||||
-kTaggedSize);
|
||||
|
||||
// Copy the parameter slots and the holes in the arguments.
|
||||
// We need to fill in mapped_count slots. They index the context,
|
||||
// where parameters are stored in reverse order, at
|
||||
// context_header_size .. context_header_size+argument_count-1
|
||||
// The mapped parameter thus need to get indices
|
||||
// context_header_size+parameter_count-1 ..
|
||||
// context_header_size+argument_count-mapped_count
|
||||
// We loop from right to left.
|
||||
Comment("Fill in mapped parameters");
|
||||
STATIC_ASSERT(Context::MIN_CONTEXT_EXTENDED_SLOTS ==
|
||||
Context::MIN_CONTEXT_SLOTS + 1);
|
||||
TNode<IntPtrT> flags = LoadAndUntagObjectField(LoadScopeInfo(context),
|
||||
ScopeInfo::kFlagsOffset);
|
||||
TNode<BInt> context_header_size = IntPtrOrSmiAdd(
|
||||
IntPtrToBInt(
|
||||
Signed(DecodeWord<ScopeInfo::HasContextExtensionSlotField>(flags))),
|
||||
BIntConstant(Context::MIN_CONTEXT_SLOTS));
|
||||
TVARIABLE(BInt, context_index,
|
||||
IntPtrOrSmiSub(IntPtrOrSmiAdd(context_header_size,
|
||||
info.formal_parameter_count),
|
||||
mapped_count));
|
||||
TNode<Oddball> the_hole = TheHoleConstant();
|
||||
VariableList var_list2({&context_index}, zone());
|
||||
const int kParameterMapHeaderSize = FixedArray::OffsetOfElementAt(2);
|
||||
TNode<IntPtrT> adjusted_map_array = IntPtrAdd(
|
||||
BitcastTaggedToWord(alloc_result.parameter_map),
|
||||
IntPtrConstant(kParameterMapHeaderSize - FixedArray::kHeaderSize));
|
||||
TNode<IntPtrT> zero_offset = ElementOffsetFromIndex(
|
||||
zero, PACKED_ELEMENTS, mode, FixedArray::kHeaderSize - kHeapObjectTag);
|
||||
BuildFastLoop<IntPtrT>(
|
||||
var_list2, mapped_offset, zero_offset,
|
||||
[&](TNode<IntPtrT> offset) {
|
||||
StoreNoWriteBarrier(MachineRepresentation::kTagged,
|
||||
alloc_result.elements, offset, the_hole);
|
||||
StoreNoWriteBarrier(MachineRepresentation::kTagged,
|
||||
adjusted_map_array, offset,
|
||||
BIntToSmi(context_index.value()));
|
||||
Increment(&context_index);
|
||||
},
|
||||
-kTaggedSize);
|
||||
|
||||
result = alloc_result.arguments_object;
|
||||
Goto(&done);
|
||||
}
|
||||
|
||||
BIND(&no_parameters);
|
||||
{
|
||||
Comment("No parameters JSSloppyArgumentsObject");
|
||||
GotoIfFixedArraySizeDoesntFitInNewSpace(
|
||||
info.argument_count, &runtime,
|
||||
JSSloppyArgumentsObject::kSize + FixedArray::kHeaderSize, mode);
|
||||
const TNode<NativeContext> native_context = LoadNativeContext(context);
|
||||
TNode<Map> map = CAST(LoadContextElement(
|
||||
native_context, Context::SLOPPY_ARGUMENTS_MAP_INDEX));
|
||||
result = ConstructParametersObjectFromArgs(
|
||||
map, info.frame, info.argument_count, zero, info.argument_count,
|
||||
JSSloppyArgumentsObject::kSize);
|
||||
StoreObjectFieldNoWriteBarrier(
|
||||
result.value(), JSSloppyArgumentsObject::kCalleeOffset, function);
|
||||
Goto(&done);
|
||||
}
|
||||
|
||||
BIND(&empty);
|
||||
{
|
||||
Comment("Empty JSSloppyArgumentsObject");
|
||||
const TNode<NativeContext> native_context = LoadNativeContext(context);
|
||||
const TNode<Map> map = CAST(LoadContextElement(
|
||||
native_context, Context::SLOPPY_ARGUMENTS_MAP_INDEX));
|
||||
ArgumentsAllocationResult alloc_result =
|
||||
AllocateArgumentsObject(map, zero, {}, JSSloppyArgumentsObject::kSize);
|
||||
result = alloc_result.arguments_object;
|
||||
StoreObjectFieldNoWriteBarrier(
|
||||
result.value(), JSSloppyArgumentsObject::kCalleeOffset, function);
|
||||
Goto(&done);
|
||||
}
|
||||
|
||||
BIND(&runtime);
|
||||
{
|
||||
result = CAST(CallRuntime(Runtime::kNewSloppyArguments, context, function));
|
||||
Goto(&done);
|
||||
}
|
||||
|
||||
BIND(&done);
|
||||
return result.value();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
@ -1,57 +0,0 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
#ifndef V8_BUILTINS_BUILTINS_ARGUMENTS_GEN_H_
|
||||
#define V8_BUILTINS_BUILTINS_ARGUMENTS_GEN_H_
|
||||
|
||||
#include "src/codegen/code-stub-assembler.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// TODO(v8:9396): these declarations pollute the v8::internal scope.
|
||||
using CodeAssemblerState = compiler::CodeAssemblerState;
|
||||
using CodeAssemblerLabel = compiler::CodeAssemblerLabel;
|
||||
|
||||
class ArgumentsBuiltinsAssembler : public CodeStubAssembler {
|
||||
public:
|
||||
explicit ArgumentsBuiltinsAssembler(CodeAssemblerState* state)
|
||||
: CodeStubAssembler(state) {}
|
||||
|
||||
TNode<JSObject> EmitFastNewStrictArguments(TNode<Context> context,
|
||||
TNode<JSFunction> function);
|
||||
TNode<JSObject> EmitFastNewSloppyArguments(TNode<Context> context,
|
||||
TNode<JSFunction> function);
|
||||
TNode<JSObject> EmitFastNewRestParameter(TNode<Context> context,
|
||||
TNode<JSFunction> function);
|
||||
|
||||
private:
|
||||
struct ArgumentsAllocationResult {
|
||||
TNode<JSObject> arguments_object;
|
||||
TNode<FixedArray> elements;
|
||||
TNode<FixedArray> parameter_map;
|
||||
};
|
||||
// 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, or empty TNode<> otherwise).
|
||||
ArgumentsAllocationResult AllocateArgumentsObject(
|
||||
TNode<Map> map, TNode<BInt> arguments, TNode<BInt> mapped_arguments,
|
||||
int base_size);
|
||||
|
||||
// For Rest parameters and Strict arguments, the copying of parameters from
|
||||
// the stack into the arguments object is straight-forward and shares much of
|
||||
// the same underlying logic, which is encapsulated by this function. It
|
||||
// allocates an arguments-like object of size |base_size| with the map |map|,
|
||||
// and then copies |rest_count| arguments from the stack frame pointed to by
|
||||
// |frame_ptr| starting from |first_arg|. |arg_count| == |first_arg| +
|
||||
// |rest_count|.
|
||||
TNode<JSObject> ConstructParametersObjectFromArgs(
|
||||
TNode<Map> map, TNode<RawPtrT> frame_ptr, TNode<BInt> arg_count,
|
||||
TNode<BInt> first_arg, TNode<BInt> rest_count, int base_size);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_BUILTINS_BUILTINS_ARGUMENTS_GEN_H_
|
@ -11,6 +11,8 @@
|
||||
#include "src/objects/js-proxy.h"
|
||||
#include "src/objects/objects-inl.h"
|
||||
|
||||
#include "torque-generated/exported-macros-assembler-tq.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
@ -58,64 +60,6 @@ TNode<JSProxy> ProxiesCodeStubAssembler::AllocateProxy(
|
||||
return CAST(proxy);
|
||||
}
|
||||
|
||||
TNode<JSArray> ProxiesCodeStubAssembler::AllocateJSArrayForCodeStubArguments(
|
||||
TNode<Context> context, const CodeStubArguments& args,
|
||||
TNode<IntPtrT> argc) {
|
||||
Comment("AllocateJSArrayForCodeStubArguments");
|
||||
CSA_ASSERT(this, IsValidPositiveSmi(argc));
|
||||
|
||||
Label if_empty_array(this), allocate_js_array(this);
|
||||
// Do not use AllocateJSArray since {elements} might end up in LOS.
|
||||
TVARIABLE(FixedArrayBase, elements);
|
||||
|
||||
GotoIf(WordEqual(argc, IntPtrConstant(0)), &if_empty_array);
|
||||
{
|
||||
Label if_large_object(this, Label::kDeferred);
|
||||
TNode<FixedArrayBase> allocated_elements = AllocateFixedArray(
|
||||
PACKED_ELEMENTS, argc, INTPTR_PARAMETERS, kAllowLargeObjectAllocation);
|
||||
elements = allocated_elements;
|
||||
|
||||
TVARIABLE(IntPtrT, offset,
|
||||
IntPtrConstant(FixedArrayBase::kHeaderSize - kHeapObjectTag));
|
||||
VariableList list({&offset}, zone());
|
||||
|
||||
GotoIf(
|
||||
UintPtrGreaterThan(argc, IntPtrConstant(FixedArray::kMaxRegularLength)),
|
||||
&if_large_object);
|
||||
args.ForEach(list, [&](TNode<Object> arg) {
|
||||
StoreNoWriteBarrier(MachineRepresentation::kTagged, allocated_elements,
|
||||
offset.value(), arg);
|
||||
Increment(&offset, kTaggedSize);
|
||||
});
|
||||
Goto(&allocate_js_array);
|
||||
|
||||
BIND(&if_large_object);
|
||||
{
|
||||
args.ForEach(list, [&](TNode<Object> arg) {
|
||||
Store(allocated_elements, offset.value(), arg);
|
||||
Increment(&offset, kTaggedSize);
|
||||
});
|
||||
Goto(&allocate_js_array);
|
||||
}
|
||||
}
|
||||
|
||||
BIND(&if_empty_array);
|
||||
{
|
||||
elements = EmptyFixedArrayConstant();
|
||||
Goto(&allocate_js_array);
|
||||
}
|
||||
|
||||
BIND(&allocate_js_array);
|
||||
// Allocate the result JSArray.
|
||||
TNode<NativeContext> native_context = LoadNativeContext(context);
|
||||
TNode<Map> array_map =
|
||||
LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
|
||||
TNode<Smi> length = SmiTag(argc);
|
||||
TNode<JSArray> array = AllocateJSArray(array_map, elements.value(), length);
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
TNode<Context> ProxiesCodeStubAssembler::CreateProxyRevokeFunctionContext(
|
||||
TNode<JSProxy> proxy, TNode<NativeContext> native_context) {
|
||||
const TNode<Context> context =
|
||||
@ -177,7 +121,9 @@ TF_BUILTIN(CallProxy, ProxiesCodeStubAssembler) {
|
||||
|
||||
// 7. Let argArray be CreateArrayFromList(argumentsList).
|
||||
TNode<JSArray> array =
|
||||
AllocateJSArrayForCodeStubArguments(context, args, argc_ptr);
|
||||
EmitFastNewAllArguments(UncheckedCast<Context>(context),
|
||||
UncheckedCast<RawPtrT>(LoadFramePointer()),
|
||||
UncheckedCast<IntPtrT>(argc_ptr));
|
||||
|
||||
// 8. Return Call(trap, handler, «target, thisArgument, argArray»).
|
||||
TNode<Object> result = CallJS(CodeFactory::Call(isolate()), context, trap,
|
||||
@ -230,7 +176,9 @@ TF_BUILTIN(ConstructProxy, ProxiesCodeStubAssembler) {
|
||||
|
||||
// 7. Let argArray be CreateArrayFromList(argumentsList).
|
||||
TNode<JSArray> array =
|
||||
AllocateJSArrayForCodeStubArguments(context, args, argc_ptr);
|
||||
EmitFastNewAllArguments(UncheckedCast<Context>(context),
|
||||
UncheckedCast<RawPtrT>(LoadFramePointer()),
|
||||
UncheckedCast<IntPtrT>(argc_ptr));
|
||||
|
||||
// 8. Let newObj be ? Call(trap, handler, « target, argArray, newTarget »).
|
||||
TNode<Object> new_obj = CallJS(CodeFactory::Call(isolate()), context, trap,
|
||||
|
@ -39,10 +39,6 @@ class ProxiesCodeStubAssembler : public CodeStubAssembler {
|
||||
kProxyContextLength,
|
||||
};
|
||||
|
||||
TNode<JSArray> AllocateJSArrayForCodeStubArguments(
|
||||
TNode<Context> context, const CodeStubArguments& args,
|
||||
TNode<IntPtrT> argc);
|
||||
|
||||
private:
|
||||
TNode<Context> CreateProxyRevokeFunctionContext(
|
||||
TNode<JSProxy> proxy, TNode<NativeContext> native_context);
|
||||
|
@ -228,10 +228,18 @@ extern macro IntPtrToBInt(intptr): bint;
|
||||
Convert<bint, intptr>(v: intptr): bint {
|
||||
return IntPtrToBInt(v);
|
||||
}
|
||||
extern macro BIntToIntPtr(bint): intptr;
|
||||
Convert<intptr, bint>(v: bint): intptr {
|
||||
return BIntToIntPtr(v);
|
||||
}
|
||||
extern macro SmiToBInt(Smi): bint;
|
||||
Convert<bint, Smi>(v: Smi): bint {
|
||||
return SmiToBInt(v);
|
||||
}
|
||||
extern macro BIntToSmi(bint): Smi;
|
||||
Convert<Smi, bint>(v: bint): Smi {
|
||||
return BIntToSmi(v);
|
||||
}
|
||||
Convert<PromiseState, int32>(s: int32): PromiseState {
|
||||
return %RawDownCast<PromiseState>(s);
|
||||
}
|
||||
|
@ -10,52 +10,55 @@ struct Arguments {
|
||||
}
|
||||
|
||||
extern operator '[]' macro GetArgumentValue(Arguments, intptr): JSAny;
|
||||
|
||||
extern macro GetFrameArguments(FrameWithArguments, intptr): Arguments;
|
||||
|
||||
namespace arguments {
|
||||
|
||||
@export
|
||||
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.
|
||||
@export
|
||||
macro GetArgumentsFrameAndCount(implicit context: Context)(f: JSFunction):
|
||||
ArgumentsInfo {
|
||||
const frame: Frame = LoadParentFramePointer();
|
||||
assert(frame.function == f);
|
||||
|
||||
const shared: SharedFunctionInfo = f.shared_function_info;
|
||||
const formalParameterCount: bint =
|
||||
Convert<bint>(Convert<int32>(shared.formal_parameter_count));
|
||||
const argumentCount: bint = formalParameterCount;
|
||||
|
||||
const adaptor: ArgumentsAdaptorFrame =
|
||||
Cast<ArgumentsAdaptorFrame>(frame.caller)
|
||||
otherwise return ArgumentsInfo{
|
||||
frame,
|
||||
argument_count: argumentCount,
|
||||
formal_parameter_count: formalParameterCount
|
||||
};
|
||||
|
||||
return ArgumentsInfo{
|
||||
frame: adaptor,
|
||||
argument_count: Convert<bint>(adaptor.length),
|
||||
formal_parameter_count: formalParameterCount
|
||||
};
|
||||
struct ArgumentsIterator {
|
||||
macro Next(): Object labels NoMore {
|
||||
if (this.current == this.arguments.length) goto NoMore;
|
||||
return this.arguments[this.current++];
|
||||
}
|
||||
const arguments: Arguments;
|
||||
current: intptr;
|
||||
}
|
||||
|
||||
struct FrameWithArgumentsInfo {
|
||||
const frame: FrameWithArguments;
|
||||
const argument_count: bint;
|
||||
const 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 GetFrameWithArgumentsInfo(implicit context: Context)():
|
||||
FrameWithArgumentsInfo {
|
||||
const frame =
|
||||
Cast<StandardFrame>(LoadParentFramePointer()) otherwise unreachable;
|
||||
const f: JSFunction = frame.function;
|
||||
|
||||
const shared: SharedFunctionInfo = f.shared_function_info;
|
||||
const formalParameterCount: bint =
|
||||
Convert<bint>(Convert<int32>(shared.formal_parameter_count));
|
||||
const argumentCount: bint = formalParameterCount;
|
||||
|
||||
const adaptor = Cast<ArgumentsAdaptorFrame>(frame.caller)
|
||||
otherwise return FrameWithArgumentsInfo{
|
||||
frame,
|
||||
argument_count: argumentCount,
|
||||
formal_parameter_count: formalParameterCount
|
||||
};
|
||||
|
||||
return FrameWithArgumentsInfo{
|
||||
frame: adaptor,
|
||||
argument_count: Convert<bint>(adaptor.length),
|
||||
formal_parameter_count: formalParameterCount
|
||||
};
|
||||
}
|
||||
|
@ -13435,5 +13435,10 @@ void PrototypeCheckAssembler::CheckAndBranch(TNode<HeapObject> prototype,
|
||||
}
|
||||
}
|
||||
|
||||
TNode<IntPtrT> CodeStubAssembler::DecodeScopeInfoHasContextExtension(
|
||||
TNode<IntPtrT> flags) {
|
||||
return Signed(DecodeWord<ScopeInfo::HasContextExtensionSlotField>(flags));
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -2742,6 +2742,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
TNode<UintPtrT> DecodeWord(SloppyTNode<WordT> word, uint32_t shift,
|
||||
uint32_t mask);
|
||||
|
||||
TNode<IntPtrT> DecodeScopeInfoHasContextExtension(TNode<IntPtrT> flags);
|
||||
|
||||
// Returns a node that contains the updated values of a |BitField|.
|
||||
template <typename BitField>
|
||||
TNode<Word32T> UpdateWord32(TNode<Word32T> word, TNode<Uint32T> value) {
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include <array>
|
||||
#include <tuple>
|
||||
|
||||
#include "src/builtins/builtins-arguments-gen.h"
|
||||
#include "src/builtins/builtins-constructor-gen.h"
|
||||
#include "src/builtins/builtins-iterator-gen.h"
|
||||
#include "src/codegen/code-factory.h"
|
||||
@ -26,6 +25,7 @@
|
||||
#include "src/objects/shared-function-info.h"
|
||||
#include "src/objects/source-text-module.h"
|
||||
#include "src/utils/ostreams.h"
|
||||
#include "torque-generated/exported-macros-assembler-tq.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -33,6 +33,7 @@ namespace interpreter {
|
||||
|
||||
namespace {
|
||||
|
||||
using compiler::CodeAssemblerState;
|
||||
using compiler::Node;
|
||||
using Label = CodeStubAssembler::Label;
|
||||
|
||||
@ -2830,9 +2831,7 @@ IGNITION_HANDLER(CreateMappedArguments, InterpreterAssembler) {
|
||||
|
||||
BIND(&if_not_duplicate_parameters);
|
||||
{
|
||||
ArgumentsBuiltinsAssembler constructor_assembler(state());
|
||||
TNode<JSObject> result =
|
||||
constructor_assembler.EmitFastNewSloppyArguments(context, closure);
|
||||
TNode<JSObject> result = EmitFastNewSloppyArguments(context, closure);
|
||||
SetAccumulator(result);
|
||||
Dispatch();
|
||||
}
|
||||
@ -2852,7 +2851,7 @@ IGNITION_HANDLER(CreateMappedArguments, InterpreterAssembler) {
|
||||
IGNITION_HANDLER(CreateUnmappedArguments, InterpreterAssembler) {
|
||||
TNode<Context> context = GetContext();
|
||||
TNode<JSFunction> closure = CAST(LoadRegister(Register::function_closure()));
|
||||
ArgumentsBuiltinsAssembler builtins_assembler(state());
|
||||
TorqueGeneratedExportedMacrosAssembler builtins_assembler(state());
|
||||
TNode<JSObject> result =
|
||||
builtins_assembler.EmitFastNewStrictArguments(context, closure);
|
||||
SetAccumulator(result);
|
||||
@ -2865,9 +2864,9 @@ IGNITION_HANDLER(CreateUnmappedArguments, InterpreterAssembler) {
|
||||
IGNITION_HANDLER(CreateRestParameter, InterpreterAssembler) {
|
||||
TNode<JSFunction> closure = CAST(LoadRegister(Register::function_closure()));
|
||||
TNode<Context> context = GetContext();
|
||||
ArgumentsBuiltinsAssembler builtins_assembler(state());
|
||||
TorqueGeneratedExportedMacrosAssembler builtins_assembler(state());
|
||||
TNode<JSObject> result =
|
||||
builtins_assembler.EmitFastNewRestParameter(context, closure);
|
||||
builtins_assembler.EmitFastNewRestArguments(context, closure);
|
||||
SetAccumulator(result);
|
||||
Dispatch();
|
||||
}
|
||||
|
@ -32,3 +32,200 @@ type SloppyArgumentsElements extends FixedArray;
|
||||
extern class AliasedArgumentsEntry extends Struct {
|
||||
aliased_context_slot: Smi;
|
||||
}
|
||||
|
||||
// TODO(danno): This should be a namespace {} once supported
|
||||
namespace arguments {
|
||||
|
||||
macro NewJSStrictArgumentsObject(implicit context: Context)(
|
||||
elements: FixedArray): JSStrictArgumentsObject {
|
||||
const map = GetStrictArgumentsMap();
|
||||
return new JSStrictArgumentsObject{
|
||||
map,
|
||||
properties_or_hash: kEmptyFixedArray,
|
||||
elements,
|
||||
length: elements.length
|
||||
};
|
||||
}
|
||||
|
||||
macro NewJSSloppyArgumentsObject(implicit context: Context)(
|
||||
elements: FixedArray, callee: JSFunction): JSSloppyArgumentsObject {
|
||||
const map = GetSloppyArgumentsMap();
|
||||
return new JSSloppyArgumentsObject{
|
||||
map,
|
||||
properties_or_hash: kEmptyFixedArray,
|
||||
elements,
|
||||
length: elements.length,
|
||||
callee
|
||||
};
|
||||
}
|
||||
|
||||
macro NewJSFastAliasedArgumentsObject(implicit context: Context)(
|
||||
elements: FixedArray, length: Smi,
|
||||
callee: JSFunction): JSSloppyArgumentsObject {
|
||||
// TODO(danno): FastAliasedArguments should really be a type for itself
|
||||
const map = GetFastAliasedArgumentsMap();
|
||||
return new JSSloppyArgumentsObject{
|
||||
map,
|
||||
properties_or_hash: kEmptyFixedArray,
|
||||
elements,
|
||||
length,
|
||||
callee
|
||||
};
|
||||
}
|
||||
|
||||
struct ParameterMapIterator {
|
||||
macro Next(): Object labels NoMore {
|
||||
const currentMapSlotCopy = this.currentMapSlot++;
|
||||
if (currentMapSlotCopy > 1) {
|
||||
if (this.currentIndex == this.endInterationIndex) goto NoMore;
|
||||
this.currentIndex--;
|
||||
return Convert<Smi>(this.currentIndex);
|
||||
} else if (currentMapSlotCopy == 0) {
|
||||
return this.context;
|
||||
} else {
|
||||
assert(currentMapSlotCopy == 1);
|
||||
return this.elements;
|
||||
}
|
||||
}
|
||||
const context: Context;
|
||||
const elements: FixedArray;
|
||||
currentIndex: intptr;
|
||||
const endInterationIndex: intptr;
|
||||
currentMapSlot: intptr;
|
||||
}
|
||||
|
||||
macro NewParameterMapIterator(
|
||||
context: Context, elements: FixedArray, formalParameterCount: intptr,
|
||||
mappedCount: intptr): ParameterMapIterator {
|
||||
const scopeInfoFlags = Convert<intptr>(
|
||||
UnsafeCast<Smi>(context.scope_info[kScopeInfoFlagsIndex]));
|
||||
const contextExtentionSize =
|
||||
DecodeScopeInfoHasContextExtension(scopeInfoFlags);
|
||||
const contextHeaderSize = MIN_CONTEXT_SLOTS + contextExtentionSize;
|
||||
// Copy the parameter slots and the holes in the arguments.
|
||||
// We need to fill in mapped_count slots. They index the context,
|
||||
// where parameters are stored in reverse order, at
|
||||
// context_header_size .. context_header_size+argument_count-1
|
||||
// The mapped parameter thus need to get indices
|
||||
// context_header_size+parameter_count-1 ..
|
||||
// context_header_size+argument_count-mapped_count
|
||||
// We loop from right to left.
|
||||
const afterLastContextIndex = contextHeaderSize + formalParameterCount;
|
||||
const firstContextIndex = afterLastContextIndex - mappedCount;
|
||||
return ParameterMapIterator{
|
||||
context,
|
||||
elements,
|
||||
currentIndex: afterLastContextIndex,
|
||||
endInterationIndex: firstContextIndex,
|
||||
currentMapSlot: 0
|
||||
};
|
||||
}
|
||||
|
||||
struct ParameterValueIterator {
|
||||
macro Next(): Object labels NoMore() {
|
||||
if (this.mapped_count != 0) {
|
||||
this.mapped_count--;
|
||||
return TheHole;
|
||||
}
|
||||
if (this.current == this.arguments.length) goto NoMore;
|
||||
return this.arguments[this.current++];
|
||||
}
|
||||
mapped_count: intptr;
|
||||
const arguments: Arguments;
|
||||
current: intptr;
|
||||
}
|
||||
|
||||
macro NewParameterValueIterator(mappedCount: intptr, arguments: Arguments):
|
||||
ParameterValueIterator {
|
||||
return ParameterValueIterator{
|
||||
mapped_count: mappedCount,
|
||||
arguments,
|
||||
current: mappedCount
|
||||
};
|
||||
}
|
||||
|
||||
macro NewAllArguments(implicit context: Context)(
|
||||
frame: FrameWithArguments, argumentCount: intptr): JSArray {
|
||||
const map = GetFastPackedElementsJSArrayMap();
|
||||
const arguments = GetFrameArguments(frame, argumentCount);
|
||||
const it = ArgumentsIterator{arguments, current: 0};
|
||||
const elements = NewFixedArray(argumentCount, it);
|
||||
return NewJSArray(map, elements);
|
||||
}
|
||||
|
||||
macro NewRestArguments(implicit context:
|
||||
Context)(info: FrameWithArgumentsInfo): JSArray {
|
||||
const argumentCount = Convert<intptr>(info.argument_count);
|
||||
const formalParameterCount = Convert<intptr>(info.formal_parameter_count);
|
||||
const map = GetFastPackedElementsJSArrayMap();
|
||||
const length = (formalParameterCount >= argumentCount) ?
|
||||
0 :
|
||||
argumentCount - formalParameterCount;
|
||||
const arguments = GetFrameArguments(info.frame, argumentCount);
|
||||
const it = ArgumentsIterator{arguments, current: formalParameterCount};
|
||||
const elements = NewFixedArray(length, it);
|
||||
return NewJSArray(map, elements);
|
||||
}
|
||||
|
||||
macro NewStrictArguments(implicit context: Context)(
|
||||
info: FrameWithArgumentsInfo): JSStrictArgumentsObject {
|
||||
const argumentCount = Convert<intptr>(info.argument_count);
|
||||
const arguments = GetFrameArguments(info.frame, argumentCount);
|
||||
const it = ArgumentsIterator{arguments, current: 0};
|
||||
const elements = NewFixedArray(argumentCount, it);
|
||||
return NewJSStrictArgumentsObject(elements);
|
||||
}
|
||||
|
||||
macro NewSloppyArguments(implicit context: Context)(
|
||||
info: FrameWithArgumentsInfo,
|
||||
callee: JSFunction): JSSloppyArgumentsObject {
|
||||
const argumentCount = Convert<intptr>(info.argument_count);
|
||||
const arguments = GetFrameArguments(info.frame, argumentCount);
|
||||
const formalParameterCount = Convert<intptr>(info.formal_parameter_count);
|
||||
if (formalParameterCount == 0) {
|
||||
const it = ArgumentsIterator{arguments, current: 0};
|
||||
const elements = NewFixedArray(argumentCount, it);
|
||||
return NewJSSloppyArgumentsObject(elements, callee);
|
||||
}
|
||||
const mappedCount = IntPtrMin(formalParameterCount, argumentCount);
|
||||
const it = NewParameterValueIterator(mappedCount, arguments);
|
||||
const parameterValues = NewFixedArray(argumentCount, it);
|
||||
let paramIter = NewParameterMapIterator(
|
||||
context, parameterValues, formalParameterCount, mappedCount);
|
||||
const elementsLength =
|
||||
Convert<Smi>(mappedCount + kSloppyArgumentsParameterMapStart);
|
||||
const map = kSloppyArgumentsElementsMap;
|
||||
const elements = new
|
||||
FixedArray{map, length: elementsLength, objects: ...paramIter};
|
||||
const length = Convert<Smi>(argumentCount);
|
||||
return NewJSFastAliasedArgumentsObject(elements, length, callee);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@export
|
||||
macro EmitFastNewAllArguments(implicit context: Context)(
|
||||
frame: FrameWithArguments, argc: intptr): JSArray {
|
||||
return arguments::NewAllArguments(frame, argc);
|
||||
}
|
||||
|
||||
@export
|
||||
macro EmitFastNewRestArguments(implicit context: Context)(_f: JSFunction):
|
||||
JSArray {
|
||||
const info = GetFrameWithArgumentsInfo();
|
||||
return arguments::NewRestArguments(info);
|
||||
}
|
||||
|
||||
@export
|
||||
macro EmitFastNewStrictArguments(implicit context: Context)(_f: JSFunction):
|
||||
JSStrictArgumentsObject {
|
||||
const info = GetFrameWithArgumentsInfo();
|
||||
return arguments::NewStrictArguments(info);
|
||||
}
|
||||
|
||||
@export
|
||||
macro EmitFastNewSloppyArguments(implicit context: Context)(f: JSFunction):
|
||||
JSSloppyArgumentsObject {
|
||||
const info = GetFrameWithArgumentsInfo();
|
||||
return arguments::NewSloppyArguments(info, f);
|
||||
}
|
||||
|
@ -20,6 +20,9 @@ extern class NativeContext extends Context;
|
||||
extern class ScriptContext extends Context generates 'TNode<Context>';
|
||||
extern class WithContext extends Context generates 'TNode<Context>';
|
||||
|
||||
const MIN_CONTEXT_SLOTS: constexpr int31
|
||||
generates 'Context::MIN_CONTEXT_SLOTS';
|
||||
|
||||
extern enum NativeContextSlot extends intptr constexpr 'Context::Field' {
|
||||
ARRAY_BUFFER_FUN_INDEX,
|
||||
ARRAY_BUFFER_NOINIT_FUN_INDEX,
|
||||
@ -37,6 +40,9 @@ extern enum NativeContextSlot extends intptr constexpr 'Context::Field' {
|
||||
REGEXP_LAST_MATCH_INFO_INDEX,
|
||||
INITIAL_STRING_ITERATOR_MAP_INDEX,
|
||||
SLOW_OBJECT_WITH_NULL_PROTOTYPE_MAP,
|
||||
STRICT_ARGUMENTS_MAP_INDEX,
|
||||
SLOPPY_ARGUMENTS_MAP_INDEX,
|
||||
FAST_ALIASED_ARGUMENTS_MAP_INDEX,
|
||||
|
||||
PROMISE_FUNCTION_INDEX,
|
||||
PROMISE_THEN_INDEX,
|
||||
|
@ -115,3 +115,9 @@ extern macro ExtractFixedArray(
|
||||
extern macro ExtractFixedArray(
|
||||
FixedArray, intptr, intptr, intptr,
|
||||
constexpr ExtractFixedArrayFlag): FixedArray;
|
||||
|
||||
macro NewFixedArray<I: type>(length: intptr, it: I): FixedArray {
|
||||
if (length == 0) return kEmptyFixedArray;
|
||||
return new
|
||||
FixedArray{map: kFixedArrayMap, length: Convert<Smi>(length), objects: ...it};
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ void CheckAlreadyDeclared(const std::string& name, const char* new_type) {
|
||||
FilterDeclarables<T>(Declarations::TryLookupShallow(QualifiedName(name)));
|
||||
if (!declarations.empty()) {
|
||||
Scope* scope = CurrentScope::Get();
|
||||
ReportError("cannot redeclare ", name, " (type ", new_type, scope, ")");
|
||||
ReportError("cannot redeclare ", name, " (type ", *new_type, scope, ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -720,6 +720,22 @@ TEST(TestBitFieldUintptrOps) {
|
||||
ft.Call(ft.Val(val2), ft.Val(val3));
|
||||
}
|
||||
|
||||
TEST(TestTestParentFrameArguments) {
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate(CcTest::i_isolate());
|
||||
i::HandleScope scope(isolate);
|
||||
Handle<Context> context =
|
||||
Utils::OpenHandle(*v8::Isolate::GetCurrent()->GetCurrentContext());
|
||||
CodeAssemblerTester asm_tester(isolate, 1);
|
||||
TestTorqueAssembler m(asm_tester.state());
|
||||
{
|
||||
m.TestParentFrameArguments(
|
||||
m.UncheckedCast<Context>(m.HeapConstant(context)));
|
||||
m.Return(m.UndefinedConstant());
|
||||
}
|
||||
asm_tester.GenerateCode();
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -811,6 +811,14 @@ namespace test {
|
||||
check(x.TestMethod2() == Null);
|
||||
}
|
||||
|
||||
@export
|
||||
macro TestParentFrameArguments(implicit context: Context)() {
|
||||
const parentFrame = LoadParentFramePointer();
|
||||
const castFrame = Cast<StandardFrame>(parentFrame) otherwise unreachable;
|
||||
const arguments = GetFrameArguments(castFrame, 1);
|
||||
ArgumentsIterator{arguments, current: 0};
|
||||
}
|
||||
|
||||
struct TestIterator {
|
||||
macro Next(): Object labels NoMore {
|
||||
if (this.count-- == 0) goto NoMore;
|
||||
|
Loading…
Reference in New Issue
Block a user