Bug 465460 - TM: valueOf ignored on third iteration of loop (r=gal).

This commit is contained in:
Brendan Eich 2008-12-11 17:50:56 -08:00
parent 098216e2fd
commit 5d4fa98a15
14 changed files with 1488 additions and 570 deletions

View File

@ -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 $< > $@

View File

@ -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
View 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
View 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
View 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

View File

@ -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;

View File

@ -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)
{

View File

@ -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);

View File

@ -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 == &regs); \
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:

View File

@ -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),

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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";