diff --git a/qtwebengine-everywhere-src-5.10.0-no-sse2.patch b/qtwebengine-everywhere-src-5.10.0-no-sse2.patch index f66ee4f..3198c85 100644 --- a/qtwebengine-everywhere-src-5.10.0-no-sse2.patch +++ b/qtwebengine-everywhere-src-5.10.0-no-sse2.patch @@ -2649,8 +2649,8 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/base/bu #define V8_TARGET_ARCH_STORES_RETURN_ADDRESS_ON_STACK 0 diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtins/x87/builtins-x87.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/builtins/x87/builtins-x87.cc --- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtins/x87/builtins-x87.cc 1970-01-01 01:00:00.000000000 +0100 -+++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/builtins/x87/builtins-x87.cc 2017-12-28 03:52:06.933365833 +0100 -@@ -0,0 +1,3038 @@ ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/builtins/x87/builtins-x87.cc 2017-12-29 01:00:28.359896864 +0100 +@@ -0,0 +1,3008 @@ +// Copyright 2012 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. @@ -2745,34 +2745,14 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + __ jmp(ebx); +} + -+void Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) { -+ // Checking whether the queued function is ready for install is optional, -+ // since we come across interrupts and stack checks elsewhere. However, -+ // not checking may delay installing ready functions, and always checking -+ // would be quite expensive. A good compromise is to first check against -+ // stack limit as a cue for an interrupt signal. -+ Label ok; -+ ExternalReference stack_limit = -+ ExternalReference::address_of_stack_limit(masm->isolate()); -+ __ cmp(esp, Operand::StaticVariable(stack_limit)); -+ __ j(above_equal, &ok, Label::kNear); -+ -+ GenerateTailCallToReturnedCode(masm, Runtime::kTryInstallOptimizedCode); -+ -+ __ bind(&ok); -+ GenerateTailCallToSharedCode(masm); -+} -+ +namespace { + -+void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function, -+ bool create_implicit_receiver, -+ bool check_derived_construct) { ++void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- eax: number of arguments -+ // -- esi: context + // -- edi: constructor function + // -- edx: new target ++ // -- esi: context + // ----------------------------------- + + // Enter a construct frame. @@ -2783,39 +2763,10 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + __ SmiTag(eax); + __ push(esi); + __ push(eax); -+ -+ if (create_implicit_receiver) { -+ // Allocate the new receiver object. -+ __ Push(edi); -+ __ Push(edx); -+ __ Call(Builtins::CallableFor(masm->isolate(), Builtins::kFastNewObject) -+ .code(), -+ RelocInfo::CODE_TARGET); -+ __ mov(ebx, eax); -+ __ Pop(edx); -+ __ Pop(edi); -+ -+ // ----------- S t a t e ------------- -+ // -- edi: constructor function -+ // -- ebx: newly allocated object -+ // -- edx: new target -+ // ----------------------------------- -+ -+ // Retrieve smi-tagged arguments count from the stack. -+ __ mov(eax, Operand(esp, 0)); -+ } -+ + __ SmiUntag(eax); + -+ if (create_implicit_receiver) { -+ // Push the allocated receiver to the stack. We need two copies -+ // because we may have to return the original one and the calling -+ // conventions dictate that the called function pops the receiver. -+ __ push(ebx); -+ __ push(ebx); -+ } else { -+ __ PushRoot(Heap::kTheHoleValueRootIndex); -+ } ++ // The receiver for the builtin/api call. ++ __ PushRoot(Heap::kTheHoleValueRootIndex); + + // Set up pointer to last argument. + __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset)); @@ -2823,6 +2774,16 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + // Copy arguments and receiver to the expression stack. + Label loop, entry; + __ mov(ecx, eax); ++ // ----------- S t a t e ------------- ++ // -- eax: number of arguments (untagged) ++ // -- edi: constructor function ++ // -- edx: new target ++ // -- ebx: pointer to last argument ++ // -- ecx: counter ++ // -- sp[0*kPointerSize]: the hole (receiver) ++ // -- sp[1*kPointerSize]: number of arguments (tagged) ++ // -- sp[2*kPointerSize]: context ++ // ----------------------------------- + __ jmp(&entry); + __ bind(&loop); + __ push(Operand(ebx, ecx, times_4, 0)); @@ -2831,89 +2792,227 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + __ j(greater_equal, &loop); + + // Call the function. ++ // eax: number of arguments (untagged) ++ // edi: constructor function ++ // edx: new target ++ ParameterCount actual(eax); ++ __ InvokeFunction(edi, edx, actual, CALL_FUNCTION, ++ CheckDebugStepCallWrapper()); ++ ++ // Restore context from the frame. ++ __ mov(esi, Operand(ebp, ConstructFrameConstants::kContextOffset)); ++ // Restore smi-tagged arguments count from the frame. ++ __ mov(ebx, Operand(ebp, ConstructFrameConstants::kLengthOffset)); ++ // Leave construct frame. ++ } ++ ++ // Remove caller arguments from the stack and return. ++ STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); ++ __ pop(ecx); ++ __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver ++ __ push(ecx); ++ __ ret(0); ++} ++ ++// The construct stub for ES5 constructor functions and ES6 class constructors. ++void Generate_JSConstructStubGeneric(MacroAssembler* masm, ++ bool restrict_constructor_return) { ++ // ----------- S t a t e ------------- ++ // -- eax: number of arguments (untagged) ++ // -- edi: constructor function ++ // -- edx: new target ++ // -- esi: context ++ // -- sp[...]: constructor arguments ++ // ----------------------------------- ++ ++ // Enter a construct frame. ++ { ++ FrameScope scope(masm, StackFrame::CONSTRUCT); ++ Label post_instantiation_deopt_entry, not_create_implicit_receiver; ++ ++ // Preserve the incoming parameters on the stack. ++ __ mov(ecx, eax); ++ __ SmiTag(ecx); ++ __ Push(esi); ++ __ Push(ecx); ++ __ Push(edi); ++ __ Push(edx); ++ ++ // ----------- S t a t e ------------- ++ // -- sp[0*kPointerSize]: new target ++ // -- edi and sp[1*kPointerSize]: constructor function ++ // -- sp[2*kPointerSize]: argument count ++ // -- sp[3*kPointerSize]: context ++ // ----------------------------------- ++ ++ __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); ++ __ test(FieldOperand(ebx, SharedFunctionInfo::kCompilerHintsOffset), ++ Immediate(SharedFunctionInfo::kDerivedConstructorMask)); ++ __ j(not_zero, ¬_create_implicit_receiver); ++ ++ // If not derived class constructor: Allocate the new receiver object. ++ __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1); ++ __ Call(masm->isolate()->builtins()->FastNewObject(), ++ RelocInfo::CODE_TARGET); ++ __ jmp(&post_instantiation_deopt_entry, Label::kNear); ++ ++ // Else: use TheHoleValue as receiver for constructor call ++ __ bind(¬_create_implicit_receiver); ++ __ LoadRoot(eax, Heap::kTheHoleValueRootIndex); ++ ++ // ----------- S t a t e ------------- ++ // -- eax: implicit receiver ++ // -- Slot 3 / sp[0*kPointerSize]: new target ++ // -- Slot 2 / sp[1*kPointerSize]: constructor function ++ // -- Slot 1 / sp[2*kPointerSize]: number of arguments (tagged) ++ // -- Slot 0 / sp[3*kPointerSize]: context ++ // ----------------------------------- ++ // Deoptimizer enters here. ++ masm->isolate()->heap()->SetConstructStubCreateDeoptPCOffset( ++ masm->pc_offset()); ++ __ bind(&post_instantiation_deopt_entry); ++ ++ // Restore new target. ++ __ Pop(edx); ++ ++ // Push the allocated receiver to the stack. We need two copies ++ // because we may have to return the original one and the calling ++ // conventions dictate that the called function pops the receiver. ++ __ Push(eax); ++ __ Push(eax); ++ ++ // ----------- S t a t e ------------- ++ // -- edx: new target ++ // -- sp[0*kPointerSize]: implicit receiver ++ // -- sp[1*kPointerSize]: implicit receiver ++ // -- sp[2*kPointerSize]: constructor function ++ // -- sp[3*kPointerSize]: number of arguments (tagged) ++ // -- sp[4*kPointerSize]: context ++ // ----------------------------------- ++ ++ // Restore constructor function and argument count. ++ __ mov(edi, Operand(ebp, ConstructFrameConstants::kConstructorOffset)); ++ __ mov(eax, Operand(ebp, ConstructFrameConstants::kLengthOffset)); ++ __ SmiUntag(eax); ++ ++ // Set up pointer to last argument. ++ __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset)); ++ ++ // Copy arguments and receiver to the expression stack. ++ Label loop, entry; ++ __ mov(ecx, eax); ++ // ----------- S t a t e ------------- ++ // -- eax: number of arguments (untagged) ++ // -- edx: new target ++ // -- ebx: pointer to last argument ++ // -- ecx: counter (tagged) ++ // -- sp[0*kPointerSize]: implicit receiver ++ // -- sp[1*kPointerSize]: implicit receiver ++ // -- edi and sp[2*kPointerSize]: constructor function ++ // -- sp[3*kPointerSize]: number of arguments (tagged) ++ // -- sp[4*kPointerSize]: context ++ // ----------------------------------- ++ __ jmp(&entry, Label::kNear); ++ __ bind(&loop); ++ __ Push(Operand(ebx, ecx, times_pointer_size, 0)); ++ __ bind(&entry); ++ __ dec(ecx); ++ __ j(greater_equal, &loop); ++ ++ // Call the function. + ParameterCount actual(eax); + __ InvokeFunction(edi, edx, actual, CALL_FUNCTION, + CheckDebugStepCallWrapper()); + ++ // ----------- S t a t e ------------- ++ // -- eax: constructor result ++ // -- sp[0*kPointerSize]: implicit receiver ++ // -- sp[1*kPointerSize]: constructor function ++ // -- sp[2*kPointerSize]: number of arguments ++ // -- sp[3*kPointerSize]: context ++ // ----------------------------------- ++ + // Store offset of return address for deoptimizer. -+ if (create_implicit_receiver && !is_api_function) { -+ masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset()); -+ } ++ masm->isolate()->heap()->SetConstructStubInvokeDeoptPCOffset( ++ masm->pc_offset()); + + // Restore context from the frame. + __ mov(esi, Operand(ebp, ConstructFrameConstants::kContextOffset)); + -+ if (create_implicit_receiver) { -+ // If the result is an object (in the ECMA sense), we should get rid -+ // of the receiver and use the result; see ECMA-262 section 13.2.2-7 -+ // on page 74. -+ Label use_receiver, exit; ++ // If the result is an object (in the ECMA sense), we should get rid ++ // of the receiver and use the result; see ECMA-262 section 13.2.2-7 ++ // on page 74. ++ Label use_receiver, do_throw, other_result, leave_frame; + -+ // If the result is a smi, it is *not* an object in the ECMA sense. -+ __ JumpIfSmi(eax, &use_receiver, Label::kNear); ++ // If the result is undefined, we jump out to using the implicit receiver. ++ __ JumpIfRoot(eax, Heap::kUndefinedValueRootIndex, &use_receiver, ++ Label::kNear); + -+ // If the type of the result (stored in its map) is less than -+ // FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense. -+ __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ecx); -+ __ j(above_equal, &exit, Label::kNear); ++ // Otherwise we do a smi check and fall through to check if the return value ++ // is a valid receiver. + -+ // Throw away the result of the constructor invocation and use the -+ // on-stack receiver as the result. -+ __ bind(&use_receiver); -+ __ mov(eax, Operand(esp, 0)); ++ // If the result is a smi, it is *not* an object in the ECMA sense. ++ __ JumpIfSmi(eax, &other_result, Label::kNear); + -+ // Restore the arguments count and leave the construct frame. The -+ // arguments count is stored below the receiver. -+ __ bind(&exit); -+ __ mov(ebx, Operand(esp, 1 * kPointerSize)); ++ // If the type of the result (stored in its map) is less than ++ // FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense. ++ STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); ++ __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ecx); ++ __ j(above_equal, &leave_frame, Label::kNear); ++ ++ // The result is now neither undefined nor an object. ++ __ bind(&other_result); ++ __ mov(ebx, Operand(ebp, ConstructFrameConstants::kConstructorOffset)); ++ __ mov(ebx, FieldOperand(ebx, JSFunction::kSharedFunctionInfoOffset)); ++ __ test(FieldOperand(ebx, SharedFunctionInfo::kCompilerHintsOffset), ++ Immediate(SharedFunctionInfo::kClassConstructorMask)); ++ ++ if (restrict_constructor_return) { ++ // Throw if constructor function is a class constructor ++ __ j(Condition::zero, &use_receiver, Label::kNear); + } else { -+ __ mov(ebx, Operand(esp, 0)); ++ __ j(not_zero, &use_receiver, Label::kNear); ++ __ CallRuntime( ++ Runtime::kIncrementUseCounterConstructorReturnNonUndefinedPrimitive); ++ __ jmp(&use_receiver, Label::kNear); + } + ++ __ bind(&do_throw); ++ __ CallRuntime(Runtime::kThrowConstructorReturnedNonObject); ++ ++ // Throw away the result of the constructor invocation and use the ++ // on-stack receiver as the result. ++ __ bind(&use_receiver); ++ __ mov(eax, Operand(esp, 0 * kPointerSize)); ++ __ JumpIfRoot(eax, Heap::kTheHoleValueRootIndex, &do_throw); ++ ++ __ bind(&leave_frame); ++ // Restore smi-tagged arguments count from the frame. ++ __ mov(ebx, Operand(ebp, ConstructFrameConstants::kLengthOffset)); + // Leave construct frame. + } -+ -+ // ES6 9.2.2. Step 13+ -+ // Check that the result is not a Smi, indicating that the constructor result -+ // from a derived class is neither undefined nor an Object. -+ if (check_derived_construct) { -+ Label dont_throw; -+ __ JumpIfNotSmi(eax, &dont_throw); -+ { -+ FrameScope scope(masm, StackFrame::INTERNAL); -+ __ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject); -+ } -+ __ bind(&dont_throw); -+ } -+ + // Remove caller arguments from the stack and return. + STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); + __ pop(ecx); + __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver + __ push(ecx); -+ if (create_implicit_receiver) { -+ __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1); -+ } + __ ret(0); +} -+ +} // namespace + -+void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { -+ Generate_JSConstructStubHelper(masm, false, true, false); -+} -+ -+void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { -+ Generate_JSConstructStubHelper(masm, true, false, false); -+} -+ -+void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) { -+ Generate_JSConstructStubHelper(masm, false, false, false); -+} -+ -+void Builtins::Generate_JSBuiltinsConstructStubForDerived( ++void Builtins::Generate_JSConstructStubGenericRestrictedReturn( + MacroAssembler* masm) { -+ Generate_JSConstructStubHelper(masm, false, false, true); ++ return Generate_JSConstructStubGeneric(masm, true); ++} ++void Builtins::Generate_JSConstructStubGenericUnrestrictedReturn( ++ MacroAssembler* masm) { ++ return Generate_JSConstructStubGeneric(masm, false); ++} ++void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { ++ Generate_JSBuiltinsConstructStubHelper(masm); ++} ++void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) { ++ Generate_JSBuiltinsConstructStubHelper(masm); +} + +void Builtins::Generate_ConstructedNonConstructable(MacroAssembler* masm) { @@ -3138,6 +3237,37 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + __ jmp(&stepping_prepared); +} + ++static void ReplaceClosureEntryWithOptimizedCode( ++ MacroAssembler* masm, Register optimized_code_entry, Register closure, ++ Register scratch1, Register scratch2, Register scratch3) { ++ Register native_context = scratch1; ++ ++ // Store the optimized code in the closure. ++ __ lea(optimized_code_entry, ++ FieldOperand(optimized_code_entry, Code::kHeaderSize)); ++ __ mov(FieldOperand(closure, JSFunction::kCodeEntryOffset), ++ optimized_code_entry); ++ __ RecordWriteCodeEntryField(closure, optimized_code_entry, scratch2); ++ ++ // Link the closure into the optimized function list. ++ __ mov(native_context, NativeContextOperand()); ++ __ mov(scratch3, ++ ContextOperand(native_context, Context::OPTIMIZED_FUNCTIONS_LIST)); ++ __ mov(FieldOperand(closure, JSFunction::kNextFunctionLinkOffset), scratch3); ++ __ RecordWriteField(closure, JSFunction::kNextFunctionLinkOffset, scratch3, ++ scratch2, kDontSaveFPRegs, EMIT_REMEMBERED_SET, ++ OMIT_SMI_CHECK); ++ const int function_list_offset = ++ Context::SlotOffset(Context::OPTIMIZED_FUNCTIONS_LIST); ++ __ mov(ContextOperand(native_context, Context::OPTIMIZED_FUNCTIONS_LIST), ++ closure); ++ // Save closure before the write barrier. ++ __ mov(scratch3, closure); ++ __ RecordWriteContextSlot(native_context, function_list_offset, closure, ++ scratch2, kDontSaveFPRegs); ++ __ mov(closure, scratch3); ++} ++ +static void LeaveInterpreterFrame(MacroAssembler* masm, Register scratch1, + Register scratch2) { + Register args_count = scratch1; @@ -3158,6 +3288,121 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + __ push(return_pc); +} + ++// Tail-call |function_id| if |smi_entry| == |marker| ++static void TailCallRuntimeIfMarkerEquals(MacroAssembler* masm, ++ Register smi_entry, ++ OptimizationMarker marker, ++ Runtime::FunctionId function_id) { ++ Label no_match; ++ __ cmp(smi_entry, Immediate(Smi::FromEnum(marker))); ++ __ j(not_equal, &no_match, Label::kNear); ++ GenerateTailCallToReturnedCode(masm, function_id); ++ __ bind(&no_match); ++} ++ ++static void MaybeTailCallOptimizedCodeSlot(MacroAssembler* masm, ++ Register feedback_vector, ++ Register scratch) { ++ // ----------- S t a t e ------------- ++ // -- eax : argument count (preserved for callee if needed, and caller) ++ // -- edx : new target (preserved for callee if needed, and caller) ++ // -- edi : target function (preserved for callee if needed, and caller) ++ // -- feedback vector (preserved for caller if needed) ++ // ----------------------------------- ++ DCHECK(!AreAliased(feedback_vector, eax, edx, edi, scratch)); ++ ++ Label optimized_code_slot_is_cell, fallthrough; ++ ++ Register closure = edi; ++ Register optimized_code_entry = scratch; ++ ++ const int kOptimizedCodeCellOffset = ++ FeedbackVector::kOptimizedCodeIndex * kPointerSize + ++ FeedbackVector::kHeaderSize; ++ __ mov(optimized_code_entry, ++ FieldOperand(feedback_vector, kOptimizedCodeCellOffset)); ++ ++ // Check if the code entry is a Smi. If yes, we interpret it as an ++ // optimisation marker. Otherwise, interpret is as a weak cell to a code ++ // object. ++ __ JumpIfNotSmi(optimized_code_entry, &optimized_code_slot_is_cell); ++ ++ { ++ // Optimized code slot is an optimization marker. ++ ++ // Fall through if no optimization trigger. ++ __ cmp(optimized_code_entry, ++ Immediate(Smi::FromEnum(OptimizationMarker::kNone))); ++ __ j(equal, &fallthrough); ++ ++ TailCallRuntimeIfMarkerEquals(masm, optimized_code_entry, ++ OptimizationMarker::kCompileOptimized, ++ Runtime::kCompileOptimized_NotConcurrent); ++ TailCallRuntimeIfMarkerEquals( ++ masm, optimized_code_entry, ++ OptimizationMarker::kCompileOptimizedConcurrent, ++ Runtime::kCompileOptimized_Concurrent); ++ ++ { ++ // Otherwise, the marker is InOptimizationQueue. ++ if (FLAG_debug_code) { ++ __ cmp( ++ optimized_code_entry, ++ Immediate(Smi::FromEnum(OptimizationMarker::kInOptimizationQueue))); ++ __ Assert(equal, kExpectedOptimizationSentinel); ++ } ++ ++ // Checking whether the queued function is ready for install is optional, ++ // since we come across interrupts and stack checks elsewhere. However, ++ // not checking may delay installing ready functions, and always checking ++ // would be quite expensive. A good compromise is to first check against ++ // stack limit as a cue for an interrupt signal. ++ ExternalReference stack_limit = ++ ExternalReference::address_of_stack_limit(masm->isolate()); ++ __ cmp(esp, Operand::StaticVariable(stack_limit)); ++ __ j(above_equal, &fallthrough); ++ GenerateTailCallToReturnedCode(masm, Runtime::kTryInstallOptimizedCode); ++ } ++ } ++ ++ { ++ // Optimized code slot is a WeakCell. ++ __ bind(&optimized_code_slot_is_cell); ++ ++ __ mov(optimized_code_entry, ++ FieldOperand(optimized_code_entry, WeakCell::kValueOffset)); ++ __ JumpIfSmi(optimized_code_entry, &fallthrough); ++ ++ // Check if the optimized code is marked for deopt. If it is, bailout to a ++ // given label. ++ Label found_deoptimized_code; ++ __ test(FieldOperand(optimized_code_entry, Code::kKindSpecificFlags1Offset), ++ Immediate(1 << Code::kMarkedForDeoptimizationBit)); ++ __ j(not_zero, &found_deoptimized_code); ++ ++ // Optimized code is good, get it into the closure and link the closure into ++ // the optimized functions list, then tail call the optimized code. ++ __ push(eax); ++ __ push(edx); ++ // The feedback vector is no longer used, so re-use it as a scratch ++ // register. ++ ReplaceClosureEntryWithOptimizedCode(masm, optimized_code_entry, closure, ++ edx, eax, feedback_vector); ++ __ pop(edx); ++ __ pop(eax); ++ __ jmp(optimized_code_entry); ++ ++ // Optimized code slot contains deoptimized code, evict it and re-enter the ++ // closure's code. ++ __ bind(&found_deoptimized_code); ++ GenerateTailCallToReturnedCode(masm, Runtime::kEvictOptimizedCodeSlot); ++ } ++ ++ // Fall-through if the optimized code cell is clear and there is no ++ // optimization marker. ++ __ bind(&fallthrough); ++} ++ +// Generate code for entering a JS function with the interpreter. +// On entry to the function the receiver and arguments have been pushed on the +// stack left to right. The actual argument count matches the formal parameter @@ -3175,9 +3420,20 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin +void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { + ProfileEntryHookStub::MaybeCallEntryHook(masm); + ++ Register closure = edi; ++ Register feedback_vector = ebx; ++ ++ // Load the feedback vector from the closure. ++ __ mov(feedback_vector, ++ FieldOperand(closure, JSFunction::kFeedbackVectorOffset)); ++ __ mov(feedback_vector, FieldOperand(feedback_vector, Cell::kValueOffset)); ++ // Read off the optimized code slot in the feedback vector, and if there ++ // is optimized code or an optimization marker, call that instead. ++ MaybeTailCallOptimizedCodeSlot(masm, feedback_vector, ecx); ++ + // Open a frame scope to indicate that there is a frame on the stack. The -+ // MANUAL indicates that the scope shouldn't actually generate code to set up -+ // the frame (that is done below). ++ // MANUAL indicates that the scope shouldn't actually generate code to set ++ // up the frame (that is done below). + FrameScope frame_scope(masm, StackFrame::MANUAL); + __ push(ebp); // Caller's frame pointer. + __ mov(ebp, esp); @@ -3187,12 +3443,12 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + + // Get the bytecode array from the function object (or from the DebugInfo if + // it is present) and load it into kInterpreterBytecodeArrayRegister. ++ Label maybe_load_debug_bytecode_array, bytecode_array_loaded; + __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); -+ Label load_debug_bytecode_array, bytecode_array_loaded; -+ __ JumpIfNotSmi(FieldOperand(eax, SharedFunctionInfo::kDebugInfoOffset), -+ &load_debug_bytecode_array); + __ mov(kInterpreterBytecodeArrayRegister, + FieldOperand(eax, SharedFunctionInfo::kFunctionDataOffset)); ++ __ JumpIfNotSmi(FieldOperand(eax, SharedFunctionInfo::kDebugInfoOffset), ++ &maybe_load_debug_bytecode_array); + __ bind(&bytecode_array_loaded); + + // Check whether we should continue to use the interpreter. @@ -3204,11 +3460,10 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + __ j(not_equal, &switch_to_different_code_kind); + + // Increment invocation count for the function. -+ __ EmitLoadFeedbackVector(ecx); -+ __ add( -+ FieldOperand(ecx, FeedbackVector::kInvocationCountIndex * kPointerSize + -+ FeedbackVector::kHeaderSize), -+ Immediate(Smi::FromInt(1))); ++ __ add(FieldOperand(feedback_vector, ++ FeedbackVector::kInvocationCountIndex * kPointerSize + ++ FeedbackVector::kHeaderSize), ++ Immediate(Smi::FromInt(1))); + + // Check function data field is actually a BytecodeArray object. + if (FLAG_debug_code) { @@ -3279,12 +3534,19 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + LeaveInterpreterFrame(masm, ebx, ecx); + __ ret(0); + -+ // Load debug copy of the bytecode array. -+ __ bind(&load_debug_bytecode_array); -+ Register debug_info = kInterpreterBytecodeArrayRegister; -+ __ mov(debug_info, FieldOperand(eax, SharedFunctionInfo::kDebugInfoOffset)); ++ // Load debug copy of the bytecode array if it exists. ++ // kInterpreterBytecodeArrayRegister is already loaded with ++ // SharedFunctionInfo::kFunctionDataOffset. ++ __ bind(&maybe_load_debug_bytecode_array); ++ __ push(ebx); // feedback_vector == ebx, so save it. ++ __ mov(ecx, FieldOperand(eax, SharedFunctionInfo::kDebugInfoOffset)); ++ __ mov(ebx, FieldOperand(ecx, DebugInfo::kFlagsOffset)); ++ __ SmiUntag(ebx); ++ __ test(ebx, Immediate(DebugInfo::kHasBreakInfo)); ++ __ pop(ebx); ++ __ j(zero, &bytecode_array_loaded); + __ mov(kInterpreterBytecodeArrayRegister, -+ FieldOperand(debug_info, DebugInfo::kDebugBytecodeArrayOffset)); ++ FieldOperand(ecx, DebugInfo::kDebugBytecodeArrayOffset)); + __ jmp(&bytecode_array_loaded); + + // If the shared code is no longer this entry trampoline, then the underlying @@ -3349,7 +3611,8 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + +// static +void Builtins::Generate_InterpreterPushArgsThenCallImpl( -+ MacroAssembler* masm, InterpreterPushArgsMode mode) { ++ MacroAssembler* masm, ConvertReceiverMode receiver_mode, ++ InterpreterPushArgsMode mode) { + // ----------- S t a t e ------------- + // -- eax : the number of arguments (not including the receiver) + // -- ebx : the address of the first argument to be pushed. Subsequent @@ -3372,12 +3635,23 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + // Pop return address to allow tail-call after pushing arguments. + __ Pop(edx); + ++ // Push "undefined" as the receiver arg if we need to. ++ if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) { ++ __ PushRoot(Heap::kUndefinedValueRootIndex); ++ __ sub(ecx, Immediate(1)); // Subtract one for receiver. ++ } ++ + // Find the address of the last argument. + __ shl(ecx, kPointerSizeLog2); + __ neg(ecx); + __ add(ecx, ebx); + Generate_InterpreterPushArgs(masm, ecx, ebx); + ++ if (mode == InterpreterPushArgsMode::kWithFinalSpread) { ++ __ Pop(ebx); // Pass the spread in a register ++ __ sub(eax, Immediate(1)); // Subtract one for spread ++ } ++ + // Call the target. + __ Push(edx); // Re-push return address. + @@ -3410,10 +3684,10 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin +// This function modified start_addr, and only reads the contents of num_args +// register. scratch1 and scratch2 are used as temporary registers. Their +// original values are restored after the use. -+void Generate_InterpreterPushArgsThenReturnAddress( ++void Generate_InterpreterPushZeroAndArgsAndReturnAddress( + MacroAssembler* masm, Register num_args, Register start_addr, -+ Register scratch1, Register scratch2, bool receiver_in_args, -+ int num_slots_above_ret_addr, Label* stack_overflow) { ++ Register scratch1, Register scratch2, int num_slots_above_ret_addr, ++ Label* stack_overflow) { + // We have to move return address and the temporary registers above it + // before we can copy arguments onto the stack. To achieve this: + // Step 1: Increment the stack pointer by num_args + 1 (for receiver). @@ -3426,7 +3700,7 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + // | | | return addr | (2) + // | | | arg N | (3) + // | scratch1 | <-- esp | .... | -+ // | .... | | arg 0 | ++ // | .... | | arg 1 | + // | scratch-n | | arg 0 | + // | return addr | | receiver slot | + @@ -3470,17 +3744,12 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + } + + // Step 3 copy arguments to correct locations. -+ if (receiver_in_args) { -+ __ mov(scratch1, num_args); -+ __ add(scratch1, Immediate(1)); -+ } else { -+ // Slot meant for receiver contains return address. Reset it so that -+ // we will not incorrectly interpret return address as an object. -+ __ mov(Operand(esp, num_args, times_pointer_size, -+ (num_slots_above_ret_addr + 1) * kPointerSize), -+ Immediate(0)); -+ __ mov(scratch1, num_args); -+ } ++ // Slot meant for receiver contains return address. Reset it so that ++ // we will not incorrectly interpret return address as an object. ++ __ mov(Operand(esp, num_args, times_pointer_size, ++ (num_slots_above_ret_addr + 1) * kPointerSize), ++ Immediate(0)); ++ __ mov(scratch1, num_args); + + Label loop_header, loop_check; + __ jmp(&loop_check); @@ -3518,14 +3787,22 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + // Push arguments and move return address to the top of stack. + // The eax register is readonly. The ecx register will be modified. The edx + // and edi registers will be modified but restored to their original values. -+ Generate_InterpreterPushArgsThenReturnAddress(masm, eax, ecx, edx, edi, false, -+ 2, &stack_overflow); ++ Generate_InterpreterPushZeroAndArgsAndReturnAddress(masm, eax, ecx, edx, edi, ++ 2, &stack_overflow); + + // Restore edi and edx + __ Pop(edx); + __ Pop(edi); + -+ __ AssertUndefinedOrAllocationSite(ebx); ++ if (mode == InterpreterPushArgsMode::kWithFinalSpread) { ++ __ PopReturnAddressTo(ecx); ++ __ Pop(ebx); // Pass the spread in a register ++ __ PushReturnAddressFrom(ecx); ++ __ sub(eax, Immediate(1)); // Subtract one for spread ++ } else { ++ __ AssertUndefinedOrAllocationSite(ebx); ++ } ++ + if (mode == InterpreterPushArgsMode::kJSFunction) { + // Tail call to the function-specific construct stub (still in the caller + // context at this point). @@ -3577,8 +3854,8 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + // Push arguments and move return address to the top of stack. + // The eax register is readonly. The ecx register will be modified. The edx + // and edi registers will be modified but restored to their original values. -+ Generate_InterpreterPushArgsThenReturnAddress(masm, eax, ecx, edx, edi, true, -+ 1, &stack_overflow); ++ Generate_InterpreterPushZeroAndArgsAndReturnAddress(masm, eax, ecx, edx, edi, ++ 1, &stack_overflow); + + // Restore edx. + __ Pop(edx); @@ -3667,6 +3944,33 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + Generate_InterpreterEnterBytecode(masm); +} + ++void Builtins::Generate_CheckOptimizationMarker(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- rax : argument count (preserved for callee) ++ // -- rdx : new target (preserved for callee) ++ // -- rdi : target function (preserved for callee) ++ // ----------------------------------- ++ Register closure = edi; ++ ++ // Get the feedback vector. ++ Register feedback_vector = ebx; ++ __ mov(feedback_vector, ++ FieldOperand(closure, JSFunction::kFeedbackVectorOffset)); ++ __ mov(feedback_vector, FieldOperand(feedback_vector, Cell::kValueOffset)); ++ ++ // The feedback vector must be defined. ++ if (FLAG_debug_code) { ++ __ CompareRoot(feedback_vector, Heap::kUndefinedValueRootIndex); ++ __ Assert(not_equal, BailoutReason::kExpectedFeedbackVector); ++ } ++ ++ // Is there an optimization marker or optimized code in the feedback vector? ++ MaybeTailCallOptimizedCodeSlot(masm, feedback_vector, ecx); ++ ++ // Otherwise, tail call the SFI code. ++ GenerateTailCallToSharedCode(masm); ++} ++ +void Builtins::Generate_CompileLazy(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- eax : argument count (preserved for callee) @@ -3674,108 +3978,30 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + // -- edi : target function (preserved for callee) + // ----------------------------------- + // First lookup code, maybe we don't need to compile! -+ Label gotta_call_runtime, gotta_call_runtime_no_stack; -+ Label try_shared; -+ Label loop_top, loop_bottom; ++ Label gotta_call_runtime; + + Register closure = edi; -+ Register new_target = edx; -+ Register argument_count = eax; ++ Register feedback_vector = ebx; + + // Do we have a valid feedback vector? -+ __ mov(ebx, FieldOperand(closure, JSFunction::kFeedbackVectorOffset)); -+ __ mov(ebx, FieldOperand(ebx, Cell::kValueOffset)); -+ __ cmp(ebx, masm->isolate()->factory()->undefined_value()); -+ __ j(equal, &gotta_call_runtime_no_stack); ++ __ mov(feedback_vector, ++ FieldOperand(closure, JSFunction::kFeedbackVectorOffset)); ++ __ mov(feedback_vector, FieldOperand(feedback_vector, Cell::kValueOffset)); ++ __ JumpIfRoot(feedback_vector, Heap::kUndefinedValueRootIndex, ++ &gotta_call_runtime); + -+ __ push(argument_count); -+ __ push(new_target); -+ __ push(closure); ++ // Is there an optimization marker or optimized code in the feedback vector? ++ MaybeTailCallOptimizedCodeSlot(masm, feedback_vector, ecx); + -+ Register map = argument_count; -+ Register index = ebx; -+ __ mov(map, FieldOperand(closure, JSFunction::kSharedFunctionInfoOffset)); -+ __ mov(map, FieldOperand(map, SharedFunctionInfo::kOptimizedCodeMapOffset)); -+ __ mov(index, FieldOperand(map, FixedArray::kLengthOffset)); -+ __ cmp(index, Immediate(Smi::FromInt(2))); -+ __ j(less, &try_shared); -+ -+ // edx : native context -+ // ebx : length / index -+ // eax : optimized code map -+ // stack[0] : new target -+ // stack[4] : closure -+ Register native_context = edx; -+ __ mov(native_context, NativeContextOperand()); -+ -+ __ bind(&loop_top); -+ Register temp = edi; -+ -+ // Does the native context match? -+ __ mov(temp, FieldOperand(map, index, times_half_pointer_size, -+ SharedFunctionInfo::kOffsetToPreviousContext)); -+ __ mov(temp, FieldOperand(temp, WeakCell::kValueOffset)); -+ __ cmp(temp, native_context); -+ __ j(not_equal, &loop_bottom); -+ // Code available? ++ // We found no optimized code. + Register entry = ecx; -+ __ mov(entry, FieldOperand(map, index, times_half_pointer_size, -+ SharedFunctionInfo::kOffsetToPreviousCachedCode)); -+ __ mov(entry, FieldOperand(entry, WeakCell::kValueOffset)); -+ __ JumpIfSmi(entry, &try_shared); -+ -+ // Found code. Get it into the closure and return. -+ __ pop(closure); -+ // Store code entry in the closure. -+ __ lea(entry, FieldOperand(entry, Code::kHeaderSize)); -+ __ mov(FieldOperand(closure, JSFunction::kCodeEntryOffset), entry); -+ __ RecordWriteCodeEntryField(closure, entry, eax); -+ -+ // Link the closure into the optimized function list. -+ // ecx : code entry -+ // edx : native context -+ // edi : closure -+ __ mov(ebx, -+ ContextOperand(native_context, Context::OPTIMIZED_FUNCTIONS_LIST)); -+ __ mov(FieldOperand(closure, JSFunction::kNextFunctionLinkOffset), ebx); -+ __ RecordWriteField(closure, JSFunction::kNextFunctionLinkOffset, ebx, eax, -+ kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); -+ const int function_list_offset = -+ Context::SlotOffset(Context::OPTIMIZED_FUNCTIONS_LIST); -+ __ mov(ContextOperand(native_context, Context::OPTIMIZED_FUNCTIONS_LIST), -+ closure); -+ // Save closure before the write barrier. -+ __ mov(ebx, closure); -+ __ RecordWriteContextSlot(native_context, function_list_offset, closure, eax, -+ kDontSaveFPRegs); -+ __ mov(closure, ebx); -+ __ pop(new_target); -+ __ pop(argument_count); -+ __ jmp(entry); -+ -+ __ bind(&loop_bottom); -+ __ sub(index, Immediate(Smi::FromInt(SharedFunctionInfo::kEntryLength))); -+ __ cmp(index, Immediate(Smi::FromInt(1))); -+ __ j(greater, &loop_top); -+ -+ // We found no code. -+ __ jmp(&gotta_call_runtime); -+ -+ __ bind(&try_shared); -+ __ pop(closure); -+ __ pop(new_target); -+ __ pop(argument_count); + __ mov(entry, FieldOperand(closure, JSFunction::kSharedFunctionInfoOffset)); -+ // Is the shared function marked for tier up? -+ __ test(FieldOperand(entry, SharedFunctionInfo::kCompilerHintsOffset), -+ Immediate(SharedFunctionInfo::MarkedForTierUpBit::kMask)); -+ __ j(not_zero, &gotta_call_runtime_no_stack); + + // If SFI points to anything other than CompileLazy, install that. + __ mov(entry, FieldOperand(entry, SharedFunctionInfo::kCodeOffset)); + __ Move(ebx, masm->CodeObject()); + __ cmp(entry, ebx); -+ __ j(equal, &gotta_call_runtime_no_stack); ++ __ j(equal, &gotta_call_runtime); + + // Install the SFI's code entry. + __ lea(entry, FieldOperand(entry, Code::kHeaderSize)); @@ -3784,23 +4010,9 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + __ jmp(entry); + + __ bind(&gotta_call_runtime); -+ __ pop(closure); -+ __ pop(new_target); -+ __ pop(argument_count); -+ __ bind(&gotta_call_runtime_no_stack); -+ + GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy); +} + -+void Builtins::Generate_CompileOptimized(MacroAssembler* masm) { -+ GenerateTailCallToReturnedCode(masm, -+ Runtime::kCompileOptimized_NotConcurrent); -+} -+ -+void Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) { -+ GenerateTailCallToReturnedCode(masm, Runtime::kCompileOptimized_Concurrent); -+} -+ +void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- eax : argument count (preserved for callee) @@ -3942,6 +4154,72 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + Generate_MarkCodeAsExecutedOnce(masm); +} + ++void Builtins::Generate_NotifyBuiltinContinuation(MacroAssembler* masm) { ++ // Enter an internal frame. ++ { ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ // Preserve possible return result from lazy deopt. ++ __ push(eax); ++ __ CallRuntime(Runtime::kNotifyStubFailure, false); ++ __ pop(eax); ++ // Tear down internal frame. ++ } ++ ++ __ pop(MemOperand(esp, 0)); // Ignore state offset ++ __ ret(0); // Return to ContinueToBuiltin stub still on stack. ++} ++ ++namespace { ++void Generate_ContinueToBuiltinHelper(MacroAssembler* masm, ++ bool java_script_builtin, ++ bool with_result) { ++ const RegisterConfiguration* config(RegisterConfiguration::Turbofan()); ++ int allocatable_register_count = config->num_allocatable_general_registers(); ++ if (with_result) { ++ // Overwrite the hole inserted by the deoptimizer with the return value from ++ // the LAZY deopt point. ++ __ mov(Operand(esp, ++ config->num_allocatable_general_registers() * kPointerSize + ++ BuiltinContinuationFrameConstants::kFixedFrameSize), ++ eax); ++ } ++ for (int i = allocatable_register_count - 1; i >= 0; --i) { ++ int code = config->GetAllocatableGeneralCode(i); ++ __ pop(Register::from_code(code)); ++ if (java_script_builtin && code == kJavaScriptCallArgCountRegister.code()) { ++ __ SmiUntag(Register::from_code(code)); ++ } ++ } ++ __ mov( ++ ebp, ++ Operand(esp, BuiltinContinuationFrameConstants::kFixedFrameSizeFromFp)); ++ const int offsetToPC = ++ BuiltinContinuationFrameConstants::kFixedFrameSizeFromFp - kPointerSize; ++ __ pop(Operand(esp, offsetToPC)); ++ __ Drop(offsetToPC / kPointerSize); ++ __ add(Operand(esp, 0), Immediate(Code::kHeaderSize - kHeapObjectTag)); ++ __ ret(0); ++} ++} // namespace ++ ++void Builtins::Generate_ContinueToCodeStubBuiltin(MacroAssembler* masm) { ++ Generate_ContinueToBuiltinHelper(masm, false, false); ++} ++ ++void Builtins::Generate_ContinueToCodeStubBuiltinWithResult( ++ MacroAssembler* masm) { ++ Generate_ContinueToBuiltinHelper(masm, false, true); ++} ++ ++void Builtins::Generate_ContinueToJavaScriptBuiltin(MacroAssembler* masm) { ++ Generate_ContinueToBuiltinHelper(masm, true, false); ++} ++ ++void Builtins::Generate_ContinueToJavaScriptBuiltinWithResult( ++ MacroAssembler* masm) { ++ Generate_ContinueToBuiltinHelper(masm, true, true); ++} ++ +static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm, + Deoptimizer::BailoutType type) { + { @@ -3997,7 +4275,7 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + // -- esp[12] : receiver + // ----------------------------------- + -+ // 1. Load receiver into edi, argArray into eax (if present), remove all ++ // 1. Load receiver into edi, argArray into ebx (if present), remove all + // arguments from the stack (including the receiver), and push thisArg (if + // present) instead. + { @@ -4019,34 +4297,28 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize)); + __ Push(edx); + __ PushReturnAddressFrom(ecx); -+ __ Move(eax, ebx); + } + + // ----------- S t a t e ------------- -+ // -- eax : argArray ++ // -- ebx : argArray + // -- edi : receiver + // -- esp[0] : return address + // -- esp[4] : thisArg + // ----------------------------------- + -+ // 2. Make sure the receiver is actually callable. -+ Label receiver_not_callable; -+ __ JumpIfSmi(edi, &receiver_not_callable, Label::kNear); -+ __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset)); -+ __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), -+ Immediate(1 << Map::kIsCallable)); -+ __ j(zero, &receiver_not_callable, Label::kNear); ++ // 2. We don't need to check explicitly for callable receiver here, ++ // since that's the first thing the Call/CallWithArrayLike builtins ++ // will do. + + // 3. Tail call with no arguments if argArray is null or undefined. + Label no_arguments; -+ __ JumpIfRoot(eax, Heap::kNullValueRootIndex, &no_arguments, Label::kNear); -+ __ JumpIfRoot(eax, Heap::kUndefinedValueRootIndex, &no_arguments, ++ __ JumpIfRoot(ebx, Heap::kNullValueRootIndex, &no_arguments, Label::kNear); ++ __ JumpIfRoot(ebx, Heap::kUndefinedValueRootIndex, &no_arguments, + Label::kNear); + -+ // 4a. Apply the receiver to the given argArray (passing undefined for -+ // new.target). -+ __ LoadRoot(edx, Heap::kUndefinedValueRootIndex); -+ __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET); ++ // 4a. Apply the receiver to the given argArray. ++ __ Jump(masm->isolate()->builtins()->CallWithArrayLike(), ++ RelocInfo::CODE_TARGET); + + // 4b. The argArray is either null or undefined, so we tail call without any + // arguments to the receiver. @@ -4055,13 +4327,6 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + __ Set(eax, 0); + __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); + } -+ -+ // 4c. The receiver is not callable, throw an appropriate TypeError. -+ __ bind(&receiver_not_callable); -+ { -+ __ mov(Operand(esp, kPointerSize), edi); -+ __ TailCallRuntime(Runtime::kThrowApplyNonFunction); -+ } +} + +// static @@ -4120,7 +4385,7 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + // -- esp[16] : receiver + // ----------------------------------- + -+ // 1. Load target into edi (if present), argumentsList into eax (if present), ++ // 1. Load target into edi (if present), argumentsList into ebx (if present), + // remove all arguments from the stack (including the receiver), and push + // thisArgument (if present) instead. + { @@ -4141,35 +4406,22 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize)); + __ Push(edx); + __ PushReturnAddressFrom(ecx); -+ __ Move(eax, ebx); + } + + // ----------- S t a t e ------------- -+ // -- eax : argumentsList ++ // -- ebx : argumentsList + // -- edi : target + // -- esp[0] : return address + // -- esp[4] : thisArgument + // ----------------------------------- + -+ // 2. Make sure the target is actually callable. -+ Label target_not_callable; -+ __ JumpIfSmi(edi, &target_not_callable, Label::kNear); -+ __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset)); -+ __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), -+ Immediate(1 << Map::kIsCallable)); -+ __ j(zero, &target_not_callable, Label::kNear); ++ // 2. We don't need to check explicitly for callable target here, ++ // since that's the first thing the Call/CallWithArrayLike builtins ++ // will do. + -+ // 3a. Apply the target to the given argumentsList (passing undefined for -+ // new.target). -+ __ LoadRoot(edx, Heap::kUndefinedValueRootIndex); -+ __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET); -+ -+ // 3b. The target is not callable, throw an appropriate TypeError. -+ __ bind(&target_not_callable); -+ { -+ __ mov(Operand(esp, kPointerSize), edi); -+ __ TailCallRuntime(Runtime::kThrowApplyNonFunction); -+ } ++ // 3. Apply the target to the given argumentsList. ++ __ Jump(masm->isolate()->builtins()->CallWithArrayLike(), ++ RelocInfo::CODE_TARGET); +} + +void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) { @@ -4182,7 +4434,7 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + // -- esp[16] : receiver + // ----------------------------------- + -+ // 1. Load target into edi (if present), argumentsList into eax (if present), ++ // 1. Load target into edi (if present), argumentsList into ebx (if present), + // new.target into edx (if present, otherwise use target), remove all + // arguments from the stack (including the receiver), and push thisArgument + // (if present) instead. @@ -4205,49 +4457,27 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize)); + __ PushRoot(Heap::kUndefinedValueRootIndex); + __ PushReturnAddressFrom(ecx); -+ __ Move(eax, ebx); + } + + // ----------- S t a t e ------------- -+ // -- eax : argumentsList ++ // -- ebx : argumentsList + // -- edx : new.target + // -- edi : target + // -- esp[0] : return address + // -- esp[4] : receiver (undefined) + // ----------------------------------- + -+ // 2. Make sure the target is actually a constructor. -+ Label target_not_constructor; -+ __ JumpIfSmi(edi, &target_not_constructor, Label::kNear); -+ __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset)); -+ __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), -+ Immediate(1 << Map::kIsConstructor)); -+ __ j(zero, &target_not_constructor, Label::kNear); ++ // 2. We don't need to check explicitly for constructor target here, ++ // since that's the first thing the Construct/ConstructWithArrayLike ++ // builtins will do. + -+ // 3. Make sure the target is actually a constructor. -+ Label new_target_not_constructor; -+ __ JumpIfSmi(edx, &new_target_not_constructor, Label::kNear); -+ __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); -+ __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), -+ Immediate(1 << Map::kIsConstructor)); -+ __ j(zero, &new_target_not_constructor, Label::kNear); ++ // 3. We don't need to check explicitly for constructor new.target here, ++ // since that's the second thing the Construct/ConstructWithArrayLike ++ // builtins will do. + -+ // 4a. Construct the target with the given new.target and argumentsList. -+ __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET); -+ -+ // 4b. The target is not a constructor, throw an appropriate TypeError. -+ __ bind(&target_not_constructor); -+ { -+ __ mov(Operand(esp, kPointerSize), edi); -+ __ TailCallRuntime(Runtime::kThrowNotConstructor); -+ } -+ -+ // 4c. The new.target is not a constructor, throw an appropriate TypeError. -+ __ bind(&new_target_not_constructor); -+ { -+ __ mov(Operand(esp, kPointerSize), edx); -+ __ TailCallRuntime(Runtime::kThrowNotConstructor); -+ } ++ // 4. Construct the target with the given new.target and argumentsList. ++ __ Jump(masm->isolate()->builtins()->ConstructWithArrayLike(), ++ RelocInfo::CODE_TARGET); +} + +void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) { @@ -4604,7 +4834,7 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + __ mov(ebp, esp); + + // Store the arguments adaptor context sentinel. -+ __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); ++ __ push(Immediate(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR))); + + // Push the function on the stack. + __ push(edi); @@ -4632,97 +4862,26 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin +} + +// static -+void Builtins::Generate_Apply(MacroAssembler* masm) { ++void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm, ++ Handle code) { + // ----------- S t a t e ------------- -+ // -- eax : argumentsList + // -- edi : target ++ // -- eax : number of parameters on the stack (not including the receiver) ++ // -- ebx : arguments list (a FixedArray) ++ // -- ecx : len (number of elements to from args) + // -- edx : new.target (checked to be constructor or undefined) + // -- esp[0] : return address. -+ // -- esp[4] : thisArgument + // ----------------------------------- ++ __ AssertFixedArray(ebx); + -+ // Create the list of arguments from the array-like argumentsList. -+ { -+ Label create_arguments, create_array, create_holey_array, create_runtime, -+ done_create; -+ __ JumpIfSmi(eax, &create_runtime); -+ -+ // Load the map of argumentsList into ecx. -+ __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); -+ -+ // Load native context into ebx. -+ __ mov(ebx, NativeContextOperand()); -+ -+ // Check if argumentsList is an (unmodified) arguments object. -+ __ cmp(ecx, ContextOperand(ebx, Context::SLOPPY_ARGUMENTS_MAP_INDEX)); -+ __ j(equal, &create_arguments); -+ __ cmp(ecx, ContextOperand(ebx, Context::STRICT_ARGUMENTS_MAP_INDEX)); -+ __ j(equal, &create_arguments); -+ -+ // Check if argumentsList is a fast JSArray. -+ __ CmpInstanceType(ecx, JS_ARRAY_TYPE); -+ __ j(equal, &create_array); -+ -+ // Ask the runtime to create the list (actually a FixedArray). -+ __ bind(&create_runtime); -+ { -+ FrameScope scope(masm, StackFrame::INTERNAL); -+ __ Push(edi); -+ __ Push(edx); -+ __ Push(eax); -+ __ CallRuntime(Runtime::kCreateListFromArrayLike); -+ __ Pop(edx); -+ __ Pop(edi); -+ __ mov(ebx, FieldOperand(eax, FixedArray::kLengthOffset)); -+ __ SmiUntag(ebx); -+ } -+ __ jmp(&done_create); -+ -+ // Try to create the list from an arguments object. -+ __ bind(&create_arguments); -+ __ mov(ebx, FieldOperand(eax, JSArgumentsObject::kLengthOffset)); -+ __ mov(ecx, FieldOperand(eax, JSObject::kElementsOffset)); -+ __ cmp(ebx, FieldOperand(ecx, FixedArray::kLengthOffset)); -+ __ j(not_equal, &create_runtime); -+ __ SmiUntag(ebx); -+ __ mov(eax, ecx); -+ __ jmp(&done_create); -+ -+ // For holey JSArrays we need to check that the array prototype chain -+ // protector is intact and our prototype is the Array.prototype actually. -+ __ bind(&create_holey_array); -+ __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); -+ __ mov(ecx, FieldOperand(ecx, Map::kPrototypeOffset)); -+ __ cmp(ecx, ContextOperand(ebx, Context::INITIAL_ARRAY_PROTOTYPE_INDEX)); -+ __ j(not_equal, &create_runtime); -+ __ LoadRoot(ecx, Heap::kArrayProtectorRootIndex); -+ __ cmp(FieldOperand(ecx, PropertyCell::kValueOffset), -+ Immediate(Smi::FromInt(Isolate::kProtectorValid))); -+ __ j(not_equal, &create_runtime); -+ __ mov(ebx, FieldOperand(eax, JSArray::kLengthOffset)); -+ __ SmiUntag(ebx); -+ __ mov(eax, FieldOperand(eax, JSArray::kElementsOffset)); -+ __ jmp(&done_create); -+ -+ // Try to create the list from a JSArray object. -+ __ bind(&create_array); -+ __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset)); -+ __ DecodeField(ecx); -+ STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0); -+ STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1); -+ STATIC_ASSERT(PACKED_ELEMENTS == 2); -+ STATIC_ASSERT(HOLEY_ELEMENTS == 3); -+ __ cmp(ecx, Immediate(HOLEY_SMI_ELEMENTS)); -+ __ j(equal, &create_holey_array, Label::kNear); -+ __ cmp(ecx, Immediate(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); -+ } ++ // Save edx/edi/eax to stX0/stX1/stX2. ++ __ push(edx); ++ __ push(edi); ++ __ push(eax); ++ __ fld_s(MemOperand(esp, 0)); ++ __ fld_s(MemOperand(esp, 4)); ++ __ fld_s(MemOperand(esp, 8)); ++ __ lea(esp, Operand(esp, 3 * kFloatSize)); + + // Check for stack overflow. + { @@ -4731,109 +4890,97 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + Label done; + ExternalReference real_stack_limit = + ExternalReference::address_of_real_stack_limit(masm->isolate()); -+ __ mov(ecx, Operand::StaticVariable(real_stack_limit)); -+ // Make ecx the space we have left. The stack might already be overflowed -+ // here which will cause ecx to become negative. -+ __ neg(ecx); -+ __ add(ecx, esp); -+ __ sar(ecx, kPointerSizeLog2); ++ __ mov(edx, Operand::StaticVariable(real_stack_limit)); ++ // Make edx the space we have left. The stack might already be overflowed ++ // here which will cause edx to become negative. ++ __ neg(edx); ++ __ add(edx, esp); ++ __ sar(edx, kPointerSizeLog2); + // Check if the arguments will overflow the stack. -+ __ cmp(ecx, ebx); ++ __ cmp(edx, ecx); + __ j(greater, &done, Label::kNear); // Signed comparison. + __ TailCallRuntime(Runtime::kThrowStackOverflow); + __ bind(&done); + } + -+ // ----------- S t a t e ------------- -+ // -- edi : target -+ // -- eax : args (a FixedArray built from argumentsList) -+ // -- ebx : len (number of elements to push from args) -+ // -- edx : new.target (checked to be constructor or undefined) -+ // -- esp[0] : return address. -+ // -- esp[4] : thisArgument -+ // ----------------------------------- -+ -+ // Push arguments onto the stack (thisArgument is already on the stack). ++ // Push additional arguments onto the stack. + { -+ // Save edx/edi to stX0/stX1. -+ __ push(edx); -+ __ push(edi); -+ __ fld_s(MemOperand(esp, 0)); -+ __ fld_s(MemOperand(esp, 4)); -+ __ lea(esp, Operand(esp, 2 * kFloatSize)); -+ + __ PopReturnAddressTo(edx); -+ __ Move(ecx, Immediate(0)); ++ __ Move(eax, Immediate(0)); + Label done, push, loop; + __ bind(&loop); -+ __ cmp(ecx, ebx); ++ __ cmp(eax, ecx); + __ j(equal, &done, Label::kNear); + // Turn the hole into undefined as we go. + __ mov(edi, -+ FieldOperand(eax, ecx, times_pointer_size, FixedArray::kHeaderSize)); ++ FieldOperand(ebx, eax, times_pointer_size, FixedArray::kHeaderSize)); + __ CompareRoot(edi, Heap::kTheHoleValueRootIndex); + __ j(not_equal, &push, Label::kNear); + __ LoadRoot(edi, Heap::kUndefinedValueRootIndex); + __ bind(&push); + __ Push(edi); -+ __ inc(ecx); ++ __ inc(eax); + __ jmp(&loop); + __ bind(&done); + __ PushReturnAddressFrom(edx); -+ -+ // Restore edx/edi from stX0/stX1. -+ __ lea(esp, Operand(esp, -2 * kFloatSize)); -+ __ fstp_s(MemOperand(esp, 0)); -+ __ fstp_s(MemOperand(esp, 4)); -+ __ pop(edx); -+ __ pop(edi); -+ -+ __ Move(eax, ebx); + } + -+ // Dispatch to Call or Construct depending on whether new.target is undefined. -+ { -+ __ CompareRoot(edx, Heap::kUndefinedValueRootIndex); -+ __ j(equal, masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); -+ __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); -+ } ++ // Restore edx/edi/eax from stX0/stX1/stX2. ++ __ lea(esp, Operand(esp, -3 * kFloatSize)); ++ __ fstp_s(MemOperand(esp, 0)); ++ __ fstp_s(MemOperand(esp, 4)); ++ __ fstp_s(MemOperand(esp, 8)); ++ __ pop(edx); ++ __ pop(edi); ++ __ pop(eax); ++ ++ // Compute the actual parameter count. ++ __ add(eax, ecx); ++ ++ // Tail-call to the actual Call or Construct builtin. ++ __ Jump(code, RelocInfo::CODE_TARGET); +} + +// static -+void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm, -+ Handle code) { ++void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm, ++ Handle code) { + // ----------- S t a t e ------------- -+ // -- edi : the target to call (can be any Object) -+ // -- ecx : start index (to support rest parameters) -+ // -- esp[0] : return address. -+ // -- esp[4] : thisArgument ++ // -- eax : the number of arguments (not including the receiver) ++ // -- edi : the target to call (can be any Object) ++ // -- edx : the new target (for [[Construct]] calls) ++ // -- ecx : start index (to support rest parameters) + // ----------------------------------- + ++ // Preserve new.target (in case of [[Construct]]). ++ __ push(edx); ++ __ fld_s(MemOperand(esp, 0)); ++ __ lea(esp, Operand(esp, kFloatSize)); ++ + // Check if we have an arguments adaptor frame below the function frame. + Label arguments_adaptor, arguments_done; + __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); + __ cmp(Operand(ebx, CommonFrameConstants::kContextOrFrameTypeOffset), -+ Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); ++ Immediate(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR))); + __ j(equal, &arguments_adaptor, Label::kNear); + { -+ __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); -+ __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset)); -+ __ mov(eax, -+ FieldOperand(eax, SharedFunctionInfo::kFormalParameterCountOffset)); ++ __ mov(edx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); ++ __ mov(edx, FieldOperand(edx, JSFunction::kSharedFunctionInfoOffset)); ++ __ mov(edx, ++ FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); + __ mov(ebx, ebp); + } + __ jmp(&arguments_done, Label::kNear); + __ bind(&arguments_adaptor); + { + // Just load the length from the ArgumentsAdaptorFrame. -+ __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); -+ __ SmiUntag(eax); ++ __ mov(edx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); ++ __ SmiUntag(edx); + } + __ bind(&arguments_done); + -+ Label stack_empty, stack_done; -+ __ sub(eax, ecx); -+ __ j(less_equal, &stack_empty); ++ Label stack_done; ++ __ sub(edx, ecx); ++ __ j(less_equal, &stack_done); + { + // Check for stack overflow. + { @@ -4848,7 +4995,7 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + __ add(ecx, esp); + __ sar(ecx, kPointerSizeLog2); + // Check if the arguments will overflow the stack. -+ __ cmp(ecx, eax); ++ __ cmp(ecx, edx); + __ j(greater, &done, Label::kNear); // Signed comparison. + __ TailCallRuntime(Runtime::kThrowStackOverflow); + __ bind(&done); @@ -4857,25 +5004,25 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + // Forward the arguments from the caller frame. + { + Label loop; -+ __ mov(ecx, eax); -+ __ pop(edx); ++ __ add(eax, edx); ++ __ PopReturnAddressTo(ecx); + __ bind(&loop); + { -+ __ Push(Operand(ebx, ecx, times_pointer_size, 1 * kPointerSize)); -+ __ dec(ecx); ++ __ Push(Operand(ebx, edx, times_pointer_size, 1 * kPointerSize)); ++ __ dec(edx); + __ j(not_zero, &loop); + } -+ __ push(edx); ++ __ PushReturnAddressFrom(ecx); + } + } -+ __ jmp(&stack_done, Label::kNear); -+ __ bind(&stack_empty); -+ { -+ // We just pass the receiver, which is already on the stack. -+ __ Move(eax, Immediate(0)); -+ } + __ bind(&stack_done); + ++ // Restore new.target (in case of [[Construct]]). ++ __ lea(esp, Operand(esp, -kFloatSize)); ++ __ fstp_s(MemOperand(esp, 0)); ++ __ pop(edx); ++ ++ // Tail-call to the {code} handler. + __ Jump(code, RelocInfo::CODE_TARGET); +} + @@ -5111,12 +5258,12 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + __ j(equal, masm->isolate()->builtins()->CallBoundFunction(), + RelocInfo::CODE_TARGET); + -+ // Check if target has a [[Call]] internal method. ++ // Check if target is a proxy and call CallProxy external builtin + __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), + Immediate(1 << Map::kIsCallable)); + __ j(zero, &non_callable); + -+ // Check if target is a proxy and call CallProxy external builtin ++ // Call CallProxy external builtin + __ CmpInstanceType(ecx, JS_PROXY_TYPE); + __ j(not_equal, &non_function); + @@ -5145,199 +5292,6 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + } +} + -+static void CheckSpreadAndPushToStack(MacroAssembler* masm) { -+ // Free up some registers. -+ // Save edx/edi to stX0/stX1. -+ __ push(edx); -+ __ push(edi); -+ __ fld_s(MemOperand(esp, 0)); -+ __ fld_s(MemOperand(esp, 4)); -+ __ lea(esp, Operand(esp, 2 * kFloatSize)); -+ -+ Register argc = eax; -+ -+ Register scratch = ecx; -+ Register scratch2 = edi; -+ -+ Register spread = ebx; -+ Register spread_map = edx; -+ -+ Register spread_len = edx; -+ -+ Label runtime_call, push_args; -+ __ mov(spread, Operand(esp, kPointerSize)); -+ __ JumpIfSmi(spread, &runtime_call); -+ __ mov(spread_map, FieldOperand(spread, HeapObject::kMapOffset)); -+ -+ // Check that the spread is an array. -+ __ CmpInstanceType(spread_map, JS_ARRAY_TYPE); -+ __ j(not_equal, &runtime_call); -+ -+ // Check that we have the original ArrayPrototype. -+ __ mov(scratch, FieldOperand(spread_map, Map::kPrototypeOffset)); -+ __ mov(scratch2, NativeContextOperand()); -+ __ cmp(scratch, -+ ContextOperand(scratch2, Context::INITIAL_ARRAY_PROTOTYPE_INDEX)); -+ __ j(not_equal, &runtime_call); -+ -+ // Check that the ArrayPrototype hasn't been modified in a way that would -+ // affect iteration. -+ __ LoadRoot(scratch, Heap::kArrayIteratorProtectorRootIndex); -+ __ cmp(FieldOperand(scratch, PropertyCell::kValueOffset), -+ Immediate(Smi::FromInt(Isolate::kProtectorValid))); -+ __ j(not_equal, &runtime_call); -+ -+ // Check that the map of the initial array iterator hasn't changed. -+ __ mov(scratch2, NativeContextOperand()); -+ __ mov(scratch, -+ ContextOperand(scratch2, -+ Context::INITIAL_ARRAY_ITERATOR_PROTOTYPE_INDEX)); -+ __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); -+ __ cmp(scratch, -+ ContextOperand(scratch2, -+ Context::INITIAL_ARRAY_ITERATOR_PROTOTYPE_MAP_INDEX)); -+ __ j(not_equal, &runtime_call); -+ -+ // For FastPacked kinds, iteration will have the same effect as simply -+ // accessing each property in order. -+ Label no_protector_check; -+ __ mov(scratch, FieldOperand(spread_map, Map::kBitField2Offset)); -+ __ DecodeField(scratch); -+ __ cmp(scratch, Immediate(HOLEY_ELEMENTS)); -+ __ j(above, &runtime_call); -+ // For non-FastHoley kinds, we can skip the protector check. -+ __ cmp(scratch, Immediate(PACKED_SMI_ELEMENTS)); -+ __ j(equal, &no_protector_check); -+ __ cmp(scratch, Immediate(PACKED_ELEMENTS)); -+ __ j(equal, &no_protector_check); -+ // Check the ArrayProtector cell. -+ __ LoadRoot(scratch, Heap::kArrayProtectorRootIndex); -+ __ cmp(FieldOperand(scratch, PropertyCell::kValueOffset), -+ Immediate(Smi::FromInt(Isolate::kProtectorValid))); -+ __ j(not_equal, &runtime_call); -+ -+ __ bind(&no_protector_check); -+ // Load the FixedArray backing store, but use the length from the array. -+ __ mov(spread_len, FieldOperand(spread, JSArray::kLengthOffset)); -+ __ SmiUntag(spread_len); -+ __ mov(spread, FieldOperand(spread, JSArray::kElementsOffset)); -+ __ jmp(&push_args); -+ -+ __ bind(&runtime_call); -+ { -+ // Call the builtin for the result of the spread. -+ FrameScope scope(masm, StackFrame::INTERNAL); -+ // Need to save these on the stack. -+ // Restore edx/edi from stX0/stX1. -+ __ lea(esp, Operand(esp, -2 * kFloatSize)); -+ __ fstp_s(MemOperand(esp, 0)); -+ __ fstp_s(MemOperand(esp, 4)); -+ __ pop(edx); -+ __ pop(edi); -+ -+ __ Push(edi); -+ __ Push(edx); -+ __ SmiTag(argc); -+ __ Push(argc); -+ __ Push(spread); -+ __ CallRuntime(Runtime::kSpreadIterableFixed); -+ __ mov(spread, eax); -+ __ Pop(argc); -+ __ SmiUntag(argc); -+ __ Pop(edx); -+ __ Pop(edi); -+ // Free up some registers. -+ // Save edx/edi to stX0/stX1. -+ __ push(edx); -+ __ push(edi); -+ __ fld_s(MemOperand(esp, 0)); -+ __ fld_s(MemOperand(esp, 4)); -+ __ lea(esp, Operand(esp, 2 * kFloatSize)); -+ } -+ -+ { -+ // Calculate the new nargs including the result of the spread. -+ __ mov(spread_len, FieldOperand(spread, FixedArray::kLengthOffset)); -+ __ SmiUntag(spread_len); -+ -+ __ bind(&push_args); -+ // argc += spread_len - 1. Subtract 1 for the spread itself. -+ __ lea(argc, Operand(argc, spread_len, times_1, -1)); -+ } -+ -+ // Check for stack overflow. -+ { -+ // Check the stack for overflow. We are not trying to catch interruptions -+ // (i.e. debug break and preemption) here, so check the "real stack limit". -+ Label done; -+ __ LoadRoot(scratch, Heap::kRealStackLimitRootIndex); -+ // Make scratch the space we have left. The stack might already be -+ // overflowed here which will cause scratch to become negative. -+ __ neg(scratch); -+ __ add(scratch, esp); -+ __ sar(scratch, kPointerSizeLog2); -+ // Check if the arguments will overflow the stack. -+ __ cmp(scratch, spread_len); -+ __ j(greater, &done, Label::kNear); // Signed comparison. -+ __ TailCallRuntime(Runtime::kThrowStackOverflow); -+ __ bind(&done); -+ } -+ -+ // Put the evaluated spread onto the stack as additional arguments. -+ { -+ Register return_address = edi; -+ // Pop the return address and spread argument. -+ __ PopReturnAddressTo(return_address); -+ __ Pop(scratch); -+ -+ Register scratch2 = esi; -+ // Save esi to stX0, edx/edi in stX1/stX2 now. -+ __ push(esi); -+ __ fld_s(MemOperand(esp, 0)); -+ __ lea(esp, Operand(esp, 1 * kFloatSize)); -+ -+ __ mov(scratch, Immediate(0)); -+ Label done, push, loop; -+ __ bind(&loop); -+ __ cmp(scratch, spread_len); -+ __ j(equal, &done, Label::kNear); -+ __ mov(scratch2, FieldOperand(spread, scratch, times_pointer_size, -+ FixedArray::kHeaderSize)); -+ __ JumpIfNotRoot(scratch2, Heap::kTheHoleValueRootIndex, &push); -+ __ LoadRoot(scratch2, Heap::kUndefinedValueRootIndex); -+ __ bind(&push); -+ __ Push(scratch2); -+ __ inc(scratch); -+ __ jmp(&loop); -+ __ bind(&done); -+ __ PushReturnAddressFrom(return_address); -+ -+ // Now Restore esi from stX0, edx/edi from stX1/stX2. -+ __ lea(esp, Operand(esp, -3 * kFloatSize)); -+ __ fstp_s(MemOperand(esp, 0)); -+ __ fstp_s(MemOperand(esp, 4)); -+ __ fstp_s(MemOperand(esp, 8)); -+ __ pop(esi); -+ __ pop(edx); -+ __ pop(edi); -+ } -+} -+ -+// static -+void Builtins::Generate_CallWithSpread(MacroAssembler* masm) { -+ // ----------- S t a t e ------------- -+ // -- eax : the number of arguments (not including the receiver) -+ // -- edi : the target to call (can be any Object) -+ // ----------------------------------- -+ -+ // CheckSpreadAndPushToStack will push edx to save it. -+ __ LoadRoot(edx, Heap::kUndefinedValueRootIndex); -+ CheckSpreadAndPushToStack(masm); -+ __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny, -+ TailCallMode::kDisallow), -+ RelocInfo::CODE_TARGET); -+} -+ +// static +void Builtins::Generate_ConstructFunction(MacroAssembler* masm) { + // ----------- S t a t e ------------- @@ -5461,19 +5415,6 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin +} + +// static -+void Builtins::Generate_ConstructWithSpread(MacroAssembler* masm) { -+ // ----------- S t a t e ------------- -+ // -- eax : the number of arguments (not including the receiver) -+ // -- edx : the new target (either the same as the constructor or -+ // the JSFunction on which new was invoked initially) -+ // -- edi : the constructor to call (can be any Object) -+ // ----------------------------------- -+ -+ CheckSpreadAndPushToStack(masm); -+ __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); -+} -+ -+// static +void Builtins::Generate_AllocateInNewSpace(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- edx : requested object size (untagged) @@ -5684,6 +5625,35 @@ diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtin + Generate_OnStackReplacementHelper(masm, true); +} + ++void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) { ++ { ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ ++ // Save all parameter registers (see wasm-linkage.cc). They might be ++ // overwritten in the runtime call below. We don't have any callee-saved ++ // registers in wasm, so no need to store anything else. ++ constexpr Register gp_regs[]{eax, ebx, ecx, edx, esi}; ++ ++ for (auto reg : gp_regs) { ++ __ Push(reg); ++ } ++ ++ // Initialize esi register with kZero, CEntryStub will use it to set the ++ // current context on the isolate. ++ __ Move(esi, Smi::kZero); ++ __ CallRuntime(Runtime::kWasmCompileLazy); ++ // Store returned instruction start in edi. ++ __ lea(edi, FieldOperand(eax, Code::kHeaderSize)); ++ ++ // Restore registers. ++ for (int i = arraysize(gp_regs) - 1; i >= 0; --i) { ++ __ Pop(gp_regs[i]); ++ } ++ } ++ // Now jump to the instructions of the returned code object. ++ __ jmp(edi); ++} ++ +#undef __ +} // namespace internal +} // namespace v8