1/* 2 * Copyright (C) 2008, 2011, 2013, 2014 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 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. 16 * 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. 27 */ 28 29#include "config.h" 30#include "VM.h" 31 32#include "ArgList.h" 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" 49#include "Heap.h" 50#include "HeapIterationScope.h" 51#include "HostCallReturnValue.h" 52#include "Identifier.h" 53#include "IncrementalSweeper.h" 54#include "Interpreter.h" 55#include "JITCode.h" 56#include "JSAPIValueWrapper.h" 57#include "JSActivation.h" 58#include "JSArray.h" 59#include "JSCInlines.h" 60#include "JSFunction.h" 61#include "JSGlobalObjectFunctions.h" 62#include "JSLock.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" 69#include "Lexer.h" 70#include "Lookup.h" 71#include "MapData.h" 72#include "Nodes.h" 73#include "Parser.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> 92 93#if ENABLE(DFG_JIT) 94#include "ConservativeRoots.h" 95#endif 96 97#if ENABLE(REGEXP_TRACING) 98#include "RegExp.h" 99#endif 100 101#if USE(CF) 102#include <CoreFoundation/CoreFoundation.h> 103#endif 104 105using namespace WTF; 106 107namespace JSC { 108 109extern const HashTable arrayConstructorTable; 110extern const HashTable arrayPrototypeTable; 111extern const HashTable booleanPrototypeTable; 112extern const HashTable jsonTable; 113extern const HashTable dataViewTable; 114extern const HashTable dateTable; 115extern const HashTable dateConstructorTable; 116extern const HashTable errorPrototypeTable; 117extern const HashTable globalObjectTable; 118extern const HashTable numberConstructorTable; 119extern const HashTable numberPrototypeTable; 120JS_EXPORTDATA extern const HashTable objectConstructorTable; 121extern const HashTable privateNamePrototypeTable; 122extern const HashTable regExpTable; 123extern const HashTable regExpConstructorTable; 124extern const HashTable regExpPrototypeTable; 125extern const HashTable stringConstructorTable; 126#if ENABLE(PROMISES) 127extern const HashTable promisePrototypeTable; 128extern const HashTable promiseConstructorTable; 129#endif 130 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. 134 135#if ENABLE(ASSEMBLER) 136static bool enableAssembler(ExecutableAllocator& executableAllocator) 137{ 138 if (!Options::useJIT() && !Options::useRegExpJIT()) 139 return false; 140 141 if (!executableAllocator.isValid()) { 142 if (Options::crashIfCantAllocateJITMemory()) 143 CRASH(); 144 return false; 145 } 146 147#if USE(CF) 148 CFStringRef canUseJITKey = CFSTR("JavaScriptCoreUseJIT"); 149 RetainPtr<CFTypeRef> canUseJIT = adoptCF(CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication)); 150 if (canUseJIT) 151 return kCFBooleanTrue == canUseJIT.get(); 152#endif 153 154#if USE(CF) || OS(UNIX) 155 char* canUseJITString = getenv("JavaScriptCoreUseJIT"); 156 return !canUseJITString || atoi(canUseJITString); 157#else 158 return true; 159#endif 160} 161#endif // ENABLE(!ASSEMBLER) 162 163VM::VM(VMType vmType, HeapType heapType) 164 : m_apiLock(adoptRef(new JSLock(this))) 165#if ENABLE(ASSEMBLER) 166 , executableAllocator(*this) 167#endif 168 , heap(this, heapType) 169 , vmType(vmType) 170 , clientData(0) 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))) 189#if ENABLE(PROMISES) 190 , promisePrototypeTable(adoptPtr(new HashTable(JSC::promisePrototypeTable))) 191 , promiseConstructorTable(adoptPtr(new HashTable(JSC::promiseConstructorTable))) 192#endif 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))) 198 , interpreter(0) 199 , jsArrayClassInfo(JSArray::info()) 200 , jsFinalObjectClassInfo(JSFinalObject::info()) 201 , sizeOfLastScratchBuffer(0) 202 , entryScope(0) 203 , m_regExpCache(new RegExpCache(this)) 204#if ENABLE(REGEXP_TRACING) 205 , m_rtTraceList(new RTTraceList()) 206#endif 207 , m_newStringsSinceLastHashCons(0) 208#if ENABLE(ASSEMBLER) 209 , m_canUseAssembler(enableAssembler(executableAllocator)) 210#endif 211#if ENABLE(JIT) 212 , m_canUseJIT(m_canUseAssembler && Options::useJIT()) 213#endif 214#if ENABLE(YARR_JIT) 215 , m_canUseRegExpJIT(m_canUseAssembler && Options::useRegExpJIT()) 216#endif 217#if ENABLE(GC_VALIDATION) 218 , m_initializingObjectClass(0) 219#endif 220 , m_stackPointerAtVMEntry(0) 221 , m_stackLimit(0) 222#if !ENABLE(JIT) 223 , m_jsStackLimit(0) 224#endif 225#if ENABLE(FTL_JIT) 226 , m_ftlStackLimit(0) 227 , m_largestFTLStackSize(0) 228#endif 229 , m_inDefineOwnProperty(false) 230 , m_codeCache(CodeCache::create()) 231 , m_enabledProfiler(nullptr) 232 , m_builtinExecutables(BuiltinExecutables::create(*this)) 233{ 234 interpreter = new Interpreter(*this); 235 StackBounds stack = wtfThreadData().stack(); 236 updateReservedZoneSize(Options::reservedZoneSize()); 237#if !ENABLE(JIT) 238 interpreter->stack().setReservedZoneSize(Options::reservedZoneSize()); 239#endif 240 setLastStackTop(stack.origin()); 241 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())); 275#if ENABLE(PROMISES) 276 promiseDeferredStructure.set(*this, JSPromiseDeferred::createStructure(*this, 0, jsNull())); 277 promiseReactionStructure.set(*this, JSPromiseReaction::createStructure(*this, 0, jsNull())); 278#endif 279 iterationTerminator.set(*this, JSFinalObject::create(*this, JSFinalObject::createStructure(*this, 0, jsNull(), 1))); 280 smallStrings.initializeCommonStrings(*this); 281 282 wtfThreadData().setCurrentAtomicStringTable(existingEntryAtomicStringTable); 283 284#if ENABLE(JIT) 285 jitStubs = adoptPtr(new JITThunks()); 286 arityCheckFailReturnThunks = std::make_unique<ArityCheckFailReturnThunks>(); 287#endif 288 arityCheckData = std::make_unique<CommonSlowPaths::ArityCheckData>(); 289 290#if ENABLE(FTL_JIT) 291 ftlThunks = std::make_unique<FTL::Thunks>(); 292#endif // ENABLE(FTL_JIT) 293 294 interpreter->initialize(this->canUseJIT()); 295 296#if ENABLE(JIT) 297 initializeHostCallReturnValue(); // This is needed to convince the linker not to drop host call return support. 298#endif 299 300 heap.notifyIsSafeToCollect(); 301 302 LLInt::Data::performAssertions(*this); 303 304 if (Options::enableProfiler()) { 305 m_perBytecodeProfiler = adoptPtr(new Profiler::Database(*this)); 306 307 StringPrintStream pathOut; 308#if !OS(WINCE) 309 const char* profilerPath = getenv("JSC_PROFILER_PATH"); 310 if (profilerPath) 311 pathOut.print(profilerPath, "/"); 312#endif 313 pathOut.print("JSCProfile-", getCurrentProcessID(), "-", m_perBytecodeProfiler->databaseID(), ".json"); 314 m_perBytecodeProfiler->registerToSaveAtExit(pathOut.toCString().data()); 315 } 316 317#if ENABLE(DFG_JIT) 318 if (canUseJIT()) 319 dfgState = adoptPtr(new DFG::LongLivedState()); 320#endif 321 322 // Initialize this last, as a free way of asserting that VM initialization itself 323 // won't use this. 324 m_typedArrayController = adoptRef(new SimpleTypedArrayController()); 325} 326 327VM::~VM() 328{ 329 // Never GC, ever again. 330 heap.incrementDeferralDepth(); 331 332#if ENABLE(DFG_JIT) 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); 339 } 340 } 341#endif // ENABLE(DFG_JIT) 342 343 // Clear this first to ensure that nobody tries to remove themselves from it. 344 m_perBytecodeProfiler.clear(); 345 346 ASSERT(m_apiLock->currentThreadIsHoldingLock()); 347 m_apiLock->willDestroyVM(this); 348 heap.lastChanceToFinalize(); 349 350 delete interpreter; 351#ifndef NDEBUG 352 interpreter = reinterpret_cast<Interpreter*>(0xbbadbeef); 353#endif 354 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(); 372#if ENABLE(PROMISES) 373 promisePrototypeTable->deleteTable(); 374 promiseConstructorTable->deleteTable(); 375#endif 376 377 delete emptyList; 378 379 delete propertyNames; 380 if (vmType != Default) 381 delete m_atomicStringTable; 382 383 delete clientData; 384 delete m_regExpCache; 385#if ENABLE(REGEXP_TRACING) 386 delete m_rtTraceList; 387#endif 388 389#if ENABLE(DFG_JIT) 390 for (unsigned i = 0; i < scratchBuffers.size(); ++i) 391 fastFree(scratchBuffers[i]); 392#endif 393} 394 395PassRefPtr<VM> VM::createContextGroup(HeapType heapType) 396{ 397 return adoptRef(new VM(APIContextGroup, heapType)); 398} 399 400PassRefPtr<VM> VM::create(HeapType heapType) 401{ 402 return adoptRef(new VM(Default, heapType)); 403} 404 405PassRefPtr<VM> VM::createLeaked(HeapType heapType) 406{ 407 return create(heapType); 408} 409 410bool VM::sharedInstanceExists() 411{ 412 return sharedInstanceInternal(); 413} 414 415VM& VM::sharedInstance() 416{ 417 GlobalJSLock globalLock; 418 VM*& instance = sharedInstanceInternal(); 419 if (!instance) { 420 instance = adoptRef(new VM(APIShared, SmallHeap)).leakRef(); 421 instance->makeUsableFromMultipleThreads(); 422 } 423 return *instance; 424} 425 426VM*& VM::sharedInstanceInternal() 427{ 428 static VM* sharedInstance; 429 return sharedInstance; 430} 431 432#if ENABLE(JIT) 433static ThunkGenerator thunkGeneratorForIntrinsic(Intrinsic intrinsic) 434{ 435 switch (intrinsic) { 436 case CharCodeAtIntrinsic: 437 return charCodeAtThunkGenerator; 438 case CharAtIntrinsic: 439 return charAtThunkGenerator; 440 case FromCharCodeIntrinsic: 441 return fromCharCodeThunkGenerator; 442 case SqrtIntrinsic: 443 return sqrtThunkGenerator; 444 case PowIntrinsic: 445 return powThunkGenerator; 446 case AbsIntrinsic: 447 return absThunkGenerator; 448 case FloorIntrinsic: 449 return floorThunkGenerator; 450 case CeilIntrinsic: 451 return ceilThunkGenerator; 452 case RoundIntrinsic: 453 return roundThunkGenerator; 454 case ExpIntrinsic: 455 return expThunkGenerator; 456 case LogIntrinsic: 457 return logThunkGenerator; 458 case IMulIntrinsic: 459 return imulThunkGenerator; 460 case ArrayIteratorNextKeyIntrinsic: 461 return arrayIteratorNextKeyThunkGenerator; 462 case ArrayIteratorNextValueIntrinsic: 463 return arrayIteratorNextValueThunkGenerator; 464 default: 465 return 0; 466 } 467} 468 469NativeExecutable* VM::getHostFunction(NativeFunction function, NativeFunction constructor) 470{ 471 return jitStubs->hostFunctionStub(this, function, constructor); 472} 473NativeExecutable* VM::getHostFunction(NativeFunction function, Intrinsic intrinsic) 474{ 475 ASSERT(canUseJIT()); 476 return jitStubs->hostFunctionStub(this, function, intrinsic != NoIntrinsic ? thunkGeneratorForIntrinsic(intrinsic) : 0, intrinsic); 477} 478 479#else // !ENABLE(JIT) 480 481NativeExecutable* VM::getHostFunction(NativeFunction function, NativeFunction constructor) 482{ 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, 486 NoIntrinsic); 487} 488 489#endif // !ENABLE(JIT) 490 491VM::ClientData::~ClientData() 492{ 493} 494 495void VM::resetDateCache() 496{ 497 localTimeOffsetCache.reset(); 498 cachedDateString = String(); 499 cachedDateStringValue = std::numeric_limits<double>::quiet_NaN(); 500 dateInstanceCache.reset(); 501} 502 503void VM::startSampling() 504{ 505 interpreter->startSampling(); 506} 507 508void VM::stopSampling() 509{ 510 interpreter->stopSampling(); 511} 512 513void VM::waitForCompilationsToComplete() 514{ 515#if ENABLE(DFG_JIT) 516 for (unsigned i = DFG::numberOfWorklists(); i--;) { 517 if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i)) 518 worklist->completeAllPlansForVM(*this); 519 } 520#endif // ENABLE(DFG_JIT) 521} 522 523void VM::discardAllCode() 524{ 525 waitForCompilationsToComplete(); 526 m_codeCache->clear(); 527 m_regExpCache->invalidateCode(); 528 heap.deleteAllCompiledCode(); 529 heap.deleteAllUnlinkedFunctionCode(); 530 heap.reportAbandonedObjectGraph(); 531} 532 533void VM::dumpSampleData(ExecState* exec) 534{ 535 interpreter->dumpSampleData(exec); 536#if ENABLE(ASSEMBLER) 537 ExecutableAllocator::dumpProfile(); 538#endif 539} 540 541SourceProviderCache* VM::addSourceProviderCache(SourceProvider* sourceProvider) 542{ 543 auto addResult = sourceProviderCacheMap.add(sourceProvider, nullptr); 544 if (addResult.isNewEntry) 545 addResult.iterator->value = adoptRef(new SourceProviderCache); 546 return addResult.iterator->value.get(); 547} 548 549void VM::clearSourceProviderCaches() 550{ 551 sourceProviderCacheMap.clear(); 552} 553 554struct StackPreservingRecompiler : public MarkedBlock::VoidFunctor { 555 HashSet<FunctionExecutable*> currentlyExecutingFunctions; 556 void operator()(JSCell* cell) 557 { 558 if (!cell->inherits(FunctionExecutable::info())) 559 return; 560 FunctionExecutable* executable = jsCast<FunctionExecutable*>(cell); 561 if (currentlyExecutingFunctions.contains(executable)) 562 return; 563 executable->clearCodeIfNotCompiling(); 564 } 565}; 566 567void VM::releaseExecutableMemory() 568{ 569 waitForCompilationsToComplete(); 570 571 if (entryScope) { 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; 579 JSCell* cell = *ptr; 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()) 585 continue; 586 executable = function->jsExecutable(); 587 } else 588 continue; 589 ASSERT(executable->inherits(ScriptExecutable::info())); 590 executable->unlinkCalls(); 591 if (executable->inherits(FunctionExecutable::info())) 592 recompiler.currentlyExecutingFunctions.add(static_cast<FunctionExecutable*>(executable)); 593 594 } 595 heap.objectSpace().forEachLiveCell<StackPreservingRecompiler>(iterationScope, recompiler); 596 } 597 m_regExpCache->invalidateCode(); 598 heap.collectAllGarbage(); 599} 600 601static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception, unsigned bytecodeOffset) 602{ 603 exception->clearAppendSourceToMessage(); 604 605 if (!callFrame->codeBlock()->hasExpressionInfo()) 606 return; 607 608 int startOffset = 0; 609 int endOffset = 0; 610 int divotPoint = 0; 611 unsigned line = 0; 612 unsigned column = 0; 613 614 CodeBlock* codeBlock = callFrame->codeBlock(); 615 codeBlock->expressionRangeForBytecodeOffset(bytecodeOffset, divotPoint, startOffset, endOffset, line, column); 616 617 int expressionStart = divotPoint - startOffset; 618 int expressionStop = divotPoint + endOffset; 619 620 const String& sourceString = codeBlock->source()->source(); 621 if (!expressionStop || expressionStart > static_cast<int>(sourceString.length())) 622 return; 623 624 VM* vm = &callFrame->vm(); 625 JSValue jsMessage = exception->getDirect(*vm, vm->propertyNames->message); 626 if (!jsMessage || !jsMessage.isString()) 627 return; 628 629 String message = asString(jsMessage)->value(callFrame); 630 631 if (expressionStart < expressionStop) 632 message = makeString(message, " (evaluating '", codeBlock->source()->getRange(expressionStart, expressionStop), "')"); 633 else { 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') 642 start--; 643 while (start < (expressionStart - 1) && isStrWhiteSpace((*data)[start])) 644 start++; 645 while (stop < dataLength && (stop - expressionStart < 20) && (*data)[stop] != '\n') 646 stop++; 647 while (stop > expressionStart && isStrWhiteSpace((*data)[stop - 1])) 648 stop--; 649 message = makeString(message, " (near '...", codeBlock->source()->getRange(start, stop), "...')"); 650 } 651 652 exception->putDirect(*vm, vm->propertyNames->message, jsString(vm, message)); 653} 654 655JSValue VM::throwException(ExecState* exec, JSValue error) 656{ 657 if (Options::breakOnThrow()) { 658 dataLog("In call frame ", RawPointer(exec), " for code block ", *exec->codeBlock(), "\n"); 659 CRASH(); 660 } 661 662 ASSERT(exec == topCallFrame || exec == exec->lexicalGlobalObject()->globalExec() || exec == exec->vmEntryGlobalObject()->globalExec()); 663 664 Vector<StackFrame> stackTrace; 665 interpreter->getStackTrace(stackTrace); 666 m_exceptionStack = RefCountedArray<StackFrame>(stackTrace); 667 m_exception = error; 668 669 if (stackTrace.isEmpty() || !error.isObject()) 670 return error; 671 JSObject* exception = asObject(error); 672 673 StackFrame stackFrame; 674 for (unsigned i = 0 ; i < stackTrace.size(); ++i) { 675 stackFrame = stackTrace.at(i); 676 if (stackFrame.bytecodeOffset) 677 break; 678 } 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. 683 unsigned line; 684 unsigned column; 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); 690 } 691 if (exception->isErrorInstance() && static_cast<ErrorInstance*>(exception)->appendSourceToMessage()) { 692 unsigned stackIndex = 0; 693 CallFrame* callFrame; 694 for (callFrame = exec; callFrame && !callFrame->codeBlock(); ) { 695 stackIndex++; 696 callFrame = callFrame->callerFrameSkippingVMEntrySentinel(); 697 } 698 if (callFrame && callFrame->codeBlock()) { 699 stackFrame = stackTrace.at(stackIndex); 700 bytecodeOffset = stackFrame.bytecodeOffset; 701 appendSourceToError(callFrame, static_cast<ErrorInstance*>(exception), bytecodeOffset); 702 } 703 } 704 705 if (exception->hasProperty(exec, this->propertyNames->stack)) 706 return error; 707 708 exception->putDirect(*this, propertyNames->stack, interpreter->stackTraceAsString(topCallFrame, stackTrace), DontEnum); 709 return error; 710} 711 712JSObject* VM::throwException(ExecState* exec, JSObject* error) 713{ 714 return asObject(throwException(exec, JSValue(error))); 715} 716void VM::getExceptionInfo(JSValue& exception, RefCountedArray<StackFrame>& exceptionStack) 717{ 718 exception = m_exception; 719 exceptionStack = m_exceptionStack; 720} 721void VM::setExceptionInfo(JSValue& exception, RefCountedArray<StackFrame>& exceptionStack) 722{ 723 m_exception = exception; 724 m_exceptionStack = exceptionStack; 725} 726 727void VM::clearException() 728{ 729 m_exception = JSValue(); 730} 731void VM:: clearExceptionStack() 732{ 733 m_exceptionStack = RefCountedArray<StackFrame>(); 734} 735 736void VM::setStackPointerAtVMEntry(void* sp) 737{ 738 m_stackPointerAtVMEntry = sp; 739 updateStackLimit(); 740} 741 742size_t VM::updateReservedZoneSize(size_t reservedZoneSize) 743{ 744 size_t oldReservedZoneSize = m_reservedZoneSize; 745 m_reservedZoneSize = reservedZoneSize; 746 747 updateStackLimit(); 748 749 return oldReservedZoneSize; 750} 751 752#if PLATFORM(WIN) 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. 766 767static void preCommitStackMemory(void* stackLimit) 768{ 769 const int pageSize = 4096; 770 for (volatile char* p = reinterpret_cast<char*>(&stackLimit); p > stackLimit; p -= pageSize) { 771 char ch = *p; 772 *p = ch; 773 } 774} 775#endif 776 777inline void VM::updateStackLimit() 778{ 779#if PLATFORM(WIN) 780 void* lastStackLimit = m_stackLimit; 781#endif 782 783 if (m_stackPointerAtVMEntry) { 784 ASSERT(wtfThreadData().stack().isGrowingDownward()); 785 char* startOfStack = reinterpret_cast<char*>(m_stackPointerAtVMEntry); 786#if ENABLE(FTL_JIT) 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); 789#else 790 m_stackLimit = wtfThreadData().stack().recursionLimit(startOfStack, Options::maxPerThreadStackUsage(), m_reservedZoneSize); 791#endif 792 } else { 793#if ENABLE(FTL_JIT) 794 m_stackLimit = wtfThreadData().stack().recursionLimit(m_reservedZoneSize + m_largestFTLStackSize); 795 m_ftlStackLimit = wtfThreadData().stack().recursionLimit(m_reservedZoneSize + 2 * m_largestFTLStackSize); 796#else 797 m_stackLimit = wtfThreadData().stack().recursionLimit(m_reservedZoneSize); 798#endif 799 } 800 801#if PLATFORM(WIN) 802 if (lastStackLimit != m_stackLimit) 803 preCommitStackMemory(m_stackLimit); 804#endif 805} 806 807#if ENABLE(FTL_JIT) 808void VM::updateFTLLargestStackSize(size_t stackSize) 809{ 810 if (stackSize > m_largestFTLStackSize) { 811 m_largestFTLStackSize = stackSize; 812 updateStackLimit(); 813 } 814} 815#endif 816 817void releaseExecutableMemory(VM& vm) 818{ 819 vm.releaseExecutableMemory(); 820} 821 822#if ENABLE(DFG_JIT) 823void VM::gatherConservativeRoots(ConservativeRoots& conservativeRoots) 824{ 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())); 830 } 831 } 832} 833#endif 834 835void logSanitizeStack(VM* vm) 836{ 837 if (Options::verboseSanitizeStack() && vm->topCallFrame) { 838 int dummy; 839 dataLog( 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"); 844 } 845} 846 847#if ENABLE(REGEXP_TRACING) 848void VM::addRegExpToTrace(RegExp* regExp) 849{ 850 gcProtect(regExp); 851 m_rtTraceList->add(regExp); 852} 853 854void VM::dumpRegExpTrace() 855{ 856 // The first RegExp object is ignored. It is create by the RegExpPrototype ctor and not used. 857 RTTraceList::iterator iter = ++m_rtTraceList->begin(); 858 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"); 864 865 unsigned reCount = 0; 866 867 for (; iter != m_rtTraceList->end(); ++iter, ++reCount) { 868 (*iter)->printTraceData(); 869 gcUnprotect(*iter); 870 } 871 872 dataLogF("%d Regular Expressions\n", reCount); 873 } 874 875 m_rtTraceList->clear(); 876} 877#else 878void VM::dumpRegExpTrace() 879{ 880} 881#endif 882 883void VM::registerWatchpointForImpureProperty(const Identifier& propertyName, Watchpoint* watchpoint) 884{ 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); 889} 890 891void VM::addImpureProperty(const String& propertyName) 892{ 893 if (RefPtr<WatchpointSet> watchpointSet = m_impurePropertyWatchpointSets.take(propertyName)) 894 watchpointSet->fireAll(); 895} 896 897class SetEnabledProfilerFunctor { 898public: 899 bool operator()(CodeBlock* codeBlock) 900 { 901 if (JITCode::isOptimizingJIT(codeBlock->jitType())) 902 codeBlock->jettison(Profiler::JettisonDueToLegacyProfiler); 903 return false; 904 } 905}; 906 907void VM::setEnabledProfiler(LegacyProfiler* profiler) 908{ 909 m_enabledProfiler = profiler; 910 if (m_enabledProfiler) { 911 waitForCompilationsToComplete(); 912 SetEnabledProfilerFunctor functor; 913 heap.forEachCodeBlock(functor); 914 } 915} 916 917void sanitizeStackForVM(VM* vm) 918{ 919 logSanitizeStack(vm); 920#if !ENABLE(JIT) 921 vm->interpreter->stack().sanitizeStack(); 922#else 923 sanitizeStackForVMImpl(vm); 924#endif 925} 926 927} // namespace JSC 928