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/deoptimizer.h"
9 #include "src/frames-inl.h"
10 #include "src/full-codegen/full-codegen.h"
11 #include "src/snapshot/natives.h"
12
13 namespace v8 {
14 namespace internal {
15
RUNTIME_FUNCTION(Runtime_DeoptimizeFunction)16 RUNTIME_FUNCTION(Runtime_DeoptimizeFunction) {
17 HandleScope scope(isolate);
18 DCHECK(args.length() == 1);
19 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
20 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
21
22 // TODO(turbofan): Deoptimization is not supported yet.
23 if (function->code()->is_turbofanned() &&
24 function->shared()->asm_function() && !FLAG_turbo_asm_deoptimization) {
25 return isolate->heap()->undefined_value();
26 }
27
28 Deoptimizer::DeoptimizeFunction(*function);
29
30 return isolate->heap()->undefined_value();
31 }
32
33
RUNTIME_FUNCTION(Runtime_DeoptimizeNow)34 RUNTIME_FUNCTION(Runtime_DeoptimizeNow) {
35 HandleScope scope(isolate);
36 DCHECK(args.length() == 0);
37
38 Handle<JSFunction> function;
39
40 // If the argument is 'undefined', deoptimize the topmost
41 // function.
42 JavaScriptFrameIterator it(isolate);
43 while (!it.done()) {
44 if (it.frame()->is_java_script()) {
45 function = Handle<JSFunction>(it.frame()->function());
46 break;
47 }
48 }
49 if (function.is_null()) return isolate->heap()->undefined_value();
50
51 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
52
53 // TODO(turbofan): Deoptimization is not supported yet.
54 if (function->code()->is_turbofanned() &&
55 function->shared()->asm_function() && !FLAG_turbo_asm_deoptimization) {
56 return isolate->heap()->undefined_value();
57 }
58
59 Deoptimizer::DeoptimizeFunction(*function);
60
61 return isolate->heap()->undefined_value();
62 }
63
64
RUNTIME_FUNCTION(Runtime_RunningInSimulator)65 RUNTIME_FUNCTION(Runtime_RunningInSimulator) {
66 SealHandleScope shs(isolate);
67 DCHECK(args.length() == 0);
68 #if defined(USE_SIMULATOR)
69 return isolate->heap()->true_value();
70 #else
71 return isolate->heap()->false_value();
72 #endif
73 }
74
75
RUNTIME_FUNCTION(Runtime_IsConcurrentRecompilationSupported)76 RUNTIME_FUNCTION(Runtime_IsConcurrentRecompilationSupported) {
77 SealHandleScope shs(isolate);
78 DCHECK(args.length() == 0);
79 return isolate->heap()->ToBoolean(
80 isolate->concurrent_recompilation_enabled());
81 }
82
83
RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall)84 RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) {
85 HandleScope scope(isolate);
86 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
87 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
88 // The following assertion was lifted from the DCHECK inside
89 // JSFunction::MarkForOptimization().
90 RUNTIME_ASSERT(function->shared()->allows_lazy_compilation() ||
91 (function->code()->kind() == Code::FUNCTION &&
92 !function->shared()->optimization_disabled()));
93
94 // If the function is already optimized, just return.
95 if (function->IsOptimized()) return isolate->heap()->undefined_value();
96
97 function->MarkForOptimization();
98
99 Code* unoptimized = function->shared()->code();
100 if (args.length() == 2 && unoptimized->kind() == Code::FUNCTION) {
101 CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
102 if (type->IsOneByteEqualTo(STATIC_CHAR_VECTOR("concurrent")) &&
103 isolate->concurrent_recompilation_enabled()) {
104 function->AttemptConcurrentOptimization();
105 }
106 }
107
108 return isolate->heap()->undefined_value();
109 }
110
111
RUNTIME_FUNCTION(Runtime_OptimizeOsr)112 RUNTIME_FUNCTION(Runtime_OptimizeOsr) {
113 HandleScope scope(isolate);
114 RUNTIME_ASSERT(args.length() == 0 || args.length() == 1);
115 Handle<JSFunction> function = Handle<JSFunction>::null();
116
117 if (args.length() == 0) {
118 // Find the JavaScript function on the top of the stack.
119 JavaScriptFrameIterator it(isolate);
120 while (!it.done()) {
121 if (it.frame()->is_java_script()) {
122 function = Handle<JSFunction>(it.frame()->function());
123 break;
124 }
125 }
126 if (function.is_null()) return isolate->heap()->undefined_value();
127 } else {
128 // Function was passed as an argument.
129 CONVERT_ARG_HANDLE_CHECKED(JSFunction, arg, 0);
130 function = arg;
131 }
132
133 // The following assertion was lifted from the DCHECK inside
134 // JSFunction::MarkForOptimization().
135 RUNTIME_ASSERT(function->shared()->allows_lazy_compilation() ||
136 !function->shared()->optimization_disabled());
137
138 // If the function is already optimized, just return.
139 if (function->IsOptimized()) return isolate->heap()->undefined_value();
140
141 Code* unoptimized = function->shared()->code();
142 if (unoptimized->kind() == Code::FUNCTION) {
143 DCHECK(BackEdgeTable::Verify(isolate, unoptimized));
144 isolate->runtime_profiler()->AttemptOnStackReplacement(
145 *function, Code::kMaxLoopNestingMarker);
146 }
147
148 return isolate->heap()->undefined_value();
149 }
150
151
RUNTIME_FUNCTION(Runtime_NeverOptimizeFunction)152 RUNTIME_FUNCTION(Runtime_NeverOptimizeFunction) {
153 HandleScope scope(isolate);
154 DCHECK(args.length() == 1);
155 CONVERT_ARG_CHECKED(JSFunction, function, 0);
156 function->shared()->set_disable_optimization_reason(kOptimizationDisabled);
157 function->shared()->set_optimization_disabled(true);
158 return isolate->heap()->undefined_value();
159 }
160
161
RUNTIME_FUNCTION(Runtime_GetOptimizationStatus)162 RUNTIME_FUNCTION(Runtime_GetOptimizationStatus) {
163 HandleScope scope(isolate);
164 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
165 if (!isolate->use_crankshaft()) {
166 return Smi::FromInt(4); // 4 == "never".
167 }
168 bool sync_with_compiler_thread = true;
169 if (args.length() == 2) {
170 CONVERT_ARG_HANDLE_CHECKED(String, sync, 1);
171 if (sync->IsOneByteEqualTo(STATIC_CHAR_VECTOR("no sync"))) {
172 sync_with_compiler_thread = false;
173 }
174 }
175 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
176 if (isolate->concurrent_recompilation_enabled() &&
177 sync_with_compiler_thread) {
178 while (function->IsInOptimizationQueue()) {
179 isolate->optimizing_compile_dispatcher()->InstallOptimizedFunctions();
180 base::OS::Sleep(base::TimeDelta::FromMilliseconds(50));
181 }
182 }
183 if (FLAG_always_opt || FLAG_prepare_always_opt) {
184 // With --always-opt, optimization status expectations might not
185 // match up, so just return a sentinel.
186 return Smi::FromInt(3); // 3 == "always".
187 }
188 if (FLAG_deopt_every_n_times) {
189 return Smi::FromInt(6); // 6 == "maybe deopted".
190 }
191 if (function->IsOptimized() && function->code()->is_turbofanned()) {
192 return Smi::FromInt(7); // 7 == "TurboFan compiler".
193 }
194 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
195 : Smi::FromInt(2); // 2 == "no".
196 }
197
198
RUNTIME_FUNCTION(Runtime_UnblockConcurrentRecompilation)199 RUNTIME_FUNCTION(Runtime_UnblockConcurrentRecompilation) {
200 DCHECK(args.length() == 0);
201 RUNTIME_ASSERT(FLAG_block_concurrent_recompilation);
202 RUNTIME_ASSERT(isolate->concurrent_recompilation_enabled());
203 isolate->optimizing_compile_dispatcher()->Unblock();
204 return isolate->heap()->undefined_value();
205 }
206
207
RUNTIME_FUNCTION(Runtime_GetOptimizationCount)208 RUNTIME_FUNCTION(Runtime_GetOptimizationCount) {
209 HandleScope scope(isolate);
210 DCHECK(args.length() == 1);
211 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
212 return Smi::FromInt(function->shared()->opt_count());
213 }
214
215
RUNTIME_FUNCTION(Runtime_GetUndetectable)216 RUNTIME_FUNCTION(Runtime_GetUndetectable) {
217 HandleScope scope(isolate);
218 DCHECK(args.length() == 0);
219 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
220
221 Local<v8::ObjectTemplate> desc = v8::ObjectTemplate::New(v8_isolate);
222 desc->MarkAsUndetectable();
223 Local<v8::Object> obj;
224 if (!desc->NewInstance(v8_isolate->GetCurrentContext()).ToLocal(&obj)) {
225 return nullptr;
226 }
227 return *Utils::OpenHandle(*obj);
228 }
229
230
RUNTIME_FUNCTION(Runtime_ClearFunctionTypeFeedback)231 RUNTIME_FUNCTION(Runtime_ClearFunctionTypeFeedback) {
232 HandleScope scope(isolate);
233 DCHECK(args.length() == 1);
234 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
235 function->shared()->ClearTypeFeedbackInfo();
236 Code* unoptimized = function->shared()->code();
237 if (unoptimized->kind() == Code::FUNCTION) {
238 unoptimized->ClearInlineCaches();
239 }
240 return isolate->heap()->undefined_value();
241 }
242
243
RUNTIME_FUNCTION(Runtime_NotifyContextDisposed)244 RUNTIME_FUNCTION(Runtime_NotifyContextDisposed) {
245 HandleScope scope(isolate);
246 DCHECK(args.length() == 0);
247 isolate->heap()->NotifyContextDisposed(true);
248 return isolate->heap()->undefined_value();
249 }
250
251
RUNTIME_FUNCTION(Runtime_SetAllocationTimeout)252 RUNTIME_FUNCTION(Runtime_SetAllocationTimeout) {
253 SealHandleScope shs(isolate);
254 DCHECK(args.length() == 2 || args.length() == 3);
255 #ifdef DEBUG
256 CONVERT_SMI_ARG_CHECKED(interval, 0);
257 CONVERT_SMI_ARG_CHECKED(timeout, 1);
258 isolate->heap()->set_allocation_timeout(timeout);
259 FLAG_gc_interval = interval;
260 if (args.length() == 3) {
261 // Enable/disable inline allocation if requested.
262 CONVERT_BOOLEAN_ARG_CHECKED(inline_allocation, 2);
263 if (inline_allocation) {
264 isolate->heap()->EnableInlineAllocation();
265 } else {
266 isolate->heap()->DisableInlineAllocation();
267 }
268 }
269 #endif
270 return isolate->heap()->undefined_value();
271 }
272
273
RUNTIME_FUNCTION(Runtime_DebugPrint)274 RUNTIME_FUNCTION(Runtime_DebugPrint) {
275 SealHandleScope shs(isolate);
276 DCHECK(args.length() == 1);
277
278 OFStream os(stdout);
279 #ifdef DEBUG
280 if (args[0]->IsString()) {
281 // If we have a string, assume it's a code "marker"
282 // and print some interesting cpu debugging info.
283 JavaScriptFrameIterator it(isolate);
284 JavaScriptFrame* frame = it.frame();
285 os << "fp = " << static_cast<void*>(frame->fp())
286 << ", sp = " << static_cast<void*>(frame->sp())
287 << ", caller_sp = " << static_cast<void*>(frame->caller_sp()) << ": ";
288 } else {
289 os << "DebugPrint: ";
290 }
291 args[0]->Print(os);
292 if (args[0]->IsHeapObject()) {
293 os << "\n";
294 HeapObject::cast(args[0])->map()->Print(os);
295 }
296 #else
297 // ShortPrint is available in release mode. Print is not.
298 os << Brief(args[0]);
299 #endif
300 os << std::endl;
301
302 return args[0]; // return TOS
303 }
304
305
RUNTIME_FUNCTION(Runtime_DebugTrace)306 RUNTIME_FUNCTION(Runtime_DebugTrace) {
307 SealHandleScope shs(isolate);
308 DCHECK(args.length() == 0);
309 isolate->PrintStack(stdout);
310 return isolate->heap()->undefined_value();
311 }
312
313
314 // This will not allocate (flatten the string), but it may run
315 // very slowly for very deeply nested ConsStrings. For debugging use only.
RUNTIME_FUNCTION(Runtime_GlobalPrint)316 RUNTIME_FUNCTION(Runtime_GlobalPrint) {
317 SealHandleScope shs(isolate);
318 DCHECK(args.length() == 1);
319
320 CONVERT_ARG_CHECKED(String, string, 0);
321 StringCharacterStream stream(string);
322 while (stream.HasMore()) {
323 uint16_t character = stream.GetNext();
324 PrintF("%c", character);
325 }
326 return string;
327 }
328
329
RUNTIME_FUNCTION(Runtime_SystemBreak)330 RUNTIME_FUNCTION(Runtime_SystemBreak) {
331 // The code below doesn't create handles, but when breaking here in GDB
332 // having a handle scope might be useful.
333 HandleScope scope(isolate);
334 DCHECK(args.length() == 0);
335 base::OS::DebugBreak();
336 return isolate->heap()->undefined_value();
337 }
338
339
340 // Sets a v8 flag.
RUNTIME_FUNCTION(Runtime_SetFlags)341 RUNTIME_FUNCTION(Runtime_SetFlags) {
342 SealHandleScope shs(isolate);
343 DCHECK(args.length() == 1);
344 CONVERT_ARG_CHECKED(String, arg, 0);
345 base::SmartArrayPointer<char> flags =
346 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
347 FlagList::SetFlagsFromString(flags.get(), StrLength(flags.get()));
348 return isolate->heap()->undefined_value();
349 }
350
351
RUNTIME_FUNCTION(Runtime_Abort)352 RUNTIME_FUNCTION(Runtime_Abort) {
353 SealHandleScope shs(isolate);
354 DCHECK(args.length() == 1);
355 CONVERT_SMI_ARG_CHECKED(message_id, 0);
356 const char* message =
357 GetBailoutReason(static_cast<BailoutReason>(message_id));
358 base::OS::PrintError("abort: %s\n", message);
359 isolate->PrintStack(stderr);
360 base::OS::Abort();
361 UNREACHABLE();
362 return NULL;
363 }
364
365
RUNTIME_FUNCTION(Runtime_AbortJS)366 RUNTIME_FUNCTION(Runtime_AbortJS) {
367 HandleScope scope(isolate);
368 DCHECK(args.length() == 1);
369 CONVERT_ARG_HANDLE_CHECKED(String, message, 0);
370 base::OS::PrintError("abort: %s\n", message->ToCString().get());
371 isolate->PrintStack(stderr);
372 base::OS::Abort();
373 UNREACHABLE();
374 return NULL;
375 }
376
377
RUNTIME_FUNCTION(Runtime_NativeScriptsCount)378 RUNTIME_FUNCTION(Runtime_NativeScriptsCount) {
379 DCHECK(args.length() == 0);
380 return Smi::FromInt(Natives::GetBuiltinsCount() +
381 ExtraNatives::GetBuiltinsCount());
382 }
383
384
385 // Returns V8 version as a string.
RUNTIME_FUNCTION(Runtime_GetV8Version)386 RUNTIME_FUNCTION(Runtime_GetV8Version) {
387 HandleScope scope(isolate);
388 DCHECK(args.length() == 0);
389
390 const char* version_string = v8::V8::GetVersion();
391
392 return *isolate->factory()->NewStringFromAsciiChecked(version_string);
393 }
394
395
RUNTIME_FUNCTION(Runtime_DisassembleFunction)396 RUNTIME_FUNCTION(Runtime_DisassembleFunction) {
397 HandleScope scope(isolate);
398 #ifdef DEBUG
399 DCHECK(args.length() == 1);
400 // Get the function and make sure it is compiled.
401 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
402 if (!Compiler::Compile(func, KEEP_EXCEPTION)) {
403 return isolate->heap()->exception();
404 }
405 OFStream os(stdout);
406 func->code()->Print(os);
407 os << std::endl;
408 #endif // DEBUG
409 return isolate->heap()->undefined_value();
410 }
411
412
StackSize(Isolate * isolate)413 static int StackSize(Isolate* isolate) {
414 int n = 0;
415 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) n++;
416 return n;
417 }
418
419
PrintTransition(Isolate * isolate,Object * result)420 static void PrintTransition(Isolate* isolate, Object* result) {
421 // indentation
422 {
423 const int nmax = 80;
424 int n = StackSize(isolate);
425 if (n <= nmax)
426 PrintF("%4d:%*s", n, n, "");
427 else
428 PrintF("%4d:%*s", n, nmax, "...");
429 }
430
431 if (result == NULL) {
432 JavaScriptFrame::PrintTop(isolate, stdout, true, false);
433 PrintF(" {\n");
434 } else {
435 // function result
436 PrintF("} -> ");
437 result->ShortPrint();
438 PrintF("\n");
439 }
440 }
441
442
RUNTIME_FUNCTION(Runtime_TraceEnter)443 RUNTIME_FUNCTION(Runtime_TraceEnter) {
444 SealHandleScope shs(isolate);
445 DCHECK(args.length() == 0);
446 PrintTransition(isolate, NULL);
447 return isolate->heap()->undefined_value();
448 }
449
450
RUNTIME_FUNCTION(Runtime_TraceExit)451 RUNTIME_FUNCTION(Runtime_TraceExit) {
452 SealHandleScope shs(isolate);
453 DCHECK(args.length() == 1);
454 CONVERT_ARG_CHECKED(Object, obj, 0);
455 PrintTransition(isolate, obj);
456 return obj; // return TOS
457 }
458
459
RUNTIME_FUNCTION(Runtime_HaveSameMap)460 RUNTIME_FUNCTION(Runtime_HaveSameMap) {
461 SealHandleScope shs(isolate);
462 DCHECK(args.length() == 2);
463 CONVERT_ARG_CHECKED(JSObject, obj1, 0);
464 CONVERT_ARG_CHECKED(JSObject, obj2, 1);
465 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
466 }
467
468
RUNTIME_FUNCTION(Runtime_InNewSpace)469 RUNTIME_FUNCTION(Runtime_InNewSpace) {
470 SealHandleScope shs(isolate);
471 DCHECK(args.length() == 1);
472 CONVERT_ARG_CHECKED(Object, obj, 0);
473 return isolate->heap()->ToBoolean(isolate->heap()->InNewSpace(obj));
474 }
475
476
477 #define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
478 RUNTIME_FUNCTION(Runtime_Has##Name) { \
479 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
480 return isolate->heap()->ToBoolean(obj->Has##Name()); \
481 }
482
483 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiElements)
484 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastObjectElements)
485 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOrObjectElements)
486 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
487 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastHoleyElements)
488 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
489 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SloppyArgumentsElements)
490 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FixedTypedArrayElements)
491 // Properties test sitting with elements tests - not fooling anyone.
492 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties)
493
494 #undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
495
496
497 #define FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, s) \
498 RUNTIME_FUNCTION(Runtime_HasFixed##Type##Elements) { \
499 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
500 return isolate->heap()->ToBoolean(obj->HasFixed##Type##Elements()); \
501 }
502
503 TYPED_ARRAYS(FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION)
504
505 #undef FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
506 } // namespace internal
507 } // namespace v8
508