Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(180)

Unified Diff: src/deoptimizer.cc

Issue 2803853005: Inline Array.prototype.forEach in TurboFan (Closed)
Patch Set: Disable new array builtins by default Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/deoptimizer.h ('k') | src/flag-definitions.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/deoptimizer.cc
diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
index 6ad0b76c07f39abadc7a9fd41f684b008a836196..f5c56243a0fabda2932411d22bb12735241b8695 100644
--- a/src/deoptimizer.cc
+++ b/src/deoptimizer.cc
@@ -827,6 +827,12 @@ void Deoptimizer::DoComputeOutputFrames() {
case TranslatedFrame::kCompiledStub:
DoComputeCompiledStubFrame(translated_frame, frame_index);
break;
+ case TranslatedFrame::kBuiltinContinuation:
+ DoComputeBuiltinContinuation(translated_frame, frame_index, false);
+ break;
+ case TranslatedFrame::kJavaScriptBuiltinContinuation:
+ DoComputeBuiltinContinuation(translated_frame, frame_index, true);
+ break;
case TranslatedFrame::kInvalid:
FATAL("invalid frame");
break;
@@ -2161,6 +2167,292 @@ void Deoptimizer::DoComputeCompiledStubFrame(TranslatedFrame* translated_frame,
reinterpret_cast<intptr_t>(notify_failure->entry()));
}
+// BuiltinContinuationFrames capture the machine state that is expected as input
+// to a builtin, including both input register values and stack parameters. When
+// the frame is reactivated (i.e. the frame below it returns), a
+// ContinueToBuiltin stub restores the register state from the frame and tail
+// calls to the actual target builtin, making it appear that the stub had been
+// directly called by the frame above it. The input values to populate the frame
+// are taken from the deopt's FrameState.
+//
+// Frame translation happens in two modes, EAGER and LAZY. In EAGER mode, all of
+// the parameters to the Builtin are explicitly specified in the TurboFan
+// FrameState node. In LAZY mode, there is always one fewer parameters specified
+// in the FrameState than expected by the Builtin. In that case, construction of
+// BuiltinContinuationFrame adds the final missing parameter during
+// deoptimization, and that parameter is always on the stack and contains the
+// value returned from the callee of the call site triggering the LAZY deopt
+// (e.g. rax on x64). This requires that continuation Builtins for LAZY deopts
+// must have at least one stack parameter.
+//
+// TO
+// | .... |
+// +-------------------------+
+// | builtin param 0 |<- FrameState input value n becomes
+// +-------------------------+
+// | ... |
+// +-------------------------+
+// | builtin param m |<- FrameState input value n+m-1, or in
+// +-------------------------+ the LAZY case, return LAZY result value
+// | ContinueToBuiltin entry |
+// +-------------------------+
+// | | saved frame (FP) |
+// | +=========================+<- fpreg
+// | |constant pool (if ool_cp)|
+// v +-------------------------+
+// |BUILTIN_CONTINUATION mark|
+// +-------------------------+
+// | JS Builtin code object |
+// +-------------------------+
+// | builtin input GPR reg0 |<- populated from deopt FrameState using
+// +-------------------------+ the builtin's CallInterfaceDescriptor
+// | ... | to map a FrameState's 0..n-1 inputs to
+// +-------------------------+ the builtin's n input register params.
+// | builtin input GPR regn |
+// |-------------------------|<- spreg
+//
+void Deoptimizer::DoComputeBuiltinContinuation(
+ TranslatedFrame* translated_frame, int frame_index,
+ bool java_script_builtin) {
+ TranslatedFrame::iterator value_iterator = translated_frame->begin();
+ int input_index = 0;
+
+ // The output frame must have room for all of the parameters that need to be
+ // passed to the builtin continuation.
+ int height_in_words = translated_frame->height();
+
+ BailoutId bailout_id = translated_frame->node_id();
+ Builtins::Name builtin_name = Builtins::GetBuiltinFromBailoutId(bailout_id);
+ Code* builtin = isolate()->builtins()->builtin(builtin_name);
+ Callable continuation_callable =
+ Builtins::CallableFor(isolate(), builtin_name);
+ CallInterfaceDescriptor continuation_descriptor =
+ continuation_callable.descriptor();
+
+ bool is_bottommost = (0 == frame_index);
+ bool is_topmost = (output_count_ - 1 == frame_index);
+ bool must_handle_result = !is_topmost || bailout_type_ == LAZY;
+
+ const RegisterConfiguration* config(RegisterConfiguration::Turbofan());
+ int allocatable_register_count = config->num_allocatable_general_registers();
+ int register_parameter_count =
+ continuation_descriptor.GetRegisterParameterCount();
+ // Make sure to account for the context by removing it from the register
+ // parameter count.
+ int stack_param_count = height_in_words - register_parameter_count - 1;
+ if (must_handle_result) stack_param_count++;
+ int output_frame_size =
+ kPointerSize * (stack_param_count + allocatable_register_count) +
+ TYPED_FRAME_SIZE(2); // For destination builtin code and registers
+
+ // Validate types of parameters. They must all be tagged except for argc for
+ // JS builtins.
+ bool has_argc = false;
+ for (int i = 0; i < register_parameter_count; ++i) {
+ MachineType type = continuation_descriptor.GetParameterType(i);
+ int code = continuation_descriptor.GetRegisterParameter(i).code();
+ // Only tagged and int32 arguments are supported, and int32 only for the
+ // arguments count on JavaScript builtins.
+ if (type == MachineType::Int32()) {
+ CHECK_EQ(code, kJavaScriptCallArgCountRegister.code());
+ has_argc = true;
+ } else {
+ // Any other argument must be a tagged value.
+ CHECK(IsAnyTagged(type.representation()));
+ }
+ }
+ CHECK_EQ(java_script_builtin, has_argc);
+
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " translating BuiltinContinuation to %s, stack param count %d\n",
+ Builtins::name(builtin_name), stack_param_count);
+ }
+
+ unsigned output_frame_offset = output_frame_size;
+ FrameDescription* output_frame =
+ new (output_frame_size) FrameDescription(output_frame_size);
+ output_[frame_index] = output_frame;
+
+ // The top address of the frame is computed from the previous frame's top and
+ // this frame's size.
+ intptr_t top_address;
+ if (is_bottommost) {
+ top_address = caller_frame_top_ - output_frame_size;
+ } else {
+ top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
+ }
+ output_frame->SetTop(top_address);
+
+ output_frame->SetState(
+ Smi::FromInt(static_cast<int>(BailoutState::NO_REGISTERS)));
+
+ // Get the possible JSFunction for the case that
+ intptr_t maybe_function =
+ reinterpret_cast<intptr_t>(value_iterator->GetRawValue());
+ ++value_iterator;
+
+ std::vector<intptr_t> register_values;
+ int total_registers = config->num_general_registers();
+ register_values.resize(total_registers, 0);
+ for (int i = 0; i < total_registers; ++i) {
+ register_values[i] = 0;
+ }
+
+ intptr_t value;
+
+ Register result_reg = FullCodeGenerator::result_register();
+ if (must_handle_result) {
+ value = input_->GetRegister(result_reg.code());
+ } else {
+ value = reinterpret_cast<intptr_t>(isolate()->heap()->undefined_value());
+ }
+ output_frame->SetRegister(result_reg.code(), value);
+
+ int translated_stack_parameters =
+ must_handle_result ? stack_param_count - 1 : stack_param_count;
+
+ for (int i = 0; i < translated_stack_parameters; ++i) {
+ output_frame_offset -= kPointerSize;
+ WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index,
+ output_frame_offset);
+ }
+
+ if (must_handle_result) {
+ output_frame_offset -= kPointerSize;
+ WriteValueToOutput(isolate()->heap()->the_hole_value(), input_index,
+ frame_index, output_frame_offset,
+ "placeholder for return result on lazy deopt ");
+ }
+
+ for (int i = 0; i < register_parameter_count; ++i) {
+ value = reinterpret_cast<intptr_t>(value_iterator->GetRawValue());
+ int code = continuation_descriptor.GetRegisterParameter(i).code();
+ register_values[code] = value;
+ ++input_index;
+ ++value_iterator;
+ }
+
+ // The context register is always implicit in the CallInterfaceDescriptor but
+ // its register must be explicitly set when continuing to the builtin. Make
+ // sure that it's harvested from the translation and copied into the register
+ // set (it was automatically added at the end of the FrameState by the
+ // instruction selector).
+ value = reinterpret_cast<intptr_t>(value_iterator->GetRawValue());
+ register_values[kContextRegister.code()] = value;
+ output_frame->SetContext(value);
+ output_frame->SetRegister(kContextRegister.code(), value);
+ ++input_index;
+ ++value_iterator;
+
+ // Set caller's PC (JSFunction continuation).
+ output_frame_offset -= kPCOnStackSize;
+ if (is_bottommost) {
+ value = caller_pc_;
+ } else {
+ value = output_[frame_index - 1]->GetPc();
+ }
+ output_frame->SetCallerPc(output_frame_offset, value);
+ DebugPrintOutputSlot(value, frame_index, output_frame_offset,
+ "caller's pc\n");
+
+ // Read caller's FP from the previous frame, and set this frame's FP.
+ output_frame_offset -= kFPOnStackSize;
+ if (is_bottommost) {
+ value = caller_fp_;
+ } else {
+ value = output_[frame_index - 1]->GetFp();
+ }
+ output_frame->SetCallerFp(output_frame_offset, value);
+ intptr_t fp_value = top_address + output_frame_offset;
+ output_frame->SetFp(fp_value);
+ DebugPrintOutputSlot(value, frame_index, output_frame_offset,
+ "caller's fp\n");
+
+ if (FLAG_enable_embedded_constant_pool) {
+ // Read the caller's constant pool from the previous frame.
+ output_frame_offset -= kPointerSize;
+ if (is_bottommost) {
+ value = caller_constant_pool_;
+ } else {
+ value = output_[frame_index - 1]->GetConstantPool();
+ }
+ output_frame->SetCallerConstantPool(output_frame_offset, value);
+ DebugPrintOutputSlot(value, frame_index, output_frame_offset,
+ "caller's constant_pool\n");
+ }
+
+ // A marker value is used in place of the context.
+ output_frame_offset -= kPointerSize;
+ intptr_t marker =
+ java_script_builtin
+ ? StackFrame::TypeToMarker(
+ StackFrame::JAVA_SCRIPT_BUILTIN_CONTINUATION)
+ : StackFrame::TypeToMarker(StackFrame::BUILTIN_CONTINUATION);
+ output_frame->SetFrameSlot(output_frame_offset, marker);
+ DebugPrintOutputSlot(marker, frame_index, output_frame_offset,
+ "context (builtin continuation sentinel)\n");
+
+ output_frame_offset -= kPointerSize;
+ value = java_script_builtin ? maybe_function : 0;
+ output_frame->SetFrameSlot(output_frame_offset, value);
+ DebugPrintOutputSlot(value, frame_index, output_frame_offset,
+ java_script_builtin ? "JSFunction\n" : "unused\n");
+
+ // The builtin to continue to
+ output_frame_offset -= kPointerSize;
+ value = reinterpret_cast<intptr_t>(builtin);
+ output_frame->SetFrameSlot(output_frame_offset, value);
+ DebugPrintOutputSlot(value, frame_index, output_frame_offset,
+ "builtin address\n");
+
+ for (int i = 0; i < allocatable_register_count; ++i) {
+ output_frame_offset -= kPointerSize;
+ int code = config->GetAllocatableGeneralCode(i);
+ value = register_values[code];
+ output_frame->SetFrameSlot(output_frame_offset, value);
+ if (trace_scope_ != nullptr) {
+ ScopedVector<char> str(128);
+ if (java_script_builtin &&
+ code == kJavaScriptCallArgCountRegister.code()) {
+ SNPrintF(
+ str,
+ "tagged argument count %s (will be untagged by continuation)\n",
+ config->GetGeneralRegisterName(code));
+ } else {
+ SNPrintF(str, "builtin register argument %s\n",
+ config->GetGeneralRegisterName(code));
+ }
+ DebugPrintOutputSlot(value, frame_index, output_frame_offset,
+ str.start());
+ }
+ }
+
+ // Ensure the frame pointer register points to the callee's frame. The builtin
+ // will build its own frame once we continue to it.
+ Register fp_reg = JavaScriptFrame::fp_register();
+ output_frame->SetRegister(fp_reg.code(), output_[frame_index - 1]->GetFp());
+
+ Code* continue_to_builtin =
+ java_script_builtin
+ ? (must_handle_result
+ ? isolate()->builtins()->builtin(
+ Builtins::kContinueToJavaScriptBuiltinWithResult)
+ : isolate()->builtins()->builtin(
+ Builtins::kContinueToJavaScriptBuiltin))
+ : (must_handle_result
+ ? isolate()->builtins()->builtin(
+ Builtins::kContinueToCodeStubBuiltinWithResult)
+ : isolate()->builtins()->builtin(
+ Builtins::kContinueToCodeStubBuiltin));
+ output_frame->SetPc(
+ reinterpret_cast<intptr_t>(continue_to_builtin->instruction_start()));
+
+ Code* continuation =
+ isolate()->builtins()->builtin(Builtins::kNotifyBuiltinContinuation);
+ output_frame->SetContinuation(
+ reinterpret_cast<intptr_t>(continuation->entry()));
+}
void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) {
// Walk to the last JavaScript output frame to find out if it has
@@ -2405,6 +2697,24 @@ Handle<ByteArray> TranslationBuffer::CreateByteArray(Factory* factory) {
return result;
}
+void Translation::BeginBuiltinContinuationFrame(BailoutId bailout_id,
+ int literal_id,
+ unsigned height) {
+ buffer_->Add(BUILTIN_CONTINUATION_FRAME);
+ buffer_->Add(bailout_id.ToInt());
+ buffer_->Add(literal_id);
+ buffer_->Add(height);
+}
+
+void Translation::BeginJavaScriptBuiltinContinuationFrame(BailoutId bailout_id,
+ int literal_id,
+ unsigned height) {
+ buffer_->Add(JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME);
+ buffer_->Add(bailout_id.ToInt());
+ buffer_->Add(literal_id);
+ buffer_->Add(height);
+}
+
void Translation::BeginConstructStubFrame(BailoutId bailout_id, int literal_id,
unsigned height) {
buffer_->Add(CONSTRUCT_STUB_FRAME);
@@ -2607,6 +2917,8 @@ int Translation::NumberOfOperandsFor(Opcode opcode) {
case JS_FRAME:
case INTERPRETED_FRAME:
case CONSTRUCT_STUB_FRAME:
+ case BUILTIN_CONTINUATION_FRAME:
+ case JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME:
return 3;
case ARGUMENTS_ELEMENTS:
case ARGUMENTS_LENGTH:
@@ -3213,6 +3525,22 @@ TranslatedFrame TranslatedFrame::ConstructStubFrame(
return frame;
}
+TranslatedFrame TranslatedFrame::BuiltinContinuationFrame(
+ BailoutId bailout_id, SharedFunctionInfo* shared_info, int height) {
+ base::OS::DebugBreak();
+ TranslatedFrame frame(kBuiltinContinuation, shared_info->GetIsolate(),
+ shared_info, height);
+ frame.node_id_ = bailout_id;
+ return frame;
+}
+
+TranslatedFrame TranslatedFrame::JavaScriptBuiltinContinuationFrame(
+ BailoutId bailout_id, SharedFunctionInfo* shared_info, int height) {
+ TranslatedFrame frame(kJavaScriptBuiltinContinuation,
+ shared_info->GetIsolate(), shared_info, height);
+ frame.node_id_ = bailout_id;
+ return frame;
+}
int TranslatedFrame::GetValueCount() {
switch (kind()) {
@@ -3238,6 +3566,8 @@ int TranslatedFrame::GetValueCount() {
case kArgumentsAdaptor:
case kConstructStub:
+ case kBuiltinContinuation:
+ case kJavaScriptBuiltinContinuation:
return 1 + height_;
case kTailCallerFunction:
@@ -3341,6 +3671,38 @@ TranslatedFrame TranslatedState::CreateNextTranslatedFrame(
height);
}
+ case Translation::BUILTIN_CONTINUATION_FRAME: {
+ BailoutId bailout_id = BailoutId(iterator->Next());
+ SharedFunctionInfo* shared_info =
+ SharedFunctionInfo::cast(literal_array->get(iterator->Next()));
+ int height = iterator->Next();
+ if (trace_file != nullptr) {
+ std::unique_ptr<char[]> name = shared_info->DebugName()->ToCString();
+ PrintF(trace_file, " reading builtin continuation frame %s",
+ name.get());
+ PrintF(trace_file, " => bailout_id=%d, height=%d; inputs:\n",
+ bailout_id.ToInt(), height);
+ }
+ return TranslatedFrame::BuiltinContinuationFrame(bailout_id, shared_info,
+ height);
+ }
+
+ case Translation::JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME: {
+ BailoutId bailout_id = BailoutId(iterator->Next());
+ SharedFunctionInfo* shared_info =
+ SharedFunctionInfo::cast(literal_array->get(iterator->Next()));
+ int height = iterator->Next();
+ if (trace_file != nullptr) {
+ std::unique_ptr<char[]> name = shared_info->DebugName()->ToCString();
+ PrintF(trace_file, " reading JavaScript builtin continuation frame %s",
+ name.get());
+ PrintF(trace_file, " => bailout_id=%d, height=%d; inputs:\n",
+ bailout_id.ToInt(), height);
+ }
+ return TranslatedFrame::JavaScriptBuiltinContinuationFrame(
+ bailout_id, shared_info, height + 1);
+ }
+
case Translation::GETTER_STUB_FRAME: {
SharedFunctionInfo* shared_info =
SharedFunctionInfo::cast(literal_array->get(iterator->Next()));
@@ -3509,6 +3871,8 @@ int TranslatedState::CreateNextTranslatedValue(
case Translation::GETTER_STUB_FRAME:
case Translation::SETTER_STUB_FRAME:
case Translation::COMPILED_STUB_FRAME:
+ case Translation::JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME:
+ case Translation::BUILTIN_CONTINUATION_FRAME:
// Peeled off before getting here.
break;
« no previous file with comments | « src/deoptimizer.h ('k') | src/flag-definitions.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698