diff options
Diffstat (limited to 'deps/v8/src/arm/builtins-arm.cc')
-rw-r--r-- | deps/v8/src/arm/builtins-arm.cc | 296 |
1 files changed, 185 insertions, 111 deletions
diff --git a/deps/v8/src/arm/builtins-arm.cc b/deps/v8/src/arm/builtins-arm.cc index ea2c92e640..4464816f72 100644 --- a/deps/v8/src/arm/builtins-arm.cc +++ b/deps/v8/src/arm/builtins-arm.cc @@ -22,11 +22,12 @@ void Builtins::Generate_Adaptor(MacroAssembler* masm, BuiltinExtraArguments extra_args) { // ----------- S t a t e ------------- // -- r0 : number of arguments excluding receiver - // -- r1 : called function (only guaranteed when - // extra_args requires it) + // (only guaranteed when the called function + // is not marked as DontAdaptArguments) + // -- r1 : called function // -- sp[0] : last argument // -- ... - // -- sp[4 * (argc - 1)] : first argument (argc == r0) + // -- sp[4 * (argc - 1)] : first argument // -- sp[4 * argc] : receiver // ----------------------------------- __ AssertFunction(r1); @@ -48,8 +49,17 @@ void Builtins::Generate_Adaptor(MacroAssembler* masm, } // JumpToExternalReference expects r0 to contain the number of arguments - // including the receiver and the extra arguments. + // including the receiver and the extra arguments. But r0 is only valid + // if the called function is marked as DontAdaptArguments, otherwise we + // need to load the argument count from the SharedFunctionInfo. + __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); + __ ldr(r2, + FieldMemOperand(r2, SharedFunctionInfo::kFormalParameterCountOffset)); + __ SmiUntag(r2); + __ cmp(r2, Operand(SharedFunctionInfo::kDontAdaptArgumentsSentinel)); + __ mov(r0, r2, LeaveCC, ne); __ add(r0, r0, Operand(num_extra_args + 1)); + __ JumpToExternalReference(ExternalReference(id, masm->isolate())); } @@ -61,8 +71,7 @@ static void GenerateLoadInternalArrayFunction(MacroAssembler* masm, __ ldr(result, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); - __ ldr(result, - FieldMemOperand(result, GlobalObject::kNativeContextOffset)); + __ ldr(result, FieldMemOperand(result, JSGlobalObject::kNativeContextOffset)); // Load the InternalArray function from the native context. __ ldr(result, MemOperand(result, @@ -77,8 +86,7 @@ static void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) { __ ldr(result, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); - __ ldr(result, - FieldMemOperand(result, GlobalObject::kNativeContextOffset)); + __ ldr(result, FieldMemOperand(result, JSGlobalObject::kNativeContextOffset)); // Load the Array function from the native context. __ ldr(result, MemOperand(result, @@ -203,39 +211,42 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- r0 : number of arguments // -- r1 : constructor function + // -- r3 : original constructor // -- lr : return address // -- sp[(argc - n - 1) * 4] : arg[n] (zero based) // -- sp[argc * 4] : receiver // ----------------------------------- - // 1. Load the first argument into r0 and get rid of the rest (including the + // 1. Load the first argument into r2 and get rid of the rest (including the // receiver). { Label no_arguments, done; __ sub(r0, r0, Operand(1), SetCC); __ b(lo, &no_arguments); - __ ldr(r0, MemOperand(sp, r0, LSL, kPointerSizeLog2, PreIndex)); + __ ldr(r2, MemOperand(sp, r0, LSL, kPointerSizeLog2, PreIndex)); __ Drop(2); __ b(&done); __ bind(&no_arguments); - __ LoadRoot(r0, Heap::kempty_stringRootIndex); + __ LoadRoot(r2, Heap::kempty_stringRootIndex); __ Drop(1); __ bind(&done); } - // 2. Make sure r0 is a string. + // 2. Make sure r2 is a string. { Label convert, done_convert; - __ JumpIfSmi(r0, &convert); - __ CompareObjectType(r0, r2, r2, FIRST_NONSTRING_TYPE); + __ JumpIfSmi(r2, &convert); + __ CompareObjectType(r2, r4, r4, FIRST_NONSTRING_TYPE); __ b(lo, &done_convert); __ bind(&convert); { FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); ToStringStub stub(masm->isolate()); - __ Push(r1); + __ Push(r1, r3); + __ Move(r0, r2); __ CallStub(&stub); - __ Pop(r1); + __ Move(r2, r0); + __ Pop(r1, r3); } __ bind(&done_convert); } @@ -243,13 +254,18 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { // 3. Allocate a JSValue wrapper for the string. { // ----------- S t a t e ------------- - // -- r0 : the first argument + // -- r2 : the first argument // -- r1 : constructor function + // -- r3 : original constructor // -- lr : return address // ----------------------------------- - Label allocate, done_allocate; - __ Move(r2, r0); + Label allocate, done_allocate, rt_call; + + // Fall back to runtime if the original constructor and function differ. + __ cmp(r1, r3); + __ b(ne, &rt_call); + __ Allocate(JSValue::kSize, r0, r3, r4, &allocate, TAG_OBJECT); __ bind(&done_allocate); @@ -273,6 +289,18 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { __ Pop(r1, r2); } __ b(&done_allocate); + + // Fallback to the runtime to create new object. + __ bind(&rt_call); + { + FrameScope scope(masm, StackFrame::INTERNAL); + __ Push(r1, r2); + __ Push(r1, r3); // constructor function, original constructor + __ CallRuntime(Runtime::kNewObject, 2); + __ Pop(r1, r2); + } + __ str(r2, FieldMemOperand(r0, JSValue::kValueOffset)); + __ Ret(); } } @@ -360,17 +388,23 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, __ tst(r2, r2); __ b(ne, &rt_call); - // Fall back to runtime if the original constructor and function differ. - __ cmp(r1, r3); + // Verify that the original constructor is a JSFunction. + __ CompareObjectType(r3, r5, r4, JS_FUNCTION_TYPE); __ b(ne, &rt_call); // Load the initial map and verify that it is in fact a map. - // r1: constructor function - __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset)); + // r3: original constructor + __ ldr(r2, FieldMemOperand(r3, JSFunction::kPrototypeOrInitialMapOffset)); __ JumpIfSmi(r2, &rt_call); __ CompareObjectType(r2, r5, r4, MAP_TYPE); __ b(ne, &rt_call); + // Fall back to runtime if the expected base constructor and base + // constructor differ. + __ ldr(r5, FieldMemOperand(r2, Map::kConstructorOrBackPointerOffset)); + __ cmp(r1, r5); + __ b(ne, &rt_call); + // Check that the constructor is not constructing a JSFunction (see // comments in Runtime_NewObject in runtime.cc). In which case the // initial map's instance type would be JS_FUNCTION_TYPE. @@ -393,9 +427,9 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, __ cmp(r3, Operand(Map::kSlackTrackingCounterEnd)); __ b(ne, &allocate); - __ push(r1); + __ Push(r1, r2); - __ Push(r2, r1); // r1 = constructor + __ push(r2); // r2 = intial map __ CallRuntime(Runtime::kFinalizeInstanceSize, 1); __ pop(r2); @@ -490,8 +524,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, // r3: original constructor __ bind(&rt_call); - __ push(r1); // argument 2/1: constructor function - __ push(r3); // argument 3/2: original constructor + __ push(r1); // constructor function + __ push(r3); // original constructor __ CallRuntime(Runtime::kNewObject, 2); __ mov(r4, r0); @@ -896,21 +930,7 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { // - Support profiler (specifically profiling_counter). // - Call ProfileEntryHookStub when isolate has a function_entry_hook. // - Allow simulator stop operations if FLAG_stop_at is set. - // - Deal with sloppy mode functions which need to replace the - // receiver with the global proxy when called as functions (without an - // explicit receiver object). // - Code aging of the BytecodeArray object. - // - Supporting FLAG_trace. - // - // The following items are also not done here, and will probably be done using - // explicit bytecodes instead: - // - Allocating a new local context if applicable. - // - Setting up a local binding to the this function, which is used in - // derived constructors with super calls. - // - Setting new.target if required. - // - Dealing with REST parameters (only if - // https://codereview.chromium.org/1235153006 doesn't land by then). - // - Dealing with argument objects. // Perform stack guard check. { @@ -918,7 +938,9 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { __ LoadRoot(ip, Heap::kStackLimitRootIndex); __ cmp(sp, Operand(ip)); __ b(hs, &ok); + __ push(kInterpreterBytecodeArrayRegister); __ CallRuntime(Runtime::kStackGuard, 0); + __ pop(kInterpreterBytecodeArrayRegister); __ bind(&ok); } @@ -966,6 +988,66 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) { } +static void Generate_InterpreterPushArgs(MacroAssembler* masm, Register index, + Register limit, Register scratch) { + Label loop_header, loop_check; + __ b(al, &loop_check); + __ bind(&loop_header); + __ ldr(scratch, MemOperand(index, -kPointerSize, PostIndex)); + __ push(scratch); + __ bind(&loop_check); + __ cmp(index, limit); + __ b(gt, &loop_header); +} + + +// static +void Builtins::Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- r0 : the number of arguments (not including the receiver) + // -- r2 : the address of the first argument to be pushed. Subsequent + // arguments should be consecutive above this, in the same order as + // they are to be pushed onto the stack. + // -- r1 : the target to call (can be any Object). + // ----------------------------------- + + // Find the address of the last argument. + __ add(r3, r0, Operand(1)); // Add one for receiver. + __ mov(r3, Operand(r3, LSL, kPointerSizeLog2)); + __ sub(r3, r2, r3); + + // Push the arguments. + Generate_InterpreterPushArgs(masm, r2, r3, r4); + + // Call the target. + __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); +} + + +// static +void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- r0 : argument count (not including receiver) + // -- r3 : original constructor + // -- r1 : constructor to call + // -- r2 : address of the first argument + // ----------------------------------- + + // Find the address of the last argument. + __ mov(r4, Operand(r0, LSL, kPointerSizeLog2)); + __ sub(r4, r2, r4); + + // Push a slot for the receiver to be constructed. + __ push(r0); + + // Push the arguments. + Generate_InterpreterPushArgs(masm, r2, r4, r5); + + // Call the constructor with r0, r1, and r3 unmodified. + __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CONSTRUCT_CALL); +} + + void Builtins::Generate_CompileLazy(MacroAssembler* masm) { CallRuntimePassFunction(masm, Runtime::kCompileLazy); GenerateTailCallToReturnedCode(masm); @@ -1483,70 +1565,82 @@ static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) { // static -void Builtins::Generate_CallFunction(MacroAssembler* masm) { +void Builtins::Generate_CallFunction(MacroAssembler* masm, + ConvertReceiverMode mode) { // ----------- S t a t e ------------- // -- r0 : the number of arguments (not including the receiver) // -- r1 : the function to call (checked to be a JSFunction) // ----------------------------------- - - Label convert, convert_global_proxy, convert_to_object, done_convert; __ AssertFunction(r1); - // TODO(bmeurer): Throw a TypeError if function's [[FunctionKind]] internal - // slot is "classConstructor". + + // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList) + // Check that the function is not a "classConstructor". + Label class_constructor; + __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); + __ ldrb(r3, FieldMemOperand(r2, SharedFunctionInfo::kFunctionKindByteOffset)); + __ tst(r3, Operand(SharedFunctionInfo::kClassConstructorBitsWithinByte)); + __ b(ne, &class_constructor); + // Enter the context of the function; ToObject has to run in the function // context, and we also need to take the global proxy from the function // context in case of conversion. - // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList) STATIC_ASSERT(SharedFunctionInfo::kNativeByteOffset == SharedFunctionInfo::kStrictModeByteOffset); __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); - __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); // We need to convert the receiver for non-native sloppy mode functions. + Label done_convert; __ ldrb(r3, FieldMemOperand(r2, SharedFunctionInfo::kNativeByteOffset)); __ tst(r3, Operand((1 << SharedFunctionInfo::kNativeBitWithinByte) | (1 << SharedFunctionInfo::kStrictModeBitWithinByte))); __ b(ne, &done_convert); { - __ ldr(r3, MemOperand(sp, r0, LSL, kPointerSizeLog2)); - // ----------- S t a t e ------------- // -- r0 : the number of arguments (not including the receiver) // -- r1 : the function to call (checked to be a JSFunction) // -- r2 : the shared function info. - // -- r3 : the receiver // -- cp : the function context. // ----------------------------------- - Label convert_receiver; - __ JumpIfSmi(r3, &convert_to_object); - STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); - __ CompareObjectType(r3, r4, r4, FIRST_JS_RECEIVER_TYPE); - __ b(hs, &done_convert); - __ JumpIfRoot(r3, Heap::kUndefinedValueRootIndex, &convert_global_proxy); - __ JumpIfNotRoot(r3, Heap::kNullValueRootIndex, &convert_to_object); - __ bind(&convert_global_proxy); - { + if (mode == ConvertReceiverMode::kNullOrUndefined) { // Patch receiver to global proxy. __ LoadGlobalProxy(r3); + } else { + Label convert_to_object, convert_receiver; + __ ldr(r3, MemOperand(sp, r0, LSL, kPointerSizeLog2)); + __ JumpIfSmi(r3, &convert_to_object); + STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); + __ CompareObjectType(r3, r4, r4, FIRST_JS_RECEIVER_TYPE); + __ b(hs, &done_convert); + if (mode != ConvertReceiverMode::kNotNullOrUndefined) { + Label convert_global_proxy; + __ JumpIfRoot(r3, Heap::kUndefinedValueRootIndex, + &convert_global_proxy); + __ JumpIfNotRoot(r3, Heap::kNullValueRootIndex, &convert_to_object); + __ bind(&convert_global_proxy); + { + // Patch receiver to global proxy. + __ LoadGlobalProxy(r3); + } + __ b(&convert_receiver); + } + __ bind(&convert_to_object); + { + // Convert receiver using ToObject. + // TODO(bmeurer): Inline the allocation here to avoid building the frame + // in the fast case? (fall back to AllocateInNewSpace?) + FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); + __ SmiTag(r0); + __ Push(r0, r1); + __ mov(r0, r3); + ToObjectStub stub(masm->isolate()); + __ CallStub(&stub); + __ mov(r3, r0); + __ Pop(r0, r1); + __ SmiUntag(r0); + } + __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); + __ bind(&convert_receiver); } - __ b(&convert_receiver); - __ bind(&convert_to_object); - { - // Convert receiver using ToObject. - // TODO(bmeurer): Inline the allocation here to avoid building the frame - // in the fast case? (fall back to AllocateInNewSpace?) - FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); - __ SmiTag(r0); - __ Push(r0, r1); - __ mov(r0, r3); - ToObjectStub stub(masm->isolate()); - __ CallStub(&stub); - __ mov(r3, r0); - __ Pop(r0, r1); - __ SmiUntag(r0); - } - __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); - __ bind(&convert_receiver); __ str(r3, MemOperand(sp, r0, LSL, kPointerSizeLog2)); } __ bind(&done_convert); @@ -1565,11 +1659,18 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm) { ParameterCount actual(r0); ParameterCount expected(r2); __ InvokeCode(r3, expected, actual, JUMP_FUNCTION, NullCallWrapper()); + + // The function is a "classConstructor", need to raise an exception. + __ bind(&class_constructor); + { + FrameScope frame(masm, StackFrame::INTERNAL); + __ CallRuntime(Runtime::kThrowConstructorNonCallableError, 0); + } } // static -void Builtins::Generate_Call(MacroAssembler* masm) { +void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) { // ----------- S t a t e ------------- // -- r0 : the number of arguments (not including the receiver) // -- r1 : the target to call (can be any Object). @@ -1579,8 +1680,8 @@ void Builtins::Generate_Call(MacroAssembler* masm) { __ JumpIfSmi(r1, &non_callable); __ bind(&non_smi); __ CompareObjectType(r1, r4, r5, JS_FUNCTION_TYPE); - __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET, - eq); + __ Jump(masm->isolate()->builtins()->CallFunction(mode), + RelocInfo::CODE_TARGET, eq); __ cmp(r5, Operand(JS_FUNCTION_PROXY_TYPE)); __ b(ne, &non_function); @@ -1601,7 +1702,9 @@ void Builtins::Generate_Call(MacroAssembler* masm) { __ str(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2)); // Let the "call_as_function_delegate" take care of the rest. __ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, r1); - __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET); + __ Jump(masm->isolate()->builtins()->CallFunction( + ConvertReceiverMode::kNotNullOrUndefined), + RelocInfo::CODE_TARGET); // 3. Call to something that is not callable. __ bind(&non_callable); @@ -1696,35 +1799,6 @@ void Builtins::Generate_Construct(MacroAssembler* masm) { } -// static -void Builtins::Generate_PushArgsAndCall(MacroAssembler* masm) { - // ----------- S t a t e ------------- - // -- r0 : the number of arguments (not including the receiver) - // -- r2 : the address of the first argument to be pushed. Subsequent - // arguments should be consecutive above this, in the same order as - // they are to be pushed onto the stack. - // -- r1 : the target to call (can be any Object). - - // Find the address of the last argument. - __ add(r3, r0, Operand(1)); // Add one for receiver. - __ mov(r3, Operand(r3, LSL, kPointerSizeLog2)); - __ sub(r3, r2, r3); - - // Push the arguments. - Label loop_header, loop_check; - __ b(al, &loop_check); - __ bind(&loop_header); - __ ldr(r4, MemOperand(r2, -kPointerSize, PostIndex)); - __ push(r4); - __ bind(&loop_check); - __ cmp(r2, r3); - __ b(gt, &loop_header); - - // Call the target. - __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); -} - - void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- r0 : actual number of arguments |