Skip to content

Commit

Permalink
avm2: Don't call value_of implementation in as_number, `as_intege…
Browse files Browse the repository at this point in the history
…r`, and `as_u32`

Also, rename those functions to `as_f64`, `as_i32`, and `as_u32` for consistency.
  • Loading branch information
Lord-McSweeney authored and Lord-McSweeney committed Oct 4, 2024
1 parent 33d1f65 commit 5066f8f
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 120 deletions.
24 changes: 3 additions & 21 deletions core/src/avm2/amf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,31 +79,13 @@ pub fn serialize_value<'gc>(
} else if let Some(vec) = o.as_vector_storage() {
let val_type = vec.value_type();
if val_type == Some(activation.avm2().class_defs().int) {
let int_vec: Vec<_> = vec
.iter()
.map(|v| {
v.as_integer(activation.strings())
.expect("Unexpected non-int value in int vector")
})
.collect();
let int_vec: Vec<_> = vec.iter().map(|v| v.as_i32()).collect();
Some(AmfValue::VectorInt(int_vec, vec.is_fixed()))
} else if val_type == Some(activation.avm2().class_defs().uint) {
let uint_vec: Vec<_> = vec
.iter()
.map(|v| {
v.as_u32(activation.strings())
.expect("Unexpected non-uint value in int vector")
})
.collect();
let uint_vec: Vec<_> = vec.iter().map(|v| v.as_u32()).collect();
Some(AmfValue::VectorUInt(uint_vec, vec.is_fixed()))
} else if val_type == Some(activation.avm2().class_defs().number) {
let num_vec: Vec<_> = vec
.iter()
.map(|v| {
v.as_number(activation.strings())
.expect("Unexpected non-uint value in int vector")
})
.collect();
let num_vec: Vec<_> = vec.iter().map(|v| v.as_f64()).collect();
Some(AmfValue::VectorDouble(num_vec, vec.is_fixed()))
} else {
let obj_vec: Vec<_> = vec
Expand Down
5 changes: 1 addition & 4 deletions core/src/avm2/globals/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,7 @@ pub fn instance_init<'gc>(

if let Some(mut array) = this.as_array_storage_mut(activation.context.gc_context) {
if args.len() == 1 {
if let Some(expected_len) = args
.get(0)
.and_then(|v| v.as_number(activation.strings()).ok())
{
if let Some(expected_len) = args.get(0).filter(|v| v.is_number()).map(|v| v.as_f64()) {
if expected_len < 0.0 || expected_len.is_nan() || expected_len.fract() != 0.0 {
return Err(Error::AvmError(range_error(
activation,
Expand Down
17 changes: 4 additions & 13 deletions core/src/avm2/globals/flash/display/graphics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1283,17 +1283,9 @@ fn read_point<'gc>(
data: &VectorStorage<'gc>,
data_index: &mut usize,
) -> Option<Point<Twips>> {
let x = data
.get(*data_index, activation)
.ok()?
.as_number(activation.strings())
.expect("data is not a Vec.<Number>");

let y = data
.get(*data_index + 1, activation)
.ok()?
.as_number(activation.strings())
.expect("data is not a Vec.<Number>");
let x = data.get(*data_index, activation).ok()?.as_f64();

let y = data.get(*data_index + 1, activation).ok()?.as_f64();

*data_index += 2;

Expand Down Expand Up @@ -1395,8 +1387,7 @@ fn process_commands<'gc>(
let command = commands
.get(i, activation)
.expect("missing command")
.as_integer(activation.strings())
.expect("commands is not a Vec.<int>");
.as_i32();

if process_command(activation, drawing, data, command, &mut data_index).is_none() {
break;
Expand Down
24 changes: 6 additions & 18 deletions core/src/avm2/globals/flash/display/shader_job.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,19 +107,16 @@ pub fn get_shader_args<'gc>(
let width = shader_input
.get_public_property("width", activation)
.unwrap()
.as_u32(activation.strings())
.unwrap();
.as_u32();
let height = shader_input
.get_public_property("height", activation)
.unwrap()
.as_u32(activation.strings())
.unwrap();
.as_u32();

let input_channels = shader_input
.get_public_property("channels", activation)
.unwrap()
.as_u32(activation.strings())
.unwrap();
.as_u32();

assert_eq!(*channels as u32, input_channels);

Expand Down Expand Up @@ -155,10 +152,7 @@ pub fn get_shader_args<'gc>(
channels: input_channels,
bytes: vector
.iter()
.flat_map(|val| {
(val.as_number(activation.strings()).unwrap() as f32)
.to_le_bytes()
})
.flat_map(|val| (val.as_f64() as f32).to_le_bytes())
.collect(),
}
} else {
Expand Down Expand Up @@ -207,15 +201,9 @@ pub fn start<'gc>(
.as_object()
.expect("ShaderJob.target is not an object");

let output_width = this
.get_public_property("width", activation)?
.as_u32(activation.strings())
.expect("ShaderJob.width is not a number");
let output_width = this.get_public_property("width", activation)?.as_u32();

let output_height = this
.get_public_property("height", activation)?
.as_u32(activation.strings())
.expect("ShaderJob.height is not a number");
let output_height = this.get_public_property("height", activation)?.as_u32();

let pixel_bender_target = if let Some(bitmap) = target.as_bitmap_data() {
let target_bitmap = bitmap.sync(activation.context.renderer);
Expand Down
42 changes: 21 additions & 21 deletions core/src/avm2/globals/flash/display3D/context_3d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,8 +320,8 @@ pub fn set_program_constants_from_matrix<'gc>(
.as_vector_storage()
.unwrap()
.iter()
.map(|val| val.coerce_to_number(activation).map(|val| val as f32))
.collect::<Result<Vec<f32>, Error>>()?;
.map(|val| val.as_f64() as f32)
.collect::<Vec<f32>>();

context.set_program_constants_from_matrix(is_vertex, first_register, matrix_raw_data);
}
Expand Down Expand Up @@ -365,29 +365,29 @@ pub fn set_program_constants_from_vector<'gc>(

let raw_data = vector
.iter()
.map(|val| val.as_number(activation.strings()).map(|val| val as f32))
.map(|val| val.as_f64() as f32)
.take(to_take)
.collect::<Result<Vec<f32>, _>>()?;
.collect::<Vec<f32>>();

context.set_program_constants_from_matrix(program_type, first_register, raw_data);
}
Ok(Value::Undefined)
}

pub fn clear<'gc>(
activation: &mut Activation<'_, 'gc>,
_activation: &mut Activation<'_, 'gc>,
this: Object<'gc>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(context) = this.as_context_3d() {
// This is a native method, so all of the arguments have been checked and coerced for us
let red = args[0].as_number(activation.strings())?;
let green = args[1].as_number(activation.strings())?;
let blue = args[2].as_number(activation.strings())?;
let alpha = args[3].as_number(activation.strings())?;
let depth = args[4].as_number(activation.strings())?;
let stencil = args[5].as_integer(activation.strings())? as u32;
let mask = args[6].as_integer(activation.strings())? as u32;
let red = args[0].as_f64();
let green = args[1].as_f64();
let blue = args[2].as_f64();
let alpha = args[3].as_f64();
let depth = args[4].as_f64();
let stencil = args[5].as_i32() as u32;
let mask = args[6].as_i32() as u32;
context.set_clear(red, green, blue, alpha, depth, stencil, mask);
}
Ok(Value::Undefined)
Expand All @@ -400,11 +400,11 @@ pub fn create_texture<'gc>(
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(context) = this.as_context_3d() {
// This is a native method, so all of the arguments have been checked and coerced for us
let width = args[0].as_integer(activation.strings())? as u32;
let height = args[1].as_integer(activation.strings())? as u32;
let width = args[0].as_i32() as u32;
let height = args[1].as_i32() as u32;
let format = args[2].coerce_to_string(activation)?;
let optimize_for_render_to_texture = args[3].coerce_to_boolean();
let streaming_levels = args[4].as_integer(activation.strings())? as u32;
let streaming_levels = args[4].as_i32() as u32;
let format = Context3DTextureFormat::from_wstr(&format).ok_or_else(|| {
Error::RustError(
format!("Unsupported texture format in createTexture: {:?}", format).into(),
Expand Down Expand Up @@ -433,8 +433,8 @@ pub fn create_rectangle_texture<'gc>(
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(context) = this.as_context_3d() {
// This is a native method, so all of the arguments have been checked and coerced for us
let width = args[0].as_integer(activation.strings())? as u32;
let height = args[1].as_integer(activation.strings())? as u32;
let width = args[0].as_i32() as u32;
let height = args[1].as_i32() as u32;
let format = args[2].coerce_to_string(activation)?;
let optimize_for_render_to_texture = args[3].coerce_to_boolean();
let format = Context3DTextureFormat::from_wstr(&format).ok_or_else(|| {
Expand Down Expand Up @@ -469,10 +469,10 @@ pub fn create_cube_texture<'gc>(
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(context) = this.as_context_3d() {
// This is a native method, so all of the arguments have been checked and coerced for us
let size = args[0].as_integer(activation.strings())? as u32;
let size = args[0].as_i32() as u32;
let format = args[1].coerce_to_string(activation)?;
let optimize_for_render_to_texture = args[2].coerce_to_boolean();
let streaming_levels = args[3].as_integer(activation.strings())? as u32;
let streaming_levels = args[3].as_i32() as u32;
let format = Context3DTextureFormat::from_wstr(&format).ok_or_else(|| {
Error::RustError(
format!(
Expand Down Expand Up @@ -501,7 +501,7 @@ pub fn set_texture_at<'gc>(
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(context) = this.as_context_3d() {
// This is a native method, so all of the arguments have been checked and coerced for us
let sampler = args[0].as_integer(activation.strings())? as u32;
let sampler = args[0].as_i32() as u32;
let mut cube = false;
let texture = if matches!(args[1], Value::Null) {
None
Expand Down Expand Up @@ -652,7 +652,7 @@ pub fn set_sampler_state_at<'gc>(
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(context) = this.as_context_3d() {
// This is a native method, so all of the arguments have been checked and coerced for us
let sampler = args[0].as_integer(activation.strings())? as u32;
let sampler = args[0].as_i32() as u32;
let wrap = args[1].coerce_to_string(activation)?;
let filter = args[2].coerce_to_string(activation)?;
let mip_filter = args[3].coerce_to_string(activation)?;
Expand Down
9 changes: 4 additions & 5 deletions core/src/avm2/globals/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,16 +332,15 @@ pub fn stringify<'gc>(
};
Some(indent_bytes)
}
} else {
let indent_size = spaces
.as_number(activation.strings())
.unwrap_or(0.0)
.clamp(0.0, 10.0) as u16;
} else if spaces.is_number() {
let indent_size = spaces.as_f64().clamp(0.0, 10.0) as u16;
if indent_size == 0 {
None
} else {
Some(Cow::Owned(b" ".repeat(indent_size.into())))
}
} else {
None
};

let mut serializer = AvmSerializer::new(replacer);
Expand Down
50 changes: 14 additions & 36 deletions core/src/avm2/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::avm2::Error;
use crate::avm2::Multiname;
use crate::avm2::Namespace;
use crate::ecma_conversions::{f64_to_wrapping_i32, f64_to_wrapping_u32};
use crate::string::{AvmAtom, AvmString, StringContext, WStr};
use crate::string::{AvmAtom, AvmString, WStr};
use gc_arena::Collect;
use num_bigint::BigInt;
use num_traits::{ToPrimitive, Zero};
Expand Down Expand Up @@ -552,52 +552,30 @@ impl<'gc> Value<'gc> {

/// Get the numerical portion of the value, if it exists.
///
/// This function performs no numerical coercion, nor are user-defined
/// object methods called. This should only be used if you specifically
/// need the behavior of only handling actual numbers; otherwise you should
/// use the appropriate `coerce_to_` method.
pub fn as_number(&self, context: &mut StringContext<'gc>) -> Result<f64, Error<'gc>> {
/// This function performs no numerical coercion, nor are any methods called.
pub fn as_f64(&self) -> f64 {
match self {
// Methods that look for numbers in Flash Player don't seem to care
// about user-defined `valueOf` implementations. This code upholds
// that limitation as long as `TObject`'s `value_of` method also
// does not call user-defined functions.
Value::Object(num) => match num.value_of(context)? {
Value::Number(num) => Ok(num),
Value::Integer(num) => Ok(num as f64),
_ => Err(format!("Expected Number, int, or uint, found {self:?}").into()),
},
Value::Number(num) => Ok(*num),
Value::Integer(num) => Ok(*num as f64),
_ => Err(format!("Expected Number, int, or uint, found {self:?}").into()),
Value::Number(num) => *num,
Value::Integer(num) => *num as f64,
_ => panic!("Expected Number or Integer"),
}
}

/// Like `as_number`, but for `i32`
pub fn as_integer(&self, context: &mut StringContext<'gc>) -> Result<i32, Error<'gc>> {
pub fn as_i32(&self) -> i32 {
match self {
Value::Object(num) => match num.value_of(context)? {
Value::Number(num) => Ok(num as i32),
Value::Integer(num) => Ok(num),
_ => Err(format!("Expected Number, int, or uint, found {self:?}").into()),
},
Value::Number(num) => Ok(*num as i32),
Value::Integer(num) => Ok(*num),
_ => Err(format!("Expected Number, int, or uint, found {self:?}").into()),
Value::Number(num) => *num as i32,
Value::Integer(num) => *num,
_ => panic!("Expected Number or Integer"),
}
}

/// Like `as_number`, but for `u32`
pub fn as_u32(&self, context: &mut StringContext<'gc>) -> Result<u32, Error<'gc>> {
pub fn as_u32(&self) -> u32 {
match self {
Value::Object(num) => match num.value_of(context)? {
Value::Number(num) => Ok(num as u32),
Value::Integer(num) => Ok(num as u32),
_ => Err(format!("Expected Number, int, or uint, found {self:?}").into()),
},
Value::Number(num) => Ok(*num as u32),
Value::Integer(num) => Ok(*num as u32),
_ => Err(format!("Expected Number, int, or uint, found {self:?}").into()),
Value::Number(num) => *num as u32,
Value::Integer(num) => *num as u32,
_ => panic!("Expected Number or Integer"),
}
}

Expand Down
4 changes: 2 additions & 2 deletions core/src/bitmap/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1669,8 +1669,8 @@ pub fn set_vector<'gc>(
let color = iter
.next()
.expect("BitmapData.setVector: Expected element")
.as_u32(activation.strings())
.expect("BitmapData.setVector: Expected uint vector");
.as_u32();

bitmap_data.set_pixel32_raw(
x,
y,
Expand Down

0 comments on commit 5066f8f

Please sign in to comment.