Merge V8 5.2.361.47 DO NOT MERGE
https://chromium.googlesource.com/v8/v8/+/5.2.361.47
FPIIM-449
Change-Id: Ibec421b85a9b88cb3a432ada642e469fe7e78346
(cherry picked from commit bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8)
diff --git a/src/arm64/builtins-arm64.cc b/src/arm64/builtins-arm64.cc
index 44bfc17..be372e6 100644
--- a/src/arm64/builtins-arm64.cc
+++ b/src/arm64/builtins-arm64.cc
@@ -605,16 +605,9 @@
// x0: number of arguments
// x1: constructor function
// x3: new target
- if (is_api_function) {
- __ Ldr(cp, FieldMemOperand(constructor, JSFunction::kContextOffset));
- Handle<Code> code =
- masm->isolate()->builtins()->HandleApiCallConstruct();
- __ Call(code, RelocInfo::CODE_TARGET);
- } else {
- ParameterCount actual(argc);
- __ InvokeFunction(constructor, new_target, actual, CALL_FUNCTION,
- CheckDebugStepCallWrapper());
- }
+ ParameterCount actual(argc);
+ __ InvokeFunction(constructor, new_target, actual, CALL_FUNCTION,
+ CheckDebugStepCallWrapper());
// Store offset of return address for deoptimizer.
if (create_implicit_receiver && !is_api_function) {
@@ -711,6 +704,132 @@
__ CallRuntime(Runtime::kThrowConstructedNonConstructable);
}
+// static
+void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- x0 : the value to pass to the generator
+ // -- x1 : the JSGeneratorObject to resume
+ // -- x2 : the resume mode (tagged)
+ // -- lr : return address
+ // -----------------------------------
+ __ AssertGeneratorObject(x1);
+
+ // Store input value into generator object.
+ __ Str(x0, FieldMemOperand(x1, JSGeneratorObject::kInputOffset));
+ __ RecordWriteField(x1, JSGeneratorObject::kInputOffset, x0, x3,
+ kLRHasNotBeenSaved, kDontSaveFPRegs);
+
+ // Store resume mode into generator object.
+ __ Str(x2, FieldMemOperand(x1, JSGeneratorObject::kResumeModeOffset));
+
+ // Load suspended function and context.
+ __ Ldr(cp, FieldMemOperand(x1, JSGeneratorObject::kContextOffset));
+ __ Ldr(x4, FieldMemOperand(x1, JSGeneratorObject::kFunctionOffset));
+
+ // Flood function if we are stepping.
+ Label skip_flooding;
+ ExternalReference step_in_enabled =
+ ExternalReference::debug_step_in_enabled_address(masm->isolate());
+ __ Mov(x10, Operand(step_in_enabled));
+ __ Ldrb(x10, MemOperand(x10));
+ __ CompareAndBranch(x10, Operand(0), eq, &skip_flooding);
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ __ Push(x1, x2, x4);
+ __ CallRuntime(Runtime::kDebugPrepareStepInIfStepping);
+ __ Pop(x2, x1);
+ __ Ldr(x4, FieldMemOperand(x1, JSGeneratorObject::kFunctionOffset));
+ }
+ __ bind(&skip_flooding);
+
+ // Push receiver.
+ __ Ldr(x5, FieldMemOperand(x1, JSGeneratorObject::kReceiverOffset));
+ __ Push(x5);
+
+ // ----------- S t a t e -------------
+ // -- x1 : the JSGeneratorObject to resume
+ // -- x2 : the resume mode (tagged)
+ // -- x4 : generator function
+ // -- cp : generator context
+ // -- lr : return address
+ // -- jssp[0] : generator receiver
+ // -----------------------------------
+
+ // Push holes for arguments to generator function. Since the parser forced
+ // context allocation for any variables in generators, the actual argument
+ // values have already been copied into the context and these dummy values
+ // will never be used.
+ __ Ldr(x10, FieldMemOperand(x4, JSFunction::kSharedFunctionInfoOffset));
+ __ Ldr(w10,
+ FieldMemOperand(x10, SharedFunctionInfo::kFormalParameterCountOffset));
+ __ LoadRoot(x11, Heap::kTheHoleValueRootIndex);
+ __ PushMultipleTimes(x11, w10);
+
+ // Dispatch on the kind of generator object.
+ Label old_generator;
+ __ Ldr(x3, FieldMemOperand(x4, JSFunction::kSharedFunctionInfoOffset));
+ __ Ldr(x3, FieldMemOperand(x3, SharedFunctionInfo::kFunctionDataOffset));
+ __ CompareObjectType(x3, x3, x3, BYTECODE_ARRAY_TYPE);
+ __ B(ne, &old_generator);
+
+ // New-style (ignition/turbofan) generator object
+ {
+ __ Ldr(x0, FieldMemOperand(x4, JSFunction::kSharedFunctionInfoOffset));
+ __ Ldr(x0,
+ FieldMemOperand(x0, SharedFunctionInfo::kFormalParameterCountOffset));
+ __ SmiUntag(x0);
+ // We abuse new.target both to indicate that this is a resume call and to
+ // pass in the generator object. In ordinary calls, new.target is always
+ // undefined because generator functions are non-constructable.
+ __ Move(x3, x1);
+ __ Move(x1, x4);
+ __ Ldr(x5, FieldMemOperand(x1, JSFunction::kCodeEntryOffset));
+ __ Jump(x5);
+ }
+
+ // Old-style (full-codegen) generator object
+ __ bind(&old_generator);
+ {
+ // Enter a new JavaScript frame, and initialize its slots as they were when
+ // the generator was suspended.
+ FrameScope scope(masm, StackFrame::MANUAL);
+ __ Push(lr, fp);
+ __ Move(fp, jssp);
+ __ Push(cp, x4);
+
+ // Restore the operand stack.
+ __ Ldr(x0, FieldMemOperand(x1, JSGeneratorObject::kOperandStackOffset));
+ __ Ldr(w3, UntagSmiFieldMemOperand(x0, FixedArray::kLengthOffset));
+ __ Add(x0, x0, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+ __ Add(x3, x0, Operand(x3, LSL, kPointerSizeLog2));
+ {
+ Label done_loop, loop;
+ __ Bind(&loop);
+ __ Cmp(x0, x3);
+ __ B(eq, &done_loop);
+ __ Ldr(x10, MemOperand(x0, kPointerSize, PostIndex));
+ __ Push(x10);
+ __ B(&loop);
+ __ Bind(&done_loop);
+ }
+
+ // Reset operand stack so we don't leak.
+ __ LoadRoot(x10, Heap::kEmptyFixedArrayRootIndex);
+ __ Str(x10, FieldMemOperand(x1, JSGeneratorObject::kOperandStackOffset));
+
+ // Resume the generator function at the continuation.
+ __ Ldr(x10, FieldMemOperand(x4, JSFunction::kSharedFunctionInfoOffset));
+ __ Ldr(x10, FieldMemOperand(x10, SharedFunctionInfo::kCodeOffset));
+ __ Add(x10, x10, Code::kHeaderSize - kHeapObjectTag);
+ __ Ldrsw(x11,
+ UntagSmiFieldMemOperand(x1, JSGeneratorObject::kContinuationOffset));
+ __ Add(x10, x10, x11);
+ __ Mov(x12, Smi::FromInt(JSGeneratorObject::kGeneratorExecuting));
+ __ Str(x12, FieldMemOperand(x1, JSGeneratorObject::kContinuationOffset));
+ __ Move(x0, x1); // Continuation expects generator object in x0.
+ __ Br(x10);
+ }
+}
enum IsTagged { kArgcIsSmiTagged, kArgcIsUntaggedInt };
@@ -844,7 +963,6 @@
Generate_JSEntryTrampolineHelper(masm, true);
}
-
// 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
@@ -861,6 +979,8 @@
// The function builds an interpreter frame. See InterpreterFrameConstants in
// frames.h for its layout.
void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
+ ProfileEntryHookStub::MaybeCallEntryHook(masm);
+
// 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).
@@ -868,8 +988,8 @@
__ Push(lr, fp, cp, x1);
__ Add(fp, jssp, StandardFrameConstants::kFixedFrameSizeFromFp);
- // Get the bytecode array from the function object and load the pointer to the
- // first entry into kInterpreterBytecodeRegister.
+ // Get the bytecode array from the function object (or from the DebugInfo if
+ // it is present) and load it into kInterpreterBytecodeArrayRegister.
__ Ldr(x0, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
Register debug_info = kInterpreterBytecodeArrayRegister;
Label load_debug_bytecode_array, bytecode_array_loaded;
@@ -881,8 +1001,12 @@
FieldMemOperand(x0, SharedFunctionInfo::kFunctionDataOffset));
__ Bind(&bytecode_array_loaded);
+ // Check function data field is actually a BytecodeArray object.
+ Label bytecode_array_not_present;
+ __ CompareRoot(kInterpreterBytecodeArrayRegister,
+ Heap::kUndefinedValueRootIndex);
+ __ B(eq, &bytecode_array_not_present);
if (FLAG_debug_code) {
- // Check function data field is actually a BytecodeArray object.
__ AssertNotSmi(kInterpreterBytecodeArrayRegister,
kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
__ CompareObjectType(kInterpreterBytecodeArrayRegister, x0, x0,
@@ -890,8 +1014,12 @@
__ Assert(eq, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
}
- // Push new.target, bytecode array and zero for bytecode array offset.
- __ Mov(x0, Operand(0));
+ // Load the initial bytecode offset.
+ __ Mov(kInterpreterBytecodeOffsetRegister,
+ Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
+
+ // Push new.target, bytecode array and Smi tagged bytecode array offset.
+ __ SmiTag(x0, kInterpreterBytecodeOffsetRegister);
__ Push(x3, kInterpreterBytecodeArrayRegister, x0);
// Allocate the local and temporary register file on the stack.
@@ -921,18 +1049,8 @@
__ Bind(&loop_header);
}
- // TODO(rmcilroy): List of things not currently dealt with here but done in
- // fullcodegen's prologue:
- // - Call ProfileEntryHookStub when isolate has a function_entry_hook.
- // - Code aging of the BytecodeArray object.
-
- // Load accumulator, register file, bytecode offset, dispatch table into
- // registers.
+ // Load accumulator and dispatch table into registers.
__ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
- __ Add(kInterpreterRegisterFileRegister, fp,
- Operand(InterpreterFrameConstants::kRegisterFilePointerFromFp));
- __ Mov(kInterpreterBytecodeOffsetRegister,
- Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
__ Mov(kInterpreterDispatchTableRegister,
Operand(ExternalReference::interpreter_dispatch_table_address(
masm->isolate())));
@@ -942,60 +1060,130 @@
kInterpreterBytecodeOffsetRegister));
__ Mov(x1, Operand(x1, LSL, kPointerSizeLog2));
__ Ldr(ip0, MemOperand(kInterpreterDispatchTableRegister, x1));
- // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
- // and header removal.
- __ Add(ip0, ip0, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Call(ip0);
+ masm->isolate()->heap()->SetInterpreterEntryReturnPCOffset(masm->pc_offset());
- // Even though the first bytecode handler was called, we will never return.
- __ Abort(kUnexpectedReturnFromBytecodeHandler);
+ // The return value is in x0.
+
+ // Get the arguments + reciever count.
+ __ ldr(x1, MemOperand(fp, InterpreterFrameConstants::kBytecodeArrayFromFp));
+ __ Ldr(w1, FieldMemOperand(x1, BytecodeArray::kParameterSizeOffset));
+
+ // Leave the frame (also dropping the register file).
+ __ LeaveFrame(StackFrame::JAVA_SCRIPT);
+
+ // Drop receiver + arguments and return.
+ __ Drop(x1, 1);
+ __ Ret();
// Load debug copy of the bytecode array.
__ Bind(&load_debug_bytecode_array);
__ Ldr(kInterpreterBytecodeArrayRegister,
FieldMemOperand(debug_info, DebugInfo::kAbstractCodeIndex));
__ B(&bytecode_array_loaded);
-}
-
-void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
- // TODO(rmcilroy): List of things not currently dealt with here but done in
- // fullcodegen's EmitReturnSequence.
- // - Supporting FLAG_trace for Runtime::TraceExit.
- // - Support profiler (specifically decrementing profiling_counter
- // appropriately and calling out to HandleInterrupts if necessary).
-
- // The return value is in accumulator, which is already in x0.
-
- // Leave the frame (also dropping the register file).
+ // If the bytecode array is no longer present, then the underlying function
+ // has been switched to a different kind of code and we heal the closure by
+ // switching the code entry field over to the new code object as well.
+ __ Bind(&bytecode_array_not_present);
__ LeaveFrame(StackFrame::JAVA_SCRIPT);
-
- // Drop receiver + arguments and return.
- __ Ldr(w1, FieldMemOperand(kInterpreterBytecodeArrayRegister,
- BytecodeArray::kParameterSizeOffset));
- __ Drop(x1, 1);
- __ Ret();
+ __ Ldr(x7, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
+ __ Ldr(x7, FieldMemOperand(x7, SharedFunctionInfo::kCodeOffset));
+ __ Add(x7, x7, Operand(Code::kHeaderSize - kHeapObjectTag));
+ __ Str(x7, FieldMemOperand(x1, JSFunction::kCodeEntryOffset));
+ __ RecordWriteCodeEntryField(x1, x7, x5);
+ __ Jump(x7);
}
+// static
+void Builtins::Generate_InterpreterPushArgsAndCallImpl(
+ MacroAssembler* masm, TailCallMode tail_call_mode) {
+ // ----------- S t a t e -------------
+ // -- x0 : the number of arguments (not including the receiver)
+ // -- x2 : 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.
+ // -- x1 : the target to call (can be any Object).
+ // -----------------------------------
-static void Generate_EnterBytecodeDispatch(MacroAssembler* masm) {
- // Initialize register file register and dispatch table register.
- __ Add(kInterpreterRegisterFileRegister, fp,
- Operand(InterpreterFrameConstants::kRegisterFilePointerFromFp));
+ // Find the address of the last argument.
+ __ add(x3, x0, Operand(1)); // Add one for receiver.
+ __ lsl(x3, x3, kPointerSizeLog2);
+ __ sub(x4, x2, x3);
+
+ // Push the arguments.
+ Label loop_header, loop_check;
+ __ Mov(x5, jssp);
+ __ Claim(x3, 1);
+ __ B(&loop_check);
+ __ Bind(&loop_header);
+ // TODO(rmcilroy): Push two at a time once we ensure we keep stack aligned.
+ __ Ldr(x3, MemOperand(x2, -kPointerSize, PostIndex));
+ __ Str(x3, MemOperand(x5, -kPointerSize, PreIndex));
+ __ Bind(&loop_check);
+ __ Cmp(x2, x4);
+ __ B(gt, &loop_header);
+
+ // Call the target.
+ __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
+ tail_call_mode),
+ RelocInfo::CODE_TARGET);
+}
+
+// static
+void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- x0 : argument count (not including receiver)
+ // -- x3 : new target
+ // -- x1 : constructor to call
+ // -- x2 : address of the first argument
+ // -----------------------------------
+
+ // Find the address of the last argument.
+ __ add(x5, x0, Operand(1)); // Add one for receiver (to be constructed).
+ __ lsl(x5, x5, kPointerSizeLog2);
+
+ // Set stack pointer and where to stop.
+ __ Mov(x6, jssp);
+ __ Claim(x5, 1);
+ __ sub(x4, x6, x5);
+
+ // Push a slot for the receiver.
+ __ Str(xzr, MemOperand(x6, -kPointerSize, PreIndex));
+
+ Label loop_header, loop_check;
+ // Push the arguments.
+ __ B(&loop_check);
+ __ Bind(&loop_header);
+ // TODO(rmcilroy): Push two at a time once we ensure we keep stack aligned.
+ __ Ldr(x5, MemOperand(x2, -kPointerSize, PostIndex));
+ __ Str(x5, MemOperand(x6, -kPointerSize, PreIndex));
+ __ Bind(&loop_check);
+ __ Cmp(x6, x4);
+ __ B(gt, &loop_header);
+
+ // Call the constructor with x0, x1, and x3 unmodified.
+ __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
+}
+
+void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
+ // Set the return address to the correct point in the interpreter entry
+ // trampoline.
+ Smi* interpreter_entry_return_pc_offset(
+ masm->isolate()->heap()->interpreter_entry_return_pc_offset());
+ DCHECK_NE(interpreter_entry_return_pc_offset, Smi::FromInt(0));
+ __ LoadObject(x1, masm->isolate()->builtins()->InterpreterEntryTrampoline());
+ __ Add(lr, x1, Operand(interpreter_entry_return_pc_offset->value() +
+ Code::kHeaderSize - kHeapObjectTag));
+
+ // Initialize the dispatch table register.
__ Mov(kInterpreterDispatchTableRegister,
Operand(ExternalReference::interpreter_dispatch_table_address(
masm->isolate())));
- // Get the context from the frame.
- __ Ldr(kContextRegister,
- MemOperand(kInterpreterRegisterFileRegister,
- InterpreterFrameConstants::kContextFromRegisterPointer));
-
// Get the bytecode array pointer from the frame.
- __ Ldr(
- kInterpreterBytecodeArrayRegister,
- MemOperand(kInterpreterRegisterFileRegister,
- InterpreterFrameConstants::kBytecodeArrayFromRegisterPointer));
+ __ Ldr(kInterpreterBytecodeArrayRegister,
+ MemOperand(fp, InterpreterFrameConstants::kBytecodeArrayFromFp));
if (FLAG_debug_code) {
// Check function data field is actually a BytecodeArray object.
@@ -1008,9 +1196,7 @@
// Get the target bytecode offset from the frame.
__ Ldr(kInterpreterBytecodeOffsetRegister,
- MemOperand(
- kInterpreterRegisterFileRegister,
- InterpreterFrameConstants::kBytecodeOffsetFromRegisterPointer));
+ MemOperand(fp, InterpreterFrameConstants::kBytecodeOffsetFromFp));
__ SmiUntag(kInterpreterBytecodeOffsetRegister);
// Dispatch to the target bytecode.
@@ -1018,63 +1204,147 @@
kInterpreterBytecodeOffsetRegister));
__ Mov(x1, Operand(x1, LSL, kPointerSizeLog2));
__ Ldr(ip0, MemOperand(kInterpreterDispatchTableRegister, x1));
- __ Add(ip0, ip0, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Jump(ip0);
}
-
-static void Generate_InterpreterNotifyDeoptimizedHelper(
- MacroAssembler* masm, Deoptimizer::BailoutType type) {
- // Enter an internal frame.
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
-
- // Pass the deoptimization type to the runtime system.
- __ Mov(x1, Operand(Smi::FromInt(static_cast<int>(type))));
- __ Push(x1);
- __ CallRuntime(Runtime::kNotifyDeoptimized);
- // Tear down internal frame.
- }
-
- // Drop state (we don't use these for interpreter deopts) and and pop the
- // accumulator value into the accumulator register.
- __ Drop(1);
- __ Pop(kInterpreterAccumulatorRegister);
-
- // Enter the bytecode dispatch.
- Generate_EnterBytecodeDispatch(masm);
-}
-
-
-void Builtins::Generate_InterpreterNotifyDeoptimized(MacroAssembler* masm) {
- Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
-}
-
-
-void Builtins::Generate_InterpreterNotifySoftDeoptimized(MacroAssembler* masm) {
- Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
-}
-
-
-void Builtins::Generate_InterpreterNotifyLazyDeoptimized(MacroAssembler* masm) {
- Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
-}
-
-void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
- // Set the address of the interpreter entry trampoline as a return address.
- // This simulates the initial call to bytecode handlers in interpreter entry
- // trampoline. The return will never actually be taken, but our stack walker
- // uses this address to determine whether a frame is interpreted.
- __ LoadObject(lr, masm->isolate()->builtins()->InterpreterEntryTrampoline());
-
- Generate_EnterBytecodeDispatch(masm);
-}
-
-
void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- x0 : argument count (preserved for callee)
+ // -- x3 : new target (preserved for callee)
+ // -- x1 : target function (preserved for callee)
+ // -----------------------------------
+ // First lookup code, maybe we don't need to compile!
+ Label gotta_call_runtime;
+ Label maybe_call_runtime;
+ Label try_shared;
+ Label loop_top, loop_bottom;
+
+ Register closure = x1;
+ Register map = x13;
+ Register index = x2;
+ __ Ldr(map, FieldMemOperand(closure, JSFunction::kSharedFunctionInfoOffset));
+ __ Ldr(map,
+ FieldMemOperand(map, SharedFunctionInfo::kOptimizedCodeMapOffset));
+ __ Ldrsw(index, UntagSmiFieldMemOperand(map, FixedArray::kLengthOffset));
+ __ Cmp(index, Operand(2));
+ __ B(lt, &gotta_call_runtime);
+
+ // Find literals.
+ // x3 : native context
+ // x2 : length / index
+ // x13 : optimized code map
+ // stack[0] : new target
+ // stack[4] : closure
+ Register native_context = x4;
+ __ Ldr(native_context, NativeContextMemOperand());
+
+ __ Bind(&loop_top);
+ Register temp = x5;
+ Register array_pointer = x6;
+
+ // Does the native context match?
+ __ Add(array_pointer, map, Operand(index, LSL, kPointerSizeLog2));
+ __ Ldr(temp, FieldMemOperand(array_pointer,
+ SharedFunctionInfo::kOffsetToPreviousContext));
+ __ Ldr(temp, FieldMemOperand(temp, WeakCell::kValueOffset));
+ __ Cmp(temp, native_context);
+ __ B(ne, &loop_bottom);
+ // OSR id set to none?
+ __ Ldr(temp, FieldMemOperand(array_pointer,
+ SharedFunctionInfo::kOffsetToPreviousOsrAstId));
+ const int bailout_id = BailoutId::None().ToInt();
+ __ Cmp(temp, Operand(Smi::FromInt(bailout_id)));
+ __ B(ne, &loop_bottom);
+ // Literals available?
+ __ Ldr(temp, FieldMemOperand(array_pointer,
+ SharedFunctionInfo::kOffsetToPreviousLiterals));
+ __ Ldr(temp, FieldMemOperand(temp, WeakCell::kValueOffset));
+ __ JumpIfSmi(temp, &gotta_call_runtime);
+
+ // Save the literals in the closure.
+ __ Str(temp, FieldMemOperand(closure, JSFunction::kLiteralsOffset));
+ __ RecordWriteField(closure, JSFunction::kLiteralsOffset, temp, x7,
+ kLRHasNotBeenSaved, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+
+ // Code available?
+ Register entry = x7;
+ __ Ldr(entry,
+ FieldMemOperand(array_pointer,
+ SharedFunctionInfo::kOffsetToPreviousCachedCode));
+ __ Ldr(entry, FieldMemOperand(entry, WeakCell::kValueOffset));
+ __ JumpIfSmi(entry, &maybe_call_runtime);
+
+ // Found literals and code. Get them into the closure and return.
+ __ Add(entry, entry, Operand(Code::kHeaderSize - kHeapObjectTag));
+
+ Label install_optimized_code_and_tailcall;
+ __ Bind(&install_optimized_code_and_tailcall);
+ __ Str(entry, FieldMemOperand(closure, JSFunction::kCodeEntryOffset));
+ __ RecordWriteCodeEntryField(closure, entry, x5);
+
+ // Link the closure into the optimized function list.
+ // x7 : code entry
+ // x4 : native context
+ // x1 : closure
+ __ Ldr(x8,
+ ContextMemOperand(native_context, Context::OPTIMIZED_FUNCTIONS_LIST));
+ __ Str(x8, FieldMemOperand(closure, JSFunction::kNextFunctionLinkOffset));
+ __ RecordWriteField(closure, JSFunction::kNextFunctionLinkOffset, x8, x13,
+ kLRHasNotBeenSaved, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+ const int function_list_offset =
+ Context::SlotOffset(Context::OPTIMIZED_FUNCTIONS_LIST);
+ __ Str(closure,
+ ContextMemOperand(native_context, Context::OPTIMIZED_FUNCTIONS_LIST));
+ __ Mov(x5, closure);
+ __ RecordWriteContextSlot(native_context, function_list_offset, x5, x13,
+ kLRHasNotBeenSaved, kDontSaveFPRegs);
+ __ Jump(entry);
+
+ __ Bind(&loop_bottom);
+ __ Sub(index, index, Operand(SharedFunctionInfo::kEntryLength));
+ __ Cmp(index, Operand(1));
+ __ B(gt, &loop_top);
+
+ // We found neither literals nor code.
+ __ B(&gotta_call_runtime);
+
+ __ Bind(&maybe_call_runtime);
+
+ // Last possibility. Check the context free optimized code map entry.
+ __ Ldr(entry, FieldMemOperand(map, FixedArray::kHeaderSize +
+ SharedFunctionInfo::kSharedCodeIndex));
+ __ Ldr(entry, FieldMemOperand(entry, WeakCell::kValueOffset));
+ __ JumpIfSmi(entry, &try_shared);
+
+ // Store code entry in the closure.
+ __ Add(entry, entry, Operand(Code::kHeaderSize - kHeapObjectTag));
+ __ B(&install_optimized_code_and_tailcall);
+
+ __ Bind(&try_shared);
+ // Is the full code valid?
+ __ Ldr(entry,
+ FieldMemOperand(closure, JSFunction::kSharedFunctionInfoOffset));
+ __ Ldr(entry, FieldMemOperand(entry, SharedFunctionInfo::kCodeOffset));
+ __ Ldr(x5, FieldMemOperand(entry, Code::kFlagsOffset));
+ __ and_(x5, x5, Operand(Code::KindField::kMask));
+ __ Mov(x5, Operand(x5, LSR, Code::KindField::kShift));
+ __ Cmp(x5, Operand(Code::BUILTIN));
+ __ B(eq, &gotta_call_runtime);
+ // Yes, install the full code.
+ __ Add(entry, entry, Operand(Code::kHeaderSize - kHeapObjectTag));
+ __ Str(entry, FieldMemOperand(closure, JSFunction::kCodeEntryOffset));
+ __ RecordWriteCodeEntryField(closure, entry, x5);
+ __ Jump(entry);
+
+ __ Bind(&gotta_call_runtime);
GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy);
}
+void Builtins::Generate_CompileBaseline(MacroAssembler* masm) {
+ GenerateTailCallToReturnedCode(masm, Runtime::kCompileBaseline);
+}
void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm,
@@ -1225,15 +1495,19 @@
// Switch on the state.
Label with_tos_register, unknown_state;
- __ CompareAndBranch(
- state, FullCodeGenerator::NO_REGISTERS, ne, &with_tos_register);
+ __ CompareAndBranch(state,
+ static_cast<int>(Deoptimizer::BailoutState::NO_REGISTERS),
+ ne, &with_tos_register);
__ Drop(1); // Remove state.
__ Ret();
__ Bind(&with_tos_register);
// Reload TOS register.
+ DCHECK_EQ(kInterpreterAccumulatorRegister.code(), x0.code());
__ Peek(x0, kPointerSize);
- __ CompareAndBranch(state, FullCodeGenerator::TOS_REG, ne, &unknown_state);
+ __ CompareAndBranch(state,
+ static_cast<int>(Deoptimizer::BailoutState::TOS_REGISTER),
+ ne, &unknown_state);
__ Drop(2); // Remove state and TOS.
__ Ret();
@@ -1439,30 +1713,6 @@
}
// static
-void Builtins::Generate_FunctionHasInstance(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- x0 : argc
- // -- jssp[0] : first argument (left-hand side)
- // -- jssp[8] : receiver (right-hand side)
- // -----------------------------------
- ASM_LOCATION("Builtins::Generate_FunctionHasInstance");
-
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
- __ Ldr(InstanceOfDescriptor::LeftRegister(),
- MemOperand(fp, 2 * kPointerSize)); // Load left-hand side.
- __ Ldr(InstanceOfDescriptor::RightRegister(),
- MemOperand(fp, 3 * kPointerSize)); // Load right-hand side.
- InstanceOfStub stub(masm->isolate(), true);
- __ CallStub(&stub);
- }
-
- // Pop the argument and the receiver.
- __ Drop(2);
- __ Ret();
-}
-
-// static
void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- x0 : argc
@@ -2434,80 +2684,33 @@
RelocInfo::CODE_TARGET);
}
-
// static
-void Builtins::Generate_InterpreterPushArgsAndCallImpl(
- MacroAssembler* masm, TailCallMode tail_call_mode) {
+void Builtins::Generate_AllocateInNewSpace(MacroAssembler* masm) {
+ ASM_LOCATION("Builtins::Generate_AllocateInNewSpace");
// ----------- S t a t e -------------
- // -- x0 : the number of arguments (not including the receiver)
- // -- x2 : 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.
- // -- x1 : the target to call (can be any Object).
+ // -- x1 : requested object size (untagged)
+ // -- lr : return address
// -----------------------------------
-
- // Find the address of the last argument.
- __ add(x3, x0, Operand(1)); // Add one for receiver.
- __ lsl(x3, x3, kPointerSizeLog2);
- __ sub(x4, x2, x3);
-
- // Push the arguments.
- Label loop_header, loop_check;
- __ Mov(x5, jssp);
- __ Claim(x3, 1);
- __ B(&loop_check);
- __ Bind(&loop_header);
- // TODO(rmcilroy): Push two at a time once we ensure we keep stack aligned.
- __ Ldr(x3, MemOperand(x2, -kPointerSize, PostIndex));
- __ Str(x3, MemOperand(x5, -kPointerSize, PreIndex));
- __ Bind(&loop_check);
- __ Cmp(x2, x4);
- __ B(gt, &loop_header);
-
- // Call the target.
- __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
- tail_call_mode),
- RelocInfo::CODE_TARGET);
+ __ SmiTag(x1);
+ __ Push(x1);
+ __ Move(cp, Smi::FromInt(0));
+ __ TailCallRuntime(Runtime::kAllocateInNewSpace);
}
-
// static
-void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
+void Builtins::Generate_AllocateInOldSpace(MacroAssembler* masm) {
+ ASM_LOCATION("Builtins::Generate_AllocateInOldSpace");
// ----------- S t a t e -------------
- // -- x0 : argument count (not including receiver)
- // -- x3 : new target
- // -- x1 : constructor to call
- // -- x2 : address of the first argument
+ // -- x1 : requested object size (untagged)
+ // -- lr : return address
// -----------------------------------
-
- // Find the address of the last argument.
- __ add(x5, x0, Operand(1)); // Add one for receiver (to be constructed).
- __ lsl(x5, x5, kPointerSizeLog2);
-
- // Set stack pointer and where to stop.
- __ Mov(x6, jssp);
- __ Claim(x5, 1);
- __ sub(x4, x6, x5);
-
- // Push a slot for the receiver.
- __ Str(xzr, MemOperand(x6, -kPointerSize, PreIndex));
-
- Label loop_header, loop_check;
- // Push the arguments.
- __ B(&loop_check);
- __ Bind(&loop_header);
- // TODO(rmcilroy): Push two at a time once we ensure we keep stack aligned.
- __ Ldr(x5, MemOperand(x2, -kPointerSize, PostIndex));
- __ Str(x5, MemOperand(x6, -kPointerSize, PreIndex));
- __ Bind(&loop_check);
- __ Cmp(x6, x4);
- __ B(gt, &loop_header);
-
- // Call the constructor with x0, x1, and x3 unmodified.
- __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
+ __ SmiTag(x1);
+ __ Move(x2, Smi::FromInt(AllocateTargetSpace::encode(OLD_SPACE)));
+ __ Push(x1, x2);
+ __ Move(cp, Smi::FromInt(0));
+ __ TailCallRuntime(Runtime::kAllocateInTargetSpace);
}
-
void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
ASM_LOCATION("Builtins::Generate_ArgumentsAdaptorTrampoline");
// ----------- S t a t e -------------