mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-29 21:25:35 +00:00
Bug 465460 - TM: valueOf ignored on third iteration of loop (r=gal).
This commit is contained in:
parent
098216e2fd
commit
5d4fa98a15
@ -656,3 +656,11 @@ $(CURDIR)/javascript-trace.h: $(srcdir)/javascript-trace.d
|
||||
|
||||
$(CPPSRCS:%.cpp=%.$(OBJ_SUFFIX)): $(CURDIR)/javascript-trace.h
|
||||
endif
|
||||
|
||||
imacro_asm.js: imacro_asm.js.in
|
||||
$(CC) -c -x c -E -P -I$(srcdir) $? > $@
|
||||
|
||||
GARBAGE += imacro_asm.js
|
||||
|
||||
%.c.out: %.jsasm $(PROGRAM) imacro_asm.js
|
||||
./$(PROGRAM) imacro_asm.js $< > $@
|
||||
|
@ -94,5 +94,4 @@ BUILTIN2(extern, STRING, js_TypeOfObject, CONTEXT, OBJECT,
|
||||
BUILTIN2(extern, STRING, js_TypeOfBoolean, CONTEXT, INT32, 1, 1)
|
||||
BUILTIN2(extern, DOUBLE, js_BooleanOrUndefinedToNumber, CONTEXT, INT32, 1, 1)
|
||||
BUILTIN2(extern, STRING, js_BooleanOrUndefinedToString, CONTEXT, INT32, 1, 1)
|
||||
BUILTIN2(extern, STRING, js_ObjectToString, CONTEXT, OBJECT, 0, 0)
|
||||
BUILTIN1(extern, OBJECT, js_Arguments, CONTEXT, 0, 0)
|
||||
|
308
js/src/imacro_asm.js.in
Normal file
308
js/src/imacro_asm.js.in
Normal file
@ -0,0 +1,308 @@
|
||||
/* vim: set sw=4 ts=8 et tw=78 ft=javascript: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the TraceMonkey IMacro Assembler.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Brendan Eich <brendan@mozilla.org>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
* An imacro (interpreter-macro) assembler in JS, with a light dusting of C
|
||||
* pre-processor. We depend on the snarf function from the js shell, defined
|
||||
* originally for the Narcissus metacircular evaluator, now unconditionally
|
||||
* compiled into the shell.
|
||||
*
|
||||
* Filename suffix conventions, used by Makefile.in rules:
|
||||
* .js.in C-pre-processed JS source
|
||||
* .jsasm SpiderMonkey JS assembly source, which could be input to other
|
||||
* assemblers than imacro_asm.js, hence the generic suffix!
|
||||
* .c.out C source output by imacro_asm.js
|
||||
*/
|
||||
|
||||
#define ASSERT(cond) _ASSERT(cond, #cond)
|
||||
|
||||
function _ASSERT(cond, message) {
|
||||
if (!cond)
|
||||
throw new Error("Assertion failed: " + message);
|
||||
}
|
||||
|
||||
const js_arguments_str = "arguments";
|
||||
const js_new_str = "new";
|
||||
const js_typeof_str = "typeof";
|
||||
const js_void_str = "void";
|
||||
const js_null_str = "null";
|
||||
const js_this_str = "this";
|
||||
const js_false_str = "false";
|
||||
const js_true_str = "true";
|
||||
const js_throw_str = "throw";
|
||||
const js_in_str = "in";
|
||||
const js_instanceof_str = "instanceof";
|
||||
const js_getter_str = "getter";
|
||||
const js_setter_str = "setter";
|
||||
|
||||
#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
|
||||
{jsop: #op, opcode: val, opname: name, opsrc: token, oplen: length, \
|
||||
pops: nuses, pushes: ndefs, precedence: prec, flags: #format},
|
||||
|
||||
const NULL = null;
|
||||
|
||||
const opinfo = [
|
||||
#include "jsopcode.tbl"
|
||||
];
|
||||
|
||||
const opname2info = {};
|
||||
const jsop2opcode = {};
|
||||
|
||||
for (let i = 0; i < opinfo.length; i++) {
|
||||
let info = opinfo[i];
|
||||
ASSERT(info.opcode == i);
|
||||
opname2info[info.opname] = info;
|
||||
jsop2opcode[info.jsop] = info.opcode;
|
||||
}
|
||||
|
||||
function formatoffset(n, w) {
|
||||
let s = n.toString();
|
||||
while (s.length < w)
|
||||
s = ' ' + s;
|
||||
return s;
|
||||
}
|
||||
|
||||
function immediate(op) {
|
||||
let info = op.info;
|
||||
if (info.flags.indexOf("JOF_ATOM") >= 0) {
|
||||
if (/^(?:void|object|function|string|number|boolean)$/.test(op.imm1))
|
||||
return "0, COMMON_TYPE_ATOM_INDEX(JSTYPE_" + op.imm1.toUpperCase() + ")";
|
||||
return "0, COMMON_ATOM_INDEX(" + op.imm1 + ")";
|
||||
}
|
||||
if (info.flags.indexOf("JOF_JUMP") >= 0)
|
||||
return ((op.target >> 8) & 0xff) + ", " + (op.target & 0xff);
|
||||
if (info.flags.indexOf("JOF_UINT16") >= 0)
|
||||
return ((op.imm1 & 0xff00) >> 8) + ", " + (op.imm1 & 0xff);
|
||||
throw new Error(info.jsop + " format not yet implemented");
|
||||
}
|
||||
|
||||
/*
|
||||
* Syntax (spaces are significant only to delimit tokens):
|
||||
*
|
||||
* Assembly ::= (Directive? '\n')*
|
||||
* Directive ::= (name ':')? Operation
|
||||
* Operation ::= opname Operands?
|
||||
* Operands ::= Operand (',' Operand)*
|
||||
* Operand ::= name | number
|
||||
*
|
||||
* We simplify given line structure and the maximum of one immediate operand,
|
||||
* by parsing using split and regexps.
|
||||
*
|
||||
* Pseudo-ops start with . and include .igroup and .imacro, terminated by .end.
|
||||
* .imacro must nest in .igroup, neither nests in itself. See imacros.jsasm for
|
||||
* examples.
|
||||
*/
|
||||
function assemble(filename) {
|
||||
let igroup = null, imacro = null;
|
||||
let opcode2extra = [];
|
||||
|
||||
print("/* GENERATED BY imacro_asm.js from " + filename + " -- DO NOT EDIT!!! */");
|
||||
|
||||
let s = snarf(filename);
|
||||
let a = s.split('\n');
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
if (/^\s*(?:#.*)?$/.test(a[i]))
|
||||
continue;
|
||||
let m = /(?:(\w+):)?\s*(\.?\w+)(?:\s+(\w+))?(?:\s+([\w-]+))?(?:\s*(?:#.*))?$/.exec(a[i]);
|
||||
if (!m)
|
||||
throw new Error(a[i]);
|
||||
|
||||
let [, label, opname, imm1, imm2] = m;
|
||||
|
||||
if (opname[0] == '.') {
|
||||
if (label)
|
||||
throw new Error("invalid label " + label + " before " + opname);
|
||||
|
||||
switch (opname) {
|
||||
case ".igroup":
|
||||
if (!imm1)
|
||||
throw new Error("missing .igroup name");
|
||||
if (igroup)
|
||||
throw new Error("nested .igroup " + imm1);
|
||||
let oprange = imm2.match(/^(\w+)(?:-(\w+))?$/);
|
||||
if (!oprange)
|
||||
throw new Error("invalid igroup operator range " + imm2);
|
||||
let firstop = jsop2opcode[oprange[1]];
|
||||
igroup = {
|
||||
name: imm1,
|
||||
firstop: firstop,
|
||||
lastop: oprange[2] ? jsop2opcode[oprange[2]] : firstop,
|
||||
imacros: []
|
||||
};
|
||||
break;
|
||||
|
||||
case ".imacro":
|
||||
if (!igroup)
|
||||
throw new Error(".imacro outside of .igroup");
|
||||
if (!imm1)
|
||||
throw new Error("missing .imacro name");
|
||||
if (imacro)
|
||||
throw new Error("nested .imacro " + imm1);
|
||||
imacro = {
|
||||
name: imm1,
|
||||
offset: 0,
|
||||
code: [],
|
||||
labeldefs: {},
|
||||
labelrefs: {}
|
||||
};
|
||||
break;
|
||||
|
||||
case ".end":
|
||||
if (!imacro) {
|
||||
if (!igroup)
|
||||
throw new Error(".end without prior .igroup or .imacro");
|
||||
if (imm1 && (imm1 != igroup.name || imm2))
|
||||
throw new Error(".igroup/.end name mismatch");
|
||||
|
||||
let maxdepth = 0;
|
||||
|
||||
print("static struct {");
|
||||
for (let j = 0; j < igroup.imacros.length; j++) {
|
||||
imacro = igroup.imacros[j];
|
||||
print(" jsbytecode " + imacro.name + "[" + imacro.offset + "];");
|
||||
}
|
||||
print("} " + igroup.name + "_imacros = {");
|
||||
|
||||
for (let j = 0; j < igroup.imacros.length; j++) {
|
||||
let depth = 0;
|
||||
|
||||
imacro = igroup.imacros[j];
|
||||
print(" {");
|
||||
for (let k = 0; k < imacro.code.length; k++) {
|
||||
let op = imacro.code[k];
|
||||
|
||||
print("/*" + formatoffset(op.offset,2) + "*/ " + op.info.jsop +
|
||||
(op.imm1 ? ", " + immediate(op) : "") + ",");
|
||||
|
||||
depth -= (op.info.pops < 0) ? 2 + op.imm1 : op.info.pops;
|
||||
depth += op.info.pushes;
|
||||
if (depth > maxdepth)
|
||||
maxdepth = depth;
|
||||
}
|
||||
print(" },");
|
||||
}
|
||||
|
||||
print("};");
|
||||
|
||||
let opcode = igroup.firstop;
|
||||
let oplast = igroup.lastop;
|
||||
do {
|
||||
opcode2extra[opcode] = maxdepth;
|
||||
} while (opcode++ != oplast);
|
||||
igroup = null;
|
||||
} else {
|
||||
ASSERT(igroup);
|
||||
|
||||
if (imm1 && imm1 != imacro.name)
|
||||
throw new Error(".imacro/.end name mismatch");
|
||||
|
||||
// Backpatch the forward references to labels that must now be defined.
|
||||
for (label in imacro.labelrefs) {
|
||||
if (!imacro.labelrefs.hasOwnProperty(label))
|
||||
continue;
|
||||
if (!imacro.labeldefs.hasOwnProperty(label))
|
||||
throw new Error("label " + label + " used but not defined");
|
||||
let link = imacro.labelrefs[label];
|
||||
ASSERT(link >= 0);
|
||||
for (;;) {
|
||||
let op = imacro.code[link];
|
||||
ASSERT(op);
|
||||
ASSERT(op.hasOwnProperty('target'));
|
||||
let next = op.target;
|
||||
op.target = imacro.labeldefs[label] - op.offset;
|
||||
if (next < 0)
|
||||
break;
|
||||
link = next;
|
||||
}
|
||||
}
|
||||
|
||||
igroup.imacros.push(imacro);
|
||||
}
|
||||
imacro = null;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error("unknown pseudo-op " + opname);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!opname2info.hasOwnProperty(opname))
|
||||
throw new Error("unknown opcode " + opname + (label ? " (label " + label + ")" : ""));
|
||||
|
||||
let info = opname2info[opname];
|
||||
if (info.oplen == -1)
|
||||
throw new Error("unimplemented opcode " + opname);
|
||||
|
||||
if (label) {
|
||||
if (!imacro)
|
||||
throw new Error("label " + label + " outside of .imacro");
|
||||
imacro.labeldefs[label] = imacro.offset;
|
||||
}
|
||||
|
||||
let op = {offset: imacro.offset, info: info, imm1: imm1, imm2: imm2};
|
||||
if (info.flags.indexOf("JOF_JUMP") >= 0) {
|
||||
if (imacro.labeldefs.hasOwnProperty(imm1)) {
|
||||
// Backward reference can be resolved right away, no backpatching needed.
|
||||
op.target = imacro.labeldefs[imm1] - op.offset;
|
||||
} else {
|
||||
// Link op into the .target-linked backpatch chain at labelrefs[imm1].
|
||||
// The linked list terminates with a -1 sentinel.
|
||||
op.target = imacro.labelrefs.hasOwnProperty(imm1) ? imacro.labelrefs[imm1] : -1;
|
||||
imacro.labelrefs[imm1] = imacro.code.length;
|
||||
}
|
||||
}
|
||||
|
||||
imacro.code.push(op);
|
||||
imacro.offset += info.oplen;
|
||||
}
|
||||
|
||||
print("uint8 js_opcode2extra[JSOP_LIMIT] = {");
|
||||
for (let i = 0; i < opinfo.length; i++) {
|
||||
print(" " + ((i in opcode2extra) ? opcode2extra[i] : "0") +
|
||||
", /* " + opinfo[i].jsop + " */");
|
||||
}
|
||||
print("};");
|
||||
}
|
||||
|
||||
for (let i = 0; i < arguments.length; i++) {
|
||||
try {
|
||||
assemble(arguments[i]);
|
||||
} catch (e) {
|
||||
print(e.name + ": " + e.message + "\n" + e.stack);
|
||||
}
|
||||
}
|
407
js/src/imacros.c.out
Normal file
407
js/src/imacros.c.out
Normal file
@ -0,0 +1,407 @@
|
||||
/* GENERATED BY imacro_asm.js from ../imacros.jsasm -- DO NOT EDIT!!! */
|
||||
static struct {
|
||||
jsbytecode any_obj[36];
|
||||
jsbytecode obj_any[38];
|
||||
jsbytecode obj_obj[72];
|
||||
} binary_imacros = {
|
||||
{
|
||||
/* 0*/ JSOP_DUP,
|
||||
/* 1*/ JSOP_DUP,
|
||||
/* 2*/ JSOP_GETPROP, 0, COMMON_ATOM_INDEX(valueOf),
|
||||
/* 5*/ JSOP_IFPRIMTOP, 0, 16,
|
||||
/* 8*/ JSOP_SWAP,
|
||||
/* 9*/ JSOP_STRING, 0, COMMON_TYPE_ATOM_INDEX(JSTYPE_NUMBER),
|
||||
/*12*/ JSOP_CALL, 0, 1,
|
||||
/*15*/ JSOP_IFPRIMTOP, 0, 17,
|
||||
/*18*/ JSOP_GOTO, 0, 4,
|
||||
/*21*/ JSOP_POP,
|
||||
/*22*/ JSOP_POP,
|
||||
/*23*/ JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(toString),
|
||||
/*26*/ JSOP_CALL, 0, 0,
|
||||
/*29*/ JSOP_GOTO, 0, 5,
|
||||
/*32*/ JSOP_SWAP,
|
||||
/*33*/ JSOP_POP,
|
||||
/*34*/ JSOP_IMACOP,
|
||||
/*35*/ JSOP_STOP,
|
||||
},
|
||||
{
|
||||
/* 0*/ JSOP_SWAP,
|
||||
/* 1*/ JSOP_DUP,
|
||||
/* 2*/ JSOP_DUP,
|
||||
/* 3*/ JSOP_GETPROP, 0, COMMON_ATOM_INDEX(valueOf),
|
||||
/* 6*/ JSOP_IFPRIMTOP, 0, 16,
|
||||
/* 9*/ JSOP_SWAP,
|
||||
/*10*/ JSOP_STRING, 0, COMMON_TYPE_ATOM_INDEX(JSTYPE_NUMBER),
|
||||
/*13*/ JSOP_CALL, 0, 1,
|
||||
/*16*/ JSOP_IFPRIMTOP, 0, 17,
|
||||
/*19*/ JSOP_GOTO, 0, 4,
|
||||
/*22*/ JSOP_POP,
|
||||
/*23*/ JSOP_POP,
|
||||
/*24*/ JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(toString),
|
||||
/*27*/ JSOP_CALL, 0, 0,
|
||||
/*30*/ JSOP_GOTO, 0, 5,
|
||||
/*33*/ JSOP_SWAP,
|
||||
/*34*/ JSOP_POP,
|
||||
/*35*/ JSOP_SWAP,
|
||||
/*36*/ JSOP_IMACOP,
|
||||
/*37*/ JSOP_STOP,
|
||||
},
|
||||
{
|
||||
/* 0*/ JSOP_SWAP,
|
||||
/* 1*/ JSOP_DUP,
|
||||
/* 2*/ JSOP_DUP,
|
||||
/* 3*/ JSOP_GETPROP, 0, COMMON_ATOM_INDEX(valueOf),
|
||||
/* 6*/ JSOP_IFPRIMTOP, 0, 16,
|
||||
/* 9*/ JSOP_SWAP,
|
||||
/*10*/ JSOP_STRING, 0, COMMON_TYPE_ATOM_INDEX(JSTYPE_NUMBER),
|
||||
/*13*/ JSOP_CALL, 0, 1,
|
||||
/*16*/ JSOP_IFPRIMTOP, 0, 17,
|
||||
/*19*/ JSOP_GOTO, 0, 4,
|
||||
/*22*/ JSOP_POP,
|
||||
/*23*/ JSOP_POP,
|
||||
/*24*/ JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(toString),
|
||||
/*27*/ JSOP_CALL, 0, 0,
|
||||
/*30*/ JSOP_GOTO, 0, 5,
|
||||
/*33*/ JSOP_SWAP,
|
||||
/*34*/ JSOP_POP,
|
||||
/*35*/ JSOP_SWAP,
|
||||
/*36*/ JSOP_DUP,
|
||||
/*37*/ JSOP_DUP,
|
||||
/*38*/ JSOP_GETPROP, 0, COMMON_ATOM_INDEX(valueOf),
|
||||
/*41*/ JSOP_IFPRIMTOP, 0, 16,
|
||||
/*44*/ JSOP_SWAP,
|
||||
/*45*/ JSOP_STRING, 0, COMMON_TYPE_ATOM_INDEX(JSTYPE_NUMBER),
|
||||
/*48*/ JSOP_CALL, 0, 1,
|
||||
/*51*/ JSOP_IFPRIMTOP, 0, 17,
|
||||
/*54*/ JSOP_GOTO, 0, 4,
|
||||
/*57*/ JSOP_POP,
|
||||
/*58*/ JSOP_POP,
|
||||
/*59*/ JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(toString),
|
||||
/*62*/ JSOP_CALL, 0, 0,
|
||||
/*65*/ JSOP_GOTO, 0, 5,
|
||||
/*68*/ JSOP_SWAP,
|
||||
/*69*/ JSOP_POP,
|
||||
/*70*/ JSOP_IMACOP,
|
||||
/*71*/ JSOP_STOP,
|
||||
},
|
||||
};
|
||||
static struct {
|
||||
jsbytecode any_obj[36];
|
||||
jsbytecode obj_any[38];
|
||||
jsbytecode obj_obj[72];
|
||||
} add_imacros = {
|
||||
{
|
||||
/* 0*/ JSOP_DUP,
|
||||
/* 1*/ JSOP_DUP,
|
||||
/* 2*/ JSOP_GETPROP, 0, COMMON_ATOM_INDEX(valueOf),
|
||||
/* 5*/ JSOP_IFPRIMTOP, 0, 16,
|
||||
/* 8*/ JSOP_SWAP,
|
||||
/* 9*/ JSOP_STRING, 0, COMMON_TYPE_ATOM_INDEX(JSTYPE_VOID),
|
||||
/*12*/ JSOP_CALL, 0, 1,
|
||||
/*15*/ JSOP_IFPRIMTOP, 0, 17,
|
||||
/*18*/ JSOP_GOTO, 0, 4,
|
||||
/*21*/ JSOP_POP,
|
||||
/*22*/ JSOP_POP,
|
||||
/*23*/ JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(toString),
|
||||
/*26*/ JSOP_CALL, 0, 0,
|
||||
/*29*/ JSOP_GOTO, 0, 5,
|
||||
/*32*/ JSOP_SWAP,
|
||||
/*33*/ JSOP_POP,
|
||||
/*34*/ JSOP_ADD,
|
||||
/*35*/ JSOP_STOP,
|
||||
},
|
||||
{
|
||||
/* 0*/ JSOP_SWAP,
|
||||
/* 1*/ JSOP_DUP,
|
||||
/* 2*/ JSOP_DUP,
|
||||
/* 3*/ JSOP_GETPROP, 0, COMMON_ATOM_INDEX(valueOf),
|
||||
/* 6*/ JSOP_IFPRIMTOP, 0, 16,
|
||||
/* 9*/ JSOP_SWAP,
|
||||
/*10*/ JSOP_STRING, 0, COMMON_TYPE_ATOM_INDEX(JSTYPE_VOID),
|
||||
/*13*/ JSOP_CALL, 0, 1,
|
||||
/*16*/ JSOP_IFPRIMTOP, 0, 17,
|
||||
/*19*/ JSOP_GOTO, 0, 4,
|
||||
/*22*/ JSOP_POP,
|
||||
/*23*/ JSOP_POP,
|
||||
/*24*/ JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(toString),
|
||||
/*27*/ JSOP_CALL, 0, 0,
|
||||
/*30*/ JSOP_GOTO, 0, 5,
|
||||
/*33*/ JSOP_SWAP,
|
||||
/*34*/ JSOP_POP,
|
||||
/*35*/ JSOP_SWAP,
|
||||
/*36*/ JSOP_ADD,
|
||||
/*37*/ JSOP_STOP,
|
||||
},
|
||||
{
|
||||
/* 0*/ JSOP_SWAP,
|
||||
/* 1*/ JSOP_DUP,
|
||||
/* 2*/ JSOP_DUP,
|
||||
/* 3*/ JSOP_GETPROP, 0, COMMON_ATOM_INDEX(valueOf),
|
||||
/* 6*/ JSOP_IFPRIMTOP, 0, 16,
|
||||
/* 9*/ JSOP_SWAP,
|
||||
/*10*/ JSOP_STRING, 0, COMMON_TYPE_ATOM_INDEX(JSTYPE_VOID),
|
||||
/*13*/ JSOP_CALL, 0, 1,
|
||||
/*16*/ JSOP_IFPRIMTOP, 0, 17,
|
||||
/*19*/ JSOP_GOTO, 0, 4,
|
||||
/*22*/ JSOP_POP,
|
||||
/*23*/ JSOP_POP,
|
||||
/*24*/ JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(toString),
|
||||
/*27*/ JSOP_CALL, 0, 0,
|
||||
/*30*/ JSOP_GOTO, 0, 5,
|
||||
/*33*/ JSOP_SWAP,
|
||||
/*34*/ JSOP_POP,
|
||||
/*35*/ JSOP_SWAP,
|
||||
/*36*/ JSOP_DUP,
|
||||
/*37*/ JSOP_DUP,
|
||||
/*38*/ JSOP_GETPROP, 0, COMMON_ATOM_INDEX(valueOf),
|
||||
/*41*/ JSOP_IFPRIMTOP, 0, 16,
|
||||
/*44*/ JSOP_SWAP,
|
||||
/*45*/ JSOP_STRING, 0, COMMON_TYPE_ATOM_INDEX(JSTYPE_VOID),
|
||||
/*48*/ JSOP_CALL, 0, 1,
|
||||
/*51*/ JSOP_IFPRIMTOP, 0, 17,
|
||||
/*54*/ JSOP_GOTO, 0, 4,
|
||||
/*57*/ JSOP_POP,
|
||||
/*58*/ JSOP_POP,
|
||||
/*59*/ JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(toString),
|
||||
/*62*/ JSOP_CALL, 0, 0,
|
||||
/*65*/ JSOP_GOTO, 0, 5,
|
||||
/*68*/ JSOP_SWAP,
|
||||
/*69*/ JSOP_POP,
|
||||
/*70*/ JSOP_ADD,
|
||||
/*71*/ JSOP_STOP,
|
||||
},
|
||||
};
|
||||
uint8 js_opcode2extra[JSOP_LIMIT] = {
|
||||
0, /* JSOP_INTERRUPT */
|
||||
0, /* JSOP_PUSH */
|
||||
0, /* JSOP_POPV */
|
||||
0, /* JSOP_ENTERWITH */
|
||||
0, /* JSOP_LEAVEWITH */
|
||||
0, /* JSOP_RETURN */
|
||||
0, /* JSOP_GOTO */
|
||||
0, /* JSOP_IFEQ */
|
||||
0, /* JSOP_IFNE */
|
||||
0, /* JSOP_ARGUMENTS */
|
||||
0, /* JSOP_FORARG */
|
||||
0, /* JSOP_FORLOCAL */
|
||||
0, /* JSOP_DUP */
|
||||
0, /* JSOP_DUP2 */
|
||||
0, /* JSOP_SETCONST */
|
||||
3, /* JSOP_BITOR */
|
||||
3, /* JSOP_BITXOR */
|
||||
3, /* JSOP_BITAND */
|
||||
3, /* JSOP_EQ */
|
||||
3, /* JSOP_NE */
|
||||
3, /* JSOP_LT */
|
||||
3, /* JSOP_LE */
|
||||
3, /* JSOP_GT */
|
||||
3, /* JSOP_GE */
|
||||
3, /* JSOP_LSH */
|
||||
3, /* JSOP_RSH */
|
||||
3, /* JSOP_URSH */
|
||||
3, /* JSOP_ADD */
|
||||
3, /* JSOP_SUB */
|
||||
3, /* JSOP_MUL */
|
||||
3, /* JSOP_DIV */
|
||||
3, /* JSOP_MOD */
|
||||
0, /* JSOP_NOT */
|
||||
0, /* JSOP_BITNOT */
|
||||
0, /* JSOP_NEG */
|
||||
0, /* JSOP_NEW */
|
||||
0, /* JSOP_DELNAME */
|
||||
0, /* JSOP_DELPROP */
|
||||
0, /* JSOP_DELELEM */
|
||||
0, /* JSOP_TYPEOF */
|
||||
0, /* JSOP_VOID */
|
||||
0, /* JSOP_INCNAME */
|
||||
0, /* JSOP_INCPROP */
|
||||
0, /* JSOP_INCELEM */
|
||||
0, /* JSOP_DECNAME */
|
||||
0, /* JSOP_DECPROP */
|
||||
0, /* JSOP_DECELEM */
|
||||
0, /* JSOP_NAMEINC */
|
||||
0, /* JSOP_PROPINC */
|
||||
0, /* JSOP_ELEMINC */
|
||||
0, /* JSOP_NAMEDEC */
|
||||
0, /* JSOP_PROPDEC */
|
||||
0, /* JSOP_ELEMDEC */
|
||||
0, /* JSOP_GETPROP */
|
||||
0, /* JSOP_SETPROP */
|
||||
0, /* JSOP_GETELEM */
|
||||
0, /* JSOP_SETELEM */
|
||||
0, /* JSOP_CALLNAME */
|
||||
0, /* JSOP_CALL */
|
||||
0, /* JSOP_NAME */
|
||||
0, /* JSOP_DOUBLE */
|
||||
0, /* JSOP_STRING */
|
||||
0, /* JSOP_ZERO */
|
||||
0, /* JSOP_ONE */
|
||||
0, /* JSOP_NULL */
|
||||
0, /* JSOP_THIS */
|
||||
0, /* JSOP_FALSE */
|
||||
0, /* JSOP_TRUE */
|
||||
0, /* JSOP_OR */
|
||||
0, /* JSOP_AND */
|
||||
0, /* JSOP_TABLESWITCH */
|
||||
0, /* JSOP_LOOKUPSWITCH */
|
||||
0, /* JSOP_STRICTEQ */
|
||||
0, /* JSOP_STRICTNE */
|
||||
0, /* JSOP_NULLTHIS */
|
||||
0, /* JSOP_ITER */
|
||||
0, /* JSOP_NEXTITER */
|
||||
0, /* JSOP_ENDITER */
|
||||
0, /* JSOP_APPLY */
|
||||
0, /* JSOP_SWAP */
|
||||
0, /* JSOP_OBJECT */
|
||||
0, /* JSOP_POP */
|
||||
0, /* JSOP_POS */
|
||||
0, /* JSOP_TRAP */
|
||||
0, /* JSOP_GETARG */
|
||||
0, /* JSOP_SETARG */
|
||||
0, /* JSOP_GETLOCAL */
|
||||
0, /* JSOP_SETLOCAL */
|
||||
0, /* JSOP_UINT16 */
|
||||
0, /* JSOP_NEWINIT */
|
||||
0, /* JSOP_ENDINIT */
|
||||
0, /* JSOP_INITPROP */
|
||||
0, /* JSOP_INITELEM */
|
||||
0, /* JSOP_DEFSHARP */
|
||||
0, /* JSOP_USESHARP */
|
||||
0, /* JSOP_INCARG */
|
||||
0, /* JSOP_DECARG */
|
||||
0, /* JSOP_ARGINC */
|
||||
0, /* JSOP_ARGDEC */
|
||||
0, /* JSOP_INCLOCAL */
|
||||
0, /* JSOP_DECLOCAL */
|
||||
0, /* JSOP_LOCALINC */
|
||||
0, /* JSOP_LOCALDEC */
|
||||
0, /* JSOP_IMACOP */
|
||||
0, /* JSOP_FORNAME */
|
||||
0, /* JSOP_FORPROP */
|
||||
0, /* JSOP_FORELEM */
|
||||
0, /* JSOP_POPN */
|
||||
0, /* JSOP_BINDNAME */
|
||||
0, /* JSOP_SETNAME */
|
||||
0, /* JSOP_THROW */
|
||||
0, /* JSOP_IN */
|
||||
0, /* JSOP_INSTANCEOF */
|
||||
0, /* JSOP_DEBUGGER */
|
||||
0, /* JSOP_GOSUB */
|
||||
0, /* JSOP_RETSUB */
|
||||
0, /* JSOP_EXCEPTION */
|
||||
0, /* JSOP_LINENO */
|
||||
0, /* JSOP_CONDSWITCH */
|
||||
0, /* JSOP_CASE */
|
||||
0, /* JSOP_DEFAULT */
|
||||
0, /* JSOP_EVAL */
|
||||
0, /* JSOP_ENUMELEM */
|
||||
0, /* JSOP_GETTER */
|
||||
0, /* JSOP_SETTER */
|
||||
0, /* JSOP_DEFFUN */
|
||||
0, /* JSOP_DEFCONST */
|
||||
0, /* JSOP_DEFVAR */
|
||||
0, /* JSOP_ANONFUNOBJ */
|
||||
0, /* JSOP_NAMEDFUNOBJ */
|
||||
0, /* JSOP_SETLOCALPOP */
|
||||
0, /* JSOP_IFPRIMTOP */
|
||||
0, /* JSOP_SETCALL */
|
||||
0, /* JSOP_TRY */
|
||||
0, /* JSOP_FINALLY */
|
||||
0, /* JSOP_NOP */
|
||||
0, /* JSOP_ARGSUB */
|
||||
0, /* JSOP_ARGCNT */
|
||||
0, /* JSOP_DEFLOCALFUN */
|
||||
0, /* JSOP_GOTOX */
|
||||
0, /* JSOP_IFEQX */
|
||||
0, /* JSOP_IFNEX */
|
||||
0, /* JSOP_ORX */
|
||||
0, /* JSOP_ANDX */
|
||||
0, /* JSOP_GOSUBX */
|
||||
0, /* JSOP_CASEX */
|
||||
0, /* JSOP_DEFAULTX */
|
||||
0, /* JSOP_TABLESWITCHX */
|
||||
0, /* JSOP_LOOKUPSWITCHX */
|
||||
0, /* JSOP_BACKPATCH */
|
||||
0, /* JSOP_BACKPATCH_POP */
|
||||
0, /* JSOP_THROWING */
|
||||
0, /* JSOP_SETRVAL */
|
||||
0, /* JSOP_RETRVAL */
|
||||
0, /* JSOP_GETGVAR */
|
||||
0, /* JSOP_SETGVAR */
|
||||
0, /* JSOP_INCGVAR */
|
||||
0, /* JSOP_DECGVAR */
|
||||
0, /* JSOP_GVARINC */
|
||||
0, /* JSOP_GVARDEC */
|
||||
0, /* JSOP_REGEXP */
|
||||
0, /* JSOP_DEFXMLNS */
|
||||
0, /* JSOP_ANYNAME */
|
||||
0, /* JSOP_QNAMEPART */
|
||||
0, /* JSOP_QNAMECONST */
|
||||
0, /* JSOP_QNAME */
|
||||
0, /* JSOP_TOATTRNAME */
|
||||
0, /* JSOP_TOATTRVAL */
|
||||
0, /* JSOP_ADDATTRNAME */
|
||||
0, /* JSOP_ADDATTRVAL */
|
||||
0, /* JSOP_BINDXMLNAME */
|
||||
0, /* JSOP_SETXMLNAME */
|
||||
0, /* JSOP_XMLNAME */
|
||||
0, /* JSOP_DESCENDANTS */
|
||||
0, /* JSOP_FILTER */
|
||||
0, /* JSOP_ENDFILTER */
|
||||
0, /* JSOP_TOXML */
|
||||
0, /* JSOP_TOXMLLIST */
|
||||
0, /* JSOP_XMLTAGEXPR */
|
||||
0, /* JSOP_XMLELTEXPR */
|
||||
0, /* JSOP_XMLOBJECT */
|
||||
0, /* JSOP_XMLCDATA */
|
||||
0, /* JSOP_XMLCOMMENT */
|
||||
0, /* JSOP_XMLPI */
|
||||
0, /* JSOP_CALLPROP */
|
||||
0, /* JSOP_GETFUNNS */
|
||||
0, /* JSOP_GETUPVAR */
|
||||
0, /* JSOP_DELDESC */
|
||||
0, /* JSOP_UINT24 */
|
||||
0, /* JSOP_INDEXBASE */
|
||||
0, /* JSOP_RESETBASE */
|
||||
0, /* JSOP_RESETBASE0 */
|
||||
0, /* JSOP_STARTXML */
|
||||
0, /* JSOP_STARTXMLEXPR */
|
||||
0, /* JSOP_CALLELEM */
|
||||
0, /* JSOP_STOP */
|
||||
0, /* JSOP_GETXPROP */
|
||||
0, /* JSOP_CALLXMLNAME */
|
||||
0, /* JSOP_TYPEOFEXPR */
|
||||
0, /* JSOP_ENTERBLOCK */
|
||||
0, /* JSOP_LEAVEBLOCK */
|
||||
0, /* JSOP_UNUSED201 */
|
||||
0, /* JSOP_UNUSED202 */
|
||||
0, /* JSOP_UNUSED203 */
|
||||
0, /* JSOP_UNUSED204 */
|
||||
0, /* JSOP_UNUSED205 */
|
||||
0, /* JSOP_UNUSED206 */
|
||||
0, /* JSOP_UNUSED207 */
|
||||
0, /* JSOP_UNUSED208 */
|
||||
0, /* JSOP_UNUSED209 */
|
||||
0, /* JSOP_GENERATOR */
|
||||
0, /* JSOP_YIELD */
|
||||
0, /* JSOP_ARRAYPUSH */
|
||||
0, /* JSOP_CALLUPVAR */
|
||||
0, /* JSOP_ENUMCONSTELEM */
|
||||
0, /* JSOP_LEAVEBLOCKEXPR */
|
||||
0, /* JSOP_GETTHISPROP */
|
||||
0, /* JSOP_GETARGPROP */
|
||||
0, /* JSOP_GETLOCALPROP */
|
||||
0, /* JSOP_UNUSED219 */
|
||||
0, /* JSOP_INDEXBASE1 */
|
||||
0, /* JSOP_INDEXBASE2 */
|
||||
0, /* JSOP_INDEXBASE3 */
|
||||
0, /* JSOP_CALLGVAR */
|
||||
0, /* JSOP_CALLLOCAL */
|
||||
0, /* JSOP_CALLARG */
|
||||
0, /* JSOP_UNUSED226 */
|
||||
0, /* JSOP_INT8 */
|
||||
0, /* JSOP_INT32 */
|
||||
0, /* JSOP_LENGTH */
|
||||
0, /* JSOP_NEWARRAY */
|
||||
0, /* JSOP_HOLE */
|
||||
};
|
210
js/src/imacros.jsasm
Normal file
210
js/src/imacros.jsasm
Normal file
@ -0,0 +1,210 @@
|
||||
# vim: set sw=4 ts=8 et tw=78 ft=asm:
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is the TraceMonkey IMacro Assembler.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Brendan Eich <brendan@mozilla.org>.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2008
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
.igroup binary JSOP_BITOR-JSOP_MOD
|
||||
|
||||
.imacro any_obj # any obj
|
||||
dup # any obj obj
|
||||
dup # any obj obj obj
|
||||
getprop valueOf # any obj obj valueOf
|
||||
ifprimtop 1 # any obj obj valueOf
|
||||
swap # any obj valueOf obj
|
||||
string number # any obj valueOf obj "number"
|
||||
call 1 # any obj rval
|
||||
ifprimtop 3 # any obj rval
|
||||
goto 2
|
||||
1: pop # any obj obj
|
||||
2: pop # any obj
|
||||
callprop toString # any toString obj
|
||||
call 0 # any rval
|
||||
goto 4 # any rval
|
||||
3: swap # any rval obj
|
||||
pop # any rval
|
||||
4: imacop # bval
|
||||
stop
|
||||
.end
|
||||
|
||||
.imacro obj_any # obj any
|
||||
swap # any obj
|
||||
dup # any obj obj
|
||||
dup # any obj obj obj
|
||||
getprop valueOf # any obj obj valueOf
|
||||
ifprimtop 1 # any obj obj valueOf
|
||||
swap # any obj valueOf obj
|
||||
string number # any obj valueOf obj "number"
|
||||
call 1 # any obj lval
|
||||
ifprimtop 3 # any obj lval
|
||||
goto 2
|
||||
1: pop # any obj obj
|
||||
2: pop # any obj
|
||||
callprop toString # any toString obj
|
||||
call 0 # any lval
|
||||
goto 4 # any lval
|
||||
3: swap # any lval obj
|
||||
pop # any lval
|
||||
4: swap # lval any
|
||||
imacop # bval
|
||||
stop
|
||||
.end
|
||||
|
||||
.imacro obj_obj # obj1 obj2
|
||||
swap # obj2 obj1
|
||||
dup # obj2 obj1 obj1
|
||||
dup # obj2 obj1 obj1 obj1
|
||||
getprop valueOf # obj2 obj1 obj1 valueOf
|
||||
ifprimtop 1 # obj2 obj1 obj1 valueOf
|
||||
swap # obj2 obj1 valueOf obj1
|
||||
string number # obj2 obj1 valueOf obj1 "number"
|
||||
call 1 # obj2 obj1 lval
|
||||
ifprimtop 3 # obj2 obj1 lval
|
||||
goto 2
|
||||
1: pop # obj2 obj1 obj1
|
||||
2: pop # obj2 obj1
|
||||
callprop toString # obj2 toString obj1
|
||||
call 0 # obj2 lval
|
||||
goto 4 # obj2 lval
|
||||
3: swap # obj2 lval obj1
|
||||
pop # obj2 lval
|
||||
4: swap # lval obj2
|
||||
dup # lval obj1 obj1
|
||||
dup # lval obj obj obj
|
||||
getprop valueOf # lval obj obj valueOf
|
||||
ifprimtop 5 # lval obj obj valueOf
|
||||
swap # lval obj valueOf obj
|
||||
string number # lval obj valueOf obj "number"
|
||||
call 1 # lval obj rval
|
||||
ifprimtop 7 # lval obj rval
|
||||
goto 6
|
||||
5: pop # lval obj obj
|
||||
6: pop # lval obj
|
||||
callprop toString # lval toString obj
|
||||
call 0 # lval rval
|
||||
goto 8 # lval rval
|
||||
7: swap # lval rval obj
|
||||
pop # lval rval
|
||||
8: imacop # bval
|
||||
stop
|
||||
.end
|
||||
|
||||
.end
|
||||
|
||||
.igroup add JSOP_ADD
|
||||
|
||||
.imacro any_obj # any obj
|
||||
dup # any obj obj
|
||||
dup # any obj obj obj
|
||||
getprop valueOf # any obj obj valueOf
|
||||
ifprimtop 1 # any obj obj valueOf
|
||||
swap # any obj valueOf obj
|
||||
string void # lval obj valueOf obj "void"
|
||||
call 1 # any obj rval
|
||||
ifprimtop 3 # any obj rval
|
||||
goto 2
|
||||
1: pop # any obj obj
|
||||
2: pop # any obj
|
||||
callprop toString # any toString obj
|
||||
call 0 # any rval
|
||||
goto 4 # any rval
|
||||
3: swap # any rval obj
|
||||
pop # any rval
|
||||
4: add # aval
|
||||
stop
|
||||
.end
|
||||
|
||||
.imacro obj_any # obj any
|
||||
swap # any obj
|
||||
dup # any obj obj
|
||||
dup # any obj obj obj
|
||||
getprop valueOf # any obj obj valueOf
|
||||
ifprimtop 1 # any obj obj valueOf
|
||||
swap # any obj valueOf obj
|
||||
string void # lval obj valueOf obj "void"
|
||||
call 1 # any obj lval
|
||||
ifprimtop 3 # any obj lval
|
||||
goto 2
|
||||
1: pop # any obj obj
|
||||
2: pop # any obj
|
||||
callprop toString # any toString obj
|
||||
call 0 # any lval
|
||||
goto 4 # any lval
|
||||
3: swap # any lval obj
|
||||
pop # any lval
|
||||
4: swap # lval any
|
||||
add # aval
|
||||
stop
|
||||
.end
|
||||
|
||||
.imacro obj_obj # obj1 obj2
|
||||
swap # obj2 obj1
|
||||
dup # obj2 obj1 obj1
|
||||
dup # obj2 obj1 obj1 obj1
|
||||
getprop valueOf # obj2 obj1 obj1 valueOf
|
||||
ifprimtop 1 # obj2 obj1 obj1 valueOf
|
||||
swap # obj2 obj1 valueOf obj1
|
||||
string void # lval obj valueOf obj "void"
|
||||
call 1 # obj2 obj1 lval
|
||||
ifprimtop 3 # obj2 obj1 lval
|
||||
goto 2
|
||||
1: pop # obj2 obj1 obj1
|
||||
2: pop # obj2 obj1
|
||||
callprop toString # obj2 toString obj1
|
||||
call 0 # obj2 lval
|
||||
goto 4 # obj2 lval
|
||||
3: swap # obj2 lval obj1
|
||||
pop # obj2 lval
|
||||
4: swap # lval obj2
|
||||
dup # lval obj1 obj1
|
||||
dup # lval obj obj obj
|
||||
getprop valueOf # lval obj obj valueOf
|
||||
ifprimtop 5 # lval obj obj valueOf
|
||||
swap # lval obj valueOf obj
|
||||
string void # lval obj valueOf obj "void"
|
||||
call 1 # lval obj rval
|
||||
ifprimtop 7 # lval obj rval
|
||||
goto 6
|
||||
5: pop # lval obj obj
|
||||
6: pop # lval obj
|
||||
callprop toString # lval toString obj
|
||||
call 0 # lval rval
|
||||
goto 8 # lval rval
|
||||
7: swap # lval rval obj
|
||||
pop # lval rval
|
||||
8: add # aval
|
||||
stop
|
||||
.end
|
||||
|
||||
.end
|
280
js/src/js.cpp
280
js/src/js.cpp
@ -310,10 +310,18 @@ Process(JSContext *cx, JSObject *obj, char *filename, JSBool forceTTY)
|
||||
lineno++;
|
||||
} while (!JS_BufferIsCompilableUnit(cx, obj, buffer, strlen(buffer)));
|
||||
|
||||
/* Clear any pending exception from previous failed compiles. */
|
||||
/* Clear any pending exception from previous failed compiles. */
|
||||
JS_ClearPendingException(cx);
|
||||
|
||||
/* Even though we're interactive, we have a compile-n-go opportunity. */
|
||||
oldopts = JS_GetOptions(cx);
|
||||
if (!compileOnly)
|
||||
JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO);
|
||||
script = JS_CompileScript(cx, obj, buffer, strlen(buffer), "typein",
|
||||
startline);
|
||||
if (!compileOnly)
|
||||
JS_SetOptions(cx, oldopts);
|
||||
|
||||
if (script) {
|
||||
if (!compileOnly) {
|
||||
ok = JS_ExecuteScript(cx, obj, script, &result);
|
||||
@ -2901,6 +2909,131 @@ fail:
|
||||
JS_DEFINE_TRCINFO_1(Print, (2, (static, JSVAL_FAIL, Print_tn, CONTEXT, STRING, 0, 0)))
|
||||
JS_DEFINE_TRCINFO_1(ShapeOf, (1, (static, INT32, ShapeOf_tn, OBJECT, 0, 0)))
|
||||
|
||||
#ifdef XP_UNIX
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/*
|
||||
* Returns a JS_malloc'd string (that the caller needs to JS_free)
|
||||
* containing the directory (non-leaf) part of |from| prepended to |leaf|.
|
||||
* If |from| is empty or a leaf, MakeAbsolutePathname returns a copy of leaf.
|
||||
* Returns NULL to indicate an error.
|
||||
*/
|
||||
static char *
|
||||
MakeAbsolutePathname(JSContext *cx, const char *from, const char *leaf)
|
||||
{
|
||||
size_t dirlen;
|
||||
char *dir;
|
||||
const char *slash = NULL, *cp;
|
||||
|
||||
cp = from;
|
||||
while (*cp) {
|
||||
if (*cp == '/'
|
||||
#ifdef XP_WIN
|
||||
|| *cp == '\\'
|
||||
#endif
|
||||
) {
|
||||
slash = cp;
|
||||
}
|
||||
|
||||
++cp;
|
||||
}
|
||||
|
||||
if (!slash) {
|
||||
/* We were given a leaf or |from| was empty. */
|
||||
return JS_strdup(cx, leaf);
|
||||
}
|
||||
|
||||
/* Else, we were given a real pathname, return that + the leaf. */
|
||||
dirlen = slash - from + 1;
|
||||
dir = (char*) JS_malloc(cx, dirlen + strlen(leaf) + 1);
|
||||
if (!dir)
|
||||
return NULL;
|
||||
|
||||
strncpy(dir, from, dirlen);
|
||||
strcpy(dir + dirlen, leaf); /* Note: we can't use strcat here. */
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
#endif // XP_UNIX
|
||||
|
||||
static JSBool
|
||||
Snarf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
JSString *str;
|
||||
const char *filename;
|
||||
char *pathname;
|
||||
JSStackFrame *fp;
|
||||
JSBool ok;
|
||||
off_t cc, len;
|
||||
char *buf;
|
||||
FILE *file;
|
||||
|
||||
str = JS_ValueToString(cx, argv[0]);
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
filename = JS_GetStringBytes(str);
|
||||
|
||||
/* Get the currently executing script's name. */
|
||||
fp = JS_GetScriptedCaller(cx, NULL);
|
||||
JS_ASSERT(fp && fp->script->filename);
|
||||
#ifdef XP_UNIX
|
||||
pathname = MakeAbsolutePathname(cx, fp->script->filename, filename);
|
||||
if (!pathname)
|
||||
return JS_FALSE;
|
||||
#else
|
||||
pathname = filename;
|
||||
#endif
|
||||
|
||||
ok = JS_FALSE;
|
||||
len = 0;
|
||||
buf = NULL;
|
||||
file = fopen(pathname, "rb");
|
||||
if (!file) {
|
||||
JS_ReportError(cx, "can't open %s: %s", pathname, strerror(errno));
|
||||
} else {
|
||||
if (fseek(file, 0, SEEK_END) == EOF) {
|
||||
JS_ReportError(cx, "can't seek end of %s", pathname);
|
||||
} else {
|
||||
len = ftell(file);
|
||||
if (len == -1 || fseek(file, 0, SEEK_SET) == EOF) {
|
||||
JS_ReportError(cx, "can't seek start of %s", pathname);
|
||||
} else {
|
||||
buf = (char*) JS_malloc(cx, len + 1);
|
||||
if (buf) {
|
||||
cc = fread(buf, 1, len, file);
|
||||
if (cc != len) {
|
||||
JS_free(cx, buf);
|
||||
JS_ReportError(cx, "can't read %s: %s", pathname,
|
||||
(cc < 0) ? strerror(errno)
|
||||
: "short read");
|
||||
} else {
|
||||
len = (size_t)cc;
|
||||
ok = JS_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
JS_free(cx, pathname);
|
||||
if (!ok) {
|
||||
JS_free(cx, buf);
|
||||
return ok;
|
||||
}
|
||||
|
||||
buf[len] = '\0';
|
||||
str = JS_NewString(cx, buf, len);
|
||||
if (!str) {
|
||||
JS_free(cx, buf);
|
||||
return JS_FALSE;
|
||||
}
|
||||
*rval = STRING_TO_JSVAL(str);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* We use a mix of JS_FS and JS_FN to test both kinds of natives. */
|
||||
static JSFunctionSpec shell_functions[] = {
|
||||
JS_FS("version", Version, 0,0,0),
|
||||
@ -2947,29 +3080,30 @@ static JSFunctionSpec shell_functions[] = {
|
||||
JS_FS("evalcx", EvalInContext, 1,0,0),
|
||||
JS_TN("shapeOf", ShapeOf, 1,0, ShapeOf_trcinfo),
|
||||
#ifdef MOZ_SHARK
|
||||
JS_FS("startShark", js_StartShark, 0,0,0),
|
||||
JS_FS("stopShark", js_StopShark, 0,0,0),
|
||||
JS_FS("connectShark", js_ConnectShark, 0,0,0),
|
||||
JS_FS("disconnectShark", js_DisconnectShark, 0,0,0),
|
||||
JS_FS("startShark", js_StartShark, 0,0,0),
|
||||
JS_FS("stopShark", js_StopShark, 0,0,0),
|
||||
JS_FS("connectShark", js_ConnectShark, 0,0,0),
|
||||
JS_FS("disconnectShark",js_DisconnectShark, 0,0,0),
|
||||
#endif
|
||||
#ifdef MOZ_CALLGRIND
|
||||
JS_FS("startCallgrind", js_StartCallgrind, 0,0,0),
|
||||
JS_FS("stopCallgrind", js_StopCallgrind, 0,0,0),
|
||||
JS_FS("dumpCallgrind", js_DumpCallgrind, 1,0,0),
|
||||
JS_FS("startCallgrind", js_StartCallgrind, 0,0,0),
|
||||
JS_FS("stopCallgrind", js_StopCallgrind, 0,0,0),
|
||||
JS_FS("dumpCallgrind", js_DumpCallgrind, 1,0,0),
|
||||
#endif
|
||||
#ifdef MOZ_VTUNE
|
||||
JS_FS("startVtune", js_StartVtune, 1,0,0),
|
||||
JS_FS("stopVtune", js_StopVtune, 0,0,0),
|
||||
JS_FS("pauseVtune", js_PauseVtune, 0,0,0),
|
||||
JS_FS("resumeVtune", js_ResumeVtune, 0,0,0),
|
||||
JS_FS("startVtune", js_StartVtune, 1,0,0),
|
||||
JS_FS("stopVtune", js_StopVtune, 0,0,0),
|
||||
JS_FS("pauseVtune", js_PauseVtune, 0,0,0),
|
||||
JS_FS("resumeVtune", js_ResumeVtune, 0,0,0),
|
||||
#endif
|
||||
#ifdef DEBUG_ARRAYS
|
||||
JS_FS("arrayInfo", js_ArrayInfo, 1,0,0),
|
||||
JS_FS("arrayInfo", js_ArrayInfo, 1,0,0),
|
||||
#endif
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_FN("sleep", Sleep_fn, 1,0),
|
||||
JS_FN("scatter", Scatter, 1,0),
|
||||
#endif
|
||||
JS_FS("snarf", Snarf, 0,0,0),
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
@ -3057,6 +3191,7 @@ static const char *const shell_help_messages[] = {
|
||||
"sleep(dt) Sleep for dt seconds",
|
||||
"scatter(fns) Call functions concurrently (ignoring errors)",
|
||||
#endif
|
||||
"snarf(filename) Read filename into returned string"
|
||||
};
|
||||
|
||||
/* Help messages must match shell functions. */
|
||||
@ -3820,123 +3955,6 @@ Evaluate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
return ok;
|
||||
}
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/*
|
||||
* Returns a JS_malloc'd string (that the caller needs to JS_free)
|
||||
* containing the directory (non-leaf) part of |from| prepended to |leaf|.
|
||||
* If |from| is empty or a leaf, MakeAbsolutePathname returns a copy of leaf.
|
||||
* Returns NULL to indicate an error.
|
||||
*/
|
||||
static char *
|
||||
MakeAbsolutePathname(JSContext *cx, const char *from, const char *leaf)
|
||||
{
|
||||
size_t dirlen;
|
||||
char *dir;
|
||||
const char *slash = NULL, *cp;
|
||||
|
||||
cp = from;
|
||||
while (*cp) {
|
||||
if (*cp == '/'
|
||||
#ifdef XP_WIN
|
||||
|| *cp == '\\'
|
||||
#endif
|
||||
) {
|
||||
slash = cp;
|
||||
}
|
||||
|
||||
++cp;
|
||||
}
|
||||
|
||||
if (!slash) {
|
||||
/* We were given a leaf or |from| was empty. */
|
||||
return JS_strdup(cx, leaf);
|
||||
}
|
||||
|
||||
/* Else, we were given a real pathname, return that + the leaf. */
|
||||
dirlen = slash - from + 1;
|
||||
dir = (char*) JS_malloc(cx, dirlen + strlen(leaf) + 1);
|
||||
if (!dir)
|
||||
return NULL;
|
||||
|
||||
strncpy(dir, from, dirlen);
|
||||
strcpy(dir + dirlen, leaf); /* Note: we can't use strcat here. */
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
snarf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
JSString *str;
|
||||
const char *filename;
|
||||
char *pathname;
|
||||
JSStackFrame *fp;
|
||||
JSBool ok;
|
||||
off_t cc, len;
|
||||
char *buf;
|
||||
FILE *file;
|
||||
|
||||
str = JS_ValueToString(cx, argv[0]);
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
filename = JS_GetStringBytes(str);
|
||||
|
||||
/* Get the currently executing script's name. */
|
||||
fp = JS_GetScriptedCaller(cx, NULL);
|
||||
JS_ASSERT(fp && fp->script->filename);
|
||||
pathname = MakeAbsolutePathname(cx, fp->script->filename, filename);
|
||||
if (!pathname)
|
||||
return JS_FALSE;
|
||||
|
||||
ok = JS_FALSE;
|
||||
len = 0;
|
||||
buf = NULL;
|
||||
file = fopen(pathname, "rb");
|
||||
if (!file) {
|
||||
JS_ReportError(cx, "can't open %s: %s", pathname, strerror(errno));
|
||||
} else {
|
||||
if (fseek(file, 0, SEEK_END) == EOF) {
|
||||
JS_ReportError(cx, "can't seek end of %s", pathname);
|
||||
} else {
|
||||
len = ftell(file);
|
||||
if (len == -1 || fseek(file, 0, SEEK_SET) == EOF) {
|
||||
JS_ReportError(cx, "can't seek start of %s", pathname);
|
||||
} else {
|
||||
buf = (char*) JS_malloc(cx, len + 1);
|
||||
if (buf) {
|
||||
cc = fread(buf, 1, len, file);
|
||||
if (cc != len) {
|
||||
JS_free(cx, buf);
|
||||
JS_ReportError(cx, "can't read %s: %s", pathname,
|
||||
(cc < 0) ? strerror(errno)
|
||||
: "short read");
|
||||
} else {
|
||||
len = (size_t)cc;
|
||||
ok = JS_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
JS_free(cx, pathname);
|
||||
if (!ok) {
|
||||
JS_free(cx, buf);
|
||||
return ok;
|
||||
}
|
||||
|
||||
buf[len] = '\0';
|
||||
str = JS_NewString(cx, buf, len);
|
||||
if (!str) {
|
||||
JS_free(cx, buf);
|
||||
return JS_FALSE;
|
||||
}
|
||||
*rval = STRING_TO_JSVAL(str);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
#endif /* NARCISSUS */
|
||||
|
||||
static JSBool
|
||||
@ -4070,8 +4088,6 @@ main(int argc, char **argv, char **envp)
|
||||
jsval v;
|
||||
static const char Object_prototype[] = "Object.prototype";
|
||||
|
||||
if (!JS_DefineFunction(cx, glob, "snarf", snarf, 1, 0))
|
||||
return 1;
|
||||
if (!JS_DefineFunction(cx, glob, "evaluate", Evaluate, 3, 0))
|
||||
return 1;
|
||||
|
||||
|
@ -402,7 +402,7 @@ JSBool FASTCALL
|
||||
js_HasNamedProperty(JSContext* cx, JSObject* obj, JSString* idstr)
|
||||
{
|
||||
jsid id;
|
||||
if (!obj || !js_ValueToStringId(cx, STRING_TO_JSVAL(idstr), &id))
|
||||
if (!js_ValueToStringId(cx, STRING_TO_JSVAL(idstr), &id))
|
||||
return JSVAL_TO_BOOLEAN(JSVAL_VOID);
|
||||
|
||||
JSObject* obj2;
|
||||
@ -418,7 +418,7 @@ JSBool FASTCALL
|
||||
js_HasNamedPropertyInt32(JSContext* cx, JSObject* obj, int32 index)
|
||||
{
|
||||
jsid id;
|
||||
if (!obj || !js_Int32ToId(cx, index, &id))
|
||||
if (!js_Int32ToId(cx, index, &id))
|
||||
return JSVAL_TO_BOOLEAN(JSVAL_VOID);
|
||||
|
||||
JSObject* obj2;
|
||||
@ -471,18 +471,6 @@ js_BooleanOrUndefinedToString(JSContext *cx, int32 unboxed)
|
||||
return ATOM_TO_STRING(cx->runtime->atomState.booleanAtoms[unboxed]);
|
||||
}
|
||||
|
||||
JSString* FASTCALL
|
||||
js_ObjectToString(JSContext* cx, JSObject* obj)
|
||||
{
|
||||
if (!obj)
|
||||
return ATOM_TO_STRING(cx->runtime->atomState.nullAtom);
|
||||
jsval v;
|
||||
if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_STRING, &v))
|
||||
return NULL;
|
||||
JS_ASSERT(JSVAL_IS_STRING(v));
|
||||
return JSVAL_TO_STRING(v);
|
||||
}
|
||||
|
||||
JSObject* FASTCALL
|
||||
js_Arguments(JSContext* cx)
|
||||
{
|
||||
|
@ -157,18 +157,22 @@ UpdateDepth(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t target)
|
||||
jsbytecode *pc;
|
||||
JSOp op;
|
||||
const JSCodeSpec *cs;
|
||||
uintN depth;
|
||||
uintN extra, depth;
|
||||
intN nuses, ndefs;
|
||||
extern uint8 js_opcode2extra[];
|
||||
|
||||
pc = CG_CODE(cg, target);
|
||||
op = (JSOp) *pc;
|
||||
cs = &js_CodeSpec[op];
|
||||
if (cs->format & JOF_TMPSLOT_MASK) {
|
||||
extra = js_opcode2extra[op];
|
||||
if ((cs->format & JOF_TMPSLOT_MASK) || extra) {
|
||||
depth = (uintN) cg->stackDepth +
|
||||
((cs->format & JOF_TMPSLOT_MASK) >> JOF_TMPSLOT_SHIFT);
|
||||
((cs->format & JOF_TMPSLOT_MASK) >> JOF_TMPSLOT_SHIFT) +
|
||||
extra;
|
||||
if (depth > cg->maxStackDepth)
|
||||
cg->maxStackDepth = depth;
|
||||
}
|
||||
|
||||
nuses = cs->nuses;
|
||||
if (nuses < 0)
|
||||
nuses = js_GetVariableStackUseLength(op, pc);
|
||||
|
@ -231,7 +231,8 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape,
|
||||
#endif
|
||||
SCOPE_MAKE_UNIQUE_SHAPE(cx, scope);
|
||||
SCOPE_SET_BRANDED(scope);
|
||||
kshape = scope->shape;
|
||||
if (OBJ_SCOPE(obj) == scope)
|
||||
kshape = scope->shape;
|
||||
}
|
||||
vword = JSVAL_OBJECT_TO_PCVAL(v);
|
||||
break;
|
||||
@ -2647,7 +2648,9 @@ js_Interpret(JSContext *cx)
|
||||
ENABLE_TRACER(js_MonitorLoopEdge(cx, inlineCallCount)); \
|
||||
fp = cx->fp; \
|
||||
script = fp->script; \
|
||||
atoms = script->atomMap.vector; \
|
||||
atoms = fp->imacpc \
|
||||
? COMMON_ATOMS_START(&rt->atomState) \
|
||||
: script->atomMap.vector; \
|
||||
currentVersion = (JSVersion) script->version; \
|
||||
JS_ASSERT(fp->regs == ®s); \
|
||||
if (cx->throwing) \
|
||||
@ -3074,7 +3077,9 @@ js_Interpret(JSContext *cx)
|
||||
|
||||
/* Restore the calling script's interpreter registers. */
|
||||
script = fp->script;
|
||||
atoms = script->atomMap.vector;
|
||||
atoms = fp->imacpc
|
||||
? COMMON_ATOMS_START(&rt->atomState)
|
||||
: script->atomMap.vector;
|
||||
|
||||
/* Resume execution in the calling frame. */
|
||||
inlineCallCount--;
|
||||
@ -6482,6 +6487,19 @@ js_Interpret(JSContext *cx)
|
||||
fp->slots[slot] = POP_OPND();
|
||||
END_CASE(JSOP_SETLOCALPOP)
|
||||
|
||||
BEGIN_CASE(JSOP_IFPRIMTOP)
|
||||
/*
|
||||
* If the top of stack is of primitive type, jump to our target.
|
||||
* Otherwise advance to the next opcode.
|
||||
*/
|
||||
JS_ASSERT(regs.sp > StackBase(fp));
|
||||
rval = FETCH_OPND(-1);
|
||||
if (JSVAL_IS_PRIMITIVE(rval)) {
|
||||
len = GET_JUMP_OFFSET(regs.pc);
|
||||
BRANCH(len);
|
||||
}
|
||||
END_CASE(JSOP_IFPRIMTOP)
|
||||
|
||||
BEGIN_CASE(JSOP_INSTANCEOF)
|
||||
rval = FETCH_OPND(-1);
|
||||
if (JSVAL_IS_PRIMITIVE(rval) ||
|
||||
@ -6933,7 +6951,6 @@ js_Interpret(JSContext *cx)
|
||||
L_JSOP_DEFXMLNS:
|
||||
# endif
|
||||
|
||||
L_JSOP_UNUSED131:
|
||||
L_JSOP_UNUSED201:
|
||||
L_JSOP_UNUSED202:
|
||||
L_JSOP_UNUSED203:
|
||||
|
@ -1082,6 +1082,14 @@ obj_valueOf(JSContext *cx, uintN argc, jsval *vp)
|
||||
return !JSVAL_IS_NULL(*vp);
|
||||
}
|
||||
|
||||
#ifdef JS_TRACER
|
||||
static jsval FASTCALL
|
||||
Object_p_valueOf(JSContext* cx, JSObject* obj, JSString *hint)
|
||||
{
|
||||
return OBJECT_TO_JSVAL(obj);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Check whether principals subsumes scopeobj's principals, and return true
|
||||
* if so (or if scopeobj has no principals, for backward compatibility with
|
||||
@ -1810,6 +1818,8 @@ const char js_lookupGetter_str[] = "__lookupGetter__";
|
||||
const char js_lookupSetter_str[] = "__lookupSetter__";
|
||||
#endif
|
||||
|
||||
JS_DEFINE_TRCINFO_1(obj_valueOf,
|
||||
(3, (static, JSVAL, Object_p_valueOf, CONTEXT, THIS, STRING, 0, 0)))
|
||||
JS_DEFINE_TRCINFO_1(obj_hasOwnProperty,
|
||||
(3, (static, BOOL_FAIL, Object_p_hasOwnProperty, CONTEXT, THIS, STRING, 0, 0)))
|
||||
JS_DEFINE_TRCINFO_1(obj_propertyIsEnumerable,
|
||||
@ -1821,7 +1831,8 @@ static JSFunctionSpec object_methods[] = {
|
||||
#endif
|
||||
JS_FN(js_toString_str, obj_toString, 0,0),
|
||||
JS_FN(js_toLocaleString_str, obj_toLocaleString, 0,0),
|
||||
JS_FN(js_valueOf_str, obj_valueOf, 0,0),
|
||||
JS_TN(js_valueOf_str, obj_valueOf, 0,0,
|
||||
obj_valueOf_trcinfo),
|
||||
#if JS_HAS_OBJ_WATCHPOINT
|
||||
JS_FN(js_watch_str, obj_watch, 2,0),
|
||||
JS_FN(js_unwatch_str, obj_unwatch, 1,0),
|
||||
|
@ -127,23 +127,23 @@ OPDEF(JSOP_FORLOCAL, 11, "forlocal", NULL, 3, 2, 2, 19, JOF_LOCAL|
|
||||
OPDEF(JSOP_DUP, 12, "dup", NULL, 1, 1, 2, 0, JOF_BYTE)
|
||||
OPDEF(JSOP_DUP2, 13, "dup2", NULL, 1, 2, 4, 0, JOF_BYTE)
|
||||
OPDEF(JSOP_SETCONST, 14, "setconst", NULL, 3, 1, 1, 3, JOF_ATOM|JOF_NAME|JOF_SET)
|
||||
OPDEF(JSOP_BITOR, 15, "bitor", "|", 1, 2, 1, 7, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2)
|
||||
OPDEF(JSOP_BITXOR, 16, "bitxor", "^", 1, 2, 1, 8, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2)
|
||||
OPDEF(JSOP_BITAND, 17, "bitand", "&", 1, 2, 1, 9, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2)
|
||||
OPDEF(JSOP_BITOR, 15, "bitor", "|", 1, 2, 1, 7, JOF_BYTE|JOF_LEFTASSOC)
|
||||
OPDEF(JSOP_BITXOR, 16, "bitxor", "^", 1, 2, 1, 8, JOF_BYTE|JOF_LEFTASSOC)
|
||||
OPDEF(JSOP_BITAND, 17, "bitand", "&", 1, 2, 1, 9, JOF_BYTE|JOF_LEFTASSOC)
|
||||
OPDEF(JSOP_EQ, 18, "eq", "==", 1, 2, 1, 10, JOF_BYTE|JOF_LEFTASSOC|JOF_DETECTING)
|
||||
OPDEF(JSOP_NE, 19, "ne", "!=", 1, 2, 1, 10, JOF_BYTE|JOF_LEFTASSOC|JOF_DETECTING)
|
||||
OPDEF(JSOP_LT, 20, "lt", "<", 1, 2, 1, 11, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2)
|
||||
OPDEF(JSOP_LE, 21, "le", "<=", 1, 2, 1, 11, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2)
|
||||
OPDEF(JSOP_GT, 22, "gt", ">", 1, 2, 1, 11, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2)
|
||||
OPDEF(JSOP_GE, 23, "ge", ">=", 1, 2, 1, 11, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2)
|
||||
OPDEF(JSOP_LSH, 24, "lsh", "<<", 1, 2, 1, 12, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2)
|
||||
OPDEF(JSOP_RSH, 25, "rsh", ">>", 1, 2, 1, 12, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2)
|
||||
OPDEF(JSOP_URSH, 26, "ursh", ">>>", 1, 2, 1, 12, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2)
|
||||
OPDEF(JSOP_ADD, 27, "add", "+", 1, 2, 1, 13, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2)
|
||||
OPDEF(JSOP_SUB, 28, "sub", "-", 1, 2, 1, 13, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2)
|
||||
OPDEF(JSOP_MUL, 29, "mul", "*", 1, 2, 1, 14, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2)
|
||||
OPDEF(JSOP_DIV, 30, "div", "/", 1, 2, 1, 14, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2)
|
||||
OPDEF(JSOP_MOD, 31, "mod", "%", 1, 2, 1, 14, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2)
|
||||
OPDEF(JSOP_LT, 20, "lt", "<", 1, 2, 1, 11, JOF_BYTE|JOF_LEFTASSOC)
|
||||
OPDEF(JSOP_LE, 21, "le", "<=", 1, 2, 1, 11, JOF_BYTE|JOF_LEFTASSOC)
|
||||
OPDEF(JSOP_GT, 22, "gt", ">", 1, 2, 1, 11, JOF_BYTE|JOF_LEFTASSOC)
|
||||
OPDEF(JSOP_GE, 23, "ge", ">=", 1, 2, 1, 11, JOF_BYTE|JOF_LEFTASSOC)
|
||||
OPDEF(JSOP_LSH, 24, "lsh", "<<", 1, 2, 1, 12, JOF_BYTE|JOF_LEFTASSOC)
|
||||
OPDEF(JSOP_RSH, 25, "rsh", ">>", 1, 2, 1, 12, JOF_BYTE|JOF_LEFTASSOC)
|
||||
OPDEF(JSOP_URSH, 26, "ursh", ">>>", 1, 2, 1, 12, JOF_BYTE|JOF_LEFTASSOC)
|
||||
OPDEF(JSOP_ADD, 27, "add", "+", 1, 2, 1, 13, JOF_BYTE|JOF_LEFTASSOC)
|
||||
OPDEF(JSOP_SUB, 28, "sub", "-", 1, 2, 1, 13, JOF_BYTE|JOF_LEFTASSOC)
|
||||
OPDEF(JSOP_MUL, 29, "mul", "*", 1, 2, 1, 14, JOF_BYTE|JOF_LEFTASSOC)
|
||||
OPDEF(JSOP_DIV, 30, "div", "/", 1, 2, 1, 14, JOF_BYTE|JOF_LEFTASSOC)
|
||||
OPDEF(JSOP_MOD, 31, "mod", "%", 1, 2, 1, 14, JOF_BYTE|JOF_LEFTASSOC)
|
||||
OPDEF(JSOP_NOT, 32, "not", "!", 1, 1, 1, 15, JOF_BYTE|JOF_DETECTING)
|
||||
OPDEF(JSOP_BITNOT, 33, "bitnot", "~", 1, 1, 1, 15, JOF_BYTE)
|
||||
OPDEF(JSOP_NEG, 34, "neg", "- ", 1, 1, 1, 15, JOF_BYTE)
|
||||
@ -333,8 +333,8 @@ OPDEF(JSOP_NAMEDFUNOBJ, 129, "namedfunobj", NULL, 3, 0, 1, 19, JOF_OBJECT
|
||||
*/
|
||||
OPDEF(JSOP_SETLOCALPOP, 130, "setlocalpop", NULL, 3, 1, 0, 3, JOF_LOCAL|JOF_NAME|JOF_SET)
|
||||
|
||||
/* Parenthesization opcode to help the decompiler. */
|
||||
OPDEF(JSOP_UNUSED131, 131, "unused131", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||
/* Jump to target if top of stack value is of primitive type. */
|
||||
OPDEF(JSOP_IFPRIMTOP, 131, "ifprimtop", NULL, 3, 1, 1, 0, JOF_JUMP|JOF_DETECTING)
|
||||
|
||||
/*
|
||||
* Host object extension: given 'o.item(i) = j', the left-hand side compiles
|
||||
|
@ -70,6 +70,7 @@
|
||||
#include "jstracer.h"
|
||||
|
||||
#include "jsautooplen.h" // generated headers last
|
||||
#include "imacros.c.out"
|
||||
|
||||
/* Never use JSVAL_IS_BOOLEAN because it restricts the value (true, false) and
|
||||
the type. What you want to use is JSVAL_TAG(x) == JSVAL_BOOLEAN and then
|
||||
@ -81,8 +82,12 @@
|
||||
range since we only use JSVAL_INT to indicate integers. */
|
||||
#define JSVAL_BOXED 3
|
||||
|
||||
/* Another fake jsval tag, used to distinguish null from object values. */
|
||||
#define JSVAL_TNULL 5
|
||||
|
||||
/* Map to translate a type tag into a printable representation. */
|
||||
static const char typeChar[] = "OIDVS?B?";
|
||||
static const char typeChar[] = "OIDVSNB?";
|
||||
static const char tagChar[] = "OIDISIBI";
|
||||
|
||||
/* Number of iterations of a loop where we start tracing. That is, we don't
|
||||
start tracing until the beginning of the HOTLOOP-th iteration. */
|
||||
@ -344,13 +349,13 @@ static inline bool isInt32(jsval v)
|
||||
/* Return JSVAL_DOUBLE for all numbers (int and double) and the tag otherwise. */
|
||||
static inline uint8 getPromotedType(jsval v)
|
||||
{
|
||||
return JSVAL_IS_INT(v) ? JSVAL_DOUBLE : uint8(JSVAL_TAG(v));
|
||||
return JSVAL_IS_INT(v) ? JSVAL_DOUBLE : JSVAL_IS_NULL(v) ? JSVAL_TNULL : uint8(JSVAL_TAG(v));
|
||||
}
|
||||
|
||||
/* Return JSVAL_INT for all whole numbers that fit into signed 32-bit and the tag otherwise. */
|
||||
static inline uint8 getCoercedType(jsval v)
|
||||
{
|
||||
return isInt32(v) ? JSVAL_INT : (uint8) JSVAL_TAG(v);
|
||||
return isInt32(v) ? JSVAL_INT : JSVAL_IS_NULL(v) ? JSVAL_TNULL : uint8(JSVAL_TAG(v));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1283,6 +1288,10 @@ ValueToNative(JSContext* cx, jsval v, uint8 type, double* slot)
|
||||
*(JSString**)slot = JSVAL_TO_STRING(v);
|
||||
debug_only_v(printf("string<%p> ", *(JSString**)slot);)
|
||||
return;
|
||||
case JSVAL_TNULL:
|
||||
JS_ASSERT(tag == JSVAL_OBJECT);
|
||||
*(JSObject**)slot = NULL;
|
||||
return;
|
||||
default:
|
||||
/* Note: we should never see JSVAL_BOXED in an entry type map. */
|
||||
JS_ASSERT(type == JSVAL_OBJECT);
|
||||
@ -1397,6 +1406,11 @@ NativeToValue(JSContext* cx, jsval& v, uint8 type, double* slot)
|
||||
v = *(jsval*)slot;
|
||||
debug_only_v(printf("box<%lx> ", v));
|
||||
break;
|
||||
case JSVAL_TNULL:
|
||||
JS_ASSERT(*(JSObject**)slot == NULL);
|
||||
v = JSVAL_NULL;
|
||||
debug_only_v(printf("null<%p> ", *(JSObject**)slot));
|
||||
break;
|
||||
default:
|
||||
JS_ASSERT(type == JSVAL_OBJECT);
|
||||
v = OBJECT_TO_JSVAL(*(JSObject**)slot);
|
||||
@ -1809,11 +1823,18 @@ TraceRecorder::determineSlotType(jsval* vp) const
|
||||
LIns* i = get(vp);
|
||||
m = isNumber(*vp)
|
||||
? (isPromoteInt(i) ? JSVAL_INT : JSVAL_DOUBLE)
|
||||
: JSVAL_IS_NULL(*vp)
|
||||
? JSVAL_TNULL
|
||||
: JSVAL_TAG(*vp);
|
||||
JS_ASSERT((m != JSVAL_INT) || isInt32(*vp));
|
||||
return m;
|
||||
}
|
||||
|
||||
/*
|
||||
* Combine fp->imacpc and fp->regs->pc into one word, with 8 bits for the pc
|
||||
* adjustment from one byte before the imacro's start (so a 0 high byte means
|
||||
* we're not in an imacro), and 24 for the pc adjustment from script->code.
|
||||
*/
|
||||
#define IMACRO_PC_ADJ_BITS 8
|
||||
#define SCRIPT_PC_ADJ_BITS (32 - IMACRO_PC_ADJ_BITS)
|
||||
|
||||
@ -1849,6 +1870,9 @@ TraceRecorder::determineSlotType(jsval* vp) const
|
||||
|
||||
static jsbytecode* imacro_code[JSOP_LIMIT];
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(binary_imacros) < IMACRO_PC_ADJ_LIMIT);
|
||||
JS_STATIC_ASSERT(sizeof(add_imacros) < IMACRO_PC_ADJ_LIMIT);
|
||||
|
||||
JS_REQUIRES_STACK LIns*
|
||||
TraceRecorder::snapshot(ExitType exitType)
|
||||
{
|
||||
@ -2036,16 +2060,19 @@ TraceRecorder::checkType(jsval& v, uint8 t, jsval*& stage_val, LIns*& stage_ins,
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (t == JSVAL_TNULL && JSVAL_IS_NULL(v))
|
||||
return true;
|
||||
/* for non-number types we expect a precise match of the type */
|
||||
uint8 vt = getCoercedType(v);
|
||||
#ifdef DEBUG
|
||||
if (JSVAL_TAG(v) != t) {
|
||||
debug_only_v(printf("Type mismatch: val %c, map %c ", typeChar[JSVAL_TAG(v)],
|
||||
if (vt != t) {
|
||||
debug_only_v(printf("Type mismatch: val %c, map %c ", typeChar[vt],
|
||||
typeChar[t]);)
|
||||
}
|
||||
#endif
|
||||
debug_only_v(printf("checkType(tag=%d, t=%d) stage_count=%d\n",
|
||||
(int) JSVAL_TAG(v), t, stage_count);)
|
||||
return JSVAL_TAG(v) == t;
|
||||
debug_only_v(printf("checkType(vt=%d, t=%d) stage_count=%d\n",
|
||||
(int) vt, t, stage_count);)
|
||||
return vt == t;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2192,7 +2219,7 @@ checktype_fail_2:
|
||||
JS_ASSERT(isNumber(*vp));
|
||||
ADD_UNDEMOTE_SLOT(demotes, unsigned(m - typemap));
|
||||
} else {
|
||||
JS_ASSERT(*m == JSVAL_TAG(*vp));
|
||||
JS_ASSERT((*m == JSVAL_TNULL) ? JSVAL_IS_NULL(*vp) : *m == JSVAL_TAG(*vp));
|
||||
}
|
||||
m++;
|
||||
);
|
||||
@ -2626,22 +2653,6 @@ TraceRecorder::hasMethod(JSObject* obj, jsid id)
|
||||
return found;
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::hasToStringMethod(JSObject* obj)
|
||||
{
|
||||
JS_ASSERT(cx->fp->regs->sp + 1 <= cx->fp->slots + cx->fp->script->nslots);
|
||||
|
||||
return hasMethod(obj, ATOM_TO_JSID(cx->runtime->atomState.toStringAtom));
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::hasValueOfMethod(JSObject* obj)
|
||||
{
|
||||
JS_ASSERT(cx->fp->regs->sp + 2 <= cx->fp->slots + cx->fp->script->nslots);
|
||||
|
||||
return hasMethod(obj, ATOM_TO_JSID(cx->runtime->atomState.valueOfAtom));
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::hasIteratorMethod(JSObject* obj)
|
||||
{
|
||||
@ -3304,7 +3315,7 @@ js_IsEntryTypeCompatible(jsval* vp, uint8* m)
|
||||
{
|
||||
unsigned tag = JSVAL_TAG(*vp);
|
||||
|
||||
debug_only_v(printf("%c/%c ", "OIDISIBI"[tag], "OID?S?B?"[*m]);)
|
||||
debug_only_v(printf("%c/%c ", tagChar[tag], typeChar[*m]);)
|
||||
|
||||
switch (*m) {
|
||||
case JSVAL_INT:
|
||||
@ -3330,9 +3341,11 @@ js_IsEntryTypeCompatible(jsval* vp, uint8* m)
|
||||
return true;
|
||||
debug_only_v(printf("string != tag%u", tag);)
|
||||
return false;
|
||||
case JSVAL_TNULL:
|
||||
return JSVAL_IS_NULL(*vp);
|
||||
default:
|
||||
JS_ASSERT(*m == JSVAL_OBJECT);
|
||||
if (tag == JSVAL_OBJECT)
|
||||
if (tag == JSVAL_OBJECT && !JSVAL_IS_NULL(*vp))
|
||||
return true;
|
||||
debug_only_v(printf("object != tag%u", tag);)
|
||||
return false;
|
||||
@ -4333,7 +4346,7 @@ TraceRecorder::ifop()
|
||||
/* test for boolean is true, negate later if we are testing for false */
|
||||
cond = JSVAL_TO_BOOLEAN(v) == 1;
|
||||
x = lir->ins2i(LIR_eq, v_ins, 1);
|
||||
} else if (JSVAL_IS_OBJECT(v)) {
|
||||
} else if (JSVAL_TAG(v) == JSVAL_OBJECT) {
|
||||
cond = !JSVAL_IS_NULL(v);
|
||||
x = v_ins;
|
||||
} else if (isNumber(v)) {
|
||||
@ -4521,45 +4534,6 @@ evalCmp(LOpcode op, JSString* l, JSString* r)
|
||||
return evalCmp(op, js_CompareStrings(l, r));
|
||||
}
|
||||
|
||||
static struct {
|
||||
jsbytecode obj_any[13];
|
||||
jsbytecode any_obj[11];
|
||||
jsbytecode obj_obj[22];
|
||||
} binary_imacros = {
|
||||
{
|
||||
JSOP_SWAP,
|
||||
JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(valueOf),
|
||||
JSOP_STRING, 0, COMMON_TYPE_ATOM_INDEX(JSTYPE_NUMBER),
|
||||
JSOP_CALL, 0, 1,
|
||||
JSOP_SWAP,
|
||||
JSOP_IMACOP,
|
||||
JSOP_STOP
|
||||
},
|
||||
|
||||
{
|
||||
JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(valueOf),
|
||||
JSOP_STRING, 0, COMMON_TYPE_ATOM_INDEX(JSTYPE_NUMBER),
|
||||
JSOP_CALL, 0, 1,
|
||||
JSOP_IMACOP,
|
||||
JSOP_STOP
|
||||
},
|
||||
|
||||
{
|
||||
JSOP_SWAP,
|
||||
JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(valueOf),
|
||||
JSOP_STRING, 0, COMMON_TYPE_ATOM_INDEX(JSTYPE_NUMBER),
|
||||
JSOP_CALL, 0, 1,
|
||||
JSOP_SWAP,
|
||||
JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(valueOf),
|
||||
JSOP_STRING, 0, COMMON_TYPE_ATOM_INDEX(JSTYPE_NUMBER),
|
||||
JSOP_CALL, 0, 1,
|
||||
JSOP_IMACOP,
|
||||
JSOP_STOP
|
||||
}
|
||||
};
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(binary_imacros) < IMACRO_PC_ADJ_LIMIT);
|
||||
|
||||
JS_REQUIRES_STACK void
|
||||
TraceRecorder::strictEquality(bool equal)
|
||||
{
|
||||
@ -4660,7 +4634,7 @@ TraceRecorder::equality(int flags)
|
||||
jsdouble rnum = js_ValueToNumber(cx, &tmp[1]);
|
||||
cond = (lnum == rnum);
|
||||
} else if ((JSVAL_TAG(l) == JSVAL_BOOLEAN && JSVAL_TAG(r) == JSVAL_BOOLEAN) ||
|
||||
(JSVAL_IS_OBJECT(l) && JSVAL_IS_OBJECT(r))) {
|
||||
(JSVAL_TAG(l) == JSVAL_OBJECT && JSVAL_TAG(r) == JSVAL_OBJECT)) {
|
||||
cond = (l == r);
|
||||
} else {
|
||||
ABORT_TRACE("unsupported operand types for cmp");
|
||||
@ -4719,15 +4693,13 @@ TraceRecorder::relational(LOpcode op, int flags)
|
||||
* property; if both arguments are objects with non-function-valued valueOf
|
||||
* properties, abort.
|
||||
*/
|
||||
if (JSVAL_IS_OBJECT(l) && hasValueOfMethod(l)) {
|
||||
if (JSVAL_IS_OBJECT(r) && hasValueOfMethod(r))
|
||||
if (!JSVAL_IS_PRIMITIVE(l)) {
|
||||
if (!JSVAL_IS_PRIMITIVE(r))
|
||||
return call_imacro(binary_imacros.obj_obj);
|
||||
return call_imacro(binary_imacros.obj_any);
|
||||
}
|
||||
if (JSVAL_IS_OBJECT(r) && hasValueOfMethod(r))
|
||||
if (!JSVAL_IS_PRIMITIVE(r))
|
||||
return call_imacro(binary_imacros.any_obj);
|
||||
if (JSVAL_IS_OBJECT(l) || JSVAL_IS_OBJECT(r))
|
||||
ABORT_TRACE("comparing two objects with non-function valueOf");
|
||||
|
||||
/* 11.8.5 steps 3, 16-21. */
|
||||
if (JSVAL_IS_STRING(l) && JSVAL_IS_STRING(r)) {
|
||||
@ -4748,9 +4720,14 @@ TraceRecorder::relational(LOpcode op, int flags)
|
||||
case JSVAL_STRING:
|
||||
l_ins = lir->insCall(&js_StringToNumber_ci, args);
|
||||
break;
|
||||
case JSVAL_OBJECT:
|
||||
if (JSVAL_IS_NULL(l)) {
|
||||
l_ins = lir->insImmq(0);
|
||||
break;
|
||||
}
|
||||
// FALL THROUGH
|
||||
case JSVAL_INT:
|
||||
case JSVAL_DOUBLE:
|
||||
case JSVAL_OBJECT:
|
||||
default:
|
||||
JS_NOT_REACHED("JSVAL_IS_NUMBER if int/double, objects should "
|
||||
"have been handled at start of method");
|
||||
@ -4766,9 +4743,14 @@ TraceRecorder::relational(LOpcode op, int flags)
|
||||
case JSVAL_STRING:
|
||||
r_ins = lir->insCall(&js_StringToNumber_ci, args);
|
||||
break;
|
||||
case JSVAL_OBJECT:
|
||||
if (JSVAL_IS_NULL(r)) {
|
||||
r_ins = lir->insImmq(0);
|
||||
break;
|
||||
}
|
||||
// FALL THROUGH
|
||||
case JSVAL_INT:
|
||||
case JSVAL_DOUBLE:
|
||||
case JSVAL_OBJECT:
|
||||
default:
|
||||
JS_NOT_REACHED("JSVAL_IS_NUMBER if int/double, objects should "
|
||||
"have been handled at start of method");
|
||||
@ -4838,12 +4820,12 @@ TraceRecorder::binary(LOpcode op)
|
||||
jsval& r = stackval(-1);
|
||||
jsval& l = stackval(-2);
|
||||
|
||||
if (JSVAL_IS_OBJECT(l) && hasValueOfMethod(l)) {
|
||||
if (JSVAL_IS_OBJECT(r) && hasValueOfMethod(r))
|
||||
if (!JSVAL_IS_PRIMITIVE(l)) {
|
||||
if (!JSVAL_IS_PRIMITIVE(r))
|
||||
return call_imacro(binary_imacros.obj_obj);
|
||||
return call_imacro(binary_imacros.obj_any);
|
||||
}
|
||||
if (JSVAL_IS_OBJECT(r) && hasValueOfMethod(r))
|
||||
if (!JSVAL_IS_PRIMITIVE(r))
|
||||
return call_imacro(binary_imacros.any_obj);
|
||||
|
||||
bool intop = !(op & LIR64);
|
||||
@ -5039,7 +5021,7 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2
|
||||
JS_ASSERT(entry->kpc == (jsbytecode*) atoms[index]);
|
||||
JS_ASSERT(entry->kshape == jsuword(aobj));
|
||||
#endif
|
||||
if (aobj != globalObj) {
|
||||
if (aobj != globalObj && !obj_ins->isconstp()) {
|
||||
guard(true, addName(lir->ins2i(LIR_eq, obj_ins, entry->kshape), "guard(kobj)"),
|
||||
MISMATCH_EXIT);
|
||||
}
|
||||
@ -5234,12 +5216,20 @@ TraceRecorder::unbox_jsval(jsval v, LIns*& v_ins)
|
||||
MISMATCH_EXIT);
|
||||
v_ins = lir->ins2i(LIR_ush, v_ins, JSVAL_TAGBITS);
|
||||
return true;
|
||||
case JSVAL_OBJECT:
|
||||
guard(true,
|
||||
lir->ins2i(LIR_eq,
|
||||
lir->ins2(LIR_piand, v_ins, INS_CONST(JSVAL_TAGMASK)),
|
||||
JSVAL_OBJECT),
|
||||
MISMATCH_EXIT);
|
||||
case JSVAL_OBJECT:
|
||||
if (JSVAL_IS_NULL(v)) {
|
||||
// JSVAL_NULL maps to type JSVAL_TNULL, so insist that v_ins == 0 here.
|
||||
guard(true, lir->ins_eq0(v_ins), MISMATCH_EXIT);
|
||||
} else {
|
||||
// We must guard that v_ins has JSVAL_OBJECT tag but is not JSVAL_NULL.
|
||||
LIns* exit = snapshot(MISMATCH_EXIT);
|
||||
guard(true,
|
||||
lir->ins2i(LIR_eq,
|
||||
lir->ins2(LIR_piand, v_ins, INS_CONST(JSVAL_TAGMASK)),
|
||||
JSVAL_OBJECT),
|
||||
exit);
|
||||
guard(false, lir->ins_eq0(v_ins), exit);
|
||||
}
|
||||
return true;
|
||||
case JSVAL_STRING:
|
||||
guard(true,
|
||||
@ -5664,53 +5654,18 @@ TraceRecorder::record_JSOP_URSH()
|
||||
return binary(LIR_ush);
|
||||
}
|
||||
|
||||
static struct {
|
||||
jsbytecode obj_any[10];
|
||||
jsbytecode any_obj[8];
|
||||
jsbytecode obj_obj[16];
|
||||
} add_imacros = {
|
||||
{
|
||||
JSOP_SWAP,
|
||||
JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(toString),
|
||||
JSOP_CALL, 0, 0,
|
||||
JSOP_SWAP,
|
||||
JSOP_ADD,
|
||||
JSOP_STOP
|
||||
},
|
||||
|
||||
{
|
||||
JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(toString),
|
||||
JSOP_CALL, 0, 0,
|
||||
JSOP_ADD,
|
||||
JSOP_STOP
|
||||
},
|
||||
|
||||
{
|
||||
JSOP_SWAP,
|
||||
JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(toString),
|
||||
JSOP_CALL, 0, 0,
|
||||
JSOP_SWAP,
|
||||
JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(toString),
|
||||
JSOP_CALL, 0, 0,
|
||||
JSOP_ADD,
|
||||
JSOP_STOP
|
||||
}
|
||||
};
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(add_imacros) < IMACRO_PC_ADJ_LIMIT);
|
||||
|
||||
JS_REQUIRES_STACK bool
|
||||
TraceRecorder::record_JSOP_ADD()
|
||||
{
|
||||
jsval& r = stackval(-1);
|
||||
jsval& l = stackval(-2);
|
||||
|
||||
if (JSVAL_IS_OBJECT(l) && hasToStringMethod(l)) {
|
||||
if (JSVAL_IS_OBJECT(r) && hasToStringMethod(r))
|
||||
if (!JSVAL_IS_PRIMITIVE(l)) {
|
||||
if (!JSVAL_IS_PRIMITIVE(r))
|
||||
return call_imacro(add_imacros.obj_obj);
|
||||
return call_imacro(add_imacros.obj_any);
|
||||
}
|
||||
if (JSVAL_IS_OBJECT(r) && hasToStringMethod(r))
|
||||
if (!JSVAL_IS_PRIMITIVE(r))
|
||||
return call_imacro(add_imacros.any_obj);
|
||||
|
||||
if (JSVAL_IS_STRING(l) || JSVAL_IS_STRING(r)) {
|
||||
@ -5750,12 +5705,12 @@ TraceRecorder::record_JSOP_MOD()
|
||||
jsval& r = stackval(-1);
|
||||
jsval& l = stackval(-2);
|
||||
|
||||
if (JSVAL_IS_OBJECT(l) && hasValueOfMethod(l)) {
|
||||
if (JSVAL_IS_OBJECT(r) && hasValueOfMethod(r))
|
||||
if (!JSVAL_IS_PRIMITIVE(l)) {
|
||||
if (!JSVAL_IS_PRIMITIVE(r))
|
||||
return call_imacro(binary_imacros.obj_obj);
|
||||
return call_imacro(binary_imacros.obj_any);
|
||||
}
|
||||
if (JSVAL_IS_OBJECT(r) && hasValueOfMethod(r))
|
||||
if (!JSVAL_IS_PRIMITIVE(r))
|
||||
return call_imacro(binary_imacros.any_obj);
|
||||
|
||||
if (isNumber(l) && isNumber(r)) {
|
||||
@ -5792,7 +5747,7 @@ TraceRecorder::record_JSOP_NOT()
|
||||
lir->ins_eq0(lir->ins2(LIR_feq, v_ins, v_ins))));
|
||||
return true;
|
||||
}
|
||||
if (JSVAL_IS_OBJECT(v)) {
|
||||
if (JSVAL_TAG(v) == JSVAL_OBJECT) {
|
||||
set(&v, lir->ins_eq0(get(&v)));
|
||||
return true;
|
||||
}
|
||||
@ -5858,7 +5813,7 @@ TraceRecorder::getClassPrototype(JSObject* ctor, LIns*& proto_ins)
|
||||
&pval)) {
|
||||
ABORT_TRACE("error getting prototype from constructor");
|
||||
}
|
||||
if (!JSVAL_IS_OBJECT(pval))
|
||||
if (JSVAL_TAG(pval) != JSVAL_OBJECT)
|
||||
ABORT_TRACE("got primitive prototype from constructor");
|
||||
proto_ins = INS_CONSTPTR(JSVAL_TO_OBJECT(pval));
|
||||
return true;
|
||||
@ -5981,7 +5936,7 @@ TraceRecorder::functionCall(bool constructing, uintN argc)
|
||||
if (argtype == 'C') {
|
||||
*argp = cx_ins;
|
||||
} else if (argtype == 'T') { /* this, as an object */
|
||||
if (!JSVAL_IS_OBJECT(tval))
|
||||
if (JSVAL_IS_PRIMITIVE(tval))
|
||||
goto next_specialization;
|
||||
*argp = this_ins;
|
||||
} else if (argtype == 'S') { /* this, as a string */
|
||||
@ -6018,7 +5973,7 @@ TraceRecorder::functionCall(bool constructing, uintN argc)
|
||||
if (argtype == 'i')
|
||||
*argp = f2i(*argp);
|
||||
} else if (argtype == 'o') {
|
||||
if (!JSVAL_IS_OBJECT(arg))
|
||||
if (JSVAL_IS_PRIMITIVE(arg))
|
||||
goto next_specialization;
|
||||
} else if (argtype == 's') {
|
||||
if (!JSVAL_IS_STRING(arg))
|
||||
@ -6152,7 +6107,7 @@ TraceRecorder::record_JSOP_TYPEOF()
|
||||
JS_ASSERT(JSVAL_TO_BOOLEAN(r) <= 2);
|
||||
type = lir->insCall(&js_TypeOfBoolean_ci, args);
|
||||
} else {
|
||||
JS_ASSERT(JSVAL_IS_OBJECT(r));
|
||||
JS_ASSERT(JSVAL_TAG(r) == JSVAL_OBJECT);
|
||||
type = lir->insCall(&js_TypeOfObject_ci, args);
|
||||
}
|
||||
}
|
||||
@ -6524,13 +6479,13 @@ TraceRecorder::record_JSOP_CALLNAME()
|
||||
JS_REQUIRES_STACK bool
|
||||
TraceRecorder::record_JSOP_GETUPVAR()
|
||||
{
|
||||
ABORT_TRACE("GETUPVAR");
|
||||
return false;
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK bool
|
||||
TraceRecorder::record_JSOP_CALLUPVAR()
|
||||
{
|
||||
ABORT_TRACE("CALLUPVAR");
|
||||
return false;
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK bool
|
||||
@ -7344,7 +7299,7 @@ TraceRecorder::record_JSOP_ITER()
|
||||
if (!JSVAL_IS_PRIMITIVE(v)) {
|
||||
jsuint flags = cx->fp->regs->pc[1];
|
||||
|
||||
if (!hasIteratorMethod(v)) {
|
||||
if (!hasIteratorMethod(JSVAL_TO_OBJECT(v))) {
|
||||
LIns* args[] = { get(&v), INS_CONST(flags), cx_ins };
|
||||
LIns* v_ins = lir->insCall(&js_FastValueToIterator_ci, args);
|
||||
guard(false, lir->ins_eq0(v_ins), MISMATCH_EXIT);
|
||||
@ -7704,6 +7659,16 @@ TraceRecorder::record_JSOP_SETLOCALPOP()
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK bool
|
||||
TraceRecorder::record_JSOP_IFPRIMTOP()
|
||||
{
|
||||
// Traces are type-specialized, including null vs. object, so we need do
|
||||
// nothing here. The upstream unbox_jsval called after valueOf or toString
|
||||
// from an imacro (e.g.) will fork the trace for us, allowing us to just
|
||||
// follow along mindlessly :-).
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK bool
|
||||
TraceRecorder::record_JSOP_SETCALL()
|
||||
{
|
||||
@ -8571,7 +8536,6 @@ InitIMacroCode()
|
||||
|
||||
#define UNUSED(n) JS_REQUIRES_STACK bool TraceRecorder::record_JSOP_UNUSED##n() { return false; }
|
||||
|
||||
UNUSED(131)
|
||||
UNUSED(201)
|
||||
UNUSED(202)
|
||||
UNUSED(203)
|
||||
|
@ -420,21 +420,7 @@ class TraceRecorder : public avmplus::GCObject {
|
||||
JS_REQUIRES_STACK void fuseIf(jsbytecode* pc, bool cond, nanojit::LIns* x);
|
||||
|
||||
bool hasMethod(JSObject* obj, jsid id);
|
||||
bool hasToStringMethod(JSObject* obj);
|
||||
bool hasToStringMethod(jsval v) {
|
||||
JS_ASSERT(JSVAL_IS_OBJECT(v));
|
||||
return hasToStringMethod(JSVAL_TO_OBJECT(v));
|
||||
}
|
||||
bool hasValueOfMethod(JSObject* obj);
|
||||
bool hasValueOfMethod(jsval v) {
|
||||
JS_ASSERT(JSVAL_IS_OBJECT(v));
|
||||
return hasValueOfMethod(JSVAL_TO_OBJECT(v));
|
||||
}
|
||||
bool hasIteratorMethod(JSObject* obj);
|
||||
bool hasIteratorMethod(jsval v) {
|
||||
JS_ASSERT(JSVAL_IS_OBJECT(v));
|
||||
return hasIteratorMethod(JSVAL_TO_OBJECT(v));
|
||||
}
|
||||
|
||||
public:
|
||||
friend JS_REQUIRES_STACK bool js_MonitorRecording(TraceRecorder* tr);
|
||||
|
@ -2011,255 +2011,6 @@ function testBug466262() {
|
||||
testBug466262.expected = true;
|
||||
test(testBug466262);
|
||||
|
||||
// BEGIN MANDELBROT STUFF
|
||||
// XXXbz I would dearly like to wrap it up into a function to avoid polluting
|
||||
// the global scope, but the function ends up heavyweight, and then we lose on
|
||||
// the jit.
|
||||
load("mandelbrot-results.js");
|
||||
//function testMandelbrotAll() {
|
||||
// Configuration options that affect which codepaths we follow.
|
||||
var doImageData = true;
|
||||
var avoidSparseArray = true;
|
||||
|
||||
// Control of iteration numbers and sizing. We'll do
|
||||
// scaler * colorNames.length iterations or so before deciding that we
|
||||
// don't escape.
|
||||
const scaler = 5;
|
||||
const numRows = 600;
|
||||
const numCols = 600;
|
||||
|
||||
// For now, avoid hitting memory pressure
|
||||
gcparam("maxBytes", 1300000000);
|
||||
gcparam("maxMallocBytes", 1300000000);
|
||||
|
||||
const colorNames = [
|
||||
"black",
|
||||
"green",
|
||||
"blue",
|
||||
"red",
|
||||
"purple",
|
||||
"orange",
|
||||
"cyan",
|
||||
"yellow",
|
||||
"magenta",
|
||||
"brown",
|
||||
"pink",
|
||||
"chartreuse",
|
||||
"darkorange",
|
||||
"crimson",
|
||||
"gray",
|
||||
"deeppink",
|
||||
"firebrick",
|
||||
"lavender",
|
||||
"lawngreen",
|
||||
"lightsalmon",
|
||||
"lime",
|
||||
"goldenrod"
|
||||
];
|
||||
const threshold = (colorNames.length - 1) * scaler;
|
||||
|
||||
// Now set up our colors
|
||||
var colors = [];
|
||||
// 3-part for loop (iterators buggy, we will add a separate test for them)
|
||||
for (var colorNameIdx = 0; colorNameIdx < colorNames.length; ++colorNameIdx) {
|
||||
//for (var colorNameIdx in colorNames) {
|
||||
colorNameIdx = parseInt(colorNameIdx);
|
||||
colors.push([colorNameIdx, colorNameIdx, colorNameIdx, 0]);
|
||||
}
|
||||
|
||||
// Storage for our point data
|
||||
var points;
|
||||
|
||||
var scratch = {};
|
||||
var scratchZ = {};
|
||||
function complexMult(a, b) {
|
||||
var newr = a.r * b.r - a.i * b.i;
|
||||
var newi = a.r * b.i + a.i * b.r;
|
||||
scratch.r = newr;
|
||||
scratch.i = newi;
|
||||
return scratch;
|
||||
}
|
||||
function complexAdd(a, b) {
|
||||
scratch.r = a.r + b.r;
|
||||
scratch.i = a.i + b.i;
|
||||
return scratch;
|
||||
}
|
||||
function abs(a) {
|
||||
return Math.sqrt(a.r * a.r + a.i * a.i);
|
||||
}
|
||||
|
||||
function escapeAbsDiff(normZ, absC) {
|
||||
var absZ = Math.sqrt(normZ);
|
||||
return normZ > absZ + absC;
|
||||
}
|
||||
|
||||
function escapeNorm2(normZ) {
|
||||
return normZ > 4;
|
||||
}
|
||||
|
||||
function fuzzyColors(i) {
|
||||
return Math.floor(i / scaler) + 1;
|
||||
}
|
||||
|
||||
function moddedColors(i) {
|
||||
return (i % (colorNames.length - 1)) + 1;
|
||||
}
|
||||
|
||||
function computeEscapeSpeedObjects(real, imag) {
|
||||
var c = { r: real, i: imag }
|
||||
scratchZ.r = scratchZ.i = 0;
|
||||
var absC = abs(c);
|
||||
for (var i = 0; i < threshold; ++i) {
|
||||
scratchZ = complexAdd(c, complexMult(scratchZ, scratchZ));
|
||||
if (escape(scratchZ.r * scratchZ.r + scratchZ.i * scratchZ.i,
|
||||
absC)) {
|
||||
return colorMap(i);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function computeEscapeSpeedOneObject(real, imag) {
|
||||
// fold in the fact that we start with 0
|
||||
var r = real;
|
||||
var i = imag;
|
||||
var absC = abs({r: real, i: imag});
|
||||
for (var j = 0; j < threshold; ++j) {
|
||||
var r2 = r * r;
|
||||
var i2 = i * i;
|
||||
if (escape(r2 + i2, absC)) {
|
||||
return colorMap(j);
|
||||
}
|
||||
i = 2 * r * i + imag;
|
||||
r = r2 - i2 + real;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function computeEscapeSpeedDoubles(real, imag) {
|
||||
// fold in the fact that we start with 0
|
||||
var r = real;
|
||||
var i = imag;
|
||||
var absC = Math.sqrt(real * real + imag * imag);
|
||||
for (var j = 0; j < threshold; ++j) {
|
||||
var r2 = r * r;
|
||||
var i2 = i * i;
|
||||
if (escape(r2 + i2, absC)) {
|
||||
return colorMap(j);
|
||||
}
|
||||
i = 2 * r * i + imag;
|
||||
r = r2 - i2 + real;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
var computeEscapeSpeed = computeEscapeSpeedDoubles;
|
||||
var escape = escapeNorm2;
|
||||
var colorMap = fuzzyColors;
|
||||
|
||||
function addPointOrig(pointArray, n, i, j) {
|
||||
if (!points[n]) {
|
||||
points[n] = [];
|
||||
points[n].push([i, j, 1, 1]);
|
||||
} else {
|
||||
var point = points[n][points[n].length-1];
|
||||
if (point[0] == i && point[1] == j - point[3]) {
|
||||
++point[3];
|
||||
} else {
|
||||
points[n].push([i, j, 1, 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addPointImagedata(pointArray, n, col, row) {
|
||||
var slotIdx = ((row * numCols) + col) * 4;
|
||||
pointArray[slotIdx] = colors[n][0];
|
||||
pointArray[slotIdx+1] = colors[n][1];
|
||||
pointArray[slotIdx+2] = colors[n][2];
|
||||
pointArray[slotIdx+3] = colors[n][3];
|
||||
}
|
||||
|
||||
function createMandelSet() {
|
||||
var realRange = { min: -2.1, max: 1 };
|
||||
var imagRange = { min: -1.5, max: 1.5 };
|
||||
|
||||
var addPoint;
|
||||
if (doImageData) {
|
||||
addPoint = addPointImagedata;
|
||||
points = new Array(4*numCols*numRows);
|
||||
if (avoidSparseArray) {
|
||||
for (var idx = 0; idx < 4*numCols*numRows; ++idx) {
|
||||
points[idx] = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
addPoint = addPointOrig;
|
||||
points = [];
|
||||
}
|
||||
var realStep = (realRange.max - realRange.min)/numCols;
|
||||
var imagStep = (imagRange.min - imagRange.max)/numRows;
|
||||
for (var i = 0, curReal = realRange.min;
|
||||
i < numCols;
|
||||
++i, curReal += realStep) {
|
||||
for (var j = 0, curImag = imagRange.max;
|
||||
j < numRows;
|
||||
++j, curImag += imagStep) {
|
||||
var n = computeEscapeSpeed(curReal, curImag);
|
||||
addPoint(points, n, i, j)
|
||||
}
|
||||
}
|
||||
var result;
|
||||
if (doImageData) {
|
||||
if (colorMap == fuzzyColors) {
|
||||
result = mandelbrotImageDataFuzzyResult;
|
||||
} else {
|
||||
result = mandelbrotImageDataModdedResult;
|
||||
}
|
||||
} else {
|
||||
result = mandelbrotNoImageDataResult;
|
||||
}
|
||||
return points.toSource() == result;
|
||||
}
|
||||
|
||||
createMandelSet.expected = true;
|
||||
|
||||
const escapeTests = [ escapeAbsDiff ];
|
||||
const colorMaps = [ fuzzyColors, moddedColors ];
|
||||
const escapeComputations = [ computeEscapeSpeedObjects,
|
||||
computeEscapeSpeedOneObject,
|
||||
computeEscapeSpeedDoubles ];
|
||||
// Test all possible escape-speed generation codepaths, using the
|
||||
// imageData + sparse array avoidance storage.
|
||||
doImageData = true;
|
||||
avoidSparseArray = true;
|
||||
for (var escapeIdx in escapeTests) {
|
||||
escape = escapeTests[escapeIdx];
|
||||
for (var colorMapIdx in colorMaps) {
|
||||
colorMap = colorMaps[colorMapIdx];
|
||||
for (var escapeComputationIdx in escapeComputations) {
|
||||
computeEscapeSpeed = escapeComputations[escapeComputationIdx];
|
||||
test(createMandelSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test all possible storage strategies. Note that we already tested
|
||||
// doImageData == true with avoidSparseArray == true.
|
||||
escape = escapeAbsDiff;
|
||||
colorMap = fuzzyColors; // This part doesn't really matter too much here
|
||||
computeEscapeSpeed = computeEscapeSpeedDoubles;
|
||||
|
||||
doImageData = true;
|
||||
avoidSparseArray = false;
|
||||
test(createMandelSet);
|
||||
|
||||
escape = escapeNorm2;
|
||||
doImageData = false; // avoidSparseArray doesn't matter here
|
||||
test(createMandelSet);
|
||||
//}
|
||||
//testMandelbrotAll();
|
||||
// END MANDELBROT STUFF
|
||||
|
||||
function testNewDate()
|
||||
{
|
||||
// Accessing global.Date for the first time will change the global shape,
|
||||
@ -3726,6 +3477,255 @@ function testComparisons()
|
||||
testComparisons.expected = "no failures reported!";
|
||||
test(testComparisons);
|
||||
|
||||
// BEGIN MANDELBROT STUFF
|
||||
// XXXbz I would dearly like to wrap it up into a function to avoid polluting
|
||||
// the global scope, but the function ends up heavyweight, and then we lose on
|
||||
// the jit.
|
||||
load("mandelbrot-results.js");
|
||||
//function testMandelbrotAll() {
|
||||
// Configuration options that affect which codepaths we follow.
|
||||
var doImageData = true;
|
||||
var avoidSparseArray = true;
|
||||
|
||||
// Control of iteration numbers and sizing. We'll do
|
||||
// scaler * colorNames.length iterations or so before deciding that we
|
||||
// don't escape.
|
||||
const scaler = 5;
|
||||
const numRows = 600;
|
||||
const numCols = 600;
|
||||
|
||||
// For now, avoid hitting memory pressure
|
||||
gcparam("maxBytes", 1300000000);
|
||||
gcparam("maxMallocBytes", 1300000000);
|
||||
|
||||
const colorNames = [
|
||||
"black",
|
||||
"green",
|
||||
"blue",
|
||||
"red",
|
||||
"purple",
|
||||
"orange",
|
||||
"cyan",
|
||||
"yellow",
|
||||
"magenta",
|
||||
"brown",
|
||||
"pink",
|
||||
"chartreuse",
|
||||
"darkorange",
|
||||
"crimson",
|
||||
"gray",
|
||||
"deeppink",
|
||||
"firebrick",
|
||||
"lavender",
|
||||
"lawngreen",
|
||||
"lightsalmon",
|
||||
"lime",
|
||||
"goldenrod"
|
||||
];
|
||||
const threshold = (colorNames.length - 1) * scaler;
|
||||
|
||||
// Now set up our colors
|
||||
var colors = [];
|
||||
// 3-part for loop (iterators buggy, we will add a separate test for them)
|
||||
for (var colorNameIdx = 0; colorNameIdx < colorNames.length; ++colorNameIdx) {
|
||||
//for (var colorNameIdx in colorNames) {
|
||||
colorNameIdx = parseInt(colorNameIdx);
|
||||
colors.push([colorNameIdx, colorNameIdx, colorNameIdx, 0]);
|
||||
}
|
||||
|
||||
// Storage for our point data
|
||||
var points;
|
||||
|
||||
var scratch = {};
|
||||
var scratchZ = {};
|
||||
function complexMult(a, b) {
|
||||
var newr = a.r * b.r - a.i * b.i;
|
||||
var newi = a.r * b.i + a.i * b.r;
|
||||
scratch.r = newr;
|
||||
scratch.i = newi;
|
||||
return scratch;
|
||||
}
|
||||
function complexAdd(a, b) {
|
||||
scratch.r = a.r + b.r;
|
||||
scratch.i = a.i + b.i;
|
||||
return scratch;
|
||||
}
|
||||
function abs(a) {
|
||||
return Math.sqrt(a.r * a.r + a.i * a.i);
|
||||
}
|
||||
|
||||
function escapeAbsDiff(normZ, absC) {
|
||||
var absZ = Math.sqrt(normZ);
|
||||
return normZ > absZ + absC;
|
||||
}
|
||||
|
||||
function escapeNorm2(normZ) {
|
||||
return normZ > 4;
|
||||
}
|
||||
|
||||
function fuzzyColors(i) {
|
||||
return Math.floor(i / scaler) + 1;
|
||||
}
|
||||
|
||||
function moddedColors(i) {
|
||||
return (i % (colorNames.length - 1)) + 1;
|
||||
}
|
||||
|
||||
function computeEscapeSpeedObjects(real, imag) {
|
||||
var c = { r: real, i: imag }
|
||||
scratchZ.r = scratchZ.i = 0;
|
||||
var absC = abs(c);
|
||||
for (var i = 0; i < threshold; ++i) {
|
||||
scratchZ = complexAdd(c, complexMult(scratchZ, scratchZ));
|
||||
if (escape(scratchZ.r * scratchZ.r + scratchZ.i * scratchZ.i,
|
||||
absC)) {
|
||||
return colorMap(i);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function computeEscapeSpeedOneObject(real, imag) {
|
||||
// fold in the fact that we start with 0
|
||||
var r = real;
|
||||
var i = imag;
|
||||
var absC = abs({r: real, i: imag});
|
||||
for (var j = 0; j < threshold; ++j) {
|
||||
var r2 = r * r;
|
||||
var i2 = i * i;
|
||||
if (escape(r2 + i2, absC)) {
|
||||
return colorMap(j);
|
||||
}
|
||||
i = 2 * r * i + imag;
|
||||
r = r2 - i2 + real;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function computeEscapeSpeedDoubles(real, imag) {
|
||||
// fold in the fact that we start with 0
|
||||
var r = real;
|
||||
var i = imag;
|
||||
var absC = Math.sqrt(real * real + imag * imag);
|
||||
for (var j = 0; j < threshold; ++j) {
|
||||
var r2 = r * r;
|
||||
var i2 = i * i;
|
||||
if (escape(r2 + i2, absC)) {
|
||||
return colorMap(j);
|
||||
}
|
||||
i = 2 * r * i + imag;
|
||||
r = r2 - i2 + real;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
var computeEscapeSpeed = computeEscapeSpeedDoubles;
|
||||
var escape = escapeNorm2;
|
||||
var colorMap = fuzzyColors;
|
||||
|
||||
function addPointOrig(pointArray, n, i, j) {
|
||||
if (!points[n]) {
|
||||
points[n] = [];
|
||||
points[n].push([i, j, 1, 1]);
|
||||
} else {
|
||||
var point = points[n][points[n].length-1];
|
||||
if (point[0] == i && point[1] == j - point[3]) {
|
||||
++point[3];
|
||||
} else {
|
||||
points[n].push([i, j, 1, 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addPointImagedata(pointArray, n, col, row) {
|
||||
var slotIdx = ((row * numCols) + col) * 4;
|
||||
pointArray[slotIdx] = colors[n][0];
|
||||
pointArray[slotIdx+1] = colors[n][1];
|
||||
pointArray[slotIdx+2] = colors[n][2];
|
||||
pointArray[slotIdx+3] = colors[n][3];
|
||||
}
|
||||
|
||||
function createMandelSet() {
|
||||
var realRange = { min: -2.1, max: 1 };
|
||||
var imagRange = { min: -1.5, max: 1.5 };
|
||||
|
||||
var addPoint;
|
||||
if (doImageData) {
|
||||
addPoint = addPointImagedata;
|
||||
points = new Array(4*numCols*numRows);
|
||||
if (avoidSparseArray) {
|
||||
for (var idx = 0; idx < 4*numCols*numRows; ++idx) {
|
||||
points[idx] = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
addPoint = addPointOrig;
|
||||
points = [];
|
||||
}
|
||||
var realStep = (realRange.max - realRange.min)/numCols;
|
||||
var imagStep = (imagRange.min - imagRange.max)/numRows;
|
||||
for (var i = 0, curReal = realRange.min;
|
||||
i < numCols;
|
||||
++i, curReal += realStep) {
|
||||
for (var j = 0, curImag = imagRange.max;
|
||||
j < numRows;
|
||||
++j, curImag += imagStep) {
|
||||
var n = computeEscapeSpeed(curReal, curImag);
|
||||
addPoint(points, n, i, j)
|
||||
}
|
||||
}
|
||||
var result;
|
||||
if (doImageData) {
|
||||
if (colorMap == fuzzyColors) {
|
||||
result = mandelbrotImageDataFuzzyResult;
|
||||
} else {
|
||||
result = mandelbrotImageDataModdedResult;
|
||||
}
|
||||
} else {
|
||||
result = mandelbrotNoImageDataResult;
|
||||
}
|
||||
return points.toSource() == result;
|
||||
}
|
||||
|
||||
createMandelSet.expected = true;
|
||||
|
||||
const escapeTests = [ escapeAbsDiff ];
|
||||
const colorMaps = [ fuzzyColors, moddedColors ];
|
||||
const escapeComputations = [ computeEscapeSpeedObjects,
|
||||
computeEscapeSpeedOneObject,
|
||||
computeEscapeSpeedDoubles ];
|
||||
// Test all possible escape-speed generation codepaths, using the
|
||||
// imageData + sparse array avoidance storage.
|
||||
doImageData = true;
|
||||
avoidSparseArray = true;
|
||||
for (var escapeIdx in escapeTests) {
|
||||
escape = escapeTests[escapeIdx];
|
||||
for (var colorMapIdx in colorMaps) {
|
||||
colorMap = colorMaps[colorMapIdx];
|
||||
for (var escapeComputationIdx in escapeComputations) {
|
||||
computeEscapeSpeed = escapeComputations[escapeComputationIdx];
|
||||
test(createMandelSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test all possible storage strategies. Note that we already tested
|
||||
// doImageData == true with avoidSparseArray == true.
|
||||
escape = escapeAbsDiff;
|
||||
colorMap = fuzzyColors; // This part doesn't really matter too much here
|
||||
computeEscapeSpeed = computeEscapeSpeedDoubles;
|
||||
|
||||
doImageData = true;
|
||||
avoidSparseArray = false;
|
||||
test(createMandelSet);
|
||||
|
||||
escape = escapeNorm2;
|
||||
doImageData = false; // avoidSparseArray doesn't matter here
|
||||
test(createMandelSet);
|
||||
//}
|
||||
//testMandelbrotAll();
|
||||
// END MANDELBROT STUFF
|
||||
|
||||
/* NOTE: Keep this test last, since it screws up all for...in loops after it. */
|
||||
function testGlobalProtoAccess() {
|
||||
return "ok";
|
||||
|
Loading…
Reference in New Issue
Block a user