[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:
bmeurer 2017-06-08 11:31:59 -07:00 committed by Commit Bot
parent ae947e26fe
commit af76779aa3
36 changed files with 825 additions and 858 deletions

View File

@ -933,6 +933,7 @@ v8_source_set("v8_builtins_generators") {
"src/builtins/builtins-async-iterator-gen.cc", "src/builtins/builtins-async-iterator-gen.cc",
"src/builtins/builtins-boolean-gen.cc", "src/builtins/builtins-boolean-gen.cc",
"src/builtins/builtins-call-gen.cc", "src/builtins/builtins-call-gen.cc",
"src/builtins/builtins-call-gen.h",
"src/builtins/builtins-collections-gen.cc", "src/builtins/builtins-collections-gen.cc",
"src/builtins/builtins-console-gen.cc", "src/builtins/builtins-console-gen.cc",
"src/builtins/builtins-constructor-gen.cc", "src/builtins/builtins-constructor-gen.cc",

View File

@ -157,6 +157,16 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers); 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( void CallForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
// r0 : number of arguments // r0 : number of arguments
@ -166,6 +176,25 @@ void CallForwardVarargsDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers); 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( void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
// r0 : number of arguments // r0 : number of arguments
@ -176,6 +205,15 @@ void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers); 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( void ConstructStubDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
// r0 : number of arguments // r0 : number of arguments

View File

@ -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) { void MacroAssembler::AssertFunction(Register object) {
if (emit_debug_code()) { if (emit_debug_code()) {

View File

@ -1215,6 +1215,9 @@ class MacroAssembler: public Assembler {
void AssertNotSmi(Register object); void AssertNotSmi(Register object);
void AssertSmi(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. // Abort execution if argument is not a JSFunction, enabled via --debug-code.
void AssertFunction(Register object); void AssertFunction(Register object);

View File

@ -176,6 +176,16 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers); 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( void CallForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
// x1: target // x1: target
@ -185,6 +195,25 @@ void CallForwardVarargsDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers); 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( void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
// x3: new target // x3: new target
@ -195,6 +224,15 @@ void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers); 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( void ConstructStubDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
// x3: new target // x3: new target

View File

@ -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) { void MacroAssembler::AssertFunction(Register object) {
if (emit_debug_code()) { if (emit_debug_code()) {

View File

@ -1565,6 +1565,9 @@ class MacroAssembler : public Assembler {
inline void ObjectTag(Register tagged_obj, Register obj); inline void ObjectTag(Register tagged_obj, Register obj);
inline void ObjectUntag(Register untagged_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. // Abort execution if argument is not a JSFunction, enabled via --debug-code.
void AssertFunction(Register object); void AssertFunction(Register object);

View File

@ -142,6 +142,7 @@ namespace internal {
V(kOffsetOutOfRange, "Offset out of range") \ V(kOffsetOutOfRange, "Offset out of range") \
V(kOperandIsASmiAndNotABoundFunction, \ V(kOperandIsASmiAndNotABoundFunction, \
"Operand is a smi and not a bound function") \ "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(kOperandIsASmiAndNotAFunction, "Operand is a smi and not a function") \
V(kOperandIsASmiAndNotAGeneratorObject, \ V(kOperandIsASmiAndNotAGeneratorObject, \
"Operand is a smi and not a generator object") \ "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(kOperandIsASmiAndNotAString, "Operand is a smi and not a string") \
V(kOperandIsASmi, "Operand is a smi") \ V(kOperandIsASmi, "Operand is a smi") \
V(kOperandIsNotABoundFunction, "Operand is not a bound function") \ V(kOperandIsNotABoundFunction, "Operand is not a bound function") \
V(kOperandIsNotAFixedArray, "Operand is not a fixed array") \
V(kOperandIsNotAFunction, "Operand is not a function") \ V(kOperandIsNotAFunction, "Operand is not a function") \
V(kOperandIsNotAGeneratorObject, "Operand is not a generator object") \ V(kOperandIsNotAGeneratorObject, "Operand is not a generator object") \
V(kOperandIsNotAReceiver, "Operand is not a receiver") \ V(kOperandIsNotAReceiver, "Operand is not a receiver") \

View File

@ -1832,24 +1832,23 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
// -- sp[8] : receiver // -- 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 // arguments from the stack (including the receiver), and push thisArg (if
// present) instead. // present) instead.
{ {
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex); __ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
__ mov(r3, r2); __ mov(r2, r5);
__ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2)); // receiver __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2)); // receiver
__ sub(r4, r0, Operand(1), SetCC); __ 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); __ 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)); __ add(sp, sp, Operand(r0, LSL, kPointerSizeLog2));
__ str(r2, MemOperand(sp, 0)); __ str(r5, MemOperand(sp, 0));
__ mov(r0, r3);
} }
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r0 : argArray // -- r2 : argArray
// -- r1 : receiver // -- r1 : receiver
// -- sp[0] : thisArg // -- 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. // 3. Tail call with no arguments if argArray is null or undefined.
Label no_arguments; Label no_arguments;
__ JumpIfRoot(r0, Heap::kNullValueRootIndex, &no_arguments); __ JumpIfRoot(r2, Heap::kNullValueRootIndex, &no_arguments);
__ JumpIfRoot(r0, Heap::kUndefinedValueRootIndex, &no_arguments); __ JumpIfRoot(r2, Heap::kUndefinedValueRootIndex, &no_arguments);
// 4a. Apply the receiver to the given argArray (passing undefined for // 4a. Apply the receiver to the given argArray.
// new.target). __ Jump(masm->isolate()->builtins()->CallWithArrayLike(),
__ LoadRoot(r3, Heap::kUndefinedValueRootIndex); RelocInfo::CODE_TARGET);
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
// 4b. The argArray is either null or undefined, so we tail call without any // 4b. The argArray is either null or undefined, so we tail call without any
// arguments to the receiver. // arguments to the receiver.
@ -1940,26 +1938,25 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
// -- sp[12] : receiver // -- 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 // remove all arguments from the stack (including the receiver), and push
// thisArgument (if present) instead. // thisArgument (if present) instead.
{ {
__ LoadRoot(r1, Heap::kUndefinedValueRootIndex); __ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
__ mov(r5, r1);
__ mov(r2, r1); __ mov(r2, r1);
__ mov(r3, r1);
__ sub(r4, r0, Operand(1), SetCC); __ sub(r4, r0, Operand(1), SetCC);
__ ldr(r1, MemOperand(sp, r4, LSL, kPointerSizeLog2), ge); // target __ ldr(r1, MemOperand(sp, r4, LSL, kPointerSizeLog2), ge); // target
__ sub(r4, r4, Operand(1), SetCC, ge); __ 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); __ 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)); __ add(sp, sp, Operand(r0, LSL, kPointerSizeLog2));
__ str(r2, MemOperand(sp, 0)); __ str(r5, MemOperand(sp, 0));
__ mov(r0, r3);
} }
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r0 : argumentsList // -- r2 : argumentsList
// -- r1 : target // -- r1 : target
// -- sp[0] : thisArgument // -- sp[0] : thisArgument
// ----------------------------------- // -----------------------------------
@ -1972,10 +1969,9 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
__ tst(r4, Operand(1 << Map::kIsCallable)); __ tst(r4, Operand(1 << Map::kIsCallable));
__ b(eq, &target_not_callable); __ b(eq, &target_not_callable);
// 3a. Apply the target to the given argumentsList (passing undefined for // 3a. Apply the target to the given argumentsList.
// new.target). __ Jump(masm->isolate()->builtins()->CallWithArrayLike(),
__ LoadRoot(r3, Heap::kUndefinedValueRootIndex); RelocInfo::CODE_TARGET);
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
// 3b. The target is not callable, throw an appropriate TypeError. // 3b. The target is not callable, throw an appropriate TypeError.
__ bind(&target_not_callable); __ bind(&target_not_callable);
@ -1994,7 +1990,7 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
// -- sp[12] : receiver // -- 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 // new.target into r3 (if present, otherwise use target), remove all
// arguments from the stack (including the receiver), and push thisArgument // arguments from the stack (including the receiver), and push thisArgument
// (if present) instead. // (if present) instead.
@ -2010,11 +2006,10 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
__ sub(r4, r4, Operand(1), SetCC, ge); __ sub(r4, r4, Operand(1), SetCC, ge);
__ ldr(r3, MemOperand(sp, r4, LSL, kPointerSizeLog2), ge); // new.target __ ldr(r3, MemOperand(sp, r4, LSL, kPointerSizeLog2), ge); // new.target
__ add(sp, sp, Operand(r0, LSL, kPointerSizeLog2)); __ add(sp, sp, Operand(r0, LSL, kPointerSizeLog2));
__ mov(r0, r2);
} }
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r0 : argumentsList // -- r2 : argumentsList
// -- r3 : new.target // -- r3 : new.target
// -- r1 : target // -- r1 : target
// -- sp[0] : receiver (undefined) // -- sp[0] : receiver (undefined)
@ -2037,7 +2032,8 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
__ b(eq, &new_target_not_constructor); __ b(eq, &new_target_not_constructor);
// 4a. Construct the target with the given new.target and argumentsList. // 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. // 4b. The target is not a constructor, throw an appropriate TypeError.
__ bind(&target_not_constructor); __ bind(&target_not_constructor);
@ -2078,98 +2074,16 @@ static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
} }
// static // static
void Builtins::Generate_Apply(MacroAssembler* masm) { void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm,
Handle<Code> code) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r0 : argumentsList // -- r1 : target
// -- r1 : target // -- r0 : number of parameters on the stack (not including the receiver)
// -- r3 : new.target (checked to be constructor or undefined) // -- r2 : arguments list (a FixedArray)
// -- sp[0] : thisArgument // -- r4 : len (number of elements to push from args)
// -- r3 : new.target (for [[Construct]])
// ----------------------------------- // -----------------------------------
__ AssertFixedArray(r2);
// 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);
}
// Check for stack overflow. // Check for stack overflow.
{ {
@ -2181,51 +2095,38 @@ void Builtins::Generate_Apply(MacroAssembler* masm) {
// here which will cause ip to become negative. // here which will cause ip to become negative.
__ sub(ip, sp, ip); __ sub(ip, sp, ip);
// Check if the arguments will overflow the stack. // 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. __ b(gt, &done); // Signed comparison.
__ TailCallRuntime(Runtime::kThrowStackOverflow); __ TailCallRuntime(Runtime::kThrowStackOverflow);
__ bind(&done); __ 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). // Push arguments onto the stack (thisArgument is already on the stack).
{ {
__ mov(r4, Operand(0)); __ mov(r6, Operand(0));
__ LoadRoot(r5, Heap::kTheHoleValueRootIndex); __ LoadRoot(r5, Heap::kTheHoleValueRootIndex);
__ LoadRoot(r6, Heap::kUndefinedValueRootIndex);
Label done, loop; Label done, loop;
__ bind(&loop); __ bind(&loop);
__ cmp(r4, r2); __ cmp(r6, r4);
__ b(eq, &done); __ b(eq, &done);
__ add(ip, r0, Operand(r4, LSL, kPointerSizeLog2)); __ add(ip, r2, Operand(r6, LSL, kPointerSizeLog2));
__ ldr(ip, FieldMemOperand(ip, FixedArray::kHeaderSize)); __ ldr(ip, FieldMemOperand(ip, FixedArray::kHeaderSize));
__ cmp(r5, ip); __ cmp(ip, r5);
__ mov(ip, r6, LeaveCC, eq); __ LoadRoot(ip, Heap::kUndefinedValueRootIndex, eq);
__ Push(ip); __ Push(ip);
__ add(r4, r4, Operand(1)); __ add(r6, r6, Operand(1));
__ b(&loop); __ b(&loop);
__ bind(&done); __ bind(&done);
__ Move(r0, r4); __ add(r0, r0, r6);
} }
// Dispatch to Call or Construct depending on whether new.target is undefined. // Tail-call to the actual Call or Construct builtin.
{ __ Jump(code, RelocInfo::CODE_TARGET);
__ CompareRoot(r3, Heap::kUndefinedValueRootIndex);
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET, eq);
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
} }
// static // static
void Builtins::Generate_ForwardVarargs(MacroAssembler* masm, void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
Handle<Code> code) { Handle<Code> code) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r0 : the number of arguments (not including the receiver) // -- r0 : the number of arguments (not including the receiver)
// -- r3 : the new.target (for [[Construct]] calls) // -- r3 : the new.target (for [[Construct]] calls)

View File

@ -1880,16 +1880,16 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
ASM_LOCATION("Builtins::Generate_FunctionPrototypeApply"); ASM_LOCATION("Builtins::Generate_FunctionPrototypeApply");
Register argc = x0; Register argc = x0;
Register arg_array = x0; Register arg_array = x2;
Register receiver = x1; Register receiver = x1;
Register this_arg = x2; Register this_arg = x0;
Register undefined_value = x3; Register undefined_value = x3;
Register null_value = x4; Register null_value = x4;
__ LoadRoot(undefined_value, Heap::kUndefinedValueRootIndex); __ LoadRoot(undefined_value, Heap::kUndefinedValueRootIndex);
__ LoadRoot(null_value, Heap::kNullValueRootIndex); __ 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 // arguments from the stack (including the receiver), and push thisArg (if
// present) instead. // present) instead.
{ {
@ -1914,9 +1914,8 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
} }
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- x0 : argArray // -- x2 : argArray
// -- x1 : receiver // -- x1 : receiver
// -- x3 : undefined root value
// -- jssp[0] : thisArg // -- jssp[0] : thisArg
// ----------------------------------- // -----------------------------------
@ -1934,10 +1933,9 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
__ Ccmp(arg_array, undefined_value, ZFlag, ne); __ Ccmp(arg_array, undefined_value, ZFlag, ne);
__ B(eq, &no_arguments); __ B(eq, &no_arguments);
// 4a. Apply the receiver to the given argArray (passing undefined for // 4a. Apply the receiver to the given argArray.
// new.target in x3). __ Jump(masm->isolate()->builtins()->CallWithArrayLike(),
DCHECK(undefined_value.Is(x3)); RelocInfo::CODE_TARGET);
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
// 4b. The argArray is either null or undefined, so we tail call without any // 4b. The argArray is either null or undefined, so we tail call without any
// arguments to the receiver. // arguments to the receiver.
@ -2013,14 +2011,14 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
ASM_LOCATION("Builtins::Generate_ReflectApply"); ASM_LOCATION("Builtins::Generate_ReflectApply");
Register argc = x0; Register argc = x0;
Register arguments_list = x0; Register arguments_list = x2;
Register target = x1; Register target = x1;
Register this_argument = x2; Register this_argument = x4;
Register undefined_value = x3; Register undefined_value = x3;
__ LoadRoot(undefined_value, Heap::kUndefinedValueRootIndex); __ 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 // remove all arguments from the stack (including the receiver), and push
// thisArgument (if present) instead. // thisArgument (if present) instead.
{ {
@ -2047,7 +2045,7 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
} }
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- x0 : argumentsList // -- x2 : argumentsList
// -- x1 : target // -- x1 : target
// -- jssp[0] : thisArgument // -- jssp[0] : thisArgument
// ----------------------------------- // -----------------------------------
@ -2059,10 +2057,9 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
__ Ldr(x10, FieldMemOperand(x10, Map::kBitFieldOffset)); __ Ldr(x10, FieldMemOperand(x10, Map::kBitFieldOffset));
__ TestAndBranchIfAllClear(x10, 1 << Map::kIsCallable, &target_not_callable); __ TestAndBranchIfAllClear(x10, 1 << Map::kIsCallable, &target_not_callable);
// 3a. Apply the target to the given argumentsList (passing undefined for // 3a. Apply the target to the given argumentsList.
// new.target in x3). __ Jump(masm->isolate()->builtins()->CallWithArrayLike(),
DCHECK(undefined_value.Is(x3)); RelocInfo::CODE_TARGET);
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
// 3b. The target is not callable, throw an appropriate TypeError. // 3b. The target is not callable, throw an appropriate TypeError.
__ Bind(&target_not_callable); __ Bind(&target_not_callable);
@ -2083,14 +2080,14 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
ASM_LOCATION("Builtins::Generate_ReflectConstruct"); ASM_LOCATION("Builtins::Generate_ReflectConstruct");
Register argc = x0; Register argc = x0;
Register arguments_list = x0; Register arguments_list = x2;
Register target = x1; Register target = x1;
Register new_target = x3; Register new_target = x3;
Register undefined_value = x4; Register undefined_value = x4;
__ LoadRoot(undefined_value, Heap::kUndefinedValueRootIndex); __ 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 // new.target into x3 (if present, otherwise use target), remove all
// arguments from the stack (including the receiver), and push thisArgument // arguments from the stack (including the receiver), and push thisArgument
// (if present) instead. // (if present) instead.
@ -2118,7 +2115,7 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
} }
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- x0 : argumentsList // -- x2 : argumentsList
// -- x1 : target // -- x1 : target
// -- x3 : new.target // -- x3 : new.target
// -- jssp[0] : receiver (undefined) // -- jssp[0] : receiver (undefined)
@ -2141,7 +2138,8 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
&new_target_not_constructor); &new_target_not_constructor);
// 4a. Construct the target with the given new.target and argumentsList. // 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. // 4b. The target is not a constructor, throw an appropriate TypeError.
__ Bind(&target_not_constructor); __ Bind(&target_not_constructor);
@ -2182,113 +2180,20 @@ static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
} }
// static // static
void Builtins::Generate_Apply(MacroAssembler* masm) { void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm,
Handle<Code> code) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- x0 : argumentsList // -- x1 : target
// -- x1 : target // -- x0 : number of parameters on the stack (not including the receiver)
// -- x3 : new.target (checked to be constructor or undefined) // -- x2 : arguments list (a FixedArray)
// -- jssp[0] : thisArgument // -- x4 : len (number of elements to push from args)
// -- x3 : new.target (for [[Construct]])
// ----------------------------------- // -----------------------------------
__ AssertFixedArray(x2);
Register arguments_list = x0; Register arguments_list = x2;
Register target = x1; Register argc = x0;
Register new_target = x3; Register len = x4;
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);
}
// Check for stack overflow. // Check for stack overflow.
{ {
@ -2306,21 +2211,13 @@ void Builtins::Generate_Apply(MacroAssembler* masm) {
__ Bind(&done); __ 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). // Push arguments onto the stack (thisArgument is already on the stack).
{ {
Label done, push, loop; Label done, push, loop;
Register src = x4; Register src = x5;
__ Add(src, args, FixedArray::kHeaderSize - kHeapObjectTag); __ Add(src, arguments_list, FixedArray::kHeaderSize - kHeapObjectTag);
__ Mov(x0, len); // The 'len' argument for Call() or Construct(). __ Add(argc, argc, len); // The 'len' argument for Call() or Construct().
__ Cbz(len, &done); __ Cbz(len, &done);
Register the_hole_value = x11; Register the_hole_value = x11;
Register undefined_value = x12; Register undefined_value = x12;
@ -2339,28 +2236,13 @@ void Builtins::Generate_Apply(MacroAssembler* masm) {
__ Bind(&done); __ Bind(&done);
} }
// ----------- S t a t e ------------- // Tail-call to the actual Call or Construct builtin.
// -- x0 : argument count (len) __ Jump(code, RelocInfo::CODE_TARGET);
// -- 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);
}
} }
// static // static
void Builtins::Generate_ForwardVarargs(MacroAssembler* masm, void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
Handle<Code> code) { Handle<Code> code) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- x0 : the number of arguments (not including the receiver) // -- x0 : the number of arguments (not including the receiver)
// -- x3 : the new.target (for [[Construct]] calls) // -- x3 : the new.target (for [[Construct]] calls)

View File

@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // 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/builtins/builtins.h"
#include "src/globals.h" #include "src/globals.h"
#include "src/isolate.h" #include "src/isolate.h"
@ -82,12 +85,132 @@ void Builtins::Generate_TailCall_ReceiverIsAny(MacroAssembler* masm) {
Generate_Call(masm, ConvertReceiverMode::kAny, TailCallMode::kAllow); 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) { 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) { 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 } // namespace internal

View 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_

View File

@ -5,6 +5,7 @@
#include "src/builtins/builtins-constructor-gen.h" #include "src/builtins/builtins-constructor-gen.h"
#include "src/ast/ast.h" #include "src/ast/ast.h"
#include "src/builtins/builtins-call-gen.h"
#include "src/builtins/builtins-constructor.h" #include "src/builtins/builtins-constructor.h"
#include "src/builtins/builtins-utils-gen.h" #include "src/builtins/builtins-utils-gen.h"
#include "src/builtins/builtins.h" #include "src/builtins/builtins.h"
@ -17,13 +18,28 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
void Builtins::Generate_ConstructVarargs(MacroAssembler* masm) {
Generate_CallOrConstructVarargs(masm,
masm->isolate()->builtins()->Construct());
}
void Builtins::Generate_ConstructForwardVarargs(MacroAssembler* masm) { 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) { void Builtins::Generate_ConstructFunctionForwardVarargs(MacroAssembler* masm) {
Generate_ForwardVarargs(masm, Generate_CallOrConstructForwardVarargs(
masm->isolate()->builtins()->ConstructFunction()); 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; typedef compiler::Node Node;

View File

@ -75,7 +75,9 @@ namespace internal {
ASM(TailCall_ReceiverIsNullOrUndefined) \ ASM(TailCall_ReceiverIsNullOrUndefined) \
ASM(TailCall_ReceiverIsNotNullOrUndefined) \ ASM(TailCall_ReceiverIsNotNullOrUndefined) \
ASM(TailCall_ReceiverIsAny) \ ASM(TailCall_ReceiverIsAny) \
ASM(CallVarargs) \
ASM(CallWithSpread) \ ASM(CallWithSpread) \
TFC(CallWithArrayLike, CallWithArrayLike, 1) \
ASM(CallForwardVarargs) \ ASM(CallForwardVarargs) \
ASM(CallFunctionForwardVarargs) \ ASM(CallFunctionForwardVarargs) \
\ \
@ -89,7 +91,9 @@ namespace internal {
ASM(ConstructProxy) \ ASM(ConstructProxy) \
/* ES6 section 7.3.13 Construct (F, [argumentsList], [newTarget]) */ \ /* ES6 section 7.3.13 Construct (F, [argumentsList], [newTarget]) */ \
ASM(Construct) \ ASM(Construct) \
ASM(ConstructVarargs) \
ASM(ConstructWithSpread) \ ASM(ConstructWithSpread) \
TFC(ConstructWithArrayLike, ConstructWithArrayLike, 1) \
ASM(ConstructForwardVarargs) \ ASM(ConstructForwardVarargs) \
ASM(ConstructFunctionForwardVarargs) \ ASM(ConstructFunctionForwardVarargs) \
ASM(JSConstructStubApi) \ ASM(JSConstructStubApi) \
@ -108,7 +112,6 @@ namespace internal {
TFC(FastCloneShallowObject, FastCloneShallowObject, 1) \ TFC(FastCloneShallowObject, FastCloneShallowObject, 1) \
\ \
/* Apply and entries */ \ /* Apply and entries */ \
ASM(Apply) \
ASM(JSEntryTrampoline) \ ASM(JSEntryTrampoline) \
ASM(JSConstructEntryTrampoline) \ ASM(JSConstructEntryTrampoline) \
ASM(ResumeGeneratorTrampoline) \ ASM(ResumeGeneratorTrampoline) \

View File

@ -132,7 +132,10 @@ class Builtins {
static void Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode, static void Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
TailCallMode tail_call_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( static void Generate_InterpreterPushArgsThenCallImpl(
MacroAssembler* masm, ConvertReceiverMode receiver_mode, MacroAssembler* masm, ConvertReceiverMode receiver_mode,

View File

@ -1588,7 +1588,7 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
// -- esp[12] : receiver // -- 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 // arguments from the stack (including the receiver), and push thisArg (if
// present) instead. // present) instead.
{ {
@ -1610,11 +1610,10 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
__ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize)); __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
__ Push(edx); __ Push(edx);
__ PushReturnAddressFrom(ecx); __ PushReturnAddressFrom(ecx);
__ Move(eax, ebx);
} }
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- eax : argArray // -- ebx : argArray
// -- edi : receiver // -- edi : receiver
// -- esp[0] : return address // -- esp[0] : return address
// -- esp[4] : thisArg // -- 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. // 3. Tail call with no arguments if argArray is null or undefined.
Label no_arguments; Label no_arguments;
__ JumpIfRoot(eax, Heap::kNullValueRootIndex, &no_arguments, Label::kNear); __ JumpIfRoot(ebx, Heap::kNullValueRootIndex, &no_arguments, Label::kNear);
__ JumpIfRoot(eax, Heap::kUndefinedValueRootIndex, &no_arguments, __ JumpIfRoot(ebx, Heap::kUndefinedValueRootIndex, &no_arguments,
Label::kNear); Label::kNear);
// 4a. Apply the receiver to the given argArray (passing undefined for // 4a. Apply the receiver to the given argArray.
// new.target). __ Jump(masm->isolate()->builtins()->CallWithArrayLike(),
__ LoadRoot(edx, Heap::kUndefinedValueRootIndex); RelocInfo::CODE_TARGET);
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
// 4b. The argArray is either null or undefined, so we tail call without any // 4b. The argArray is either null or undefined, so we tail call without any
// arguments to the receiver. // arguments to the receiver.
@ -1711,7 +1709,7 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
// -- esp[16] : receiver // -- 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 // remove all arguments from the stack (including the receiver), and push
// thisArgument (if present) instead. // thisArgument (if present) instead.
{ {
@ -1732,11 +1730,10 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
__ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize)); __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
__ Push(edx); __ Push(edx);
__ PushReturnAddressFrom(ecx); __ PushReturnAddressFrom(ecx);
__ Move(eax, ebx);
} }
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- eax : argumentsList // -- ebx : argumentsList
// -- edi : target // -- edi : target
// -- esp[0] : return address // -- esp[0] : return address
// -- esp[4] : thisArgument // -- esp[4] : thisArgument
@ -1750,10 +1747,9 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
Immediate(1 << Map::kIsCallable)); Immediate(1 << Map::kIsCallable));
__ j(zero, &target_not_callable, Label::kNear); __ j(zero, &target_not_callable, Label::kNear);
// 3a. Apply the target to the given argumentsList (passing undefined for // 3a. Apply the target to the given argumentsList.
// new.target). __ Jump(masm->isolate()->builtins()->CallWithArrayLike(),
__ LoadRoot(edx, Heap::kUndefinedValueRootIndex); RelocInfo::CODE_TARGET);
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
// 3b. The target is not callable, throw an appropriate TypeError. // 3b. The target is not callable, throw an appropriate TypeError.
__ bind(&target_not_callable); __ bind(&target_not_callable);
@ -1773,7 +1769,7 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
// -- esp[16] : receiver // -- 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 // new.target into edx (if present, otherwise use target), remove all
// arguments from the stack (including the receiver), and push thisArgument // arguments from the stack (including the receiver), and push thisArgument
// (if present) instead. // (if present) instead.
@ -1796,11 +1792,10 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
__ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize)); __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
__ PushRoot(Heap::kUndefinedValueRootIndex); __ PushRoot(Heap::kUndefinedValueRootIndex);
__ PushReturnAddressFrom(ecx); __ PushReturnAddressFrom(ecx);
__ Move(eax, ebx);
} }
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- eax : argumentsList // -- ebx : argumentsList
// -- edx : new.target // -- edx : new.target
// -- edi : target // -- edi : target
// -- esp[0] : return address // -- esp[0] : return address
@ -1824,7 +1819,8 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
__ j(zero, &new_target_not_constructor, Label::kNear); __ j(zero, &new_target_not_constructor, Label::kNear);
// 4a. Construct the target with the given new.target and argumentsList. // 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. // 4b. The target is not a constructor, throw an appropriate TypeError.
__ bind(&target_not_constructor); __ bind(&target_not_constructor);
@ -2223,97 +2219,22 @@ static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
} }
// static // static
void Builtins::Generate_Apply(MacroAssembler* masm) { void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm,
Handle<Code> code) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- eax : argumentsList
// -- edi : target // -- 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) // -- edx : new.target (checked to be constructor or undefined)
// -- esp[0] : return address. // -- esp[0] : return address.
// -- esp[4] : thisArgument
// ----------------------------------- // -----------------------------------
__ AssertFixedArray(ebx);
// Create the list of arguments from the array-like argumentsList. // We need to preserve eax, edi and ebx.
{ __ movd(xmm0, edx);
Label create_arguments, create_array, create_holey_array, create_runtime, __ movd(xmm1, edi);
done_create; __ movd(xmm2, eax);
__ 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);
}
// Check for stack overflow. // Check for stack overflow.
{ {
@ -2322,66 +2243,56 @@ void Builtins::Generate_Apply(MacroAssembler* masm) {
Label done; Label done;
ExternalReference real_stack_limit = ExternalReference real_stack_limit =
ExternalReference::address_of_real_stack_limit(masm->isolate()); ExternalReference::address_of_real_stack_limit(masm->isolate());
__ mov(ecx, Operand::StaticVariable(real_stack_limit)); __ mov(edx, Operand::StaticVariable(real_stack_limit));
// Make ecx the space we have left. The stack might already be overflowed // Make edx the space we have left. The stack might already be overflowed
// here which will cause ecx to become negative. // here which will cause edx to become negative.
__ neg(ecx); __ neg(edx);
__ add(ecx, esp); __ add(edx, esp);
__ sar(ecx, kPointerSizeLog2); __ sar(edx, kPointerSizeLog2);
// Check if the arguments will overflow the stack. // Check if the arguments will overflow the stack.
__ cmp(ecx, ebx); __ cmp(edx, ecx);
__ j(greater, &done, Label::kNear); // Signed comparison. __ j(greater, &done, Label::kNear); // Signed comparison.
__ TailCallRuntime(Runtime::kThrowStackOverflow); __ TailCallRuntime(Runtime::kThrowStackOverflow);
__ bind(&done); __ bind(&done);
} }
// ----------- S t a t e ------------- // Push additional arguments onto the stack.
// -- 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).
{ {
__ movd(xmm0, edx);
__ movd(xmm1, edi);
__ PopReturnAddressTo(edx); __ PopReturnAddressTo(edx);
__ Move(ecx, Immediate(0)); __ Move(eax, Immediate(0));
Label done, push, loop; Label done, push, loop;
__ bind(&loop); __ bind(&loop);
__ cmp(ecx, ebx); __ cmp(eax, ecx);
__ j(equal, &done, Label::kNear); __ j(equal, &done, Label::kNear);
// Turn the hole into undefined as we go. // Turn the hole into undefined as we go.
__ mov(edi, __ mov(edi,
FieldOperand(eax, ecx, times_pointer_size, FixedArray::kHeaderSize)); FieldOperand(ebx, eax, times_pointer_size, FixedArray::kHeaderSize));
__ CompareRoot(edi, Heap::kTheHoleValueRootIndex); __ CompareRoot(edi, Heap::kTheHoleValueRootIndex);
__ j(not_equal, &push, Label::kNear); __ j(not_equal, &push, Label::kNear);
__ LoadRoot(edi, Heap::kUndefinedValueRootIndex); __ LoadRoot(edi, Heap::kUndefinedValueRootIndex);
__ bind(&push); __ bind(&push);
__ Push(edi); __ Push(edi);
__ inc(ecx); __ inc(eax);
__ jmp(&loop); __ jmp(&loop);
__ bind(&done); __ bind(&done);
__ PushReturnAddressFrom(edx); __ PushReturnAddressFrom(edx);
__ movd(edi, xmm1);
__ movd(edx, xmm0);
__ Move(eax, ebx);
} }
// Dispatch to Call or Construct depending on whether new.target is undefined. // Restore eax, edi and edx.
{ __ movd(eax, xmm2);
__ CompareRoot(edx, Heap::kUndefinedValueRootIndex); __ movd(edi, xmm1);
__ j(equal, masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); __ movd(edx, xmm0);
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
} // Compute the actual parameter count.
__ add(eax, ecx);
// Tail-call to the actual Call or Construct builtin.
__ Jump(code, RelocInfo::CODE_TARGET);
} }
// static // static
void Builtins::Generate_ForwardVarargs(MacroAssembler* masm, void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
Handle<Code> code) { Handle<Code> code) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver) // -- eax : the number of arguments (not including the receiver)
// -- edi : the target to call (can be any Object) // -- edi : the target to call (can be any Object)

View File

@ -1840,11 +1840,11 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
__ bind(&no_arg); __ bind(&no_arg);
__ Addu(sp, sp, Operand(scratch)); __ Addu(sp, sp, Operand(scratch));
__ sw(a2, MemOperand(sp)); __ sw(a2, MemOperand(sp));
__ mov(a0, a3); __ mov(a2, a3);
} }
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- a0 : argArray // -- a2 : argArray
// -- a1 : receiver // -- a1 : receiver
// -- sp[0] : thisArg // -- 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. // 3. Tail call with no arguments if argArray is null or undefined.
Label no_arguments; Label no_arguments;
__ JumpIfRoot(a0, Heap::kNullValueRootIndex, &no_arguments); __ JumpIfRoot(a2, Heap::kNullValueRootIndex, &no_arguments);
__ JumpIfRoot(a0, Heap::kUndefinedValueRootIndex, &no_arguments); __ JumpIfRoot(a2, Heap::kUndefinedValueRootIndex, &no_arguments);
// 4a. Apply the receiver to the given argArray (passing undefined for // 4a. Apply the receiver to the given argArray.
// new.target). __ Jump(masm->isolate()->builtins()->CallWithArrayLike(),
__ LoadRoot(a3, Heap::kUndefinedValueRootIndex); RelocInfo::CODE_TARGET);
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
// 4b. The argArray is either null or undefined, so we tail call without any // 4b. The argArray is either null or undefined, so we tail call without any
// arguments to the receiver. // arguments to the receiver.
@ -1958,11 +1957,11 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
__ bind(&no_arg); __ bind(&no_arg);
__ Addu(sp, sp, Operand(scratch)); __ Addu(sp, sp, Operand(scratch));
__ sw(a2, MemOperand(sp)); __ sw(a2, MemOperand(sp));
__ mov(a0, a3); __ mov(a2, a3);
} }
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- a0 : argumentsList // -- a2 : argumentsList
// -- a1 : target // -- a1 : target
// -- sp[0] : thisArgument // -- sp[0] : thisArgument
// ----------------------------------- // -----------------------------------
@ -1975,10 +1974,9 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
__ And(t0, t0, Operand(1 << Map::kIsCallable)); __ And(t0, t0, Operand(1 << Map::kIsCallable));
__ Branch(&target_not_callable, eq, t0, Operand(zero_reg)); __ Branch(&target_not_callable, eq, t0, Operand(zero_reg));
// 3a. Apply the target to the given argumentsList (passing undefined for // 3a. Apply the target to the given argumentsList.
// new.target). __ Jump(masm->isolate()->builtins()->CallWithArrayLike(),
__ LoadRoot(a3, Heap::kUndefinedValueRootIndex); RelocInfo::CODE_TARGET);
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
// 3b. The target is not callable, throw an appropriate TypeError. // 3b. The target is not callable, throw an appropriate TypeError.
__ bind(&target_not_callable); __ bind(&target_not_callable);
@ -2022,11 +2020,10 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
__ lw(a3, MemOperand(a0)); // new.target __ lw(a3, MemOperand(a0)); // new.target
__ bind(&no_arg); __ bind(&no_arg);
__ Addu(sp, sp, Operand(scratch)); __ Addu(sp, sp, Operand(scratch));
__ mov(a0, a2);
} }
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- a0 : argumentsList // -- a2 : argumentsList
// -- a3 : new.target // -- a3 : new.target
// -- a1 : target // -- a1 : target
// -- sp[0] : receiver (undefined) // -- sp[0] : receiver (undefined)
@ -2049,7 +2046,8 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
__ Branch(&new_target_not_constructor, eq, t0, Operand(zero_reg)); __ Branch(&new_target_not_constructor, eq, t0, Operand(zero_reg));
// 4a. Construct the target with the given new.target and argumentsList. // 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. // 4b. The target is not a constructor, throw an appropriate TypeError.
__ bind(&target_not_constructor); __ bind(&target_not_constructor);
@ -2090,149 +2088,59 @@ static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
} }
// static // static
void Builtins::Generate_Apply(MacroAssembler* masm) { void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm,
Handle<Code> code) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- a0 : argumentsList // -- a1 : target
// -- a1 : target // -- a0 : number of parameters on the stack (not including the receiver)
// -- a3 : new.target (checked to be constructor or undefined) // -- a2 : arguments list (a FixedArray)
// -- sp[0] : thisArgument // -- t0 : len (number of elements to push from args)
// -- a3 : new.target (for [[Construct]])
// ----------------------------------- // -----------------------------------
__ AssertFixedArray(a2);
// 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);
}
// Check for stack overflow. // Check for stack overflow.
{ {
// Check the stack for overflow. We are not trying to catch interruptions // 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". // (i.e. debug break and preemption) here, so check the "real stack limit".
Label done; Label done;
__ LoadRoot(t0, Heap::kRealStackLimitRootIndex); __ LoadRoot(t1, Heap::kRealStackLimitRootIndex);
// Make ip the space we have left. The stack might already be overflowed // Make ip the space we have left. The stack might already be overflowed
// here which will cause ip to become negative. // here which will cause ip to become negative.
__ Subu(t0, sp, t0); __ Subu(t1, sp, t1);
// Check if the arguments will overflow the stack. // Check if the arguments will overflow the stack.
__ sll(at, a2, kPointerSizeLog2); __ sll(at, t0, kPointerSizeLog2);
__ Branch(&done, gt, t0, Operand(at)); // Signed comparison. __ Branch(&done, gt, t1, Operand(at)); // Signed comparison.
__ TailCallRuntime(Runtime::kThrowStackOverflow); __ TailCallRuntime(Runtime::kThrowStackOverflow);
__ bind(&done); __ 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). // Push arguments onto the stack (thisArgument is already on the stack).
{ {
__ mov(t0, zero_reg); __ mov(t2, zero_reg);
Label done, push, loop; Label done, push, loop;
__ LoadRoot(t1, Heap::kTheHoleValueRootIndex); __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
__ bind(&loop); __ bind(&loop);
__ Branch(&done, eq, t0, Operand(a2)); __ Branch(&done, eq, t2, Operand(t0));
__ Lsa(at, a0, t0, kPointerSizeLog2); __ Lsa(at, a2, t2, kPointerSizeLog2);
__ lw(at, FieldMemOperand(at, FixedArray::kHeaderSize)); __ lw(at, FieldMemOperand(at, FixedArray::kHeaderSize));
__ Branch(&push, ne, t1, Operand(at)); __ Branch(&push, ne, t1, Operand(at));
__ LoadRoot(at, Heap::kUndefinedValueRootIndex); __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
__ bind(&push); __ bind(&push);
__ Push(at); __ Push(at);
__ Addu(t0, t0, Operand(1)); __ Addu(t2, t2, Operand(1));
__ Branch(&loop); __ Branch(&loop);
__ bind(&done); __ bind(&done);
__ Move(a0, t0); __ Addu(a0, a0, t2);
} }
// Dispatch to Call or Construct depending on whether new.target is undefined. // Tail-call to the actual Call or Construct builtin.
{ __ Jump(code, RelocInfo::CODE_TARGET);
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);
}
} }
// static // static
void Builtins::Generate_ForwardVarargs(MacroAssembler* masm, void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
Handle<Code> code) { Handle<Code> code) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver) // -- a0 : the number of arguments (not including the receiver)
// -- a3 : the new.target (for [[Construct]] calls) // -- a3 : the new.target (for [[Construct]] calls)

View File

@ -1823,14 +1823,14 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
// ----------------------------------- // -----------------------------------
Register argc = a0; Register argc = a0;
Register arg_array = a0; Register arg_array = a2;
Register receiver = a1; Register receiver = a1;
Register this_arg = a2; Register this_arg = a5;
Register undefined_value = a3; Register undefined_value = a3;
Register scratch = a4; Register scratch = a4;
__ LoadRoot(undefined_value, Heap::kUndefinedValueRootIndex); __ 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 // arguments from the stack (including the receiver), and push thisArg (if
// present) instead. // present) instead.
{ {
@ -1850,7 +1850,7 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
} }
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- a0 : argArray // -- a2 : argArray
// -- a1 : receiver // -- a1 : receiver
// -- a3 : undefined root value // -- a3 : undefined root value
// -- sp[0] : thisArg // -- sp[0] : thisArg
@ -1869,10 +1869,9 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
__ JumpIfRoot(arg_array, Heap::kNullValueRootIndex, &no_arguments); __ JumpIfRoot(arg_array, Heap::kNullValueRootIndex, &no_arguments);
__ Branch(&no_arguments, eq, arg_array, Operand(undefined_value)); __ Branch(&no_arguments, eq, arg_array, Operand(undefined_value));
// 4a. Apply the receiver to the given argArray (passing undefined for // 4a. Apply the receiver to the given argArray.
// new.target). __ Jump(masm->isolate()->builtins()->CallWithArrayLike(),
DCHECK(undefined_value.is(a3)); RelocInfo::CODE_TARGET);
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
// 4b. The argArray is either null or undefined, so we tail call without any // 4b. The argArray is either null or undefined, so we tail call without any
// arguments to the receiver. // arguments to the receiver.
@ -1943,14 +1942,14 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
// ----------------------------------- // -----------------------------------
Register argc = a0; Register argc = a0;
Register arguments_list = a0; Register arguments_list = a2;
Register target = a1; Register target = a1;
Register this_argument = a2; Register this_argument = a5;
Register undefined_value = a3; Register undefined_value = a3;
Register scratch = a4; Register scratch = a4;
__ LoadRoot(undefined_value, Heap::kUndefinedValueRootIndex); __ 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 // remove all arguments from the stack (including the receiver), and push
// thisArgument (if present) instead. // thisArgument (if present) instead.
{ {
@ -1974,7 +1973,7 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
} }
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- a0 : argumentsList // -- a2 : argumentsList
// -- a1 : target // -- a1 : target
// -- a3 : undefined root value // -- a3 : undefined root value
// -- sp[0] : thisArgument // -- sp[0] : thisArgument
@ -1988,10 +1987,9 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
__ And(a4, a4, Operand(1 << Map::kIsCallable)); __ And(a4, a4, Operand(1 << Map::kIsCallable));
__ Branch(&target_not_callable, eq, a4, Operand(zero_reg)); __ Branch(&target_not_callable, eq, a4, Operand(zero_reg));
// 3a. Apply the target to the given argumentsList (passing undefined for // 3a. Apply the target to the given argumentsList.
// new.target). __ Jump(masm->isolate()->builtins()->CallWithArrayLike(),
DCHECK(undefined_value.is(a3)); RelocInfo::CODE_TARGET);
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
// 3b. The target is not callable, throw an appropriate TypeError. // 3b. The target is not callable, throw an appropriate TypeError.
__ bind(&target_not_callable); __ bind(&target_not_callable);
@ -2010,13 +2008,13 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
// -- sp[12] : receiver // -- sp[12] : receiver
// ----------------------------------- // -----------------------------------
Register argc = a0; Register argc = a0;
Register arguments_list = a0; Register arguments_list = a2;
Register target = a1; Register target = a1;
Register new_target = a3; Register new_target = a3;
Register undefined_value = a4; Register undefined_value = a4;
Register scratch = a5; 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 // new.target into a3 (if present, otherwise use target), remove all
// arguments from the stack (including the receiver), and push thisArgument // arguments from the stack (including the receiver), and push thisArgument
// (if present) instead. // (if present) instead.
@ -2041,7 +2039,7 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
} }
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- a0 : argumentsList // -- a2 : argumentsList
// -- a1 : target // -- a1 : target
// -- a3 : new.target // -- a3 : new.target
// -- sp[0] : receiver (undefined) // -- sp[0] : receiver (undefined)
@ -2064,7 +2062,8 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
__ Branch(&new_target_not_constructor, eq, a4, Operand(zero_reg)); __ Branch(&new_target_not_constructor, eq, a4, Operand(zero_reg));
// 4a. Construct the target with the given new.target and argumentsList. // 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. // 4b. The target is not a constructor, throw an appropriate TypeError.
__ bind(&target_not_constructor); __ bind(&target_not_constructor);
@ -2107,135 +2106,45 @@ static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
} }
// static // static
void Builtins::Generate_Apply(MacroAssembler* masm) { void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm,
Handle<Code> code) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- a0 : argumentsList // -- a1 : target
// -- a1 : target // -- a0 : number of parameters on the stack (not including the receiver)
// -- a3 : new.target (checked to be constructor or undefined) // -- a2 : arguments list (a FixedArray)
// -- sp[0] : thisArgument // -- a4 : len (number of elements to push from args)
// -- a3 : new.target (for [[Construct]])
// ----------------------------------- // -----------------------------------
__ AssertFixedArray(a2);
Register arguments_list = a0; Register args = a2;
Register target = a1; Register len = a4;
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);
}
// Check for stack overflow. // Check for stack overflow.
{ {
// Check the stack for overflow. We are not trying to catch interruptions // 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". // (i.e. debug break and preemption) here, so check the "real stack limit".
Label done; Label done;
__ LoadRoot(a4, Heap::kRealStackLimitRootIndex); __ LoadRoot(a5, Heap::kRealStackLimitRootIndex);
// Make ip the space we have left. The stack might already be overflowed // Make ip the space we have left. The stack might already be overflowed
// here which will cause ip to become negative. // here which will cause ip to become negative.
__ Dsubu(a4, sp, a4); __ Dsubu(a5, sp, a5);
// Check if the arguments will overflow the stack. // Check if the arguments will overflow the stack.
__ dsll(at, len, kPointerSizeLog2); __ dsll(at, len, kPointerSizeLog2);
__ Branch(&done, gt, a4, Operand(at)); // Signed comparison. __ Branch(&done, gt, a5, Operand(at)); // Signed comparison.
__ TailCallRuntime(Runtime::kThrowStackOverflow); __ TailCallRuntime(Runtime::kThrowStackOverflow);
__ bind(&done); __ 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). // Push arguments onto the stack (thisArgument is already on the stack).
{ {
Label done, push, loop; Label done, push, loop;
Register src = a4; Register src = a6;
Register scratch = len; Register scratch = len;
__ daddiu(src, args, FixedArray::kHeaderSize - kHeapObjectTag); __ daddiu(src, args, FixedArray::kHeaderSize - kHeapObjectTag);
__ Branch(&done, eq, len, Operand(zero_reg), i::USE_DELAY_SLOT); __ 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); __ dsll(scratch, len, kPointerSizeLog2);
__ Dsubu(scratch, sp, Operand(scratch)); __ Dsubu(scratch, sp, Operand(scratch));
__ LoadRoot(t1, Heap::kTheHoleValueRootIndex); __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
@ -2250,31 +2159,13 @@ void Builtins::Generate_Apply(MacroAssembler* masm) {
__ bind(&done); __ bind(&done);
} }
// ----------- S t a t e ------------- // Tail-call to the actual Call or Construct builtin.
// -- a0 : argument count (len) __ Jump(code, RelocInfo::CODE_TARGET);
// -- 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);
}
} }
// static // static
void Builtins::Generate_ForwardVarargs(MacroAssembler* masm, void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
Handle<Code> code) { Handle<Code> code) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver) // -- a0 : the number of arguments (not including the receiver)
// -- a3 : the new.target (for [[Construct]] calls) // -- a3 : the new.target (for [[Construct]] calls)

View File

@ -1553,7 +1553,7 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
// -- rsp[24] : receiver // -- 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 // arguments from the stack (including the receiver), and push thisArg (if
// present) instead. // present) instead.
{ {
@ -1576,11 +1576,10 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
__ leap(rsp, Operand(rsp, rax, times_pointer_size, kPointerSize)); __ leap(rsp, Operand(rsp, rax, times_pointer_size, kPointerSize));
__ Push(rdx); __ Push(rdx);
__ PushReturnAddressFrom(rcx); __ PushReturnAddressFrom(rcx);
__ movp(rax, rbx);
} }
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- rax : argArray // -- rbx : argArray
// -- rdi : receiver // -- rdi : receiver
// -- rsp[0] : return address // -- rsp[0] : return address
// -- rsp[8] : thisArg // -- 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. // 3. Tail call with no arguments if argArray is null or undefined.
Label no_arguments; Label no_arguments;
__ JumpIfRoot(rax, Heap::kNullValueRootIndex, &no_arguments, Label::kNear); __ JumpIfRoot(rbx, Heap::kNullValueRootIndex, &no_arguments, Label::kNear);
__ JumpIfRoot(rax, Heap::kUndefinedValueRootIndex, &no_arguments, __ JumpIfRoot(rbx, Heap::kUndefinedValueRootIndex, &no_arguments,
Label::kNear); Label::kNear);
// 4a. Apply the receiver to the given argArray (passing undefined for // 4a. Apply the receiver to the given argArray.
// new.target). __ Jump(masm->isolate()->builtins()->CallWithArrayLike(),
__ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); RelocInfo::CODE_TARGET);
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
// 4b. The argArray is either null or undefined, so we tail call without any // 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 // 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 // -- 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 // remove all arguments from the stack (including the receiver), and push
// thisArgument (if present) instead. // thisArgument (if present) instead.
{ {
@ -1707,11 +1705,10 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
__ leap(rsp, Operand(rsp, rax, times_pointer_size, kPointerSize)); __ leap(rsp, Operand(rsp, rax, times_pointer_size, kPointerSize));
__ Push(rdx); __ Push(rdx);
__ PushReturnAddressFrom(rcx); __ PushReturnAddressFrom(rcx);
__ movp(rax, rbx);
} }
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- rax : argumentsList // -- rbx : argumentsList
// -- rdi : target // -- rdi : target
// -- rsp[0] : return address // -- rsp[0] : return address
// -- rsp[8] : thisArgument // -- rsp[8] : thisArgument
@ -1725,10 +1722,9 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
Immediate(1 << Map::kIsCallable)); Immediate(1 << Map::kIsCallable));
__ j(zero, &target_not_callable, Label::kNear); __ j(zero, &target_not_callable, Label::kNear);
// 3a. Apply the target to the given argumentsList (passing undefined for // 3a. Apply the target to the given argumentsList.
// new.target). __ Jump(masm->isolate()->builtins()->CallWithArrayLike(),
__ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); RelocInfo::CODE_TARGET);
__ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
// 3b. The target is not callable, throw an appropriate TypeError. // 3b. The target is not callable, throw an appropriate TypeError.
__ bind(&target_not_callable); __ bind(&target_not_callable);
@ -1749,7 +1745,7 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
// -- rsp[32] : receiver // -- 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 // new.target into rdx (if present, otherwise use target), remove all
// arguments from the stack (including the receiver), and push thisArgument // arguments from the stack (including the receiver), and push thisArgument
// (if present) instead. // (if present) instead.
@ -1773,11 +1769,10 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
__ leap(rsp, Operand(rsp, rax, times_pointer_size, kPointerSize)); __ leap(rsp, Operand(rsp, rax, times_pointer_size, kPointerSize));
__ PushRoot(Heap::kUndefinedValueRootIndex); __ PushRoot(Heap::kUndefinedValueRootIndex);
__ PushReturnAddressFrom(rcx); __ PushReturnAddressFrom(rcx);
__ movp(rax, rbx);
} }
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- rax : argumentsList // -- rbx : argumentsList
// -- rdx : new.target // -- rdx : new.target
// -- rdi : target // -- rdi : target
// -- rsp[0] : return address // -- rsp[0] : return address
@ -1801,7 +1796,8 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
__ j(zero, &new_target_not_constructor, Label::kNear); __ j(zero, &new_target_not_constructor, Label::kNear);
// 4a. Construct the target with the given new.target and argumentsList. // 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. // 4b. The target is not a constructor, throw an appropriate TypeError.
__ bind(&target_not_constructor); __ bind(&target_not_constructor);
@ -2339,94 +2335,17 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
} }
// static // static
void Builtins::Generate_Apply(MacroAssembler* masm) { void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm,
Handle<Code> code) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- rax : argumentsList
// -- rdi : target // -- rdi : target
// -- rdx : new.target (checked to be constructor or undefined) // -- rax : number of parameters on the stack (not including the receiver)
// -- rsp[0] : return address. // -- rbx : arguments list (a FixedArray)
// -- rsp[8] : thisArgument // -- rcx : len (number of elements to push from args)
// -- rdx : new.target (for [[Construct]])
// -- rsp[0] : return address
// ----------------------------------- // -----------------------------------
__ AssertFixedArray(rbx);
// 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);
}
// Check for stack overflow. // 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". // (i.e. debug break and preemption) here, so check the "real stack limit".
Label done; Label done;
__ LoadRoot(kScratchRegister, Heap::kRealStackLimitRootIndex); __ LoadRoot(kScratchRegister, Heap::kRealStackLimitRootIndex);
__ movp(rcx, rsp); __ movp(r8, rsp);
// Make rcx the space we have left. The stack might already be overflowed // Make r8 the space we have left. The stack might already be overflowed
// here which will cause rcx to become negative. // here which will cause r8 to become negative.
__ subp(rcx, kScratchRegister); __ subp(r8, kScratchRegister);
__ sarp(rcx, Immediate(kPointerSizeLog2)); __ sarp(r8, Immediate(kPointerSizeLog2));
// Check if the arguments will overflow the stack. // Check if the arguments will overflow the stack.
__ cmpp(rcx, rbx); __ cmpp(r8, rcx);
__ j(greater, &done, Label::kNear); // Signed comparison. __ j(greater, &done, Label::kNear); // Signed comparison.
__ TailCallRuntime(Runtime::kThrowStackOverflow); __ TailCallRuntime(Runtime::kThrowStackOverflow);
__ bind(&done); __ bind(&done);
} }
// ----------- S t a t e ------------- // Push additional arguments onto the stack.
// -- 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).
{ {
__ PopReturnAddressTo(r8); __ PopReturnAddressTo(r8);
__ Set(rcx, 0); __ Set(r9, 0);
Label done, push, loop; Label done, push, loop;
__ bind(&loop); __ bind(&loop);
__ cmpl(rcx, rbx); __ cmpl(r9, rcx);
__ j(equal, &done, Label::kNear); __ j(equal, &done, Label::kNear);
// Turn the hole into undefined as we go. // Turn the hole into undefined as we go.
__ movp(r9, FieldOperand(rax, rcx, times_pointer_size, __ movp(r11,
FixedArray::kHeaderSize)); FieldOperand(rbx, r9, times_pointer_size, FixedArray::kHeaderSize));
__ CompareRoot(r9, Heap::kTheHoleValueRootIndex); __ CompareRoot(r11, Heap::kTheHoleValueRootIndex);
__ j(not_equal, &push, Label::kNear); __ j(not_equal, &push, Label::kNear);
__ LoadRoot(r9, Heap::kUndefinedValueRootIndex); __ LoadRoot(r11, Heap::kUndefinedValueRootIndex);
__ bind(&push); __ bind(&push);
__ Push(r9); __ Push(r11);
__ incl(rcx); __ incl(r9);
__ jmp(&loop); __ jmp(&loop);
__ bind(&done); __ bind(&done);
__ PushReturnAddressFrom(r8); __ PushReturnAddressFrom(r8);
__ Move(rax, rcx); __ addq(rax, r9);
} }
// Dispatch to Call or Construct depending on whether new.target is undefined. // Tail-call to the actual Call or Construct builtin.
{ __ Jump(code, RelocInfo::CODE_TARGET);
__ CompareRoot(rdx, Heap::kUndefinedValueRootIndex);
__ j(equal, masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
} }
// static // static
void Builtins::Generate_ForwardVarargs(MacroAssembler* masm, void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
Handle<Code> code) { Handle<Code> code) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- rax : the number of arguments (not including the receiver) // -- rax : the number of arguments (not including the receiver)
// -- rdx : the new target (for [[Construct]] calls) // -- rdx : the new target (for [[Construct]] calls)

View File

@ -409,6 +409,12 @@ Callable CodeFactory::CallFunction(Isolate* isolate, ConvertReceiverMode mode,
CallTrampolineDescriptor(isolate)); CallTrampolineDescriptor(isolate));
} }
// static
Callable CodeFactory::CallVarargs(Isolate* isolate) {
return Callable(isolate->builtins()->CallVarargs(),
CallVarargsDescriptor(isolate));
}
// static // static
Callable CodeFactory::CallForwardVarargs(Isolate* isolate) { Callable CodeFactory::CallForwardVarargs(Isolate* isolate) {
return Callable(isolate->builtins()->CallForwardVarargs(), return Callable(isolate->builtins()->CallForwardVarargs(),
@ -439,6 +445,12 @@ Callable CodeFactory::ConstructFunction(Isolate* isolate) {
ConstructTrampolineDescriptor(isolate)); ConstructTrampolineDescriptor(isolate));
} }
// static
Callable CodeFactory::ConstructVarargs(Isolate* isolate) {
return Callable(isolate->builtins()->ConstructVarargs(),
ConstructVarargsDescriptor(isolate));
}
// static // static
Callable CodeFactory::ConstructForwardVarargs(Isolate* isolate) { Callable CodeFactory::ConstructForwardVarargs(Isolate* isolate) {
return Callable(isolate->builtins()->ConstructForwardVarargs(), return Callable(isolate->builtins()->ConstructForwardVarargs(),

View File

@ -146,11 +146,13 @@ class V8_EXPORT_PRIVATE CodeFactory final {
static Callable CallFunction( static Callable CallFunction(
Isolate* isolate, ConvertReceiverMode mode = ConvertReceiverMode::kAny, Isolate* isolate, ConvertReceiverMode mode = ConvertReceiverMode::kAny,
TailCallMode tail_call_mode = TailCallMode::kDisallow); TailCallMode tail_call_mode = TailCallMode::kDisallow);
static Callable CallVarargs(Isolate* isolate);
static Callable CallForwardVarargs(Isolate* isolate); static Callable CallForwardVarargs(Isolate* isolate);
static Callable CallFunctionForwardVarargs(Isolate* isolate); static Callable CallFunctionForwardVarargs(Isolate* isolate);
static Callable Construct(Isolate* isolate); static Callable Construct(Isolate* isolate);
static Callable ConstructWithSpread(Isolate* isolate); static Callable ConstructWithSpread(Isolate* isolate);
static Callable ConstructFunction(Isolate* isolate); static Callable ConstructFunction(Isolate* isolate);
static Callable ConstructVarargs(Isolate* isolate);
static Callable ConstructForwardVarargs(Isolate* isolate); static Callable ConstructForwardVarargs(Isolate* isolate);
static Callable ConstructFunctionForwardVarargs(Isolate* isolate); static Callable ConstructFunctionForwardVarargs(Isolate* isolate);
static Callable CreateIterResultObject(Isolate* isolate); static Callable CreateIterResultObject(Isolate* isolate);

View File

@ -156,6 +156,16 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers); 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( void CallForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
// eax : number of arguments // eax : number of arguments
@ -165,6 +175,25 @@ void CallForwardVarargsDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers); 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( void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
// eax : number of arguments // eax : number of arguments
@ -175,6 +204,15 @@ void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers); 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( void ConstructStubDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
// eax : number of arguments // eax : number of arguments

View File

@ -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) { void MacroAssembler::AssertFunction(Register object) {
if (emit_debug_code()) { if (emit_debug_code()) {

View File

@ -521,6 +521,9 @@ class MacroAssembler: public Assembler {
// Abort execution if argument is a smi, enabled via --debug-code. // Abort execution if argument is a smi, enabled via --debug-code.
void AssertNotSmi(Register object); 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. // Abort execution if argument is not a JSFunction, enabled via --debug-code.
void AssertFunction(Register object); void AssertFunction(Register object);

View File

@ -459,6 +459,16 @@ void CallTrampolineDescriptor::InitializePlatformIndependent(
machine_types); 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( void CallForwardVarargsDescriptor::InitializePlatformIndependent(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
// kTarget, kActualArgumentsCount, kStartIndex // kTarget, kActualArgumentsCount, kStartIndex
@ -468,6 +478,26 @@ void CallForwardVarargsDescriptor::InitializePlatformIndependent(
machine_types); 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( void ConstructForwardVarargsDescriptor::InitializePlatformIndependent(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
// kTarget, kNewTarget, kActualArgumentsCount, kStartIndex // kTarget, kNewTarget, kActualArgumentsCount, kStartIndex
@ -478,6 +508,16 @@ void ConstructForwardVarargsDescriptor::InitializePlatformIndependent(
machine_types); 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( void ConstructStubDescriptor::InitializePlatformIndependent(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
// kFunction, kNewTarget, kActualArgumentsCount, kAllocationSite // kFunction, kNewTarget, kActualArgumentsCount, kAllocationSite

View File

@ -44,11 +44,15 @@ class PlatformInterfaceDescriptor;
V(CallFunction) \ V(CallFunction) \
V(CallIC) \ V(CallIC) \
V(CallICTrampoline) \ V(CallICTrampoline) \
V(CallVarargs) \
V(CallForwardVarargs) \ V(CallForwardVarargs) \
V(CallWithArrayLike) \
V(CallConstruct) \ V(CallConstruct) \
V(CallTrampoline) \ V(CallTrampoline) \
V(ConstructStub) \ V(ConstructStub) \
V(ConstructVarargs) \
V(ConstructForwardVarargs) \ V(ConstructForwardVarargs) \
V(ConstructWithArrayLike) \
V(ConstructTrampoline) \ V(ConstructTrampoline) \
V(TransitionElementsKind) \ V(TransitionElementsKind) \
V(AllocateHeapNumber) \ V(AllocateHeapNumber) \
@ -574,6 +578,14 @@ class CallTrampolineDescriptor : public CallInterfaceDescriptor {
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 { class CallForwardVarargsDescriptor : public CallInterfaceDescriptor {
public: public:
DEFINE_PARAMETERS(kTarget, kActualArgumentsCount, kStartIndex) DEFINE_PARAMETERS(kTarget, kActualArgumentsCount, kStartIndex)
@ -581,6 +593,21 @@ class CallForwardVarargsDescriptor : public CallInterfaceDescriptor {
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 { class ConstructForwardVarargsDescriptor : public CallInterfaceDescriptor {
public: public:
DEFINE_PARAMETERS(kTarget, kNewTarget, kActualArgumentsCount, kStartIndex) DEFINE_PARAMETERS(kTarget, kNewTarget, kActualArgumentsCount, kStartIndex)
@ -588,6 +615,13 @@ class ConstructForwardVarargsDescriptor : public CallInterfaceDescriptor {
ConstructForwardVarargsDescriptor, 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 { class ConstructStubDescriptor : public CallInterfaceDescriptor {
public: public:
DEFINE_PARAMETERS(kFunction, kNewTarget, kActualArgumentsCount, DEFINE_PARAMETERS(kFunction, kNewTarget, kActualArgumentsCount,

View File

@ -155,6 +155,16 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers); 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( void CallForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
// a1: the target to call // a1: the target to call
@ -164,6 +174,25 @@ void CallForwardVarargsDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers); 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( void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
// a1: the target to call // a1: the target to call
@ -174,6 +203,15 @@ void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers); 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( void ConstructStubDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
// a1: target // a1: target

View File

@ -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) { void MacroAssembler::AssertFunction(Register object) {
if (emit_debug_code()) { if (emit_debug_code()) {

View File

@ -1538,6 +1538,9 @@ const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
void AssertNotSmi(Register object); void AssertNotSmi(Register object);
void AssertSmi(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. // Abort execution if argument is not a JSFunction, enabled via --debug-code.
void AssertFunction(Register object); void AssertFunction(Register object);

View File

@ -155,6 +155,16 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers); 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( void CallForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
// a1: the target to call // a1: the target to call
@ -164,6 +174,25 @@ void CallForwardVarargsDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers); 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( void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
// a1: the target to call // a1: the target to call
@ -174,6 +203,15 @@ void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers); 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( void ConstructStubDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
// a1: target // a1: target

View File

@ -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) { void MacroAssembler::AssertFunction(Register object) {
if (emit_debug_code()) { if (emit_debug_code()) {

View File

@ -1692,6 +1692,9 @@ const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
void AssertNotSmi(Register object); void AssertNotSmi(Register object);
void AssertSmi(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. // Abort execution if argument is not a JSFunction, enabled via --debug-code.
void AssertFunction(Register object); void AssertFunction(Register object);

View File

@ -180,6 +180,7 @@
'builtins/builtins-async-iterator-gen.cc', 'builtins/builtins-async-iterator-gen.cc',
'builtins/builtins-boolean-gen.cc', 'builtins/builtins-boolean-gen.cc',
'builtins/builtins-call-gen.cc', 'builtins/builtins-call-gen.cc',
'builtins/builtins-call-gen.h',
'builtins/builtins-collections-gen.cc', 'builtins/builtins-collections-gen.cc',
'builtins/builtins-console-gen.cc', 'builtins/builtins-console-gen.cc',
'builtins/builtins-constructor-gen.cc', 'builtins/builtins-constructor-gen.cc',

View File

@ -155,6 +155,16 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers); 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( void CallForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
// rax : number of arguments // rax : number of arguments
@ -164,6 +174,25 @@ void CallForwardVarargsDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers); 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( void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
// rax : number of arguments // rax : number of arguments
@ -174,6 +203,15 @@ void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers); 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( void ConstructStubDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
// rax : number of arguments // rax : number of arguments

View File

@ -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) { void MacroAssembler::AssertZeroExtended(Register int32_register) {
if (emit_debug_code()) { if (emit_debug_code()) {

View File

@ -1145,6 +1145,9 @@ class MacroAssembler: public Assembler {
void AssertSmi(Register object); void AssertSmi(Register object);
void AssertSmi(const Operand& 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 // 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. // have zeros in the top 32 bits, enabled via --debug-code.
void AssertZeroExtended(Register reg); void AssertZeroExtended(Register reg);