Skip to content

Commit

Permalink
add --frozen-global flag (see #10)
Browse files Browse the repository at this point in the history
when --frozen-global is present on the command line, it becomes a syntax error to
set a property on the global object (i.e. every lhs of an assignment has to be an
in-scope variable declaration.)

Also, since we know the global object is frozen we can inline loads from the C globals
instead of calling _ejs_global_getprop at all.
  • Loading branch information
toshok committed Jan 3, 2014
1 parent aaf45f7 commit 2bbd84e
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 10 deletions.
4 changes: 4 additions & 0 deletions ejs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ temp_files = []
options =
# our defaults:
debug_level: 0
frozen_global: false
record_types: false
output_filename: null
combine_scripts: false
Expand Down Expand Up @@ -95,6 +96,9 @@ args =
"--record-types":
flag: "record_types"
help: "generates an executable which records types in a format later used for optimizations."
"--frozen-global":
flag: "frozen_global"
help: "compiler acts as if the global object is frozen after initialization, allowing for faster access."

output_usage = ->
console.warn 'Usage:';
Expand Down
24 changes: 17 additions & 7 deletions lib/compiler.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ class LLVMIRVisitor extends TreeVisitor
@ejs_runtime = runtime.createInterface module, @abi
@ejs_binops = runtime.createBinopsInterface module, @abi
@ejs_atoms = runtime.createAtomsInterface module
@ejs_globals = runtime.createGlobalsInterface module

@module_atoms = Object.create null
@literalInitializationFunction = @module.getOrInsertFunction "_ejs_module_init_string_literals_#{@filename}", types.void, []
Expand All @@ -293,7 +294,7 @@ class LLVMIRVisitor extends TreeVisitor

@doInsideBBlock entry_bb, => ir.createBr return_bb
@doInsideBBlock return_bb, =>
@createCall @ejs_runtime.log, [(consts.string ir, "done with literal initialization")], ""
#@createCall @ejs_runtime.log, [(consts.string ir, "done with literal initialization")], ""
ir.createRetVoid()

@literalInitializationBB = entry_bb
Expand Down Expand Up @@ -328,7 +329,9 @@ class LLVMIRVisitor extends TreeVisitor
ir.createStore consts.int64_lowhi(0xfff98000, if n then 0x00000001 else 0x000000000), alloca_as_int64
else
ir.createStore consts.int64_lowhi(0xffffff83, if n then 0x00000001 else 0x00000000), alloca_as_int64
ir.createLoad bool_alloca, "#{name}_load"
rv = ir.createLoad bool_alloca, "#{name}_load"
rv._ejs_returns_ejsval_bool = true
rv

loadDoubleEjsValue: (n) ->
c = llvm.ConstantFP.getDouble n
Expand Down Expand Up @@ -369,8 +372,13 @@ class LLVMIRVisitor extends TreeVisitor
@createCall @ejs_runtime.global_setprop, [c, value], "globalpropstore_#{pname}"

loadGlobal: (prop) ->
pname = @getAtom prop.name
@createCall @ejs_runtime.global_getprop, [pname], "globalloadprop_#{prop.name}"
gname = prop.name

if @options.frozen_global and hasOwn.call @ejs_globals, gname
return ir.createLoad @ejs_globals[prop.name], "load-#{gname}"

pname = @getAtom gname
@createCall @ejs_runtime.global_getprop, [pname], "globalloadprop_#{gname}"

visitWithScope: (scope, children) ->
@scope_stack.push scope
Expand Down Expand Up @@ -594,7 +602,7 @@ class LLVMIRVisitor extends TreeVisitor
generateCondBr: (exp, then_bb, else_bb) ->
exp_value = @visit exp
if exp_value._ejs_returns_ejsval_bool
cmp = @createEjsvalCmpEq exp_value, (@loadBoolEjsValue false), "cmpresult"
cmp = @createEjsvalCmpEq exp_value, @loadBoolEjsValue(false), "cmpresult"
else
cond_truthy = @createCall @ejs_runtime.truthy, [exp_value], "cond_truthy"
cmp = ir.createICmpEq cond_truthy, consts.false(), "cmpresult"
Expand Down Expand Up @@ -1609,10 +1617,12 @@ class LLVMIRVisitor extends TreeVisitor
new_local_val

handleGetGlobal: (exp, opencode) ->
pname = @getAtom exp.arguments[0].name
@createCall @ejs_runtime.global_getprop, [pname], "globalloadprop_#{exp.arguments[0].name}"
@loadGlobal exp.arguments[0]

handleSetGlobal: (exp, opencode) ->
if @options.frozen_global
throw new SyntaxError "cannot set global property '#{exp.arguments[0].name}' when using --frozen-global"

pname = @getAtom exp.arguments[0].name
value = @visit exp.arguments[1]

Expand Down
25 changes: 24 additions & 1 deletion lib/runtime.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,27 @@ exports.createAtomsInterface = (module) ->
"Object": { get: -> module.getOrInsertGlobal "_ejs_atom_Object", types.EjsValue }
"Array": { get: -> module.getOrInsertGlobal "_ejs_atom_Array", types.EjsValue }
}


exports.createGlobalsInterface = (module) ->
return Object.create null, {
"Object": { get: -> module.getOrInsertGlobal "_ejs_Object", types.EjsValue }
"Boolean": { get: -> module.getOrInsertGlobal "_ejs_Boolean", types.EjsValue }
"String": { get: -> module.getOrInsertGlobal "_ejs_String", types.EjsValue }
"Number": { get: -> module.getOrInsertGlobal "_ejs_Number", types.EjsValue }
"Array": { get: -> module.getOrInsertGlobal "_ejs_Array", types.EjsValue }
"Date": { get: -> module.getOrInsertGlobal "_ejs_Date", types.EjsValue }
"Error": { get: -> module.getOrInsertGlobal "_ejs_Error", types.EjsValue }
"Function": { get: -> module.getOrInsertGlobal "_ejs_Function", types.EjsValue }
"JSON": { get: -> module.getOrInsertGlobal "_ejs_JSON", types.EjsValue }
"Math": { get: -> module.getOrInsertGlobal "_ejs_Math", types.EjsValue }
"console": { get: -> module.getOrInsertGlobal "_ejs_console", types.EjsValue }
"require": { get: -> module.getOrInsertGlobal "_ejs_require", types.EjsValue }
"ArrayBuffer": { get: -> module.getOrInsertGlobal "_ejs_ArrayBuffer", types.EjsValue }
"Int8Array": { get: -> module.getOrInsertGlobal "_ejs_Int8Array", types.EjsValue }
"Uint16Array": { get: -> module.getOrInsertGlobal "_ejs_Uint16Array", types.EjsValue }
"Int32Array": { get: -> module.getOrInsertGlobal "_ejs_Int32Array", types.EjsValue }
"Float32Array": { get: -> module.getOrInsertGlobal "_ejs_Float32Array", types.EjsValue }
# kind of a hack, but since we don't define these...
"window": { get: -> module.getOrInsertGlobal "_ejs_undefined", types.EjsValue }
"document": { get: -> module.getOrInsertGlobal "_ejs_undefined", types.EjsValue }
}
3 changes: 2 additions & 1 deletion runtime/ejs-console.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,12 @@ _ejs_console_warn (ejsval env, ejsval _this, uint32_t argc, ejsval *args)
return output (stderr, argc, args);
}

ejsval _ejs_console EJSVAL_ALIGNMENT;

void
_ejs_console_init(ejsval global)
{
ejsval _ejs_console = _ejs_object_new (_ejs_null, &_ejs_object_specops);
_ejs_console = _ejs_object_new (_ejs_null, &_ejs_object_specops);
_ejs_object_setprop (global, _ejs_atom_console, _ejs_console);

#define OBJ_METHOD(x) EJS_INSTALL_ATOM_FUNCTION(_ejs_console, x, _ejs_console_##x)
Expand Down
2 changes: 2 additions & 0 deletions runtime/ejs-console.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

EJS_BEGIN_DECLS

ejsval _ejs_console;

void _ejs_console_init(ejsval global);

EJS_END_DECLS
Expand Down
2 changes: 1 addition & 1 deletion runtime/ejs-json.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

EJS_BEGIN_DECLS

extern ejsval _ejs_Json;
extern ejsval _ejs_JSON;

void _ejs_json_init(ejsval global);

Expand Down

0 comments on commit 2bbd84e

Please sign in to comment.