Commit 6179ebbf authored by dslomov@chromium.org's avatar dslomov@chromium.org

Add simple inline macros to js2c and use that for typed array constructors.

R=yangguo@chromium.org

Review URL: https://codereview.chromium.org/44173003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17491 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 23d085c6
...@@ -34,59 +34,71 @@ var $ArrayBuffer = global.ArrayBuffer; ...@@ -34,59 +34,71 @@ var $ArrayBuffer = global.ArrayBuffer;
// --------------- Typed Arrays --------------------- // --------------- Typed Arrays ---------------------
macro TYPED_ARRAYS(FUNCTION)
function CreateTypedArrayConstructor(name, elementSize, arrayId, constructor) { // arrayIds below should be synchronized with Runtime_TypedArrayInitialize.
function ConstructByArrayBuffer(obj, buffer, byteOffset, length) { FUNCTION(1, Uint8Array, 1)
var offset = ToPositiveInteger(byteOffset, "invalid_typed_array_length") FUNCTION(2, Int8Array, 1)
FUNCTION(3, Uint16Array, 2)
if (offset % elementSize !== 0) { FUNCTION(4, Int16Array, 2)
throw MakeRangeError("invalid_typed_array_alignment", FUNCTION(5, Uint32Array, 4)
"start offset", name, elementSize); FUNCTION(6, Int32Array, 4)
} FUNCTION(7, Float32Array, 4)
var bufferByteLength = %ArrayBufferGetByteLength(buffer); FUNCTION(8, Float64Array, 8)
if (offset > bufferByteLength) { FUNCTION(9, Uint8ClampedArray, 1)
throw MakeRangeError("invalid_typed_array_offset"); endmacro
}
macro TYPED_ARRAY_CONSTRUCTOR(ARRAY_ID, NAME, ELEMENT_SIZE)
var newByteLength; function NAMEConstructor(arg1, arg2, arg3) {
var newLength; function ConstructByArrayBuffer(obj, buffer, byteOffset, length) {
if (IS_UNDEFINED(length)) { var offset = ToPositiveInteger(byteOffset, "invalid_typed_array_length")
if (bufferByteLength % elementSize !== 0) {
if (offset % ELEMENT_SIZE !== 0) {
throw MakeRangeError("invalid_typed_array_alignment", throw MakeRangeError("invalid_typed_array_alignment",
"byte length", name, elementSize); "start offset", "NAME", ELEMENT_SIZE);
} }
newByteLength = bufferByteLength - offset; var bufferByteLength = %ArrayBufferGetByteLength(buffer);
newLength = newByteLength / elementSize; if (offset > bufferByteLength) {
} else { throw MakeRangeError("invalid_typed_array_offset");
var newLength = ToPositiveInteger(length, "invalid_typed_array_length"); }
newByteLength = newLength * elementSize;
} var newByteLength;
if (offset + newByteLength > bufferByteLength) { var newLength;
throw MakeRangeError("invalid_typed_array_length"); if (IS_UNDEFINED(length)) {
if (bufferByteLength % ELEMENT_SIZE !== 0) {
throw MakeRangeError("invalid_typed_array_alignment",
"byte length", "NAME", ELEMENT_SIZE);
}
newByteLength = bufferByteLength - offset;
newLength = newByteLength / ELEMENT_SIZE;
} else {
var newLength = ToPositiveInteger(length, "invalid_typed_array_length");
newByteLength = newLength * ELEMENT_SIZE;
}
if (offset + newByteLength > bufferByteLength) {
throw MakeRangeError("invalid_typed_array_length");
}
%TypedArrayInitialize(obj, ARRAY_ID, buffer, offset, newByteLength);
} }
%TypedArrayInitialize(obj, arrayId, buffer, offset, newByteLength);
}
function ConstructByLength(obj, length) { function ConstructByLength(obj, length) {
var l = ToPositiveInteger(length, "invalid_typed_array_length"); var l = ToPositiveInteger(length, "invalid_typed_array_length");
var byteLength = l * elementSize; var byteLength = l * ELEMENT_SIZE;
var buffer = new $ArrayBuffer(byteLength); var buffer = new $ArrayBuffer(byteLength);
%TypedArrayInitialize(obj, arrayId, buffer, 0, byteLength); %TypedArrayInitialize(obj, ARRAY_ID, buffer, 0, byteLength);
} }
function ConstructByArrayLike(obj, arrayLike) { function ConstructByArrayLike(obj, arrayLike) {
var length = arrayLike.length; var length = arrayLike.length;
var l = ToPositiveInteger(length, "invalid_typed_array_length"); var l = ToPositiveInteger(length, "invalid_typed_array_length");
if(!%TypedArrayInitializeFromArrayLike(obj, arrayId, arrayLike, l)) { if(!%TypedArrayInitializeFromArrayLike(obj, ARRAY_ID, arrayLike, l)) {
for (var i = 0; i < l; i++) { for (var i = 0; i < l; i++) {
// It is crucial that we let any execptions from arrayLike[i] // It is crucial that we let any execptions from arrayLike[i]
// propagate outside the function. // propagate outside the function.
obj[i] = arrayLike[i]; obj[i] = arrayLike[i];
}
} }
} }
}
return function (arg1, arg2, arg3) {
if (%_IsConstructCall()) { if (%_IsConstructCall()) {
if (IS_ARRAYBUFFER(arg1)) { if (IS_ARRAYBUFFER(arg1)) {
ConstructByArrayBuffer(this, arg1, arg2, arg3); ConstructByArrayBuffer(this, arg1, arg2, arg3);
...@@ -97,10 +109,12 @@ function CreateTypedArrayConstructor(name, elementSize, arrayId, constructor) { ...@@ -97,10 +109,12 @@ function CreateTypedArrayConstructor(name, elementSize, arrayId, constructor) {
ConstructByArrayLike(this, arg1); ConstructByArrayLike(this, arg1);
} }
} else { } else {
throw MakeTypeError("constructor_not_function", [name]) throw MakeTypeError("constructor_not_function", ["NAME"])
} }
} }
} endmacro
TYPED_ARRAYS(TYPED_ARRAY_CONSTRUCTOR)
function TypedArrayGetBuffer() { function TypedArrayGetBuffer() {
return %TypedArrayGetBuffer(this); return %TypedArrayGetBuffer(this);
...@@ -247,10 +261,8 @@ function TypedArraySet(obj, offset) { ...@@ -247,10 +261,8 @@ function TypedArraySet(obj, offset) {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
function SetupTypedArray(arrayId, name, constructor, elementSize) { function SetupTypedArray(constructor, fun, elementSize) {
%CheckIsBootstrapping(); %CheckIsBootstrapping();
var fun = CreateTypedArrayConstructor(name, elementSize,
arrayId, constructor);
%SetCode(constructor, fun); %SetCode(constructor, fun);
%FunctionSetPrototype(constructor, new $Object()); %FunctionSetPrototype(constructor, new $Object());
...@@ -272,17 +284,12 @@ function SetupTypedArray(arrayId, name, constructor, elementSize) { ...@@ -272,17 +284,12 @@ function SetupTypedArray(arrayId, name, constructor, elementSize) {
)); ));
} }
// arrayIds below should be synchronized with Runtime_TypedArrayInitialize.
SetupTypedArray(1, "Uint8Array", global.Uint8Array, 1);
SetupTypedArray(2, "Int8Array", global.Int8Array, 1);
SetupTypedArray(3, "Uint16Array", global.Uint16Array, 2);
SetupTypedArray(4, "Int16Array", global.Int16Array, 2);
SetupTypedArray(5, "Uint32Array", global.Uint32Array, 4);
SetupTypedArray(6, "Int32Array", global.Int32Array, 4);
SetupTypedArray(7, "Float32Array", global.Float32Array, 4);
SetupTypedArray(8, "Float64Array", global.Float64Array, 8);
SetupTypedArray(9, "Uint8ClampedArray", global.Uint8ClampedArray, 1);
macro SETUP_TYPED_ARRAY(ARRAY_ID, NAME, ELEMENT_SIZE)
SetupTypedArray (global.NAME, NAMEConstructor, ELEMENT_SIZE);
endmacro
TYPED_ARRAYS(SETUP_TYPED_ARRAY)
// --------------------------- DataView ----------------------------- // --------------------------- DataView -----------------------------
......
...@@ -116,41 +116,47 @@ def ExpandConstants(lines, constants): ...@@ -116,41 +116,47 @@ def ExpandConstants(lines, constants):
return lines return lines
def ExpandMacroDefinition(lines, pos, name_pattern, macro, expander):
pattern_match = name_pattern.search(lines, pos)
while pattern_match is not None:
# Scan over the arguments
height = 1
start = pattern_match.start()
end = pattern_match.end()
assert lines[end - 1] == '('
last_match = end
arg_index = [0] # Wrap state into array, to work around Python "scoping"
mapping = { }
def add_arg(str):
# Remember to expand recursively in the arguments
replacement = expander(str.strip())
mapping[macro.args[arg_index[0]]] = replacement
arg_index[0] += 1
while end < len(lines) and height > 0:
# We don't count commas at higher nesting levels.
if lines[end] == ',' and height == 1:
add_arg(lines[last_match:end])
last_match = end + 1
elif lines[end] in ['(', '{', '[']:
height = height + 1
elif lines[end] in [')', '}', ']']:
height = height - 1
end = end + 1
# Remember to add the last match.
add_arg(lines[last_match:end-1])
result = macro.expand(mapping)
# Replace the occurrence of the macro with the expansion
lines = lines[:start] + result + lines[end:]
pattern_match = name_pattern.search(lines, start + len(result))
return lines
def ExpandMacros(lines, macros): def ExpandMacros(lines, macros):
# We allow macros to depend on the previously declared macros, but # We allow macros to depend on the previously declared macros, but
# we don't allow self-dependecies or recursion. # we don't allow self-dependecies or recursion.
for name_pattern, macro in reversed(macros): for name_pattern, macro in reversed(macros):
pattern_match = name_pattern.search(lines, 0) def expander(s):
while pattern_match is not None: return ExpandMacros(s, macros)
# Scan over the arguments lines = ExpandMacroDefinition(lines, 0, name_pattern, macro, expander)
height = 1
start = pattern_match.start()
end = pattern_match.end()
assert lines[end - 1] == '('
last_match = end
arg_index = [0] # Wrap state into array, to work around Python "scoping"
mapping = { }
def add_arg(str):
# Remember to expand recursively in the arguments
replacement = ExpandMacros(str.strip(), macros)
mapping[macro.args[arg_index[0]]] = replacement
arg_index[0] += 1
while end < len(lines) and height > 0:
# We don't count commas at higher nesting levels.
if lines[end] == ',' and height == 1:
add_arg(lines[last_match:end])
last_match = end + 1
elif lines[end] in ['(', '{', '[']:
height = height + 1
elif lines[end] in [')', '}', ']']:
height = height - 1
end = end + 1
# Remember to add the last match.
add_arg(lines[last_match:end-1])
result = macro.expand(mapping)
# Replace the occurrence of the macro with the expansion
lines = lines[:start] + result + lines[end:]
pattern_match = name_pattern.search(lines, start + len(result))
return lines return lines
class TextMacro: class TextMacro:
...@@ -210,6 +216,34 @@ def ReadMacros(lines): ...@@ -210,6 +216,34 @@ def ReadMacros(lines):
raise ("Illegal line: " + line) raise ("Illegal line: " + line)
return (constants, macros) return (constants, macros)
INLINE_MACRO_PATTERN = re.compile(r'macro\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*\n')
INLINE_MACRO_END_PATTERN = re.compile(r'endmacro\s*\n')
def ExpandInlineMacros(lines, filename):
pos = 0
while True:
macro_match = INLINE_MACRO_PATTERN.search(lines, pos)
if macro_match is None:
# no more macros
return lines
name = macro_match.group(1)
args = [match.strip() for match in macro_match.group(2).split(',')]
end_macro_match = INLINE_MACRO_END_PATTERN.search(lines, macro_match.end());
if end_macro_match is None:
raise ("Macro %s unclosed in %s" % (name, filename))
body = lines[macro_match.end():end_macro_match.start()]
# remove macro definition
lines = lines[:macro_match.start()] + lines[end_macro_match.end():]
name_pattern = re.compile("\\b%s\\(" % name)
macro = TextMacro(args, body)
# advance position to where the macro defintion was
pos = macro_match.start()
def non_expander(s):
return s
lines = ExpandMacroDefinition(lines, pos, name_pattern, macro, non_expander)
HEADER_TEMPLATE = """\ HEADER_TEMPLATE = """\
// Copyright 2011 Google Inc. All Rights Reserved. // Copyright 2011 Google Inc. All Rights Reserved.
...@@ -325,6 +359,8 @@ def JS2C(source, target, env): ...@@ -325,6 +359,8 @@ def JS2C(source, target, env):
lines = ReadFile(filename) lines = ReadFile(filename)
lines = ExpandConstants(lines, consts) lines = ExpandConstants(lines, consts)
lines = ExpandMacros(lines, macros) lines = ExpandMacros(lines, macros)
lines = RemoveCommentsAndTrailingWhitespace(lines)
lines = ExpandInlineMacros(lines, filename)
Validate(lines, filename) Validate(lines, filename)
lines = minifier.JSMinify(lines) lines = minifier.JSMinify(lines)
id = (os.path.split(filename)[1])[:-3] id = (os.path.split(filename)[1])[:-3]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment