Index: src/arm/builtins-arm.cc |
diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc |
index e3774cb27d50f3b97a9d9f4cdc80ec775d30b789..50066137e404759f01b1f57456002a8144660f92 100644 |
--- a/src/arm/builtins-arm.cc |
+++ b/src/arm/builtins-arm.cc |
@@ -10,6 +10,7 @@ |
#include "src/debug.h" |
#include "src/deoptimizer.h" |
#include "src/full-codegen/full-codegen.h" |
+#include "src/interpreter/bytecodes.h" |
#include "src/runtime/runtime.h" |
namespace v8 { |
@@ -869,6 +870,143 @@ void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { |
} |
+// 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 |
+// count expected by the function. |
+// |
+// The live registers are: |
+// o r1: the JS function object being called. |
+// o cp: our context |
+// o pp: the caller's constant pool pointer (if enabled) |
+// o fp: the caller's frame pointer |
+// o sp: stack pointer |
+// o lr: return address |
+// |
+// The function builds a JS frame. Please see JavaScriptFrameConstants in |
+// frames-arm.h for its layout. |
+// TODO(rmcilroy): We will need to include the current bytecode pointer in the |
+// frame. |
+void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* 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). |
+ FrameScope frame_scope(masm, StackFrame::MANUAL); |
+ __ PushFixedFrame(r1); |
+ __ add(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp)); |
+ |
+ // Get the bytecode array from the function object and load the pointer to the |
+ // first entry into kInterpreterBytecodeRegister. |
+ __ ldr(r0, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); |
+ __ ldr(kInterpreterBytecodeArrayRegister, |
+ FieldMemOperand(r0, SharedFunctionInfo::kFunctionDataOffset)); |
+ |
+ if (FLAG_debug_code) { |
+ // Check function data field is actually a BytecodeArray object. |
+ __ SmiTst(kInterpreterBytecodeArrayRegister); |
+ __ Assert(ne, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry); |
+ __ CompareObjectType(kInterpreterBytecodeArrayRegister, r0, no_reg, |
+ BYTECODE_ARRAY_TYPE); |
+ __ Assert(eq, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry); |
+ } |
+ |
+ // Allocate the local and temporary register file on the stack. |
+ { |
+ // Load frame size from the BytecodeArray object. |
+ __ ldr(r4, FieldMemOperand(kInterpreterBytecodeArrayRegister, |
+ BytecodeArray::kFrameSizeOffset)); |
+ |
+ // Do a stack check to ensure we don't go over the limit. |
+ Label ok; |
+ __ sub(r9, sp, Operand(r4)); |
+ __ LoadRoot(r2, Heap::kRealStackLimitRootIndex); |
+ __ cmp(r9, Operand(r2)); |
+ __ b(hs, &ok); |
+ __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION); |
+ __ bind(&ok); |
+ |
+ // If ok, push undefined as the initial value for all register file entries. |
+ // Note: there should always be at least one stack slot for the return |
+ // register in the register file. |
+ Label loop_header; |
+ __ LoadRoot(r9, Heap::kUndefinedValueRootIndex); |
+ __ bind(&loop_header); |
+ // TODO(rmcilroy): Consider doing more than one push per loop iteration. |
+ __ push(r9); |
+ // Continue loop if not done. |
+ __ sub(r4, r4, Operand(kPointerSize), SetCC); |
+ __ b(&loop_header, ne); |
+ } |
+ |
+ // TODO(rmcilroy): List of things not currently dealt with here but done in |
+ // fullcodegen's prologue: |
+ // - Support profiler (specifically profiling_counter). |
+ // - Call ProfileEntryHookStub when isolate has a function_entry_hook. |
+ // - Allow simulator stop operations if FLAG_stop_at is set. |
+ // - Deal with sloppy mode functions which need to replace the |
+ // receiver with the global proxy when called as functions (without an |
+ // explicit receiver object). |
+ // - Code aging of the BytecodeArray object. |
+ // - Supporting FLAG_trace. |
+ // |
+ // The following items are also not done here, and will probably be done using |
+ // explicit bytecodes instead: |
+ // - Allocating a new local context if applicable. |
+ // - Setting up a local binding to the this function, which is used in |
+ // derived constructors with super calls. |
+ // - Setting new.target if required. |
+ // - Dealing with REST parameters (only if |
+ // https://codereview.chromium.org/1235153006 doesn't land by then). |
+ // - Dealing with argument objects. |
+ |
+ // Perform stack guard check. |
+ { |
+ Label ok; |
+ __ LoadRoot(ip, Heap::kStackLimitRootIndex); |
+ __ cmp(sp, Operand(ip)); |
+ __ b(hs, &ok); |
+ __ CallRuntime(Runtime::kStackGuard, 0); |
+ __ bind(&ok); |
+ } |
+ |
+ // Load bytecode offset and dispatch table into registers. |
+ __ mov(kInterpreterBytecodeOffsetRegister, |
+ Operand(BytecodeArray::kHeaderSize - kHeapObjectTag)); |
+ __ LoadRoot(kInterpreterDispatchTableRegister, |
+ Heap::kInterpreterTableRootIndex); |
+ __ add(kInterpreterDispatchTableRegister, kInterpreterDispatchTableRegister, |
+ Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
+ |
+ // Dispatch to the first bytecode handler for the function. |
+ __ ldrb(r0, MemOperand(kInterpreterBytecodeArrayRegister, |
+ kInterpreterBytecodeOffsetRegister)); |
+ __ ldr(ip, MemOperand(kInterpreterDispatchTableRegister, r0, LSL, |
+ kPointerSizeLog2)); |
+ // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging |
+ // and header removal. |
+ __ add(ip, ip, Operand(Code::kHeaderSize - kHeapObjectTag)); |
+ __ Jump(ip); |
+} |
+ |
+ |
+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). |
+ |
+ // Load return value into r0. |
+ __ ldr(r0, MemOperand(fp, -kPointerSize - |
+ StandardFrameConstants::kFixedFrameSizeFromFp)); |
+ // Leave the frame (also dropping the register file). |
+ __ LeaveFrame(StackFrame::JAVA_SCRIPT); |
+ // Drop receiver + arguments. |
+ __ Drop(1); // TODO(rmcilroy): Get number of arguments from BytecodeArray. |
+ __ Jump(lr); |
+} |
+ |
+ |
void Builtins::Generate_CompileLazy(MacroAssembler* masm) { |
CallRuntimePassFunction(masm, Runtime::kCompileLazy); |
GenerateTailCallToReturnedCode(masm); |