Implement default string arguments.
1 /* vim: set ts=4 sw=4 tw=99 et:
3 * Copyright (C) 2012 David Anderson
5 * This file is part of JITCraft.
7 * JITCraft is free software: you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License as published by the Free
9 * Software Foundation, either version 3 of the License, or (at your option)
12 * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
13 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along with
17 * JITCraft. If not, see http://www.gnu.org/licenses/.
20 #include "../include/keima.h"
22 #include "RootScopes.h"
23 #include "CompileContext.h"
26 #include "SemanticAnalysis.h"
27 #include "BytecodeCompiler.h"
29 #include "GlobalRoots.h"
30 #include "Reference.h"
32 #include "Interpreter.h"
35 #include "Spaces-inl.h"
41 Ke::Keima::Initialize()
43 SingleThreadedZone = new Zone();
44 if (!SingleThreadedZone || !SingleThreadedZone->initialize())
52 delete SingleThreadedZone;
53 SingleThreadedZone = NULL;
56 Ke::HandleScope::HandleScope()
58 position_(zone_->rootScopes().position()),
59 prev_(*zone_->rootScopes().scope())
61 *zone_->rootScopes().scope() = this;
64 Ke::HandleScope::~HandleScope()
66 zone_->rootScopes().unwind(position_);
67 *zone_->rootScopes().scope() = prev_;
71 Ke::HandleScope::CreateHandle(ke::Object *obj)
76 return ZONE()->rootScopes().make(obj);
79 template <typename From, typename To> static inline To *
80 Open(Ke::Handle<From> from)
82 return *reinterpret_cast<To **>(*from);
85 template <typename From, typename To> static inline To *
88 return *reinterpret_cast<To **>(from);
91 template <typename From, typename To> static inline Ke::Local<To>
94 return Ke::Local<To>(reinterpret_cast<To *>(Ke::HandleScope::CreateHandle(from)));
98 CompileFromSource(CompileContext &cc, const char *path, const char *stream, size_t length)
100 Parser parser(ZONE(), cc, stream, length);
101 ParseTree *tree = parser.parse();
106 if (!Scope::Bind(cc, tree))
109 SemanticAnalysis semantics(ZONE(), cc, tree);
110 if (!semantics.analyze())
113 Scope::Allocate(tree);
115 BytecodeCompiler compiler(ZONE(), tree, NULL);
116 ke::Local<Module> module(ke::ZONE(), compiler.compile());
121 if (!ke::ZONE()->stack().pushModuleFrame(module, args))
123 if (!ke::Interpret(ke::ZONE(), NULL, NULL))
130 InternalCompile(const char *path)
132 RootScope roots(ZONE());
133 CompileContext cc(ZONE(), path);
138 FILE *fp = fopen(path, "rb");
140 cc.reportError(SourcePosition(), Message_CantOpenFile);
144 if (fseek(fp, 0, SEEK_END)) {
145 cc.reportError(SourcePosition(), Message_ErrorSeekingFile);
149 long size = ftell(fp);
151 cc.reportError(SourcePosition(), Message_ErrorSeekingFile);
156 length = size_t(size);
157 bytes = new char[length + 1];
158 if (fread(bytes, 1, length, fp) != length) {
159 cc.reportError(SourcePosition(), Message_ErrorReadingFile);
167 ke::Local<ke::Module> module(ZONE(), CompileFromSource(cc, path, bytes, length));
172 ke::Local<ke::String> pathstr(ZONE(), ke::String::New(ZONE(), path, Heap::Tenure_Old));
176 module->setPath(pathstr);
180 // This is split out from InternalCompile so the RootScope doesn't conflict
181 // with making a return handle.
182 Ke::Local<Ke::Module>
183 Ke::Compile(const char *path)
185 ke::Local<ke::Module> module(ZONE(), InternalCompile(path));
186 return ToLocal<ke::Module, Ke::Module>(module);
190 Ke::Keima::InstallMessageReporter(Ke::IMessageReporter *reporter)
192 ZONE()->installErrorReporter(reporter);
195 class StackFrameIterator : public Ke::IStackFrameIterator
205 virtual bool done() {
209 const char *function() {
210 return iter_.function();
213 const char *source() {
214 return iter_.source();
217 unsigned lineNumber() {
218 return iter_.lineNumber();
226 Ke::IStackFrameIterator *
227 Ke::Keima::NewStackFrameIterator()
229 return new StackFrameIterator();
232 static inline ke::HeapRoot *
233 FromAPI(ke::HeapRoot *from)
235 ke::Address address = reinterpret_cast<ke::Address>(from);
236 address -= offsetof(ke::HeapRoot, obj);
237 return reinterpret_cast<ke::HeapRoot *>(address);
241 Ke::Internals::NewHeapRoot(ke::Object **ptr)
243 ke::Local<ke::Object> obj(ZONE(), *ptr);
244 ke::HeapRoot *root = ke::ZONE()->globalRoots()->create(obj);
248 // Compute an interior pointer, so it looks like a Handle to an object.
249 return reinterpret_cast<ke::HeapRoot *>(&root->obj);
253 Ke::Internals::IncRef(ke::HeapRoot *root)
255 ZONE()->globalRoots()->incref(FromAPI(root));
259 Ke::Internals::DecRef(ke::HeapRoot *root)
261 ZONE()->globalRoots()->decref(FromAPI(root));
265 Ke::Keima::IsInCallStack(Handle<Module> argModule)
267 ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(argModule));
268 return ZONE()->stack().isInCallStack(module);
272 Ke::Keima::CollectGarbage()
274 ke::ZONE()->heap().reclaim();
278 Ke::Keima::ClearPendingException()
280 ke::ZONE()->clearPendingException();
284 Ke::Module::numPublics()
286 ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
287 if (!module->publics())
289 return module->publics()->length();
292 Ke::Local<Ke::Function>
293 Ke::Module::getPublic(unsigned index)
295 ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
296 ke::Local<ke::Function> fun(ke::ZONE(), ke::Function::cast(module->publics()->at(index)));
297 return ToLocal<ke::Function, Ke::Function>(fun);
301 Ke::Module::numNatives()
303 ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
304 if (!module->natives())
306 return module->natives()->length();
309 Ke::Local<Ke::Native>
310 Ke::Module::getNative(unsigned index)
312 ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
313 ke::Local<ke::Native> fun(ke::ZONE(), ke::Native::cast(module->natives()->at(index)));
314 return ToLocal<ke::Native, Ke::Native>(fun);
318 Ke::Module::setNativeIdentity(void *identity)
320 ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
321 module->setNativeIdentity(identity);
327 ke::Local<ke::String> obj(ke::ZONE(), Open<Ke::String, ke::String>(this));
328 return obj->length();
334 ke::Local<ke::String> obj(ke::ZONE(), Open<Ke::String, ke::String>(this));
338 Ke::Local<Ke::String>
341 ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(this));
342 return ToLocal<ke::String, Ke::String>(fun->name());
345 Ke::Local<Ke::String>
348 ke::Local<ke::Native> native(ke::ZONE(), Open<Ke::Native, ke::Native>(this));
349 return ToLocal<ke::String, Ke::String>(native->name());
353 Ke::Native::bind(void *function)
355 ke::Local<ke::Native> native(ke::ZONE(), Open<Ke::Native, ke::Native>(this));
356 native->bind(function);
359 static inline const char *
360 GetInvokeTypeName(Ke::Parameter::Type type)
363 case Ke::Parameter::Array:
365 case Ke::Parameter::CharArray:
367 case Ke::Parameter::Float:
369 case Ke::Parameter::FloatRef:
371 case Ke::Parameter::Int:
373 case Ke::Parameter::IntRef:
381 CheckInvokeType(const Ke::Parameter ¶m, Type *type)
383 switch (param.type()) {
384 case Ke::Parameter::Array:
385 return type->isArray() &&
386 type->levels() == 1 &&
387 (type->contained()->isPrimitive() || type->contained()->isEnum()) &&
388 (type->contained()->primitive() != PrimitiveType_Char);
389 case Ke::Parameter::CharArray:
390 return type->isCharArray();
391 case Ke::Parameter::Float:
392 return type->isFloat();
393 case Ke::Parameter::FloatRef:
394 return type->isReference() && type->contained()->isFloat();
395 case Ke::Parameter::Int:
396 return type->isInt32() || type->isEnum();
397 case Ke::Parameter::IntRef:
398 return type->isReference() && (type->contained()->isInt32() || type->contained()->isEnum());
405 CheckInvokeTypes(Ke::Handle<Ke::Function> argFun, const Ke::Parameter *params, unsigned nparams)
407 ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(argFun));
409 if (fun->nargs() != nparams)
412 for (unsigned i = 0; i < nparams; i++) {
413 if (!CheckInvokeType(params[i], fun->argType(i))) {
414 ke::ZONE()->reportError(Message_TypeMismatchDuringInvoke,
415 GetInvokeTypeName(params[i].type()),
416 GetTypeName(fun->argType(i)));
421 // Functions can only return tagged cells, for ISPE1-compatible Invoke().
422 ke::Local<ke::Type> returnType(ke::ZONE(), fun->type()->returnType());
423 if (!returnType->isPrimitive() &&
424 !returnType->isEnum() &&
425 !returnType->isVoid())
427 ke::ZONE()->reportError(Message_CannotInvokeReturnType, GetTypeName(returnType));
435 Ke::Keima::Invoke(Handle<Function> argFun, const Parameter *params, unsigned nparams,
436 bool checkTypes, int *retval)
438 assert(CheckInvokeTypes(argFun, params, nparams));
440 ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(argFun));
442 if (fun->nargs() != nparams) {
443 // :TODO: report error
449 if (!ke::ZONE()->stack().pushInvokeFrame(fun, args))
452 if (checkTypes && !CheckInvokeTypes(argFun, params, nparams))
455 for (unsigned i = 0; i < nparams; i++) {
456 ke::LocalSlot &slot = args.arg(i);
457 switch (params[i].type()) {
458 case Ke::Parameter::Int:
459 slot.i32 = params[i].i32();
462 case Ke::Parameter::Float:
463 slot.f = params[i].f();
466 case Ke::Parameter::IntRef:
467 if (params[i].writeback()) {
468 slot.ref = Reference::NewStack(ke::ZONE(), params[i].i32p(), Heap::Tenure_Stack);
471 other.i32 = *params[i].i32p();
472 slot.ref = Reference::NewStack(ke::ZONE(), other, Heap::Tenure_Stack);
478 case Ke::Parameter::FloatRef:
479 if (params[i].writeback()) {
480 slot.ref = Reference::NewStack(ke::ZONE(), params[i].fp(), Heap::Tenure_Stack);
483 other.f = *params[i].fp();
484 slot.ref = Reference::NewStack(ke::ZONE(), other, Heap::Tenure_Stack);
490 case Ke::Parameter::Array:
492 ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->genericArrayMap());
493 if (params[i].writeback()) {
494 slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].length(),
495 params[i].buffer(), Heap::Tenure_Stack);
499 Array *array = Array::New(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
502 memcpy(array->vec(), params[i].buffer(), params[i].length() * sizeof(int));
507 case Ke::Parameter::CharArray:
509 ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->charArrayMap());
510 if (params[i].writeback()) {
511 slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].length(),
512 params[i].buffer(), Heap::Tenure_Stack);
516 Array *array = Array::New(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
519 memcpy(array->vec(), params[i].buffer(), params[i].length() * sizeof(char));
527 if (!Interpret(ke::ZONE(), NULL, &result))
530 if (fun->type()->returnType()->isVoid())
533 *retval = result.i32;