Example #1
0
Arguments* StackVisitor::Frame::arguments()
{
    ASSERT(m_callFrame);
    CallFrame* physicalFrame = m_callFrame;
    VM& vm = physicalFrame->vm();
    Arguments* arguments;
#if ENABLE(DFG_JIT)
    if (isInlinedFrame()) {
        ASSERT(m_inlineCallFrame);
        arguments = Arguments::create(vm, physicalFrame, m_inlineCallFrame);
        arguments->tearOff(physicalFrame, m_inlineCallFrame);
    } else 
#endif
    {
        arguments = Arguments::create(vm, physicalFrame);
        arguments->tearOff(physicalFrame);
    }
    return arguments;
}
Example #2
0
PassRefPtr<ScriptCallStack> createScriptCallStack(JSC::ExecState* exec, size_t maxStackSize, bool emptyIsAllowed)
{
    Vector<ScriptCallFrame> frames;

    if (exec) {
        CallFrame* frame = exec->vm().topCallFrame;
        CreateScriptCallStackFunctor functor(false, frames, maxStackSize);
        frame->iterate(functor);
    }

    if (frames.isEmpty() && !emptyIsAllowed) {
        // No frames found. It may happen in the case where
        // a bound function is called from native code for example.
        // Fallback to setting lineNumber to 0, and source and function name to "undefined".
        frames.append(ScriptCallFrame(ASCIILiteral("undefined"), ASCIILiteral("undefined"), 0, 0));
    }

    return ScriptCallStack::create(frames);
}
PassRefPtr<ScriptCallStack> createScriptCallStack(size_t maxStackSize, bool emptyIsAllowed)
{
    Vector<ScriptCallFrame> frames;
    if (JSC::ExecState* exec = JSMainThreadExecState::currentState()) {
        CallFrame* frame = exec->vm().topCallFrame;
        for (StackIterator iter = frame->begin(); iter != frame->end() && maxStackSize--; ++iter) {
            unsigned line;
            unsigned column;
            iter->computeLineAndColumn(line, column);
            frames.append(ScriptCallFrame(iter->functionName(), iter->sourceURL(), line, column));
        }
    }
    if (frames.isEmpty() && !emptyIsAllowed) {
        // No frames found. It may happen in the case where
        // a bound function is called from native code for example.
        // Fallback to setting lineNumber to 0, and source and function name to "undefined".
        frames.append(ScriptCallFrame("undefined", "undefined", 0, 0));
    }
    return ScriptCallStack::create(frames);
}
Example #4
0
JSValue evaluateInGlobalCallFrame(const String& script, JSValue& exception, JSGlobalObject* globalObject)
{
    CallFrame* globalCallFrame = globalObject->globalExec();
    VM& vm = globalObject->vm();

    EvalExecutable* eval = EvalExecutable::create(globalCallFrame, makeSource(script), false);
    if (!eval) {
        exception = vm.exception;
        vm.exception = JSValue();
        return exception;
    }

    JSValue result = vm.interpreter->execute(eval, globalCallFrame, globalObject, globalCallFrame->scope());
    if (vm.exception) {
        exception = vm.exception;
        vm.exception = JSValue();
    }
    ASSERT(result);
    return result;
}
Example #5
0
  CallFrame* VM::get_variables_frame(ssize_t up) {
    CallFrame* frame = call_frame_;

    while(frame && up-- > 0) {
      frame = frame->previous;
    }

    while(frame) {
      if(!frame->is_inline_block()
          && !frame->native_method_p()
          && frame->scope)
      {
        return frame;
      }

      frame = frame->previous;
    }

    return NULL;
  }
PassRefPtr<ScriptCallStack> createScriptCallStack(JSC::ExecState* exec, size_t maxStackSize)
{
    Vector<ScriptCallFrame> frames;
    ASSERT(exec);
    CallFrame* frame = exec->vm().topCallFrame;
    StackIterator iter = frame->begin();
    if (iter.numberOfFrames() > 1)
        ++iter;
    for (; iter != frame->end() && maxStackSize--; ++iter) {
        // This early exit is necessary to maintain our old behaviour
        // but the stack trace we produce now is complete and handles all
        // ways in which code may be running
        if (!iter->callee() && frames.size())
            break;
        unsigned line;
        unsigned column;
        iter->computeLineAndColumn(line, column);
        frames.append(ScriptCallFrame(iter->functionName(), iter->sourceURL(), line, column));
    }
    return ScriptCallStack::create(frames);
}
Example #7
0
JSValue JSActivation::argumentsGetter(ExecState* exec, const Identifier&, const PropertySlot& slot)
{
    JSActivation* activation = asActivation(slot.slotBase());

    if (activation->d()->functionExecutable->usesArguments()) {
        PropertySlot slot;
        activation->symbolTableGet(exec->propertyNames().arguments, slot);
        return slot.getValue(exec, exec->propertyNames().arguments);
    }

    CallFrame* callFrame = CallFrame::create(activation->d()->registers);
    Arguments* arguments = callFrame->optionalCalleeArguments();
    if (!arguments) {
        arguments = new (callFrame) Arguments(callFrame);
        arguments->copyRegisters();
        callFrame->setCalleeArguments(arguments);
    }
    ASSERT(arguments->inherits(&Arguments::info));

    return arguments;
}
Ref<ScriptCallStack> createScriptCallStackForConsole(JSC::ExecState* exec, size_t maxStackSize)
{
    if (!exec)
        return ScriptCallStack::create();

    JSLockHolder locker(exec);
    Vector<ScriptCallFrame> frames;

    CallFrame* frame = exec->vm().topCallFrame;
    if (!frame)
        return ScriptCallStack::create();
    CreateScriptCallStackFunctor functor(true, frames, maxStackSize);
    frame->iterate(functor);

    if (frames.isEmpty()) {
        CreateScriptCallStackFunctor functor(false, frames, maxStackSize);
        frame->iterate(functor);
    }

    return ScriptCallStack::create(frames);
}
Example #9
0
	void ScriptCallStack::fillFrames()
	{
		if (m_filled || !m_caller)
			return;
		
		/*
		AJValue function = m_exec->interpreter()->retrieveCaller(m_exec, m_caller);
		while (!function.isNull()) {
			InternalFunction* internal = asInternalFunction(function);
			m_frames.append(ScriptCallFrame(internal->name(m_exec), UString(), 0, ArgList(), 0));
			function = m_exec->interpreter()->retrieveCaller(m_exec, internal);
		}*/
		CallFrame* callFrame = m_exec->callerFrame();
		
		while(callFrame) {
			UString functionName;
			int tmpLineNO;
			intptr_t sourceID;
			UString urlString;
			AJValue function;
			
			m_exec->interpreter()->retrieveLastCaller(callFrame, tmpLineNO, sourceID, urlString, function);
			
			if (function) {
				functionName = asInternalFunction(function)->name(m_exec);
			} else {
				if (!m_frames.isEmpty())
					break;
			}
			
			unsigned lineNO = tmpLineNO >= 0 ? tmpLineNO : 0;
			m_frames.append(ScriptCallFrame(functionName, urlString, lineNO, ArgList(), 0));
			
			if (!function)
				break;
			callFrame = callFrame->callerFrame();
		}
		
		m_filled = true;
	}
void JSActivation::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
    JSActivation* thisObject = jsCast<JSActivation*>(object);

    CallFrame* callFrame = CallFrame::create(reinterpret_cast<Register*>(thisObject->m_registers));
    if (mode == IncludeDontEnumProperties && !thisObject->isTornOff() && (callFrame->codeBlock()->usesArguments() || callFrame->codeBlock()->usesEval()))
        propertyNames.add(exec->propertyNames().arguments);

    {
        ConcurrentJITLocker locker(thisObject->symbolTable()->m_lock);
        SymbolTable::Map::iterator end = thisObject->symbolTable()->end(locker);
        for (SymbolTable::Map::iterator it = thisObject->symbolTable()->begin(locker); it != end; ++it) {
            if (it->value.getAttributes() & DontEnum && mode != IncludeDontEnumProperties)
                continue;
            if (!thisObject->isValid(it->value))
                continue;
            propertyNames.add(Identifier(exec, it->key.get()));
        }
    }
    // Skip the JSVariableObject implementation of getOwnNonIndexPropertyNames
    JSObject::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode);
}
Example #11
0
void StackIterator::readInlinedFrame(CallFrame* callFrame, CodeOrigin* codeOrigin)
{
    ASSERT(codeOrigin);
    ASSERT(!callFrame->hasHostCallFrameFlag());

    unsigned frameOffset = inlinedFrameOffset(codeOrigin);
    bool isInlined = !!frameOffset;
    if (isInlined) {
        InlineCallFrame* inlineCallFrame = codeOrigin->inlineCallFrame;

        m_frame.m_callFrame = callFrame;
        m_frame.m_inlineCallFrame = inlineCallFrame;
        m_frame.m_argumentCountIncludingThis = inlineCallFrame->arguments.size();
        m_frame.m_codeBlock = inlineCallFrame->baselineCodeBlock();
        m_frame.m_bytecodeOffset = codeOrigin->bytecodeIndex;

        JSFunction* callee = inlineCallFrame->callee.get();
        if (callee) {
            m_frame.m_scope = callee->scope();
            m_frame.m_callee = callee;
        } else {
            CallFrame* inlinedFrame = callFrame + frameOffset;
            m_frame.m_scope = inlinedFrame->scope();
            m_frame.m_callee = inlinedFrame->callee();
        }
        ASSERT(m_frame.scope());
        ASSERT(m_frame.callee());

        // The callerFrame just needs to be non-null to indicate that we
        // haven't reached the last frame yet. Setting it to the root
        // frame (i.e. the callFrame that this inlined frame is called from)
        // would work just fine.
        m_frame.m_callerFrame = callFrame;
        return;
    }

    readNonInlinedFrame(callFrame, codeOrigin);
}
void ScriptCallStack::initialize()
{
    if (!m_caller || m_initialized)
        return;

    int signedLineNumber;
    intptr_t sourceID;
    UString urlString;
    JSValue function;
    // callFrame must exist if m_caller is not null.
    CallFrame* callFrame = m_exec->callerFrame();
    while (true) {
        ASSERT(callFrame);
        m_exec->interpreter()->retrieveLastCaller(callFrame, signedLineNumber, sourceID, urlString, function);
        if (!function)
            break;
        JSFunction* jsFunction = asFunction(function);
        unsigned lineNumber = signedLineNumber >= 0 ? signedLineNumber : 0;
        m_frames.append(ScriptCallFrame(jsFunction->name(m_exec), urlString, lineNumber, m_exec, 0));
        callFrame = callFrame->callerFrame();
    }
    m_initialized = true;
}
Example #13
0
  void LLVMState::compile_callframe(STATE, CompiledMethod* start, CallFrame* call_frame,
                                    int primitive) {

    if(debug_search) {
      std::cout << std::endl << "JIT:       triggered: "
            << enclosure_name(start) << "#"
            << symbol_debug_str(start->name()) << std::endl;
    }

    // if(config().jit_inline_debug) {
      // if(start) {
        // std::cout << "JIT: target search from "
          // << symbol_debug_str(start->name()) << "\n";
      // } else {
        // std::cout << "JIT: target search from primitive\n";
      // }
    // }

    CallFrame* candidate = find_candidate(state, start, call_frame);
    if(!candidate || candidate->jitted_p() || candidate->inline_method_p()) {
      if(debug_search) {
        std::cout << "JIT: invalid candidate returned" << std::endl;
      }

      return;
    }

    if(debug_search) {
      std::cout << "! ";
      candidate->print_backtrace(state, 1);
    }

    if(start && candidate->cm != start) {
      start->backend_method()->call_count = 0;
    }

    if(candidate->cm->backend_method()->call_count <= 1) {
      if(!start || start->backend_method()->jitted()) return;
      // Ignore it. compile this one.
      candidate = call_frame;
    }

    if(candidate->block_p()) {
      compile_soon(state, candidate->cm, candidate->block_env(), true);
    } else {
      if(candidate->cm->can_specialize_p()) {
        compile_soon(state, candidate->cm, candidate->self()->class_object(state));
      } else {
        compile_soon(state, candidate->cm, cNil);
      }
    }
  }
Example #14
0
// Evaluate some JavaScript code in the scope of this frame.
JSValue DebuggerCallFrame::evaluate(const String& script, NakedPtr<Exception>& exception)
{
    ASSERT(isValid());
    CallFrame* callFrame = m_callFrame;
    if (!callFrame)
        return jsNull();

    JSLockHolder lock(callFrame);

    if (!callFrame->codeBlock())
        return JSValue();
    
    DebuggerEvalEnabler evalEnabler(callFrame);
    VM& vm = callFrame->vm();
    auto& codeBlock = *callFrame->codeBlock();
    ThisTDZMode thisTDZMode = codeBlock.unlinkedCodeBlock()->constructorKind() == ConstructorKind::Derived ? ThisTDZMode::AlwaysCheck : ThisTDZMode::CheckIfNeeded;

    VariableEnvironment variablesUnderTDZ;
    JSScope::collectVariablesUnderTDZ(scope()->jsScope(), variablesUnderTDZ);

    EvalExecutable* eval = EvalExecutable::create(callFrame, makeSource(script), codeBlock.isStrictMode(), thisTDZMode, codeBlock.unlinkedCodeBlock()->isDerivedConstructorContext(), codeBlock.unlinkedCodeBlock()->isArrowFunction(), &variablesUnderTDZ);
    if (vm.exception()) {
        exception = vm.exception();
        vm.clearException();
        return jsUndefined();
    }

    JSValue thisValue = thisValueForCallFrame(callFrame);
    JSValue result = vm.interpreter->execute(eval, callFrame, thisValue, scope()->jsScope());
    if (vm.exception()) {
        exception = vm.exception();
        vm.clearException();
    }
    ASSERT(result);
    return result;
}
EncodedJSValue JSLexicalEnvironment::argumentsGetter(ExecState*, JSObject* slotBase, EncodedJSValue, PropertyName)
{
    JSLexicalEnvironment* lexicalEnvironment = jsCast<JSLexicalEnvironment*>(slotBase);
    CallFrame* callFrame = CallFrame::create(reinterpret_cast<Register*>(lexicalEnvironment->m_registers));
    return JSValue::encode(jsUndefined());

    VirtualRegister argumentsRegister = callFrame->codeBlock()->argumentsRegister();
    if (JSValue arguments = callFrame->uncheckedR(argumentsRegister.offset()).jsValue())
        return JSValue::encode(arguments);
    int realArgumentsRegister = unmodifiedArgumentsRegister(argumentsRegister).offset();

    JSValue arguments = JSValue(Arguments::create(callFrame->vm(), callFrame));
    callFrame->uncheckedR(argumentsRegister.offset()) = arguments;
    callFrame->uncheckedR(realArgumentsRegister) = arguments;
    
    ASSERT(callFrame->uncheckedR(realArgumentsRegister).jsValue().inherits(Arguments::info()));
    return JSValue::encode(callFrame->uncheckedR(realArgumentsRegister).jsValue());
}
Example #16
0
JSObject* addErrorInfo(ExecState* exec, JSObject* error, int line, const SourceCode& source)
{
    JSGlobalData* globalData = &exec->globalData();

    addErrorInfo(globalData, error, line, source);

    JSArray* stack = constructEmptyArray(exec);
    CallFrame* frame = exec;

    JSObject* stackFrame;
    CodeBlock* codeBlock;
    UString sourceURL;
    UString functionName;
    ReturnAddressPtr pc;

    while (!frame->hasHostCallFrameFlag()) {
        stackFrame = constructEmptyObject(exec);
        codeBlock = frame->codeBlock();

        // sourceURL
        sourceURL = codeBlock->ownerExecutable()->sourceURL();
        stackFrame->putWithAttributes(
            globalData, Identifier(globalData, sourceURLPropertyName),
            jsString(globalData, sourceURL), ReadOnly | DontDelete
        );

        // line
        if (frame != exec) {
            line = codeBlock->lineNumberForBytecodeOffset(codeBlock->bytecodeOffset(pc));
        }
        stackFrame->putWithAttributes(
            globalData, Identifier(globalData, linePropertyName),
            jsNumber(line), ReadOnly | DontDelete
        );

        // function
        JSObject* function = frame->callee();
        if (function && function->inherits(&JSFunction::s_info)) {
            functionName = asFunction(function)->calculatedDisplayName(exec);
            stackFrame->putWithAttributes(
                globalData, Identifier(globalData, functionPropertyName),
                jsString(globalData, functionName), ReadOnly | DontDelete
            );
        }

        stack->push(exec, JSValue(stackFrame));

        pc = frame->returnPC();
        frame = frame->callerFrame();
    }

    error->putWithAttributes(globalData, Identifier(globalData, stackPropertyName), stack, ReadOnly | DontDelete);
    return error;
}
Example #17
0
JSValue JSActivation::argumentsGetter(ExecState*, JSValue slotBase, PropertyName)
{
    JSActivation* activation = jsCast<JSActivation*>(slotBase);
    if (activation->isTornOff())
        return jsUndefined();

    CallFrame* callFrame = CallFrame::create(reinterpret_cast<Register*>(activation->m_registers));
    int argumentsRegister = callFrame->codeBlock()->argumentsRegister();
    if (JSValue arguments = callFrame->uncheckedR(argumentsRegister).jsValue())
        return arguments;
    int realArgumentsRegister = unmodifiedArgumentsRegister(argumentsRegister);

    JSValue arguments = JSValue(Arguments::create(callFrame->vm(), callFrame));
    callFrame->uncheckedR(argumentsRegister) = arguments;
    callFrame->uncheckedR(realArgumentsRegister) = arguments;
    
    ASSERT(callFrame->uncheckedR(realArgumentsRegister).jsValue().inherits(Arguments::info()));
    return callFrame->uncheckedR(realArgumentsRegister).jsValue();
}
Example #18
0
JSValue JSActivation::argumentsGetter(ExecState*, JSValue slotBase, const Identifier&)
{
    JSActivation* activation = asActivation(slotBase);
    CallFrame* callFrame = CallFrame::create(reinterpret_cast<Register*>(activation->m_registers));
    int argumentsRegister = activation->m_argumentsRegister;
    if (JSValue arguments = callFrame->uncheckedR(argumentsRegister).jsValue())
        return arguments;
    int realArgumentsRegister = unmodifiedArgumentsRegister(argumentsRegister);

    JSValue arguments = JSValue(Arguments::create(callFrame->globalData(), callFrame));
    callFrame->uncheckedR(argumentsRegister) = arguments;
    callFrame->uncheckedR(realArgumentsRegister) = arguments;
    
    ASSERT(callFrame->uncheckedR(realArgumentsRegister).jsValue().inherits(&Arguments::s_info));
    return callFrame->uncheckedR(realArgumentsRegister).jsValue();
}
JSValue JSActivation::argumentsGetter(ExecState*, JSValue slotBase, const Identifier&)
{
    JSActivation* activation = asActivation(slotBase);
    CallFrame* callFrame = CallFrame::create(activation->d()->registers);
    int argumentsRegister = activation->d()->functionExecutable->generatedBytecode().argumentsRegister();
    if (!callFrame->uncheckedR(argumentsRegister).jsValue()) {
        JSValue arguments = JSValue(new (callFrame) Arguments(callFrame));
        callFrame->uncheckedR(argumentsRegister) = arguments;
        callFrame->uncheckedR(unmodifiedArgumentsRegister(argumentsRegister)) = arguments;
    }

    ASSERT(callFrame->uncheckedR(argumentsRegister).jsValue().inherits(&Arguments::info));
    return callFrame->uncheckedR(argumentsRegister).jsValue();
}
Example #20
0
CallFrame* CallFrame::trueCallFrame(AbstractPC pc)
{
    // Am I an inline call frame? If so, we're done.
    if (isInlineCallFrame())
        return this;
    
    // If I don't have a code block, then I'm not DFG code, so I'm the true call frame.
    CodeBlock* machineCodeBlock = codeBlock();
    if (!machineCodeBlock)
        return this;
    
    // If the code block does not have any code origins, then there was no inlining, so
    // I'm done.
    if (!machineCodeBlock->hasCodeOrigins())
        return this;
    
    // At this point the PC must be due either to the DFG, or it must be unset.
    ASSERT(pc.hasJITReturnAddress() || !pc);
    
    // Try to determine the CodeOrigin. If we don't have a pc set then the only way
    // that this makes sense is if the CodeOrigin index was set in the call frame.
    // FIXME: Note that you will see "Not currently in inlined code" comments below.
    // Currently, we do not record code origins for code that is not inlined, because
    // the only thing that we use code origins for is determining the inline stack.
    // But in the future, we'll want to use this same functionality (having a code
    // origin mapping for any calls out of JIT code) to determine the PC at any point
    // in the stack even if not in inlined code. When that happens, the code below
    // will have to change the way it detects the presence of inlining: it will always
    // get a code origin, but sometimes, that code origin will not have an inline call
    // frame. In that case, this method should bail and return this.
    CodeOrigin codeOrigin;
    if (pc.isSet()) {
        ReturnAddressPtr currentReturnPC = pc.jitReturnAddress();
        
        bool hasCodeOrigin = machineCodeBlock->codeOriginForReturn(currentReturnPC, codeOrigin);
        ASSERT_UNUSED(hasCodeOrigin, hasCodeOrigin);
    } else {
        unsigned index = codeOriginIndexForDFG();
        codeOrigin = machineCodeBlock->codeOrigin(index);
    }

    if (!codeOrigin.inlineCallFrame)
        return this; // Not currently in inlined code.
    
    for (InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame; inlineCallFrame;) {
        InlineCallFrame* nextInlineCallFrame = inlineCallFrame->caller.inlineCallFrame;
        
        CallFrame* inlinedCaller = this + inlineCallFrame->stackOffset;
        
        JSFunction* calleeAsFunction = inlineCallFrame->callee.get();
        
        // Fill in the inlinedCaller
        inlinedCaller->setCodeBlock(machineCodeBlock);
        
        inlinedCaller->setScopeChain(calleeAsFunction->scope());
        if (nextInlineCallFrame)
            inlinedCaller->setCallerFrame(this + nextInlineCallFrame->stackOffset);
        else
            inlinedCaller->setCallerFrame(this);
        
        inlinedCaller->setInlineCallFrame(inlineCallFrame);
        inlinedCaller->setArgumentCountIncludingThis(inlineCallFrame->arguments.size());
        inlinedCaller->setCallee(calleeAsFunction);
        
        inlineCallFrame = nextInlineCallFrame;
    }
    
    return this + codeOrigin.inlineCallFrame->stackOffset;
}
Example #21
0
  void SignalThread::print_backtraces() {
    STATE = shared_.env()->state;
    ThreadList* threads = shared_.thread_nexus()->threads();

    for(ThreadList::iterator i = threads->begin(); i != threads->end(); ++i) {
      VM* vm = (*i)->as_vm();
      if(!vm) continue;

      bool first = true;
      CallFrame* frame = vm->call_frame();

      while(frame) {
        if(first) {
          logger::fatal("--- %s %d backtrace ---", vm->kind_name(), vm->thread_id());
          first = false;
        }

        std::ostringstream stream;

        if(NativeMethodFrame* nmf = frame->native_method_frame()) {
          stream << static_cast<void*>(frame) << ": ";
          NativeMethod* nm = try_as<NativeMethod>(nmf->get_object(nmf->method()));
          if(nm && nm->name()->symbol_p()) {
            stream << "capi:" << nm->name()->debug_str(state) << " at ";
            stream << nm->file()->c_str(state);
          } else {
            stream << "unknown capi";
          }
        } else if(frame->compiled_code) {
          if(frame->is_block_p(state)) {
            stream << "__block__";
          } else {
            if(SingletonClass* sc = try_as<SingletonClass>(frame->module())) {
              Object* obj = sc->singleton();

              if(Module* mod = try_as<Module>(obj)) {
                stream << mod->debug_str(state) << ".";
              } else {
                if(obj == G(main)) {
                  stream << "MAIN.";
                } else {
                  stream << "#<" << obj->class_object(state)->debug_str(state) <<
                            ":" << (void*)obj->id(state)->to_native() << ">.";
                }
              }
            } else if(IncludedModule* im = try_as<IncludedModule>(frame->module())) {
              stream <<  im->module()->debug_str(state) << "#";
            } else {
              Symbol* name;
              std::string mod_name;

              if(frame->module()->nil_p()) {
                mod_name = frame->lexical_scope()->module()->debug_str(state);
              } else {
                if((name = try_as<Symbol>(frame->module()->module_name()))) {
                  mod_name = name->debug_str(state);
                } else if((name = try_as<Symbol>(
                          frame->lexical_scope()->module()->module_name()))) {
                  mod_name = name->debug_str(state);
                } else {
                  mod_name = "<anonymous module>";
                }
              }
              stream << mod_name << "#";
            }

            Symbol* name = try_as<Symbol>(frame->name());
            if(name) {
              stream << name->debug_str(state);
            } else {
              stream << frame->compiled_code->name()->debug_str(state);
            }
          }

          stream << " in ";
          if(Symbol* file_sym = try_as<Symbol>(frame->compiled_code->file())) {
            stream << file_sym->debug_str(state) << ":" << frame->line(state);
          } else {
            stream << "<unknown>";
          }

          stream << " (+" << frame->ip();
          if(frame->is_inline_frame()) {
            stream << " inline";
          } else if(frame->jitted_p()) {
            stream << " jit";
          }
          stream << ")";
        }

        logger::fatal(stream.str().c_str());

        frame = frame->previous;
      }
    }
  }
void ShadowChicken::update(VM&, ExecState* exec)
{
    if (verbose) {
        dataLog("Running update on: ", *this, "\n");
        WTFReportBacktrace();
    }
    
    const unsigned logCursorIndex = m_logCursor - m_log;
    
    // We need to figure out how to reconcile the current machine stack with our shadow stack. We do
    // that by figuring out how much of the shadow stack to pop. We apply three different rules. The
    // precise rule relies on the log. The log contains caller frames, which means that we know
    // where we bottomed out after making any call. If we bottomed out but made no calls then 'exec'
    // will tell us. That's why "highestPointSinceLastTime" will go no lower than exec. The third
    // rule, based on comparing to the current real stack, is executed in a later loop.
    CallFrame* highestPointSinceLastTime = exec;
    for (unsigned i = logCursorIndex; i--;) {
        Packet packet = m_log[i];
        if (packet.isPrologue()) {
            CallFrame* watermark;
            if (i && m_log[i - 1].isTail())
                watermark = packet.frame;
            else
                watermark = packet.callerFrame;
            highestPointSinceLastTime = std::max(highestPointSinceLastTime, watermark);
        }
    }
    
    if (verbose)
        dataLog("    Highest point since last time: ", RawPointer(highestPointSinceLastTime), "\n");
    
    while (!m_stack.isEmpty() && m_stack.last().frame < highestPointSinceLastTime)
        m_stack.removeLast();
    
    if (verbose)
        dataLog("    Revised stack: ", listDump(m_stack), "\n");
    
    // It's possible that the top of stack is now tail-deleted. The stack no longer contains any
    // frames below the log's high watermark. That means that we just need to look for the first
    // occurence of a tail packet for the current stack top.
    if (!m_stack.isEmpty()) {
        ASSERT(!m_stack.last().isTailDeleted);
        for (unsigned i = 0; i < logCursorIndex; ++i) {
            Packet& packet = m_log[i];
            if (packet.isTail() && packet.frame == m_stack.last().frame) {
                m_stack.last().isTailDeleted = true;
                break;
            }
        }
    }
    
    if (verbose)
        dataLog("    Revised stack: ", listDump(m_stack), "\n");
    
    // The log-based and exec-based rules require that ShadowChicken was enabled. The point of
    // ShadowChicken is to give sensible-looking results even if we had not logged. This means that
    // we need to reconcile the shadow stack and the real stack by actually looking at the real
    // stack. This reconciliation allows the shadow stack to have extra tail-deleted frames, but it
    // forbids it from diverging from the real stack on normal frames.
    if (!m_stack.isEmpty()) {
        Vector<Frame> stackRightNow;
        StackVisitor::visit(
            exec, [&] (StackVisitor& visitor) -> StackVisitor::Status {
                if (visitor->isInlinedFrame())
                    return StackVisitor::Continue;
                bool isTailDeleted = false;
                stackRightNow.append(Frame(visitor->callee(), visitor->callFrame(), isTailDeleted));
                return StackVisitor::Continue;
            });
        stackRightNow.reverse();
        
        if (verbose)
            dataLog("    Stack right now: ", listDump(stackRightNow), "\n");
        
        unsigned shadowIndex = 0;
        unsigned rightNowIndex = 0;
        while (shadowIndex < m_stack.size() && rightNowIndex < stackRightNow.size()) {
            if (m_stack[shadowIndex].isTailDeleted) {
                shadowIndex++;
                continue;
            }
            if (m_stack[shadowIndex] == stackRightNow[rightNowIndex]) {
                shadowIndex++;
                rightNowIndex++;
                continue;
            }
            break;
        }
        m_stack.resize(shadowIndex);
        
        if (verbose)
            dataLog("    Revised stack: ", listDump(m_stack), "\n");
    }
    
    // It's possible that the top stack frame is actually lower than highestPointSinceLastTime.
    // Account for that here.
    highestPointSinceLastTime = nullptr;
    for (unsigned i = m_stack.size(); i--;) {
        if (!m_stack[i].isTailDeleted) {
            highestPointSinceLastTime = m_stack[i].frame;
            break;
        }
    }
    
    if (verbose)
        dataLog("    Highest point since last time: ", RawPointer(highestPointSinceLastTime), "\n");
    
    // Set everything up so that we know where the top frame is in the log.
    unsigned indexInLog = logCursorIndex;
    
    auto advanceIndexInLogTo =
        [&] (CallFrame* frame, JSObject* callee, CallFrame* callerFrame) -> bool {
        if (verbose)
            dataLog("    Advancing to frame = ", RawPointer(frame), " from indexInLog = ", indexInLog, "\n");
        if (indexInLog > logCursorIndex) {
            if (verbose)
                dataLog("    Bailing.\n");
            return false;
        }
        
        unsigned oldIndexInLog = indexInLog;
        
        while (indexInLog--) {
            Packet packet = m_log[indexInLog];
            
            // If all callees opt into ShadowChicken, then this search will rapidly terminate when
            // we find our frame. But if our frame's callee didn't emit a prologue packet because it
            // didn't opt in, then we will keep looking backwards until we *might* find a different
            // frame. If we've been given the callee and callerFrame as a filter, then it's unlikely
            // that we will hit the wrong frame. But we don't always have that information.
            //
            // This means it's worth adding other filters. For example, we could track changes in
            // stack size. Once we've seen a frame at some height, we're no longer interested in
            // frames below that height. Also, we can break as soon as we see a frame higher than
            // the one we're looking for.
            // FIXME: Add more filters.
            // https://bugs.webkit.org/show_bug.cgi?id=155685
            
            if (packet.isPrologue() && packet.frame == frame
                && (!callee || packet.callee == callee)
                && (!callerFrame || packet.callerFrame == callerFrame)) {
                if (verbose)
                    dataLog("    Found at indexInLog = ", indexInLog, "\n");
                return true;
            }
        }
        
        // This is an interesting eventuality. We will see this if ShadowChicken was not
        // consistently enabled. We have a choice between:
        //
        // - Leaving the log index at -1, which will prevent the log from being considered. This is
        //   the most conservative. It means that we will not be able to recover tail-deleted frames
        //   from anything that sits above a frame that didn't log a prologue packet. This means
        //   that everyone who creates prologues must log prologue packets.
        //
        // - Restoring the log index to what it was before. This prevents us from considering
        //   whether this frame has tail-deleted frames behind it, but that's about it. The problem
        //   with this approach is that it might recover tail-deleted frames that aren't relevant.
        //   I haven't thought about this too deeply, though.
        //
        // It seems like the latter option is less harmful, so that's what we do.
        indexInLog = oldIndexInLog;
        
        if (verbose)
            dataLog("    Didn't find it.\n");
        return false;
    };
    
    Vector<Frame> toPush;
    StackVisitor::visit(
        exec, [&] (StackVisitor& visitor) -> StackVisitor::Status {
            if (visitor->isInlinedFrame()) {
                // FIXME: Handle inlining.
                // https://bugs.webkit.org/show_bug.cgi?id=155686
                return StackVisitor::Continue;
            }
            CallFrame* callFrame = visitor->callFrame();
            if (verbose)
                dataLog("    Examining ", RawPointer(callFrame), "\n");
            if (!toPush.isEmpty() && indexInLog < logCursorIndex
                // This condition protects us from the case where advanceIndexInLogTo didn't find
                // anything.
                && m_log[indexInLog].frame == toPush.last().frame) {
                if (verbose)
                    dataLog("    Going to loop through things with indexInLog = ", indexInLog, " and push-stack top = ", toPush.last(), "\n");
                for (;;) {
                    ASSERT(m_log[indexInLog].frame == toPush.last().frame);
                    
                    // Right now the index is pointing at a prologue packet of the last frame that
                    // we pushed. Peek behind that packet to see if there is a tail packet. If there
                    // is one then we know that there is a corresponding prologue packet that will
                    // tell us about a tail-deleted frame.
                    
                    if (!indexInLog)
                        break;
                    Packet lastPacket = m_log[indexInLog - 1];
                    if (!lastPacket.isTail()) {
                        // Last frame that we recorded was not the outcome of a tail call. So, there
                        // will not be any more deleted frames.
                        // FIXME: We might want to have a filter here. Consider that this was a tail
                        // marker for a tail call to something that didn't log anything. It should
                        // be sufficient to give the tail marker a copy of the caller frame.
                        // https://bugs.webkit.org/show_bug.cgi?id=155687
                        break;
                    }
                    indexInLog--; // Skip over the tail packet.
                    
                    if (!advanceIndexInLogTo(lastPacket.frame, nullptr, nullptr)) {
                        // We were unable to locate the prologue packet for this tail packet. That's
                        // quite suspect, so give up.
                        break;
                    }
                    Packet packet = m_log[indexInLog];
                    bool isTailDeleted = true;
                    toPush.append(Frame(packet.callee, packet.frame, isTailDeleted));
                }
            }
            if (callFrame == highestPointSinceLastTime) {
                if (verbose)
                    dataLog("    Bailing at ", RawPointer(callFrame), " because it's the highest point since last time.\n");
                return StackVisitor::Done;
            }
            advanceIndexInLogTo(callFrame, callFrame->callee(), callFrame->callerFrame());
            bool isTailDeleted = false;
            toPush.append(Frame(visitor->callee(), callFrame, isTailDeleted));
            return StackVisitor::Continue;
        });
    
    if (verbose)
        dataLog("    Pushing: ", listDump(toPush), "\n");
    
    for (unsigned i = toPush.size(); i--;)
        m_stack.append(toPush[i]);
    
    // We want to reset the log. There is a fun corner-case: there could be a tail marker at the end
    // of this log. We could make that work by setting isTailDeleted on the top of stack, but that
    // would require more corner cases in the complicated reconciliation code above. That code
    // already knows how to handle a tail packet at the beginning, so we just leverage that here.
    if (logCursorIndex && m_log[logCursorIndex - 1].isTail()) {
        m_log[0] = m_log[logCursorIndex - 1];
        m_logCursor = m_log + 1;
    } else
        m_logCursor = m_log;

    if (verbose)
        dataLog("    After pushing: ", *this, "\n");
    
    // Remove tail frames until the stack is small enough again.
    const unsigned stackSizeLimit = Options::shadowChickenStackSizeLimit();
    if (m_stack.size() > stackSizeLimit) {
        unsigned dstIndex = 0;
        unsigned srcIndex = 0;
        unsigned size = m_stack.size();
        while (srcIndex < m_stack.size()) {
            Frame frame = m_stack[srcIndex++];
            if (size > stackSizeLimit && frame.isTailDeleted) {
                size--;
                continue;
            }
            m_stack[dstIndex++] = frame;
        }
        RELEASE_ASSERT(dstIndex == size);
        m_stack.resize(size);
    }

    if (verbose)
        dataLog("    After clean-up: ", *this, "\n");
}
Example #23
0
  CallFrame* LLVMState::find_candidate(STATE, CallFrame* call_frame, CompiledCode* start) {
    if(!config_.jit_inline_generic) {
      return call_frame;
    }

    int depth = config().jit_limit_search;

    if(!start) {
      throw CompileError("find_candidate: null start");
    }

    if(!call_frame) {
      throw CompileError("find_candidate: null call frame");
    }

    if(debug_search) {
      std::cout << "> call_count: " << call_frame->compiled_code->machine_code()->call_count
            << " size: " << call_frame->compiled_code->machine_code()->total
            << " sends: " << call_frame->compiled_code->machine_code()->call_site_count()
            << std::endl;

      call_frame->print_backtrace(state, 1);
    }

    if(start->machine_code()->total > (size_t)config_.jit_limit_inline_method) {
      if(debug_search) {
        std::cout << "JIT: STOP. reason: trigger method isn't small: "
              << start->machine_code()->total << " > "
              << config_.jit_limit_inline_method
              << std::endl;
      }

      return call_frame;
    }

    MachineCode* mcode = start->machine_code();

    if(mcode->required_args != mcode->total_args) {
      if(debug_search) {
        std::cout << "JIT: STOP. reason: trigger method req_args != total_args" << std::endl;
      }

      return call_frame;
    }

    if(mcode->no_inline_p()) {
      if(debug_search) {
        std::cout << "JIT: STOP. reason: trigger method no_inline_p() = true" << std::endl;
      }

      return call_frame;
    }

    CallFrame* callee = call_frame;

    // Now start looking at callers.
    while(callee) {
      if(depth-- == 0) break;

      CompiledCode* cur = callee->compiled_code;

      if(!cur) {
        if(debug_search) {
          std::cout << "JIT: STOP. reason: synthetic CallFrame hit" << std::endl;
        }
        return callee;
      }

      MachineCode* mcode = cur->machine_code();

      if(debug_search) {
        std::cout << "> call_count: " << mcode->call_count
              << " size: " << mcode->total
              << " sends: " << mcode->call_site_count()
              << std::endl;

        call_frame->print_backtrace(state, 1);
      }


      /*
      if(call_frame->block_p()
          || mcode->required_args != mcode->total_args // has a splat
          || mcode->call_count < 200 // not called much
          || mcode->jitted() // already jitted
          || mcode->parent() // is a block
        ) return callee;
      */

      if(mcode->required_args != mcode->total_args) {
        if(debug_search) {
          std::cout << "JIT: STOP. reason: req_args != total_args" << std::endl;
        }
        return callee;
      }

      if(mcode->call_count < config_.jit_threshold_inline) {
        if(debug_search) {
          std::cout << "JIT: STOP. reason: call_count too small: "
                << mcode->call_count << " < "
                << config_.jit_threshold_inline << std::endl;
        }

        return callee;
      }

      if(mcode->jitted_p()) {
        if(debug_search) {
          std::cout << "JIT: STOP. reason: already jitted" << std::endl;
        }

        return callee;
      }

      if(mcode->no_inline_p()) {
        if(debug_search) {
          std::cout << "JIT: STOP. reason: no_inline_p() = true" << std::endl;
        }

        return callee;
      }

      if(callee->jitted_p() || callee->inline_method_p()) {
        return callee;
      }

      if(mcode->call_site_count() > eMaxInlineSendCount) {
        if(debug_search) {
          std::cout << "JIT: STOP. reason: high send count" << std::endl;
        }

        return callee;
      }

      // if(mcode->required_args != mcode->total_args // has a splat
          // || mcode->call_count < 200 // not called much
          // || mcode->jitted() // already jitted
          // || !mcode->no_inline_p() // method marked as not inlineable
        // ) return callee;

      // if(cur->machine_code()->total > SMALL_METHOD_SIZE) {
        // if(debug_search) {
          // std::cout << "JIT: STOP. reason: big method: "
                // << cur->machine_code()->total << " > "
                // << SMALL_METHOD_SIZE
                // << "\n";
        // }

        // return call_frame;
      // }

      // if(!next || cur->machine_code()->total > SMALL_METHOD_SIZE) return call_frame;

      callee = callee->previous;
    }

    return callee;
  }
Example #24
0
 VariableScope* VariableScope::of_sender(STATE, CallFrame* call_frame) {
   CallFrame* dest = static_cast<CallFrame*>(call_frame->previous);
   // Skip any frames for native methods
   while(dest->native_method_p()) { dest = dest->previous; }
   return dest->promote_scope(state);
 }
Example #25
0
    Object* const_get(STATE, Symbol* name, ConstantMissingReason* reason, Object* filter, bool replace_autoload) {
      LexicalScope *cur;
      Object* result;

      *reason = vNonExistent;

      CallFrame* frame = state->vm()->get_ruby_frame();

      // Ok, this has to be explained or it will be considered black magic.
      // The scope chain always ends with an entry at the top that contains
      // a parent of nil, and a module of Object. This entry is put in
      // regardless of lexical scoping, it's the fallback scope (the default
      // scope). This is not case when deriving from BasicObject, which is
      // explained later.
      //
      // When looking up a constant, we don't want to consider the fallback
      // scope (ie, Object) initially because we need to lookup up
      // the superclass chain first, because falling back on the default.
      //
      // The rub comes from the fact that if a user explicitly opens up
      // Object in their code, we DO consider it. Like:
      //
      // class Idiot
      //   A = 2
      // end
      //
      // class ::Object
      //   A = 1
      //   class Stupid < Idiot
      //     def foo
      //       p A
      //     end
      //   end
      // end
      //
      // In this code, when A is looked up, Object must be considering during
      // the scope walk, NOT during the superclass walk.
      //
      // So, in this case, foo would print "1", not "2".
      //
      // As indicated above, the fallback scope isn't used when the superclass
      // chain directly rooted from BasicObject. To determine this is the
      // case, we record whether Object is seen when looking up the superclass
      // chain. If Object isn't seen, this means we are directly deriving from
      // BasicObject.

      cur = frame->lexical_scope();
      while(!cur->nil_p()) {
        // Detect the toplevel scope (the default) and get outta dodge.
        if(cur->top_level_p(state)) break;

        result = cur->module()->get_const(state, name, G(sym_private), reason, false, replace_autoload);
        if(*reason == vFound) {
          if(result != filter) return result;
          *reason = vNonExistent;
        }

        cur = cur->parent();
      }

      // Now look up the superclass chain.
      Module *fallback = G(object);

      cur = frame->lexical_scope();
      if(!cur->nil_p()) {
        bool object_seen = false;
        Module* mod = cur->module();
        while(!mod->nil_p()) {
          if(mod == G(object)) {
            object_seen = true;
          }
          if(!object_seen && mod == G(basicobject)) {
            fallback = NULL;
          }

          result = mod->get_const(state, name, G(sym_private), reason, false, replace_autoload);
          if(*reason == vFound) {
            if(result != filter) return result;
            *reason = vNonExistent;
          }

          mod = mod->superclass();
        }
      }

      // Lastly, check the fallback scope (=Object) specifically if needed
      if(fallback) {
        result = fallback->get_const(state, name, G(sym_private), reason, true, replace_autoload);
        if(*reason == vFound) {
          if(result != filter) return result;
          *reason = vNonExistent;
        }
      }

      return cNil;
    }
EncodedJSValue JSActivation::argumentsGetter(ExecState*, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
{
    JSActivation* activation = jsCast<JSActivation*>(JSValue::decode(slotBase));
    CallFrame* callFrame = CallFrame::create(reinterpret_cast<Register*>(activation->m_registers));
    ASSERT(!activation->isTornOff() && (callFrame->codeBlock()->usesArguments() || callFrame->codeBlock()->usesEval()));
    if (activation->isTornOff() || !(callFrame->codeBlock()->usesArguments() || callFrame->codeBlock()->usesEval()))
        return JSValue::encode(jsUndefined());

    VirtualRegister argumentsRegister = callFrame->codeBlock()->argumentsRegister();
    if (JSValue arguments = callFrame->uncheckedR(argumentsRegister.offset()).jsValue())
        return JSValue::encode(arguments);
    int realArgumentsRegister = unmodifiedArgumentsRegister(argumentsRegister).offset();

    JSValue arguments = JSValue(Arguments::create(callFrame->vm(), callFrame));
    callFrame->uncheckedR(argumentsRegister.offset()) = arguments;
    callFrame->uncheckedR(realArgumentsRegister) = arguments;
    
    ASSERT(callFrame->uncheckedR(realArgumentsRegister).jsValue().inherits(Arguments::info()));
    return JSValue::encode(callFrame->uncheckedR(realArgumentsRegister).jsValue());
}
Example #27
0
  bool QueryAgent::process_commands(int client) {
    bert::IOReader reader(client);
    bert::Decoder<bert::IOReader> decoder(reader);

    bert::IOWriter writer(client);
    bert::Encoder<bert::IOWriter> encoder(writer);

    int ver = decoder.read_version();
    if(ver != 131) return false;

    bert::Value* val = decoder.next_value();
    if(!val || reader.eof_p()) return false;

    encoder.write_version();

    if(val->type() == bert::Tuple) {
      bert::Value* cmd = val->get_element(0);
      if(cmd->equal_atom("uname")) {
        struct utsname name;
        if(uname(&name)) {
          encoder.write_atom("error");
          return true;
        } else {
          encoder.write_tuple(5);
          encoder.write_binary(name.sysname);
          encoder.write_binary(name.nodename);
          encoder.write_binary(name.release);
          encoder.write_binary(name.version);
          encoder.write_binary(name.machine);
          return true;
        }
      } else if(cmd->equal_atom("set_config")) {
        if(val->elements()->size() == 3) {
          bert::Value* key = val->get_element(1);
          bert::Value* value = val->get_element(2);

          if(key->type() == bert::Binary &&
              value->type() == bert::Binary) {
            if(shared_.config.import(key->string(), value->string())) {
              encoder.write_atom("ok");
            } else {
              encoder.write_atom("unknown_key");
            }
            return true;
          }
        }

        encoder.write_atom("error");
        return true;
      } else if(cmd->equal_atom("get_config")) {
        if(val->elements()->size() == 2) {
          bert::Value* key = val->get_element(1);
          if(key->type() == bert::Binary) {
            if(config::ConfigItem* item = shared_.config.find(key->string())) {
              std::stringstream ss;
              item->print_value(ss);

              encoder.write_tuple(2);
              encoder.write_atom("ok");
              if(config::Integer* i = dynamic_cast<config::Integer*>(item)) {
                encoder.write_integer(i->value);
              } else {
                encoder.write_binary(ss.str().c_str());
              }
            } else {
              encoder.write_atom("unknown_key");
            }
            return true;
          }
        }

        encoder.write_atom("error");
        return true;
      } else if(cmd->equal_atom("backtrace")) {
        if(verbose_) {
          std::cerr << "[QA: Gathering backtraces, pausing threads]\n";
        }

        encoder.write_tuple(2);
        encoder.write_atom("ok");

        {
          GlobalLock::LockGuard guard(shared_.global_lock());

          encoder.write_tuple(shared_.call_frame_locations().size());

          for(CallFrameLocationList::iterator i = shared_.call_frame_locations().begin();
              i != shared_.call_frame_locations().end();
              i++) {
            CallFrame* loc = *(*i);

            std::ostringstream ss;
            loc->print_backtrace(state_, ss);
            encoder.write_binary(ss.str().c_str());
          }
        }

        if(verbose_) {
          std::cerr << "[QA: Threads restarted]\n";
        }
      }

      return true;
    } else if(val->equal_atom("close")) {
      encoder.write_atom("bye");
      return false;
    }

    encoder.write_atom("unknown");

    return true;
  }
Example #28
0
void StackVisitor::Frame::dump(PrintStream& out, Indenter indent, WTF::Function<void(PrintStream&)> prefix) const
{
    if (!this->callFrame()) {
        out.print(indent, "frame 0x0\n");
        return;
    }

    CodeBlock* codeBlock = this->codeBlock();
    out.print(indent);
    prefix(out);
    out.print("frame ", RawPointer(this->callFrame()), " {\n");

    {
        indent++;

        CallFrame* callFrame = m_callFrame;
        CallFrame* callerFrame = this->callerFrame();
        const void* returnPC = callFrame->hasReturnPC() ? callFrame->returnPC().value() : nullptr;

        out.print(indent, "name: ", functionName(), "\n");
        out.print(indent, "sourceURL: ", sourceURL(), "\n");

        bool isInlined = false;
#if ENABLE(DFG_JIT)
        isInlined = isInlinedFrame();
        out.print(indent, "isInlinedFrame: ", isInlinedFrame(), "\n");
        if (isInlinedFrame())
            out.print(indent, "InlineCallFrame: ", RawPointer(m_inlineCallFrame), "\n");
#endif

        out.print(indent, "callee: ", RawPointer(callee().rawPtr()), "\n");
        out.print(indent, "returnPC: ", RawPointer(returnPC), "\n");
        out.print(indent, "callerFrame: ", RawPointer(callerFrame), "\n");
        uintptr_t locationRawBits = callFrame->callSiteAsRawBits();
        out.print(indent, "rawLocationBits: ", locationRawBits,
            " ", RawPointer(reinterpret_cast<void*>(locationRawBits)), "\n");
        out.print(indent, "codeBlock: ", RawPointer(codeBlock));
        if (codeBlock)
            out.print(" ", *codeBlock);
        out.print("\n");
        if (codeBlock && !isInlined) {
            indent++;

            if (callFrame->callSiteBitsAreBytecodeOffset()) {
                unsigned bytecodeOffset = callFrame->bytecodeOffset();
                out.print(indent, "bytecodeOffset: ", bytecodeOffset, " of ", codeBlock->instructions().size(), "\n");
#if ENABLE(DFG_JIT)
            } else {
                out.print(indent, "hasCodeOrigins: ", codeBlock->hasCodeOrigins(), "\n");
                if (codeBlock->hasCodeOrigins()) {
                    CallSiteIndex callSiteIndex = callFrame->callSiteIndex();
                    out.print(indent, "callSiteIndex: ", callSiteIndex.bits(), " of ", codeBlock->codeOrigins().size(), "\n");

                    JITCode::JITType jitType = codeBlock->jitType();
                    if (jitType != JITCode::FTLJIT) {
                        JITCode* jitCode = codeBlock->jitCode().get();
                        out.print(indent, "jitCode: ", RawPointer(jitCode),
                            " start ", RawPointer(jitCode->start()),
                            " end ", RawPointer(jitCode->end()), "\n");
                    }
                }
#endif
            }
            unsigned line = 0;
            unsigned column = 0;
            computeLineAndColumn(line, column);
            out.print(indent, "line: ", line, "\n");
            out.print(indent, "column: ", column, "\n");

            indent--;
        }
        out.print(indent, "EntryFrame: ", RawPointer(m_entryFrame), "\n");
        indent--;
    }
    out.print(indent, "}\n");
}
Example #29
0
  void CallFrame::print_backtrace(STATE, std::ostream& stream, int total, bool filter) {
    CallFrame* cf = this;

    int i = -1;

    while(cf) {
      i++;

      if(total > 0 && i == total) return;

      if(NativeMethodFrame* nmf = cf->native_method_frame()) {
        stream << static_cast<void*>(cf) << ": ";
        NativeMethod* nm = try_as<NativeMethod>(nmf->get_object(nmf->method()));
        if(nm && nm->name()->symbol_p()) {
          stream << "capi:" << nm->name()->debug_str(state) << " at ";
          stream << nm->file()->c_str(state);
        } else {
          stream << "unknown capi";
        }

        stream << std::endl;
        cf = cf->previous;
        continue;
      }

      if(!cf->compiled_code) {
        cf = cf->previous;
        continue;
      }

      if(filter && cf->compiled_code->kernel_method(state)) {
        cf = cf->previous;
        continue;
      }

      stream << static_cast<void*>(cf) << ": ";

      if(cf->is_block_p(state)) {
        stream << "__block__";
      } else {
        if(SingletonClass* sc = try_as<SingletonClass>(cf->module())) {
          Object* obj = sc->attached_instance();

          if(Module* mod = try_as<Module>(obj)) {
            stream << mod->debug_str(state) << ".";
          } else {
            if(obj == G(main)) {
              stream << "MAIN.";
            } else {
              stream << "#<" << obj->class_object(state)->debug_str(state) <<
                        ":" << (void*)obj->id(state)->to_native() << ">.";
            }
          }
        } else if(IncludedModule* im = try_as<IncludedModule>(cf->module())) {
          stream <<  im->module()->debug_str(state) << "#";
        } else {
          Symbol* name;
          std::string mod_name;

          if(cf->module()->nil_p()) {
            mod_name = cf->constant_scope()->module()->debug_str(state);
          } else {
            if((name = try_as<Symbol>(cf->module()->module_name()))) {
              mod_name = name->debug_str(state);
            } else if((name = try_as<Symbol>(
                      cf->constant_scope()->module()->module_name()))) {
              mod_name = name->debug_str(state);
            } else {
              mod_name = "<anonymous module>";
            }
          }
          stream << mod_name << "#";
        }

        Symbol* name = try_as<Symbol>(cf->name());
        if(name) {
          stream << name->debug_str(state);
        } else {
          stream << cf->compiled_code->name()->debug_str(state);
        }
      }

      stream << " in ";
      if(Symbol* file_sym = try_as<Symbol>(cf->compiled_code->file())) {
        stream << file_sym->debug_str(state) << ":" << cf->line(state);
      } else {
        stream << "<unknown>";
      }

      stream << " (+" << cf->ip();
      if(cf->is_inline_frame()) {
        stream << " inline";
      } else if(cf->jitted_p()) {
        stream << " jit";
      }
      stream << ")";

      stream << std::endl;
      cf = cf->previous;
    }

  }
Example #30
0
void StackVisitor::Frame::print(int indent)
{
    if (!this->callFrame()) {
        log(indent, "frame 0x0\n");
        return;
    }

    CodeBlock* codeBlock = this->codeBlock();
    logF(indent, "frame %p {\n", this->callFrame());

    {
        indent++;

        CallFrame* callFrame = m_callFrame;
        CallFrame* callerFrame = this->callerFrame();
        void* returnPC = callFrame->hasReturnPC() ? callFrame->returnPC().value() : nullptr;

        log(indent, "name: ", functionName(), "\n");
        log(indent, "sourceURL: ", sourceURL(), "\n");

        bool isInlined = false;
#if ENABLE(DFG_JIT)
        isInlined = isInlinedFrame();
        log(indent, "isInlinedFrame: ", isInlinedFrame(), "\n");
        if (isInlinedFrame())
            logF(indent, "InlineCallFrame: %p\n", m_inlineCallFrame);
#endif

        logF(indent, "callee: %p\n", callee());
        logF(indent, "returnPC: %p\n", returnPC);
        logF(indent, "callerFrame: %p\n", callerFrame);
        unsigned locationRawBits = callFrame->callSiteAsRawBits();
        logF(indent, "rawLocationBits: %u 0x%x\n", locationRawBits, locationRawBits);
        logF(indent, "codeBlock: %p ", codeBlock);
        if (codeBlock)
            dataLog(*codeBlock);
        dataLog("\n");
        if (codeBlock && !isInlined) {
            indent++;

            if (callFrame->callSiteBitsAreBytecodeOffset()) {
                unsigned bytecodeOffset = callFrame->bytecodeOffset();
                log(indent, "bytecodeOffset: ", bytecodeOffset, " of ", codeBlock->instructions().size(), "\n");
#if ENABLE(DFG_JIT)
            } else {
                log(indent, "hasCodeOrigins: ", codeBlock->hasCodeOrigins(), "\n");
                if (codeBlock->hasCodeOrigins()) {
                    CallSiteIndex callSiteIndex = callFrame->callSiteIndex();
                    log(indent, "callSiteIndex: ", callSiteIndex.bits(), " of ", codeBlock->codeOrigins().size(), "\n");

                    JITCode::JITType jitType = codeBlock->jitType();
                    if (jitType != JITCode::FTLJIT) {
                        JITCode* jitCode = codeBlock->jitCode().get();
                        logF(indent, "jitCode: %p start %p end %p\n", jitCode, jitCode->start(), jitCode->end());
                    }
                }
#endif
            }
            unsigned line = 0;
            unsigned column = 0;
            computeLineAndColumn(line, column);
            log(indent, "line: ", line, "\n");
            log(indent, "column: ", column, "\n");

            indent--;
        }
        indent--;
    }
    log(indent, "}\n");
}