2 * Copyright (C) 2008, 2011, 2013, 2014 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include "ArityCheckFailReturnThunks.h"
34 #include "ArrayBufferNeuteringWatchpoint.h"
35 #include "BuiltinExecutables.h"
36 #include "CodeBlock.h"
37 #include "CodeCache.h"
38 #include "CommonIdentifiers.h"
39 #include "CommonSlowPaths.h"
40 #include "CustomGetterSetter.h"
41 #include "DFGLongLivedState.h"
42 #include "DFGWorklist.h"
43 #include "DebuggerActivation.h"
44 #include "ErrorInstance.h"
45 #include "FTLThunks.h"
46 #include "FunctionConstructor.h"
47 #include "GCActivityCallback.h"
48 #include "GetterSetter.h"
50 #include "HeapIterationScope.h"
51 #include "HostCallReturnValue.h"
52 #include "Identifier.h"
53 #include "IncrementalSweeper.h"
54 #include "Interpreter.h"
56 #include "JSAPIValueWrapper.h"
57 #include "JSActivation.h"
59 #include "JSCInlines.h"
60 #include "JSFunction.h"
61 #include "JSGlobalObjectFunctions.h"
63 #include "JSNameScope.h"
64 #include "JSNotAnObject.h"
65 #include "JSPromiseDeferred.h"
66 #include "JSPromiseReaction.h"
67 #include "JSPropertyNameIterator.h"
68 #include "JSWithScope.h"
74 #include "ParserArena.h"
75 #include "ProfilerDatabase.h"
76 #include "PropertyMapHashTable.h"
77 #include "RegExpCache.h"
78 #include "RegExpObject.h"
79 #include "SimpleTypedArrayController.h"
80 #include "SourceProviderCache.h"
81 #include "StrictEvalActivation.h"
82 #include "StrongInlines.h"
83 #include "StructureInlines.h"
84 #include "UnlinkedCodeBlock.h"
85 #include "WeakMapData.h"
86 #include <wtf/ProcessID.h>
87 #include <wtf/RetainPtr.h>
88 #include <wtf/StringPrintStream.h>
89 #include <wtf/Threading.h>
90 #include <wtf/WTFThreadData.h>
91 #include <wtf/text/AtomicStringTable.h>
94 #include "ConservativeRoots.h"
97 #if ENABLE(REGEXP_TRACING)
102 #include <CoreFoundation/CoreFoundation.h>
109 extern const HashTable arrayConstructorTable
;
110 extern const HashTable arrayPrototypeTable
;
111 extern const HashTable booleanPrototypeTable
;
112 extern const HashTable jsonTable
;
113 extern const HashTable dataViewTable
;
114 extern const HashTable dateTable
;
115 extern const HashTable dateConstructorTable
;
116 extern const HashTable errorPrototypeTable
;
117 extern const HashTable globalObjectTable
;
118 extern const HashTable numberConstructorTable
;
119 extern const HashTable numberPrototypeTable
;
120 JS_EXPORTDATA
extern const HashTable objectConstructorTable
;
121 extern const HashTable privateNamePrototypeTable
;
122 extern const HashTable regExpTable
;
123 extern const HashTable regExpConstructorTable
;
124 extern const HashTable regExpPrototypeTable
;
125 extern const HashTable stringConstructorTable
;
127 extern const HashTable promisePrototypeTable
;
128 extern const HashTable promiseConstructorTable
;
131 // Note: Platform.h will enforce that ENABLE(ASSEMBLER) is true if either
132 // ENABLE(JIT) or ENABLE(YARR_JIT) or both are enabled. The code below
133 // just checks for ENABLE(JIT) or ENABLE(YARR_JIT) with this premise in mind.
135 #if ENABLE(ASSEMBLER)
136 static bool enableAssembler(ExecutableAllocator
& executableAllocator
)
138 if (!Options::useJIT() && !Options::useRegExpJIT())
141 if (!executableAllocator
.isValid()) {
142 if (Options::crashIfCantAllocateJITMemory())
148 CFStringRef canUseJITKey
= CFSTR("JavaScriptCoreUseJIT");
149 RetainPtr
<CFTypeRef
> canUseJIT
= adoptCF(CFPreferencesCopyAppValue(canUseJITKey
, kCFPreferencesCurrentApplication
));
151 return kCFBooleanTrue
== canUseJIT
.get();
154 #if USE(CF) || OS(UNIX)
155 char* canUseJITString
= getenv("JavaScriptCoreUseJIT");
156 return !canUseJITString
|| atoi(canUseJITString
);
161 #endif // ENABLE(!ASSEMBLER)
163 VM::VM(VMType vmType
, HeapType heapType
)
164 : m_apiLock(adoptRef(new JSLock(this)))
165 #if ENABLE(ASSEMBLER)
166 , executableAllocator(*this)
168 , heap(this, heapType
)
171 , topCallFrame(CallFrame::noCaller())
172 , arrayConstructorTable(adoptPtr(new HashTable(JSC::arrayConstructorTable
)))
173 , arrayPrototypeTable(adoptPtr(new HashTable(JSC::arrayPrototypeTable
)))
174 , booleanPrototypeTable(adoptPtr(new HashTable(JSC::booleanPrototypeTable
)))
175 , dataViewTable(adoptPtr(new HashTable(JSC::dataViewTable
)))
176 , dateTable(adoptPtr(new HashTable(JSC::dateTable
)))
177 , dateConstructorTable(adoptPtr(new HashTable(JSC::dateConstructorTable
)))
178 , errorPrototypeTable(adoptPtr(new HashTable(JSC::errorPrototypeTable
)))
179 , globalObjectTable(adoptPtr(new HashTable(JSC::globalObjectTable
)))
180 , jsonTable(adoptPtr(new HashTable(JSC::jsonTable
)))
181 , numberConstructorTable(adoptPtr(new HashTable(JSC::numberConstructorTable
)))
182 , numberPrototypeTable(adoptPtr(new HashTable(JSC::numberPrototypeTable
)))
183 , objectConstructorTable(adoptPtr(new HashTable(JSC::objectConstructorTable
)))
184 , privateNamePrototypeTable(adoptPtr(new HashTable(JSC::privateNamePrototypeTable
)))
185 , regExpTable(adoptPtr(new HashTable(JSC::regExpTable
)))
186 , regExpConstructorTable(adoptPtr(new HashTable(JSC::regExpConstructorTable
)))
187 , regExpPrototypeTable(adoptPtr(new HashTable(JSC::regExpPrototypeTable
)))
188 , stringConstructorTable(adoptPtr(new HashTable(JSC::stringConstructorTable
)))
190 , promisePrototypeTable(adoptPtr(new HashTable(JSC::promisePrototypeTable
)))
191 , promiseConstructorTable(adoptPtr(new HashTable(JSC::promiseConstructorTable
)))
193 , m_atomicStringTable(vmType
== Default
? wtfThreadData().atomicStringTable() : new AtomicStringTable
)
194 , propertyNames(nullptr)
195 , emptyList(new MarkedArgumentBuffer
)
196 , parserArena(adoptPtr(new ParserArena
))
197 , keywords(adoptPtr(new Keywords(*this)))
199 , jsArrayClassInfo(JSArray::info())
200 , jsFinalObjectClassInfo(JSFinalObject::info())
201 , sizeOfLastScratchBuffer(0)
203 , m_regExpCache(new RegExpCache(this))
204 #if ENABLE(REGEXP_TRACING)
205 , m_rtTraceList(new RTTraceList())
207 , m_newStringsSinceLastHashCons(0)
208 #if ENABLE(ASSEMBLER)
209 , m_canUseAssembler(enableAssembler(executableAllocator
))
212 , m_canUseJIT(m_canUseAssembler
&& Options::useJIT())
215 , m_canUseRegExpJIT(m_canUseAssembler
&& Options::useRegExpJIT())
217 #if ENABLE(GC_VALIDATION)
218 , m_initializingObjectClass(0)
220 , m_stackPointerAtVMEntry(0)
227 , m_largestFTLStackSize(0)
229 , m_inDefineOwnProperty(false)
230 , m_codeCache(CodeCache::create())
231 , m_enabledProfiler(nullptr)
232 , m_builtinExecutables(BuiltinExecutables::create(*this))
234 interpreter
= new Interpreter(*this);
235 StackBounds stack
= wtfThreadData().stack();
236 updateReservedZoneSize(Options::reservedZoneSize());
238 interpreter
->stack().setReservedZoneSize(Options::reservedZoneSize());
240 setLastStackTop(stack
.origin());
242 // Need to be careful to keep everything consistent here
243 JSLockHolder
lock(this);
244 AtomicStringTable
* existingEntryAtomicStringTable
= wtfThreadData().setCurrentAtomicStringTable(m_atomicStringTable
);
245 propertyNames
= new CommonIdentifiers(this);
246 structureStructure
.set(*this, Structure::createStructure(*this));
247 structureRareDataStructure
.set(*this, StructureRareData::createStructure(*this, 0, jsNull()));
248 debuggerActivationStructure
.set(*this, DebuggerActivation::createStructure(*this, 0, jsNull()));
249 terminatedExecutionErrorStructure
.set(*this, TerminatedExecutionError::createStructure(*this, 0, jsNull()));
250 stringStructure
.set(*this, JSString::createStructure(*this, 0, jsNull()));
251 notAnObjectStructure
.set(*this, JSNotAnObject::createStructure(*this, 0, jsNull()));
252 propertyNameIteratorStructure
.set(*this, JSPropertyNameIterator::createStructure(*this, 0, jsNull()));
253 getterSetterStructure
.set(*this, GetterSetter::createStructure(*this, 0, jsNull()));
254 customGetterSetterStructure
.set(*this, CustomGetterSetter::createStructure(*this, 0, jsNull()));
255 apiWrapperStructure
.set(*this, JSAPIValueWrapper::createStructure(*this, 0, jsNull()));
256 JSScopeStructure
.set(*this, JSScope::createStructure(*this, 0, jsNull()));
257 executableStructure
.set(*this, ExecutableBase::createStructure(*this, 0, jsNull()));
258 nativeExecutableStructure
.set(*this, NativeExecutable::createStructure(*this, 0, jsNull()));
259 evalExecutableStructure
.set(*this, EvalExecutable::createStructure(*this, 0, jsNull()));
260 programExecutableStructure
.set(*this, ProgramExecutable::createStructure(*this, 0, jsNull()));
261 functionExecutableStructure
.set(*this, FunctionExecutable::createStructure(*this, 0, jsNull()));
262 regExpStructure
.set(*this, RegExp::createStructure(*this, 0, jsNull()));
263 symbolTableStructure
.set(*this, SymbolTable::createStructure(*this, 0, jsNull()));
264 structureChainStructure
.set(*this, StructureChain::createStructure(*this, 0, jsNull()));
265 sparseArrayValueMapStructure
.set(*this, SparseArrayValueMap::createStructure(*this, 0, jsNull()));
266 arrayBufferNeuteringWatchpointStructure
.set(*this, ArrayBufferNeuteringWatchpoint::createStructure(*this));
267 withScopeStructure
.set(*this, JSWithScope::createStructure(*this, 0, jsNull()));
268 unlinkedFunctionExecutableStructure
.set(*this, UnlinkedFunctionExecutable::createStructure(*this, 0, jsNull()));
269 unlinkedProgramCodeBlockStructure
.set(*this, UnlinkedProgramCodeBlock::createStructure(*this, 0, jsNull()));
270 unlinkedEvalCodeBlockStructure
.set(*this, UnlinkedEvalCodeBlock::createStructure(*this, 0, jsNull()));
271 unlinkedFunctionCodeBlockStructure
.set(*this, UnlinkedFunctionCodeBlock::createStructure(*this, 0, jsNull()));
272 propertyTableStructure
.set(*this, PropertyTable::createStructure(*this, 0, jsNull()));
273 mapDataStructure
.set(*this, MapData::createStructure(*this, 0, jsNull()));
274 weakMapDataStructure
.set(*this, WeakMapData::createStructure(*this, 0, jsNull()));
276 promiseDeferredStructure
.set(*this, JSPromiseDeferred::createStructure(*this, 0, jsNull()));
277 promiseReactionStructure
.set(*this, JSPromiseReaction::createStructure(*this, 0, jsNull()));
279 iterationTerminator
.set(*this, JSFinalObject::create(*this, JSFinalObject::createStructure(*this, 0, jsNull(), 1)));
280 smallStrings
.initializeCommonStrings(*this);
282 wtfThreadData().setCurrentAtomicStringTable(existingEntryAtomicStringTable
);
285 jitStubs
= adoptPtr(new JITThunks());
286 arityCheckFailReturnThunks
= std::make_unique
<ArityCheckFailReturnThunks
>();
288 arityCheckData
= std::make_unique
<CommonSlowPaths::ArityCheckData
>();
291 ftlThunks
= std::make_unique
<FTL::Thunks
>();
292 #endif // ENABLE(FTL_JIT)
294 interpreter
->initialize(this->canUseJIT());
297 initializeHostCallReturnValue(); // This is needed to convince the linker not to drop host call return support.
300 heap
.notifyIsSafeToCollect();
302 LLInt::Data::performAssertions(*this);
304 if (Options::enableProfiler()) {
305 m_perBytecodeProfiler
= adoptPtr(new Profiler::Database(*this));
307 StringPrintStream pathOut
;
309 const char* profilerPath
= getenv("JSC_PROFILER_PATH");
311 pathOut
.print(profilerPath
, "/");
313 pathOut
.print("JSCProfile-", getCurrentProcessID(), "-", m_perBytecodeProfiler
->databaseID(), ".json");
314 m_perBytecodeProfiler
->registerToSaveAtExit(pathOut
.toCString().data());
319 dfgState
= adoptPtr(new DFG::LongLivedState());
322 // Initialize this last, as a free way of asserting that VM initialization itself
324 m_typedArrayController
= adoptRef(new SimpleTypedArrayController());
329 // Never GC, ever again.
330 heap
.incrementDeferralDepth();
333 // Make sure concurrent compilations are done, but don't install them, since there is
334 // no point to doing so.
335 for (unsigned i
= DFG::numberOfWorklists(); i
--;) {
336 if (DFG::Worklist
* worklist
= DFG::worklistForIndexOrNull(i
)) {
337 worklist
->waitUntilAllPlansForVMAreReady(*this);
338 worklist
->removeAllReadyPlansForVM(*this);
341 #endif // ENABLE(DFG_JIT)
343 // Clear this first to ensure that nobody tries to remove themselves from it.
344 m_perBytecodeProfiler
.clear();
346 ASSERT(m_apiLock
->currentThreadIsHoldingLock());
347 m_apiLock
->willDestroyVM(this);
348 heap
.lastChanceToFinalize();
352 interpreter
= reinterpret_cast<Interpreter
*>(0xbbadbeef);
355 arrayPrototypeTable
->deleteTable();
356 arrayConstructorTable
->deleteTable();
357 booleanPrototypeTable
->deleteTable();
358 dataViewTable
->deleteTable();
359 dateTable
->deleteTable();
360 dateConstructorTable
->deleteTable();
361 errorPrototypeTable
->deleteTable();
362 globalObjectTable
->deleteTable();
363 jsonTable
->deleteTable();
364 numberConstructorTable
->deleteTable();
365 numberPrototypeTable
->deleteTable();
366 objectConstructorTable
->deleteTable();
367 privateNamePrototypeTable
->deleteTable();
368 regExpTable
->deleteTable();
369 regExpConstructorTable
->deleteTable();
370 regExpPrototypeTable
->deleteTable();
371 stringConstructorTable
->deleteTable();
373 promisePrototypeTable
->deleteTable();
374 promiseConstructorTable
->deleteTable();
379 delete propertyNames
;
380 if (vmType
!= Default
)
381 delete m_atomicStringTable
;
384 delete m_regExpCache
;
385 #if ENABLE(REGEXP_TRACING)
386 delete m_rtTraceList
;
390 for (unsigned i
= 0; i
< scratchBuffers
.size(); ++i
)
391 fastFree(scratchBuffers
[i
]);
395 PassRefPtr
<VM
> VM::createContextGroup(HeapType heapType
)
397 return adoptRef(new VM(APIContextGroup
, heapType
));
400 PassRefPtr
<VM
> VM::create(HeapType heapType
)
402 return adoptRef(new VM(Default
, heapType
));
405 PassRefPtr
<VM
> VM::createLeaked(HeapType heapType
)
407 return create(heapType
);
410 bool VM::sharedInstanceExists()
412 return sharedInstanceInternal();
415 VM
& VM::sharedInstance()
417 GlobalJSLock globalLock
;
418 VM
*& instance
= sharedInstanceInternal();
420 instance
= adoptRef(new VM(APIShared
, SmallHeap
)).leakRef();
421 instance
->makeUsableFromMultipleThreads();
426 VM
*& VM::sharedInstanceInternal()
428 static VM
* sharedInstance
;
429 return sharedInstance
;
433 static ThunkGenerator
thunkGeneratorForIntrinsic(Intrinsic intrinsic
)
436 case CharCodeAtIntrinsic
:
437 return charCodeAtThunkGenerator
;
438 case CharAtIntrinsic
:
439 return charAtThunkGenerator
;
440 case FromCharCodeIntrinsic
:
441 return fromCharCodeThunkGenerator
;
443 return sqrtThunkGenerator
;
445 return powThunkGenerator
;
447 return absThunkGenerator
;
449 return floorThunkGenerator
;
451 return ceilThunkGenerator
;
453 return roundThunkGenerator
;
455 return expThunkGenerator
;
457 return logThunkGenerator
;
459 return imulThunkGenerator
;
460 case ArrayIteratorNextKeyIntrinsic
:
461 return arrayIteratorNextKeyThunkGenerator
;
462 case ArrayIteratorNextValueIntrinsic
:
463 return arrayIteratorNextValueThunkGenerator
;
469 NativeExecutable
* VM::getHostFunction(NativeFunction function
, NativeFunction constructor
)
471 return jitStubs
->hostFunctionStub(this, function
, constructor
);
473 NativeExecutable
* VM::getHostFunction(NativeFunction function
, Intrinsic intrinsic
)
476 return jitStubs
->hostFunctionStub(this, function
, intrinsic
!= NoIntrinsic
? thunkGeneratorForIntrinsic(intrinsic
) : 0, intrinsic
);
479 #else // !ENABLE(JIT)
481 NativeExecutable
* VM::getHostFunction(NativeFunction function
, NativeFunction constructor
)
483 return NativeExecutable::create(*this,
484 adoptRef(new NativeJITCode(MacroAssemblerCodeRef::createLLIntCodeRef(llint_native_call_trampoline
), JITCode::HostCallThunk
)), function
,
485 adoptRef(new NativeJITCode(MacroAssemblerCodeRef::createLLIntCodeRef(llint_native_construct_trampoline
), JITCode::HostCallThunk
)), constructor
,
489 #endif // !ENABLE(JIT)
491 VM::ClientData::~ClientData()
495 void VM::resetDateCache()
497 localTimeOffsetCache
.reset();
498 cachedDateString
= String();
499 cachedDateStringValue
= std::numeric_limits
<double>::quiet_NaN();
500 dateInstanceCache
.reset();
503 void VM::startSampling()
505 interpreter
->startSampling();
508 void VM::stopSampling()
510 interpreter
->stopSampling();
513 void VM::waitForCompilationsToComplete()
516 for (unsigned i
= DFG::numberOfWorklists(); i
--;) {
517 if (DFG::Worklist
* worklist
= DFG::worklistForIndexOrNull(i
))
518 worklist
->completeAllPlansForVM(*this);
520 #endif // ENABLE(DFG_JIT)
523 void VM::discardAllCode()
525 waitForCompilationsToComplete();
526 m_codeCache
->clear();
527 m_regExpCache
->invalidateCode();
528 heap
.deleteAllCompiledCode();
529 heap
.deleteAllUnlinkedFunctionCode();
530 heap
.reportAbandonedObjectGraph();
533 void VM::dumpSampleData(ExecState
* exec
)
535 interpreter
->dumpSampleData(exec
);
536 #if ENABLE(ASSEMBLER)
537 ExecutableAllocator::dumpProfile();
541 SourceProviderCache
* VM::addSourceProviderCache(SourceProvider
* sourceProvider
)
543 auto addResult
= sourceProviderCacheMap
.add(sourceProvider
, nullptr);
544 if (addResult
.isNewEntry
)
545 addResult
.iterator
->value
= adoptRef(new SourceProviderCache
);
546 return addResult
.iterator
->value
.get();
549 void VM::clearSourceProviderCaches()
551 sourceProviderCacheMap
.clear();
554 struct StackPreservingRecompiler
: public MarkedBlock::VoidFunctor
{
555 HashSet
<FunctionExecutable
*> currentlyExecutingFunctions
;
556 void operator()(JSCell
* cell
)
558 if (!cell
->inherits(FunctionExecutable::info()))
560 FunctionExecutable
* executable
= jsCast
<FunctionExecutable
*>(cell
);
561 if (currentlyExecutingFunctions
.contains(executable
))
563 executable
->clearCodeIfNotCompiling();
567 void VM::releaseExecutableMemory()
569 waitForCompilationsToComplete();
572 StackPreservingRecompiler recompiler
;
573 HeapIterationScope
iterationScope(heap
);
574 HashSet
<JSCell
*> roots
;
575 heap
.getConservativeRegisterRoots(roots
);
576 HashSet
<JSCell
*>::iterator end
= roots
.end();
577 for (HashSet
<JSCell
*>::iterator ptr
= roots
.begin(); ptr
!= end
; ++ptr
) {
578 ScriptExecutable
* executable
= 0;
580 if (cell
->inherits(ScriptExecutable::info()))
581 executable
= static_cast<ScriptExecutable
*>(*ptr
);
582 else if (cell
->inherits(JSFunction::info())) {
583 JSFunction
* function
= jsCast
<JSFunction
*>(*ptr
);
584 if (function
->isHostFunction())
586 executable
= function
->jsExecutable();
589 ASSERT(executable
->inherits(ScriptExecutable::info()));
590 executable
->unlinkCalls();
591 if (executable
->inherits(FunctionExecutable::info()))
592 recompiler
.currentlyExecutingFunctions
.add(static_cast<FunctionExecutable
*>(executable
));
595 heap
.objectSpace().forEachLiveCell
<StackPreservingRecompiler
>(iterationScope
, recompiler
);
597 m_regExpCache
->invalidateCode();
598 heap
.collectAllGarbage();
601 static void appendSourceToError(CallFrame
* callFrame
, ErrorInstance
* exception
, unsigned bytecodeOffset
)
603 exception
->clearAppendSourceToMessage();
605 if (!callFrame
->codeBlock()->hasExpressionInfo())
614 CodeBlock
* codeBlock
= callFrame
->codeBlock();
615 codeBlock
->expressionRangeForBytecodeOffset(bytecodeOffset
, divotPoint
, startOffset
, endOffset
, line
, column
);
617 int expressionStart
= divotPoint
- startOffset
;
618 int expressionStop
= divotPoint
+ endOffset
;
620 const String
& sourceString
= codeBlock
->source()->source();
621 if (!expressionStop
|| expressionStart
> static_cast<int>(sourceString
.length()))
624 VM
* vm
= &callFrame
->vm();
625 JSValue jsMessage
= exception
->getDirect(*vm
, vm
->propertyNames
->message
);
626 if (!jsMessage
|| !jsMessage
.isString())
629 String message
= asString(jsMessage
)->value(callFrame
);
631 if (expressionStart
< expressionStop
)
632 message
= makeString(message
, " (evaluating '", codeBlock
->source()->getRange(expressionStart
, expressionStop
), "')");
634 // No range information, so give a few characters of context.
635 const StringImpl
* data
= sourceString
.impl();
636 int dataLength
= sourceString
.length();
637 int start
= expressionStart
;
638 int stop
= expressionStart
;
639 // Get up to 20 characters of context to the left and right of the divot, clamping to the line.
640 // Then strip whitespace.
641 while (start
> 0 && (expressionStart
- start
< 20) && (*data
)[start
- 1] != '\n')
643 while (start
< (expressionStart
- 1) && isStrWhiteSpace((*data
)[start
]))
645 while (stop
< dataLength
&& (stop
- expressionStart
< 20) && (*data
)[stop
] != '\n')
647 while (stop
> expressionStart
&& isStrWhiteSpace((*data
)[stop
- 1]))
649 message
= makeString(message
, " (near '...", codeBlock
->source()->getRange(start
, stop
), "...')");
652 exception
->putDirect(*vm
, vm
->propertyNames
->message
, jsString(vm
, message
));
655 JSValue
VM::throwException(ExecState
* exec
, JSValue error
)
657 if (Options::breakOnThrow()) {
658 dataLog("In call frame ", RawPointer(exec
), " for code block ", *exec
->codeBlock(), "\n");
662 ASSERT(exec
== topCallFrame
|| exec
== exec
->lexicalGlobalObject()->globalExec() || exec
== exec
->vmEntryGlobalObject()->globalExec());
664 Vector
<StackFrame
> stackTrace
;
665 interpreter
->getStackTrace(stackTrace
);
666 m_exceptionStack
= RefCountedArray
<StackFrame
>(stackTrace
);
669 if (stackTrace
.isEmpty() || !error
.isObject())
671 JSObject
* exception
= asObject(error
);
673 StackFrame stackFrame
;
674 for (unsigned i
= 0 ; i
< stackTrace
.size(); ++i
) {
675 stackFrame
= stackTrace
.at(i
);
676 if (stackFrame
.bytecodeOffset
)
679 unsigned bytecodeOffset
= stackFrame
.bytecodeOffset
;
680 if (!hasErrorInfo(exec
, exception
)) {
681 // FIXME: We should only really be adding these properties to VM generated exceptions,
682 // but the inspector currently requires these for all thrown objects.
685 stackFrame
.computeLineAndColumn(line
, column
);
686 exception
->putDirect(*this, Identifier(this, "line"), jsNumber(line
), ReadOnly
| DontDelete
);
687 exception
->putDirect(*this, Identifier(this, "column"), jsNumber(column
), ReadOnly
| DontDelete
);
688 if (!stackFrame
.sourceURL
.isEmpty())
689 exception
->putDirect(*this, Identifier(this, "sourceURL"), jsString(this, stackFrame
.sourceURL
), ReadOnly
| DontDelete
);
691 if (exception
->isErrorInstance() && static_cast<ErrorInstance
*>(exception
)->appendSourceToMessage()) {
692 unsigned stackIndex
= 0;
693 CallFrame
* callFrame
;
694 for (callFrame
= exec
; callFrame
&& !callFrame
->codeBlock(); ) {
696 callFrame
= callFrame
->callerFrameSkippingVMEntrySentinel();
698 if (callFrame
&& callFrame
->codeBlock()) {
699 stackFrame
= stackTrace
.at(stackIndex
);
700 bytecodeOffset
= stackFrame
.bytecodeOffset
;
701 appendSourceToError(callFrame
, static_cast<ErrorInstance
*>(exception
), bytecodeOffset
);
705 if (exception
->hasProperty(exec
, this->propertyNames
->stack
))
708 exception
->putDirect(*this, propertyNames
->stack
, interpreter
->stackTraceAsString(topCallFrame
, stackTrace
), DontEnum
);
712 JSObject
* VM::throwException(ExecState
* exec
, JSObject
* error
)
714 return asObject(throwException(exec
, JSValue(error
)));
716 void VM::getExceptionInfo(JSValue
& exception
, RefCountedArray
<StackFrame
>& exceptionStack
)
718 exception
= m_exception
;
719 exceptionStack
= m_exceptionStack
;
721 void VM::setExceptionInfo(JSValue
& exception
, RefCountedArray
<StackFrame
>& exceptionStack
)
723 m_exception
= exception
;
724 m_exceptionStack
= exceptionStack
;
727 void VM::clearException()
729 m_exception
= JSValue();
731 void VM:: clearExceptionStack()
733 m_exceptionStack
= RefCountedArray
<StackFrame
>();
736 void VM::setStackPointerAtVMEntry(void* sp
)
738 m_stackPointerAtVMEntry
= sp
;
742 size_t VM::updateReservedZoneSize(size_t reservedZoneSize
)
744 size_t oldReservedZoneSize
= m_reservedZoneSize
;
745 m_reservedZoneSize
= reservedZoneSize
;
749 return oldReservedZoneSize
;
753 // On Windows the reserved stack space consists of committed memory, a guard page, and uncommitted memory,
754 // where the guard page is a barrier between committed and uncommitted memory.
755 // When data from the guard page is read or written, the guard page is moved, and memory is committed.
756 // This is how the system grows the stack.
757 // When using the C stack on Windows we need to precommit the needed stack space.
758 // Otherwise we might crash later if we access uncommitted stack memory.
759 // This can happen if we allocate stack space larger than the page guard size (4K).
760 // The system does not get the chance to move the guard page, and commit more memory,
761 // and we crash if uncommitted memory is accessed.
762 // The MSVC compiler fixes this by inserting a call to the _chkstk() function,
763 // when needed, see http://support.microsoft.com/kb/100775.
764 // By touching every page up to the stack limit with a dummy operation,
765 // we force the system to move the guard page, and commit memory.
767 static void preCommitStackMemory(void* stackLimit
)
769 const int pageSize
= 4096;
770 for (volatile char* p
= reinterpret_cast<char*>(&stackLimit
); p
> stackLimit
; p
-= pageSize
) {
777 inline void VM::updateStackLimit()
780 void* lastStackLimit
= m_stackLimit
;
783 if (m_stackPointerAtVMEntry
) {
784 ASSERT(wtfThreadData().stack().isGrowingDownward());
785 char* startOfStack
= reinterpret_cast<char*>(m_stackPointerAtVMEntry
);
787 m_stackLimit
= wtfThreadData().stack().recursionLimit(startOfStack
, Options::maxPerThreadStackUsage(), m_reservedZoneSize
+ m_largestFTLStackSize
);
788 m_ftlStackLimit
= wtfThreadData().stack().recursionLimit(startOfStack
, Options::maxPerThreadStackUsage(), m_reservedZoneSize
+ 2 * m_largestFTLStackSize
);
790 m_stackLimit
= wtfThreadData().stack().recursionLimit(startOfStack
, Options::maxPerThreadStackUsage(), m_reservedZoneSize
);
794 m_stackLimit
= wtfThreadData().stack().recursionLimit(m_reservedZoneSize
+ m_largestFTLStackSize
);
795 m_ftlStackLimit
= wtfThreadData().stack().recursionLimit(m_reservedZoneSize
+ 2 * m_largestFTLStackSize
);
797 m_stackLimit
= wtfThreadData().stack().recursionLimit(m_reservedZoneSize
);
802 if (lastStackLimit
!= m_stackLimit
)
803 preCommitStackMemory(m_stackLimit
);
808 void VM::updateFTLLargestStackSize(size_t stackSize
)
810 if (stackSize
> m_largestFTLStackSize
) {
811 m_largestFTLStackSize
= stackSize
;
817 void releaseExecutableMemory(VM
& vm
)
819 vm
.releaseExecutableMemory();
823 void VM::gatherConservativeRoots(ConservativeRoots
& conservativeRoots
)
825 for (size_t i
= 0; i
< scratchBuffers
.size(); i
++) {
826 ScratchBuffer
* scratchBuffer
= scratchBuffers
[i
];
827 if (scratchBuffer
->activeLength()) {
828 void* bufferStart
= scratchBuffer
->dataBuffer();
829 conservativeRoots
.add(bufferStart
, static_cast<void*>(static_cast<char*>(bufferStart
) + scratchBuffer
->activeLength()));
835 void logSanitizeStack(VM
* vm
)
837 if (Options::verboseSanitizeStack() && vm
->topCallFrame
) {
840 "Sanitizing stack with top call frame at ", RawPointer(vm
->topCallFrame
),
841 ", current stack pointer at ", RawPointer(&dummy
), ", in ",
842 pointerDump(vm
->topCallFrame
->codeBlock()), " and last code origin = ",
843 vm
->topCallFrame
->codeOrigin(), "\n");
847 #if ENABLE(REGEXP_TRACING)
848 void VM::addRegExpToTrace(RegExp
* regExp
)
851 m_rtTraceList
->add(regExp
);
854 void VM::dumpRegExpTrace()
856 // The first RegExp object is ignored. It is create by the RegExpPrototype ctor and not used.
857 RTTraceList::iterator iter
= ++m_rtTraceList
->begin();
859 if (iter
!= m_rtTraceList
->end()) {
860 dataLogF("\nRegExp Tracing\n");
861 dataLogF("Regular Expression 8 Bit 16 Bit match() Matches Average\n");
862 dataLogF(" <Match only / Match> JIT Addr JIT Address calls found String len\n");
863 dataLogF("----------------------------------------+----------------+----------------+----------+----------+-----------\n");
865 unsigned reCount
= 0;
867 for (; iter
!= m_rtTraceList
->end(); ++iter
, ++reCount
) {
868 (*iter
)->printTraceData();
872 dataLogF("%d Regular Expressions\n", reCount
);
875 m_rtTraceList
->clear();
878 void VM::dumpRegExpTrace()
883 void VM::registerWatchpointForImpureProperty(const Identifier
& propertyName
, Watchpoint
* watchpoint
)
885 auto result
= m_impurePropertyWatchpointSets
.add(propertyName
.string(), nullptr);
886 if (result
.isNewEntry
)
887 result
.iterator
->value
= adoptRef(new WatchpointSet(IsWatched
));
888 result
.iterator
->value
->add(watchpoint
);
891 void VM::addImpureProperty(const String
& propertyName
)
893 if (RefPtr
<WatchpointSet
> watchpointSet
= m_impurePropertyWatchpointSets
.take(propertyName
))
894 watchpointSet
->fireAll();
897 class SetEnabledProfilerFunctor
{
899 bool operator()(CodeBlock
* codeBlock
)
901 if (JITCode::isOptimizingJIT(codeBlock
->jitType()))
902 codeBlock
->jettison(Profiler::JettisonDueToLegacyProfiler
);
907 void VM::setEnabledProfiler(LegacyProfiler
* profiler
)
909 m_enabledProfiler
= profiler
;
910 if (m_enabledProfiler
) {
911 waitForCompilationsToComplete();
912 SetEnabledProfilerFunctor functor
;
913 heap
.forEachCodeBlock(functor
);
917 void sanitizeStackForVM(VM
* vm
)
919 logSanitizeStack(vm
);
921 vm
->interpreter
->stack().sanitizeStack();
923 sanitizeStackForVMImpl(vm
);