<commit_before>
/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkGLWidget.h"

#if SK_SUPPORT_GPU

SkGLWidget::SkGLWidget(SkDebugger* debugger) : QGLWidget() {
    fDebugger = debugger;
}

SkGLWidget::~SkGLWidget() {
}

void SkGLWidget::setSampleCount(int sampleCount) {
    QGLFormat currentFormat = format();
    currentFormat.setSampleBuffers(sampleCount > 0);
    currentFormat.setSamples(sampleCount);
    setFormat(currentFormat);
}

void SkGLWidget::initializeGL() {
    if (!fCurIntf) {
        fCurIntf.reset(GrGLCreateNativeInterface());
    }
    if (!fCurIntf) {
        return;
    }
    if (!fCurContext) {
        fCurContext.reset(GrContext::Create(kOpenGL_GrBackend, (GrBackendContext) fCurIntf.get()));
    }
    if (!fCurContext) {
        return;
    }

    // The call may come multiple times, for example after setSampleCount().  The QGLContext will be
    // different, but we do not have a mechanism to catch the destroying of QGLContext, so that
    // proper resource cleanup could be made. Instead, we assume that the underlying GL context
    // never actually changes. If it would, we could not destroy the resources.
    fGpuDevice.reset(NULL);
    fCanvas.reset(NULL);
}

void SkGLWidget::createRenderTarget() {
    if (!fCurContext) {
        return;
    }

    glDisable(GL_SCISSOR_TEST);
    glStencilMask(0xffffffff);
    glClearStencil(0);
    glClear(GL_STENCIL_BUFFER_BIT);
    fCurContext->resetContext();

    fGpuDevice.reset(NULL);
    fCanvas.reset(NULL);

    GrBackendRenderTargetDesc desc = this->getDesc(this->width(), this->height());
    desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
    SkAutoTUnref<GrRenderTarget> curRenderTarget(fCurContext->wrapBackendRenderTarget(desc));
    SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
    fGpuDevice.reset(SkGpuDevice::Create(curRenderTarget, &props));
    fCanvas.reset(new SkCanvas(fGpuDevice));
}

void SkGLWidget::resizeGL(int w, int h) {
    SkASSERT(w == this->width() && h == this->height());
    this->createRenderTarget();
}

void SkGLWidget::paintGL() {
    if (!this->isHidden() && fCanvas) {
        fDebugger->draw(fCanvas.get());
        // TODO(chudy): Implement an optional flush button in Gui.
        fCanvas->flush();
        emit drawComplete();
    }
}

GrBackendRenderTargetDesc SkGLWidget::getDesc(int w, int h) {
    GrBackendRenderTargetDesc desc;
    desc.fWidth = SkScalarRoundToInt(this->width());
    desc.fHeight = SkScalarRoundToInt(this->height());
    desc.fConfig = kSkia8888_GrPixelConfig;
    GR_GL_GetIntegerv(fCurIntf, GR_GL_SAMPLES, &desc.fSampleCnt);
    GR_GL_GetIntegerv(fCurIntf, GR_GL_STENCIL_BITS, &desc.fStencilBits);
    GrGLint buffer;
    GR_GL_GetIntegerv(fCurIntf, GR_GL_FRAMEBUFFER_BINDING, &buffer);
    desc.fRenderTargetHandle = buffer;

    return desc;
}

#endif
<commit_msg>debugger: Abandon context when Qt changes it without notice<commit_after>
/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkGLWidget.h"

#if SK_SUPPORT_GPU

SkGLWidget::SkGLWidget(SkDebugger* debugger) : QGLWidget() {
    fDebugger = debugger;
}

SkGLWidget::~SkGLWidget() {
}

void SkGLWidget::setSampleCount(int sampleCount) {
    QGLFormat currentFormat = format();
    currentFormat.setSampleBuffers(sampleCount > 0);
    currentFormat.setSamples(sampleCount);
    setFormat(currentFormat);
}

void SkGLWidget::initializeGL() {
    if (!fCurIntf) {
        fCurIntf.reset(GrGLCreateNativeInterface());
    }
    if (!fCurIntf) {
        return;
    }
    // The call may come multiple times, for example after setSampleCount().  The QGLContext will be
    // different, but we do not have a mechanism to catch the destroying of QGLContext, so that
    // proper resource cleanup could be made.
    if (fCurContext) {
        fCurContext->abandonContext();
    }
    fGpuDevice.reset(NULL);
    fCanvas.reset(NULL);

    fCurContext.reset(GrContext::Create(kOpenGL_GrBackend, (GrBackendContext) fCurIntf.get()));
}

void SkGLWidget::createRenderTarget() {
    if (!fCurContext) {
        return;
    }

    glDisable(GL_SCISSOR_TEST);
    glStencilMask(0xffffffff);
    glClearStencil(0);
    glClear(GL_STENCIL_BUFFER_BIT);
    fCurContext->resetContext();

    fGpuDevice.reset(NULL);
    fCanvas.reset(NULL);

    GrBackendRenderTargetDesc desc = this->getDesc(this->width(), this->height());
    desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
    SkAutoTUnref<GrRenderTarget> curRenderTarget(fCurContext->wrapBackendRenderTarget(desc));
    SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
    fGpuDevice.reset(SkGpuDevice::Create(curRenderTarget, &props));
    fCanvas.reset(new SkCanvas(fGpuDevice));
}

void SkGLWidget::resizeGL(int w, int h) {
    SkASSERT(w == this->width() && h == this->height());
    this->createRenderTarget();
}

void SkGLWidget::paintGL() {
    if (!this->isHidden() && fCanvas) {
        fCurContext->resetContext();
        fDebugger->draw(fCanvas.get());
        // TODO(chudy): Implement an optional flush button in Gui.
        fCanvas->flush();
        emit drawComplete();
    }
}

GrBackendRenderTargetDesc SkGLWidget::getDesc(int w, int h) {
    GrBackendRenderTargetDesc desc;
    desc.fWidth = SkScalarRoundToInt(this->width());
    desc.fHeight = SkScalarRoundToInt(this->height());
    desc.fConfig = kSkia8888_GrPixelConfig;
    GR_GL_GetIntegerv(fCurIntf, GR_GL_SAMPLES, &desc.fSampleCnt);
    GR_GL_GetIntegerv(fCurIntf, GR_GL_STENCIL_BITS, &desc.fStencilBits);
    GrGLint buffer;
    GR_GL_GetIntegerv(fCurIntf, GR_GL_FRAMEBUFFER_BINDING, &buffer);
    desc.fRenderTargetHandle = buffer;

    return desc;
}

#endif
<|endoftext|>


<commit_before>//===--- llvm-as.cpp - The low-level LLVM assembler -----------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This utility may be invoked in the following manner:
//   llvm-as --help         - Output information about command line switches
//   llvm-as [options]      - Read LLVM asm from stdin, write bytecode to stdout
//   llvm-as [options] x.ll - Read LLVM asm from the x.ll file, write bytecode
//                            to the x.bc file.
//
//===------------------------------------------------------------------------===

#include "llvm/Module.h"
#include "llvm/Assembly/Parser.h"
#include "llvm/Bytecode/Writer.h"
#include "llvm/Analysis/Verifier.h"
#include "Support/CommandLine.h"
#include "llvm/System/Signals.h"
#include <fstream>
#include <iostream>
#include <memory>

using namespace llvm;

static cl::opt<std::string>
InputFilename(cl::Positional, cl::desc("<input .llvm file>"), cl::init("-"));

static cl::opt<std::string>
OutputFilename("o", cl::desc("Override output filename"),
               cl::value_desc("filename"));

static cl::opt<bool>
Force("f", cl::desc("Overwrite output files"));

static cl::opt<bool>
DumpAsm("d", cl::desc("Print assembly as parsed"), cl::Hidden);

static cl::opt<bool>
DisableVerify("disable-verify", cl::Hidden,
              cl::desc("Do not run verifier on input LLVM (dangerous!)"));

int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv, " llvm .ll -> .bc assembler\n");
  PrintStackTraceOnErrorSignal();

  std::ostream *Out = 0;
  try {
    // Parse the file now...
    std::auto_ptr<Module> M(ParseAssemblyFile(InputFilename));
    if (M.get() == 0) {
      std::cerr << argv[0] << ": assembly didn't read correctly.\n";
      return 1;
    }

    if (!DisableVerify && verifyModule(*M.get())) {
      std::cerr << argv[0]
                << ": assembly parsed, but does not verify as correct!\n";
      return 1;
    }

    if (DumpAsm) std::cerr << "Here's the assembly:\n" << M.get();

    if (OutputFilename != "") {   // Specified an output filename?
      if (OutputFilename != "-") {  // Not stdout?
        if (!Force && std::ifstream(OutputFilename.c_str())) {
          // If force is not specified, make sure not to overwrite a file!
          std::cerr << argv[0] << ": error opening '" << OutputFilename
                    << "': file exists!\n"
                    << "Use -f command line argument to force output\n";
          return 1;
        }
        Out = new std::ofstream(OutputFilename.c_str(), std::ios_base::out |
                                std::ios_base::trunc | std::ios_base::binary);
      } else {                      // Specified stdout
	Out = &std::cout;
      }
    } else {
      if (InputFilename == "-") {
	OutputFilename = "-";
	Out = &std::cout;
      } else {
	std::string IFN = InputFilename;
	int Len = IFN.length();
	if (IFN[Len-3] == '.' && IFN[Len-2] == 'l' && IFN[Len-1] == 'l') {
	  // Source ends in .ll
	  OutputFilename = std::string(IFN.begin(), IFN.end()-3);
        } else {
	  OutputFilename = IFN;   // Append a .bc to it
	}
	OutputFilename += ".bc";

        if (!Force && std::ifstream(OutputFilename.c_str())) {
          // If force is not specified, make sure not to overwrite a file!
          std::cerr << argv[0] << ": error opening '" << OutputFilename
                    << "': file exists!\n"
                    << "Use -f command line argument to force output\n";
          return 1;
        }

	Out = new std::ofstream(OutputFilename.c_str(), std::ios_base::out |
                                std::ios_base::trunc | std::ios_base::binary);
        // Make sure that the Out file gets unlinked from the disk if we get a
        // SIGINT
        RemoveFileOnSignal(OutputFilename);
      }
    }

    if (!Out->good()) {
      std::cerr << argv[0] << ": error opening " << OutputFilename << "!\n";
      return 1;
    }

    WriteBytecodeToFile(M.get(), *Out);
  } catch (const ParseException &E) {
    std::cerr << argv[0] << ": " << E.getMessage() << "\n";
    return 1;
  }

  if (Out != &std::cout) delete Out;
  return 0;
}

<commit_msg>There is no reason to abort and print a stack trace if there is a verification error.  Just print the message like a good little tool.<commit_after>//===--- llvm-as.cpp - The low-level LLVM assembler -----------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This utility may be invoked in the following manner:
//   llvm-as --help         - Output information about command line switches
//   llvm-as [options]      - Read LLVM asm from stdin, write bytecode to stdout
//   llvm-as [options] x.ll - Read LLVM asm from the x.ll file, write bytecode
//                            to the x.bc file.
//
//===------------------------------------------------------------------------===

#include "llvm/Module.h"
#include "llvm/Assembly/Parser.h"
#include "llvm/Bytecode/Writer.h"
#include "llvm/Analysis/Verifier.h"
#include "Support/CommandLine.h"
#include "llvm/System/Signals.h"
#include <fstream>
#include <iostream>
#include <memory>

using namespace llvm;

static cl::opt<std::string>
InputFilename(cl::Positional, cl::desc("<input .llvm file>"), cl::init("-"));

static cl::opt<std::string>
OutputFilename("o", cl::desc("Override output filename"),
               cl::value_desc("filename"));

static cl::opt<bool>
Force("f", cl::desc("Overwrite output files"));

static cl::opt<bool>
DumpAsm("d", cl::desc("Print assembly as parsed"), cl::Hidden);

static cl::opt<bool>
DisableVerify("disable-verify", cl::Hidden,
              cl::desc("Do not run verifier on input LLVM (dangerous!)"));

int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv, " llvm .ll -> .bc assembler\n");
  PrintStackTraceOnErrorSignal();

  std::ostream *Out = 0;
  try {
    // Parse the file now...
    std::auto_ptr<Module> M(ParseAssemblyFile(InputFilename));
    if (M.get() == 0) {
      std::cerr << argv[0] << ": assembly didn't read correctly.\n";
      return 1;
    }

    if (!DisableVerify && verifyModule(*M.get(), PrintMessageAction)) {
      std::cerr << argv[0]
                << ": assembly parsed, but does not verify as correct!\n";
      return 1;
    }

    if (DumpAsm) std::cerr << "Here's the assembly:\n" << M.get();

    if (OutputFilename != "") {   // Specified an output filename?
      if (OutputFilename != "-") {  // Not stdout?
        if (!Force && std::ifstream(OutputFilename.c_str())) {
          // If force is not specified, make sure not to overwrite a file!
          std::cerr << argv[0] << ": error opening '" << OutputFilename
                    << "': file exists!\n"
                    << "Use -f command line argument to force output\n";
          return 1;
        }
        Out = new std::ofstream(OutputFilename.c_str(), std::ios_base::out |
                                std::ios_base::trunc | std::ios_base::binary);
      } else {                      // Specified stdout
	Out = &std::cout;
      }
    } else {
      if (InputFilename == "-") {
	OutputFilename = "-";
	Out = &std::cout;
      } else {
	std::string IFN = InputFilename;
	int Len = IFN.length();
	if (IFN[Len-3] == '.' && IFN[Len-2] == 'l' && IFN[Len-1] == 'l') {
	  // Source ends in .ll
	  OutputFilename = std::string(IFN.begin(), IFN.end()-3);
        } else {
	  OutputFilename = IFN;   // Append a .bc to it
	}
	OutputFilename += ".bc";

        if (!Force && std::ifstream(OutputFilename.c_str())) {
          // If force is not specified, make sure not to overwrite a file!
          std::cerr << argv[0] << ": error opening '" << OutputFilename
                    << "': file exists!\n"
                    << "Use -f command line argument to force output\n";
          return 1;
        }

	Out = new std::ofstream(OutputFilename.c_str(), std::ios_base::out |
                                std::ios_base::trunc | std::ios_base::binary);
        // Make sure that the Out file gets unlinked from the disk if we get a
        // SIGINT
        RemoveFileOnSignal(OutputFilename);
      }
    }

    if (!Out->good()) {
      std::cerr << argv[0] << ": error opening " << OutputFilename << "!\n";
      return 1;
    }

    WriteBytecodeToFile(M.get(), *Out);
  } catch (const ParseException &E) {
    std::cerr << argv[0] << ": " << E.getMessage() << "\n";
    return 1;
  }

  if (Out != &std::cout) delete Out;
  return 0;
}

<|endoftext|>


<commit_before><commit_msg>mipgen:  Disambiguated string with std:: prefix. (#741)<commit_after><|endoftext|>


<commit_before>#include <iostream>
#include <vector>
#include <string>
#include <cstring>
#include <stdlib.h>
#include <sstream>

int main(int argc, char** argv)
{
	std::vector<std::string> gccArgs;
	std::string source;
	std::string outfile;

	if(argc <= 1)
	{
		return system("g++");
	}

	for(int i = 1; i < argc; i++)
	{
		if(strstr(argv[i], "-gencode")
			|| strstr(argv[i], "-X")
			|| strstr(argv[i], "-arch"))
			continue;

		if(!strcmp("-o", argv[i]) && i < argc - 1)
		{
			outfile = argv[++i];
			continue;
		}
		else if(!strcmp("-isystem", argv[i]))
		{
			gccArgs.push_back("-I");
			continue;
		}

		gccArgs.push_back(argv[i]);
	}

	std::stringstream args;
	if(gccArgs.empty())
	{
		return 1;
	}

	source = gccArgs.back();
	gccArgs.pop_back();

	for(auto& s : gccArgs)
		args << " " << s;

	args << " -I/usr/include -I/usr/include/cudalibre -lOpenCL -Wl,-rpath=. -lclruntime";

	std::string culccArgs = "culcc ";

	// produces something like "culcc <source> -o <out> -- <some args>"
	culccArgs += source + " -o " + source + ".cpp -- " + args.str();

	if(system(culccArgs.c_str()))
	{
		std::cerr << "Could not preprocess CUDA file!" << std::endl;
		return 1;
	}

	// Add source file here so it does not interfere with the culccArgs earlier

	if(!outfile.empty())
		args << " -o " << outfile;

	args << " " << source << ".cpp";
	return system(("g++ " + args.str()).c_str());
}<commit_msg>* Improved culccd argument handling<commit_after>#include <cstring>
#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <string>
#include <vector>
#include <regex>

/// Some default flags so gcc and culcc can find headers and libraries
const std::string g_defaultFlags =
"-I/usr/include -I/usr/include/cudalibre -lOpenCL -Wl,-rpath=. -lclruntime";

// Switch-case on strings
#define SWITCH(x) { auto value = (x); if(false) {
#define CASE(x) } else if(std::regex_match(value, std::regex(x))) {
#define DEFAULT  } else {
#define IGNORE(x) CASE(x){}
#define HCTIWS }}

void usage(const char* name)
{
	std::cout << name << " [options] <source>" << std::endl;
	std::cout << "\t" << std::endl;
}

bool isArgnameEq(const char* name, const char* str)
{
	std::regex e(name);
	return !strcmp(name, str) || (*str == '-' && !strcmp(name, str+1));
}

struct Arguments
{
	std::string output;
	std::string input;
	bool hasC;
	bool verbose;
};

void parseArgs(int argc,
	       char** argv,
	       std::stringstream& culccArgs,
	       std::stringstream& gccArgs,
	       Arguments& args)
{
	args.hasC = false;
	args.verbose = false;

	for(size_t i = 1; i < argc - 1; i++)
	{
		char* arg = argv[i];

		SWITCH(arg)
			IGNORE("-?-cuda")
			IGNORE("-?-gencode=.*")
			IGNORE("-X.*")
			IGNORE("-arch.*")
			CASE("-isystem.*")
			{
				gccArgs << "-I" << argv[++i] << " ";
			}
			CASE("-c|-?-compile")
			{
				args.hasC = true;
			}
			CASE("-o")
			{
				if(++i < argc)
				{
					args.output = argv[i];
				}
				else
				{
					std::cerr << "-o expects an argument!" << std::endl;
					exit(1);
				}
			}
			CASE("-v|-?-verbose")
			{
				args.verbose = true;
			}
			DEFAULT
			{
				gccArgs << arg << " ";
			}
		HCTIWS
	}

	args.input = argv[argc - 1];

	gccArgs << g_defaultFlags;
	culccArgs << " -- " << gccArgs.str();
}

int main(int argc, char** argv)
{
	if (argc <= 1)
	{
		usage(argv[0]);
		return 0;
	}

	std::stringstream culccArgs, gccArgs;
	Arguments args;
	parseArgs(argc, argv, culccArgs, gccArgs, args);

	// produces something like "culcc <source> -o <out> -- <some args>"
	std::string command = "culcc " + args.input + " -o " + args.input + ".cpp" + culccArgs.str();
	if(args.verbose)
		std::cout << command << std::endl;

	if (system(command.c_str()))
	{
		std::cerr << "Could not preprocess CUDA file!" << std::endl;
		return 1;
	}

	// Add source file here so it does not interfere with the culccArgs earlier

	if (!args.output.empty())
		gccArgs << " -o " << args.output;

	gccArgs << " " << (args.hasC ? "-c " : "") << args.input << ".cpp";

	command = "g++ " + gccArgs.str();
	if(args.verbose)
		std::cout << command << std::endl;

	return system(command.c_str());
}
<|endoftext|>


<commit_before>// sg_path.cxx -- routines to abstract out path separator differences
//               between MacOS and the rest of the world
//
// Written by Curtis L. Olson, started April 1999.
//
// Copyright (C) 1999  Curtis L. Olson - curt@flightgear.org
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
// Boston, MA  02111-1307, USA.
//
// $Id$

#include <simgear_config.h>
#include <stdio.h>

#include "sg_path.hxx"

// If Unix, replace all ":" with "/".  If MacOS, replace all "/" with
// ":" it should go without saying that neither of these characters
// should be used in file or directory names.  In windoze, allow the
// second character to be a ":" for things like c:\foo\bar

void
SGPath::fix()
{
    for ( string::size_type i = 0; i < path.size(); ++i ) {
#if defined( WIN32 )
	// for windoze, don't replace the ":" for the second character
	if ( i == 1 ) {
	    continue;
	}
#endif
	if ( path[i] == SG_BAD_PATH_SEP ) {
	    path[i] = SG_PATH_SEP;
	}
    }
}

// default constructor
SGPath::SGPath()
    : path("")
{
}

// create a path based on "path"
SGPath::SGPath( const std::string& p )
    : path(p)
{
    fix();
}

// destructor
SGPath::~SGPath() {
}

// set path
void SGPath::set( const string& p ) {
    path = p;
    fix();
}

// append another piece to the existing path
void SGPath::append( const string& p ) {
    if ( path.size() == 0 ) {
	path = p;
    } else {
	if ( p[0] != SG_PATH_SEP ) {
	    path += SG_PATH_SEP;
	}
	path += p;
    }
    fix();
}

// concatenate a string to the end of the path without inserting a
// path separator
void SGPath::concat( const string& p ) {
    if ( path.size() == 0 ) {
	path = p;
    } else {
	path += p;
    }
    fix();
}

// get the directory part of the path.
string SGPath::dir() {
    int index = path.rfind(SG_PATH_SEP);
    if (index >= 0) {
	return path.substr(0, index);
    } else {
	return "";
    }
}

bool SGPath::exists() const {
    FILE* fp = fopen( path.c_str(), "r");
    if (fp == 0) {
	return false;
    }
    fclose(fp);
    return true;
}
<commit_msg>Oops, missed this the first time.<commit_after>// sg_path.cxx -- routines to abstract out path separator differences
//               between MacOS and the rest of the world
//
// Written by Curtis L. Olson, started April 1999.
//
// Copyright (C) 1999  Curtis L. Olson - curt@flightgear.org
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
// Boston, MA  02111-1307, USA.
//
// $Id$

#include <simgear_config.h>
#include <stdio.h>

#include "sg_path.hxx"

// If Unix, replace all ":" with "/".  If MacOS, replace all "/" with
// ":" it should go without saying that neither of these characters
// should be used in file or directory names.  In windoze, allow the
// second character to be a ":" for things like c:\foo\bar

void
SGPath::fix()
{
    for ( string::size_type i = 0; i < path.size(); ++i ) {
#if defined( WIN32 )
	// for windoze, don't replace the ":" for the second character
	if ( i == 1 ) {
	    continue;
	}
#endif
	if ( path[i] == SG_BAD_PATH_SEP ) {
	    path[i] = SG_PATH_SEP;
	}
    }
}

// default constructor
SGPath::SGPath()
    : path("")
{
}

// create a path based on "path"
SGPath::SGPath( const std::string& p )
    : path(p)
{
    fix();
}

// destructor
SGPath::~SGPath() {
}

// set path
void SGPath::set( const string& p ) {
    path = p;
    fix();
}

// append another piece to the existing path
void SGPath::append( const string& p ) {
    if ( path.size() == 0 ) {
	path = p;
    } else {
	if ( p[0] != SG_PATH_SEP ) {
	    path += SG_PATH_SEP;
	}
	path += p;
    }
    fix();
}

// concatenate a string to the end of the path without inserting a
// path separator
void SGPath::concat( const string& p ) {
    if ( path.size() == 0 ) {
	path = p;
    } else {
	path += p;
    }
    fix();
}

// get the directory part of the path.
string SGPath::dir() {
    int index = path.rfind(SG_PATH_SEP);
    if (index >= 0) {
	return path.substr(0, index);
    } else {
	return "";
    }
}

string SGPath::filename() {
    int index = path.rfind(SG_PATH_SEP);
    if (index < 0) index = 0;
    return path.substr(index);
}

bool SGPath::exists() const {
    FILE* fp = fopen( path.c_str(), "r");
    if (fp == 0) {
	return false;
    }
    fclose(fp);
    return true;
}
<|endoftext|>


<commit_before>//===----------------------- LSUnit.cpp --------------------------*- C++-*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/// \file
///
/// A Load-Store Unit for the llvm-mca tool.
///
//===----------------------------------------------------------------------===//

#include "LSUnit.h"
#include "Instruction.h"

#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

#define DEBUG_TYPE "llvm-mca"

namespace mca {

#ifndef NDEBUG
void LSUnit::dump() const {
  dbgs() << "[LSUnit] LQ_Size = " << LQ_Size << '\n';
  dbgs() << "[LSUnit] SQ_Size = " << SQ_Size << '\n';
  dbgs() << "[LSUnit] NextLQSlotIdx = " << LoadQueue.size() << '\n';
  dbgs() << "[LSUnit] NextSQSlotIdx = " << StoreQueue.size() << '\n';
}
#endif

void LSUnit::assignLQSlot(unsigned Index) {
  assert(!isLQFull());
  assert(LoadQueue.count(Index) == 0);

  LLVM_DEBUG(dbgs() << "[LSUnit] - AssignLQSlot <Idx=" << Index
                    << ",slot=" << LoadQueue.size() << ">\n");
  LoadQueue.insert(Index);
}

void LSUnit::assignSQSlot(unsigned Index) {
  assert(!isSQFull());
  assert(StoreQueue.count(Index) == 0);

  LLVM_DEBUG(dbgs() << "[LSUnit] - AssignSQSlot <Idx=" << Index
                    << ",slot=" << StoreQueue.size() << ">\n");
  StoreQueue.insert(Index);
}

bool LSUnit::reserve(const InstRef &IR) {
  const InstrDesc Desc = IR.getInstruction()->getDesc();
  unsigned MayLoad = Desc.MayLoad;
  unsigned MayStore = Desc.MayStore;
  unsigned IsMemBarrier = Desc.HasSideEffects;
  if (!MayLoad && !MayStore)
    return false;

  const unsigned Index = IR.getSourceIndex();
  if (MayLoad) {
    if (IsMemBarrier)
      LoadBarriers.insert(Index);
    assignLQSlot(Index);
  }
  if (MayStore) {
    if (IsMemBarrier)
      StoreBarriers.insert(Index);
    assignSQSlot(Index);
  }
  return true;
}

bool LSUnit::isReady(const InstRef &IR) const {
  const unsigned Index = IR.getSourceIndex();
  bool IsALoad = LoadQueue.count(Index) != 0;
  bool IsAStore = StoreQueue.count(Index) != 0;
  assert((IsALoad || IsAStore) && "Instruction is not in queue!");

  if (IsALoad && !LoadBarriers.empty()) {
    unsigned LoadBarrierIndex = *LoadBarriers.begin();
    if (Index > LoadBarrierIndex)
      return false;
    if (Index == LoadBarrierIndex && Index != *LoadQueue.begin())
      return false;
  }

  if (IsAStore && !StoreBarriers.empty()) {
    unsigned StoreBarrierIndex = *StoreBarriers.begin();
    if (Index > StoreBarrierIndex)
      return false;
    if (Index == StoreBarrierIndex && Index != *StoreQueue.begin())
      return false;
  }

  if (NoAlias && IsALoad)
    return true;

  if (StoreQueue.size()) {
    // Check if this memory operation is younger than the older store.
    if (Index > *StoreQueue.begin())
      return false;
  }

  // Okay, we are older than the oldest store in the queue.
  // If there are no pending loads, then we can say for sure that this
  // instruction is ready.
  if (isLQEmpty())
    return true;

  // Check if there are no older loads.
  if (Index <= *LoadQueue.begin())
    return true;

  // There is at least one younger load.
  return !IsAStore;
}

void LSUnit::onInstructionExecuted(const InstRef &IR) {
  const unsigned Index = IR.getSourceIndex();
  std::set<unsigned>::iterator it = LoadQueue.find(Index);
  if (it != LoadQueue.end()) {
    LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << Index
                      << " has been removed from the load queue.\n");
    LoadQueue.erase(it);
  }

  it = StoreQueue.find(Index);
  if (it != StoreQueue.end()) {
    LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << Index
                      << " has been removed from the store queue.\n");
    StoreQueue.erase(it);
  }

  if (!StoreBarriers.empty() && Index == *StoreBarriers.begin()) {
    LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << Index
                      << " has been removed from the set of store barriers.\n");
    StoreBarriers.erase(StoreBarriers.begin());
  }
  if (!LoadBarriers.empty() && Index == *LoadBarriers.begin()) {
    LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << Index
                      << " has been removed from the set of load barriers.\n");
    LoadBarriers.erase(LoadBarriers.begin());
  }
}
} // namespace mca
<commit_msg>[MCA] Avoid an InstrDesc copy in mca::LSUnit::reserve.<commit_after>//===----------------------- LSUnit.cpp --------------------------*- C++-*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/// \file
///
/// A Load-Store Unit for the llvm-mca tool.
///
//===----------------------------------------------------------------------===//

#include "LSUnit.h"
#include "Instruction.h"

#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

#define DEBUG_TYPE "llvm-mca"

namespace mca {

#ifndef NDEBUG
void LSUnit::dump() const {
  dbgs() << "[LSUnit] LQ_Size = " << LQ_Size << '\n';
  dbgs() << "[LSUnit] SQ_Size = " << SQ_Size << '\n';
  dbgs() << "[LSUnit] NextLQSlotIdx = " << LoadQueue.size() << '\n';
  dbgs() << "[LSUnit] NextSQSlotIdx = " << StoreQueue.size() << '\n';
}
#endif

void LSUnit::assignLQSlot(unsigned Index) {
  assert(!isLQFull());
  assert(LoadQueue.count(Index) == 0);

  LLVM_DEBUG(dbgs() << "[LSUnit] - AssignLQSlot <Idx=" << Index
                    << ",slot=" << LoadQueue.size() << ">\n");
  LoadQueue.insert(Index);
}

void LSUnit::assignSQSlot(unsigned Index) {
  assert(!isSQFull());
  assert(StoreQueue.count(Index) == 0);

  LLVM_DEBUG(dbgs() << "[LSUnit] - AssignSQSlot <Idx=" << Index
                    << ",slot=" << StoreQueue.size() << ">\n");
  StoreQueue.insert(Index);
}

bool LSUnit::reserve(const InstRef &IR) {
  const InstrDesc &Desc = IR.getInstruction()->getDesc();
  unsigned MayLoad = Desc.MayLoad;
  unsigned MayStore = Desc.MayStore;
  unsigned IsMemBarrier = Desc.HasSideEffects;
  if (!MayLoad && !MayStore)
    return false;

  const unsigned Index = IR.getSourceIndex();
  if (MayLoad) {
    if (IsMemBarrier)
      LoadBarriers.insert(Index);
    assignLQSlot(Index);
  }
  if (MayStore) {
    if (IsMemBarrier)
      StoreBarriers.insert(Index);
    assignSQSlot(Index);
  }
  return true;
}

bool LSUnit::isReady(const InstRef &IR) const {
  const unsigned Index = IR.getSourceIndex();
  bool IsALoad = LoadQueue.count(Index) != 0;
  bool IsAStore = StoreQueue.count(Index) != 0;
  assert((IsALoad || IsAStore) && "Instruction is not in queue!");

  if (IsALoad && !LoadBarriers.empty()) {
    unsigned LoadBarrierIndex = *LoadBarriers.begin();
    if (Index > LoadBarrierIndex)
      return false;
    if (Index == LoadBarrierIndex && Index != *LoadQueue.begin())
      return false;
  }

  if (IsAStore && !StoreBarriers.empty()) {
    unsigned StoreBarrierIndex = *StoreBarriers.begin();
    if (Index > StoreBarrierIndex)
      return false;
    if (Index == StoreBarrierIndex && Index != *StoreQueue.begin())
      return false;
  }

  if (NoAlias && IsALoad)
    return true;

  if (StoreQueue.size()) {
    // Check if this memory operation is younger than the older store.
    if (Index > *StoreQueue.begin())
      return false;
  }

  // Okay, we are older than the oldest store in the queue.
  // If there are no pending loads, then we can say for sure that this
  // instruction is ready.
  if (isLQEmpty())
    return true;

  // Check if there are no older loads.
  if (Index <= *LoadQueue.begin())
    return true;

  // There is at least one younger load.
  return !IsAStore;
}

void LSUnit::onInstructionExecuted(const InstRef &IR) {
  const unsigned Index = IR.getSourceIndex();
  std::set<unsigned>::iterator it = LoadQueue.find(Index);
  if (it != LoadQueue.end()) {
    LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << Index
                      << " has been removed from the load queue.\n");
    LoadQueue.erase(it);
  }

  it = StoreQueue.find(Index);
  if (it != StoreQueue.end()) {
    LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << Index
                      << " has been removed from the store queue.\n");
    StoreQueue.erase(it);
  }

  if (!StoreBarriers.empty() && Index == *StoreBarriers.begin()) {
    LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << Index
                      << " has been removed from the set of store barriers.\n");
    StoreBarriers.erase(StoreBarriers.begin());
  }
  if (!LoadBarriers.empty() && Index == *LoadBarriers.begin()) {
    LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << Index
                      << " has been removed from the set of load barriers.\n");
    LoadBarriers.erase(LoadBarriers.begin());
  }
}
} // namespace mca
<|endoftext|>


<commit_before>//===-- Immediate.cpp - the swift immediate mode --------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This is the implementation of the swift interpreter, which takes a
// TranslationUnit and JITs it.
//
//===----------------------------------------------------------------------===//

#include "Immediate.h"
#include "Frontend.h"
#include "swift/Subsystems.h"
#include "swift/IRGen/Options.h"
#include "swift/Parse/Lexer.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Component.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Diagnostics.h"
#include "swift/AST/Module.h"
#include "swift/AST/Stmt.h"
#include "swift/Basic/DiagnosticConsumer.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/system_error.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Linker.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"

#include <histedit.h>
#include <dlfcn.h>

static void LoadSwiftRuntime() {
  // FIXME: Need error-checking.
  llvm::sys::Path LibPath =
      llvm::sys::Path::GetMainExecutable(0, (void*)&swift::RunImmediately);
  LibPath.eraseComponent();
  LibPath.eraseComponent();
  LibPath.appendComponent("lib");
  LibPath.appendComponent("libswift_abi.dylib");
  dlopen(LibPath.c_str(), 0);
}

void swift::RunImmediately(TranslationUnit *TU) {
  ASTContext &Context = TU->Ctx;
  irgen::Options Options;
  Options.OutputFilename = "";
  Options.Triple = llvm::sys::getDefaultTargetTriple();
  Options.OptLevel = 0;
  Options.OutputKind = irgen::OutputKind::Module;

  // IRGen the main module.
  llvm::LLVMContext LLVMContext;
  llvm::Module Module(TU->Name.str(), LLVMContext);
  performCaptureAnalysis(TU);
  performIRGeneration(Options, &Module, TU);

  if (Context.hadError())
    return;

  llvm::SmallPtrSet<TranslationUnit*, 8> ImportedModules;
  llvm::SmallVector<llvm::Function*, 4> InitFuncs;
  // IRGen the modules this module depends on.
  for (auto ModPair : TU->getImportedModules()) {
    if (isa<BuiltinModule>(ModPair.second))
      continue;

    TranslationUnit *SubTU = cast<TranslationUnit>(ModPair.second);
    if (!ImportedModules.insert(SubTU))
      continue;

    // FIXME: Need to check whether this is actually safe in general.
    llvm::Module SubModule(SubTU->Name.str(), LLVMContext);
    performCaptureAnalysis(SubTU);
    performIRGeneration(Options, &SubModule, SubTU);

    if (Context.hadError())
      return;

    std::string ErrorMessage;
    if (llvm::Linker::LinkModules(&Module, &SubModule,
                                  llvm::Linker::DestroySource,
                                  &ErrorMessage)) {
      llvm::errs() << "Error linking swift modules\n";
      llvm::errs() << ErrorMessage << "\n";
      return;
    }

    // FIXME: This is an ugly hack; need to figure out how this should
    // actually work.
    SmallVector<char, 20> NameBuf;
    StringRef InitFnName = (SubTU->Name.str() + ".init").toStringRef(NameBuf);
    llvm::Function *InitFn = Module.getFunction(InitFnName);
    if (InitFn)
      InitFuncs.push_back(InitFn);
  }

  LoadSwiftRuntime();

  // Run the generated program.

  llvm::EngineBuilder builder(&Module);
  std::string ErrorMsg;
  builder.setErrorStr(&ErrorMsg);
  builder.setEngineKind(llvm::EngineKind::JIT);

  llvm::ExecutionEngine *EE = builder.create();
  for (auto InitFn : InitFuncs)
    EE->runFunctionAsMain(InitFn, std::vector<std::string>(), 0);

  llvm::Function *EntryFn = Module.getFunction("main");
  EE->runFunctionAsMain(EntryFn, std::vector<std::string>(), 0);
}

struct EditLineWrapper {
  EditLine *e;
  size_t PromptContinuationLevel;

  llvm::SmallString<80> PromptString;

  EditLineWrapper() {
    e = el_init("swift", stdin, stdout, stderr);
    PromptContinuationLevel = 0;
    el_set(e, EL_EDITOR, "emacs");
    el_set(e, EL_PROMPT, PromptFn);
    el_set(e, EL_CLIENTDATA, (void*)this);
  }

  static char *PromptFn(EditLine *e) {
    void* clientdata;
    el_get(e, EL_CLIENTDATA, &clientdata);
    return (char*)((EditLineWrapper*)clientdata)->getPrompt();
  }

  const char *getPrompt() {
    if (PromptContinuationLevel == 0)
      return "swift> ";

    PromptString = "swift| ";
    PromptString.append(2*PromptContinuationLevel, ' ');
    return PromptString.c_str();
  };

  ~EditLineWrapper() {
    el_end(e);
  }
  operator EditLine*() { return e; }
};

void swift::REPL(ASTContext &Context) {
  if (llvm::sys::Process::FileDescriptorIsDisplayed(2))
    llvm::errs() << "Welcome to swift.  Type 'help' for assistance.\n";

  // FIXME: We should do something a bit more elaborate than
  // "allocate a 1MB buffer and hope it's enough".
  llvm::MemoryBuffer *Buffer =
      llvm::MemoryBuffer::getNewMemBuffer(1 << 20, "<REPL Buffer>");

  Component *Comp = new (Context.Allocate<Component>(1)) Component();
  unsigned BufferID =
    Context.SourceMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc());
  Identifier ID = Context.getIdentifier("REPL");
  TranslationUnit *TU = new (Context) TranslationUnit(ID, Comp, Context,
                                                      /*IsMainModule=*/true,
                                                      /*IsReplModule=*/true);

  llvm::SmallPtrSet<TranslationUnit*, 8> ImportedModules;
  llvm::LLVMContext LLVMContext;
  llvm::Module Module("REPL", LLVMContext);
  std::string ErrorMessage;

  LoadSwiftRuntime();

  llvm::EngineBuilder builder(&Module);
  std::string ErrorMsg;
  builder.setErrorStr(&ErrorMsg);
  builder.setEngineKind(llvm::EngineKind::JIT);
  llvm::ExecutionEngine *EE = builder.create();

  irgen::Options Options;
  Options.OutputFilename = "";
  Options.Triple = llvm::sys::getDefaultTargetTriple();
  Options.OptLevel = 0;
  Options.OutputKind = irgen::OutputKind::Module;
  Options.IsREPL = true;

  EditLineWrapper e;

  char* CurBuffer = const_cast<char*>(Buffer->getBufferStart());
  unsigned CurBufferOffset = 0;
  unsigned CurBufferEndOffset = 0;

  unsigned CurTUElem = 0;
  unsigned BraceCount = 0;
  unsigned CurChunkLines = 0;

  while (1) {
    // Read one line.
    e.PromptContinuationLevel = BraceCount;
    int LineCount;
    const char* Line = el_gets(e, &LineCount);
    if (!Line)
      return;

    strcpy(CurBuffer, Line);
    CurBuffer += strlen(Line);
    CurBufferEndOffset += strlen(Line);
    ++CurChunkLines;

    // If we detect unbalanced braces, keep reading before we start parsing.
    Lexer L(Line, Context.SourceMgr, nullptr);
    Token Tok;
    do {
      L.lex(Tok);
      if (Tok.is(tok::l_brace))
        ++BraceCount;
      else if (Tok.is(tok::r_brace) && BraceCount > 0)
        --BraceCount;
    } while (!Tok.is(tok::eof));

    if (BraceCount)
      continue;

    // Parse the current line(s).
    bool ShouldRun =
        swift::appendToMainTranslationUnit(TU, BufferID, CurTUElem,
                                           CurBufferOffset,
                                           CurBufferEndOffset);

    if (Context.hadError()) {
      Context.Diags.resetHadAnyError();
      while (TU->Decls.size() > CurTUElem)
        TU->Decls.pop_back();
      TU->clearUnresolvedIdentifierTypes();

      // FIXME: Handling of "import" declarations?  Is there any other
      // state which needs to be reset?

      if (CurChunkLines > 1)
        llvm::errs() << "(discarded " << CurChunkLines << " lines)\n";
      CurChunkLines = 0;
      continue;
    }

    // If we didn't see an expression, statement, or decl which might have
    // side-effects, keep reading.
    if (!ShouldRun)
      continue;

    // IRGen the current line(s).
    llvm::Module LineModule("REPLLine", LLVMContext);
    performCaptureAnalysis(TU, CurTUElem);
    performIRGeneration(Options, &LineModule, TU, CurTUElem);

    if (Context.hadError())
      return;

    CurTUElem = TU->Decls.size();
    CurChunkLines = 0;

    if (llvm::Linker::LinkModules(&Module, &LineModule,
                                  llvm::Linker::DestroySource,
                                  &ErrorMessage)) {
      llvm::errs() << "Error linking swift modules\n";
      llvm::errs() << ErrorMessage << "\n";
      return;
    }

    // IRGen the modules this module depends on.
    llvm::SmallVector<llvm::Function*, 4> InitFuncs;
    for (auto ModPair : TU->getImportedModules()) {
      if (isa<BuiltinModule>(ModPair.second))
        continue;

      TranslationUnit *SubTU = cast<TranslationUnit>(ModPair.second);
      if (!ImportedModules.insert(SubTU))
        continue;

      // FIXME: Need to check whether this is actually safe in general.
      llvm::Module SubModule(SubTU->Name.str(), LLVMContext);
      performCaptureAnalysis(SubTU);
      performIRGeneration(Options, &SubModule, SubTU);

      if (Context.hadError())
        return;

      if (llvm::Linker::LinkModules(&Module, &SubModule,
                                    llvm::Linker::DestroySource,
                                    &ErrorMessage)) {
        llvm::errs() << "Error linking swift modules\n";
        llvm::errs() << ErrorMessage << "\n";
        return;
      }

      // FIXME: This is an ugly hack; need to figure out how this should
      // actually work.
      SmallVector<char, 20> NameBuf;
      StringRef InitFnName = (SubTU->Name.str() + ".init").toStringRef(NameBuf);
      llvm::Function *InitFn = Module.getFunction(InitFnName);
      if (InitFn)
        InitFuncs.push_back(InitFn);
    }

    for (auto InitFn : InitFuncs)
      EE->runFunctionAsMain(InitFn, std::vector<std::string>(), 0);

    // FIXME: The way we do this is really ugly... we should be able to
    // improve this.
    llvm::Function *EntryFn = Module.getFunction("main");
    EE->runFunctionAsMain(EntryFn, std::vector<std::string>(), 0);
    EE->freeMachineCodeForFunction(EntryFn);
    EntryFn->eraseFromParent();
  }
}

// FIXME: We shouldn't be writing implemenetations for functions in the swift
// module in C, and this isn't really an ideal place to put those
// implementations.
extern "C" void _TSs5printFT3valNSs5Int64_T_(int64_t l) {
  printf("%lld", l);
}

extern "C" void _TSs5printFT3valNSs6Double_T_(double l) {
  printf("%f", l);
}

extern "C" void _TSs9printCharFT9characterNSs5Int64_T_(int64_t l) {
  printf("%c", (char)l);
}

extern "C" void _TSs5printFT3valNSs6String_T_(char* l) {
  printf("%s", l);
}

// func Strlen(value : Builtin.RawPointer) -> Int
extern "C" int64_t _TSs6StrlenFT5valuep_NSs5Int64(char* s) {
  return strlen(s);
}

// func [infix_left=190] + (lhs : String,
//                          rhs : String) -> String
extern "C" char* _TSsop1pFT3lhsNSs6String3rhsS__S_(char* lhs, char* rhs) {
   size_t ls = strlen(lhs);
   size_t rs = strlen(rhs);
   char* s = (char*)malloc(ls+rs+1);
   memcpy(s, lhs, ls);
   strcpy(s+ls, rhs);
   return s;
}

extern "C" bool _TNSs4Bool13getLogicValuefRS_FT_i1(bool* b) {
  return *b;
}

extern "C" void _TSs4exitFT8exitCodeNSs5Int64_T_(int64_t l) {
  exit(l);
}
<commit_msg>add a new UnsafePointerInt8 type, use it to implement String.size in swift instead of in C++.<commit_after>//===-- Immediate.cpp - the swift immediate mode --------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This is the implementation of the swift interpreter, which takes a
// TranslationUnit and JITs it.
//
//===----------------------------------------------------------------------===//

#include "Immediate.h"
#include "Frontend.h"
#include "swift/Subsystems.h"
#include "swift/IRGen/Options.h"
#include "swift/Parse/Lexer.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Component.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Diagnostics.h"
#include "swift/AST/Module.h"
#include "swift/AST/Stmt.h"
#include "swift/Basic/DiagnosticConsumer.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/system_error.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Linker.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"

#include <histedit.h>
#include <dlfcn.h>

static void LoadSwiftRuntime() {
  // FIXME: Need error-checking.
  llvm::sys::Path LibPath =
      llvm::sys::Path::GetMainExecutable(0, (void*)&swift::RunImmediately);
  LibPath.eraseComponent();
  LibPath.eraseComponent();
  LibPath.appendComponent("lib");
  LibPath.appendComponent("libswift_abi.dylib");
  dlopen(LibPath.c_str(), 0);
}

void swift::RunImmediately(TranslationUnit *TU) {
  ASTContext &Context = TU->Ctx;
  irgen::Options Options;
  Options.OutputFilename = "";
  Options.Triple = llvm::sys::getDefaultTargetTriple();
  Options.OptLevel = 0;
  Options.OutputKind = irgen::OutputKind::Module;

  // IRGen the main module.
  llvm::LLVMContext LLVMContext;
  llvm::Module Module(TU->Name.str(), LLVMContext);
  performCaptureAnalysis(TU);
  performIRGeneration(Options, &Module, TU);

  if (Context.hadError())
    return;

  llvm::SmallPtrSet<TranslationUnit*, 8> ImportedModules;
  llvm::SmallVector<llvm::Function*, 4> InitFuncs;
  // IRGen the modules this module depends on.
  for (auto ModPair : TU->getImportedModules()) {
    if (isa<BuiltinModule>(ModPair.second))
      continue;

    TranslationUnit *SubTU = cast<TranslationUnit>(ModPair.second);
    if (!ImportedModules.insert(SubTU))
      continue;

    // FIXME: Need to check whether this is actually safe in general.
    llvm::Module SubModule(SubTU->Name.str(), LLVMContext);
    performCaptureAnalysis(SubTU);
    performIRGeneration(Options, &SubModule, SubTU);

    if (Context.hadError())
      return;

    std::string ErrorMessage;
    if (llvm::Linker::LinkModules(&Module, &SubModule,
                                  llvm::Linker::DestroySource,
                                  &ErrorMessage)) {
      llvm::errs() << "Error linking swift modules\n";
      llvm::errs() << ErrorMessage << "\n";
      return;
    }

    // FIXME: This is an ugly hack; need to figure out how this should
    // actually work.
    SmallVector<char, 20> NameBuf;
    StringRef InitFnName = (SubTU->Name.str() + ".init").toStringRef(NameBuf);
    llvm::Function *InitFn = Module.getFunction(InitFnName);
    if (InitFn)
      InitFuncs.push_back(InitFn);
  }

  LoadSwiftRuntime();

  // Run the generated program.

  llvm::EngineBuilder builder(&Module);
  std::string ErrorMsg;
  builder.setErrorStr(&ErrorMsg);
  builder.setEngineKind(llvm::EngineKind::JIT);

  llvm::ExecutionEngine *EE = builder.create();
  for (auto InitFn : InitFuncs)
    EE->runFunctionAsMain(InitFn, std::vector<std::string>(), 0);

  llvm::Function *EntryFn = Module.getFunction("main");
  EE->runFunctionAsMain(EntryFn, std::vector<std::string>(), 0);
}

struct EditLineWrapper {
  EditLine *e;
  size_t PromptContinuationLevel;

  llvm::SmallString<80> PromptString;

  EditLineWrapper() {
    e = el_init("swift", stdin, stdout, stderr);
    PromptContinuationLevel = 0;
    el_set(e, EL_EDITOR, "emacs");
    el_set(e, EL_PROMPT, PromptFn);
    el_set(e, EL_CLIENTDATA, (void*)this);
  }

  static char *PromptFn(EditLine *e) {
    void* clientdata;
    el_get(e, EL_CLIENTDATA, &clientdata);
    return (char*)((EditLineWrapper*)clientdata)->getPrompt();
  }

  const char *getPrompt() {
    if (PromptContinuationLevel == 0)
      return "swift> ";

    PromptString = "swift| ";
    PromptString.append(2*PromptContinuationLevel, ' ');
    return PromptString.c_str();
  };

  ~EditLineWrapper() {
    el_end(e);
  }
  operator EditLine*() { return e; }
};

void swift::REPL(ASTContext &Context) {
  if (llvm::sys::Process::FileDescriptorIsDisplayed(2))
    llvm::errs() << "Welcome to swift.  Type 'help' for assistance.\n";

  // FIXME: We should do something a bit more elaborate than
  // "allocate a 1MB buffer and hope it's enough".
  llvm::MemoryBuffer *Buffer =
      llvm::MemoryBuffer::getNewMemBuffer(1 << 20, "<REPL Buffer>");

  Component *Comp = new (Context.Allocate<Component>(1)) Component();
  unsigned BufferID =
    Context.SourceMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc());
  Identifier ID = Context.getIdentifier("REPL");
  TranslationUnit *TU = new (Context) TranslationUnit(ID, Comp, Context,
                                                      /*IsMainModule=*/true,
                                                      /*IsReplModule=*/true);

  llvm::SmallPtrSet<TranslationUnit*, 8> ImportedModules;
  llvm::LLVMContext LLVMContext;
  llvm::Module Module("REPL", LLVMContext);
  std::string ErrorMessage;

  LoadSwiftRuntime();

  llvm::EngineBuilder builder(&Module);
  std::string ErrorMsg;
  builder.setErrorStr(&ErrorMsg);
  builder.setEngineKind(llvm::EngineKind::JIT);
  llvm::ExecutionEngine *EE = builder.create();

  irgen::Options Options;
  Options.OutputFilename = "";
  Options.Triple = llvm::sys::getDefaultTargetTriple();
  Options.OptLevel = 0;
  Options.OutputKind = irgen::OutputKind::Module;
  Options.IsREPL = true;

  EditLineWrapper e;

  char* CurBuffer = const_cast<char*>(Buffer->getBufferStart());
  unsigned CurBufferOffset = 0;
  unsigned CurBufferEndOffset = 0;

  unsigned CurTUElem = 0;
  unsigned BraceCount = 0;
  unsigned CurChunkLines = 0;

  while (1) {
    // Read one line.
    e.PromptContinuationLevel = BraceCount;
    int LineCount;
    const char* Line = el_gets(e, &LineCount);
    if (!Line)
      return;

    strcpy(CurBuffer, Line);
    CurBuffer += strlen(Line);
    CurBufferEndOffset += strlen(Line);
    ++CurChunkLines;

    // If we detect unbalanced braces, keep reading before we start parsing.
    Lexer L(Line, Context.SourceMgr, nullptr);
    Token Tok;
    do {
      L.lex(Tok);
      if (Tok.is(tok::l_brace))
        ++BraceCount;
      else if (Tok.is(tok::r_brace) && BraceCount > 0)
        --BraceCount;
    } while (!Tok.is(tok::eof));

    if (BraceCount)
      continue;

    // Parse the current line(s).
    bool ShouldRun =
        swift::appendToMainTranslationUnit(TU, BufferID, CurTUElem,
                                           CurBufferOffset,
                                           CurBufferEndOffset);

    if (Context.hadError()) {
      Context.Diags.resetHadAnyError();
      while (TU->Decls.size() > CurTUElem)
        TU->Decls.pop_back();
      TU->clearUnresolvedIdentifierTypes();

      // FIXME: Handling of "import" declarations?  Is there any other
      // state which needs to be reset?

      if (CurChunkLines > 1)
        llvm::errs() << "(discarded " << CurChunkLines << " lines)\n";
      CurChunkLines = 0;
      continue;
    }

    // If we didn't see an expression, statement, or decl which might have
    // side-effects, keep reading.
    if (!ShouldRun)
      continue;

    // IRGen the current line(s).
    llvm::Module LineModule("REPLLine", LLVMContext);
    performCaptureAnalysis(TU, CurTUElem);
    performIRGeneration(Options, &LineModule, TU, CurTUElem);

    if (Context.hadError())
      return;

    CurTUElem = TU->Decls.size();
    CurChunkLines = 0;

    if (llvm::Linker::LinkModules(&Module, &LineModule,
                                  llvm::Linker::DestroySource,
                                  &ErrorMessage)) {
      llvm::errs() << "Error linking swift modules\n";
      llvm::errs() << ErrorMessage << "\n";
      return;
    }

    // IRGen the modules this module depends on.
    llvm::SmallVector<llvm::Function*, 4> InitFuncs;
    for (auto ModPair : TU->getImportedModules()) {
      if (isa<BuiltinModule>(ModPair.second))
        continue;

      TranslationUnit *SubTU = cast<TranslationUnit>(ModPair.second);
      if (!ImportedModules.insert(SubTU))
        continue;

      // FIXME: Need to check whether this is actually safe in general.
      llvm::Module SubModule(SubTU->Name.str(), LLVMContext);
      performCaptureAnalysis(SubTU);
      performIRGeneration(Options, &SubModule, SubTU);

      if (Context.hadError())
        return;

      if (llvm::Linker::LinkModules(&Module, &SubModule,
                                    llvm::Linker::DestroySource,
                                    &ErrorMessage)) {
        llvm::errs() << "Error linking swift modules\n";
        llvm::errs() << ErrorMessage << "\n";
        return;
      }

      // FIXME: This is an ugly hack; need to figure out how this should
      // actually work.
      SmallVector<char, 20> NameBuf;
      StringRef InitFnName = (SubTU->Name.str() + ".init").toStringRef(NameBuf);
      llvm::Function *InitFn = Module.getFunction(InitFnName);
      if (InitFn)
        InitFuncs.push_back(InitFn);
    }

    for (auto InitFn : InitFuncs)
      EE->runFunctionAsMain(InitFn, std::vector<std::string>(), 0);

    // FIXME: The way we do this is really ugly... we should be able to
    // improve this.
    llvm::Function *EntryFn = Module.getFunction("main");
    EE->runFunctionAsMain(EntryFn, std::vector<std::string>(), 0);
    EE->freeMachineCodeForFunction(EntryFn);
    EntryFn->eraseFromParent();
  }
}

// FIXME: We shouldn't be writing implemenetations for functions in the swift
// module in C, and this isn't really an ideal place to put those
// implementations.
extern "C" void _TSs5printFT3valNSs5Int64_T_(int64_t l) {
  printf("%lld", l);
}

extern "C" void _TSs5printFT3valNSs6Double_T_(double l) {
  printf("%f", l);
}

extern "C" void _TSs9printCharFT9characterNSs5Int64_T_(int64_t l) {
  printf("%c", (char)l);
}

extern "C" void _TSs5printFT3valNSs6String_T_(char* l) {
  printf("%s", l);
}

// func [infix_left=190] + (lhs : String,
//                          rhs : String) -> String
extern "C" char* _TSsop1pFT3lhsNSs6String3rhsS__S_(char* lhs, char* rhs) {
   size_t ls = strlen(lhs);
   size_t rs = strlen(rhs);
   char* s = (char*)malloc(ls+rs+1);
   memcpy(s, lhs, ls);
   strcpy(s+ls, rhs);
   return s;
}

extern "C" bool _TNSs4Bool13getLogicValuefRS_FT_i1(bool* b) {
  return *b;
}

extern "C" void _TSs4exitFT8exitCodeNSs5Int64_T_(int64_t l) {
  exit(l);
}
<|endoftext|>


<commit_before>/*
 */
#include "manifest.h"
#include "build.h"
#include "debug.h"
#include <vector>
#include <algorithm>
#include <sstream>  // stringstream
#ifdef _WIN32
# include <Windows.h>
#else
# include <spawn.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/wait.h>
# include <fcntl.h>
#endif

struct BuildList
{
    struct BuildEnt {
        const PackageManifest*  package;
        unsigned level;
    };
    ::std::vector<BuildEnt>  m_list;

    void add_dependencies(const PackageManifest& p, unsigned level);
    void add_package(const PackageManifest& p, unsigned level);
    void sort_list();

    struct Iter {
        const BuildList& l;
        size_t  i;

        const PackageManifest& operator*() const {
            return *this->l.m_list[this->i].package;
        }
        void operator++() {
            this->i++;
        }
        bool operator!=(const Iter& x) const {
            return this->i != x.i;
        }
        Iter begin() const {
            return *this;
        }
        Iter end() {
            return Iter{ this->l, this->l.m_list.size() };
        }
    };

    Iter iter() const {
        return Iter { *this, 0 };
    }
};

class StringList
{
    ::std::vector<::std::string>    m_cached;
    ::std::vector<const char*>  m_strings;
public:
    StringList()
    {
    }
    StringList(const StringList&) = delete;

    const ::std::vector<const char*>& get_vec() const
    {
        return m_strings;
    }

    void push_back(::std::string s)
    {
#if _WIN32
        // NOTE: MSVC's STL changes the pointer on move it seems
        if(m_cached.capacity() == m_cached.size())
        {
            ::std::vector<bool> b;
            b.reserve(m_strings.size());
            size_t j = 0;
            for(const auto* s : m_strings)
            {
                if(j == m_cached.size())
                    break;
                if(s == m_cached[j].c_str())
                    b.push_back(true);
                else
                    b.push_back(false);
            }

            m_cached.push_back(::std::move(s));
            j = 0;
            for(size_t i = 0; i < b.size(); i ++)
            {
                if(b[i])
                    m_strings[i] = m_cached[j++].c_str();
            }
        }
        else
#endif
        m_cached.push_back(::std::move(s));
        m_strings.push_back(m_cached.back().c_str());
    }
    void push_back(const char* s)
    {
        m_strings.push_back(s);
    }
};

struct Timestamp
{
#if _WIN32
    uint64_t m_val;

    Timestamp(FILETIME ft):
        m_val( (static_cast<uint64_t>(ft.dwHighDateTime) << 32) | static_cast<uint64_t>(ft.dwLowDateTime) )
    {
    }
#else
    time_t  m_val;
#endif
    static Timestamp infinite_past() {
#if _WIN32
        return Timestamp { FILETIME { 0, 0 } };
#else
        return Timestamp { 0 };
#endif
    }

    bool operator==(const Timestamp& x) const {
        return m_val == x.m_val;
    }
    bool operator<(const Timestamp& x) const {
        return m_val < x.m_val;
    }

    friend ::std::ostream& operator<<(::std::ostream& os, const Timestamp& x) {
#if _WIN32
        os << ::std::hex << x.m_val << ::std::dec;
#else
        os << x.m_val;
#endif
        return os;
    }
};

#if _WIN32
const char* const Builder::MRUSTC_PATH = "x64\\Release\\mrustc.exe";
#else
const char* const Builder::MRUSTC_PATH = "../bin/mrustc";
#endif

void MiniCargo_Build(const PackageManifest& manifest, ::helpers::path override_path)
{
    BuildList   list;

    list.add_dependencies(manifest, 0);

    list.sort_list();
    // dedup?
    for(const auto& p : list.iter())
    {
        DEBUG("WILL BUILD " << p.name() << " from " << p.manifest_path());
    }

    // Build dependencies
    Builder builder { "output", override_path };
    for(const auto& p : list.iter())
    {
        if( ! builder.build_library(p) )
        {
            return;
        }
    }

    // TODO: If the manifest doesn't have a library, build the binary
    builder.build_library(manifest);
}

void BuildList::add_dependencies(const PackageManifest& p, unsigned level)
{
    TRACE_FUNCTION_F(p.name());
    for (const auto& dep : p.dependencies())
    {
        if( dep.is_optional() )
        {
            continue ;
        }
        DEBUG("Depenency " << dep.name());
        add_package(dep.get_package(), level+1);
    }
}
void BuildList::add_package(const PackageManifest& p, unsigned level)
{
    TRACE_FUNCTION_F(p.name());
    // If the package is already loaded
    for(auto& ent : m_list)
    {
        if(ent.package == &p && ent.level >= level)
        {
            // NOTE: Only skip if this package will be built before we needed (i.e. the level is greater)
            return ;
        }
        // Keep searching (might already have a higher entry)
    }
    m_list.push_back({ &p, level });
    add_dependencies(p, level);
}
void BuildList::sort_list()
{
    ::std::sort(m_list.begin(), m_list.end(), [](const auto& a, const auto& b){ return a.level > b.level; });

    // Needed to deduplicate after sorting (`add_package` doesn't fully dedup)
    for(auto it = m_list.begin(); it != m_list.end(); )
    {
        auto it2 = ::std::find_if(m_list.begin(), it, [&](const auto& x){ return x.package == it->package; });
        if( it2 != it )
        {
            DEBUG((it - m_list.begin()) << ": Duplicate " << it->package->name() << " - Already at pos " << (it2 - m_list.begin()));
            it = m_list.erase(it);
        }
        else
        {
            DEBUG((it - m_list.begin()) << ": Keep " << it->package->name() << ", level = " << it->level);
            ++it;
        }
    }
}

bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& target) const
{
    auto outfile = m_output_dir / ::format("lib", target.m_name, ".hir");
    //DEBUG("Building " << manifest.name() << ":" << target.m_name << " as " << outfile);

    // TODO: Determine if it needs re-running
    // Rerun if:
    // > `outfile` is missing
    // > mrustc/minicargo is newer than `outfile`
    // > build script has changed
    // > any input file has changed (requires depfile from mrustc)
    bool force_rebuild = false;
    auto ts_result = this->get_timestamp(outfile);
    if( force_rebuild ) {
        DEBUG("Building " << outfile << " - Force");
    }
    else if( ts_result == Timestamp::infinite_past() ) {
        // Rebuild (missing)
        DEBUG("Building " << outfile << " - Missing");
    }
    else if( ts_result < this->get_timestamp(MRUSTC_PATH) /*|| ts_result < this->get_timestamp("bin/minicargo")*/ ) {
        // Rebuild (older than mrustc/minicargo)
        DEBUG("Building " << outfile << " - Older than mrustc ( " << ts_result << " < " << this->get_timestamp(MRUSTC_PATH) << ")");
    }
    else {
        // TODO: Check dependencies. (from depfile)
        // Don't rebuild (no need to)
        DEBUG("Not building " << outfile << " - not out of date");
        return true;
    }

    for(const auto& cmd : manifest.build_script_output().pre_build_commands)
    {
        // TODO: Run commands specified by build script (override)
    }

    StringList  args;
    args.push_back(::helpers::path(manifest.manifest_path()).parent() / ::helpers::path(target.m_path));
    args.push_back("--crate-name"); args.push_back(target.m_name.c_str());
    args.push_back("--crate-type"); args.push_back("rlib");
    args.push_back("-o"); args.push_back(outfile);
    args.push_back("-L"); args.push_back(m_output_dir.str().c_str());
    for(const auto& dir : manifest.build_script_output().rustc_link_search) {
        args.push_back("-L"); args.push_back(dir.second.c_str());
    }
    for(const auto& lib : manifest.build_script_output().rustc_link_lib) {
        args.push_back("-l"); args.push_back(lib.second.c_str());
    }
    for(const auto& cfg : manifest.build_script_output().rustc_cfg) {
        args.push_back("--cfg"); args.push_back(cfg.c_str());
    }
    for(const auto& flag : manifest.build_script_output().rustc_flags) {
        args.push_back(flag.c_str());
    }
    // TODO: Environment variables (rustc_env)

    return this->spawn_process(args, outfile + "_dbg.txt");
}
bool Builder::build_library(const PackageManifest& manifest) const
{
    if( manifest.build_script() != "" )
    {
        // Locate a build script override file
        if(this->m_build_script_overrides.is_valid())
        {
            auto override_file = this->m_build_script_overrides / "build_" + manifest.name().c_str() + ".txt";
            // TODO: Should this test if it exists? or just assume and let it error?

            // > Note, override file can specify a list of commands to run.
            const_cast<PackageManifest&>(manifest).load_build_script( override_file.str() );
        }
        else
        {
            // Otherwise, compile and run build script
            // - Load dependencies for the build script
            // - Build the script itself
            //this->build_build_script( manifest );
            // - Run the script and put output in the right dir
            //manifest.load_build_script( m_output_dir / "build_" + manifest.name().c_str() + ".txt" );
            throw ::std::runtime_error("TODO: Build script for " + manifest.name());
        }
    }

    return this->build_target(manifest, manifest.get_library());
}
bool Builder::spawn_process(const StringList& args, const ::helpers::path& logfile) const
{
#ifdef _WIN32
    ::std::stringstream cmdline;
    cmdline << "mrustc.exe";
    for (const auto& arg : args.get_vec())
        cmdline << " " << arg;
    auto cmdline_str = cmdline.str();
    DEBUG("Calling " << cmdline_str);

    CreateDirectory(static_cast<::std::string>(logfile.parent()).c_str(), NULL);

    STARTUPINFO si = { 0 };
    si.cb = sizeof(si);
    si.dwFlags = STARTF_USESTDHANDLES;
    si.hStdInput = NULL;
    si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
    {
        SECURITY_ATTRIBUTES sa = { 0 };
        sa.nLength = sizeof(sa);
        sa.bInheritHandle = TRUE;
        si.hStdOutput = CreateFile( static_cast<::std::string>(logfile).c_str(), GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
        DWORD   tmp;
        WriteFile(si.hStdOutput, cmdline_str.data(), cmdline_str.size(), &tmp, NULL);
        WriteFile(si.hStdOutput, "\n", 1, &tmp, NULL);
    }
    PROCESS_INFORMATION pi = { 0 };
    char env[] =
        "MRUSTC_DEBUG=""\0"
        ;
    CreateProcessA(MRUSTC_PATH, (LPSTR)cmdline_str.c_str(), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
    CloseHandle(si.hStdOutput);
    WaitForSingleObject(pi.hProcess, INFINITE);
    DWORD status = 1;
    GetExitCodeProcess(pi.hProcess, &status);
    if (status != 0)
    {
        DEBUG("Compiler exited with non-zero exit status " << status);
        return false;
    }
#else

    // Create logfile output directory
    mkdir(static_cast<::std::string>(logfile.parent()).c_str(), 0755);

    // Create handles such that the log file is on stdout
    ::std::string logfile_str = logfile;
    pid_t pid;
    posix_spawn_file_actions_t  fa;
    {
        posix_spawn_file_actions_init(&fa);
        posix_spawn_file_actions_addopen(&fa, 1, logfile_str.c_str(), O_CREAT|O_WRONLY|O_TRUNC, 0644);
    }

    // Generate `argv`
    auto argv = args.get_vec();
    argv.insert(argv.begin(), "mrustc");
    DEBUG("Calling " << argv);
    argv.push_back(nullptr);

    // Generate `envp`
    ::std::vector<const char*> envp;
    extern char **environ;
    for(auto p = environ; *p; p++)
    {
        envp.push_back(*p);
    }
    envp.push_back(nullptr);

    if( posix_spawn(&pid, "../bin/mrustc", &fa, /*attr=*/nullptr, (char* const*)argv.data(), (char* const*)envp.data()) != 0 )
    {
        perror("posix_spawn");
        DEBUG("Unable to spawn compiler");
        posix_spawn_file_actions_destroy(&fa);
        return false;
    }
    posix_spawn_file_actions_destroy(&fa);
    int status = -1;
    waitpid(pid, &status, 0);
    if( WEXITSTATUS(status) != 0 )
    {
        DEBUG("Compiler exited with non-zero exit status " << WEXITSTATUS(status));
        return false;
    }
#endif
    return true;
}

Timestamp Builder::get_timestamp(const ::helpers::path& path) const
{
#if _WIN32
    FILETIME    out;
    auto handle = CreateFile(path.str().c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
    if(handle == INVALID_HANDLE_VALUE) {
        //DEBUG("Can't find " << path);
        return Timestamp::infinite_past();
    }
    if( GetFileTime(handle, NULL, NULL, &out) == FALSE ) {
        //DEBUG("Can't GetFileTime on " << path);
        CloseHandle(handle);
        return Timestamp::infinite_past();
    }
    CloseHandle(handle);
    //DEBUG(Timestamp{out} << " " << path);
    return Timestamp { out };
#else
    struct stat  s;
    if( stat(path.str().c_str(), &s) == 0 )
    {
        return Timestamp { s.st_mtime };
    }
    else
    {
        return Timestamp::infinite_past();
    }
#endif
}

<commit_msg>minicargo build - Fix exit detection<commit_after>/*
 */
#include "manifest.h"
#include "build.h"
#include "debug.h"
#include <vector>
#include <algorithm>
#include <sstream>  // stringstream
#ifdef _WIN32
# include <Windows.h>
#else
# include <spawn.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/wait.h>
# include <fcntl.h>
#endif

struct BuildList
{
    struct BuildEnt {
        const PackageManifest*  package;
        unsigned level;
    };
    ::std::vector<BuildEnt>  m_list;

    void add_dependencies(const PackageManifest& p, unsigned level);
    void add_package(const PackageManifest& p, unsigned level);
    void sort_list();

    struct Iter {
        const BuildList& l;
        size_t  i;

        const PackageManifest& operator*() const {
            return *this->l.m_list[this->i].package;
        }
        void operator++() {
            this->i++;
        }
        bool operator!=(const Iter& x) const {
            return this->i != x.i;
        }
        Iter begin() const {
            return *this;
        }
        Iter end() {
            return Iter{ this->l, this->l.m_list.size() };
        }
    };

    Iter iter() const {
        return Iter { *this, 0 };
    }
};

class StringList
{
    ::std::vector<::std::string>    m_cached;
    ::std::vector<const char*>  m_strings;
public:
    StringList()
    {
    }
    StringList(const StringList&) = delete;

    const ::std::vector<const char*>& get_vec() const
    {
        return m_strings;
    }

    void push_back(::std::string s)
    {
#if _WIN32
        // NOTE: MSVC's STL changes the pointer on move it seems
        if(m_cached.capacity() == m_cached.size())
        {
            ::std::vector<bool> b;
            b.reserve(m_strings.size());
            size_t j = 0;
            for(const auto* s : m_strings)
            {
                if(j == m_cached.size())
                    break;
                if(s == m_cached[j].c_str())
                    b.push_back(true);
                else
                    b.push_back(false);
            }

            m_cached.push_back(::std::move(s));
            j = 0;
            for(size_t i = 0; i < b.size(); i ++)
            {
                if(b[i])
                    m_strings[i] = m_cached[j++].c_str();
            }
        }
        else
#endif
        m_cached.push_back(::std::move(s));
        m_strings.push_back(m_cached.back().c_str());
    }
    void push_back(const char* s)
    {
        m_strings.push_back(s);
    }
};

struct Timestamp
{
#if _WIN32
    uint64_t m_val;

    Timestamp(FILETIME ft):
        m_val( (static_cast<uint64_t>(ft.dwHighDateTime) << 32) | static_cast<uint64_t>(ft.dwLowDateTime) )
    {
    }
#else
    time_t  m_val;
#endif
    static Timestamp infinite_past() {
#if _WIN32
        return Timestamp { FILETIME { 0, 0 } };
#else
        return Timestamp { 0 };
#endif
    }

    bool operator==(const Timestamp& x) const {
        return m_val == x.m_val;
    }
    bool operator<(const Timestamp& x) const {
        return m_val < x.m_val;
    }

    friend ::std::ostream& operator<<(::std::ostream& os, const Timestamp& x) {
#if _WIN32
        os << ::std::hex << x.m_val << ::std::dec;
#else
        os << x.m_val;
#endif
        return os;
    }
};

#if _WIN32
const char* const Builder::MRUSTC_PATH = "x64\\Release\\mrustc.exe";
#else
const char* const Builder::MRUSTC_PATH = "../bin/mrustc";
#endif

void MiniCargo_Build(const PackageManifest& manifest, ::helpers::path override_path)
{
    BuildList   list;

    list.add_dependencies(manifest, 0);

    list.sort_list();
    // dedup?
    for(const auto& p : list.iter())
    {
        DEBUG("WILL BUILD " << p.name() << " from " << p.manifest_path());
    }

    // Build dependencies
    Builder builder { "output", override_path };
    for(const auto& p : list.iter())
    {
        if( ! builder.build_library(p) )
        {
            return;
        }
    }

    // TODO: If the manifest doesn't have a library, build the binary
    builder.build_library(manifest);
}

void BuildList::add_dependencies(const PackageManifest& p, unsigned level)
{
    TRACE_FUNCTION_F(p.name());
    for (const auto& dep : p.dependencies())
    {
        if( dep.is_optional() )
        {
            continue ;
        }
        DEBUG("Depenency " << dep.name());
        add_package(dep.get_package(), level+1);
    }
}
void BuildList::add_package(const PackageManifest& p, unsigned level)
{
    TRACE_FUNCTION_F(p.name());
    // If the package is already loaded
    for(auto& ent : m_list)
    {
        if(ent.package == &p && ent.level >= level)
        {
            // NOTE: Only skip if this package will be built before we needed (i.e. the level is greater)
            return ;
        }
        // Keep searching (might already have a higher entry)
    }
    m_list.push_back({ &p, level });
    add_dependencies(p, level);
}
void BuildList::sort_list()
{
    ::std::sort(m_list.begin(), m_list.end(), [](const auto& a, const auto& b){ return a.level > b.level; });

    // Needed to deduplicate after sorting (`add_package` doesn't fully dedup)
    for(auto it = m_list.begin(); it != m_list.end(); )
    {
        auto it2 = ::std::find_if(m_list.begin(), it, [&](const auto& x){ return x.package == it->package; });
        if( it2 != it )
        {
            DEBUG((it - m_list.begin()) << ": Duplicate " << it->package->name() << " - Already at pos " << (it2 - m_list.begin()));
            it = m_list.erase(it);
        }
        else
        {
            DEBUG((it - m_list.begin()) << ": Keep " << it->package->name() << ", level = " << it->level);
            ++it;
        }
    }
}

bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& target) const
{
    auto outfile = m_output_dir / ::format("lib", target.m_name, ".hir");
    //DEBUG("Building " << manifest.name() << ":" << target.m_name << " as " << outfile);

    // TODO: Determine if it needs re-running
    // Rerun if:
    // > `outfile` is missing
    // > mrustc/minicargo is newer than `outfile`
    // > build script has changed
    // > any input file has changed (requires depfile from mrustc)
    bool force_rebuild = false;
    auto ts_result = this->get_timestamp(outfile);
    if( force_rebuild ) {
        DEBUG("Building " << outfile << " - Force");
    }
    else if( ts_result == Timestamp::infinite_past() ) {
        // Rebuild (missing)
        DEBUG("Building " << outfile << " - Missing");
    }
    else if( ts_result < this->get_timestamp(MRUSTC_PATH) /*|| ts_result < this->get_timestamp("bin/minicargo")*/ ) {
        // Rebuild (older than mrustc/minicargo)
        DEBUG("Building " << outfile << " - Older than mrustc ( " << ts_result << " < " << this->get_timestamp(MRUSTC_PATH) << ")");
    }
    else {
        // TODO: Check dependencies. (from depfile)
        // Don't rebuild (no need to)
        DEBUG("Not building " << outfile << " - not out of date");
        return true;
    }

    for(const auto& cmd : manifest.build_script_output().pre_build_commands)
    {
        // TODO: Run commands specified by build script (override)
    }

    StringList  args;
    args.push_back(::helpers::path(manifest.manifest_path()).parent() / ::helpers::path(target.m_path));
    args.push_back("--crate-name"); args.push_back(target.m_name.c_str());
    args.push_back("--crate-type"); args.push_back("rlib");
    args.push_back("-o"); args.push_back(outfile);
    args.push_back("-L"); args.push_back(m_output_dir.str().c_str());
    for(const auto& dir : manifest.build_script_output().rustc_link_search) {
        args.push_back("-L"); args.push_back(dir.second.c_str());
    }
    for(const auto& lib : manifest.build_script_output().rustc_link_lib) {
        args.push_back("-l"); args.push_back(lib.second.c_str());
    }
    for(const auto& cfg : manifest.build_script_output().rustc_cfg) {
        args.push_back("--cfg"); args.push_back(cfg.c_str());
    }
    for(const auto& flag : manifest.build_script_output().rustc_flags) {
        args.push_back(flag.c_str());
    }
    // TODO: Environment variables (rustc_env)

    return this->spawn_process(args, outfile + "_dbg.txt");
}
bool Builder::build_library(const PackageManifest& manifest) const
{
    if( manifest.build_script() != "" )
    {
        // Locate a build script override file
        if(this->m_build_script_overrides.is_valid())
        {
            auto override_file = this->m_build_script_overrides / "build_" + manifest.name().c_str() + ".txt";
            // TODO: Should this test if it exists? or just assume and let it error?

            // > Note, override file can specify a list of commands to run.
            const_cast<PackageManifest&>(manifest).load_build_script( override_file.str() );
        }
        else
        {
            // Otherwise, compile and run build script
            // - Load dependencies for the build script
            // - Build the script itself
            //this->build_build_script( manifest );
            // - Run the script and put output in the right dir
            //manifest.load_build_script( m_output_dir / "build_" + manifest.name().c_str() + ".txt" );
            throw ::std::runtime_error("TODO: Build script for " + manifest.name());
        }
    }

    return this->build_target(manifest, manifest.get_library());
}
bool Builder::spawn_process(const StringList& args, const ::helpers::path& logfile) const
{
#ifdef _WIN32
    ::std::stringstream cmdline;
    cmdline << "mrustc.exe";
    for (const auto& arg : args.get_vec())
        cmdline << " " << arg;
    auto cmdline_str = cmdline.str();
    DEBUG("Calling " << cmdline_str);

    CreateDirectory(static_cast<::std::string>(logfile.parent()).c_str(), NULL);

    STARTUPINFO si = { 0 };
    si.cb = sizeof(si);
    si.dwFlags = STARTF_USESTDHANDLES;
    si.hStdInput = NULL;
    si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
    {
        SECURITY_ATTRIBUTES sa = { 0 };
        sa.nLength = sizeof(sa);
        sa.bInheritHandle = TRUE;
        si.hStdOutput = CreateFile( static_cast<::std::string>(logfile).c_str(), GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
        DWORD   tmp;
        WriteFile(si.hStdOutput, cmdline_str.data(), cmdline_str.size(), &tmp, NULL);
        WriteFile(si.hStdOutput, "\n", 1, &tmp, NULL);
    }
    PROCESS_INFORMATION pi = { 0 };
    char env[] =
        "MRUSTC_DEBUG=""\0"
        ;
    CreateProcessA(MRUSTC_PATH, (LPSTR)cmdline_str.c_str(), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
    CloseHandle(si.hStdOutput);
    WaitForSingleObject(pi.hProcess, INFINITE);
    DWORD status = 1;
    GetExitCodeProcess(pi.hProcess, &status);
    if (status != 0)
    {
        DEBUG("Compiler exited with non-zero exit status " << status);
        return false;
    }
#else

    // Create logfile output directory
    mkdir(static_cast<::std::string>(logfile.parent()).c_str(), 0755);

    // Create handles such that the log file is on stdout
    ::std::string logfile_str = logfile;
    pid_t pid;
    posix_spawn_file_actions_t  fa;
    {
        posix_spawn_file_actions_init(&fa);
        posix_spawn_file_actions_addopen(&fa, 1, logfile_str.c_str(), O_CREAT|O_WRONLY|O_TRUNC, 0644);
    }

    // Generate `argv`
    auto argv = args.get_vec();
    argv.insert(argv.begin(), "mrustc");
    DEBUG("Calling " << argv);
    argv.push_back(nullptr);

    // Generate `envp`
    ::std::vector<const char*> envp;
    extern char **environ;
    for(auto p = environ; *p; p++)
    {
        envp.push_back(*p);
    }
    envp.push_back(nullptr);

    if( posix_spawn(&pid, "../bin/mrustc", &fa, /*attr=*/nullptr, (char* const*)argv.data(), (char* const*)envp.data()) != 0 )
    {
        perror("posix_spawn");
        DEBUG("Unable to spawn compiler");
        posix_spawn_file_actions_destroy(&fa);
        return false;
    }
    posix_spawn_file_actions_destroy(&fa);
    int status = -1;
    waitpid(pid, &status, 0);
    if( status != 0 )
    {
        if( WIFEXITED(status) )
            DEBUG("Compiler exited with non-zero exit status " << WEXITSTATUS(status));
        else if( WIFSIGNALED(status) )
            DEBUG("Compiler was terminated with signal " << WSTOPSIG(status));
        else
            DEBUG("Compiler terminated for unknown reason, status=" << status);
        return false;
    }
#endif
    return true;
}

Timestamp Builder::get_timestamp(const ::helpers::path& path) const
{
#if _WIN32
    FILETIME    out;
    auto handle = CreateFile(path.str().c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
    if(handle == INVALID_HANDLE_VALUE) {
        //DEBUG("Can't find " << path);
        return Timestamp::infinite_past();
    }
    if( GetFileTime(handle, NULL, NULL, &out) == FALSE ) {
        //DEBUG("Can't GetFileTime on " << path);
        CloseHandle(handle);
        return Timestamp::infinite_past();
    }
    CloseHandle(handle);
    //DEBUG(Timestamp{out} << " " << path);
    return Timestamp { out };
#else
    struct stat  s;
    if( stat(path.str().c_str(), &s) == 0 )
    {
        return Timestamp { s.st_mtime };
    }
    else
    {
        return Timestamp::infinite_past();
    }
#endif
}

<|endoftext|>