[builtins] Start refactoring the Apply builtin.
This splits the monolithic Apply builtin into several smaller builtins, namely CallVargargs and ConstructVarargs, which accept a length and a FixedArray of elements and deal with the actual stack manipulation, and CallWithArrayLike / ConstructWithArrayLike that deal with getting the elements from the receiver (for Function.prototype.apply, Reflect.apply and Reflect.construct), which can now be written using the CSA. The idea is that these builtins can be reused by TurboFan directly in the future when we optimize apply better, and that we can also reuse the core logic in the handling of spread calls/constructs. R=petermarshall@chromium.org BUG=v8:4587,v8:5269 Review-Url: https://codereview.chromium.org/2930623002 Cr-Commit-Position: refs/heads/master@{#45794}
This commit is contained in:
parent
ae947e26fe
commit
af76779aa3
1
BUILD.gn
1
BUILD.gn
@ -933,6 +933,7 @@ v8_source_set("v8_builtins_generators") {
|
||||
"src/builtins/builtins-async-iterator-gen.cc",
|
||||
"src/builtins/builtins-boolean-gen.cc",
|
||||
"src/builtins/builtins-call-gen.cc",
|
||||
"src/builtins/builtins-call-gen.h",
|
||||
"src/builtins/builtins-collections-gen.cc",
|
||||
"src/builtins/builtins-console-gen.cc",
|
||||
"src/builtins/builtins-constructor-gen.cc",
|
||||
|
@ -157,6 +157,16 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void CallVarargsDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// r0 : number of arguments (on the stack, not including receiver)
|
||||
// r1 : the target to call
|
||||
// r2 : arguments list (FixedArray)
|
||||
// r4 : arguments list length (untagged)
|
||||
Register registers[] = {r1, r0, r2, r4};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void CallForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// r0 : number of arguments
|
||||
@ -166,6 +176,25 @@ void CallForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void CallWithArrayLikeDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// r1 : the target to call
|
||||
// r2 : the arguments list
|
||||
Register registers[] = {r1, r2};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void ConstructVarargsDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// r0 : number of arguments (on the stack, not including receiver)
|
||||
// r1 : the target to call
|
||||
// r3 : the new target
|
||||
// r2 : arguments list (FixedArray)
|
||||
// r4 : arguments list length (untagged)
|
||||
Register registers[] = {r1, r3, r0, r2, r4};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// r0 : number of arguments
|
||||
@ -176,6 +205,15 @@ void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void ConstructWithArrayLikeDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// r1 : the target to call
|
||||
// r3 : the new target
|
||||
// r2 : the arguments list
|
||||
Register registers[] = {r1, r3, r2};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void ConstructStubDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// r0 : number of arguments
|
||||
|
@ -2794,6 +2794,17 @@ void MacroAssembler::AssertSmi(Register object) {
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::AssertFixedArray(Register object) {
|
||||
if (emit_debug_code()) {
|
||||
STATIC_ASSERT(kSmiTag == 0);
|
||||
tst(object, Operand(kSmiTagMask));
|
||||
Check(ne, kOperandIsASmiAndNotAFixedArray);
|
||||
push(object);
|
||||
CompareObjectType(object, object, object, FIXED_ARRAY_TYPE);
|
||||
pop(object);
|
||||
Check(eq, kOperandIsNotAFixedArray);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::AssertFunction(Register object) {
|
||||
if (emit_debug_code()) {
|
||||
|
@ -1215,6 +1215,9 @@ class MacroAssembler: public Assembler {
|
||||
void AssertNotSmi(Register object);
|
||||
void AssertSmi(Register object);
|
||||
|
||||
// Abort execution if argument is not a FixedArray, enabled via --debug-code.
|
||||
void AssertFixedArray(Register object);
|
||||
|
||||
// Abort execution if argument is not a JSFunction, enabled via --debug-code.
|
||||
void AssertFunction(Register object);
|
||||
|
||||
|
@ -176,6 +176,16 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void CallVarargsDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// x0 : number of arguments (on the stack, not including receiver)
|
||||
// x1 : the target to call
|
||||
// x2 : arguments list (FixedArray)
|
||||
// x4 : arguments list length (untagged)
|
||||
Register registers[] = {x1, x0, x2, x4};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void CallForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// x1: target
|
||||
@ -185,6 +195,25 @@ void CallForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void CallWithArrayLikeDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// x1 : the target to call
|
||||
// x2 : the arguments list
|
||||
Register registers[] = {x1, x2};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void ConstructVarargsDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// x0 : number of arguments (on the stack, not including receiver)
|
||||
// x1 : the target to call
|
||||
// x3 : the new target
|
||||
// x2 : arguments list (FixedArray)
|
||||
// x4 : arguments list length (untagged)
|
||||
Register registers[] = {x1, x3, x0, x2, x4};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// x3: new target
|
||||
@ -195,6 +224,15 @@ void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void ConstructWithArrayLikeDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// x1 : the target to call
|
||||
// x3 : the new target
|
||||
// x2 : the arguments list
|
||||
Register registers[] = {x1, x3, x2};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void ConstructStubDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// x3: new target
|
||||
|
@ -1781,6 +1781,17 @@ void MacroAssembler::AssertNotSmi(Register object, BailoutReason reason) {
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::AssertFixedArray(Register object) {
|
||||
if (emit_debug_code()) {
|
||||
AssertNotSmi(object, kOperandIsASmiAndNotAFixedArray);
|
||||
|
||||
UseScratchRegisterScope temps(this);
|
||||
Register temp = temps.AcquireX();
|
||||
|
||||
CompareObjectType(object, temp, temp, FIXED_ARRAY_TYPE);
|
||||
Check(eq, kOperandIsNotAFixedArray);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::AssertFunction(Register object) {
|
||||
if (emit_debug_code()) {
|
||||
|
@ -1565,6 +1565,9 @@ class MacroAssembler : public Assembler {
|
||||
inline void ObjectTag(Register tagged_obj, Register obj);
|
||||
inline void ObjectUntag(Register untagged_obj, Register obj);
|
||||
|
||||
// Abort execution if argument is not a FixedArray, enabled via --debug-code.
|
||||
void AssertFixedArray(Register object);
|
||||
|
||||
// Abort execution if argument is not a JSFunction, enabled via --debug-code.
|
||||
void AssertFunction(Register object);
|
||||
|
||||
|
@ -142,6 +142,7 @@ namespace internal {
|
||||
V(kOffsetOutOfRange, "Offset out of range") \
|
||||
V(kOperandIsASmiAndNotABoundFunction, \
|
||||
"Operand is a smi and not a bound function") \
|
||||
V(kOperandIsASmiAndNotAFixedArray, "Operand is a smi and not a fixed array") \
|
||||
V(kOperandIsASmiAndNotAFunction, "Operand is a smi and not a function") \
|
||||
V(kOperandIsASmiAndNotAGeneratorObject, \
|
||||
"Operand is a smi and not a generator object") \
|
||||
@ -150,6 +151,7 @@ namespace internal {
|
||||
V(kOperandIsASmiAndNotAString, "Operand is a smi and not a string") \
|
||||
V(kOperandIsASmi, "Operand is a smi") \
|
||||
V(kOperandIsNotABoundFunction, "Operand is not a bound function") \
|
||||
V(kOperandIsNotAFixedArray, "Operand is not a fixed array") \
|
||||
V(kOperandIsNotAFunction, "Operand is not a function") \
|
||||
V(kOperandIsNotAGeneratorObject, "Operand is not a generator object") \
|
||||
V(kOperandIsNotAReceiver, "Operand is not a receiver") \
|
||||
|
@ -1832,24 +1832,23 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
|
||||
// -- sp[8] : receiver
|
||||
// -----------------------------------
|
||||
|
||||
// 1. Load receiver into r1, argArray into r0 (if present), remove all
|
||||
// 1. Load receiver into r1, argArray into r2 (if present), remove all
|
||||
// arguments from the stack (including the receiver), and push thisArg (if
|
||||
// present) instead.
|
||||
{
|
||||
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
|
||||
__ mov(r3, r2);
|
||||
__ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
|
||||
__ mov(r2, r5);
|
||||
__ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2)); // receiver
|
||||
__ sub(r4, r0, Operand(1), SetCC);
|
||||
__ ldr(r2, MemOperand(sp, r4, LSL, kPointerSizeLog2), ge); // thisArg
|
||||
__ ldr(r5, MemOperand(sp, r4, LSL, kPointerSizeLog2), ge); // thisArg
|
||||
__ sub(r4, r4, Operand(1), SetCC, ge);
|
||||
__ ldr(r3, MemOperand(sp, r4, LSL, kPointerSizeLog2), ge); // argArray
|
||||
__ ldr(r2, MemOperand(sp, r4, LSL, kPointerSizeLog2), ge); // argArray
|
||||
__ add(sp, sp, Operand(r0, LSL, kPointerSizeLog2));
|
||||
__ str(r2, MemOperand(sp, 0));
|
||||
__ mov(r0, r3);
|
||||
__ str(r5, MemOperand(sp, 0));
|
||||
}
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- r0 : argArray
|
||||
// -- r2 : argArray
|
||||
// -- r1 : receiver
|
||||
// -- sp[0] : thisArg
|
||||
// -----------------------------------
|
||||
@ -1864,13 +1863,12 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
|
||||
|
||||
// 3. Tail call with no arguments if argArray is null or undefined.
|
||||
Label no_arguments;
|
||||
__ JumpIfRoot(r0, Heap::kNullValueRootIndex, &no_arguments);
|
||||
__ JumpIfRoot(r0, Heap::kUndefinedValueRootIndex, &no_arguments);
|
||||
__ JumpIfRoot(r2, Heap::kNullValueRootIndex, &no_arguments);
|
||||
__ JumpIfRoot(r2, Heap::kUndefinedValueRootIndex, &no_arguments);
|
||||
|
||||
// 4a. Apply the receiver to the given argArray (passing undefined for
|
||||
// new.target).
|
||||
__ LoadRoot(r3, Heap::kUndefinedValueRootIndex);
|
||||
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
|
||||
// 4a. Apply the receiver to the given argArray.
|
||||
__ Jump(masm->isolate()->builtins()->CallWithArrayLike(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
||||
// 4b. The argArray is either null or undefined, so we tail call without any
|
||||
// arguments to the receiver.
|
||||
@ -1940,26 +1938,25 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
|
||||
// -- sp[12] : receiver
|
||||
// -----------------------------------
|
||||
|
||||
// 1. Load target into r1 (if present), argumentsList into r0 (if present),
|
||||
// 1. Load target into r1 (if present), argumentsList into r2 (if present),
|
||||
// remove all arguments from the stack (including the receiver), and push
|
||||
// thisArgument (if present) instead.
|
||||
{
|
||||
__ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
|
||||
__ mov(r5, r1);
|
||||
__ mov(r2, r1);
|
||||
__ mov(r3, r1);
|
||||
__ sub(r4, r0, Operand(1), SetCC);
|
||||
__ ldr(r1, MemOperand(sp, r4, LSL, kPointerSizeLog2), ge); // target
|
||||
__ sub(r4, r4, Operand(1), SetCC, ge);
|
||||
__ ldr(r2, MemOperand(sp, r4, LSL, kPointerSizeLog2), ge); // thisArgument
|
||||
__ ldr(r5, MemOperand(sp, r4, LSL, kPointerSizeLog2), ge); // thisArgument
|
||||
__ sub(r4, r4, Operand(1), SetCC, ge);
|
||||
__ ldr(r3, MemOperand(sp, r4, LSL, kPointerSizeLog2), ge); // argumentsList
|
||||
__ ldr(r2, MemOperand(sp, r4, LSL, kPointerSizeLog2), ge); // argumentsList
|
||||
__ add(sp, sp, Operand(r0, LSL, kPointerSizeLog2));
|
||||
__ str(r2, MemOperand(sp, 0));
|
||||
__ mov(r0, r3);
|
||||
__ str(r5, MemOperand(sp, 0));
|
||||
}
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- r0 : argumentsList
|
||||
// -- r2 : argumentsList
|
||||
// -- r1 : target
|
||||
// -- sp[0] : thisArgument
|
||||
// -----------------------------------
|
||||
@ -1972,10 +1969,9 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
|
||||
__ tst(r4, Operand(1 << Map::kIsCallable));
|
||||
__ b(eq, &target_not_callable);
|
||||
|
||||
// 3a. Apply the target to the given argumentsList (passing undefined for
|
||||
// new.target).
|
||||
__ LoadRoot(r3, Heap::kUndefinedValueRootIndex);
|
||||
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
|
||||
// 3a. Apply the target to the given argumentsList.
|
||||
__ Jump(masm->isolate()->builtins()->CallWithArrayLike(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
||||
// 3b. The target is not callable, throw an appropriate TypeError.
|
||||
__ bind(&target_not_callable);
|
||||
@ -1994,7 +1990,7 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
|
||||
// -- sp[12] : receiver
|
||||
// -----------------------------------
|
||||
|
||||
// 1. Load target into r1 (if present), argumentsList into r0 (if present),
|
||||
// 1. Load target into r1 (if present), argumentsList into r2 (if present),
|
||||
// new.target into r3 (if present, otherwise use target), remove all
|
||||
// arguments from the stack (including the receiver), and push thisArgument
|
||||
// (if present) instead.
|
||||
@ -2010,11 +2006,10 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
|
||||
__ sub(r4, r4, Operand(1), SetCC, ge);
|
||||
__ ldr(r3, MemOperand(sp, r4, LSL, kPointerSizeLog2), ge); // new.target
|
||||
__ add(sp, sp, Operand(r0, LSL, kPointerSizeLog2));
|
||||
__ mov(r0, r2);
|
||||
}
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- r0 : argumentsList
|
||||
// -- r2 : argumentsList
|
||||
// -- r3 : new.target
|
||||
// -- r1 : target
|
||||
// -- sp[0] : receiver (undefined)
|
||||
@ -2037,7 +2032,8 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
|
||||
__ b(eq, &new_target_not_constructor);
|
||||
|
||||
// 4a. Construct the target with the given new.target and argumentsList.
|
||||
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
|
||||
__ Jump(masm->isolate()->builtins()->ConstructWithArrayLike(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
||||
// 4b. The target is not a constructor, throw an appropriate TypeError.
|
||||
__ bind(&target_not_constructor);
|
||||
@ -2078,98 +2074,16 @@ static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
// static
|
||||
void Builtins::Generate_Apply(MacroAssembler* masm) {
|
||||
void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm,
|
||||
Handle<Code> code) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- r0 : argumentsList
|
||||
// -- r1 : target
|
||||
// -- r3 : new.target (checked to be constructor or undefined)
|
||||
// -- sp[0] : thisArgument
|
||||
// -- r1 : target
|
||||
// -- r0 : number of parameters on the stack (not including the receiver)
|
||||
// -- r2 : arguments list (a FixedArray)
|
||||
// -- r4 : len (number of elements to push from args)
|
||||
// -- r3 : new.target (for [[Construct]])
|
||||
// -----------------------------------
|
||||
|
||||
// Create the list of arguments from the array-like argumentsList.
|
||||
{
|
||||
Label create_arguments, create_array, create_holey_array, create_runtime,
|
||||
done_create;
|
||||
__ JumpIfSmi(r0, &create_runtime);
|
||||
|
||||
// Load the map of argumentsList into r2.
|
||||
__ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
|
||||
|
||||
// Load native context into r4.
|
||||
__ ldr(r4, NativeContextMemOperand());
|
||||
|
||||
// Check if argumentsList is an (unmodified) arguments object.
|
||||
__ ldr(ip, ContextMemOperand(r4, Context::SLOPPY_ARGUMENTS_MAP_INDEX));
|
||||
__ cmp(ip, r2);
|
||||
__ b(eq, &create_arguments);
|
||||
__ ldr(ip, ContextMemOperand(r4, Context::STRICT_ARGUMENTS_MAP_INDEX));
|
||||
__ cmp(ip, r2);
|
||||
__ b(eq, &create_arguments);
|
||||
|
||||
// Check if argumentsList is a fast JSArray.
|
||||
__ CompareInstanceType(r2, ip, JS_ARRAY_TYPE);
|
||||
__ b(eq, &create_array);
|
||||
|
||||
// Ask the runtime to create the list (actually a FixedArray).
|
||||
__ bind(&create_runtime);
|
||||
{
|
||||
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
|
||||
__ Push(r1, r3, r0);
|
||||
__ CallRuntime(Runtime::kCreateListFromArrayLike);
|
||||
__ Pop(r1, r3);
|
||||
__ ldr(r2, FieldMemOperand(r0, FixedArray::kLengthOffset));
|
||||
__ SmiUntag(r2);
|
||||
}
|
||||
__ jmp(&done_create);
|
||||
|
||||
// Try to create the list from an arguments object.
|
||||
__ bind(&create_arguments);
|
||||
__ ldr(r2, FieldMemOperand(r0, JSArgumentsObject::kLengthOffset));
|
||||
__ ldr(r4, FieldMemOperand(r0, JSObject::kElementsOffset));
|
||||
__ ldr(ip, FieldMemOperand(r4, FixedArray::kLengthOffset));
|
||||
__ cmp(r2, ip);
|
||||
__ b(ne, &create_runtime);
|
||||
__ SmiUntag(r2);
|
||||
__ mov(r0, r4);
|
||||
__ b(&done_create);
|
||||
|
||||
// For holey JSArrays we need to check that the array prototype chain
|
||||
// protector is intact and our prototype is the Array.prototype actually.
|
||||
__ bind(&create_holey_array);
|
||||
__ ldr(r2, FieldMemOperand(r2, Map::kPrototypeOffset));
|
||||
__ ldr(r4, ContextMemOperand(r4, Context::INITIAL_ARRAY_PROTOTYPE_INDEX));
|
||||
__ cmp(r2, r4);
|
||||
__ b(ne, &create_runtime);
|
||||
__ LoadRoot(r4, Heap::kArrayProtectorRootIndex);
|
||||
__ ldr(r2, FieldMemOperand(r4, PropertyCell::kValueOffset));
|
||||
__ cmp(r2, Operand(Smi::FromInt(Isolate::kProtectorValid)));
|
||||
__ b(ne, &create_runtime);
|
||||
__ ldr(r2, FieldMemOperand(r0, JSArray::kLengthOffset));
|
||||
__ ldr(r0, FieldMemOperand(r0, JSArray::kElementsOffset));
|
||||
__ SmiUntag(r2);
|
||||
__ b(&done_create);
|
||||
|
||||
// Try to create the list from a JSArray object.
|
||||
// -- r2 and r4 must be preserved till bne create_holey_array.
|
||||
__ bind(&create_array);
|
||||
__ ldr(r5, FieldMemOperand(r2, Map::kBitField2Offset));
|
||||
__ DecodeField<Map::ElementsKindBits>(r5);
|
||||
STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
|
||||
STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
|
||||
STATIC_ASSERT(FAST_ELEMENTS == 2);
|
||||
STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
|
||||
__ cmp(r5, Operand(FAST_HOLEY_ELEMENTS));
|
||||
__ b(hi, &create_runtime);
|
||||
// Only FAST_XXX after this point, FAST_HOLEY_XXX are odd values.
|
||||
__ tst(r5, Operand(1));
|
||||
__ b(ne, &create_holey_array);
|
||||
// FAST_SMI_ELEMENTS or FAST_ELEMENTS after this point.
|
||||
__ ldr(r2, FieldMemOperand(r0, JSArray::kLengthOffset));
|
||||
__ ldr(r0, FieldMemOperand(r0, JSArray::kElementsOffset));
|
||||
__ SmiUntag(r2);
|
||||
|
||||
__ bind(&done_create);
|
||||
}
|
||||
__ AssertFixedArray(r2);
|
||||
|
||||
// Check for stack overflow.
|
||||
{
|
||||
@ -2181,51 +2095,38 @@ void Builtins::Generate_Apply(MacroAssembler* masm) {
|
||||
// here which will cause ip to become negative.
|
||||
__ sub(ip, sp, ip);
|
||||
// Check if the arguments will overflow the stack.
|
||||
__ cmp(ip, Operand(r2, LSL, kPointerSizeLog2));
|
||||
__ cmp(ip, Operand(r4, LSL, kPointerSizeLog2));
|
||||
__ b(gt, &done); // Signed comparison.
|
||||
__ TailCallRuntime(Runtime::kThrowStackOverflow);
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- r1 : target
|
||||
// -- r0 : args (a FixedArray built from argumentsList)
|
||||
// -- r2 : len (number of elements to push from args)
|
||||
// -- r3 : new.target (checked to be constructor or undefined)
|
||||
// -- sp[0] : thisArgument
|
||||
// -----------------------------------
|
||||
|
||||
// Push arguments onto the stack (thisArgument is already on the stack).
|
||||
{
|
||||
__ mov(r4, Operand(0));
|
||||
__ mov(r6, Operand(0));
|
||||
__ LoadRoot(r5, Heap::kTheHoleValueRootIndex);
|
||||
__ LoadRoot(r6, Heap::kUndefinedValueRootIndex);
|
||||
Label done, loop;
|
||||
__ bind(&loop);
|
||||
__ cmp(r4, r2);
|
||||
__ cmp(r6, r4);
|
||||
__ b(eq, &done);
|
||||
__ add(ip, r0, Operand(r4, LSL, kPointerSizeLog2));
|
||||
__ add(ip, r2, Operand(r6, LSL, kPointerSizeLog2));
|
||||
__ ldr(ip, FieldMemOperand(ip, FixedArray::kHeaderSize));
|
||||
__ cmp(r5, ip);
|
||||
__ mov(ip, r6, LeaveCC, eq);
|
||||
__ cmp(ip, r5);
|
||||
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex, eq);
|
||||
__ Push(ip);
|
||||
__ add(r4, r4, Operand(1));
|
||||
__ add(r6, r6, Operand(1));
|
||||
__ b(&loop);
|
||||
__ bind(&done);
|
||||
__ Move(r0, r4);
|
||||
__ add(r0, r0, r6);
|
||||
}
|
||||
|
||||
// Dispatch to Call or Construct depending on whether new.target is undefined.
|
||||
{
|
||||
__ CompareRoot(r3, Heap::kUndefinedValueRootIndex);
|
||||
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET, eq);
|
||||
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
|
||||
}
|
||||
// Tail-call to the actual Call or Construct builtin.
|
||||
__ Jump(code, RelocInfo::CODE_TARGET);
|
||||
}
|
||||
|
||||
// static
|
||||
void Builtins::Generate_ForwardVarargs(MacroAssembler* masm,
|
||||
Handle<Code> code) {
|
||||
void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
|
||||
Handle<Code> code) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- r0 : the number of arguments (not including the receiver)
|
||||
// -- r3 : the new.target (for [[Construct]] calls)
|
||||
|
@ -1880,16 +1880,16 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
|
||||
ASM_LOCATION("Builtins::Generate_FunctionPrototypeApply");
|
||||
|
||||
Register argc = x0;
|
||||
Register arg_array = x0;
|
||||
Register arg_array = x2;
|
||||
Register receiver = x1;
|
||||
Register this_arg = x2;
|
||||
Register this_arg = x0;
|
||||
Register undefined_value = x3;
|
||||
Register null_value = x4;
|
||||
|
||||
__ LoadRoot(undefined_value, Heap::kUndefinedValueRootIndex);
|
||||
__ LoadRoot(null_value, Heap::kNullValueRootIndex);
|
||||
|
||||
// 1. Load receiver into x1, argArray into x0 (if present), remove all
|
||||
// 1. Load receiver into x1, argArray into x2 (if present), remove all
|
||||
// arguments from the stack (including the receiver), and push thisArg (if
|
||||
// present) instead.
|
||||
{
|
||||
@ -1914,9 +1914,8 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- x0 : argArray
|
||||
// -- x2 : argArray
|
||||
// -- x1 : receiver
|
||||
// -- x3 : undefined root value
|
||||
// -- jssp[0] : thisArg
|
||||
// -----------------------------------
|
||||
|
||||
@ -1934,10 +1933,9 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
|
||||
__ Ccmp(arg_array, undefined_value, ZFlag, ne);
|
||||
__ B(eq, &no_arguments);
|
||||
|
||||
// 4a. Apply the receiver to the given argArray (passing undefined for
|
||||
// new.target in x3).
|
||||
DCHECK(undefined_value.Is(x3));
|
||||
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
|
||||
// 4a. Apply the receiver to the given argArray.
|
||||
__ Jump(masm->isolate()->builtins()->CallWithArrayLike(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
||||
// 4b. The argArray is either null or undefined, so we tail call without any
|
||||
// arguments to the receiver.
|
||||
@ -2013,14 +2011,14 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
|
||||
ASM_LOCATION("Builtins::Generate_ReflectApply");
|
||||
|
||||
Register argc = x0;
|
||||
Register arguments_list = x0;
|
||||
Register arguments_list = x2;
|
||||
Register target = x1;
|
||||
Register this_argument = x2;
|
||||
Register this_argument = x4;
|
||||
Register undefined_value = x3;
|
||||
|
||||
__ LoadRoot(undefined_value, Heap::kUndefinedValueRootIndex);
|
||||
|
||||
// 1. Load target into x1 (if present), argumentsList into x0 (if present),
|
||||
// 1. Load target into x1 (if present), argumentsList into x2 (if present),
|
||||
// remove all arguments from the stack (including the receiver), and push
|
||||
// thisArgument (if present) instead.
|
||||
{
|
||||
@ -2047,7 +2045,7 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- x0 : argumentsList
|
||||
// -- x2 : argumentsList
|
||||
// -- x1 : target
|
||||
// -- jssp[0] : thisArgument
|
||||
// -----------------------------------
|
||||
@ -2059,10 +2057,9 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
|
||||
__ Ldr(x10, FieldMemOperand(x10, Map::kBitFieldOffset));
|
||||
__ TestAndBranchIfAllClear(x10, 1 << Map::kIsCallable, &target_not_callable);
|
||||
|
||||
// 3a. Apply the target to the given argumentsList (passing undefined for
|
||||
// new.target in x3).
|
||||
DCHECK(undefined_value.Is(x3));
|
||||
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
|
||||
// 3a. Apply the target to the given argumentsList.
|
||||
__ Jump(masm->isolate()->builtins()->CallWithArrayLike(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
||||
// 3b. The target is not callable, throw an appropriate TypeError.
|
||||
__ Bind(&target_not_callable);
|
||||
@ -2083,14 +2080,14 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
|
||||
ASM_LOCATION("Builtins::Generate_ReflectConstruct");
|
||||
|
||||
Register argc = x0;
|
||||
Register arguments_list = x0;
|
||||
Register arguments_list = x2;
|
||||
Register target = x1;
|
||||
Register new_target = x3;
|
||||
Register undefined_value = x4;
|
||||
|
||||
__ LoadRoot(undefined_value, Heap::kUndefinedValueRootIndex);
|
||||
|
||||
// 1. Load target into x1 (if present), argumentsList into x0 (if present),
|
||||
// 1. Load target into x1 (if present), argumentsList into x2 (if present),
|
||||
// new.target into x3 (if present, otherwise use target), remove all
|
||||
// arguments from the stack (including the receiver), and push thisArgument
|
||||
// (if present) instead.
|
||||
@ -2118,7 +2115,7 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- x0 : argumentsList
|
||||
// -- x2 : argumentsList
|
||||
// -- x1 : target
|
||||
// -- x3 : new.target
|
||||
// -- jssp[0] : receiver (undefined)
|
||||
@ -2141,7 +2138,8 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
|
||||
&new_target_not_constructor);
|
||||
|
||||
// 4a. Construct the target with the given new.target and argumentsList.
|
||||
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
|
||||
__ Jump(masm->isolate()->builtins()->ConstructWithArrayLike(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
||||
// 4b. The target is not a constructor, throw an appropriate TypeError.
|
||||
__ Bind(&target_not_constructor);
|
||||
@ -2182,113 +2180,20 @@ static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
// static
|
||||
void Builtins::Generate_Apply(MacroAssembler* masm) {
|
||||
void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm,
|
||||
Handle<Code> code) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- x0 : argumentsList
|
||||
// -- x1 : target
|
||||
// -- x3 : new.target (checked to be constructor or undefined)
|
||||
// -- jssp[0] : thisArgument
|
||||
// -- x1 : target
|
||||
// -- x0 : number of parameters on the stack (not including the receiver)
|
||||
// -- x2 : arguments list (a FixedArray)
|
||||
// -- x4 : len (number of elements to push from args)
|
||||
// -- x3 : new.target (for [[Construct]])
|
||||
// -----------------------------------
|
||||
__ AssertFixedArray(x2);
|
||||
|
||||
Register arguments_list = x0;
|
||||
Register target = x1;
|
||||
Register new_target = x3;
|
||||
|
||||
Register args = x0;
|
||||
Register len = x2;
|
||||
|
||||
// Create the list of arguments from the array-like argumentsList.
|
||||
{
|
||||
Label create_arguments, create_array, create_holey_array, create_runtime,
|
||||
done_create;
|
||||
__ JumpIfSmi(arguments_list, &create_runtime);
|
||||
|
||||
// Load native context.
|
||||
Register native_context = x4;
|
||||
__ Ldr(native_context, NativeContextMemOperand());
|
||||
|
||||
// Load the map of argumentsList.
|
||||
Register arguments_list_map = x2;
|
||||
__ Ldr(arguments_list_map,
|
||||
FieldMemOperand(arguments_list, HeapObject::kMapOffset));
|
||||
|
||||
// Check if argumentsList is an (unmodified) arguments object.
|
||||
__ Ldr(x10, ContextMemOperand(native_context,
|
||||
Context::SLOPPY_ARGUMENTS_MAP_INDEX));
|
||||
__ Ldr(x11, ContextMemOperand(native_context,
|
||||
Context::STRICT_ARGUMENTS_MAP_INDEX));
|
||||
__ Cmp(arguments_list_map, x10);
|
||||
__ Ccmp(arguments_list_map, x11, ZFlag, ne);
|
||||
__ B(eq, &create_arguments);
|
||||
|
||||
// Check if argumentsList is a fast JSArray.
|
||||
__ CompareInstanceType(arguments_list_map, x10, JS_ARRAY_TYPE);
|
||||
__ B(eq, &create_array);
|
||||
|
||||
// Ask the runtime to create the list (actually a FixedArray).
|
||||
__ Bind(&create_runtime);
|
||||
{
|
||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||
__ Push(target, new_target, arguments_list);
|
||||
__ CallRuntime(Runtime::kCreateListFromArrayLike);
|
||||
__ Pop(new_target, target);
|
||||
__ Ldrsw(len, UntagSmiFieldMemOperand(arguments_list,
|
||||
FixedArray::kLengthOffset));
|
||||
}
|
||||
__ B(&done_create);
|
||||
|
||||
// Try to create the list from an arguments object.
|
||||
__ Bind(&create_arguments);
|
||||
__ Ldrsw(len, UntagSmiFieldMemOperand(arguments_list,
|
||||
JSArgumentsObject::kLengthOffset));
|
||||
__ Ldr(x10, FieldMemOperand(arguments_list, JSObject::kElementsOffset));
|
||||
__ Ldrsw(x11, UntagSmiFieldMemOperand(x10, FixedArray::kLengthOffset));
|
||||
__ CompareAndBranch(len, x11, ne, &create_runtime);
|
||||
__ Mov(args, x10);
|
||||
__ B(&done_create);
|
||||
|
||||
// For holey JSArrays we need to check that the array prototype chain
|
||||
// protector is intact and our prototype is the Array.prototype actually.
|
||||
__ Bind(&create_holey_array);
|
||||
// -- x2 : arguments_list_map
|
||||
// -- x4 : native_context
|
||||
Register arguments_list_prototype = x2;
|
||||
__ Ldr(arguments_list_prototype,
|
||||
FieldMemOperand(arguments_list_map, Map::kPrototypeOffset));
|
||||
__ Ldr(x10, ContextMemOperand(native_context,
|
||||
Context::INITIAL_ARRAY_PROTOTYPE_INDEX));
|
||||
__ Cmp(arguments_list_prototype, x10);
|
||||
__ B(ne, &create_runtime);
|
||||
__ LoadRoot(x10, Heap::kArrayProtectorRootIndex);
|
||||
__ Ldrsw(x11, UntagSmiFieldMemOperand(x10, PropertyCell::kValueOffset));
|
||||
__ Cmp(x11, Isolate::kProtectorValid);
|
||||
__ B(ne, &create_runtime);
|
||||
__ Ldrsw(len,
|
||||
UntagSmiFieldMemOperand(arguments_list, JSArray::kLengthOffset));
|
||||
__ Ldr(args, FieldMemOperand(arguments_list, JSArray::kElementsOffset));
|
||||
__ B(&done_create);
|
||||
|
||||
// Try to create the list from a JSArray object.
|
||||
__ Bind(&create_array);
|
||||
__ Ldr(x10, FieldMemOperand(arguments_list_map, Map::kBitField2Offset));
|
||||
__ DecodeField<Map::ElementsKindBits>(x10);
|
||||
STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
|
||||
STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
|
||||
STATIC_ASSERT(FAST_ELEMENTS == 2);
|
||||
STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
|
||||
// Check if it is a holey array, the order of the cmp is important as
|
||||
// anything higher than FAST_HOLEY_ELEMENTS will fall back to runtime.
|
||||
__ Cmp(x10, FAST_HOLEY_ELEMENTS);
|
||||
__ B(hi, &create_runtime);
|
||||
// Only FAST_XXX after this point, FAST_HOLEY_XXX are odd values.
|
||||
__ Tbnz(x10, 0, &create_holey_array);
|
||||
// FAST_SMI_ELEMENTS or FAST_ELEMENTS after this point.
|
||||
__ Ldrsw(len,
|
||||
UntagSmiFieldMemOperand(arguments_list, JSArray::kLengthOffset));
|
||||
__ Ldr(args, FieldMemOperand(arguments_list, JSArray::kElementsOffset));
|
||||
|
||||
__ Bind(&done_create);
|
||||
}
|
||||
Register arguments_list = x2;
|
||||
Register argc = x0;
|
||||
Register len = x4;
|
||||
|
||||
// Check for stack overflow.
|
||||
{
|
||||
@ -2306,21 +2211,13 @@ void Builtins::Generate_Apply(MacroAssembler* masm) {
|
||||
__ Bind(&done);
|
||||
}
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- x0 : args (a FixedArray built from argumentsList)
|
||||
// -- x1 : target
|
||||
// -- x2 : len (number of elements to push from args)
|
||||
// -- x3 : new.target (checked to be constructor or undefined)
|
||||
// -- jssp[0] : thisArgument
|
||||
// -----------------------------------
|
||||
|
||||
// Push arguments onto the stack (thisArgument is already on the stack).
|
||||
{
|
||||
Label done, push, loop;
|
||||
Register src = x4;
|
||||
Register src = x5;
|
||||
|
||||
__ Add(src, args, FixedArray::kHeaderSize - kHeapObjectTag);
|
||||
__ Mov(x0, len); // The 'len' argument for Call() or Construct().
|
||||
__ Add(src, arguments_list, FixedArray::kHeaderSize - kHeapObjectTag);
|
||||
__ Add(argc, argc, len); // The 'len' argument for Call() or Construct().
|
||||
__ Cbz(len, &done);
|
||||
Register the_hole_value = x11;
|
||||
Register undefined_value = x12;
|
||||
@ -2339,28 +2236,13 @@ void Builtins::Generate_Apply(MacroAssembler* masm) {
|
||||
__ Bind(&done);
|
||||
}
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- x0 : argument count (len)
|
||||
// -- x1 : target
|
||||
// -- x3 : new.target (checked to be constructor or undefined)
|
||||
// -- jssp[0] : args[len-1]
|
||||
// -- jssp[8] : args[len-2]
|
||||
// ... : ...
|
||||
// -- jssp[8*(len-2)] : args[1]
|
||||
// -- jssp[8*(len-1)] : args[0]
|
||||
// -----------------------------------
|
||||
|
||||
// Dispatch to Call or Construct depending on whether new.target is undefined.
|
||||
{
|
||||
__ CompareRoot(new_target, Heap::kUndefinedValueRootIndex);
|
||||
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET, eq);
|
||||
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
|
||||
}
|
||||
// Tail-call to the actual Call or Construct builtin.
|
||||
__ Jump(code, RelocInfo::CODE_TARGET);
|
||||
}
|
||||
|
||||
// static
|
||||
void Builtins::Generate_ForwardVarargs(MacroAssembler* masm,
|
||||
Handle<Code> code) {
|
||||
void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
|
||||
Handle<Code> code) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- x0 : the number of arguments (not including the receiver)
|
||||
// -- x3 : the new.target (for [[Construct]] calls)
|
||||
|
@ -2,6 +2,9 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/builtins/builtins-call-gen.h"
|
||||
|
||||
#include "src/builtins/builtins-utils-gen.h"
|
||||
#include "src/builtins/builtins.h"
|
||||
#include "src/globals.h"
|
||||
#include "src/isolate.h"
|
||||
@ -82,12 +85,132 @@ void Builtins::Generate_TailCall_ReceiverIsAny(MacroAssembler* masm) {
|
||||
Generate_Call(masm, ConvertReceiverMode::kAny, TailCallMode::kAllow);
|
||||
}
|
||||
|
||||
void Builtins::Generate_CallVarargs(MacroAssembler* masm) {
|
||||
Generate_CallOrConstructVarargs(masm, masm->isolate()->builtins()->Call());
|
||||
}
|
||||
|
||||
void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm) {
|
||||
Generate_ForwardVarargs(masm, masm->isolate()->builtins()->Call());
|
||||
Generate_CallOrConstructForwardVarargs(masm,
|
||||
masm->isolate()->builtins()->Call());
|
||||
}
|
||||
|
||||
void Builtins::Generate_CallFunctionForwardVarargs(MacroAssembler* masm) {
|
||||
Generate_ForwardVarargs(masm, masm->isolate()->builtins()->CallFunction());
|
||||
Generate_CallOrConstructForwardVarargs(
|
||||
masm, masm->isolate()->builtins()->CallFunction());
|
||||
}
|
||||
|
||||
void CallOrConstructBuiltinsAssembler::CallOrConstructWithArrayLike(
|
||||
Node* target, Node* new_target, Node* arguments_list, Node* context) {
|
||||
Variable var_elements(this, MachineRepresentation::kTagged);
|
||||
Variable var_length(this, MachineRepresentation::kWord32);
|
||||
Label if_done(this), if_arguments(this), if_array(this),
|
||||
if_holey_array(this, Label::kDeferred),
|
||||
if_runtime(this, Label::kDeferred);
|
||||
|
||||
GotoIf(TaggedIsSmi(arguments_list), &if_runtime);
|
||||
Node* arguments_list_map = LoadMap(arguments_list);
|
||||
Node* native_context = LoadNativeContext(context);
|
||||
|
||||
// Check if {arguments_list} is an (unmodified) arguments object.
|
||||
Node* sloppy_arguments_map =
|
||||
LoadContextElement(native_context, Context::SLOPPY_ARGUMENTS_MAP_INDEX);
|
||||
GotoIf(WordEqual(arguments_list_map, sloppy_arguments_map), &if_arguments);
|
||||
Node* strict_arguments_map =
|
||||
LoadContextElement(native_context, Context::STRICT_ARGUMENTS_MAP_INDEX);
|
||||
GotoIf(WordEqual(arguments_list_map, strict_arguments_map), &if_arguments);
|
||||
|
||||
// Check if {arguments_list} is a fast JSArray.
|
||||
Branch(IsJSArrayMap(arguments_list_map), &if_array, &if_runtime);
|
||||
|
||||
BIND(&if_array);
|
||||
{
|
||||
// Try to extract the elements from a JSArray object.
|
||||
var_elements.Bind(
|
||||
LoadObjectField(arguments_list, JSArray::kElementsOffset));
|
||||
var_length.Bind(LoadAndUntagToWord32ObjectField(arguments_list,
|
||||
JSArray::kLengthOffset));
|
||||
|
||||
// Holey arrays and double backing stores need special treatment.
|
||||
Node* kind = LoadMapElementsKind(arguments_list_map);
|
||||
STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
|
||||
STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
|
||||
STATIC_ASSERT(FAST_ELEMENTS == 2);
|
||||
STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
|
||||
GotoIf(Word32Equal(kind, Int32Constant(FAST_HOLEY_SMI_ELEMENTS)),
|
||||
&if_holey_array);
|
||||
GotoIf(Word32Equal(kind, Int32Constant(FAST_HOLEY_ELEMENTS)),
|
||||
&if_holey_array);
|
||||
Branch(Uint32LessThanOrEqual(kind, Int32Constant(FAST_HOLEY_ELEMENTS)),
|
||||
&if_done, &if_runtime);
|
||||
}
|
||||
|
||||
BIND(&if_holey_array);
|
||||
{
|
||||
// For holey JSArrays we need to check that the array prototype chain
|
||||
// protector is intact and our prototype is the Array.prototype actually.
|
||||
Node* arguments_list_prototype = LoadMapPrototype(arguments_list_map);
|
||||
Node* initial_array_prototype = LoadContextElement(
|
||||
native_context, Context::INITIAL_ARRAY_PROTOTYPE_INDEX);
|
||||
GotoIfNot(WordEqual(arguments_list_prototype, initial_array_prototype),
|
||||
&if_runtime);
|
||||
Node* protector_cell = LoadRoot(Heap::kArrayProtectorRootIndex);
|
||||
DCHECK(isolate()->heap()->array_protector()->IsPropertyCell());
|
||||
Branch(
|
||||
WordEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
|
||||
SmiConstant(Smi::FromInt(Isolate::kProtectorValid))),
|
||||
&if_done, &if_runtime);
|
||||
}
|
||||
|
||||
BIND(&if_arguments);
|
||||
{
|
||||
// Try to extract the elements from an JSArgumentsObject.
|
||||
Node* length =
|
||||
LoadObjectField(arguments_list, JSArgumentsObject::kLengthOffset);
|
||||
Node* elements =
|
||||
LoadObjectField(arguments_list, JSArgumentsObject::kElementsOffset);
|
||||
Node* elements_length =
|
||||
LoadObjectField(elements, FixedArray::kLengthOffset);
|
||||
GotoIfNot(WordEqual(length, elements_length), &if_runtime);
|
||||
var_elements.Bind(elements);
|
||||
var_length.Bind(SmiToWord32(length));
|
||||
Goto(&if_done);
|
||||
}
|
||||
|
||||
BIND(&if_runtime);
|
||||
{
|
||||
// Ask the runtime to create the list (actually a FixedArray).
|
||||
Node* elements =
|
||||
CallRuntime(Runtime::kCreateListFromArrayLike, context, arguments_list);
|
||||
var_elements.Bind(elements);
|
||||
var_length.Bind(
|
||||
LoadAndUntagToWord32ObjectField(elements, FixedArray::kLengthOffset));
|
||||
Goto(&if_done);
|
||||
}
|
||||
|
||||
// Tail call to the appropriate builtin (depending on whether we have
|
||||
// a {new_target} passed).
|
||||
BIND(&if_done);
|
||||
{
|
||||
Node* elements = var_elements.value();
|
||||
Node* length = var_length.value();
|
||||
if (new_target == nullptr) {
|
||||
Callable callable = CodeFactory::CallVarargs(isolate());
|
||||
TailCallStub(callable, context, target, Int32Constant(0), elements,
|
||||
length);
|
||||
} else {
|
||||
Callable callable = CodeFactory::ConstructVarargs(isolate());
|
||||
TailCallStub(callable, context, target, new_target, Int32Constant(0),
|
||||
elements, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TF_BUILTIN(CallWithArrayLike, CallOrConstructBuiltinsAssembler) {
|
||||
Node* target = Parameter(CallWithArrayLikeDescriptor::kTarget);
|
||||
Node* new_target = nullptr;
|
||||
Node* arguments_list = Parameter(CallWithArrayLikeDescriptor::kArgumentsList);
|
||||
Node* context = Parameter(CallWithArrayLikeDescriptor::kContext);
|
||||
CallOrConstructWithArrayLike(target, new_target, arguments_list, context);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
25
src/builtins/builtins-call-gen.h
Normal file
25
src/builtins/builtins-call-gen.h
Normal file
@ -0,0 +1,25 @@
|
||||
// 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_CALL_GEN_H_
|
||||
#define V8_BUILTINS_BUILTINS_CALL_GEN_H_
|
||||
|
||||
#include "src/code-stub-assembler.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class CallOrConstructBuiltinsAssembler : public CodeStubAssembler {
|
||||
public:
|
||||
explicit CallOrConstructBuiltinsAssembler(compiler::CodeAssemblerState* state)
|
||||
: CodeStubAssembler(state) {}
|
||||
|
||||
void CallOrConstructWithArrayLike(Node* target, Node* new_target,
|
||||
Node* arguments_list, Node* context);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_BUILTINS_BUILTINS_CALL_GEN_H_
|
@ -5,6 +5,7 @@
|
||||
#include "src/builtins/builtins-constructor-gen.h"
|
||||
|
||||
#include "src/ast/ast.h"
|
||||
#include "src/builtins/builtins-call-gen.h"
|
||||
#include "src/builtins/builtins-constructor.h"
|
||||
#include "src/builtins/builtins-utils-gen.h"
|
||||
#include "src/builtins/builtins.h"
|
||||
@ -17,13 +18,28 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
void Builtins::Generate_ConstructVarargs(MacroAssembler* masm) {
|
||||
Generate_CallOrConstructVarargs(masm,
|
||||
masm->isolate()->builtins()->Construct());
|
||||
}
|
||||
|
||||
void Builtins::Generate_ConstructForwardVarargs(MacroAssembler* masm) {
|
||||
Generate_ForwardVarargs(masm, masm->isolate()->builtins()->Construct());
|
||||
Generate_CallOrConstructForwardVarargs(
|
||||
masm, masm->isolate()->builtins()->Construct());
|
||||
}
|
||||
|
||||
void Builtins::Generate_ConstructFunctionForwardVarargs(MacroAssembler* masm) {
|
||||
Generate_ForwardVarargs(masm,
|
||||
masm->isolate()->builtins()->ConstructFunction());
|
||||
Generate_CallOrConstructForwardVarargs(
|
||||
masm, masm->isolate()->builtins()->ConstructFunction());
|
||||
}
|
||||
|
||||
TF_BUILTIN(ConstructWithArrayLike, CallOrConstructBuiltinsAssembler) {
|
||||
Node* target = Parameter(ConstructWithArrayLikeDescriptor::kTarget);
|
||||
Node* new_target = Parameter(ConstructWithArrayLikeDescriptor::kNewTarget);
|
||||
Node* arguments_list =
|
||||
Parameter(ConstructWithArrayLikeDescriptor::kArgumentsList);
|
||||
Node* context = Parameter(ConstructWithArrayLikeDescriptor::kContext);
|
||||
CallOrConstructWithArrayLike(target, new_target, arguments_list, context);
|
||||
}
|
||||
|
||||
typedef compiler::Node Node;
|
||||
|
@ -75,7 +75,9 @@ namespace internal {
|
||||
ASM(TailCall_ReceiverIsNullOrUndefined) \
|
||||
ASM(TailCall_ReceiverIsNotNullOrUndefined) \
|
||||
ASM(TailCall_ReceiverIsAny) \
|
||||
ASM(CallVarargs) \
|
||||
ASM(CallWithSpread) \
|
||||
TFC(CallWithArrayLike, CallWithArrayLike, 1) \
|
||||
ASM(CallForwardVarargs) \
|
||||
ASM(CallFunctionForwardVarargs) \
|
||||
\
|
||||
@ -89,7 +91,9 @@ namespace internal {
|
||||
ASM(ConstructProxy) \
|
||||
/* ES6 section 7.3.13 Construct (F, [argumentsList], [newTarget]) */ \
|
||||
ASM(Construct) \
|
||||
ASM(ConstructVarargs) \
|
||||
ASM(ConstructWithSpread) \
|
||||
TFC(ConstructWithArrayLike, ConstructWithArrayLike, 1) \
|
||||
ASM(ConstructForwardVarargs) \
|
||||
ASM(ConstructFunctionForwardVarargs) \
|
||||
ASM(JSConstructStubApi) \
|
||||
@ -108,7 +112,6 @@ namespace internal {
|
||||
TFC(FastCloneShallowObject, FastCloneShallowObject, 1) \
|
||||
\
|
||||
/* Apply and entries */ \
|
||||
ASM(Apply) \
|
||||
ASM(JSEntryTrampoline) \
|
||||
ASM(JSConstructEntryTrampoline) \
|
||||
ASM(ResumeGeneratorTrampoline) \
|
||||
|
@ -132,7 +132,10 @@ class Builtins {
|
||||
static void Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
|
||||
TailCallMode tail_call_mode);
|
||||
|
||||
static void Generate_ForwardVarargs(MacroAssembler* masm, Handle<Code> code);
|
||||
static void Generate_CallOrConstructVarargs(MacroAssembler* masm,
|
||||
Handle<Code> code);
|
||||
static void Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
|
||||
Handle<Code> code);
|
||||
|
||||
static void Generate_InterpreterPushArgsThenCallImpl(
|
||||
MacroAssembler* masm, ConvertReceiverMode receiver_mode,
|
||||
|
@ -1588,7 +1588,7 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
|
||||
// -- esp[12] : receiver
|
||||
// -----------------------------------
|
||||
|
||||
// 1. Load receiver into edi, argArray into eax (if present), remove all
|
||||
// 1. Load receiver into edi, argArray into ebx (if present), remove all
|
||||
// arguments from the stack (including the receiver), and push thisArg (if
|
||||
// present) instead.
|
||||
{
|
||||
@ -1610,11 +1610,10 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
|
||||
__ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
|
||||
__ Push(edx);
|
||||
__ PushReturnAddressFrom(ecx);
|
||||
__ Move(eax, ebx);
|
||||
}
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- eax : argArray
|
||||
// -- ebx : argArray
|
||||
// -- edi : receiver
|
||||
// -- esp[0] : return address
|
||||
// -- esp[4] : thisArg
|
||||
@ -1630,14 +1629,13 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
|
||||
|
||||
// 3. Tail call with no arguments if argArray is null or undefined.
|
||||
Label no_arguments;
|
||||
__ JumpIfRoot(eax, Heap::kNullValueRootIndex, &no_arguments, Label::kNear);
|
||||
__ JumpIfRoot(eax, Heap::kUndefinedValueRootIndex, &no_arguments,
|
||||
__ JumpIfRoot(ebx, Heap::kNullValueRootIndex, &no_arguments, Label::kNear);
|
||||
__ JumpIfRoot(ebx, Heap::kUndefinedValueRootIndex, &no_arguments,
|
||||
Label::kNear);
|
||||
|
||||
// 4a. Apply the receiver to the given argArray (passing undefined for
|
||||
// new.target).
|
||||
__ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
|
||||
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
|
||||
// 4a. Apply the receiver to the given argArray.
|
||||
__ Jump(masm->isolate()->builtins()->CallWithArrayLike(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
||||
// 4b. The argArray is either null or undefined, so we tail call without any
|
||||
// arguments to the receiver.
|
||||
@ -1711,7 +1709,7 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
|
||||
// -- esp[16] : receiver
|
||||
// -----------------------------------
|
||||
|
||||
// 1. Load target into edi (if present), argumentsList into eax (if present),
|
||||
// 1. Load target into edi (if present), argumentsList into ebx (if present),
|
||||
// remove all arguments from the stack (including the receiver), and push
|
||||
// thisArgument (if present) instead.
|
||||
{
|
||||
@ -1732,11 +1730,10 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
|
||||
__ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
|
||||
__ Push(edx);
|
||||
__ PushReturnAddressFrom(ecx);
|
||||
__ Move(eax, ebx);
|
||||
}
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- eax : argumentsList
|
||||
// -- ebx : argumentsList
|
||||
// -- edi : target
|
||||
// -- esp[0] : return address
|
||||
// -- esp[4] : thisArgument
|
||||
@ -1750,10 +1747,9 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
|
||||
Immediate(1 << Map::kIsCallable));
|
||||
__ j(zero, &target_not_callable, Label::kNear);
|
||||
|
||||
// 3a. Apply the target to the given argumentsList (passing undefined for
|
||||
// new.target).
|
||||
__ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
|
||||
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
|
||||
// 3a. Apply the target to the given argumentsList.
|
||||
__ Jump(masm->isolate()->builtins()->CallWithArrayLike(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
||||
// 3b. The target is not callable, throw an appropriate TypeError.
|
||||
__ bind(&target_not_callable);
|
||||
@ -1773,7 +1769,7 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
|
||||
// -- esp[16] : receiver
|
||||
// -----------------------------------
|
||||
|
||||
// 1. Load target into edi (if present), argumentsList into eax (if present),
|
||||
// 1. Load target into edi (if present), argumentsList into ebx (if present),
|
||||
// new.target into edx (if present, otherwise use target), remove all
|
||||
// arguments from the stack (including the receiver), and push thisArgument
|
||||
// (if present) instead.
|
||||
@ -1796,11 +1792,10 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
|
||||
__ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
|
||||
__ PushRoot(Heap::kUndefinedValueRootIndex);
|
||||
__ PushReturnAddressFrom(ecx);
|
||||
__ Move(eax, ebx);
|
||||
}
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- eax : argumentsList
|
||||
// -- ebx : argumentsList
|
||||
// -- edx : new.target
|
||||
// -- edi : target
|
||||
// -- esp[0] : return address
|
||||
@ -1824,7 +1819,8 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
|
||||
__ j(zero, &new_target_not_constructor, Label::kNear);
|
||||
|
||||
// 4a. Construct the target with the given new.target and argumentsList.
|
||||
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
|
||||
__ Jump(masm->isolate()->builtins()->ConstructWithArrayLike(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
||||
// 4b. The target is not a constructor, throw an appropriate TypeError.
|
||||
__ bind(&target_not_constructor);
|
||||
@ -2223,97 +2219,22 @@ static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
// static
|
||||
void Builtins::Generate_Apply(MacroAssembler* masm) {
|
||||
void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm,
|
||||
Handle<Code> code) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- eax : argumentsList
|
||||
// -- edi : target
|
||||
// -- eax : number of parameters on the stack (not including the receiver)
|
||||
// -- ebx : arguments list (a FixedArray)
|
||||
// -- ecx : len (number of elements to from args)
|
||||
// -- edx : new.target (checked to be constructor or undefined)
|
||||
// -- esp[0] : return address.
|
||||
// -- esp[4] : thisArgument
|
||||
// -----------------------------------
|
||||
__ AssertFixedArray(ebx);
|
||||
|
||||
// Create the list of arguments from the array-like argumentsList.
|
||||
{
|
||||
Label create_arguments, create_array, create_holey_array, create_runtime,
|
||||
done_create;
|
||||
__ JumpIfSmi(eax, &create_runtime);
|
||||
|
||||
// Load the map of argumentsList into ecx.
|
||||
__ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
|
||||
|
||||
// Load native context into ebx.
|
||||
__ mov(ebx, NativeContextOperand());
|
||||
|
||||
// Check if argumentsList is an (unmodified) arguments object.
|
||||
__ cmp(ecx, ContextOperand(ebx, Context::SLOPPY_ARGUMENTS_MAP_INDEX));
|
||||
__ j(equal, &create_arguments);
|
||||
__ cmp(ecx, ContextOperand(ebx, Context::STRICT_ARGUMENTS_MAP_INDEX));
|
||||
__ j(equal, &create_arguments);
|
||||
|
||||
// Check if argumentsList is a fast JSArray.
|
||||
__ CmpInstanceType(ecx, JS_ARRAY_TYPE);
|
||||
__ j(equal, &create_array);
|
||||
|
||||
// Ask the runtime to create the list (actually a FixedArray).
|
||||
__ bind(&create_runtime);
|
||||
{
|
||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||
__ Push(edi);
|
||||
__ Push(edx);
|
||||
__ Push(eax);
|
||||
__ CallRuntime(Runtime::kCreateListFromArrayLike);
|
||||
__ Pop(edx);
|
||||
__ Pop(edi);
|
||||
__ mov(ebx, FieldOperand(eax, FixedArray::kLengthOffset));
|
||||
__ SmiUntag(ebx);
|
||||
}
|
||||
__ jmp(&done_create);
|
||||
|
||||
// Try to create the list from an arguments object.
|
||||
__ bind(&create_arguments);
|
||||
__ mov(ebx, FieldOperand(eax, JSArgumentsObject::kLengthOffset));
|
||||
__ mov(ecx, FieldOperand(eax, JSObject::kElementsOffset));
|
||||
__ cmp(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
|
||||
__ j(not_equal, &create_runtime);
|
||||
__ SmiUntag(ebx);
|
||||
__ mov(eax, ecx);
|
||||
__ jmp(&done_create);
|
||||
|
||||
// For holey JSArrays we need to check that the array prototype chain
|
||||
// protector is intact and our prototype is the Array.prototype actually.
|
||||
__ bind(&create_holey_array);
|
||||
__ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
|
||||
__ mov(ecx, FieldOperand(ecx, Map::kPrototypeOffset));
|
||||
__ cmp(ecx, ContextOperand(ebx, Context::INITIAL_ARRAY_PROTOTYPE_INDEX));
|
||||
__ j(not_equal, &create_runtime);
|
||||
__ LoadRoot(ecx, Heap::kArrayProtectorRootIndex);
|
||||
__ cmp(FieldOperand(ecx, PropertyCell::kValueOffset),
|
||||
Immediate(Smi::FromInt(Isolate::kProtectorValid)));
|
||||
__ j(not_equal, &create_runtime);
|
||||
__ mov(ebx, FieldOperand(eax, JSArray::kLengthOffset));
|
||||
__ SmiUntag(ebx);
|
||||
__ mov(eax, FieldOperand(eax, JSArray::kElementsOffset));
|
||||
__ jmp(&done_create);
|
||||
|
||||
// Try to create the list from a JSArray object.
|
||||
__ bind(&create_array);
|
||||
__ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
|
||||
__ DecodeField<Map::ElementsKindBits>(ecx);
|
||||
STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
|
||||
STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
|
||||
STATIC_ASSERT(FAST_ELEMENTS == 2);
|
||||
STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
|
||||
__ cmp(ecx, Immediate(FAST_HOLEY_SMI_ELEMENTS));
|
||||
__ j(equal, &create_holey_array, Label::kNear);
|
||||
__ cmp(ecx, Immediate(FAST_HOLEY_ELEMENTS));
|
||||
__ j(equal, &create_holey_array, Label::kNear);
|
||||
__ j(above, &create_runtime);
|
||||
__ mov(ebx, FieldOperand(eax, JSArray::kLengthOffset));
|
||||
__ SmiUntag(ebx);
|
||||
__ mov(eax, FieldOperand(eax, JSArray::kElementsOffset));
|
||||
|
||||
__ bind(&done_create);
|
||||
}
|
||||
// We need to preserve eax, edi and ebx.
|
||||
__ movd(xmm0, edx);
|
||||
__ movd(xmm1, edi);
|
||||
__ movd(xmm2, eax);
|
||||
|
||||
// Check for stack overflow.
|
||||
{
|
||||
@ -2322,66 +2243,56 @@ void Builtins::Generate_Apply(MacroAssembler* masm) {
|
||||
Label done;
|
||||
ExternalReference real_stack_limit =
|
||||
ExternalReference::address_of_real_stack_limit(masm->isolate());
|
||||
__ mov(ecx, Operand::StaticVariable(real_stack_limit));
|
||||
// Make ecx the space we have left. The stack might already be overflowed
|
||||
// here which will cause ecx to become negative.
|
||||
__ neg(ecx);
|
||||
__ add(ecx, esp);
|
||||
__ sar(ecx, kPointerSizeLog2);
|
||||
__ mov(edx, Operand::StaticVariable(real_stack_limit));
|
||||
// Make edx the space we have left. The stack might already be overflowed
|
||||
// here which will cause edx to become negative.
|
||||
__ neg(edx);
|
||||
__ add(edx, esp);
|
||||
__ sar(edx, kPointerSizeLog2);
|
||||
// Check if the arguments will overflow the stack.
|
||||
__ cmp(ecx, ebx);
|
||||
__ cmp(edx, ecx);
|
||||
__ j(greater, &done, Label::kNear); // Signed comparison.
|
||||
__ TailCallRuntime(Runtime::kThrowStackOverflow);
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- edi : target
|
||||
// -- eax : args (a FixedArray built from argumentsList)
|
||||
// -- ebx : len (number of elements to push from args)
|
||||
// -- edx : new.target (checked to be constructor or undefined)
|
||||
// -- esp[0] : return address.
|
||||
// -- esp[4] : thisArgument
|
||||
// -----------------------------------
|
||||
|
||||
// Push arguments onto the stack (thisArgument is already on the stack).
|
||||
// Push additional arguments onto the stack.
|
||||
{
|
||||
__ movd(xmm0, edx);
|
||||
__ movd(xmm1, edi);
|
||||
__ PopReturnAddressTo(edx);
|
||||
__ Move(ecx, Immediate(0));
|
||||
__ Move(eax, Immediate(0));
|
||||
Label done, push, loop;
|
||||
__ bind(&loop);
|
||||
__ cmp(ecx, ebx);
|
||||
__ cmp(eax, ecx);
|
||||
__ j(equal, &done, Label::kNear);
|
||||
// Turn the hole into undefined as we go.
|
||||
__ mov(edi,
|
||||
FieldOperand(eax, ecx, times_pointer_size, FixedArray::kHeaderSize));
|
||||
FieldOperand(ebx, eax, times_pointer_size, FixedArray::kHeaderSize));
|
||||
__ CompareRoot(edi, Heap::kTheHoleValueRootIndex);
|
||||
__ j(not_equal, &push, Label::kNear);
|
||||
__ LoadRoot(edi, Heap::kUndefinedValueRootIndex);
|
||||
__ bind(&push);
|
||||
__ Push(edi);
|
||||
__ inc(ecx);
|
||||
__ inc(eax);
|
||||
__ jmp(&loop);
|
||||
__ bind(&done);
|
||||
__ PushReturnAddressFrom(edx);
|
||||
__ movd(edi, xmm1);
|
||||
__ movd(edx, xmm0);
|
||||
__ Move(eax, ebx);
|
||||
}
|
||||
|
||||
// Dispatch to Call or Construct depending on whether new.target is undefined.
|
||||
{
|
||||
__ CompareRoot(edx, Heap::kUndefinedValueRootIndex);
|
||||
__ j(equal, masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
||||
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
|
||||
}
|
||||
// Restore eax, edi and edx.
|
||||
__ movd(eax, xmm2);
|
||||
__ movd(edi, xmm1);
|
||||
__ movd(edx, xmm0);
|
||||
|
||||
// Compute the actual parameter count.
|
||||
__ add(eax, ecx);
|
||||
|
||||
// Tail-call to the actual Call or Construct builtin.
|
||||
__ Jump(code, RelocInfo::CODE_TARGET);
|
||||
}
|
||||
|
||||
// static
|
||||
void Builtins::Generate_ForwardVarargs(MacroAssembler* masm,
|
||||
Handle<Code> code) {
|
||||
void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
|
||||
Handle<Code> code) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- eax : the number of arguments (not including the receiver)
|
||||
// -- edi : the target to call (can be any Object)
|
||||
|
@ -1840,11 +1840,11 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
|
||||
__ bind(&no_arg);
|
||||
__ Addu(sp, sp, Operand(scratch));
|
||||
__ sw(a2, MemOperand(sp));
|
||||
__ mov(a0, a3);
|
||||
__ mov(a2, a3);
|
||||
}
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- a0 : argArray
|
||||
// -- a2 : argArray
|
||||
// -- a1 : receiver
|
||||
// -- sp[0] : thisArg
|
||||
// -----------------------------------
|
||||
@ -1859,13 +1859,12 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
|
||||
|
||||
// 3. Tail call with no arguments if argArray is null or undefined.
|
||||
Label no_arguments;
|
||||
__ JumpIfRoot(a0, Heap::kNullValueRootIndex, &no_arguments);
|
||||
__ JumpIfRoot(a0, Heap::kUndefinedValueRootIndex, &no_arguments);
|
||||
__ JumpIfRoot(a2, Heap::kNullValueRootIndex, &no_arguments);
|
||||
__ JumpIfRoot(a2, Heap::kUndefinedValueRootIndex, &no_arguments);
|
||||
|
||||
// 4a. Apply the receiver to the given argArray (passing undefined for
|
||||
// new.target).
|
||||
__ LoadRoot(a3, Heap::kUndefinedValueRootIndex);
|
||||
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
|
||||
// 4a. Apply the receiver to the given argArray.
|
||||
__ Jump(masm->isolate()->builtins()->CallWithArrayLike(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
||||
// 4b. The argArray is either null or undefined, so we tail call without any
|
||||
// arguments to the receiver.
|
||||
@ -1958,11 +1957,11 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
|
||||
__ bind(&no_arg);
|
||||
__ Addu(sp, sp, Operand(scratch));
|
||||
__ sw(a2, MemOperand(sp));
|
||||
__ mov(a0, a3);
|
||||
__ mov(a2, a3);
|
||||
}
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- a0 : argumentsList
|
||||
// -- a2 : argumentsList
|
||||
// -- a1 : target
|
||||
// -- sp[0] : thisArgument
|
||||
// -----------------------------------
|
||||
@ -1975,10 +1974,9 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
|
||||
__ And(t0, t0, Operand(1 << Map::kIsCallable));
|
||||
__ Branch(&target_not_callable, eq, t0, Operand(zero_reg));
|
||||
|
||||
// 3a. Apply the target to the given argumentsList (passing undefined for
|
||||
// new.target).
|
||||
__ LoadRoot(a3, Heap::kUndefinedValueRootIndex);
|
||||
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
|
||||
// 3a. Apply the target to the given argumentsList.
|
||||
__ Jump(masm->isolate()->builtins()->CallWithArrayLike(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
||||
// 3b. The target is not callable, throw an appropriate TypeError.
|
||||
__ bind(&target_not_callable);
|
||||
@ -2022,11 +2020,10 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
|
||||
__ lw(a3, MemOperand(a0)); // new.target
|
||||
__ bind(&no_arg);
|
||||
__ Addu(sp, sp, Operand(scratch));
|
||||
__ mov(a0, a2);
|
||||
}
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- a0 : argumentsList
|
||||
// -- a2 : argumentsList
|
||||
// -- a3 : new.target
|
||||
// -- a1 : target
|
||||
// -- sp[0] : receiver (undefined)
|
||||
@ -2049,7 +2046,8 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
|
||||
__ Branch(&new_target_not_constructor, eq, t0, Operand(zero_reg));
|
||||
|
||||
// 4a. Construct the target with the given new.target and argumentsList.
|
||||
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
|
||||
__ Jump(masm->isolate()->builtins()->ConstructWithArrayLike(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
||||
// 4b. The target is not a constructor, throw an appropriate TypeError.
|
||||
__ bind(&target_not_constructor);
|
||||
@ -2090,149 +2088,59 @@ static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
// static
|
||||
void Builtins::Generate_Apply(MacroAssembler* masm) {
|
||||
void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm,
|
||||
Handle<Code> code) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- a0 : argumentsList
|
||||
// -- a1 : target
|
||||
// -- a3 : new.target (checked to be constructor or undefined)
|
||||
// -- sp[0] : thisArgument
|
||||
// -- a1 : target
|
||||
// -- a0 : number of parameters on the stack (not including the receiver)
|
||||
// -- a2 : arguments list (a FixedArray)
|
||||
// -- t0 : len (number of elements to push from args)
|
||||
// -- a3 : new.target (for [[Construct]])
|
||||
// -----------------------------------
|
||||
|
||||
// Create the list of arguments from the array-like argumentsList.
|
||||
{
|
||||
Label create_arguments, create_array, create_holey_array, create_runtime,
|
||||
done_create;
|
||||
__ JumpIfSmi(a0, &create_runtime);
|
||||
|
||||
// Load the map of argumentsList into a2.
|
||||
__ lw(a2, FieldMemOperand(a0, HeapObject::kMapOffset));
|
||||
|
||||
// Load native context into t0.
|
||||
__ lw(t0, NativeContextMemOperand());
|
||||
|
||||
// Check if argumentsList is an (unmodified) arguments object.
|
||||
__ lw(at, ContextMemOperand(t0, Context::SLOPPY_ARGUMENTS_MAP_INDEX));
|
||||
__ Branch(&create_arguments, eq, a2, Operand(at));
|
||||
__ lw(at, ContextMemOperand(t0, Context::STRICT_ARGUMENTS_MAP_INDEX));
|
||||
__ Branch(&create_arguments, eq, a2, Operand(at));
|
||||
|
||||
// Check if argumentsList is a fast JSArray.
|
||||
__ lbu(v0, FieldMemOperand(a2, Map::kInstanceTypeOffset));
|
||||
__ Branch(&create_array, eq, v0, Operand(JS_ARRAY_TYPE));
|
||||
|
||||
// Ask the runtime to create the list (actually a FixedArray).
|
||||
__ bind(&create_runtime);
|
||||
{
|
||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||
__ Push(a1, a3, a0);
|
||||
__ CallRuntime(Runtime::kCreateListFromArrayLike);
|
||||
__ mov(a0, v0);
|
||||
__ Pop(a1, a3);
|
||||
__ lw(a2, FieldMemOperand(v0, FixedArray::kLengthOffset));
|
||||
__ SmiUntag(a2);
|
||||
}
|
||||
__ Branch(&done_create);
|
||||
|
||||
// Try to create the list from an arguments object.
|
||||
__ bind(&create_arguments);
|
||||
__ lw(a2, FieldMemOperand(a0, JSArgumentsObject::kLengthOffset));
|
||||
__ lw(t0, FieldMemOperand(a0, JSObject::kElementsOffset));
|
||||
__ lw(at, FieldMemOperand(t0, FixedArray::kLengthOffset));
|
||||
__ Branch(&create_runtime, ne, a2, Operand(at));
|
||||
__ SmiUntag(a2);
|
||||
__ mov(a0, t0);
|
||||
__ Branch(&done_create);
|
||||
|
||||
// For holey JSArrays we need to check that the array prototype chain
|
||||
// protector is intact and our prototype is the Array.prototype actually.
|
||||
__ bind(&create_holey_array);
|
||||
__ lw(a2, FieldMemOperand(a2, Map::kPrototypeOffset));
|
||||
__ lw(at, ContextMemOperand(t0, Context::INITIAL_ARRAY_PROTOTYPE_INDEX));
|
||||
__ Branch(&create_runtime, ne, a2, Operand(at));
|
||||
__ LoadRoot(at, Heap::kArrayProtectorRootIndex);
|
||||
__ lw(a2, FieldMemOperand(at, PropertyCell::kValueOffset));
|
||||
__ Branch(&create_runtime, ne, a2,
|
||||
Operand(Smi::FromInt(Isolate::kProtectorValid)));
|
||||
__ lw(a2, FieldMemOperand(a0, JSArray::kLengthOffset));
|
||||
__ lw(a0, FieldMemOperand(a0, JSArray::kElementsOffset));
|
||||
__ SmiUntag(a2);
|
||||
__ Branch(&done_create);
|
||||
|
||||
// Try to create the list from a JSArray object.
|
||||
__ bind(&create_array);
|
||||
__ lbu(t1, FieldMemOperand(a2, Map::kBitField2Offset));
|
||||
__ DecodeField<Map::ElementsKindBits>(t1);
|
||||
STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
|
||||
STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
|
||||
STATIC_ASSERT(FAST_ELEMENTS == 2);
|
||||
STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
|
||||
__ Branch(&create_holey_array, eq, t1, Operand(FAST_HOLEY_SMI_ELEMENTS));
|
||||
__ Branch(&create_holey_array, eq, t1, Operand(FAST_HOLEY_ELEMENTS));
|
||||
__ Branch(&create_runtime, hi, t1, Operand(FAST_ELEMENTS));
|
||||
__ lw(a2, FieldMemOperand(a0, JSArray::kLengthOffset));
|
||||
__ lw(a0, FieldMemOperand(a0, JSArray::kElementsOffset));
|
||||
__ SmiUntag(a2);
|
||||
|
||||
__ bind(&done_create);
|
||||
}
|
||||
__ AssertFixedArray(a2);
|
||||
|
||||
// Check for stack overflow.
|
||||
{
|
||||
// Check the stack for overflow. We are not trying to catch interruptions
|
||||
// (i.e. debug break and preemption) here, so check the "real stack limit".
|
||||
Label done;
|
||||
__ LoadRoot(t0, Heap::kRealStackLimitRootIndex);
|
||||
__ LoadRoot(t1, Heap::kRealStackLimitRootIndex);
|
||||
// Make ip the space we have left. The stack might already be overflowed
|
||||
// here which will cause ip to become negative.
|
||||
__ Subu(t0, sp, t0);
|
||||
__ Subu(t1, sp, t1);
|
||||
// Check if the arguments will overflow the stack.
|
||||
__ sll(at, a2, kPointerSizeLog2);
|
||||
__ Branch(&done, gt, t0, Operand(at)); // Signed comparison.
|
||||
__ sll(at, t0, kPointerSizeLog2);
|
||||
__ Branch(&done, gt, t1, Operand(at)); // Signed comparison.
|
||||
__ TailCallRuntime(Runtime::kThrowStackOverflow);
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- a1 : target
|
||||
// -- a0 : args (a FixedArray built from argumentsList)
|
||||
// -- a2 : len (number of elements to push from args)
|
||||
// -- a3 : new.target (checked to be constructor or undefined)
|
||||
// -- sp[0] : thisArgument
|
||||
// -----------------------------------
|
||||
|
||||
// Push arguments onto the stack (thisArgument is already on the stack).
|
||||
{
|
||||
__ mov(t0, zero_reg);
|
||||
__ mov(t2, zero_reg);
|
||||
Label done, push, loop;
|
||||
__ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
|
||||
__ bind(&loop);
|
||||
__ Branch(&done, eq, t0, Operand(a2));
|
||||
__ Lsa(at, a0, t0, kPointerSizeLog2);
|
||||
__ Branch(&done, eq, t2, Operand(t0));
|
||||
__ Lsa(at, a2, t2, kPointerSizeLog2);
|
||||
__ lw(at, FieldMemOperand(at, FixedArray::kHeaderSize));
|
||||
__ Branch(&push, ne, t1, Operand(at));
|
||||
__ LoadRoot(at, Heap::kUndefinedValueRootIndex);
|
||||
__ bind(&push);
|
||||
__ Push(at);
|
||||
__ Addu(t0, t0, Operand(1));
|
||||
__ Addu(t2, t2, Operand(1));
|
||||
__ Branch(&loop);
|
||||
__ bind(&done);
|
||||
__ Move(a0, t0);
|
||||
__ Addu(a0, a0, t2);
|
||||
}
|
||||
|
||||
// Dispatch to Call or Construct depending on whether new.target is undefined.
|
||||
{
|
||||
Label construct;
|
||||
__ LoadRoot(at, Heap::kUndefinedValueRootIndex);
|
||||
__ Branch(&construct, ne, a3, Operand(at));
|
||||
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
||||
__ bind(&construct);
|
||||
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
|
||||
}
|
||||
// Tail-call to the actual Call or Construct builtin.
|
||||
__ Jump(code, RelocInfo::CODE_TARGET);
|
||||
}
|
||||
|
||||
// static
|
||||
void Builtins::Generate_ForwardVarargs(MacroAssembler* masm,
|
||||
Handle<Code> code) {
|
||||
void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
|
||||
Handle<Code> code) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- a0 : the number of arguments (not including the receiver)
|
||||
// -- a3 : the new.target (for [[Construct]] calls)
|
||||
|
@ -1823,14 +1823,14 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
|
||||
// -----------------------------------
|
||||
|
||||
Register argc = a0;
|
||||
Register arg_array = a0;
|
||||
Register arg_array = a2;
|
||||
Register receiver = a1;
|
||||
Register this_arg = a2;
|
||||
Register this_arg = a5;
|
||||
Register undefined_value = a3;
|
||||
Register scratch = a4;
|
||||
|
||||
__ LoadRoot(undefined_value, Heap::kUndefinedValueRootIndex);
|
||||
// 1. Load receiver into a1, argArray into a0 (if present), remove all
|
||||
// 1. Load receiver into a1, argArray into a2 (if present), remove all
|
||||
// arguments from the stack (including the receiver), and push thisArg (if
|
||||
// present) instead.
|
||||
{
|
||||
@ -1850,7 +1850,7 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- a0 : argArray
|
||||
// -- a2 : argArray
|
||||
// -- a1 : receiver
|
||||
// -- a3 : undefined root value
|
||||
// -- sp[0] : thisArg
|
||||
@ -1869,10 +1869,9 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
|
||||
__ JumpIfRoot(arg_array, Heap::kNullValueRootIndex, &no_arguments);
|
||||
__ Branch(&no_arguments, eq, arg_array, Operand(undefined_value));
|
||||
|
||||
// 4a. Apply the receiver to the given argArray (passing undefined for
|
||||
// new.target).
|
||||
DCHECK(undefined_value.is(a3));
|
||||
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
|
||||
// 4a. Apply the receiver to the given argArray.
|
||||
__ Jump(masm->isolate()->builtins()->CallWithArrayLike(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
||||
// 4b. The argArray is either null or undefined, so we tail call without any
|
||||
// arguments to the receiver.
|
||||
@ -1943,14 +1942,14 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
|
||||
// -----------------------------------
|
||||
|
||||
Register argc = a0;
|
||||
Register arguments_list = a0;
|
||||
Register arguments_list = a2;
|
||||
Register target = a1;
|
||||
Register this_argument = a2;
|
||||
Register this_argument = a5;
|
||||
Register undefined_value = a3;
|
||||
Register scratch = a4;
|
||||
|
||||
__ LoadRoot(undefined_value, Heap::kUndefinedValueRootIndex);
|
||||
// 1. Load target into a1 (if present), argumentsList into a0 (if present),
|
||||
// 1. Load target into a1 (if present), argumentsList into a2 (if present),
|
||||
// remove all arguments from the stack (including the receiver), and push
|
||||
// thisArgument (if present) instead.
|
||||
{
|
||||
@ -1974,7 +1973,7 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- a0 : argumentsList
|
||||
// -- a2 : argumentsList
|
||||
// -- a1 : target
|
||||
// -- a3 : undefined root value
|
||||
// -- sp[0] : thisArgument
|
||||
@ -1988,10 +1987,9 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
|
||||
__ And(a4, a4, Operand(1 << Map::kIsCallable));
|
||||
__ Branch(&target_not_callable, eq, a4, Operand(zero_reg));
|
||||
|
||||
// 3a. Apply the target to the given argumentsList (passing undefined for
|
||||
// new.target).
|
||||
DCHECK(undefined_value.is(a3));
|
||||
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
|
||||
// 3a. Apply the target to the given argumentsList.
|
||||
__ Jump(masm->isolate()->builtins()->CallWithArrayLike(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
||||
// 3b. The target is not callable, throw an appropriate TypeError.
|
||||
__ bind(&target_not_callable);
|
||||
@ -2010,13 +2008,13 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
|
||||
// -- sp[12] : receiver
|
||||
// -----------------------------------
|
||||
Register argc = a0;
|
||||
Register arguments_list = a0;
|
||||
Register arguments_list = a2;
|
||||
Register target = a1;
|
||||
Register new_target = a3;
|
||||
Register undefined_value = a4;
|
||||
Register scratch = a5;
|
||||
|
||||
// 1. Load target into a1 (if present), argumentsList into a0 (if present),
|
||||
// 1. Load target into a1 (if present), argumentsList into a2 (if present),
|
||||
// new.target into a3 (if present, otherwise use target), remove all
|
||||
// arguments from the stack (including the receiver), and push thisArgument
|
||||
// (if present) instead.
|
||||
@ -2041,7 +2039,7 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- a0 : argumentsList
|
||||
// -- a2 : argumentsList
|
||||
// -- a1 : target
|
||||
// -- a3 : new.target
|
||||
// -- sp[0] : receiver (undefined)
|
||||
@ -2064,7 +2062,8 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
|
||||
__ Branch(&new_target_not_constructor, eq, a4, Operand(zero_reg));
|
||||
|
||||
// 4a. Construct the target with the given new.target and argumentsList.
|
||||
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
|
||||
__ Jump(masm->isolate()->builtins()->ConstructWithArrayLike(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
||||
// 4b. The target is not a constructor, throw an appropriate TypeError.
|
||||
__ bind(&target_not_constructor);
|
||||
@ -2107,135 +2106,45 @@ static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
// static
|
||||
void Builtins::Generate_Apply(MacroAssembler* masm) {
|
||||
void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm,
|
||||
Handle<Code> code) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- a0 : argumentsList
|
||||
// -- a1 : target
|
||||
// -- a3 : new.target (checked to be constructor or undefined)
|
||||
// -- sp[0] : thisArgument
|
||||
// -- a1 : target
|
||||
// -- a0 : number of parameters on the stack (not including the receiver)
|
||||
// -- a2 : arguments list (a FixedArray)
|
||||
// -- a4 : len (number of elements to push from args)
|
||||
// -- a3 : new.target (for [[Construct]])
|
||||
// -----------------------------------
|
||||
__ AssertFixedArray(a2);
|
||||
|
||||
Register arguments_list = a0;
|
||||
Register target = a1;
|
||||
Register new_target = a3;
|
||||
|
||||
Register args = a0;
|
||||
Register len = a2;
|
||||
|
||||
// Create the list of arguments from the array-like argumentsList.
|
||||
{
|
||||
Label create_arguments, create_array, create_holey_array, create_runtime,
|
||||
done_create;
|
||||
__ JumpIfSmi(arguments_list, &create_runtime);
|
||||
|
||||
// Load the map of argumentsList into a2.
|
||||
Register arguments_list_map = a2;
|
||||
__ Ld(arguments_list_map,
|
||||
FieldMemOperand(arguments_list, HeapObject::kMapOffset));
|
||||
|
||||
// Load native context into a4.
|
||||
Register native_context = a4;
|
||||
__ Ld(native_context, NativeContextMemOperand());
|
||||
|
||||
// Check if argumentsList is an (unmodified) arguments object.
|
||||
__ Ld(at, ContextMemOperand(native_context,
|
||||
Context::SLOPPY_ARGUMENTS_MAP_INDEX));
|
||||
__ Branch(&create_arguments, eq, arguments_list_map, Operand(at));
|
||||
__ Ld(at, ContextMemOperand(native_context,
|
||||
Context::STRICT_ARGUMENTS_MAP_INDEX));
|
||||
__ Branch(&create_arguments, eq, arguments_list_map, Operand(at));
|
||||
|
||||
// Check if argumentsList is a fast JSArray.
|
||||
__ Lbu(v0, FieldMemOperand(a2, Map::kInstanceTypeOffset));
|
||||
__ Branch(&create_array, eq, v0, Operand(JS_ARRAY_TYPE));
|
||||
|
||||
// Ask the runtime to create the list (actually a FixedArray).
|
||||
__ bind(&create_runtime);
|
||||
{
|
||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||
__ Push(target, new_target, arguments_list);
|
||||
__ CallRuntime(Runtime::kCreateListFromArrayLike);
|
||||
__ mov(arguments_list, v0);
|
||||
__ Pop(target, new_target);
|
||||
__ Lw(len, UntagSmiFieldMemOperand(v0, FixedArray::kLengthOffset));
|
||||
}
|
||||
__ Branch(&done_create);
|
||||
|
||||
// Try to create the list from an arguments object.
|
||||
__ bind(&create_arguments);
|
||||
__ Lw(len, UntagSmiFieldMemOperand(arguments_list,
|
||||
JSArgumentsObject::kLengthOffset));
|
||||
__ Ld(a4, FieldMemOperand(arguments_list, JSObject::kElementsOffset));
|
||||
__ Lw(at, UntagSmiFieldMemOperand(a4, FixedArray::kLengthOffset));
|
||||
__ Branch(&create_runtime, ne, len, Operand(at));
|
||||
__ mov(args, a4);
|
||||
|
||||
__ Branch(&done_create);
|
||||
|
||||
// For holey JSArrays we need to check that the array prototype chain
|
||||
// protector is intact and our prototype is the Array.prototype actually.
|
||||
__ bind(&create_holey_array);
|
||||
__ Ld(a2, FieldMemOperand(a2, Map::kPrototypeOffset));
|
||||
__ Ld(at, ContextMemOperand(native_context,
|
||||
Context::INITIAL_ARRAY_PROTOTYPE_INDEX));
|
||||
__ Branch(&create_runtime, ne, a2, Operand(at));
|
||||
__ LoadRoot(at, Heap::kArrayProtectorRootIndex);
|
||||
__ Lw(a2, FieldMemOperand(at, PropertyCell::kValueOffset));
|
||||
__ Branch(&create_runtime, ne, a2,
|
||||
Operand(Smi::FromInt(Isolate::kProtectorValid)));
|
||||
__ Lw(a2, UntagSmiFieldMemOperand(a0, JSArray::kLengthOffset));
|
||||
__ Ld(a0, FieldMemOperand(a0, JSArray::kElementsOffset));
|
||||
__ Branch(&done_create);
|
||||
|
||||
// Try to create the list from a JSArray object.
|
||||
__ bind(&create_array);
|
||||
__ Lbu(t1, FieldMemOperand(a2, Map::kBitField2Offset));
|
||||
__ DecodeField<Map::ElementsKindBits>(t1);
|
||||
STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
|
||||
STATIC_ASSERT(FAST_ELEMENTS == 2);
|
||||
STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
|
||||
__ Branch(&create_holey_array, eq, t1, Operand(FAST_HOLEY_SMI_ELEMENTS));
|
||||
__ Branch(&create_holey_array, eq, t1, Operand(FAST_HOLEY_ELEMENTS));
|
||||
__ Branch(&create_runtime, hi, t1, Operand(FAST_ELEMENTS));
|
||||
__ Lw(a2, UntagSmiFieldMemOperand(arguments_list, JSArray::kLengthOffset));
|
||||
__ Ld(a0, FieldMemOperand(arguments_list, JSArray::kElementsOffset));
|
||||
|
||||
__ bind(&done_create);
|
||||
}
|
||||
Register args = a2;
|
||||
Register len = a4;
|
||||
|
||||
// Check for stack overflow.
|
||||
{
|
||||
// Check the stack for overflow. We are not trying to catch interruptions
|
||||
// (i.e. debug break and preemption) here, so check the "real stack limit".
|
||||
Label done;
|
||||
__ LoadRoot(a4, Heap::kRealStackLimitRootIndex);
|
||||
__ LoadRoot(a5, Heap::kRealStackLimitRootIndex);
|
||||
// Make ip the space we have left. The stack might already be overflowed
|
||||
// here which will cause ip to become negative.
|
||||
__ Dsubu(a4, sp, a4);
|
||||
__ Dsubu(a5, sp, a5);
|
||||
// Check if the arguments will overflow the stack.
|
||||
__ dsll(at, len, kPointerSizeLog2);
|
||||
__ Branch(&done, gt, a4, Operand(at)); // Signed comparison.
|
||||
__ Branch(&done, gt, a5, Operand(at)); // Signed comparison.
|
||||
__ TailCallRuntime(Runtime::kThrowStackOverflow);
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- a1 : target
|
||||
// -- a0 : args (a FixedArray built from argumentsList)
|
||||
// -- a2 : len (number of elements to push from args)
|
||||
// -- a3 : new.target (checked to be constructor or undefined)
|
||||
// -- sp[0] : thisArgument
|
||||
// -----------------------------------
|
||||
|
||||
// Push arguments onto the stack (thisArgument is already on the stack).
|
||||
{
|
||||
Label done, push, loop;
|
||||
Register src = a4;
|
||||
Register src = a6;
|
||||
Register scratch = len;
|
||||
|
||||
__ daddiu(src, args, FixedArray::kHeaderSize - kHeapObjectTag);
|
||||
__ Branch(&done, eq, len, Operand(zero_reg), i::USE_DELAY_SLOT);
|
||||
__ mov(a0, len); // The 'len' argument for Call() or Construct().
|
||||
__ Daddu(a0, a0, len); // The 'len' argument for Call() or Construct().
|
||||
__ dsll(scratch, len, kPointerSizeLog2);
|
||||
__ Dsubu(scratch, sp, Operand(scratch));
|
||||
__ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
|
||||
@ -2250,31 +2159,13 @@ void Builtins::Generate_Apply(MacroAssembler* masm) {
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- a0 : argument count (len)
|
||||
// -- a1 : target
|
||||
// -- a3 : new.target (checked to be constructor or undefinded)
|
||||
// -- sp[0] : args[len-1]
|
||||
// -- sp[8] : args[len-2]
|
||||
// ... : ...
|
||||
// -- sp[8*(len-2)] : args[1]
|
||||
// -- sp[8*(len-1)] : args[0]
|
||||
// ----------------------------------
|
||||
|
||||
// Dispatch to Call or Construct depending on whether new.target is undefined.
|
||||
{
|
||||
Label construct;
|
||||
__ LoadRoot(at, Heap::kUndefinedValueRootIndex);
|
||||
__ Branch(&construct, ne, a3, Operand(at));
|
||||
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
||||
__ bind(&construct);
|
||||
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
|
||||
}
|
||||
// Tail-call to the actual Call or Construct builtin.
|
||||
__ Jump(code, RelocInfo::CODE_TARGET);
|
||||
}
|
||||
|
||||
// static
|
||||
void Builtins::Generate_ForwardVarargs(MacroAssembler* masm,
|
||||
Handle<Code> code) {
|
||||
void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
|
||||
Handle<Code> code) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- a0 : the number of arguments (not including the receiver)
|
||||
// -- a3 : the new.target (for [[Construct]] calls)
|
||||
|
@ -1553,7 +1553,7 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
|
||||
// -- rsp[24] : receiver
|
||||
// -----------------------------------
|
||||
|
||||
// 1. Load receiver into rdi, argArray into rax (if present), remove all
|
||||
// 1. Load receiver into rdi, argArray into rbx (if present), remove all
|
||||
// arguments from the stack (including the receiver), and push thisArg (if
|
||||
// present) instead.
|
||||
{
|
||||
@ -1576,11 +1576,10 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
|
||||
__ leap(rsp, Operand(rsp, rax, times_pointer_size, kPointerSize));
|
||||
__ Push(rdx);
|
||||
__ PushReturnAddressFrom(rcx);
|
||||
__ movp(rax, rbx);
|
||||
}
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- rax : argArray
|
||||
// -- rbx : argArray
|
||||
// -- rdi : receiver
|
||||
// -- rsp[0] : return address
|
||||
// -- rsp[8] : thisArg
|
||||
@ -1596,14 +1595,13 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
|
||||
|
||||
// 3. Tail call with no arguments if argArray is null or undefined.
|
||||
Label no_arguments;
|
||||
__ JumpIfRoot(rax, Heap::kNullValueRootIndex, &no_arguments, Label::kNear);
|
||||
__ JumpIfRoot(rax, Heap::kUndefinedValueRootIndex, &no_arguments,
|
||||
__ JumpIfRoot(rbx, Heap::kNullValueRootIndex, &no_arguments, Label::kNear);
|
||||
__ JumpIfRoot(rbx, Heap::kUndefinedValueRootIndex, &no_arguments,
|
||||
Label::kNear);
|
||||
|
||||
// 4a. Apply the receiver to the given argArray (passing undefined for
|
||||
// new.target).
|
||||
__ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
|
||||
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
|
||||
// 4a. Apply the receiver to the given argArray.
|
||||
__ Jump(masm->isolate()->builtins()->CallWithArrayLike(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
||||
// 4b. The argArray is either null or undefined, so we tail call without any
|
||||
// arguments to the receiver. Since we did not create a frame for
|
||||
@ -1685,7 +1683,7 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
|
||||
// -- rsp[32] : receiver
|
||||
// -----------------------------------
|
||||
|
||||
// 1. Load target into rdi (if present), argumentsList into rax (if present),
|
||||
// 1. Load target into rdi (if present), argumentsList into rbx (if present),
|
||||
// remove all arguments from the stack (including the receiver), and push
|
||||
// thisArgument (if present) instead.
|
||||
{
|
||||
@ -1707,11 +1705,10 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
|
||||
__ leap(rsp, Operand(rsp, rax, times_pointer_size, kPointerSize));
|
||||
__ Push(rdx);
|
||||
__ PushReturnAddressFrom(rcx);
|
||||
__ movp(rax, rbx);
|
||||
}
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- rax : argumentsList
|
||||
// -- rbx : argumentsList
|
||||
// -- rdi : target
|
||||
// -- rsp[0] : return address
|
||||
// -- rsp[8] : thisArgument
|
||||
@ -1725,10 +1722,9 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
|
||||
Immediate(1 << Map::kIsCallable));
|
||||
__ j(zero, &target_not_callable, Label::kNear);
|
||||
|
||||
// 3a. Apply the target to the given argumentsList (passing undefined for
|
||||
// new.target).
|
||||
__ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
|
||||
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
|
||||
// 3a. Apply the target to the given argumentsList.
|
||||
__ Jump(masm->isolate()->builtins()->CallWithArrayLike(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
||||
// 3b. The target is not callable, throw an appropriate TypeError.
|
||||
__ bind(&target_not_callable);
|
||||
@ -1749,7 +1745,7 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
|
||||
// -- rsp[32] : receiver
|
||||
// -----------------------------------
|
||||
|
||||
// 1. Load target into rdi (if present), argumentsList into rax (if present),
|
||||
// 1. Load target into rdi (if present), argumentsList into rbx (if present),
|
||||
// new.target into rdx (if present, otherwise use target), remove all
|
||||
// arguments from the stack (including the receiver), and push thisArgument
|
||||
// (if present) instead.
|
||||
@ -1773,11 +1769,10 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
|
||||
__ leap(rsp, Operand(rsp, rax, times_pointer_size, kPointerSize));
|
||||
__ PushRoot(Heap::kUndefinedValueRootIndex);
|
||||
__ PushReturnAddressFrom(rcx);
|
||||
__ movp(rax, rbx);
|
||||
}
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- rax : argumentsList
|
||||
// -- rbx : argumentsList
|
||||
// -- rdx : new.target
|
||||
// -- rdi : target
|
||||
// -- rsp[0] : return address
|
||||
@ -1801,7 +1796,8 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
|
||||
__ j(zero, &new_target_not_constructor, Label::kNear);
|
||||
|
||||
// 4a. Construct the target with the given new.target and argumentsList.
|
||||
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
|
||||
__ Jump(masm->isolate()->builtins()->ConstructWithArrayLike(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
||||
// 4b. The target is not a constructor, throw an appropriate TypeError.
|
||||
__ bind(&target_not_constructor);
|
||||
@ -2339,94 +2335,17 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
// static
|
||||
void Builtins::Generate_Apply(MacroAssembler* masm) {
|
||||
void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm,
|
||||
Handle<Code> code) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- rax : argumentsList
|
||||
// -- rdi : target
|
||||
// -- rdx : new.target (checked to be constructor or undefined)
|
||||
// -- rsp[0] : return address.
|
||||
// -- rsp[8] : thisArgument
|
||||
// -- rax : number of parameters on the stack (not including the receiver)
|
||||
// -- rbx : arguments list (a FixedArray)
|
||||
// -- rcx : len (number of elements to push from args)
|
||||
// -- rdx : new.target (for [[Construct]])
|
||||
// -- rsp[0] : return address
|
||||
// -----------------------------------
|
||||
|
||||
// Create the list of arguments from the array-like argumentsList.
|
||||
{
|
||||
Label create_arguments, create_array, create_holey_array, create_runtime,
|
||||
done_create;
|
||||
__ JumpIfSmi(rax, &create_runtime);
|
||||
|
||||
// Load the map of argumentsList into rcx.
|
||||
__ movp(rcx, FieldOperand(rax, HeapObject::kMapOffset));
|
||||
|
||||
// Load native context into rbx.
|
||||
__ movp(rbx, NativeContextOperand());
|
||||
|
||||
// Check if argumentsList is an (unmodified) arguments object.
|
||||
__ cmpp(rcx, ContextOperand(rbx, Context::SLOPPY_ARGUMENTS_MAP_INDEX));
|
||||
__ j(equal, &create_arguments);
|
||||
__ cmpp(rcx, ContextOperand(rbx, Context::STRICT_ARGUMENTS_MAP_INDEX));
|
||||
__ j(equal, &create_arguments);
|
||||
|
||||
// Check if argumentsList is a fast JSArray.
|
||||
__ CmpInstanceType(rcx, JS_ARRAY_TYPE);
|
||||
__ j(equal, &create_array);
|
||||
|
||||
// Ask the runtime to create the list (actually a FixedArray).
|
||||
__ bind(&create_runtime);
|
||||
{
|
||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||
__ Push(rdi);
|
||||
__ Push(rdx);
|
||||
__ Push(rax);
|
||||
__ CallRuntime(Runtime::kCreateListFromArrayLike);
|
||||
__ Pop(rdx);
|
||||
__ Pop(rdi);
|
||||
__ SmiToInteger32(rbx, FieldOperand(rax, FixedArray::kLengthOffset));
|
||||
}
|
||||
__ jmp(&done_create);
|
||||
|
||||
// Try to create the list from an arguments object.
|
||||
__ bind(&create_arguments);
|
||||
__ movp(rbx, FieldOperand(rax, JSArgumentsObject::kLengthOffset));
|
||||
__ movp(rcx, FieldOperand(rax, JSObject::kElementsOffset));
|
||||
__ cmpp(rbx, FieldOperand(rcx, FixedArray::kLengthOffset));
|
||||
__ j(not_equal, &create_runtime);
|
||||
__ SmiToInteger32(rbx, rbx);
|
||||
__ movp(rax, rcx);
|
||||
__ jmp(&done_create);
|
||||
|
||||
__ bind(&create_holey_array);
|
||||
// For holey JSArrays we need to check that the array prototype chain
|
||||
// protector is intact and our prototype is the Array.prototype actually.
|
||||
__ movp(rcx, FieldOperand(rax, HeapObject::kMapOffset));
|
||||
__ movp(rcx, FieldOperand(rcx, Map::kPrototypeOffset));
|
||||
__ cmpp(rcx, ContextOperand(rbx, Context::INITIAL_ARRAY_PROTOTYPE_INDEX));
|
||||
__ j(not_equal, &create_runtime);
|
||||
__ LoadRoot(rcx, Heap::kArrayProtectorRootIndex);
|
||||
__ Cmp(FieldOperand(rcx, PropertyCell::kValueOffset),
|
||||
Smi::FromInt(Isolate::kProtectorValid));
|
||||
__ j(not_equal, &create_runtime);
|
||||
__ SmiToInteger32(rbx, FieldOperand(rax, JSArray::kLengthOffset));
|
||||
__ movp(rax, FieldOperand(rax, JSArray::kElementsOffset));
|
||||
__ jmp(&done_create);
|
||||
|
||||
// Try to create the list from a JSArray object.
|
||||
__ bind(&create_array);
|
||||
__ movzxbp(rcx, FieldOperand(rcx, Map::kBitField2Offset));
|
||||
__ DecodeField<Map::ElementsKindBits>(rcx);
|
||||
STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
|
||||
STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
|
||||
STATIC_ASSERT(FAST_ELEMENTS == 2);
|
||||
STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
|
||||
__ cmpl(rcx, Immediate(FAST_HOLEY_SMI_ELEMENTS));
|
||||
__ j(equal, &create_holey_array);
|
||||
__ cmpl(rcx, Immediate(FAST_HOLEY_ELEMENTS));
|
||||
__ j(equal, &create_holey_array);
|
||||
__ j(above, &create_runtime);
|
||||
__ SmiToInteger32(rbx, FieldOperand(rax, JSArray::kLengthOffset));
|
||||
__ movp(rax, FieldOperand(rax, JSArray::kElementsOffset));
|
||||
|
||||
__ bind(&done_create);
|
||||
}
|
||||
__ AssertFixedArray(rbx);
|
||||
|
||||
// Check for stack overflow.
|
||||
{
|
||||
@ -2434,61 +2353,48 @@ void Builtins::Generate_Apply(MacroAssembler* masm) {
|
||||
// (i.e. debug break and preemption) here, so check the "real stack limit".
|
||||
Label done;
|
||||
__ LoadRoot(kScratchRegister, Heap::kRealStackLimitRootIndex);
|
||||
__ movp(rcx, rsp);
|
||||
// Make rcx the space we have left. The stack might already be overflowed
|
||||
// here which will cause rcx to become negative.
|
||||
__ subp(rcx, kScratchRegister);
|
||||
__ sarp(rcx, Immediate(kPointerSizeLog2));
|
||||
__ movp(r8, rsp);
|
||||
// Make r8 the space we have left. The stack might already be overflowed
|
||||
// here which will cause r8 to become negative.
|
||||
__ subp(r8, kScratchRegister);
|
||||
__ sarp(r8, Immediate(kPointerSizeLog2));
|
||||
// Check if the arguments will overflow the stack.
|
||||
__ cmpp(rcx, rbx);
|
||||
__ cmpp(r8, rcx);
|
||||
__ j(greater, &done, Label::kNear); // Signed comparison.
|
||||
__ TailCallRuntime(Runtime::kThrowStackOverflow);
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- rdi : target
|
||||
// -- rax : args (a FixedArray built from argumentsList)
|
||||
// -- rbx : len (number of elements to push from args)
|
||||
// -- rdx : new.target (checked to be constructor or undefined)
|
||||
// -- rsp[0] : return address.
|
||||
// -- rsp[8] : thisArgument
|
||||
// -----------------------------------
|
||||
|
||||
// Push arguments onto the stack (thisArgument is already on the stack).
|
||||
// Push additional arguments onto the stack.
|
||||
{
|
||||
__ PopReturnAddressTo(r8);
|
||||
__ Set(rcx, 0);
|
||||
__ Set(r9, 0);
|
||||
Label done, push, loop;
|
||||
__ bind(&loop);
|
||||
__ cmpl(rcx, rbx);
|
||||
__ cmpl(r9, rcx);
|
||||
__ j(equal, &done, Label::kNear);
|
||||
// Turn the hole into undefined as we go.
|
||||
__ movp(r9, FieldOperand(rax, rcx, times_pointer_size,
|
||||
FixedArray::kHeaderSize));
|
||||
__ CompareRoot(r9, Heap::kTheHoleValueRootIndex);
|
||||
__ movp(r11,
|
||||
FieldOperand(rbx, r9, times_pointer_size, FixedArray::kHeaderSize));
|
||||
__ CompareRoot(r11, Heap::kTheHoleValueRootIndex);
|
||||
__ j(not_equal, &push, Label::kNear);
|
||||
__ LoadRoot(r9, Heap::kUndefinedValueRootIndex);
|
||||
__ LoadRoot(r11, Heap::kUndefinedValueRootIndex);
|
||||
__ bind(&push);
|
||||
__ Push(r9);
|
||||
__ incl(rcx);
|
||||
__ Push(r11);
|
||||
__ incl(r9);
|
||||
__ jmp(&loop);
|
||||
__ bind(&done);
|
||||
__ PushReturnAddressFrom(r8);
|
||||
__ Move(rax, rcx);
|
||||
__ addq(rax, r9);
|
||||
}
|
||||
|
||||
// Dispatch to Call or Construct depending on whether new.target is undefined.
|
||||
{
|
||||
__ CompareRoot(rdx, Heap::kUndefinedValueRootIndex);
|
||||
__ j(equal, masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
||||
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
|
||||
}
|
||||
// Tail-call to the actual Call or Construct builtin.
|
||||
__ Jump(code, RelocInfo::CODE_TARGET);
|
||||
}
|
||||
|
||||
// static
|
||||
void Builtins::Generate_ForwardVarargs(MacroAssembler* masm,
|
||||
Handle<Code> code) {
|
||||
void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
|
||||
Handle<Code> code) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- rax : the number of arguments (not including the receiver)
|
||||
// -- rdx : the new target (for [[Construct]] calls)
|
||||
|
@ -409,6 +409,12 @@ Callable CodeFactory::CallFunction(Isolate* isolate, ConvertReceiverMode mode,
|
||||
CallTrampolineDescriptor(isolate));
|
||||
}
|
||||
|
||||
// static
|
||||
Callable CodeFactory::CallVarargs(Isolate* isolate) {
|
||||
return Callable(isolate->builtins()->CallVarargs(),
|
||||
CallVarargsDescriptor(isolate));
|
||||
}
|
||||
|
||||
// static
|
||||
Callable CodeFactory::CallForwardVarargs(Isolate* isolate) {
|
||||
return Callable(isolate->builtins()->CallForwardVarargs(),
|
||||
@ -439,6 +445,12 @@ Callable CodeFactory::ConstructFunction(Isolate* isolate) {
|
||||
ConstructTrampolineDescriptor(isolate));
|
||||
}
|
||||
|
||||
// static
|
||||
Callable CodeFactory::ConstructVarargs(Isolate* isolate) {
|
||||
return Callable(isolate->builtins()->ConstructVarargs(),
|
||||
ConstructVarargsDescriptor(isolate));
|
||||
}
|
||||
|
||||
// static
|
||||
Callable CodeFactory::ConstructForwardVarargs(Isolate* isolate) {
|
||||
return Callable(isolate->builtins()->ConstructForwardVarargs(),
|
||||
|
@ -146,11 +146,13 @@ class V8_EXPORT_PRIVATE CodeFactory final {
|
||||
static Callable CallFunction(
|
||||
Isolate* isolate, ConvertReceiverMode mode = ConvertReceiverMode::kAny,
|
||||
TailCallMode tail_call_mode = TailCallMode::kDisallow);
|
||||
static Callable CallVarargs(Isolate* isolate);
|
||||
static Callable CallForwardVarargs(Isolate* isolate);
|
||||
static Callable CallFunctionForwardVarargs(Isolate* isolate);
|
||||
static Callable Construct(Isolate* isolate);
|
||||
static Callable ConstructWithSpread(Isolate* isolate);
|
||||
static Callable ConstructFunction(Isolate* isolate);
|
||||
static Callable ConstructVarargs(Isolate* isolate);
|
||||
static Callable ConstructForwardVarargs(Isolate* isolate);
|
||||
static Callable ConstructFunctionForwardVarargs(Isolate* isolate);
|
||||
static Callable CreateIterResultObject(Isolate* isolate);
|
||||
|
@ -156,6 +156,16 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void CallVarargsDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// eax : number of arguments (on the stack, not including receiver)
|
||||
// edi : the target to call
|
||||
// ebx : arguments list (FixedArray)
|
||||
// ecx : arguments list length (untagged)
|
||||
Register registers[] = {edi, eax, ebx, ecx};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void CallForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// eax : number of arguments
|
||||
@ -165,6 +175,25 @@ void CallForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void CallWithArrayLikeDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// edi : the target to call
|
||||
// ebx : the arguments list
|
||||
Register registers[] = {edi, ebx};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void ConstructVarargsDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// eax : number of arguments (on the stack, not including receiver)
|
||||
// edi : the target to call
|
||||
// edx : the new target
|
||||
// ebx : arguments list (FixedArray)
|
||||
// ecx : arguments list length (untagged)
|
||||
Register registers[] = {edi, edx, eax, ebx, ecx};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// eax : number of arguments
|
||||
@ -175,6 +204,15 @@ void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void ConstructWithArrayLikeDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// edi : the target to call
|
||||
// edx : the new target
|
||||
// ebx : the arguments list
|
||||
Register registers[] = {edi, edx, ebx};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void ConstructStubDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// eax : number of arguments
|
||||
|
@ -821,6 +821,16 @@ void MacroAssembler::AssertSmi(Register object) {
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::AssertFixedArray(Register object) {
|
||||
if (emit_debug_code()) {
|
||||
test(object, Immediate(kSmiTagMask));
|
||||
Check(not_equal, kOperandIsASmiAndNotAFixedArray);
|
||||
Push(object);
|
||||
CmpObjectType(object, FIXED_ARRAY_TYPE, object);
|
||||
Pop(object);
|
||||
Check(equal, kOperandIsNotAFixedArray);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::AssertFunction(Register object) {
|
||||
if (emit_debug_code()) {
|
||||
|
@ -521,6 +521,9 @@ class MacroAssembler: public Assembler {
|
||||
// Abort execution if argument is a smi, enabled via --debug-code.
|
||||
void AssertNotSmi(Register object);
|
||||
|
||||
// Abort execution if argument is not a FixedArray, enabled via --debug-code.
|
||||
void AssertFixedArray(Register object);
|
||||
|
||||
// Abort execution if argument is not a JSFunction, enabled via --debug-code.
|
||||
void AssertFunction(Register object);
|
||||
|
||||
|
@ -459,6 +459,16 @@ void CallTrampolineDescriptor::InitializePlatformIndependent(
|
||||
machine_types);
|
||||
}
|
||||
|
||||
void CallVarargsDescriptor::InitializePlatformIndependent(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// kTarget, kActualArgumentsCount, kArgumentsList, kArgumentsLength
|
||||
MachineType machine_types[] = {MachineType::AnyTagged(), MachineType::Int32(),
|
||||
MachineType::AnyTagged(),
|
||||
MachineType::Int32()};
|
||||
data->InitializePlatformIndependent(arraysize(machine_types), 0,
|
||||
machine_types);
|
||||
}
|
||||
|
||||
void CallForwardVarargsDescriptor::InitializePlatformIndependent(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// kTarget, kActualArgumentsCount, kStartIndex
|
||||
@ -468,6 +478,26 @@ void CallForwardVarargsDescriptor::InitializePlatformIndependent(
|
||||
machine_types);
|
||||
}
|
||||
|
||||
void CallWithArrayLikeDescriptor::InitializePlatformIndependent(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// kTarget, kArgumentsList
|
||||
MachineType machine_types[] = {MachineType::AnyTagged(),
|
||||
MachineType::AnyTagged()};
|
||||
data->InitializePlatformIndependent(arraysize(machine_types), 0,
|
||||
machine_types);
|
||||
}
|
||||
|
||||
void ConstructVarargsDescriptor::InitializePlatformIndependent(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// kTarget, kNewTarget, kActualArgumentsCount, kArgumentsList,
|
||||
// kArgumentsLength
|
||||
MachineType machine_types[] = {
|
||||
MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::Int32(),
|
||||
MachineType::AnyTagged(), MachineType::Int32()};
|
||||
data->InitializePlatformIndependent(arraysize(machine_types), 0,
|
||||
machine_types);
|
||||
}
|
||||
|
||||
void ConstructForwardVarargsDescriptor::InitializePlatformIndependent(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// kTarget, kNewTarget, kActualArgumentsCount, kStartIndex
|
||||
@ -478,6 +508,16 @@ void ConstructForwardVarargsDescriptor::InitializePlatformIndependent(
|
||||
machine_types);
|
||||
}
|
||||
|
||||
void ConstructWithArrayLikeDescriptor::InitializePlatformIndependent(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// kTarget, kNewTarget, kArgumentsList
|
||||
MachineType machine_types[] = {MachineType::AnyTagged(),
|
||||
MachineType::AnyTagged(),
|
||||
MachineType::AnyTagged()};
|
||||
data->InitializePlatformIndependent(arraysize(machine_types), 0,
|
||||
machine_types);
|
||||
}
|
||||
|
||||
void ConstructStubDescriptor::InitializePlatformIndependent(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// kFunction, kNewTarget, kActualArgumentsCount, kAllocationSite
|
||||
|
@ -44,11 +44,15 @@ class PlatformInterfaceDescriptor;
|
||||
V(CallFunction) \
|
||||
V(CallIC) \
|
||||
V(CallICTrampoline) \
|
||||
V(CallVarargs) \
|
||||
V(CallForwardVarargs) \
|
||||
V(CallWithArrayLike) \
|
||||
V(CallConstruct) \
|
||||
V(CallTrampoline) \
|
||||
V(ConstructStub) \
|
||||
V(ConstructVarargs) \
|
||||
V(ConstructForwardVarargs) \
|
||||
V(ConstructWithArrayLike) \
|
||||
V(ConstructTrampoline) \
|
||||
V(TransitionElementsKind) \
|
||||
V(AllocateHeapNumber) \
|
||||
@ -574,6 +578,14 @@ class CallTrampolineDescriptor : public CallInterfaceDescriptor {
|
||||
CallInterfaceDescriptor)
|
||||
};
|
||||
|
||||
class CallVarargsDescriptor : public CallInterfaceDescriptor {
|
||||
public:
|
||||
DEFINE_PARAMETERS(kTarget, kActualArgumentsCount, kArgumentsList,
|
||||
kArgumentsLength)
|
||||
DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE(CallVarargsDescriptor,
|
||||
CallInterfaceDescriptor)
|
||||
};
|
||||
|
||||
class CallForwardVarargsDescriptor : public CallInterfaceDescriptor {
|
||||
public:
|
||||
DEFINE_PARAMETERS(kTarget, kActualArgumentsCount, kStartIndex)
|
||||
@ -581,6 +593,21 @@ class CallForwardVarargsDescriptor : public CallInterfaceDescriptor {
|
||||
CallInterfaceDescriptor)
|
||||
};
|
||||
|
||||
class CallWithArrayLikeDescriptor : public CallInterfaceDescriptor {
|
||||
public:
|
||||
DEFINE_PARAMETERS(kTarget, kArgumentsList)
|
||||
DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE(CallWithArrayLikeDescriptor,
|
||||
CallInterfaceDescriptor)
|
||||
};
|
||||
|
||||
class ConstructVarargsDescriptor : public CallInterfaceDescriptor {
|
||||
public:
|
||||
DEFINE_PARAMETERS(kTarget, kNewTarget, kActualArgumentsCount, kArgumentsList,
|
||||
kArgumentsLength)
|
||||
DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE(ConstructVarargsDescriptor,
|
||||
CallInterfaceDescriptor)
|
||||
};
|
||||
|
||||
class ConstructForwardVarargsDescriptor : public CallInterfaceDescriptor {
|
||||
public:
|
||||
DEFINE_PARAMETERS(kTarget, kNewTarget, kActualArgumentsCount, kStartIndex)
|
||||
@ -588,6 +615,13 @@ class ConstructForwardVarargsDescriptor : public CallInterfaceDescriptor {
|
||||
ConstructForwardVarargsDescriptor, CallInterfaceDescriptor)
|
||||
};
|
||||
|
||||
class ConstructWithArrayLikeDescriptor : public CallInterfaceDescriptor {
|
||||
public:
|
||||
DEFINE_PARAMETERS(kTarget, kNewTarget, kArgumentsList)
|
||||
DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE(ConstructWithArrayLikeDescriptor,
|
||||
CallInterfaceDescriptor)
|
||||
};
|
||||
|
||||
class ConstructStubDescriptor : public CallInterfaceDescriptor {
|
||||
public:
|
||||
DEFINE_PARAMETERS(kFunction, kNewTarget, kActualArgumentsCount,
|
||||
|
@ -155,6 +155,16 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void CallVarargsDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// a0 : number of arguments (on the stack, not including receiver)
|
||||
// a1 : the target to call
|
||||
// a2 : arguments list (FixedArray)
|
||||
// t0 : arguments list length (untagged)
|
||||
Register registers[] = {a1, a0, a2, t0};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void CallForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// a1: the target to call
|
||||
@ -164,6 +174,25 @@ void CallForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void CallWithArrayLikeDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// a1 : the target to call
|
||||
// a2 : the arguments list
|
||||
Register registers[] = {a1, a2};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void ConstructVarargsDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// a0 : number of arguments (on the stack, not including receiver)
|
||||
// a1 : the target to call
|
||||
// a3 : the new target
|
||||
// a2 : arguments list (FixedArray)
|
||||
// t0 : arguments list length (untagged)
|
||||
Register registers[] = {a1, a3, a0, a2, t0};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// a1: the target to call
|
||||
@ -174,6 +203,15 @@ void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void ConstructWithArrayLikeDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// a1 : the target to call
|
||||
// a3 : the new target
|
||||
// a2 : the arguments list
|
||||
Register registers[] = {a1, a3, a2};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void ConstructStubDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// a1: target
|
||||
|
@ -5872,6 +5872,15 @@ void MacroAssembler::AssertSmi(Register object) {
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::AssertFixedArray(Register object) {
|
||||
if (emit_debug_code()) {
|
||||
STATIC_ASSERT(kSmiTag == 0);
|
||||
SmiTst(object, t8);
|
||||
Check(ne, kOperandIsASmiAndNotAFixedArray, t8, Operand(zero_reg));
|
||||
GetObjectType(object, t8, t8);
|
||||
Check(eq, kOperandIsNotAFixedArray, t8, Operand(FIXED_ARRAY_TYPE));
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::AssertFunction(Register object) {
|
||||
if (emit_debug_code()) {
|
||||
|
@ -1538,6 +1538,9 @@ const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
|
||||
void AssertNotSmi(Register object);
|
||||
void AssertSmi(Register object);
|
||||
|
||||
// Abort execution if argument is not a FixedArray, enabled via --debug-code.
|
||||
void AssertFixedArray(Register object);
|
||||
|
||||
// Abort execution if argument is not a JSFunction, enabled via --debug-code.
|
||||
void AssertFunction(Register object);
|
||||
|
||||
|
@ -155,6 +155,16 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void CallVarargsDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// a0 : number of arguments (on the stack, not including receiver)
|
||||
// a1 : the target to call
|
||||
// a2 : arguments list (FixedArray)
|
||||
// a4 : arguments list length (untagged)
|
||||
Register registers[] = {a1, a0, a2, a4};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void CallForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// a1: the target to call
|
||||
@ -164,6 +174,25 @@ void CallForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void CallWithArrayLikeDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// a1 : the target to call
|
||||
// a2 : the arguments list
|
||||
Register registers[] = {a1, a2};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void ConstructVarargsDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// a0 : number of arguments (on the stack, not including receiver)
|
||||
// a1 : the target to call
|
||||
// a3 : the new target
|
||||
// a2 : arguments list (FixedArray)
|
||||
// a4 : arguments list length (untagged)
|
||||
Register registers[] = {a1, a3, a0, a2, a4};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// a1: the target to call
|
||||
@ -174,6 +203,15 @@ void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void ConstructWithArrayLikeDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// a1 : the target to call
|
||||
// a3 : the new target
|
||||
// a2 : the arguments list
|
||||
Register registers[] = {a1, a3, a2};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void ConstructStubDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// a1: target
|
||||
|
@ -6335,6 +6335,15 @@ void MacroAssembler::AssertSmi(Register object) {
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::AssertFixedArray(Register object) {
|
||||
if (emit_debug_code()) {
|
||||
STATIC_ASSERT(kSmiTag == 0);
|
||||
SmiTst(object, t8);
|
||||
Check(ne, kOperandIsASmiAndNotAFixedArray, t8, Operand(zero_reg));
|
||||
GetObjectType(object, t8, t8);
|
||||
Check(eq, kOperandIsNotAFixedArray, t8, Operand(FIXED_ARRAY_TYPE));
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::AssertFunction(Register object) {
|
||||
if (emit_debug_code()) {
|
||||
|
@ -1692,6 +1692,9 @@ const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
|
||||
void AssertNotSmi(Register object);
|
||||
void AssertSmi(Register object);
|
||||
|
||||
// Abort execution if argument is not a FixedArray, enabled via --debug-code.
|
||||
void AssertFixedArray(Register object);
|
||||
|
||||
// Abort execution if argument is not a JSFunction, enabled via --debug-code.
|
||||
void AssertFunction(Register object);
|
||||
|
||||
|
@ -180,6 +180,7 @@
|
||||
'builtins/builtins-async-iterator-gen.cc',
|
||||
'builtins/builtins-boolean-gen.cc',
|
||||
'builtins/builtins-call-gen.cc',
|
||||
'builtins/builtins-call-gen.h',
|
||||
'builtins/builtins-collections-gen.cc',
|
||||
'builtins/builtins-console-gen.cc',
|
||||
'builtins/builtins-constructor-gen.cc',
|
||||
|
@ -155,6 +155,16 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void CallVarargsDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// rax : number of arguments (on the stack, not including receiver)
|
||||
// rdi : the target to call
|
||||
// rbx : arguments list (FixedArray)
|
||||
// rcx : arguments list length (untagged)
|
||||
Register registers[] = {rdi, rax, rbx, rcx};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void CallForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// rax : number of arguments
|
||||
@ -164,6 +174,25 @@ void CallForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void CallWithArrayLikeDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// rdi : the target to call
|
||||
// rbx : the arguments list
|
||||
Register registers[] = {rdi, rbx};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void ConstructVarargsDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// rax : number of arguments (on the stack, not including receiver)
|
||||
// rdi : the target to call
|
||||
// rdx : the new target
|
||||
// rbx : arguments list (FixedArray)
|
||||
// rcx : arguments list length (untagged)
|
||||
Register registers[] = {rdi, rdx, rax, rbx, rcx};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// rax : number of arguments
|
||||
@ -174,6 +203,15 @@ void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void ConstructWithArrayLikeDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// rdi : the target to call
|
||||
// rdx : the new target
|
||||
// rbx : the arguments list
|
||||
Register registers[] = {rdi, rdx, rbx};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void ConstructStubDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// rax : number of arguments
|
||||
|
@ -3686,6 +3686,16 @@ void MacroAssembler::AssertSmi(const Operand& object) {
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::AssertFixedArray(Register object) {
|
||||
if (emit_debug_code()) {
|
||||
testb(object, Immediate(kSmiTagMask));
|
||||
Check(not_equal, kOperandIsASmiAndNotAFixedArray);
|
||||
Push(object);
|
||||
CmpObjectType(object, FIXED_ARRAY_TYPE, object);
|
||||
Pop(object);
|
||||
Check(equal, kOperandIsNotAFixedArray);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::AssertZeroExtended(Register int32_register) {
|
||||
if (emit_debug_code()) {
|
||||
|
@ -1145,6 +1145,9 @@ class MacroAssembler: public Assembler {
|
||||
void AssertSmi(Register object);
|
||||
void AssertSmi(const Operand& object);
|
||||
|
||||
// Abort execution if argument is not a FixedArray, enabled via --debug-code.
|
||||
void AssertFixedArray(Register object);
|
||||
|
||||
// Abort execution if a 64 bit register containing a 32 bit payload does not
|
||||
// have zeros in the top 32 bits, enabled via --debug-code.
|
||||
void AssertZeroExtended(Register reg);
|
||||
|
Loading…
Reference in New Issue
Block a user