Line data Source code
1 : // Copyright 2014 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/runtime/runtime-utils.h"
6 :
7 : #include "src/arguments.h"
8 : #include "src/asmjs/asm-js.h"
9 : #include "src/compiler-dispatcher/optimizing-compile-dispatcher.h"
10 : #include "src/compiler.h"
11 : #include "src/deoptimizer.h"
12 : #include "src/frames-inl.h"
13 : #include "src/isolate-inl.h"
14 : #include "src/messages.h"
15 : #include "src/v8threads.h"
16 : #include "src/vm-state-inl.h"
17 :
18 : namespace v8 {
19 : namespace internal {
20 :
21 1403203 : RUNTIME_FUNCTION(Runtime_CompileLazy) {
22 701602 : HandleScope scope(isolate);
23 : DCHECK_EQ(1, args.length());
24 1403204 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
25 :
26 : #ifdef DEBUG
27 : if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
28 : PrintF("[unoptimized: ");
29 : function->PrintName();
30 : PrintF("]\n");
31 : }
32 : #endif
33 :
34 701602 : StackLimitCheck check(isolate);
35 701602 : if (check.JsHasOverflowed(kStackSpaceRequiredForCompilation * KB)) {
36 30728 : return isolate->StackOverflow();
37 : }
38 670874 : if (!Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) {
39 185 : return isolate->heap()->exception();
40 : }
41 : DCHECK(function->is_compiled());
42 670688 : return function->code();
43 : }
44 :
45 55674 : RUNTIME_FUNCTION(Runtime_CompileOptimized_Concurrent) {
46 27837 : HandleScope scope(isolate);
47 : DCHECK_EQ(1, args.length());
48 55674 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
49 27837 : StackLimitCheck check(isolate);
50 27837 : if (check.JsHasOverflowed(kStackSpaceRequiredForCompilation * KB)) {
51 19198 : return isolate->StackOverflow();
52 : }
53 8639 : if (!Compiler::CompileOptimized(function, ConcurrencyMode::kConcurrent)) {
54 0 : return isolate->heap()->exception();
55 : }
56 : DCHECK(function->is_compiled());
57 8639 : return function->code();
58 : }
59 :
60 :
61 608777 : RUNTIME_FUNCTION(Runtime_CompileOptimized_NotConcurrent) {
62 304389 : HandleScope scope(isolate);
63 : DCHECK_EQ(1, args.length());
64 608778 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
65 304389 : StackLimitCheck check(isolate);
66 304389 : if (check.JsHasOverflowed(kStackSpaceRequiredForCompilation * KB)) {
67 11774 : return isolate->StackOverflow();
68 : }
69 292615 : if (!Compiler::CompileOptimized(function, ConcurrencyMode::kNotConcurrent)) {
70 0 : return isolate->heap()->exception();
71 : }
72 : DCHECK(function->is_compiled());
73 292614 : return function->code();
74 : }
75 :
76 324 : RUNTIME_FUNCTION(Runtime_EvictOptimizedCodeSlot) {
77 : SealHandleScope scope(isolate);
78 : DCHECK_EQ(1, args.length());
79 324 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
80 :
81 : DCHECK(function->shared()->is_compiled());
82 :
83 : function->feedback_vector()->EvictOptimizedCodeMarkedForDeoptimization(
84 162 : function->shared(), "Runtime_EvictOptimizedCodeSlot");
85 162 : return function->code();
86 : }
87 :
88 12742 : RUNTIME_FUNCTION(Runtime_InstantiateAsmJs) {
89 6371 : HandleScope scope(isolate);
90 : DCHECK_EQ(args.length(), 4);
91 12742 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
92 :
93 : Handle<JSReceiver> stdlib;
94 12742 : if (args[1]->IsJSReceiver()) {
95 4363 : stdlib = args.at<JSReceiver>(1);
96 : }
97 : Handle<JSReceiver> foreign;
98 12742 : if (args[2]->IsJSReceiver()) {
99 3019 : foreign = args.at<JSReceiver>(2);
100 : }
101 : Handle<JSArrayBuffer> memory;
102 12742 : if (args[3]->IsJSArrayBuffer()) {
103 2745 : memory = args.at<JSArrayBuffer>(3);
104 : }
105 6371 : if (function->shared()->HasAsmWasmData()) {
106 6365 : Handle<SharedFunctionInfo> shared(function->shared());
107 6365 : Handle<FixedArray> data(shared->asm_wasm_data());
108 : MaybeHandle<Object> result = AsmJs::InstantiateAsmWasm(
109 6365 : isolate, shared, data, stdlib, foreign, memory);
110 6365 : if (!result.is_null()) {
111 : return *result.ToHandleChecked();
112 : }
113 : }
114 : // Remove wasm data, mark as broken for asm->wasm,
115 : // replace code with CompileLazy, and return a smi 0 to indicate failure.
116 188 : if (function->shared()->HasAsmWasmData()) {
117 182 : function->shared()->ClearAsmWasmData();
118 : }
119 188 : function->shared()->set_is_asm_wasm_broken(true);
120 : DCHECK(function->code() ==
121 : isolate->builtins()->builtin(Builtins::kInstantiateAsmJs));
122 376 : function->set_code(isolate->builtins()->builtin(Builtins::kCompileLazy));
123 376 : if (function->shared()->code() ==
124 188 : isolate->builtins()->builtin(Builtins::kInstantiateAsmJs)) {
125 : function->shared()->set_code(
126 182 : isolate->builtins()->builtin(Builtins::kCompileLazy));
127 : }
128 6371 : return Smi::kZero;
129 : }
130 :
131 293646 : RUNTIME_FUNCTION(Runtime_NotifyDeoptimized) {
132 146823 : HandleScope scope(isolate);
133 : DCHECK_EQ(0, args.length());
134 440469 : Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
135 : DCHECK(deoptimizer->compiled_code()->kind() == Code::OPTIMIZED_FUNCTION);
136 : DCHECK(deoptimizer->compiled_code()->is_turbofanned());
137 : DCHECK(AllowHeapAllocation::IsAllowed());
138 : DCHECK_NULL(isolate->context());
139 :
140 293646 : TimerEventScope<TimerEventDeoptimizeCode> timer(isolate);
141 293646 : TRACE_EVENT0("v8", "V8.DeoptimizeCode");
142 146823 : Handle<JSFunction> function = deoptimizer->function();
143 146823 : Deoptimizer::BailoutType type = deoptimizer->bailout_type();
144 146823 : bool preserve_optimized_code = deoptimizer->preserve_optimized();
145 :
146 : // TODO(turbofan): We currently need the native context to materialize
147 : // the arguments object, but only to get to its map.
148 293646 : isolate->set_context(deoptimizer->function()->native_context());
149 :
150 : // Make sure to materialize objects before causing any allocation.
151 146823 : deoptimizer->MaterializeHeapObjects();
152 146823 : delete deoptimizer;
153 :
154 : // Ensure the context register is updated for materialized objects.
155 293646 : JavaScriptFrameIterator top_it(isolate);
156 146823 : JavaScriptFrame* top_frame = top_it.frame();
157 146823 : isolate->set_context(Context::cast(top_frame->context()));
158 :
159 : // Invalidate the underlying optimized code on non-lazy deopts.
160 146823 : if (type != Deoptimizer::LAZY && !preserve_optimized_code) {
161 20003 : Deoptimizer::DeoptimizeFunction(*function);
162 : }
163 :
164 293646 : return isolate->heap()->undefined_value();
165 : }
166 :
167 :
168 6038 : static bool IsSuitableForOnStackReplacement(Isolate* isolate,
169 : Handle<JSFunction> function) {
170 : // Keep track of whether we've succeeded in optimizing.
171 6038 : if (function->shared()->optimization_disabled()) return false;
172 : // If we are trying to do OSR when there are already optimized
173 : // activations of the function, it means (a) the function is directly or
174 : // indirectly recursive and (b) an optimized invocation has been
175 : // deoptimized so that we are currently in an unoptimized activation.
176 : // Check for optimized activations of this function.
177 38592 : for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
178 : JavaScriptFrame* frame = it.frame();
179 26690 : if (frame->is_optimized() && frame->function() == *function) return false;
180 : }
181 :
182 6036 : return true;
183 : }
184 :
185 : namespace {
186 :
187 6038 : BailoutId DetermineEntryAndDisarmOSRForInterpreter(JavaScriptFrame* frame) {
188 : InterpretedFrame* iframe = reinterpret_cast<InterpretedFrame*>(frame);
189 :
190 : // Note that the bytecode array active on the stack might be different from
191 : // the one installed on the function (e.g. patched by debugger). This however
192 : // is fine because we guarantee the layout to be in sync, hence any BailoutId
193 : // representing the entry point will be valid for any copy of the bytecode.
194 6038 : Handle<BytecodeArray> bytecode(iframe->GetBytecodeArray());
195 :
196 : DCHECK(frame->LookupCode()->is_interpreter_trampoline_builtin());
197 : DCHECK(frame->function()->shared()->HasBytecodeArray());
198 : DCHECK(frame->is_interpreted());
199 :
200 : // Reset the OSR loop nesting depth to disarm back edges.
201 : bytecode->set_osr_loop_nesting_level(0);
202 :
203 : // Return a BailoutId representing the bytecode offset of the back branch.
204 6038 : return BailoutId(iframe->GetBytecodeOffset());
205 : }
206 :
207 : } // namespace
208 :
209 12076 : RUNTIME_FUNCTION(Runtime_CompileForOnStackReplacement) {
210 6038 : HandleScope scope(isolate);
211 : DCHECK_EQ(1, args.length());
212 12076 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
213 :
214 : // Only reachable when OST is enabled.
215 6038 : CHECK(FLAG_use_osr);
216 :
217 : // Determine frame triggering OSR request.
218 12076 : JavaScriptFrameIterator it(isolate);
219 6038 : JavaScriptFrame* frame = it.frame();
220 : DCHECK_EQ(frame->function(), *function);
221 : DCHECK(frame->is_interpreted());
222 :
223 : // Determine the entry point for which this OSR request has been fired and
224 : // also disarm all back edges in the calling code to stop new requests.
225 6038 : BailoutId ast_id = DetermineEntryAndDisarmOSRForInterpreter(frame);
226 : DCHECK(!ast_id.IsNone());
227 :
228 : MaybeHandle<Code> maybe_result;
229 6038 : if (IsSuitableForOnStackReplacement(isolate, function)) {
230 6036 : if (FLAG_trace_osr) {
231 0 : PrintF("[OSR - Compiling: ");
232 0 : function->PrintName();
233 0 : PrintF(" at AST id %d]\n", ast_id.ToInt());
234 : }
235 6036 : maybe_result = Compiler::GetOptimizedCodeForOSR(function, ast_id, frame);
236 : }
237 :
238 : // Check whether we ended up with usable optimized code.
239 : Handle<Code> result;
240 11847 : if (maybe_result.ToHandle(&result) &&
241 5809 : result->kind() == Code::OPTIMIZED_FUNCTION) {
242 : DeoptimizationData* data =
243 5809 : DeoptimizationData::cast(result->deoptimization_data());
244 :
245 5809 : if (data->OsrPcOffset()->value() >= 0) {
246 : DCHECK(BailoutId(data->OsrBytecodeOffset()->value()) == ast_id);
247 5809 : if (FLAG_trace_osr) {
248 : PrintF("[OSR - Entry at AST id %d, offset %d in optimized code]\n",
249 0 : ast_id.ToInt(), data->OsrPcOffset()->value());
250 : }
251 :
252 : DCHECK(result->is_turbofanned());
253 5809 : if (!function->HasOptimizedCode()) {
254 : // If we're not already optimized, set to optimize non-concurrently on
255 : // the next call, otherwise we'd run unoptimized once more and
256 : // potentially compile for OSR again.
257 5352 : if (FLAG_trace_osr) {
258 0 : PrintF("[OSR - Re-marking ");
259 0 : function->PrintName();
260 0 : PrintF(" for non-concurrent optimization]\n");
261 : }
262 5352 : function->SetOptimizationMarker(OptimizationMarker::kCompileOptimized);
263 : }
264 : return *result;
265 : }
266 : }
267 :
268 : // Failed.
269 229 : if (FLAG_trace_osr) {
270 0 : PrintF("[OSR - Failed: ");
271 0 : function->PrintName();
272 0 : PrintF(" at AST id %d]\n", ast_id.ToInt());
273 : }
274 :
275 229 : if (!function->IsOptimized()) {
276 229 : function->set_code(function->shared()->code());
277 : }
278 6038 : return nullptr;
279 : }
280 :
281 2438919 : static Object* CompileGlobalEval(Isolate* isolate, Handle<String> source,
282 : Handle<SharedFunctionInfo> outer_info,
283 : LanguageMode language_mode,
284 : int eval_scope_position, int eval_position) {
285 : Handle<Context> context = Handle<Context>(isolate->context());
286 : Handle<Context> native_context = Handle<Context>(context->native_context());
287 :
288 : // Check if native context allows code generation from
289 : // strings. Throw an exception if it doesn't.
290 2438947 : if (native_context->allow_code_gen_from_strings()->IsFalse(isolate) &&
291 : !Compiler::CodeGenerationFromStringsAllowed(isolate, native_context,
292 28 : source)) {
293 : Handle<Object> error_message =
294 17 : native_context->ErrorMessageForCodeGenerationFromStrings();
295 : Handle<Object> error;
296 : MaybeHandle<Object> maybe_error = isolate->factory()->NewEvalError(
297 17 : MessageTemplate::kCodeGenFromStrings, error_message);
298 34 : if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
299 17 : return isolate->heap()->exception();
300 : }
301 :
302 : // Deal with a normal eval call with a string argument. Compile it
303 : // and return the compiled function bound in the local context.
304 : static const ParseRestriction restriction = NO_PARSE_RESTRICTION;
305 : Handle<JSFunction> compiled;
306 4877804 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
307 : isolate, compiled,
308 : Compiler::GetFunctionFromEval(source, outer_info, context, language_mode,
309 : restriction, kNoSourcePosition,
310 : eval_scope_position, eval_position),
311 : isolate->heap()->exception());
312 2337763 : return *compiled;
313 : }
314 :
315 :
316 4878864 : RUNTIME_FUNCTION(Runtime_ResolvePossiblyDirectEval) {
317 2439432 : HandleScope scope(isolate);
318 : DCHECK_EQ(6, args.length());
319 :
320 2439432 : Handle<Object> callee = args.at(0);
321 :
322 : // If "eval" didn't refer to the original GlobalEval, it's not a
323 : // direct call to eval.
324 : // (And even if it is, but the first argument isn't a string, just let
325 : // execution default to an indirect call to eval, which will also return
326 : // the first argument without doing anything).
327 7318163 : if (*callee != isolate->native_context()->global_eval_fun() ||
328 2439299 : !args[1]->IsString()) {
329 : return *callee;
330 : }
331 :
332 : DCHECK(args[3]->IsSmi());
333 : DCHECK(is_valid_language_mode(args.smi_at(3)));
334 2438919 : LanguageMode language_mode = static_cast<LanguageMode>(args.smi_at(3));
335 : DCHECK(args[4]->IsSmi());
336 : Handle<SharedFunctionInfo> outer_info(args.at<JSFunction>(2)->shared(),
337 7316757 : isolate);
338 : return CompileGlobalEval(isolate, args.at<String>(1), outer_info,
339 2438919 : language_mode, args.smi_at(4), args.smi_at(5));
340 : }
341 : } // namespace internal
342 : } // namespace v8
|