EncodedJSValue JIT_OPERATION operationGetByVal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); JSValue baseValue = JSValue::decode(encodedBase); JSValue property = JSValue::decode(encodedProperty); if (LIKELY(baseValue.isCell())) { JSCell* base = baseValue.asCell(); if (property.isUInt32()) { return getByVal(exec, base, property.asUInt32()); } else if (property.isDouble()) { double propertyAsDouble = property.asDouble(); uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble); if (propertyAsUInt32 == propertyAsDouble) return getByVal(exec, base, propertyAsUInt32); } else if (property.isString()) { Structure& structure = *base->structure(vm); if (JSCell::canUseFastGetOwnProperty(structure)) { if (AtomicStringImpl* existingAtomicString = asString(property)->toExistingAtomicString(exec)) { if (JSValue result = base->fastGetOwnProperty(vm, structure, existingAtomicString)) return JSValue::encode(result); } } } } PropertyName propertyName = property.toPropertyKey(exec); return JSValue::encode(baseValue.get(exec, propertyName)); }
void JSGlobalData::storeVPtrs() { // Enough storage to fit a JSArray, JSByteArray, JSString, or JSFunction. // COMPILE_ASSERTS below check that this is true. char storage[64]; COMPILE_ASSERT(sizeof(JSFinalObject) <= sizeof(storage), sizeof_JSFinalObject_must_be_less_than_storage); JSCell* jsFinalObject = new (storage) JSFinalObject(JSFinalObject::VPtrStealingHack); CLOBBER_MEMORY(); JSGlobalData::jsFinalObjectVPtr = jsFinalObject->vptr(); COMPILE_ASSERT(sizeof(JSArray) <= sizeof(storage), sizeof_JSArray_must_be_less_than_storage); JSCell* jsArray = new (storage) JSArray(JSArray::VPtrStealingHack); CLOBBER_MEMORY(); JSGlobalData::jsArrayVPtr = jsArray->vptr(); COMPILE_ASSERT(sizeof(JSByteArray) <= sizeof(storage), sizeof_JSByteArray_must_be_less_than_storage); JSCell* jsByteArray = new (storage) JSByteArray(JSByteArray::VPtrStealingHack); CLOBBER_MEMORY(); JSGlobalData::jsByteArrayVPtr = jsByteArray->vptr(); COMPILE_ASSERT(sizeof(JSString) <= sizeof(storage), sizeof_JSString_must_be_less_than_storage); JSCell* jsString = new (storage) JSString(JSString::VPtrStealingHack); CLOBBER_MEMORY(); JSGlobalData::jsStringVPtr = jsString->vptr(); COMPILE_ASSERT(sizeof(JSFunction) <= sizeof(storage), sizeof_JSFunction_must_be_less_than_storage); JSCell* jsFunction = new (storage) JSFunction(JSCell::VPtrStealingHack); CLOBBER_MEMORY(); JSGlobalData::jsFunctionVPtr = jsFunction->vptr(); }
EncodedJSValue DFG_OPERATION operationGetByVal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) { JSGlobalData* globalData = &exec->globalData(); NativeCallFrameTracer tracer(globalData, exec); JSValue baseValue = JSValue::decode(encodedBase); JSValue property = JSValue::decode(encodedProperty); if (LIKELY(baseValue.isCell())) { JSCell* base = baseValue.asCell(); if (property.isUInt32()) { return getByVal(exec, base, property.asUInt32()); } else if (property.isDouble()) { double propertyAsDouble = property.asDouble(); uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble); if (propertyAsUInt32 == propertyAsDouble) return getByVal(exec, base, propertyAsUInt32); } else if (property.isString()) { if (JSValue result = base->fastGetOwnProperty(exec, asString(property)->value(exec))) return JSValue::encode(result); } } Identifier ident(exec, property.toString(exec)->value(exec)); return JSValue::encode(baseValue.get(exec, ident)); }
MarkedBlock::FreeList MarkedBlock::specializedSweep() { ASSERT(blockState != Allocated && blockState != FreeListed); ASSERT(destructorCallNeeded || sweepMode != SweepOnly); // This produces a free list that is ordered in reverse through the block. // This is fine, since the allocation code makes no assumptions about the // order of the free list. FreeCell* head = 0; size_t count = 0; for (size_t i = firstAtom(); i < m_endAtom; i += m_atomsPerCell) { if (blockState == Marked && m_marks.get(i)) continue; JSCell* cell = reinterpret_cast_ptr<JSCell*>(&atoms()[i]); if (blockState == Zapped && !cell->isZapped()) continue; if (destructorCallNeeded && blockState != New) callDestructor(cell); if (sweepMode == SweepToFreeList) { FreeCell* freeCell = reinterpret_cast<FreeCell*>(cell); freeCell->next = head; head = freeCell; ++count; } } m_state = ((sweepMode == SweepToFreeList) ? FreeListed : Zapped); return FreeList(head, count * cellSize()); }
void JSGlobalData::releaseExecutableMemory() { if (dynamicGlobalObject) { StackPreservingRecompiler recompiler; HashSet<JSCell*> roots; heap.getConservativeRegisterRoots(roots); HashSet<JSCell*>::iterator end = roots.end(); for (HashSet<JSCell*>::iterator ptr = roots.begin(); ptr != end; ++ptr) { ScriptExecutable* executable = 0; JSCell* cell = *ptr; if (cell->inherits(&ScriptExecutable::s_info)) executable = static_cast<ScriptExecutable*>(*ptr); else if (cell->inherits(&JSFunction::s_info)) { JSFunction* function = jsCast<JSFunction*>(*ptr); if (function->isHostFunction()) continue; executable = function->jsExecutable(); } else continue; ASSERT(executable->inherits(&ScriptExecutable::s_info)); executable->unlinkCalls(); if (executable->inherits(&FunctionExecutable::s_info)) recompiler.currentlyExecutingFunctions.add(static_cast<FunctionExecutable*>(executable)); } heap.objectSpace().forEachCell<StackPreservingRecompiler>(recompiler); } m_regExpCache->invalidateCode(); heap.collectAllGarbage(); }
void SlotVisitor::appendJSCellOrAuxiliary(HeapCell* heapCell) { if (!heapCell) return; ASSERT(!m_isCheckingForDefaultMarkViolation); if (Heap::testAndSetMarked(m_markingVersion, heapCell)) return; switch (heapCell->cellKind()) { case HeapCell::JSCell: { JSCell* jsCell = static_cast<JSCell*>(heapCell); if (!jsCell->structure()) { ASSERT_NOT_REACHED(); return; } jsCell->setCellState(CellState::Grey); appendToMarkStack(jsCell); return; } case HeapCell::Auxiliary: { noteLiveAuxiliaryCell(heapCell); return; } } }
void VM::releaseExecutableMemory() { prepareToDiscardCode(); if (entryScope) { StackPreservingRecompiler recompiler; HeapIterationScope iterationScope(heap); HashSet<JSCell*> roots; heap.getConservativeRegisterRoots(roots); HashSet<JSCell*>::iterator end = roots.end(); for (HashSet<JSCell*>::iterator ptr = roots.begin(); ptr != end; ++ptr) { ScriptExecutable* executable = 0; JSCell* cell = *ptr; if (cell->inherits(ScriptExecutable::info())) executable = static_cast<ScriptExecutable*>(*ptr); else if (cell->inherits(JSFunction::info())) { JSFunction* function = jsCast<JSFunction*>(*ptr); if (function->isHostFunction()) continue; executable = function->jsExecutable(); } else continue; ASSERT(executable->inherits(ScriptExecutable::info())); executable->unlinkCalls(); if (executable->inherits(FunctionExecutable::info())) recompiler.currentlyExecutingFunctions.add(static_cast<FunctionExecutable*>(executable)); } heap.objectSpace().forEachLiveCell<StackPreservingRecompiler>(iterationScope, recompiler); } m_regExpCache->invalidateCode(); heap.collectAllGarbage(); }
void InspectorHeapAgent::getRemoteObject(ErrorString& errorString, int heapObjectId, const String* optionalObjectGroup, RefPtr<Inspector::Protocol::Runtime::RemoteObject>& result) { // Prevent the cell from getting collected as we look it up. VM& vm = m_environment.vm(); JSLockHolder lock(vm); DeferGC deferGC(vm.heap); unsigned heapObjectIdentifier = static_cast<unsigned>(heapObjectId); const Optional<HeapSnapshotNode> optionalNode = nodeForHeapObjectIdentifier(errorString, heapObjectIdentifier); if (!optionalNode) return; JSCell* cell = optionalNode->cell; Structure* structure = cell->structure(m_environment.vm()); if (!structure) { errorString = ASCIILiteral("Unable to get object details"); return; } JSGlobalObject* globalObject = structure->globalObject(); if (!globalObject) { errorString = ASCIILiteral("Unable to get object details"); return; } InjectedScript injectedScript = m_injectedScriptManager.injectedScriptFor(globalObject->globalExec()); if (injectedScript.hasNoValue()) { errorString = ASCIILiteral("Unable to get object details - InjectedScript"); return; } Deprecated::ScriptValue cellScriptValue(m_environment.vm(), JSValue(cell)); String objectGroup = optionalObjectGroup ? *optionalObjectGroup : String(); result = injectedScript.wrapObject(cellScriptValue, objectGroup, true); }
bool JSObjectIsFunction(JSContextRef, JSObjectRef object) { if (!object) return false; CallData callData; JSCell* cell = toJS(object); return cell->methodTable()->getCallData(cell, callData) != CallTypeNone; }
std::unique_ptr<PolyProtoAccessChain> PolyProtoAccessChain::create(JSGlobalObject* globalObject, JSCell* base, JSObject* target, bool& usesPolyProto) { JSCell* current = base; VM& vm = *base->vm(); bool found = false; usesPolyProto = false; std::unique_ptr<PolyProtoAccessChain> result(new PolyProtoAccessChain()); for (unsigned iterationNumber = 0; true; ++iterationNumber) { Structure* structure = current->structure(vm); if (!structure->propertyAccessesAreCacheable()) return nullptr; if (structure->isProxy()) return nullptr; if (structure->isDictionary()) { ASSERT(structure->isObject()); if (structure->hasBeenFlattenedBefore()) return nullptr; structure->flattenDictionaryStructure(vm, asObject(current)); } // To save memory, we don't include the base in the chain. We let // AccessCase provide the base to us as needed. if (iterationNumber) result->m_chain.append(structure); else RELEASE_ASSERT(current == base); if (current == target) { found = true; break; } // We only have poly proto if we need to access our prototype via // the poly proto protocol. If the slot base is the only poly proto // thing in the chain, and we have a cache hit on it, then we're not // poly proto. usesPolyProto |= structure->hasPolyProto(); JSValue prototype = structure->prototypeForLookup(globalObject, current); if (prototype.isNull()) break; current = asObject(prototype); } if (!found && !!target) return nullptr; return result; }
bool JSObjectIsFunction(JSContextRef ctx, JSObjectRef object) { if (!object) return false; JSLockHolder locker(toJS(ctx)); CallData callData; JSCell* cell = toJS(object); return cell->methodTable()->getCallData(cell, callData) != CallType::None; }
void SamplingProfiler::processUnverifiedStackTraces() { // This function needs to be called from the JSC execution thread. RELEASE_ASSERT(m_lock.isLocked()); TinyBloomFilter filter = m_vm.heap.objectSpace().blocks().filter(); MarkedBlockSet& markedBlockSet = m_vm.heap.objectSpace().blocks(); for (unsigned i = m_indexOfNextStackTraceToVerify; i < m_stackTraces.size(); i++) { StackTrace& stackTrace = m_stackTraces[i]; if (!stackTrace.needsVerification) continue; stackTrace.needsVerification = false; for (StackFrame& stackFrame : stackTrace.frames) { if (stackFrame.frameType != FrameType::UnverifiedCallee) { RELEASE_ASSERT(stackFrame.frameType == FrameType::VerifiedExecutable); continue; } JSValue callee = JSValue::decode(stackFrame.u.unverifiedCallee); if (!Heap::isValueGCObject(filter, markedBlockSet, callee)) { stackFrame.frameType = FrameType::Unknown; continue; } JSCell* calleeCell = callee.asCell(); auto frameTypeFromCallData = [&] () -> FrameType { FrameType result = FrameType::Unknown; CallData callData; CallType callType; callType = getCallData(calleeCell, callData); if (callType == CallTypeHost) result = FrameType::Host; return result; }; if (calleeCell->type() != JSFunctionType) { stackFrame.frameType = frameTypeFromCallData(); continue; } ExecutableBase* executable = static_cast<JSFunction*>(calleeCell)->executable(); if (!executable) { stackFrame.frameType = frameTypeFromCallData(); continue; } RELEASE_ASSERT(Heap::isPointerGCObject(filter, markedBlockSet, executable)); stackFrame.frameType = FrameType::VerifiedExecutable; stackFrame.u.verifiedExecutable = executable; m_seenExecutables.add(executable); } } m_indexOfNextStackTraceToVerify = m_stackTraces.size(); }
bool JSObjectIsFunction(JSContextRef ctx, JSObjectRef object) { if (!object) return false; ExecState* exec = toJS(ctx); VM& vm = exec->vm(); JSLockHolder locker(vm); CallData callData; JSCell* cell = toJS(object); return cell->methodTable(vm)->getCallData(cell, callData) != CallType::None; }
void JSGlobalData::storeVPtrs() { CollectorCell cell; void* storage = &cell; COMPILE_ASSERT(sizeof(JSArray) <= sizeof(CollectorCell), sizeof_JSArray_must_be_less_than_CollectorCell); JSCell* jsArray = new (storage) JSArray(JSArray::createStructure(jsNull())); JSGlobalData::jsArrayVPtr = jsArray->vptr(); jsArray->~JSCell(); COMPILE_ASSERT(sizeof(JSByteArray) <= sizeof(CollectorCell), sizeof_JSByteArray_must_be_less_than_CollectorCell); JSCell* jsByteArray = new (storage) JSByteArray(JSByteArray::VPtrStealingHack); JSGlobalData::jsByteArrayVPtr = jsByteArray->vptr(); jsByteArray->~JSCell(); COMPILE_ASSERT(sizeof(JSString) <= sizeof(CollectorCell), sizeof_JSString_must_be_less_than_CollectorCell); JSCell* jsString = new (storage) JSString(JSString::VPtrStealingHack); JSGlobalData::jsStringVPtr = jsString->vptr(); jsString->~JSCell(); COMPILE_ASSERT(sizeof(JSFunction) <= sizeof(CollectorCell), sizeof_JSFunction_must_be_less_than_CollectorCell); JSCell* jsFunction = new (storage) JSFunction(JSFunction::createStructure(jsNull())); JSGlobalData::jsFunctionVPtr = jsFunction->vptr(); jsFunction->~JSCell(); }
void InspectorHeapAgent::getPreview(ErrorString& errorString, int heapObjectId, Inspector::Protocol::OptOutput<String>* resultString, RefPtr<Inspector::Protocol::Debugger::FunctionDetails>& functionDetails, RefPtr<Inspector::Protocol::Runtime::ObjectPreview>& objectPreview) { // Prevent the cell from getting collected as we look it up. VM& vm = m_environment.vm(); JSLockHolder lock(vm); DeferGC deferGC(vm.heap); unsigned heapObjectIdentifier = static_cast<unsigned>(heapObjectId); const Optional<HeapSnapshotNode> optionalNode = nodeForHeapObjectIdentifier(errorString, heapObjectIdentifier); if (!optionalNode) return; // String preview. JSCell* cell = optionalNode->cell; if (cell->isString()) { *resultString = cell->getString(nullptr); return; } // FIXME: Provide preview information for Internal Objects? CodeBlock, Executable, etc. Structure* structure = cell->structure(m_environment.vm()); if (!structure) { errorString = ASCIILiteral("Unable to get object details - Structure"); return; } JSGlobalObject* globalObject = structure->globalObject(); if (!globalObject) { errorString = ASCIILiteral("Unable to get object details - GlobalObject"); return; } InjectedScript injectedScript = m_injectedScriptManager.injectedScriptFor(globalObject->globalExec()); if (injectedScript.hasNoValue()) { errorString = ASCIILiteral("Unable to get object details - InjectedScript"); return; } // Function preview. if (cell->inherits(JSFunction::info())) { Deprecated::ScriptValue functionScriptValue(m_environment.vm(), JSValue(cell)); injectedScript.functionDetails(errorString, functionScriptValue, &functionDetails); return; } // Object preview. Deprecated::ScriptValue cellScriptValue(m_environment.vm(), JSValue(cell)); objectPreview = injectedScript.previewValue(cellScriptValue); }
void JSGlobalData::storeVPtrs() { // Enough storage to fit a JSArray, JSByteArray, JSString, or JSFunction. // COMPILE_ASSERTS below check that this is true. char storage[64]; COMPILE_ASSERT(sizeof(JSArray) <= sizeof(storage), sizeof_JSArray_must_be_less_than_storage); JSCell* jsArray = new (storage) JSArray(JSArray::VPtrStealingHack); JSGlobalData::jsArrayVPtr = jsArray->vptr(); jsArray->~JSCell(); COMPILE_ASSERT(sizeof(JSByteArray) <= sizeof(storage), sizeof_JSByteArray_must_be_less_than_storage); JSCell* jsByteArray = new (storage) JSByteArray(JSByteArray::VPtrStealingHack); JSGlobalData::jsByteArrayVPtr = jsByteArray->vptr(); jsByteArray->~JSCell(); COMPILE_ASSERT(sizeof(JSString) <= sizeof(storage), sizeof_JSString_must_be_less_than_storage); JSCell* jsString = new (storage) JSString(JSString::VPtrStealingHack); JSGlobalData::jsStringVPtr = jsString->vptr(); jsString->~JSCell(); COMPILE_ASSERT(sizeof(JSFunction) <= sizeof(storage), sizeof_JSFunction_must_be_less_than_storage); char executableStorage[sizeof(VPtrHackExecutable)]; RefPtr<Structure> executableStructure = Structure::create(Structure::VPtrStealingHack, 0); JSCell* executable = new (executableStorage) VPtrHackExecutable(executableStructure.get()); JSCell* jsFunction = new (storage) JSFunction(Structure::create(Structure::VPtrStealingHack, &JSFunction::s_info), static_cast<VPtrHackExecutable*>(executable)); JSGlobalData::jsFunctionVPtr = jsFunction->vptr(); executable->~JSCell(); jsFunction->~JSCell(); }
void JSGlobalData::storeVPtrs() { // Enough storage to fit a JSArray, JSByteArray, JSString, or JSFunction. // COMPILE_ASSERTS below check that this is true. // -----------Instrumentation----------- // char storage[128]; // changed from 64 to fit JSLabel // ------------------------------------- // COMPILE_ASSERT(sizeof(JSArray) <= sizeof(storage), sizeof_JSArray_must_be_less_than_storage); JSCell* jsArray = new (storage) JSArray(JSArray::VPtrStealingHack); CLOBBER_MEMORY(); JSGlobalData::jsArrayVPtr = jsArray->vptr(); COMPILE_ASSERT(sizeof(JSByteArray) <= sizeof(storage), sizeof_JSByteArray_must_be_less_than_storage); JSCell* jsByteArray = new (storage) JSByteArray(JSByteArray::VPtrStealingHack); CLOBBER_MEMORY(); JSGlobalData::jsByteArrayVPtr = jsByteArray->vptr(); COMPILE_ASSERT(sizeof(JSString) <= sizeof(storage), sizeof_JSString_must_be_less_than_storage); JSCell* jsString = new (storage) JSString(JSString::VPtrStealingHack); CLOBBER_MEMORY(); JSGlobalData::jsStringVPtr = jsString->vptr(); COMPILE_ASSERT(sizeof(JSFunction) <= sizeof(storage), sizeof_JSFunction_must_be_less_than_storage); JSCell* jsFunction = new (storage) JSFunction(JSCell::VPtrStealingHack); CLOBBER_MEMORY(); JSGlobalData::jsFunctionVPtr = jsFunction->vptr(); }
void MarkStack::drain() { #if !ASSERT_DISABLED ASSERT(!m_isDraining); m_isDraining = true; #endif while (!m_markSets.isEmpty() || !m_values.isEmpty()) { while (!m_markSets.isEmpty() && m_values.size() < 50) { ASSERT(!m_markSets.isEmpty()); MarkSet& current = m_markSets.last(); ASSERT(current.m_values); JSValue* end = current.m_end; ASSERT(current.m_values); ASSERT(current.m_values != end); findNextUnmarkedNullValue: ASSERT(current.m_values != end); JSValue value = *current.m_values; current.m_values++; JSCell* cell; if (!value || !value.isCell() || Heap::testAndSetMarked(cell = value.asCell())) { if (current.m_values == end) { m_markSets.removeLast(); continue; } goto findNextUnmarkedNullValue; } if (cell->structure()->typeInfo().type() < CompoundType) { cell->JSCell::visitChildren(*this); if (current.m_values == end) { m_markSets.removeLast(); continue; } goto findNextUnmarkedNullValue; } if (current.m_values == end) m_markSets.removeLast(); visitChildren(cell); } while (!m_values.isEmpty()) visitChildren(m_values.removeLast()); } #if !ASSERT_DISABLED m_isDraining = false; #endif }
bool HandleHeap::isValidWeakNode(Node* node) { if (!isLiveNode(node)) return false; if (!node->isWeak()) return false; JSValue value = *node->slot(); if (!value || !value.isCell()) return false; JSCell* cell = value.asCell(); if (!cell || !cell->structure()) return false; return true; }
void MarkStack::validateValue(JSValue value) { if (!value) CRASH(); if (!value.isCell()) return; JSCell* cell = value.asCell(); if (!cell) CRASH(); if (!cell->structure()) CRASH(); // Both the cell's structure, and the cell's structure's structure should be the Structure Structure. // I hate this sentence. if (cell->structure()->structure()->JSCell::classInfo() != cell->structure()->JSCell::classInfo()) CRASH(); }
bool HandleHeap::isValidWeakNode(Node* node) { if (!node->isWeak()) return false; JSValue value = *node->slot(); if (!value || !value.isCell()) return false; JSCell* cell = value.asCell(); if (!cell || !cell->structure()) return false; #if ENABLE(JSC_ZOMBIES) if (cell->isZombie()) return false; #endif return true; }
void DOMGCOutputConstraint::executeImpl(SlotVisitor& visitor) { Heap& heap = m_vm.heap; if (heap.mutatorExecutionVersion() == m_lastExecutionVersion) return; m_lastExecutionVersion = heap.mutatorExecutionVersion(); m_clientData.forEachOutputConstraintSpace( [&] (Subspace& subspace) { auto func = [] (SlotVisitor& visitor, HeapCell* heapCell, HeapCell::Kind) { SetRootMarkReasonScope rootScope(visitor, SlotVisitor::RootMarkReason::DOMGCOutput); JSCell* cell = static_cast<JSCell*>(heapCell); cell->methodTable(visitor.vm())->visitOutputConstraints(cell, visitor); }; visitor.addParallelConstraintTask(subspace.forEachMarkedCellInParallel(func)); }); }
ALWAYS_INLINE void SlotVisitor::internalAppend(JSValue* slot) { // This internalAppend is only intended for visits to object and array backing stores. // as it can change the JSValue pointed to be the argument when the original JSValue // is a string that contains the same contents as another string. StackStats::probe(); ASSERT(slot); JSValue value = *slot; ASSERT(value); if (!value.isCell()) return; JSCell* cell = value.asCell(); if (!cell) return; validate(cell); if (m_shouldHashCons && cell->isString()) { JSString* string = jsCast<JSString*>(cell); if (string->shouldTryHashCons() && string->tryHashConsLock()) { UniqueStringMap::AddResult addResult = m_uniqueStrings.add(string->string().impl(), value); if (addResult.isNewEntry) string->setHashConsSingleton(); else { JSValue existingJSValue = addResult.iterator->value; if (value != existingJSValue) jsCast<JSString*>(existingJSValue.asCell())->clearHashConsSingleton(); *slot = existingJSValue; string->releaseHashConsLock(); return; } string->releaseHashConsLock(); } } internalAppend(cell); }
EncodedJSValue operationGetByVal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) { JSValue baseValue = JSValue::decode(encodedBase); JSValue property = JSValue::decode(encodedProperty); if (LIKELY(baseValue.isCell())) { JSCell* base = baseValue.asCell(); if (property.isUInt32()) { JSGlobalData* globalData = &exec->globalData(); uint32_t i = property.asUInt32(); // FIXME: the JIT used to handle these in compiled code! if (isJSArray(globalData, base) && asArray(base)->canGetIndex(i)) return JSValue::encode(asArray(base)->getIndex(i)); // FIXME: the JITstub used to relink this to an optimized form! if (isJSString(globalData, base) && asString(base)->canGetIndex(i)) return JSValue::encode(asString(base)->getIndex(exec, i)); // FIXME: the JITstub used to relink this to an optimized form! if (isJSByteArray(globalData, base) && asByteArray(base)->canAccessIndex(i)) return JSValue::encode(asByteArray(base)->getIndex(exec, i)); return JSValue::encode(baseValue.get(exec, i)); } if (property.isString()) { Identifier propertyName(exec, asString(property)->value(exec)); PropertySlot slot(base); if (base->fastGetOwnPropertySlot(exec, propertyName, slot)) return JSValue::encode(slot.getValue(exec, propertyName)); } } Identifier ident(exec, property.toString(exec)); return JSValue::encode(baseValue.get(exec, ident)); }
VPtrSet::VPtrSet() { // Bizarrely, calling fastMalloc here is faster than allocating space on the stack. void* storage = fastMalloc(sizeof(CollectorBlock)); JSCell* jsArray = new (storage) JSArray(JSArray::createStructure(jsNull())); jsArrayVPtr = jsArray->vptr(); jsArray->~JSCell(); JSCell* jsByteArray = new (storage) JSByteArray(JSByteArray::VPtrStealingHack); jsByteArrayVPtr = jsByteArray->vptr(); jsByteArray->~JSCell(); JSCell* jsString = new (storage) JSString(JSString::VPtrStealingHack); jsStringVPtr = jsString->vptr(); jsString->~JSCell(); JSCell* jsFunction = new (storage) JSFunction(JSFunction::createStructure(jsNull())); jsFunctionVPtr = jsFunction->vptr(); jsFunction->~JSCell(); fastFree(storage); }
InferredType::Descriptor InferredType::Descriptor::forValue(JSValue value) { if (value.isBoolean()) return Boolean; if (value.isUndefinedOrNull()) return Other; if (value.isInt32()) return Int32; if (value.isNumber()) return Number; if (value.isCell()) { JSCell* cell = value.asCell(); if (cell->isString()) return String; if (cell->isSymbol()) return Symbol; if (cell->isObject()) { if (cell->structure()->transitionWatchpointSetIsStillValid()) return Descriptor(ObjectWithStructure, cell->structure()); return Object; } } return Top; }